Repository: tetratelabs/wazero
Pull request #1728 (2023-09-21 05:13:22)

wazevo: fixes many params function listeners
#1496 

mathetake: seems like there is a flaky segfault, so I will pend the merge until I solve it
mathetake: `go test ./internal/integration_test/engine/... -run 'TestEngineWazevo/huge_stack' -v -count=5000` has started being flaky
mathetake: well it seems like even on the main branch it's already flaky 
mathetake: ok seems like there's a bug in stack bounds check - tomorrow I will investigate and add the "stack guards" debug test configuration
mathetake: ok found a bug on the bounds check and added the stack guard corruption verifier option, and it works now

Patch:
diff --git a/internal/engine/interpreter/interpreter.go b/internal/engine/interpreter/interpreter.go
index f19f33f3..9adb6afe 100644
--- a/internal/engine/interpreter/interpreter.go
+++ b/internal/engine/interpreter/interpreter.go
@@ -4096,10 +4096,10 @@ func (ce *callEngine) callNativeFuncWithListener(ctx context.Context, m *wasm.Mo
 	def, typ := f.definition(), f.funcType
 
 	ce.stackIterator.reset(ce.stack, ce.frames, f)
-	fnl.Before(ctx, m, def, ce.peekValues(len(typ.Params)), &ce.stackIterator)
+	fnl.Before(ctx, m, def, ce.peekValues(typ.ParamNumInUint64), &ce.stackIterator)
 	ce.stackIterator.clear()
 	ce.callNativeFunc(ctx, m, f)
-	fnl.After(ctx, m, def, ce.peekValues(len(typ.Results)))
+	fnl.After(ctx, m, def, ce.peekValues(typ.ResultNumInUint64))
 	return ctx
 }
 
diff --git a/internal/engine/wazevo/backend/isa/arm64/abi.go b/internal/engine/wazevo/backend/isa/arm64/abi.go
index f410174a..0da0fd50 100644
--- a/internal/engine/wazevo/backend/isa/arm64/abi.go
+++ b/internal/engine/wazevo/backend/isa/arm64/abi.go
@@ -20,7 +20,7 @@ var regInfo = &regalloc.RegisterInfo{
 		// - x27(=tmpReg): because of the reason described on tmpReg.
 		regalloc.RegTypeInt: {
 			x8, x9, x10, x11, x12, x13, x14, x15,
-			x16, x17, x18, x19, x20, x21, x22, x23, x24, x25,
+			x16, x17, x19, x20, x21, x22, x23, x24, x25,
 			x26, x29, x30,
 			// These are the argument/return registers. Less preferred in the allocation.
 			x7, x6, x5, x4, x3, x2, x1, x0,
@@ -116,7 +116,6 @@ func (a *abiImpl) setABIArgs(s []backend.ABIArg, types []ssa.Type) (stackSize in
 			if nextX > xArgRetRegMax {
 				arg.Kind = backend.ABIArgKindStack
 				const slotSize = 8 // Align 8 bytes.
-				stackOffset = (stackOffset + slotSize - 1) &^ (slotSize - 1)
 				arg.Offset = stackOffset
 				stackOffset += slotSize
 			} else {
@@ -131,7 +130,6 @@ func (a *abiImpl) setABIArgs(s []backend.ABIArg, types []ssa.Type) (stackSize in
 				if typ.Bits() == 128 { // Vector.
 					slotSize = 16
 				}
-				stackOffset = (stackOffset + slotSize - 1) &^ (slotSize - 1)
 				arg.Offset = stackOffset
 				stackOffset += slotSize
 			} else {
@@ -354,8 +352,8 @@ func (m *machine) lowerCall(si *ssa.Instruction) {
 	calleeABI := m.getOrCreateABIImpl(m.compiler.ResolveSignature(sigID))
 
 	stackSlotSize := calleeABI.alignedArgResultStackSlotSize()
-	if m.maxRequiredStackSizeForCalls < stackSlotSize {
-		m.maxRequiredStackSizeForCalls = stackSlotSize
+	if m.maxRequiredStackSizeForCalls < stackSlotSize+16 {
+		m.maxRequiredStackSizeForCalls = stackSlotSize + 16 // return address frame.
 	}
 
 	for i, arg := range args {
diff --git a/internal/engine/wazevo/backend/isa/arm64/abi_go_call.go b/internal/engine/wazevo/backend/isa/arm64/abi_go_call.go
index f80fb2ee..e09abea5 100644
--- a/internal/engine/wazevo/backend/isa/arm64/abi_go_call.go
+++ b/internal/engine/wazevo/backend/isa/arm64/abi_go_call.go
@@ -7,8 +7,8 @@ import (
 	"github.com/tetratelabs/wazero/internal/engine/wazevo/wazevoapi"
 )
 
-var calleeSavedRegistersPlusLinkRegSorted = []regalloc.VReg{
-	x19VReg, x20VReg, x21VReg, x22VReg, x23VReg, x24VReg, x25VReg, x26VReg, x28VReg, lrVReg,
+var calleeSavedRegistersSorted = []regalloc.VReg{
+	x19VReg, x20VReg, x21VReg, x22VReg, x23VReg, x24VReg, x25VReg, x26VReg, x28VReg,
 	v18VReg, v19VReg, v20VReg, v21VReg, v22VReg, v23VReg, v24VReg, v25VReg, v26VReg, v27VReg, v28VReg, v29VReg, v30VReg, v31VReg,
 }
 
@@ -62,21 +62,20 @@ func (m *machine) CompileGoFunctionTrampoline(exitCode wazevoapi.ExitCode, sig *
 	// First of all, to update the SP, and create "ReturnAddress + size_of_arg_ret".
 	cur = m.createReturnAddrAndSizeOfArgRetSlot(cur)
 
-	const callFrameSize = 32 // == frame_size + sliceSize + ReturnAddress + size_of_arg_ret.
+	const frameInfoSize = 16 // == frame_size + sliceSize.
 
 	// Next, we should allocate the stack for the Go function call if necessary.
 	goCallStackSize, sliceSizeInBytes := goFunctionCallRequiredStackSize(sig, argBegin)
-	cur = m.insertStackBoundsCheck(goCallStackSize+callFrameSize, cur)
+	cur = m.insertStackBoundsCheck(goCallStackSize+frameInfoSize, cur)
 
 	originalArg0Reg := x17VReg // Caller save, so we can use it for whatever we want.
 	if m.currentABI.alignedArgResultStackSlotSize() > 0 {
-		copySp := m.allocateInstr()
-		copySp.asMove64(originalArg0Reg, spVReg)
-		cur = linkInstr(cur, copySp)
+		// At this point, SP points to `ReturnAddress`, so add 16 to get the original arg 0 slot.
+		cur = m.addsAddOrSubStackPointer(cur, originalArg0Reg, frameInfoSize, true)
 	}
 
 	// Save the callee saved registers.
-	cur = m.saveRegistersInExecutionContext(cur, calleeSavedRegistersPlusLinkRegSorted)
+	cur = m.saveRegistersInExecutionContext(cur, calleeSavedRegistersSorted)
 
 	// Next, we need to store all the arguments to the stack in the typical Wasm stack style.
 	if needModuleContextPtr {
@@ -154,15 +153,30 @@ func (m *machine) CompileGoFunctionTrampoline(exitCode wazevoapi.ExitCode, sig *
 	cur = m.storeReturnAddressAndExit(cur)
 
 	// After the call, we need to restore the callee saved registers.
-	cur = m.restoreRegistersInExecutionContext(cur, calleeSavedRegistersPlusLinkRegSorted)
+	cur = m.restoreRegistersInExecutionContext(cur, calleeSavedRegistersSorted)
 
 	// Get the pointer to the arg[0]/ret[0]: We need to skip `frame_size + sliceSize`.
 	if len(abi.rets) > 0 {
-		cur = m.addsAddOrSubStackPointer(cur, arg0ret0AddrReg, 16, true)
+		cur = m.addsAddOrSubStackPointer(cur, arg0ret0AddrReg, frameInfoSize, true)
 	}
 
-	// Removes the stack frame! --> Stack pointer now points to the original arg 0 slot.
-	cur = m.addsAddOrSubStackPointer(cur, spVReg, goCallStackSize+callFrameSize+m.currentABI.alignedArgResultStackSlotSize(), true)
+	// Advances the SP so that it points to `ReturnAddress`.
+	cur = m.addsAddOrSubStackPointer(cur, spVReg, frameInfoSize+goCallStackSize, true)
+	ldr := m.allocateInstr()
+	// And load the return address.
+	ldr.asULoad(operandNR(lrVReg),
+		addressModePreOrPostIndex(spVReg, 16 /* stack pointer must be 16-byte aligned. */, false /* increment after loads */), 64)
+	cur = linkInstr(cur, ldr)
+
+	originalRet0Reg := x17VReg // Caller save, so we can use it for whatever we want.
+	if m.currentABI.retStackSize > 0 {
+		cur = m.addsAddOrSubStackPointer(cur, originalRet0Reg, m.currentABI.argStackSize, true)
+	}
+
+	// Make the SP point to the original address (above the result slot).
+	if s := m.currentABI.alignedArgResultStackSlotSize(); s > 0 {
+		cur = m.addsAddOrSubStackPointer(cur, spVReg, s, true)
+	}
 
 	for i := range abi.rets {
 		r := &abi.rets[i]
@@ -220,7 +234,7 @@ func (m *machine) CompileGoFunctionTrampoline(exitCode wazevoapi.ExitCode, sig *
 				panic("TODO")
 			}
 			cur = linkInstr(cur, loadIntoTmpReg)
-			cur = m.goFunctionCallStoreStackResult(cur, spVReg, r, resultReg)
+			cur = m.goFunctionCallStoreStackResult(cur, originalRet0Reg, r, resultReg)
 		}
 	}
 
@@ -386,23 +400,9 @@ func goFunctionCallRequiredStackSize(sig *ssa.Signature, argBegin int) (ret, ret
 }
 
 func (m *machine) goFunctionCallLoadStackArg(cur *instruction, originalArg0Reg regalloc.VReg, arg *backend.ABIArg, intVReg, floatVReg regalloc.VReg) (*instruction, regalloc.VReg) {
-	offset := arg.Offset
-
-	alu := m.allocateInstr()
-	ao := aluOpAdd
-	if imm12Operand, ok := asImm12Operand(uint64(offset)); ok {
-		alu.asALU(ao, operandNR(intVReg), operandNR(originalArg0Reg), imm12Operand, true)
-		cur = linkInstr(cur, alu)
-	} else {
-		cur = m.lowerConstantI64AndInsert(cur, tmpRegVReg, offset)
-		alu.asALU(ao, operandNR(intVReg), operandNR(originalArg0Reg), operandNR(tmpRegVReg), true)
-		cur = linkInstr(cur, alu)
-	}
-
 	load := m.allocateInstr()
-
 	var result regalloc.VReg
-	mode := addressMode{kind: addressModeKindRegUnsignedImm12, rn: intVReg}
+	mode := addressMode{kind: addressModeKindPostIndex, rn: originalArg0Reg}
 	switch arg.Type {
 	case ssa.TypeI32:
 		mode.imm = 8 // We use uint64 for all basic types, except SIMD v128.
@@ -432,32 +432,23 @@ func (m *machine) goFunctionCallLoadStackArg(cur *instruction, originalArg0Reg r
 	return cur, result
 }
 
-func (m *machine) goFunctionCallStoreStackResult(cur *instruction, originalArg0Reg regalloc.VReg, result *backend.ABIArg, resultVReg regalloc.VReg) *instruction {
-	offset := result.Offset + m.currentABI.argStackSize
-
-	alu := m.allocateInstr()
-	ao := aluOpAdd
-	if imm12Operand, ok := asImm12Operand(uint64(offset)); ok {
-		alu.asALU(ao, operandNR(tmpRegVReg), operandNR(originalArg0Reg), imm12Operand, true)
-		cur = linkInstr(cur, alu)
-	} else {
-		cur = m.lowerConstantI64AndInsert(cur, tmpRegVReg, offset)
-		alu.asALU(ao, operandNR(tmpRegVReg), operandNR(originalArg0Reg), operandNR(tmpRegVReg), true)
-		cur = linkInstr(cur, alu)
-	}
-
+func (m *machine) goFunctionCallStoreStackResult(cur *instruction, originalRet0Reg regalloc.VReg, result *backend.ABIArg, resultVReg regalloc.VReg) *instruction {
 	store := m.allocateInstr()
+	mode := addressMode{kind: addressModeKindPostIndex, rn: originalRet0Reg}
 	var sizeInBits byte
 	switch result.Type {
 	case ssa.TypeI32, ssa.TypeF32:
+		mode.imm = 8
 		sizeInBits = 32
 	case ssa.TypeI64, ssa.TypeF64:
+		mode.imm = 8
 		sizeInBits = 64
 	case ssa.TypeV128:
+		mode.imm = 16
 		sizeInBits = 128
 	default:
 		panic("TODO")
 	}
-	store.asStore(operandNR(resultVReg), addressMode{kind: addressModeKindRegUnsignedImm12, rn: tmpRegVReg}, sizeInBits)
+	store.asStore(operandNR(resultVReg), mode, sizeInBits)
 	return linkInstr(cur, store)
 }
diff --git a/internal/engine/wazevo/backend/isa/arm64/instr.go b/internal/engine/wazevo/backend/isa/arm64/instr.go
index fa953850..5a9e8b65 100644
--- a/internal/engine/wazevo/backend/isa/arm64/instr.go
+++ b/internal/engine/wazevo/backend/isa/arm64/instr.go
@@ -324,10 +324,14 @@ func (i *instruction) assignUse(index int, reg regalloc.VReg) {
 		} else if index == 1 {
 			if amodeRN := i.amode.rn; amodeRN.Valid() {
 				i.amode.rn = reg
+			} else {
+				panic("BUG")
 			}
 		} else {
 			if amodeRM := i.amode.rm; amodeRM.Valid() {
 				i.amode.rm = reg
+			} else {
+				panic("BUG")
 			}
 		}
 	case useKindCond:
diff --git a/internal/engine/wazevo/backend/isa/arm64/machine_regalloc.go b/internal/engine/wazevo/backend/isa/arm64/machine_regalloc.go
index 5f46842a..1ea3cd3a 100644
--- a/internal/engine/wazevo/backend/isa/arm64/machine_regalloc.go
+++ b/internal/engine/wazevo/backend/isa/arm64/machine_regalloc.go
@@ -325,8 +325,6 @@ func (m *machine) insertReloadRegisterAt(v regalloc.VReg, instr *instruction, af
 		panic("TODO")
 	}
 
-	cur.next = load
-	load.prev = cur
 	cur = linkInstr(cur, load)
 	linkInstr(cur, prevNext)
 }
diff --git a/internal/engine/wazevo/backend/regalloc/assign.go b/internal/engine/wazevo/backend/regalloc/assign.go
index 625b329a..11967fcc 100644
--- a/internal/engine/wazevo/backend/regalloc/assign.go
+++ b/internal/engine/wazevo/backend/regalloc/assign.go
@@ -125,7 +125,7 @@ func (a *Allocator) handleSpills(
 	case !_usesSpills && !_defSpill: // Nothing to do.
 	case !_usesSpills && _defSpill: // Only definition is spilled.
 		a.collectActiveNodesAt(pc+pcDefOffset, liveNodes)
-		a.spillHandler.init(a.nodes1)
+		a.spillHandler.init(a.nodes1, instr)
 
 		r, evictedNode := a.spillHandler.getUnusedOrEvictReg(defSpill.RegType(), a.regInfo)
 		if evictedNode != nil {
@@ -141,7 +141,7 @@ func (a *Allocator) handleSpills(
 
 	case _usesSpills:
 		a.collectActiveNodesAt(pc, liveNodes)
-		a.spillHandler.init(a.nodes1)
+		a.spillHandler.init(a.nodes1, instr)
 
 		var evicted [3]*node
 		var evictedCount int
@@ -185,7 +185,7 @@ func (a *Allocator) handleSpills(
 			if !defSpill.IsRealReg() {
 				// This case, the destination register type is different from the source registers.
 				a.collectActiveNodesAt(pc+pcDefOffset, liveNodes)
-				a.spillHandler.init(a.nodes1)
+				a.spillHandler.init(a.nodes1, instr)
 				r, evictedNode := a.spillHandler.getUnusedOrEvictReg(defSpill.RegType(), a.regInfo)
 				if evictedNode != nil {
 					evictedNodeV := evictedNode.v.SetRealReg(evictedNode.assignedRealReg())
diff --git a/internal/engine/wazevo/backend/regalloc/spill_handler.go b/internal/engine/wazevo/backend/regalloc/spill_handler.go
index bcd74df8..dc85f511 100644
--- a/internal/engine/wazevo/backend/regalloc/spill_handler.go
+++ b/internal/engine/wazevo/backend/regalloc/spill_handler.go
@@ -2,8 +2,9 @@ package regalloc
 
 // spillHandler is a helper to handle the spill and reload of registers at some point in the program.
 type spillHandler struct {
-	activeRegs map[RealReg]spillHandlerRegState
-	deleteTemp []RealReg
+	activeRegs   map[RealReg]spillHandlerRegState
+	deleteTemp   []RealReg
+	beingUsedNow map[RealReg]struct{}
 }
 
 type spillHandlerRegState struct {
@@ -15,10 +16,28 @@ const (
 	spillHandlerRegStateUsed = iota
 	spillHandlerRegStateEvictable
 	spillHandlerRegStateEvicted
+	spillHandlerRegStateBeingUsedNow
 )
 
 // init initializes the spill handler with the active nodes which are the node alive at a some point in the program.
-func (s *spillHandler) init(activeNodes []*node) {
+func (s *spillHandler) init(activeNodes []*node, inst Instr) {
+	if s.beingUsedNow == nil {
+		s.beingUsedNow = make(map[RealReg]struct{})
+	} else {
+		s.deleteTemp = s.deleteTemp[:0]
+		for r := range s.beingUsedNow {
+			s.deleteTemp = append(s.deleteTemp, r)
+		}
+		for _, r := range s.deleteTemp {
+			delete(s.beingUsedNow, r)
+		}
+		for _, u := range inst.Uses() {
+			if u.IsRealReg() {
+				s.beingUsedNow[u.RealReg()] = struct{}{}
+			}
+		}
+	}
+
 	if s.activeRegs == nil {
 		s.activeRegs = make(map[RealReg]spillHandlerRegState)
 	} else {
@@ -31,7 +50,12 @@ func (s *spillHandler) init(activeNodes []*node) {
 		}
 	}
 	for _, n := range activeNodes {
-		s.activeRegs[n.assignedRealReg()] = spillHandlerRegState{node: n, state: spillHandlerRegStateEvictable}
+		r := n.assignedRealReg()
+		if _, ok := s.beingUsedNow[r]; ok {
+			s.activeRegs[r] = spillHandlerRegState{node: n, state: spillHandlerRegStateBeingUsedNow}
+		} else {
+			s.activeRegs[r] = spillHandlerRegState{node: n, state: spillHandlerRegStateEvictable}
+		}
 	}
 }
 
diff --git a/internal/engine/wazevo/call_engine.go b/internal/engine/wazevo/call_engine.go
index d51c17d0..1c097a54 100644
--- a/internal/engine/wazevo/call_engine.go
+++ b/internal/engine/wazevo/call_engine.go
@@ -77,17 +77,29 @@ type (
 	}
 )
 
-var initialStackSize uint64 = 512
+func (c *callEngine) requiredInitialStackSize() int {
+	const initialStackSizeDefault = 512
+	stackSize := initialStackSizeDefault
+	paramResultInBytes := c.sizeOfParamResultSlice * 8 * 2 // * 8 because uint64 is 8 bytes, and *2 because we need both separated param/result slots.
+	required := paramResultInBytes + 32                    // 32 is enough to accommodate the call frame info.
+	if required > stackSize {
+		stackSize = required
+	}
+	return stackSize
+}
 
 func (c *callEngine) init() {
-	stackSize := initialStackSize
-	if c.sizeOfParamResultSlice > int(stackSize) {
-		stackSize = uint64(c.sizeOfParamResultSlice)
+	stackSize := c.requiredInitialStackSize()
+	if wazevoapi.StackGuardCheckEnabled {
+		stackSize += wazevoapi.StackGuardCheckGuardPageSize
 	}
-
 	c.stack = make([]byte, stackSize)
 	c.stackTop = alignedStackTop(c.stack)
-	c.execCtx.stackBottomPtr = &c.stack[0]
+	if wazevoapi.StackGuardCheckEnabled {
+		c.execCtx.stackBottomPtr = &c.stack[wazevoapi.StackGuardCheckGuardPageSize]
+	} else {
+		c.execCtx.stackBottomPtr = &c.stack[0]
+	}
 	c.execCtxPtr = uintptr(unsafe.Pointer(&c.execCtx))
 }
 
@@ -141,6 +153,12 @@ func (c *callEngine) CallWithStack(ctx context.Context, paramResultStack []uint6
 
 // CallWithStack implements api.Function.
 func (c *callEngine) callWithStack(ctx context.Context, paramResultStack []uint64) (err error) {
+	if wazevoapi.StackGuardCheckEnabled {
+		defer func() {
+			wazevoapi.CheckStackGuardPage(c.stack)
+		}()
+	}
+
 	p := c.parent
 	ensureTermination := p.parent.ensureTermination
 	m := p.module
@@ -206,7 +224,12 @@ func (c *callEngine) callWithStack(ctx context.Context, paramResultStack []uint6
 		case wazevoapi.ExitCodeOK:
 			return nil
 		case wazevoapi.ExitCodeGrowStack:
-			newsp, err := c.growStack()
+			var newsp uintptr
+			if wazevoapi.StackGuardCheckEnabled {
+				newsp, err = c.growStackWithGuarded()
+			} else {
+				newsp, err = c.growStack()
+			}
 			if err != nil {
 				return err
 			}
@@ -348,6 +371,21 @@ func opaqueViewFromPtr(ptr uintptr) []byte {
 
 const callStackCeiling = uintptr(5000000) // in uint64 (8 bytes) == 40000000 bytes in total == 40mb.
 
+func (c *callEngine) growStackWithGuarded() (newSP uintptr, err error) {
+	if wazevoapi.StackGuardCheckEnabled {
+		wazevoapi.CheckStackGuardPage(c.stack)
+		c.execCtx.stackGrowRequiredSize += wazevoapi.StackGuardCheckGuardPageSize
+	}
+	newSP, err = c.growStack()
+	if err != nil {
+		return
+	}
+	if wazevoapi.StackGuardCheckEnabled {
+		c.execCtx.stackBottomPtr = &c.stack[wazevoapi.StackGuardCheckGuardPageSize]
+	}
+	return
+}
+
 // growStack grows the stack, and returns the new stack pointer.
 func (c *callEngine) growStack() (newSP uintptr, err error) {
 	currentLen := uintptr(len(c.stack))
diff --git a/internal/engine/wazevo/wazevoapi/debug_options.go b/internal/engine/wazevo/wazevoapi/debug_options.go
index e006950b..a46031d6 100644
--- a/internal/engine/wazevo/wazevoapi/debug_options.go
+++ b/internal/engine/wazevo/wazevoapi/debug_options.go
@@ -2,6 +2,7 @@ package wazevoapi
 
 import (
 	"context"
+	"encoding/hex"
 	"fmt"
 	"math/rand"
 	"os"
@@ -47,6 +48,23 @@ const (
 	SSAValidationEnabled      = true
 )
 
+// ----- Stack Guard Check -----
+// These consts must be enabled by default until we reach the point where we can disable them (e.g. multiple days of fuzzing passes).
+const (
+	// StackGuardCheckEnabled enables the stack guard check to ensure that our stack bounds check works correctly.
+	StackGuardCheckEnabled       = true
+	StackGuardCheckGuardPageSize = 8096
+)
+
+// CheckStackGuardPage checks the given stack guard page is not corrupted.
+func CheckStackGuardPage(s []byte) {
+	for i := 0; i < StackGuardCheckGuardPageSize; i++ {
+		if s[i] != 0 {
+			panic(fmt.Sprintf("BUG: stack guard page is corrupted: %s", hex.EncodeToString(s[:StackGuardCheckGuardPageSize])))
+		}
+	}
+}
+
 // ----- Deterministic compilation verifier -----
 
 const (


Test patch:
diff --git a/internal/engine/wazevo/backend/backend_test.go b/internal/engine/wazevo/backend/backend_test.go
index ce901e19..2de4f81c 100644
--- a/internal/engine/wazevo/backend/backend_test.go
+++ b/internal/engine/wazevo/backend/backend_test.go
@@ -888,14 +888,15 @@ L1 (SSA Block: blk0):
 	sub sp, sp, x27
 	stp x30, x27, [sp, #-0x10]!
 	str x19, [sp, #-0x10]!
+	str x20, [sp, #-0x10]!
 	str q18, [sp, #-0x10]!
 	str q19, [sp, #-0x10]!
-	orr x27, xzr, #0x30
+	orr x27, xzr, #0x40
 	str x27, [sp, #-0x10]!
 	str x1, [x0, #0x8]
 	bl f1
-	ldr w19, [sp, #-0xc0]
-	ldr x18, [sp, #-0xb8]
+	ldr w20, [sp, #-0xc0]
+	ldr x19, [sp, #-0xb8]
 	ldr s19, [sp, #-0xb0]
 	ldr d18, [sp, #-0xa8]
 	ldr w17, [sp, #-0xa0]
@@ -918,33 +919,34 @@ L1 (SSA Block: blk0):
 	ldr x8, [sp, #-0x18]
 	ldr s9, [sp, #-0x10]
 	ldr d8, [sp, #-0x8]
-	str d8, [sp, #0x108]
-	str s9, [sp, #0x100]
-	str x8, [sp, #0xf8]
-	str w9, [sp, #0xf0]
-	str d10, [sp, #0xe8]
-	str s11, [sp, #0xe0]
-	str x10, [sp, #0xd8]
-	str w11, [sp, #0xd0]
-	str d12, [sp, #0xc8]
-	str s13, [sp, #0xc0]
-	str x12, [sp, #0xb8]
-	str w13, [sp, #0xb0]
-	str d14, [sp, #0xa8]
-	str s15, [sp, #0xa0]
-	str x14, [sp, #0x98]
-	str w15, [sp, #0x90]
-	str d16, [sp, #0x88]
-	str s17, [sp, #0x80]
-	str x16, [sp, #0x78]
-	str w17, [sp, #0x70]
-	str d18, [sp, #0x68]
-	str s19, [sp, #0x60]
-	str x18, [sp, #0x58]
-	str w19, [sp, #0x50]
+	str d8, [sp, #0x118]
+	str s9, [sp, #0x110]
+	str x8, [sp, #0x108]
+	str w9, [sp, #0x100]
+	str d10, [sp, #0xf8]
+	str s11, [sp, #0xf0]
+	str x10, [sp, #0xe8]
+	str w11, [sp, #0xe0]
+	str d12, [sp, #0xd8]
+	str s13, [sp, #0xd0]
+	str x12, [sp, #0xc8]
+	str w13, [sp, #0xc0]
+	str d14, [sp, #0xb8]
+	str s15, [sp, #0xb0]
+	str x14, [sp, #0xa8]
+	str w15, [sp, #0xa0]
+	str d16, [sp, #0x98]
+	str s17, [sp, #0x90]
+	str x16, [sp, #0x88]
+	str w17, [sp, #0x80]
+	str d18, [sp, #0x78]
+	str s19, [sp, #0x70]
+	str x19, [sp, #0x68]
+	str w20, [sp, #0x60]
 	add sp, sp, #0x10
 	ldr q19, [sp], #0x10
 	ldr q18, [sp], #0x10
+	ldr x20, [sp], #0x10
 	ldr x19, [sp], #0x10
 	ldr x30, [sp], #0x10
 	add sp, sp, #0xc0
@@ -1478,26 +1480,27 @@ L1 (SSA Block: blk0):
 	madd w16, w2, w16, wzr
 	movz w17, #0xa, lsl 0
 	madd w17, w2, w17, wzr
-	movz w18, #0xb, lsl 0
-	madd w18, w2, w18, wzr
-	orr w19, wzr, #0xc
+	movz w19, #0xb, lsl 0
 	madd w19, w2, w19, wzr
-	movz w20, #0xd, lsl 0
+	orr w20, wzr, #0xc
 	madd w20, w2, w20, wzr
-	orr w21, wzr, #0xe
+	movz w21, #0xd, lsl 0
 	madd w21, w2, w21, wzr
-	orr w22, wzr, #0xf
+	orr w22, wzr, #0xe
 	madd w22, w2, w22, wzr
-	orr w23, wzr, #0x10
+	orr w23, wzr, #0xf
 	madd w23, w2, w23, wzr
-	movz w24, #0x11, lsl 0
+	orr w24, wzr, #0x10
 	madd w24, w2, w24, wzr
-	movz w25, #0x12, lsl 0
+	movz w25, #0x11, lsl 0
 	madd w25, w2, w25, wzr
-	movz w26, #0x13, lsl 0
+	movz w26, #0x12, lsl 0
 	madd w26, w2, w26, wzr
-	movz w29, #0x14, lsl 0
+	movz w29, #0x13, lsl 0
 	madd w29, w2, w29, wzr
+	movz w30, #0x14, lsl 0
+	madd w30, w2, w30, wzr
+	add w29, w29, w30
 	add w26, w26, w29
 	add w25, w25, w26
 	add w24, w24, w25
@@ -1506,8 +1509,7 @@ L1 (SSA Block: blk0):
 	add w21, w21, w22
 	add w20, w20, w21
 	add w19, w19, w20
-	add w18, w18, w19
-	add w17, w17, w18
+	add w17, w17, w19
 	add w16, w16, w17
 	add w15, w15, w16
 	add w14, w14, w15
diff --git a/internal/engine/wazevo/backend/isa/arm64/abi_entry_preamble_test.go b/internal/engine/wazevo/backend/isa/arm64/abi_entry_preamble_test.go
index 054dd625..cb6724c3 100644
--- a/internal/engine/wazevo/backend/isa/arm64/abi_entry_preamble_test.go
+++ b/internal/engine/wazevo/backend/isa/arm64/abi_entry_preamble_test.go
@@ -215,9 +215,9 @@ func TestAbiImpl_constructEntryPreamble(t *testing.T) {
 	str s15, [x19], #0x8
 	ldr d15, [sp, #-0x30]
 	str d15, [x19], #0x8
-	ldr q15, [sp, #-0x20]
+	ldr q15, [sp, #-0x28]
 	str q15, [x19], #0x10
-	ldr q15, [sp, #-0x10]
+	ldr q15, [sp, #-0x18]
 	str q15, [x19], #0x10
 	ldr x29, [x20, #0x10]
 	ldr x27, [x20, #0x18]
diff --git a/internal/engine/wazevo/backend/isa/arm64/abi_go_call_test.go b/internal/engine/wazevo/backend/isa/arm64/abi_go_call_test.go
index 7abd9f9c..173cfe5c 100644
--- a/internal/engine/wazevo/backend/isa/arm64/abi_go_call_test.go
+++ b/internal/engine/wazevo/backend/isa/arm64/abi_go_call_test.go
@@ -13,17 +13,16 @@ import (
 	"github.com/tetratelabs/wazero/internal/testing/require"
 )
 
-func Test_calleeSavedRegistersPlusLinkRegSorted(t *testing.T) {
+func Test_calleeSavedRegistersSorted(t *testing.T) {
 	var exp []regalloc.VReg
 	for r := range regInfo.CalleeSavedRegisters {
 		exp = append(exp, regInfo.RealRegToVReg[r])
 	}
-	exp = append(exp, regInfo.RealRegToVReg[lr])
 	sort.Slice(exp, func(i, j int) bool {
 		return exp[i].RealReg() < exp[j].RealReg()
 	})
 
-	require.Equal(t, exp, calleeSavedRegistersPlusLinkRegSorted)
+	require.Equal(t, exp, calleeSavedRegistersSorted)
 }
 
 func TestMachine_CompileGoFunctionTrampoline(t *testing.T) {
@@ -54,18 +53,18 @@ func TestMachine_CompileGoFunctionTrampoline(t *testing.T) {
 				},
 			},
 			exp: `
-	orr x27, xzr, #0xc0
+	movz x27, #0xa0, lsl 0
 	sub sp, sp, x27
 	stp x30, x27, [sp, #-0x10]!
-	sub x27, sp, #0x140
+	sub x27, sp, #0x130
 	ldr x11, [x0, #0x28]
 	subs xzr, x27, x11
 	b.ge #0x14
-	movz x27, #0x140, lsl 0
+	movz x27, #0x130, lsl 0
 	str x27, [x0, #0x40]
 	ldr x27, [x0, #0x50]
 	bl x27
-	mov x17, sp
+	add x17, sp, #0x10
 	str x19, [x0, #0x60]
 	str x20, [x0, #0x70]
 	str x21, [x0, #0x80]
@@ -75,21 +74,20 @@ func TestMachine_CompileGoFunctionTrampoline(t *testing.T) {
 	str x25, [x0, #0xc0]
 	str x26, [x0, #0xd0]
 	str x28, [x0, #0xe0]
-	str x30, [x0, #0xf0]
-	str q18, [x0, #0x100]
-	str q19, [x0, #0x110]
-	str q20, [x0, #0x120]
-	str q21, [x0, #0x130]
-	str q22, [x0, #0x140]
-	str q23, [x0, #0x150]
-	str q24, [x0, #0x160]
-	str q25, [x0, #0x170]
-	str q26, [x0, #0x180]
-	str q27, [x0, #0x190]
-	str q28, [x0, #0x1a0]
-	str q29, [x0, #0x1b0]
-	str q30, [x0, #0x1c0]
-	str q31, [x0, #0x1d0]
+	str q18, [x0, #0xf0]
+	str q19, [x0, #0x100]
+	str q20, [x0, #0x110]
+	str q21, [x0, #0x120]
+	str q22, [x0, #0x130]
+	str q23, [x0, #0x140]
+	str q24, [x0, #0x150]
+	str q25, [x0, #0x160]
+	str q26, [x0, #0x170]
+	str q27, [x0, #0x180]
+	str q28, [x0, #0x190]
+	str q29, [x0, #0x1a0]
+	str q30, [x0, #0x1b0]
+	str q31, [x0, #0x1c0]
 	str x1, [x0, #0x460]
 	sub sp, sp, #0x120
 	mov x15, sp
@@ -105,19 +103,15 @@ func TestMachine_CompileGoFunctionTrampoline(t *testing.T) {
 	str x5, [x15], #0x8
 	str q6, [x15], #0x10
 	str d7, [x15], #0x8
-	add x11, x17, #0x0
-	ldr q11, [x11, #0x10]
+	ldr q11, [x17], #0x10
 	str q11, [x15], #0x10
 	str x6, [x15], #0x8
 	str x7, [x15], #0x8
-	add x11, x17, #0x10
-	ldr q11, [x11, #0x10]
+	ldr q11, [x17], #0x10
 	str q11, [x15], #0x10
-	add x11, x17, #0x20
-	ldr s11, [x11, #0x8]
+	ldr s11, [x17], #0x8
 	str d11, [x15], #0x8
-	add x11, x17, #0x30
-	ldr q11, [x11, #0x10]
+	ldr q11, [x17], #0x10
 	str q11, [x15], #0x10
 	movz x27, #0x120, lsl 0
 	movz x16, #0x23, lsl 0
@@ -138,23 +132,25 @@ func TestMachine_CompileGoFunctionTrampoline(t *testing.T) {
 	ldr x25, [x0, #0xc0]
 	ldr x26, [x0, #0xd0]
 	ldr x28, [x0, #0xe0]
-	ldr x30, [x0, #0xf0]
-	ldr q18, [x0, #0x100]
-	ldr q19, [x0, #0x110]
-	ldr q20, [x0, #0x120]
-	ldr q21, [x0, #0x130]
-	ldr q22, [x0, #0x140]
-	ldr q23, [x0, #0x150]
-	ldr q24, [x0, #0x160]
-	ldr q25, [x0, #0x170]
-	ldr q26, [x0, #0x180]
-	ldr q27, [x0, #0x190]
-	ldr q28, [x0, #0x1a0]
-	ldr q29, [x0, #0x1b0]
-	ldr q30, [x0, #0x1c0]
-	ldr q31, [x0, #0x1d0]
+	ldr q18, [x0, #0xf0]
+	ldr q19, [x0, #0x100]
+	ldr q20, [x0, #0x110]
+	ldr q21, [x0, #0x120]
+	ldr q22, [x0, #0x130]
+	ldr q23, [x0, #0x140]
+	ldr q24, [x0, #0x150]
+	ldr q25, [x0, #0x160]
+	ldr q26, [x0, #0x170]
+	ldr q27, [x0, #0x180]
+	ldr q28, [x0, #0x190]
+	ldr q29, [x0, #0x1a0]
+	ldr q30, [x0, #0x1b0]
+	ldr q31, [x0, #0x1c0]
 	add x15, sp, #0x10
-	add sp, sp, #0x200
+	add sp, sp, #0x130
+	ldr x30, [sp], #0x10
+	add x17, sp, #0x38
+	add sp, sp, #0xa0
 	ldr q0, [x15], #0x10
 	ldr w0, [x15], #0x8
 	ldr x1, [x15], #0x8
@@ -170,34 +166,25 @@ func TestMachine_CompileGoFunctionTrampoline(t *testing.T) {
 	ldr x5, [x15], #0x8
 	ldr q7, [x15], #0x10
 	ldr s11, [x15], #0x8
-	add x27, sp, #0x40
-	str s11, [x27]
+	str s11, [x17], #0x8
 	ldr q11, [x15], #0x10
-	add x27, sp, #0x50
-	str q11, [x27]
+	str q11, [x17], #0x10
 	ldr w6, [x15], #0x8
 	ldr x7, [x15], #0x8
 	ldr q11, [x15], #0x10
-	add x27, sp, #0x60
-	str q11, [x27]
+	str q11, [x17], #0x10
 	ldr s11, [x15], #0x8
-	add x27, sp, #0x70
-	str s11, [x27]
+	str s11, [x17], #0x8
 	ldr q11, [x15], #0x10
-	add x27, sp, #0x80
-	str q11, [x27]
+	str q11, [x17], #0x10
 	ldr w11, [x15], #0x8
-	add x27, sp, #0x90
-	str w11, [x27]
+	str w11, [x17], #0x8
 	ldr x11, [x15], #0x8
-	add x27, sp, #0x98
-	str x11, [x27]
+	str x11, [x17], #0x8
 	ldr q11, [x15], #0x10
-	add x27, sp, #0xa0
-	str q11, [x27]
+	str q11, [x17], #0x10
 	ldr s11, [x15], #0x8
-	add x27, sp, #0xb0
-	str s11, [x27]
+	str s11, [x17], #0x8
 	ret
 `,
 		},
@@ -211,11 +198,11 @@ func TestMachine_CompileGoFunctionTrampoline(t *testing.T) {
 			needModuleContextPtr: true,
 			exp: `
 	stp x30, xzr, [sp, #-0x10]!
-	sub x27, sp, #0x40
+	sub x27, sp, #0x30
 	ldr x11, [x0, #0x28]
 	subs xzr, x27, x11
 	b.ge #0x14
-	orr x27, xzr, #0x40
+	orr x27, xzr, #0x30
 	str x27, [x0, #0x40]
 	ldr x27, [x0, #0x50]
 	bl x27
@@ -228,21 +215,20 @@ func TestMachine_CompileGoFunctionTrampoline(t *testing.T) {
 	str x25, [x0, #0xc0]
 	str x26, [x0, #0xd0]
 	str x28, [x0, #0xe0]
-	str x30, [x0, #0xf0]
-	str q18, [x0, #0x100]
-	str q19, [x0, #0x110]
-	str q20, [x0, #0x120]
-	str q21, [x0, #0x130]
-	str q22, [x0, #0x140]
-	str q23, [x0, #0x150]
-	str q24, [x0, #0x160]
-	str q25, [x0, #0x170]
-	str q26, [x0, #0x180]
-	str q27, [x0, #0x190]
-	str q28, [x0, #0x1a0]
-	str q29, [x0, #0x1b0]
-	str q30, [x0, #0x1c0]
-	str q31, [x0, #0x1d0]
+	str q18, [x0, #0xf0]
+	str q19, [x0, #0x100]
+	str q20, [x0, #0x110]
+	str q21, [x0, #0x120]
+	str q22, [x0, #0x130]
+	str q23, [x0, #0x140]
+	str q24, [x0, #0x150]
+	str q25, [x0, #0x160]
+	str q26, [x0, #0x170]
+	str q27, [x0, #0x180]
+	str q28, [x0, #0x190]
+	str q29, [x0, #0x1a0]
+	str q30, [x0, #0x1b0]
+	str q31, [x0, #0x1c0]
 	str x1, [x0, #0x460]
 	sub sp, sp, #0x20
 	mov x15, sp
@@ -266,23 +252,23 @@ func TestMachine_CompileGoFunctionTrampoline(t *testing.T) {
 	ldr x25, [x0, #0xc0]
 	ldr x26, [x0, #0xd0]
 	ldr x28, [x0, #0xe0]
-	ldr x30, [x0, #0xf0]
-	ldr q18, [x0, #0x100]
-	ldr q19, [x0, #0x110]
-	ldr q20, [x0, #0x120]
-	ldr q21, [x0, #0x130]
-	ldr q22, [x0, #0x140]
-	ldr q23, [x0, #0x150]
-	ldr q24, [x0, #0x160]
-	ldr q25, [x0, #0x170]
-	ldr q26, [x0, #0x180]
-	ldr q27, [x0, #0x190]
-	ldr q28, [x0, #0x1a0]
-	ldr q29, [x0, #0x1b0]
-	ldr q30, [x0, #0x1c0]
-	ldr q31, [x0, #0x1d0]
+	ldr q18, [x0, #0xf0]
+	ldr q19, [x0, #0x100]
+	ldr q20, [x0, #0x110]
+	ldr q21, [x0, #0x120]
+	ldr q22, [x0, #0x130]
+	ldr q23, [x0, #0x140]
+	ldr q24, [x0, #0x150]
+	ldr q25, [x0, #0x160]
+	ldr q26, [x0, #0x170]
+	ldr q27, [x0, #0x180]
+	ldr q28, [x0, #0x190]
+	ldr q29, [x0, #0x1a0]
+	ldr q30, [x0, #0x1b0]
+	ldr q31, [x0, #0x1c0]
 	add x15, sp, #0x10
-	add sp, sp, #0x40
+	add sp, sp, #0x30
+	ldr x30, [sp], #0x10
 	ldr w0, [x15], #0x8
 	ldr x1, [x15], #0x8
 	ldr s0, [x15], #0x8
@@ -300,11 +286,11 @@ func TestMachine_CompileGoFunctionTrampoline(t *testing.T) {
 			needModuleContextPtr: true,
 			exp: `
 	stp x30, xzr, [sp, #-0x10]!
-	sub x27, sp, #0x40
+	sub x27, sp, #0x30
 	ldr x11, [x0, #0x28]
 	subs xzr, x27, x11
 	b.ge #0x14
-	orr x27, xzr, #0x40
+	orr x27, xzr, #0x30
 	str x27, [x0, #0x40]
 	ldr x27, [x0, #0x50]
 	bl x27
@@ -317,21 +303,20 @@ func TestMachine_CompileGoFunctionTrampoline(t *testing.T) {
 	str x25, [x0, #0xc0]
 	str x26, [x0, #0xd0]
 	str x28, [x0, #0xe0]
-	str x30, [x0, #0xf0]
-	str q18, [x0, #0x100]
-	str q19, [x0, #0x110]
-	str q20, [x0, #0x120]
-	str q21, [x0, #0x130]
-	str q22, [x0, #0x140]
-	str q23, [x0, #0x150]
-	str q24, [x0, #0x160]
-	str q25, [x0, #0x170]
-	str q26, [x0, #0x180]
-	str q27, [x0, #0x190]
-	str q28, [x0, #0x1a0]
-	str q29, [x0, #0x1b0]
-	str q30, [x0, #0x1c0]
-	str q31, [x0, #0x1d0]
+	str q18, [x0, #0xf0]
+	str q19, [x0, #0x100]
+	str q20, [x0, #0x110]
+	str q21, [x0, #0x120]
+	str q22, [x0, #0x130]
+	str q23, [x0, #0x140]
+	str q24, [x0, #0x150]
+	str q25, [x0, #0x160]
+	str q26, [x0, #0x170]
+	str q27, [x0, #0x180]
+	str q28, [x0, #0x190]
+	str q29, [x0, #0x1a0]
+	str q30, [x0, #0x1b0]
+	str q31, [x0, #0x1c0]
 	str x1, [x0, #0x460]
 	sub sp, sp, #0x20
 	mov x15, sp
@@ -358,22 +343,22 @@ func TestMachine_CompileGoFunctionTrampoline(t *testing.T) {
 	ldr x25, [x0, #0xc0]
 	ldr x26, [x0, #0xd0]
 	ldr x28, [x0, #0xe0]
-	ldr x30, [x0, #0xf0]
-	ldr q18, [x0, #0x100]
-	ldr q19, [x0, #0x110]
-	ldr q20, [x0, #0x120]
-	ldr q21, [x0, #0x130]
-	ldr q22, [x0, #0x140]
-	ldr q23, [x0, #0x150]
-	ldr q24, [x0, #0x160]
-	ldr q25, [x0, #0x170]
-	ldr q26, [x0, #0x180]
-	ldr q27, [x0, #0x190]
-	ldr q28, [x0, #0x1a0]
-	ldr q29, [x0, #0x1b0]
-	ldr q30, [x0, #0x1c0]
-	ldr q31, [x0, #0x1d0]
-	add sp, sp, #0x40
+	ldr q18, [x0, #0xf0]
+	ldr q19, [x0, #0x100]
+	ldr q20, [x0, #0x110]
+	ldr q21, [x0, #0x120]
+	ldr q22, [x0, #0x130]
+	ldr q23, [x0, #0x140]
+	ldr q24, [x0, #0x150]
+	ldr q25, [x0, #0x160]
+	ldr q26, [x0, #0x170]
+	ldr q27, [x0, #0x180]
+	ldr q28, [x0, #0x190]
+	ldr q29, [x0, #0x1a0]
+	ldr q30, [x0, #0x1b0]
+	ldr q31, [x0, #0x1c0]
+	add sp, sp, #0x30
+	ldr x30, [sp], #0x10
 	ret
 `,
 		},
@@ -386,11 +371,11 @@ func TestMachine_CompileGoFunctionTrampoline(t *testing.T) {
 			},
 			exp: `
 	stp x30, xzr, [sp, #-0x10]!
-	sub x27, sp, #0x30
+	sub x27, sp, #0x20
 	ldr x11, [x0, #0x28]
 	subs xzr, x27, x11
 	b.ge #0x14
-	orr x27, xzr, #0x30
+	orr x27, xzr, #0x20
 	str x27, [x0, #0x40]
 	ldr x27, [x0, #0x50]
 	bl x27
@@ -403,21 +388,20 @@ func TestMachine_CompileGoFunctionTrampoline(t *testing.T) {
 	str x25, [x0, #0xc0]
 	str x26, [x0, #0xd0]
 	str x28, [x0, #0xe0]
-	str x30, [x0, #0xf0]
-	str q18, [x0, #0x100]
-	str q19, [x0, #0x110]
-	str q20, [x0, #0x120]
-	str q21, [x0, #0x130]
-	str q22, [x0, #0x140]
-	str q23, [x0, #0x150]
-	str q24, [x0, #0x160]
-	str q25, [x0, #0x170]
-	str q26, [x0, #0x180]
-	str q27, [x0, #0x190]
-	str q28, [x0, #0x1a0]
-	str q29, [x0, #0x1b0]
-	str q30, [x0, #0x1c0]
-	str q31, [x0, #0x1d0]
+	str q18, [x0, #0xf0]
+	str q19, [x0, #0x100]
+	str q20, [x0, #0x110]
+	str q21, [x0, #0x120]
+	str q22, [x0, #0x130]
+	str q23, [x0, #0x140]
+	str q24, [x0, #0x150]
+	str q25, [x0, #0x160]
+	str q26, [x0, #0x170]
+	str q27, [x0, #0x180]
+	str q28, [x0, #0x190]
+	str q29, [x0, #0x1a0]
+	str q30, [x0, #0x1b0]
+	str q31, [x0, #0x1c0]
 	sub sp, sp, #0x10
 	mov x15, sp
 	str x1, [x15], #0x8
@@ -440,23 +424,23 @@ func TestMachine_CompileGoFunctionTrampoline(t *testing.T) {
 	ldr x25, [x0, #0xc0]
 	ldr x26, [x0, #0xd0]
 	ldr x28, [x0, #0xe0]
-	ldr x30, [x0, #0xf0]
-	ldr q18, [x0, #0x100]
-	ldr q19, [x0, #0x110]
-	ldr q20, [x0, #0x120]
-	ldr q21, [x0, #0x130]
-	ldr q22, [x0, #0x140]
-	ldr q23, [x0, #0x150]
-	ldr q24, [x0, #0x160]
-	ldr q25, [x0, #0x170]
-	ldr q26, [x0, #0x180]
-	ldr q27, [x0, #0x190]
-	ldr q28, [x0, #0x1a0]
-	ldr q29, [x0, #0x1b0]
-	ldr q30, [x0, #0x1c0]
-	ldr q31, [x0, #0x1d0]
+	ldr q18, [x0, #0xf0]
+	ldr q19, [x0, #0x100]
+	ldr q20, [x0, #0x110]
+	ldr q21, [x0, #0x120]
+	ldr q22, [x0, #0x130]
+	ldr q23, [x0, #0x140]
+	ldr q24, [x0, #0x150]
+	ldr q25, [x0, #0x160]
+	ldr q26, [x0, #0x170]
+	ldr q27, [x0, #0x180]
+	ldr q28, [x0, #0x190]
+	ldr q29, [x0, #0x1a0]
+	ldr q30, [x0, #0x1b0]
+	ldr q31, [x0, #0x1c0]
 	add x15, sp, #0x10
-	add sp, sp, #0x30
+	add sp, sp, #0x20
+	ldr x30, [sp], #0x10
 	ldr w0, [x15], #0x8
 	ret
 `,
@@ -533,98 +517,43 @@ func Test_goFunctionCallLoadStackArg(t *testing.T) {
 		exp          string
 	}{
 		{
-			name:         "i32 / small offset",
-			arg:          &backend.ABIArg{Offset: 16 * 3, Type: ssa.TypeI32},
-			expResultReg: x11VReg,
-			exp: `
-	add x11, x17, #0x30
-	ldr w11, [x11, #0x8]
-`,
-		},
-		{
-			name:         "i64 / small offset",
-			arg:          &backend.ABIArg{Offset: 16 * 3, Type: ssa.TypeI64},
+			name:         "i32",
+			arg:          &backend.ABIArg{Type: ssa.TypeI32},
 			expResultReg: x11VReg,
 			exp: `
-	add x11, x17, #0x30
-	ldr x11, [x11, #0x8]
+	ldr w11, [x17], #0x8
 `,
 		},
 		{
-			name:         "i32 / large offset",
-			arg:          &backend.ABIArg{Offset: 16 * 300, Type: ssa.TypeI32},
+			name:         "i64",
+			arg:          &backend.ABIArg{Type: ssa.TypeI64},
 			expResultReg: x11VReg,
 			exp: `
-	movz x27, #0x12c0, lsl 0
-	add x11, x17, x27
-	ldr w11, [x11, #0x8]
-`,
-		},
-		{
-			name:         "i64 / large offset",
-			arg:          &backend.ABIArg{Offset: 16 * 300, Type: ssa.TypeI64},
-			expResultReg: x11VReg,
-			exp: `
-	movz x27, #0x12c0, lsl 0
-	add x11, x17, x27
-	ldr x11, [x11, #0x8]
-`,
-		},
-		{
-			name:         "f32 / small offset",
-			arg:          &backend.ABIArg{Offset: 16 * 3, Type: ssa.TypeF32},
-			expResultReg: v11VReg,
-			exp: `
-	add x11, x17, #0x30
-	ldr s11, [x11, #0x8]
-`,
-		},
-		{
-			name:         "f64 / small offset",
-			arg:          &backend.ABIArg{Offset: 16 * 3, Type: ssa.TypeF64},
-			expResultReg: v11VReg,
-			exp: `
-	add x11, x17, #0x30
-	ldr d11, [x11, #0x8]
+	ldr x11, [x17], #0x8
 `,
 		},
 		{
-			name:         "f32 / large offset",
-			arg:          &backend.ABIArg{Offset: 16 * 300, Type: ssa.TypeF32},
+			name:         "f32",
+			arg:          &backend.ABIArg{Type: ssa.TypeF32},
 			expResultReg: v11VReg,
 			exp: `
-	movz x27, #0x12c0, lsl 0
-	add x11, x17, x27
-	ldr s11, [x11, #0x8]
+	ldr s11, [x17], #0x8
 `,
 		},
 		{
-			name:         "f64 / large offset",
-			arg:          &backend.ABIArg{Offset: 16 * 300, Type: ssa.TypeF64},
+			name:         "f64",
+			arg:          &backend.ABIArg{Type: ssa.TypeF64},
 			expResultReg: v11VReg,
 			exp: `
-	movz x27, #0x12c0, lsl 0
-	add x11, x17, x27
-	ldr d11, [x11, #0x8]
+	ldr d11, [x17], #0x8
 `,
 		},
 		{
-			name:         "v128 / small offset",
-			arg:          &backend.ABIArg{Offset: 16 * 3, Type: ssa.TypeV128},
+			name:         "v128",
+			arg:          &backend.ABIArg{Type: ssa.TypeV128},
 			expResultReg: v11VReg,
 			exp: `
-	add x11, x17, #0x30
-	ldr q11, [x11, #0x10]
-`,
-		},
-		{
-			name:         "v128 / large offset",
-			arg:          &backend.ABIArg{Offset: 16 * 300, Type: ssa.TypeV128},
-			expResultReg: v11VReg,
-			exp: `
-	movz x27, #0x12c0, lsl 0
-	add x11, x17, x27
-	ldr q11, [x11, #0x10]
+	ldr q11, [x17], #0x10
 `,
 		},
 	} {
@@ -661,18 +590,7 @@ func Test_goFunctionCallStoreStackResult(t *testing.T) {
 			result:    &backend.ABIArg{Offset: 16 * 3, Type: ssa.TypeI32},
 			resultReg: x11VReg,
 			exp: `
-	add x27, sp, #0x38
-	str w11, [x27]
-`,
-		},
-		{
-			name:      "i32 / large offset",
-			result:    &backend.ABIArg{Offset: 16 * 400, Type: ssa.TypeI32},
-			resultReg: x11VReg,
-			exp: `
-	movz x27, #0x1908, lsl 0
-	add x27, sp, x27
-	str w11, [x27]
+	str w11, [sp], #0x8
 `,
 		},
 		{
@@ -680,18 +598,7 @@ func Test_goFunctionCallStoreStackResult(t *testing.T) {
 			result:    &backend.ABIArg{Offset: 16 * 3, Type: ssa.TypeI64},
 			resultReg: x11VReg,
 			exp: `
-	add x27, sp, #0x38
-	str x11, [x27]
-`,
-		},
-		{
-			name:      "i64 / large offset",
-			result:    &backend.ABIArg{Offset: 16 * 400, Type: ssa.TypeI64},
-			resultReg: x11VReg,
-			exp: `
-	movz x27, #0x1908, lsl 0
-	add x27, sp, x27
-	str x11, [x27]
+	str x11, [sp], #0x8
 `,
 		},
 		{
@@ -699,18 +606,7 @@ func Test_goFunctionCallStoreStackResult(t *testing.T) {
 			result:    &backend.ABIArg{Offset: 16 * 3, Type: ssa.TypeF32},
 			resultReg: v11VReg,
 			exp: `
-	add x27, sp, #0x38
-	str s11, [x27]
-`,
-		},
-		{
-			name:      "f32 / large offset",
-			result:    &backend.ABIArg{Offset: 16 * 400, Type: ssa.TypeF32},
-			resultReg: v11VReg,
-			exp: `
-	movz x27, #0x1908, lsl 0
-	add x27, sp, x27
-	str s11, [x27]
+	str s11, [sp], #0x8
 `,
 		},
 		{
@@ -718,18 +614,7 @@ func Test_goFunctionCallStoreStackResult(t *testing.T) {
 			result:    &backend.ABIArg{Offset: 16 * 3, Type: ssa.TypeF64},
 			resultReg: v11VReg,
 			exp: `
-	add x27, sp, #0x38
-	str d11, [x27]
-`,
-		},
-		{
-			name:      "f64 / large offset",
-			result:    &backend.ABIArg{Offset: 16 * 400, Type: ssa.TypeF64},
-			resultReg: v11VReg,
-			exp: `
-	movz x27, #0x1908, lsl 0
-	add x27, sp, x27
-	str d11, [x27]
+	str d11, [sp], #0x8
 `,
 		},
 		{
@@ -737,18 +622,7 @@ func Test_goFunctionCallStoreStackResult(t *testing.T) {
 			result:    &backend.ABIArg{Offset: 16 * 3, Type: ssa.TypeV128},
 			resultReg: v11VReg,
 			exp: `
-	add x27, sp, #0x38
-	str q11, [x27]
-`,
-		},
-		{
-			name:      "v128 / large offset",
-			result:    &backend.ABIArg{Offset: 16 * 400, Type: ssa.TypeV128},
-			resultReg: v11VReg,
-			exp: `
-	movz x27, #0x1908, lsl 0
-	add x27, sp, x27
-	str q11, [x27]
+	str q11, [sp], #0x10
 `,
 		},
 	} {
diff --git a/internal/engine/wazevo/backend/regalloc/spill_handler_test.go b/internal/engine/wazevo/backend/regalloc/spill_handler_test.go
index c82c1141..52800237 100644
--- a/internal/engine/wazevo/backend/regalloc/spill_handler_test.go
+++ b/internal/engine/wazevo/backend/regalloc/spill_handler_test.go
@@ -7,20 +7,26 @@ import (
 )
 
 func TestSpillHandler_init(t *testing.T) {
+	instr := newMockInstr().use(FromRealReg(30, RegTypeInt))
 	var s spillHandler
-	activeNodes := []*node{{r: RealReg(0)}, {r: RealReg(1)}, {r: RealReg(2)}, {v: VReg(10).SetRealReg(100)}}
-	s.init(activeNodes)
-	require.Equal(t, 4, len(s.activeRegs))
+	activeNodes := []*node{{r: RealReg(0)}, {r: RealReg(1)}, {r: RealReg(2)}, {v: VReg(10).SetRealReg(100)}, {v: VReg(10).SetRealReg(30)}}
+	s.init(activeNodes, instr)
+	require.Equal(t, 5, len(s.activeRegs))
 	for _, n := range activeNodes {
-		require.Equal(t, spillHandlerRegState{node: n, state: spillHandlerRegStateEvictable}, s.activeRegs[n.assignedRealReg()])
+		if n.r == 30 {
+			require.Equal(t, spillHandlerRegState{node: n, state: spillHandlerRegStateBeingUsedNow}, s.activeRegs[n.assignedRealReg()])
+		} else {
+			require.Equal(t, spillHandlerRegState{node: n, state: spillHandlerRegStateEvictable}, s.activeRegs[n.assignedRealReg()])
+		}
 	}
 }
 
 func TestSpillHandler_getUnusedOrEvictReg(t *testing.T) {
 	var s spillHandler
-	activeNodes := []*node{{r: RealReg(0)}, {r: RealReg(1)}, {r: RealReg(2)}}
-	s.init(activeNodes)
-	require.Equal(t, 3, len(s.activeRegs))
+	activeNodes := []*node{{r: RealReg(30)}, {r: RealReg(0)}, {r: RealReg(1)}, {r: RealReg(2)}}
+	instr := newMockInstr().use(FromRealReg(30, RegTypeInt))
+	s.init(activeNodes, instr)
+	require.Equal(t, 4, len(s.activeRegs))
 
 	regInfo := RegisterInfo{
 		AllocatableRegisters: [RegTypeNum][]RealReg{
@@ -36,27 +42,27 @@ func TestSpillHandler_getUnusedOrEvictReg(t *testing.T) {
 	r, evicted := s.getUnusedOrEvictReg(RegTypeInt, &regInfo)
 	require.Equal(t, RealReg(0xff), r)
 	require.Nil(t, evicted)
-	require.Equal(t, 4, len(s.activeRegs))
+	require.Equal(t, 5, len(s.activeRegs))
 	require.Equal(t, spillHandlerRegState{state: spillHandlerRegStateUsed}, s.activeRegs[RealReg(0xff)])
 
 	// Get unused register.
 	r, evicted = s.getUnusedOrEvictReg(RegTypeFloat, &regInfo)
 	require.Equal(t, RealReg(0xaa), r)
 	require.Nil(t, evicted)
-	require.Equal(t, 5, len(s.activeRegs))
+	require.Equal(t, 6, len(s.activeRegs))
 	require.Equal(t, spillHandlerRegState{state: spillHandlerRegStateUsed}, s.activeRegs[RealReg(0xaa)])
 
 	// Evict register.
 	r, evicted = s.getUnusedOrEvictReg(RegTypeInt, &regInfo)
 	require.Equal(t, RealReg(0), r)
-	require.Equal(t, activeNodes[0], evicted)
-	require.Equal(t, 5, len(s.activeRegs))
-	require.Equal(t, spillHandlerRegState{node: activeNodes[0], state: spillHandlerRegStateEvicted}, s.activeRegs[RealReg(0)])
+	require.Equal(t, activeNodes[1], evicted)
+	require.Equal(t, 6, len(s.activeRegs))
+	require.Equal(t, spillHandlerRegState{node: activeNodes[1], state: spillHandlerRegStateEvicted}, s.activeRegs[RealReg(0)])
 
 	// Evict again.
 	r, evicted = s.getUnusedOrEvictReg(RegTypeInt, &regInfo)
 	require.Equal(t, RealReg(1), r)
-	require.Equal(t, activeNodes[1], evicted)
-	require.Equal(t, 5, len(s.activeRegs))
-	require.Equal(t, spillHandlerRegState{node: activeNodes[1], state: spillHandlerRegStateEvicted}, s.activeRegs[RealReg(1)])
+	require.Equal(t, activeNodes[2], evicted)
+	require.Equal(t, 6, len(s.activeRegs))
+	require.Equal(t, spillHandlerRegState{node: activeNodes[2], state: spillHandlerRegStateEvicted}, s.activeRegs[RealReg(1)])
 }
diff --git a/internal/engine/wazevo/call_engine_test.go b/internal/engine/wazevo/call_engine_test.go
index f8b88423..ae3c3c12 100644
--- a/internal/engine/wazevo/call_engine_test.go
+++ b/internal/engine/wazevo/call_engine_test.go
@@ -54,3 +54,12 @@ func TestCallEngine_growStack(t *testing.T) {
 		require.True(t, newSP <= c.stackTop)
 	})
 }
+
+func TestCallEngine_requiredInitialStackSize(t *testing.T) {
+	c := &callEngine{}
+	require.Equal(t, 512, c.requiredInitialStackSize())
+	c.sizeOfParamResultSlice = 10
+	require.Equal(t, 512, c.requiredInitialStackSize())
+	c.sizeOfParamResultSlice = 120
+	require.Equal(t, 120*16+32, c.requiredInitialStackSize())
+}
diff --git a/internal/engine/wazevo/e2e_test.go b/internal/engine/wazevo/e2e_test.go
index e020b0e0..954f7d16 100644
--- a/internal/engine/wazevo/e2e_test.go
+++ b/internal/engine/wazevo/e2e_test.go
@@ -18,16 +18,18 @@ import (
 	"github.com/tetratelabs/wazero/internal/integration_test/spectest"
 	v1 "github.com/tetratelabs/wazero/internal/integration_test/spectest/v1"
 	v2 "github.com/tetratelabs/wazero/internal/integration_test/spectest/v2"
+	"github.com/tetratelabs/wazero/internal/leb128"
 	"github.com/tetratelabs/wazero/internal/testing/binaryencoding"
 	"github.com/tetratelabs/wazero/internal/testing/require"
 	"github.com/tetratelabs/wazero/internal/wasm"
 )
 
 const (
-	i32 = wasm.ValueTypeI32
-	i64 = wasm.ValueTypeI64
-	f32 = wasm.ValueTypeF32
-	f64 = wasm.ValueTypeF64
+	i32  = wasm.ValueTypeI32
+	i64  = wasm.ValueTypeI64
+	f32  = wasm.ValueTypeF32
+	f64  = wasm.ValueTypeF64
+	v128 = wasm.ValueTypeV128
 )
 
 // TODO: migrate to integration_test/spectest/v1/spec_test.go by the time when closing https://github.com/tetratelabs/wazero/issues/1496
@@ -825,24 +827,23 @@ func TestListener_imported(t *testing.T) {
 }
 
 func TestListener_long(t *testing.T) {
-	t.Skip("TODO")
 	pickOneParam := binaryencoding.EncodeModule(&wasm.Module{
 		TypeSection: []wasm.FunctionType{{Results: []wasm.ValueType{i32}, Params: []wasm.ValueType{
-			i32, i32, i32, i32, i32, i32, i32, i32, i32, i32,
-			i32, i32, i32, i32, i32, i32, i32, i32, i32, i32,
-			i32, i32, i32, i32, i32, i32, i32, i32, i32, i32,
-			i32, i32, i32, i32, i32, i32, i32, i32, i32, i32,
-			i32, i32, i32, i32, i32, i32, i32, i32, i32, i32,
-			i32, i32, i32, i32, i32, i32, i32, i32, i32, i32,
-			i32, i32, i32, i32, i32, i32, i32, i32, i32, i32,
-			i32, i32, i32, i32, i32, i32, i32, i32, i32, i32,
-			i32, i32, i32, i32, i32, i32, i32, i32, i32, i32,
-			i32, i32, i32, i32, i32, i32, i32, i32, i32, i32,
+			i32, i32, f32, f64, i64, i32, i32, v128, f32,
+			i32, i32, f32, f64, i64, i32, i32, v128, f32,
+			i32, i32, f32, f64, i64, i32, i32, v128, f32,
+			i32, i32, f32, f64, i64, i32, i32, v128, f32,
+			i32, i32, f32, f64, i64, i32, i32, v128, f32,
+			i32, i32, f32, f64, i64, i32, i32, v128, f32,
+			i32, i32, f32, f64, i64, i32, i32, v128, f32,
+			i32, i32, f32, f64, i64, i32, i32, v128, f32,
+			i32, i32, f32, f64, i64, i32, i32, v128, f32,
+			i32, i32, f32, f64, i64, i32, i32, v128, f32,
 		}}},
 		ExportSection:   []wasm.Export{{Name: "main", Type: wasm.ExternTypeFunc, Index: 0}},
 		FunctionSection: []wasm.Index{0},
 		CodeSection: []wasm.Code{
-			{Body: []byte{wasm.OpcodeLocalGet, 98, wasm.OpcodeEnd}},
+			{Body: []byte{wasm.OpcodeLocalGet, 10, wasm.OpcodeEnd}},
 		},
 	})
 
@@ -864,8 +865,116 @@ func TestListener_long(t *testing.T) {
 	f := inst.ExportedFunction("main")
 	require.NotNil(t, f)
 	param := make([]uint64, 100)
-	param[98] = 100
+	for i := range param {
+		param[i] = uint64(i)
+	}
 	res, err := f.Call(ctx, param...)
 	require.NoError(t, err)
-	require.Equal(t, []uint64{100}, res)
+	require.Equal(t, []uint64{0xb}, res)
+
+	require.Equal(t, `
+--> .$0(0,1,3e-45,1.5e-323,4,5,6,00000000000000070000000000000008,1.1e-44,9,10,1.5e-44,6e-323,13,14,15,00000000000000100000000000000011,2.4e-44,18,19,2.8e-44,1.04e-322,22,23,24,0000000000000019000000000000001a,3.6e-44,27,28,4e-44,1.5e-322,31,32,33,00000000000000220000000000000023,4.9e-44,36,37,5.3e-44,1.93e-322,40,41,42,000000000000002b000000000000002c,6.2e-44,45,46,6.6e-44,2.37e-322,49,50,51,00000000000000340000000000000035,7.4e-44,54,55,7.8e-44,2.8e-322,58,59,60,000000000000003d000000000000003e,8.7e-44,63,64,9.1e-44,3.26e-322,67,68,69,00000000000000460000000000000047,1e-43,72,73,1.04e-43,3.7e-322,76,77,78,000000000000004f0000000000000050,1.12e-43,81,82,1.16e-43,4.15e-322,85,86,87,00000000000000580000000000000059,1.25e-43)
+<-- 11
+`, "\n"+buf.String())
+}
+
+func TestListener_long_as_is(t *testing.T) {
+	params := []wasm.ValueType{
+		i32, i64, i32, i64, i32, i64, i32, i64, i32, i64,
+		i32, i64, i32, i64, i32, i64, i32, i64, i32, i64,
+	}
+
+	const paramNum = 20
+
+	var body []byte
+	for i := 0; i < paramNum; i++ {
+		body = append(body, wasm.OpcodeLocalGet)
+		body = append(body, leb128.EncodeUint32(uint32(i))...)
+	}
+	body = append(body, wasm.OpcodeEnd)
+
+	bin := binaryencoding.EncodeModule(&wasm.Module{
+		TypeSection:     []wasm.FunctionType{{Results: params, Params: params}},
+		ExportSection:   []wasm.Export{{Name: "main", Type: wasm.ExternTypeFunc, Index: 0}},
+		FunctionSection: []wasm.Index{0},
+		CodeSection:     []wasm.Code{{Body: body}},
+	})
+
+	var buf bytes.Buffer
+	config := wazero.NewRuntimeConfigCompiler()
+	ctx := context.WithValue(context.Background(), experimental.FunctionListenerFactoryKey{}, logging.NewLoggingListenerFactory(&buf))
+
+	// Configure the new optimizing backend!
+	wazevo.ConfigureWazevo(config)
+
+	r := wazero.NewRuntimeWithConfig(ctx, config)
+	defer func() {
+		require.NoError(t, r.Close(ctx))
+	}()
+
+	inst, err := r.Instantiate(ctx, bin)
+	require.NoError(t, err)
+
+	f := inst.ExportedFunction("main")
+	require.NotNil(t, f)
+	param := make([]uint64, paramNum)
+	for i := range param {
+		param[i] = uint64(i)
+	}
+	res, err := f.Call(ctx, param...)
+	require.NoError(t, err)
+	require.Equal(t, param, res)
+
+	require.Equal(t, `
+--> .$0(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19)
+<-- (0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19)
+`, "\n"+buf.String())
+}
+
+func TestListener_long_many_consts(t *testing.T) {
+	const paramNum = 61
+
+	var exp []uint64
+	var body []byte
+	var resultTypes []wasm.ValueType
+	for i := 0; i < paramNum; i++ {
+		exp = append(exp, uint64(i))
+		resultTypes = append(resultTypes, i32)
+		body = append(body, wasm.OpcodeI32Const)
+		body = append(body, leb128.EncodeInt32(int32(i))...)
+	}
+	body = append(body, wasm.OpcodeEnd)
+
+	bin := binaryencoding.EncodeModule(&wasm.Module{
+		TypeSection:     []wasm.FunctionType{{Results: resultTypes}},
+		ExportSection:   []wasm.Export{{Name: "main", Type: wasm.ExternTypeFunc, Index: 0}},
+		FunctionSection: []wasm.Index{0},
+		CodeSection:     []wasm.Code{{Body: body}},
+	})
+
+	var buf bytes.Buffer
+	config := wazero.NewRuntimeConfigCompiler()
+	ctx := context.WithValue(context.Background(), experimental.FunctionListenerFactoryKey{}, logging.NewLoggingListenerFactory(&buf))
+
+	// Configure the new optimizing backend!
+	wazevo.ConfigureWazevo(config)
+
+	r := wazero.NewRuntimeWithConfig(ctx, config)
+	defer func() {
+		require.NoError(t, r.Close(ctx))
+	}()
+
+	inst, err := r.Instantiate(ctx, bin)
+	require.NoError(t, err)
+
+	f := inst.ExportedFunction("main")
+	require.NotNil(t, f)
+	res, err := f.Call(ctx)
+	require.NoError(t, err)
+	require.Equal(t, exp, res)
+
+	require.Equal(t, `
+--> .$0()
+<-- (0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60)
+`, "\n"+buf.String())
 }
diff --git a/internal/integration_test/engine/adhoc_test.go b/internal/integration_test/engine/adhoc_test.go
index 7fc6af6c..cf2589e4 100644
--- a/internal/integration_test/engine/adhoc_test.go
+++ b/internal/integration_test/engine/adhoc_test.go
@@ -5,6 +5,7 @@ import (
 	"context"
 	_ "embed"
 	"errors"
+	"fmt"
 	"math"
 	"runtime"
 	"strconv"
@@ -62,10 +63,15 @@ var tests = map[string]testCase{
 	"before listener stack iterator":                                   {f: testBeforeListenerStackIterator},
 	"before listener stack iterator offsets":                           {f: testListenerStackIteratorOffset, wazevoSkip: true},
 	"many params many results / doubler":                               {f: testManyParamsResultsDoubler},
+	"many params many results / doubler / listener":                    {f: testManyParamsResultsDoublerListener},
 	"many params many results / call_many_consts":                      {f: testManyParamsResultsCallManyConsts},
+	"many params many results / call_many_consts / listener":           {f: testManyParamsResultsCallManyConstsListener},
 	"many params many results / swapper":                               {f: testManyParamsResultsSwapper},
+	"many params many results / swapper / listener":                    {f: testManyParamsResultsSwapperListener},
 	"many params many results / main":                                  {f: testManyParamsResultsMain},
+	"many params many results / main / listener":                       {f: testManyParamsResultsMainListener},
 	"many params many results / call_many_consts_and_pick_last_vector": {f: testManyParamsResultsCallManyConstsAndPickLastVector},
+	"many params many results / call_many_consts_and_pick_last_vector / listener": {f: testManyParamsResultsCallManyConstsAndPickLastVectorListener},
 }
 
 func TestEngineCompiler(t *testing.T) {
@@ -1715,8 +1721,30 @@ func manyParamsResultsMod() (bin []byte, params []uint64) {
 	var callManyConstsAndPickLastVector []byte
 	callManyConstsAndPickLastVector = append(callManyConstsAndPickLastVector, wasm.OpcodeCall, 5, wasm.OpcodeCall, 6, wasm.OpcodeEnd)
 
+	nameSection := wasm.NameSection{}
+	nameSection.FunctionNames = []wasm.NameAssoc{
+		{Index: 0, Name: "main"},
+		{Index: 1, Name: "swapper"},
+		{Index: 2, Name: "doubler"},
+		{Index: 3, Name: "call_many_consts"},
+		{Index: 4, Name: "call_many_consts_and_pick_last_vector"},
+		{Index: 5, Name: "many_consts"},
+		{Index: 6, Name: "pick_last_vector"},
+	}
+
+	typeSection := []wasm.FunctionType{mainType, swapperType, doublerType, callManyConstsType, callManyConstsAndPickLastVectorType, manyConstsType, pickLastVectorType}
+
+	for i, typ := range typeSection {
+		paramNames := wasm.NameMapAssoc{Index: wasm.Index(i)}
+		for paramIndex, paramType := range typ.Params {
+			name := fmt.Sprintf("[%d:%s]", paramIndex, wasm.ValueTypeName(paramType))
+			paramNames.NameMap = append(paramNames.NameMap, wasm.NameAssoc{Index: wasm.Index(paramIndex), Name: name})
+		}
+		nameSection.LocalNames = append(nameSection.LocalNames, paramNames)
+	}
+
 	bin = binaryencoding.EncodeModule(&wasm.Module{
-		TypeSection: []wasm.FunctionType{mainType, swapperType, doublerType, callManyConstsType, callManyConstsAndPickLastVectorType, manyConstsType, pickLastVectorType},
+		TypeSection: typeSection,
 		ExportSection: []wasm.Export{
 			{Name: "main", Type: wasm.ExternTypeFunc, Index: 0},
 			{Name: "swapper", Type: wasm.ExternTypeFunc, Index: 1},
@@ -1734,6 +1762,7 @@ func manyParamsResultsMod() (bin []byte, params []uint64) {
 			{Body: manyConstsBody},
 			{Body: pickLastVector},
 		},
+		NameSection: &nameSection,
 	})
 
 	for i := 0; i < 100; i += 5 {
@@ -1749,14 +1778,16 @@ func manyParamsResultsMod() (bin []byte, params []uint64) {
 }
 
 func testManyParamsResultsCallManyConsts(t *testing.T, r wazero.Runtime) {
+	ctx := context.Background()
+
 	bin, _ := manyParamsResultsMod()
-	mod, err := r.Instantiate(testCtx, bin)
+	mod, err := r.Instantiate(ctx, bin)
 	require.NoError(t, err)
 
 	main := mod.ExportedFunction("call_many_consts")
 	require.NotNil(t, main)
 
-	results, err := main.Call(testCtx)
+	results, err := main.Call(ctx)
 	require.NoError(t, err)
 
 	exp := []uint64{
@@ -1780,16 +1811,97 @@ func testManyParamsResultsCallManyConsts(t *testing.T, r wazero.Runtime) {
 	require.Equal(t, exp, results)
 }
 
+func testManyParamsResultsCallManyConstsListener(t *testing.T, r wazero.Runtime) {
+	var buf bytes.Buffer
+	ctx := context.WithValue(context.Background(), experimental.FunctionListenerFactoryKey{}, logging.NewLoggingListenerFactory(&buf))
+
+	bin, _ := manyParamsResultsMod()
+	mod, err := r.Instantiate(ctx, bin)
+	require.NoError(t, err)
+
+	main := mod.ExportedFunction("call_many_consts")
+	require.NotNil(t, main)
+
+	results, err := main.Call(ctx)
+	require.NoError(t, err)
+
+	fmt.Println(buf.String())
+	require.Equal(t, `
+--> .call_many_consts()
+	--> .many_consts()
+	<-- (0,0,0,0,00000000000000000000000000000000,0,5,7e-45,4.16077606e-316,05050505050505050505050505050505,84215045,361700864190383365,1.4e-44,5e-323,000000000a0a0a0a0a0a0a0a0a0a0a0a,168430090,723401728380766730,6.6463464e-33,7.4e-323,000000000000000f000000000f0f0f0f,252645135,1085102592571150095,7.0533445e-30,3.815736827118017e-236,00000000000000140000000000000014,20,336860180,7.47605e-27,5.964208835435795e-212,14141414141414140000000000000019,25,25,7.914983e-24,9.01285756841504e-188,19191919191919191919191919191919,421075225,30,4.2e-44,2.496465636e-315,1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e,505290270,2170205185142300190,4.9e-44,1.73e-322,00000000232323232323232323232323,589505315,2531906049332683555,8.843688e-18,2e-322,00000000000000280000000028282828,673720360,2893606913523066920,9.334581e-15,3.0654356309538037e-115,000000000000002d000000000000002d,45,757935405,9.8439425e-12,4.4759381595361623e-91,2d2d2d2d2d2d2d2d0000000000000032,50,50,1.0372377e-08,6.749300603603778e-67,32323232323232323232323232323232,842150450,55,7.7e-44,4.576853666e-315,37373737373737373737373737373737,926365495,3978709506094217015,8.4e-44,2.96e-322,000000003c3c3c3c3c3c3c3c3c3c3c3c,1010580540,4340410370284600380,0.01148897,3.2e-322,00000000000000410000000041414141,1094795585,4702111234474983745,12.078431,2.2616345098039214e+06,00000000000000460000000000000046,70,1179010630,12689.568,3.5295369653413445e+30,4646464646464646000000000000004b,75,75,1.3323083e+07,5.2285141982483265e+54,4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b,1263225675,80,1.12e-43,6.657241696e-315,50505050505050505050505050505050)
+<-- (0,0,0,0,00000000000000000000000000000000,0,5,7e-45,4.16077606e-316,05050505050505050505050505050505,84215045,361700864190383365,1.4e-44,5e-323,000000000a0a0a0a0a0a0a0a0a0a0a0a,168430090,723401728380766730,6.6463464e-33,7.4e-323,000000000000000f000000000f0f0f0f,252645135,1085102592571150095,7.0533445e-30,3.815736827118017e-236,00000000000000140000000000000014,20,336860180,7.47605e-27,5.964208835435795e-212,14141414141414140000000000000019,25,25,7.914983e-24,9.01285756841504e-188,19191919191919191919191919191919,421075225,30,4.2e-44,2.496465636e-315,1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e,505290270,2170205185142300190,4.9e-44,1.73e-322,00000000232323232323232323232323,589505315,2531906049332683555,8.843688e-18,2e-322,00000000000000280000000028282828,673720360,2893606913523066920,9.334581e-15,3.0654356309538037e-115,000000000000002d000000000000002d,45,757935405,9.8439425e-12,4.4759381595361623e-91,2d2d2d2d2d2d2d2d0000000000000032,50,50,1.0372377e-08,6.749300603603778e-67,32323232323232323232323232323232,842150450,55,7.7e-44,4.576853666e-315,37373737373737373737373737373737,926365495,3978709506094217015,8.4e-44,2.96e-322,000000003c3c3c3c3c3c3c3c3c3c3c3c,1010580540,4340410370284600380,0.01148897,3.2e-322,00000000000000410000000041414141,1094795585,4702111234474983745,12.078431,2.2616345098039214e+06,00000000000000460000000000000046,70,1179010630,12689.568,3.5295369653413445e+30,4646464646464646000000000000004b,75,75,1.3323083e+07,5.2285141982483265e+54,4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b,1263225675,80,1.12e-43,6.657241696e-315,50505050505050505050505050505050)
+`, "\n"+buf.String())
+
+	exp := []uint64{
+		0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5, 0x5, 0x5050505, 0x505050505050505, 0x505050505050505,
+		0x505050505050505, 0xa, 0xa, 0xa0a0a0a, 0xa0a0a0a0a0a0a0a, 0xa0a0a0a0a0a0a0a, 0xa0a0a0a0a0a0a0a,
+		0xf, 0xf, 0xf0f0f0f, 0xf0f0f0f0f0f0f0f, 0xf0f0f0f0f0f0f0f, 0xf0f0f0f0f0f0f0f, 0x14, 0x14, 0x14141414,
+		0x1414141414141414, 0x1414141414141414, 0x1414141414141414, 0x19, 0x19, 0x19191919, 0x1919191919191919,
+		0x1919191919191919, 0x1919191919191919, 0x1e, 0x1e, 0x1e1e1e1e, 0x1e1e1e1e1e1e1e1e, 0x1e1e1e1e1e1e1e1e,
+		0x1e1e1e1e1e1e1e1e, 0x23, 0x23, 0x23232323, 0x2323232323232323, 0x2323232323232323, 0x2323232323232323,
+		0x28, 0x28, 0x28282828, 0x2828282828282828, 0x2828282828282828, 0x2828282828282828, 0x2d, 0x2d, 0x2d2d2d2d,
+		0x2d2d2d2d2d2d2d2d, 0x2d2d2d2d2d2d2d2d, 0x2d2d2d2d2d2d2d2d, 0x32, 0x32, 0x32323232, 0x3232323232323232,
+		0x3232323232323232, 0x3232323232323232, 0x37, 0x37, 0x37373737, 0x3737373737373737, 0x3737373737373737,
+		0x3737373737373737, 0x3c, 0x3c, 0x3c3c3c3c, 0x3c3c3c3c3c3c3c3c, 0x3c3c3c3c3c3c3c3c, 0x3c3c3c3c3c3c3c3c,
+		0x41, 0x41, 0x41414141, 0x4141414141414141, 0x4141414141414141, 0x4141414141414141, 0x46, 0x46, 0x46464646,
+		0x4646464646464646, 0x4646464646464646, 0x4646464646464646, 0x4b, 0x4b, 0x4b4b4b4b, 0x4b4b4b4b4b4b4b4b,
+		0x4b4b4b4b4b4b4b4b, 0x4b4b4b4b4b4b4b4b, 0x50, 0x50, 0x50505050, 0x5050505050505050, 0x5050505050505050,
+		0x5050505050505050, 0x55, 0x55, 0x55555555, 0x5555555555555555, 0x5555555555555555, 0x5555555555555555,
+		0x5a, 0x5a, 0x5a5a5a5a, 0x5a5a5a5a5a5a5a5a, 0x5a5a5a5a5a5a5a5a, 0x5a5a5a5a5a5a5a5a, 0x5f, 0x5f, 0x5f5f5f5f,
+		0x5f5f5f5f5f5f5f5f, 0x5f5f5f5f5f5f5f5f, 0x5f5f5f5f5f5f5f5f,
+	}
+	require.Equal(t, exp, results)
+}
+
 func testManyParamsResultsDoubler(t *testing.T, r wazero.Runtime) {
+	ctx := context.Background()
+
 	bin, params := manyParamsResultsMod()
-	mod, err := r.Instantiate(testCtx, bin)
+	mod, err := r.Instantiate(ctx, bin)
 	require.NoError(t, err)
 
 	main := mod.ExportedFunction("doubler")
 	require.NotNil(t, main)
 
-	results, err := main.Call(testCtx, params...)
+	results, err := main.Call(ctx, params...)
 	require.NoError(t, err)
+
+	exp := []uint64{
+		0x0, 0x1, 0x4, 0x6, 0x6, 0x6, 0x5, 0x6, 0xe, 0x10, 0x10, 0x10, 0xa,
+		0xb, 0x18, 0x1a, 0x1a, 0x1a, 0xf, 0x10, 0x22, 0x24, 0x24, 0x24, 0x14,
+		0x15, 0x2c, 0x2e, 0x2e, 0x2e, 0x19, 0x1a, 0x36, 0x38, 0x38, 0x38, 0x1e,
+		0x1f, 0x40, 0x42, 0x42, 0x42, 0x23, 0x24, 0x4a, 0x4c, 0x4c, 0x4c, 0x28,
+		0x29, 0x54, 0x56, 0x56, 0x56, 0x2d, 0x2e, 0x5e, 0x60, 0x60, 0x60, 0x32,
+		0x33, 0x68, 0x6a, 0x6a, 0x6a, 0x37, 0x38, 0x72, 0x74, 0x74, 0x74, 0x3c,
+		0x3d, 0x7c, 0x7e, 0x7e, 0x7e, 0x41, 0x42, 0x86, 0x88, 0x88, 0x88, 0x46,
+		0x47, 0x90, 0x92, 0x92, 0x92, 0x4b, 0x4c, 0x9a, 0x9c, 0x9c, 0x9c, 0x50,
+		0x51, 0xa4, 0xa6, 0xa6, 0xa6, 0x55, 0x56, 0xae, 0xb0, 0xb0, 0xb0, 0x5a,
+		0x5b, 0xb8, 0xba, 0xba, 0xba, 0x5f, 0x60, 0xc2, 0xc4, 0xc4, 0xc4,
+	}
+	require.Equal(t, exp, results)
+}
+
+func testManyParamsResultsDoublerListener(t *testing.T, r wazero.Runtime) {
+	var buf bytes.Buffer
+	ctx := context.WithValue(context.Background(), experimental.FunctionListenerFactoryKey{}, logging.NewLoggingListenerFactory(&buf))
+
+	bin, params := manyParamsResultsMod()
+	mod, err := r.Instantiate(ctx, bin)
+	require.NoError(t, err)
+
+	main := mod.ExportedFunction("doubler")
+	require.NotNil(t, main)
+
+	results, err := main.Call(ctx, params...)
+	require.NoError(t, err)
+
+	fmt.Println(buf.String())
+	require.Equal(t, `
+--> .doubler([0:v128]=00000000000000000000000000000001,[1:f64]=5e-324,[2:f32]=3e-45,[3:i64]=3,[4:i32]=3,[5:v128]=00000000000000030000000000000005,[6:f64]=2.5e-323,[7:f32]=8e-45,[8:i64]=7,[9:i32]=8,[10:v128]=00000000000000080000000000000008,[11:f64]=4e-323,[12:f32]=1.4e-44,[13:i64]=11,[14:i32]=12,[15:v128]=000000000000000d000000000000000d,[16:f64]=6.4e-323,[17:f32]=1.8e-44,[18:i64]=15,[19:i32]=16,[20:v128]=00000000000000110000000000000012,[21:f64]=9e-323,[22:f32]=2.5e-44,[23:i64]=18,[24:i32]=20,[25:v128]=00000000000000150000000000000016,[26:f64]=1.1e-322,[27:f32]=3.2e-44,[28:i64]=23,[29:i32]=23,[30:v128]=0000000000000019000000000000001a,[31:f64]=1.3e-322,[32:f32]=3.8e-44,[33:i64]=28,[34:i32]=28,[35:v128]=000000000000001c000000000000001e,[36:f64]=1.5e-322,[37:f32]=4.3e-44,[38:i64]=32,[39:i32]=33,[40:v128]=00000000000000210000000000000021,[41:f64]=1.63e-322,[42:f32]=4.9e-44,[43:i64]=36,[44:i32]=37,[45:v128]=00000000000000260000000000000026,[46:f64]=1.9e-322,[47:f32]=5.3e-44,[48:i64]=40,[49:i32]=41,[50:v128]=000000000000002a000000000000002b,[51:f64]=2.1e-322,[52:f32]=6e-44,[53:i64]=43,[54:i32]=45,[55:v128]=000000000000002e000000000000002f,[56:f64]=2.3e-322,[57:f32]=6.7e-44,[58:i64]=48,[59:i32]=48,[60:v128]=00000000000000320000000000000033,[61:f64]=2.5e-322,[62:f32]=7.3e-44,[63:i64]=53,[64:i32]=53,[65:v128]=00000000000000350000000000000037,[66:f64]=2.7e-322,[67:f32]=7.8e-44,[68:i64]=57,[69:i32]=58,[70:v128]=000000000000003a000000000000003a,[71:f64]=2.87e-322,[72:f32]=8.4e-44,[73:i64]=61,[74:i32]=62,[75:v128]=000000000000003f000000000000003f,[76:f64]=3.1e-322,[77:f32]=8.8e-44,[78:i64]=65,[79:i32]=66,[80:v128]=00000000000000430000000000000044,[81:f64]=3.36e-322,[82:f32]=9.5e-44,[83:i64]=68,[84:i32]=70,[85:v128]=00000000000000470000000000000048,[86:f64]=3.56e-322,[87:f32]=1.02e-43,[88:i64]=73,[89:i32]=73,[90:v128]=000000000000004b000000000000004c,[91:f64]=3.75e-322,[92:f32]=1.08e-43,[93:i64]=78,[94:i32]=78,[95:v128]=000000000000004e0000000000000050,[96:f64]=3.95e-322,[97:f32]=1.14e-43,[98:i64]=82,[99:i32]=83)
+<-- (00000000000000000000000000000001,5e-324,6e-45,6,6,00000000000000060000000000000005,2.5e-323,8e-45,14,16,00000000000000100000000000000010,8e-323,1.4e-44,11,24,000000000000001a000000000000001a,1.3e-322,3.6e-44,15,16,00000000000000220000000000000024,1.8e-322,5e-44,36,20,0000000000000015000000000000002c,2.17e-322,6.4e-44,46,46,0000000000000019000000000000001a,1.3e-322,7.6e-44,56,56,0000000000000038000000000000001e,1.5e-322,4.3e-44,64,66,00000000000000420000000000000042,3.26e-322,4.9e-44,36,74,000000000000004c000000000000004c,3.75e-322,1.06e-43,40,41,00000000000000540000000000000056,4.25e-322,1.2e-43,86,45,000000000000002e000000000000005e,4.64e-322,1.35e-43,96,96,00000000000000320000000000000033,2.5e-322,1.46e-43,106,106,000000000000006a0000000000000037,2.7e-322,7.8e-44,114,116,00000000000000740000000000000074,5.73e-322,8.4e-44,61,124,000000000000007e000000000000007e,6.23e-322,1.77e-43,65,66,00000000000000860000000000000088,6.7e-322,1.9e-43,136,70,00000000000000470000000000000090,7.1e-322,2.05e-43,146,146,000000000000004b000000000000004c,3.75e-322,2.16e-43,156,156,000000000000009c0000000000000050,3.95e-322,1.14e-43,164,166)
+`, "\n"+buf.String())
+
 	exp := []uint64{
 		0x0, 0x1, 0x4, 0x6, 0x6, 0x6, 0x5, 0x6, 0xe, 0x10, 0x10, 0x10, 0xa,
 		0xb, 0x18, 0x1a, 0x1a, 0x1a, 0xf, 0x10, 0x22, 0x24, 0x24, 0x24, 0x14,
@@ -1806,15 +1918,51 @@ func testManyParamsResultsDoubler(t *testing.T, r wazero.Runtime) {
 }
 
 func testManyParamsResultsSwapper(t *testing.T, r wazero.Runtime) {
+	ctx := context.Background()
+
 	bin, params := manyParamsResultsMod()
-	mod, err := r.Instantiate(testCtx, bin)
+	mod, err := r.Instantiate(ctx, bin)
 	require.NoError(t, err)
 
 	main := mod.ExportedFunction("swapper")
 	require.NotNil(t, main)
 
-	results, err := main.Call(testCtx, params...)
+	results, err := main.Call(ctx, params...)
 	require.NoError(t, err)
+
+	exp := []uint64{
+		0x62, 0x62, 0x62, 0x61, 0x60, 0x5f, 0x5d, 0x5d, 0x5d, 0x5c, 0x5b, 0x5a, 0x58, 0x58, 0x58, 0x57,
+		0x56, 0x55, 0x53, 0x53, 0x53, 0x52, 0x51, 0x50, 0x4e, 0x4e, 0x4e, 0x4d, 0x4c, 0x4b, 0x49, 0x49,
+		0x49, 0x48, 0x47, 0x46, 0x44, 0x44, 0x44, 0x43, 0x42, 0x41, 0x3f, 0x3f, 0x3f, 0x3e, 0x3d, 0x3c,
+		0x3a, 0x3a, 0x3a, 0x39, 0x38, 0x37, 0x35, 0x35, 0x35, 0x34, 0x33, 0x32, 0x30, 0x30, 0x30, 0x2f,
+		0x2e, 0x2d, 0x2b, 0x2b, 0x2b, 0x2a, 0x29, 0x28, 0x26, 0x26, 0x26, 0x25, 0x24, 0x23, 0x21, 0x21,
+		0x21, 0x20, 0x1f, 0x1e, 0x1c, 0x1c, 0x1c, 0x1b, 0x1a, 0x19, 0x17, 0x17, 0x17, 0x16, 0x15, 0x14,
+		0x12, 0x12, 0x12, 0x11, 0x10, 0xf, 0xd, 0xd, 0xd, 0xc, 0xb, 0xa, 0x8, 0x8, 0x8, 0x7, 0x6, 0x5,
+		0x3, 0x3, 0x3, 0x2, 0x1, 0x0,
+	}
+	require.Equal(t, exp, results)
+}
+
+func testManyParamsResultsSwapperListener(t *testing.T, r wazero.Runtime) {
+	var buf bytes.Buffer
+	ctx := context.WithValue(context.Background(), experimental.FunctionListenerFactoryKey{}, logging.NewLoggingListenerFactory(&buf))
+
+	bin, params := manyParamsResultsMod()
+	mod, err := r.Instantiate(ctx, bin)
+	require.NoError(t, err)
+
+	main := mod.ExportedFunction("swapper")
+	require.NotNil(t, main)
+
+	results, err := main.Call(ctx, params...)
+	require.NoError(t, err)
+
+	fmt.Println(buf.String())
+	require.Equal(t, `
+--> .swapper([0:i32]=0,[1:i64]=1,[2:f32]=3e-45,[3:f64]=1.5e-323,[4:v128]=00000000000000030000000000000003,[5:i32]=3,[6:i64]=5,[7:f32]=8e-45,[8:f64]=3.5e-323,[9:v128]=00000000000000080000000000000008,[10:i32]=8,[11:i64]=8,[12:f32]=1.4e-44,[13:f64]=5.4e-323,[14:v128]=000000000000000c000000000000000d,[15:i32]=13,[16:i64]=13,[17:f32]=1.8e-44,[18:f64]=7.4e-323,[19:v128]=00000000000000100000000000000011,[20:i32]=17,[21:i64]=18,[22:f32]=2.5e-44,[23:f64]=9e-323,[24:v128]=00000000000000140000000000000015,[25:i32]=21,[26:i64]=22,[27:f32]=3.2e-44,[28:f64]=1.14e-322,[29:v128]=00000000000000170000000000000019,[30:i32]=25,[31:i64]=26,[32:f32]=3.8e-44,[33:f64]=1.4e-322,[34:v128]=000000000000001c000000000000001c,[35:i32]=28,[36:i64]=30,[37:f32]=4.3e-44,[38:f64]=1.6e-322,[39:v128]=00000000000000210000000000000021,[40:i32]=33,[41:i64]=33,[42:f32]=4.9e-44,[43:f64]=1.8e-322,[44:v128]=00000000000000250000000000000026,[45:i32]=38,[46:i64]=38,[47:f32]=5.3e-44,[48:f64]=2e-322,[49:v128]=0000000000000029000000000000002a,[50:i32]=42,[51:i64]=43,[52:f32]=6e-44,[53:f64]=2.1e-322,[54:v128]=000000000000002d000000000000002e,[55:i32]=46,[56:i64]=47,[57:f32]=6.7e-44,[58:f64]=2.37e-322,[59:v128]=00000000000000300000000000000032,[60:i32]=50,[61:i64]=51,[62:f32]=7.3e-44,[63:f64]=2.6e-322,[64:v128]=00000000000000350000000000000035,[65:i32]=53,[66:i64]=55,[67:f32]=7.8e-44,[68:f64]=2.8e-322,[69:v128]=000000000000003a000000000000003a,[70:i32]=58,[71:i64]=58,[72:f32]=8.4e-44,[73:f64]=3e-322,[74:v128]=000000000000003e000000000000003f,[75:i32]=63,[76:i64]=63,[77:f32]=8.8e-44,[78:f64]=3.2e-322,[79:v128]=00000000000000420000000000000043,[80:i32]=67,[81:i64]=68,[82:f32]=9.5e-44,[83:f64]=3.36e-322,[84:v128]=00000000000000460000000000000047,[85:i32]=71,[86:i64]=72,[87:f32]=1.02e-43,[88:f64]=3.6e-322,[89:v128]=0000000000000049000000000000004b,[90:i32]=75,[91:i64]=76,[92:f32]=1.08e-43,[93:f64]=3.85e-322,[94:v128]=000000000000004e000000000000004e,[95:i32]=78,[96:i64]=80,[97:f32]=1.14e-43,[98:f64]=4.05e-322,[99:v128]=00000000000000530000000000000053)
+<-- (00000000000000620000000000000062,4.84e-322,1.37e-43,97,96,000000000000005f000000000000005d,4.6e-322,1.3e-43,93,92,000000000000005b000000000000005a,4.45e-322,1.23e-43,88,88,00000000000000570000000000000056,4.25e-322,1.19e-43,83,83,00000000000000530000000000000052,4.05e-322,1.14e-43,80,78,000000000000004e000000000000004e,3.85e-322,1.08e-43,76,75,00000000000000490000000000000049,3.6e-322,1.02e-43,72,71,00000000000000460000000000000044,3.36e-322,9.5e-44,68,67,00000000000000420000000000000041,3.2e-322,8.8e-44,63,63,000000000000003e000000000000003d,3e-322,8.4e-44,58,58,000000000000003a0000000000000039,2.8e-322,7.8e-44,55,53,00000000000000350000000000000035,2.6e-322,7.3e-44,51,50,00000000000000300000000000000030,2.37e-322,6.7e-44,47,46,000000000000002d000000000000002b,2.1e-322,6e-44,43,42,00000000000000290000000000000028,2e-322,5.3e-44,38,38,00000000000000250000000000000024,1.8e-322,4.9e-44,33,33,00000000000000210000000000000020,1.6e-322,4.3e-44,30,28,000000000000001c000000000000001c,1.4e-322,3.8e-44,26,25,00000000000000170000000000000017,1.14e-322,3.2e-44,22,21,00000000000000140000000000000012,9e-323,2.5e-44,18,17)
+`, "\n"+buf.String())
+
 	exp := []uint64{
 		0x62, 0x62, 0x62, 0x61, 0x60, 0x5f, 0x5d, 0x5d, 0x5d, 0x5c, 0x5b, 0x5a, 0x58, 0x58, 0x58, 0x57,
 		0x56, 0x55, 0x53, 0x53, 0x53, 0x52, 0x51, 0x50, 0x4e, 0x4e, 0x4e, 0x4d, 0x4c, 0x4b, 0x49, 0x49,
@@ -1829,15 +1977,52 @@ func testManyParamsResultsSwapper(t *testing.T, r wazero.Runtime) {
 }
 
 func testManyParamsResultsMain(t *testing.T, r wazero.Runtime) {
+	ctx := context.Background()
+
+	bin, params := manyParamsResultsMod()
+	mod, err := r.Instantiate(ctx, bin)
+	require.NoError(t, err)
+
+	main := mod.ExportedFunction("main")
+	require.NotNil(t, main)
+
+	results, err := main.Call(ctx, params...)
+	require.NoError(t, err)
+
+	exp := []uint64{
+		98, 98, 196, 194, 192, 190, 93, 93, 186, 184, 182, 180, 88, 88, 176, 174, 172, 170, 83, 83, 166, 164, 162,
+		160, 78, 78, 156, 154, 152, 150, 73, 73, 146, 144, 142, 140, 68, 68, 136, 134, 132, 130, 63, 63, 126, 124,
+		122, 120, 58, 58, 116, 114, 112, 110, 53, 53, 106, 104, 102, 100, 48, 48, 96, 94, 92, 90, 43, 43, 86, 84,
+		82, 80, 38, 38, 76, 74, 72, 70, 33, 33, 66, 64, 62, 60, 28, 28, 56, 54, 52, 50, 23, 23, 46, 44, 42, 40, 18,
+		18, 36, 34, 32, 30, 13, 13, 26, 24, 22, 20, 8, 8, 16, 14, 12, 10, 3, 3, 6, 4, 2, 0,
+	}
+	require.Equal(t, exp, results)
+}
+
+func testManyParamsResultsMainListener(t *testing.T, r wazero.Runtime) {
+	var buf bytes.Buffer
+	ctx := context.WithValue(context.Background(), experimental.FunctionListenerFactoryKey{}, logging.NewLoggingListenerFactory(&buf))
+
 	bin, params := manyParamsResultsMod()
-	mod, err := r.Instantiate(testCtx, bin)
+	mod, err := r.Instantiate(ctx, bin)
 	require.NoError(t, err)
 
 	main := mod.ExportedFunction("main")
 	require.NotNil(t, main)
 
-	results, err := main.Call(testCtx, params...)
+	results, err := main.Call(ctx, params...)
 	require.NoError(t, err)
+
+	fmt.Println(buf.String())
+	require.Equal(t, `
+--> .main([0:i32]=0,[1:i64]=1,[2:f32]=3e-45,[3:f64]=1.5e-323,[4:v128]=00000000000000030000000000000003,[5:i32]=3,[6:i64]=5,[7:f32]=8e-45,[8:f64]=3.5e-323,[9:v128]=00000000000000080000000000000008,[10:i32]=8,[11:i64]=8,[12:f32]=1.4e-44,[13:f64]=5.4e-323,[14:v128]=000000000000000c000000000000000d,[15:i32]=13,[16:i64]=13,[17:f32]=1.8e-44,[18:f64]=7.4e-323,[19:v128]=00000000000000100000000000000011,[20:i32]=17,[21:i64]=18,[22:f32]=2.5e-44,[23:f64]=9e-323,[24:v128]=00000000000000140000000000000015,[25:i32]=21,[26:i64]=22,[27:f32]=3.2e-44,[28:f64]=1.14e-322,[29:v128]=00000000000000170000000000000019,[30:i32]=25,[31:i64]=26,[32:f32]=3.8e-44,[33:f64]=1.4e-322,[34:v128]=000000000000001c000000000000001c,[35:i32]=28,[36:i64]=30,[37:f32]=4.3e-44,[38:f64]=1.6e-322,[39:v128]=00000000000000210000000000000021,[40:i32]=33,[41:i64]=33,[42:f32]=4.9e-44,[43:f64]=1.8e-322,[44:v128]=00000000000000250000000000000026,[45:i32]=38,[46:i64]=38,[47:f32]=5.3e-44,[48:f64]=2e-322,[49:v128]=0000000000000029000000000000002a,[50:i32]=42,[51:i64]=43,[52:f32]=6e-44,[53:f64]=2.1e-322,[54:v128]=000000000000002d000000000000002e,[55:i32]=46,[56:i64]=47,[57:f32]=6.7e-44,[58:f64]=2.37e-322,[59:v128]=00000000000000300000000000000032,[60:i32]=50,[61:i64]=51,[62:f32]=7.3e-44,[63:f64]=2.6e-322,[64:v128]=00000000000000350000000000000035,[65:i32]=53,[66:i64]=55,[67:f32]=7.8e-44,[68:f64]=2.8e-322,[69:v128]=000000000000003a000000000000003a,[70:i32]=58,[71:i64]=58,[72:f32]=8.4e-44,[73:f64]=3e-322,[74:v128]=000000000000003e000000000000003f,[75:i32]=63,[76:i64]=63,[77:f32]=8.8e-44,[78:f64]=3.2e-322,[79:v128]=00000000000000420000000000000043,[80:i32]=67,[81:i64]=68,[82:f32]=9.5e-44,[83:f64]=3.36e-322,[84:v128]=00000000000000460000000000000047,[85:i32]=71,[86:i64]=72,[87:f32]=1.02e-43,[88:f64]=3.6e-322,[89:v128]=0000000000000049000000000000004b,[90:i32]=75,[91:i64]=76,[92:f32]=1.08e-43,[93:f64]=3.85e-322,[94:v128]=000000000000004e000000000000004e,[95:i32]=78,[96:i64]=80,[97:f32]=1.14e-43,[98:f64]=4.05e-322,[99:v128]=00000000000000530000000000000053)
+	--> .swapper([0:i32]=0,[1:i64]=1,[2:f32]=3e-45,[3:f64]=1.5e-323,[4:v128]=00000000000000030000000000000003,[5:i32]=3,[6:i64]=5,[7:f32]=8e-45,[8:f64]=3.5e-323,[9:v128]=00000000000000080000000000000008,[10:i32]=8,[11:i64]=8,[12:f32]=1.4e-44,[13:f64]=5.4e-323,[14:v128]=000000000000000c000000000000000d,[15:i32]=13,[16:i64]=13,[17:f32]=1.8e-44,[18:f64]=7.4e-323,[19:v128]=00000000000000100000000000000011,[20:i32]=17,[21:i64]=18,[22:f32]=2.5e-44,[23:f64]=9e-323,[24:v128]=00000000000000140000000000000015,[25:i32]=21,[26:i64]=22,[27:f32]=3.2e-44,[28:f64]=1.14e-322,[29:v128]=00000000000000170000000000000019,[30:i32]=25,[31:i64]=26,[32:f32]=3.8e-44,[33:f64]=1.4e-322,[34:v128]=000000000000001c000000000000001c,[35:i32]=28,[36:i64]=30,[37:f32]=4.3e-44,[38:f64]=1.6e-322,[39:v128]=00000000000000210000000000000021,[40:i32]=33,[41:i64]=33,[42:f32]=4.9e-44,[43:f64]=1.8e-322,[44:v128]=00000000000000250000000000000026,[45:i32]=38,[46:i64]=38,[47:f32]=5.3e-44,[48:f64]=2e-322,[49:v128]=0000000000000029000000000000002a,[50:i32]=42,[51:i64]=43,[52:f32]=6e-44,[53:f64]=2.1e-322,[54:v128]=000000000000002d000000000000002e,[55:i32]=46,[56:i64]=47,[57:f32]=6.7e-44,[58:f64]=2.37e-322,[59:v128]=00000000000000300000000000000032,[60:i32]=50,[61:i64]=51,[62:f32]=7.3e-44,[63:f64]=2.6e-322,[64:v128]=00000000000000350000000000000035,[65:i32]=53,[66:i64]=55,[67:f32]=7.8e-44,[68:f64]=2.8e-322,[69:v128]=000000000000003a000000000000003a,[70:i32]=58,[71:i64]=58,[72:f32]=8.4e-44,[73:f64]=3e-322,[74:v128]=000000000000003e000000000000003f,[75:i32]=63,[76:i64]=63,[77:f32]=8.8e-44,[78:f64]=3.2e-322,[79:v128]=00000000000000420000000000000043,[80:i32]=67,[81:i64]=68,[82:f32]=9.5e-44,[83:f64]=3.36e-322,[84:v128]=00000000000000460000000000000047,[85:i32]=71,[86:i64]=72,[87:f32]=1.02e-43,[88:f64]=3.6e-322,[89:v128]=0000000000000049000000000000004b,[90:i32]=75,[91:i64]=76,[92:f32]=1.08e-43,[93:f64]=3.85e-322,[94:v128]=000000000000004e000000000000004e,[95:i32]=78,[96:i64]=80,[97:f32]=1.14e-43,[98:f64]=4.05e-322,[99:v128]=00000000000000530000000000000053)
+	<-- (00000000000000620000000000000062,4.84e-322,1.37e-43,97,96,000000000000005f000000000000005d,4.6e-322,1.3e-43,93,92,000000000000005b000000000000005a,4.45e-322,1.23e-43,88,88,00000000000000570000000000000056,4.25e-322,1.19e-43,83,83,00000000000000530000000000000052,4.05e-322,1.14e-43,80,78,000000000000004e000000000000004e,3.85e-322,1.08e-43,76,75,00000000000000490000000000000049,3.6e-322,1.02e-43,72,71,00000000000000460000000000000044,3.36e-322,9.5e-44,68,67,00000000000000420000000000000041,3.2e-322,8.8e-44,63,63,000000000000003e000000000000003d,3e-322,8.4e-44,58,58,000000000000003a0000000000000039,2.8e-322,7.8e-44,55,53,00000000000000350000000000000035,2.6e-322,7.3e-44,51,50,00000000000000300000000000000030,2.37e-322,6.7e-44,47,46,000000000000002d000000000000002b,2.1e-322,6e-44,43,42,00000000000000290000000000000028,2e-322,5.3e-44,38,38,00000000000000250000000000000024,1.8e-322,4.9e-44,33,33,00000000000000210000000000000020,1.6e-322,4.3e-44,30,28,000000000000001c000000000000001c,1.4e-322,3.8e-44,26,25,00000000000000170000000000000017,1.14e-322,3.2e-44,22,21,00000000000000140000000000000012,9e-323,2.5e-44,18,17)
+	--> .doubler([0:v128]=00000000000000620000000000000062,[1:f64]=4.84e-322,[2:f32]=1.37e-43,[3:i64]=97,[4:i32]=96,[5:v128]=000000000000005f000000000000005d,[6:f64]=4.6e-322,[7:f32]=1.3e-43,[8:i64]=93,[9:i32]=92,[10:v128]=000000000000005b000000000000005a,[11:f64]=4.45e-322,[12:f32]=1.23e-43,[13:i64]=88,[14:i32]=88,[15:v128]=00000000000000570000000000000056,[16:f64]=4.25e-322,[17:f32]=1.19e-43,[18:i64]=83,[19:i32]=83,[20:v128]=00000000000000530000000000000052,[21:f64]=4.05e-322,[22:f32]=1.14e-43,[23:i64]=80,[24:i32]=78,[25:v128]=000000000000004e000000000000004e,[26:f64]=3.85e-322,[27:f32]=1.08e-43,[28:i64]=76,[29:i32]=75,[30:v128]=00000000000000490000000000000049,[31:f64]=3.6e-322,[32:f32]=1.02e-43,[33:i64]=72,[34:i32]=71,[35:v128]=00000000000000460000000000000044,[36:f64]=3.36e-322,[37:f32]=9.5e-44,[38:i64]=68,[39:i32]=67,[40:v128]=00000000000000420000000000000041,[41:f64]=3.2e-322,[42:f32]=8.8e-44,[43:i64]=63,[44:i32]=63,[45:v128]=000000000000003e000000000000003d,[46:f64]=3e-322,[47:f32]=8.4e-44,[48:i64]=58,[49:i32]=58,[50:v128]=000000000000003a0000000000000039,[51:f64]=2.8e-322,[52:f32]=7.8e-44,[53:i64]=55,[54:i32]=53,[55:v128]=00000000000000350000000000000035,[56:f64]=2.6e-322,[57:f32]=7.3e-44,[58:i64]=51,[59:i32]=50,[60:v128]=00000000000000300000000000000030,[61:f64]=2.37e-322,[62:f32]=6.7e-44,[63:i64]=47,[64:i32]=46,[65:v128]=000000000000002d000000000000002b,[66:f64]=2.1e-322,[67:f32]=6e-44,[68:i64]=43,[69:i32]=42,[70:v128]=00000000000000290000000000000028,[71:f64]=2e-322,[72:f32]=5.3e-44,[73:i64]=38,[74:i32]=38,[75:v128]=00000000000000250000000000000024,[76:f64]=1.8e-322,[77:f32]=4.9e-44,[78:i64]=33,[79:i32]=33,[80:v128]=00000000000000210000000000000020,[81:f64]=1.6e-322,[82:f32]=4.3e-44,[83:i64]=30,[84:i32]=28,[85:v128]=000000000000001c000000000000001c,[86:f64]=1.4e-322,[87:f32]=3.8e-44,[88:i64]=26,[89:i32]=25,[90:v128]=00000000000000170000000000000017,[91:f64]=1.14e-322,[92:f32]=3.2e-44,[93:i64]=22,[94:i32]=21,[95:v128]=00000000000000140000000000000012,[96:f64]=9e-323,[97:f32]=2.5e-44,[98:i64]=18,[99:i32]=17)
+	<-- (00000000000000620000000000000062,4.84e-322,2.75e-43,194,192,00000000000000be000000000000005d,4.6e-322,1.3e-43,186,184,00000000000000b600000000000000b4,8.9e-322,1.23e-43,88,176,00000000000000ae00000000000000ac,8.5e-322,2.38e-43,83,83,00000000000000a600000000000000a4,8.1e-322,2.27e-43,160,78,000000000000004e000000000000009c,7.7e-322,2.16e-43,152,150,00000000000000490000000000000049,3.6e-322,2.05e-43,144,142,000000000000008c0000000000000044,3.36e-322,9.5e-44,136,134,00000000000000840000000000000082,6.4e-322,8.8e-44,63,126,000000000000007c000000000000007a,6.03e-322,1.68e-43,58,58,00000000000000740000000000000072,5.63e-322,1.57e-43,110,53,0000000000000035000000000000006a,5.24e-322,1.46e-43,102,100,00000000000000300000000000000030,2.37e-322,1.35e-43,94,92,000000000000005a000000000000002b,2.1e-322,6e-44,86,84,00000000000000520000000000000050,3.95e-322,5.3e-44,38,76,000000000000004a0000000000000048,3.56e-322,9.8e-44,33,33,00000000000000420000000000000040,3.16e-322,8.7e-44,60,28,000000000000001c0000000000000038,2.77e-322,7.6e-44,52,50,00000000000000170000000000000017,1.14e-322,6.4e-44,44,42,00000000000000280000000000000012,9e-323,2.5e-44,36,34)
+<-- (00000000000000620000000000000062,4.84e-322,2.75e-43,194,192,00000000000000be000000000000005d,4.6e-322,1.3e-43,186,184,00000000000000b600000000000000b4,8.9e-322,1.23e-43,88,176,00000000000000ae00000000000000ac,8.5e-322,2.38e-43,83,83,00000000000000a600000000000000a4,8.1e-322,2.27e-43,160,78,000000000000004e000000000000009c,7.7e-322,2.16e-43,152,150,00000000000000490000000000000049,3.6e-322,2.05e-43,144,142,000000000000008c0000000000000044,3.36e-322,9.5e-44,136,134,00000000000000840000000000000082,6.4e-322,8.8e-44,63,126,000000000000007c000000000000007a,6.03e-322,1.68e-43,58,58,00000000000000740000000000000072,5.63e-322,1.57e-43,110,53,0000000000000035000000000000006a,5.24e-322,1.46e-43,102,100,00000000000000300000000000000030,2.37e-322,1.35e-43,94,92,000000000000005a000000000000002b,2.1e-322,6e-44,86,84,00000000000000520000000000000050,3.95e-322,5.3e-44,38,76,000000000000004a0000000000000048,3.56e-322,9.8e-44,33,33,00000000000000420000000000000040,3.16e-322,8.7e-44,60,28,000000000000001c0000000000000038,2.77e-322,7.6e-44,52,50,00000000000000170000000000000017,1.14e-322,6.4e-44,44,42,00000000000000280000000000000012,9e-323,2.5e-44,36,34)
+`, "\n"+buf.String())
+
 	exp := []uint64{
 		98, 98, 196, 194, 192, 190, 93, 93, 186, 184, 182, 180, 88, 88, 176, 174, 172, 170, 83, 83, 166, 164, 162,
 		160, 78, 78, 156, 154, 152, 150, 73, 73, 146, 144, 142, 140, 68, 68, 136, 134, 132, 130, 63, 63, 126, 124,
@@ -1849,15 +2034,44 @@ func testManyParamsResultsMain(t *testing.T, r wazero.Runtime) {
 }
 
 func testManyParamsResultsCallManyConstsAndPickLastVector(t *testing.T, r wazero.Runtime) {
+	ctx := context.Background()
+
 	bin, _ := manyParamsResultsMod()
-	mod, err := r.Instantiate(testCtx, bin)
+	mod, err := r.Instantiate(ctx, bin)
 	require.NoError(t, err)
 
 	main := mod.ExportedFunction("call_many_consts_and_pick_last_vector")
 	require.NotNil(t, main)
 
-	results, err := main.Call(testCtx)
+	results, err := main.Call(ctx)
 	require.NoError(t, err)
 	exp := []uint64{0x5f5f5f5f5f5f5f5f, 0x5f5f5f5f5f5f5f5f}
 	require.Equal(t, exp, results)
 }
+
+func testManyParamsResultsCallManyConstsAndPickLastVectorListener(t *testing.T, r wazero.Runtime) {
+	var buf bytes.Buffer
+	ctx := context.WithValue(context.Background(), experimental.FunctionListenerFactoryKey{}, logging.NewLoggingListenerFactory(&buf))
+
+	bin, _ := manyParamsResultsMod()
+	mod, err := r.Instantiate(ctx, bin)
+	require.NoError(t, err)
+
+	main := mod.ExportedFunction("call_many_consts_and_pick_last_vector")
+	require.NotNil(t, main)
+
+	results, err := main.Call(ctx)
+	require.NoError(t, err)
+	exp := []uint64{0x5f5f5f5f5f5f5f5f, 0x5f5f5f5f5f5f5f5f}
+	require.Equal(t, exp, results)
+
+	fmt.Println(buf.String())
+	require.Equal(t, `
+--> .call_many_consts_and_pick_last_vector()
+	--> .many_consts()
+	<-- (0,0,0,0,00000000000000000000000000000000,0,5,7e-45,4.16077606e-316,05050505050505050505050505050505,84215045,361700864190383365,1.4e-44,5e-323,000000000a0a0a0a0a0a0a0a0a0a0a0a,168430090,723401728380766730,6.6463464e-33,7.4e-323,000000000000000f000000000f0f0f0f,252645135,1085102592571150095,7.0533445e-30,3.815736827118017e-236,00000000000000140000000000000014,20,336860180,7.47605e-27,5.964208835435795e-212,14141414141414140000000000000019,25,25,7.914983e-24,9.01285756841504e-188,19191919191919191919191919191919,421075225,30,4.2e-44,2.496465636e-315,1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e,505290270,2170205185142300190,4.9e-44,1.73e-322,00000000232323232323232323232323,589505315,2531906049332683555,8.843688e-18,2e-322,00000000000000280000000028282828,673720360,2893606913523066920,9.334581e-15,3.0654356309538037e-115,000000000000002d000000000000002d,45,757935405,9.8439425e-12,4.4759381595361623e-91,2d2d2d2d2d2d2d2d0000000000000032,50,50,1.0372377e-08,6.749300603603778e-67,32323232323232323232323232323232,842150450,55,7.7e-44,4.576853666e-315,37373737373737373737373737373737,926365495,3978709506094217015,8.4e-44,2.96e-322,000000003c3c3c3c3c3c3c3c3c3c3c3c,1010580540,4340410370284600380,0.01148897,3.2e-322,00000000000000410000000041414141,1094795585,4702111234474983745,12.078431,2.2616345098039214e+06,00000000000000460000000000000046,70,1179010630,12689.568,3.5295369653413445e+30,4646464646464646000000000000004b,75,75,1.3323083e+07,5.2285141982483265e+54,4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b,1263225675,80,1.12e-43,6.657241696e-315,50505050505050505050505050505050)
+	--> .pick_last_vector([0:i32]=0,[1:i64]=0,[2:f32]=0,[3:f64]=0,[4:v128]=00000000000000000000000000000000,[5:i32]=0,[6:i64]=5,[7:f32]=7e-45,[8:f64]=4.16077606e-316,[9:v128]=05050505050505050505050505050505,[10:i32]=84215045,[11:i64]=361700864190383365,[12:f32]=1.4e-44,[13:f64]=5e-323,[14:v128]=000000000a0a0a0a0a0a0a0a0a0a0a0a,[15:i32]=168430090,[16:i64]=723401728380766730,[17:f32]=6.6463464e-33,[18:f64]=7.4e-323,[19:v128]=000000000000000f000000000f0f0f0f,[20:i32]=252645135,[21:i64]=1085102592571150095,[22:f32]=7.0533445e-30,[23:f64]=3.815736827118017e-236,[24:v128]=00000000000000140000000000000014,[25:i32]=20,[26:i64]=336860180,[27:f32]=7.47605e-27,[28:f64]=5.964208835435795e-212,[29:v128]=14141414141414140000000000000019,[30:i32]=25,[31:i64]=25,[32:f32]=7.914983e-24,[33:f64]=9.01285756841504e-188,[34:v128]=19191919191919191919191919191919,[35:i32]=421075225,[36:i64]=30,[37:f32]=4.2e-44,[38:f64]=2.496465636e-315,[39:v128]=1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e,[40:i32]=505290270,[41:i64]=2170205185142300190,[42:f32]=4.9e-44,[43:f64]=1.73e-322,[44:v128]=00000000232323232323232323232323,[45:i32]=589505315,[46:i64]=2531906049332683555,[47:f32]=8.843688e-18,[48:f64]=2e-322,[49:v128]=00000000000000280000000028282828,[50:i32]=673720360,[51:i64]=2893606913523066920,[52:f32]=9.334581e-15,[53:f64]=3.0654356309538037e-115,[54:v128]=000000000000002d000000000000002d,[55:i32]=45,[56:i64]=757935405,[57:f32]=9.8439425e-12,[58:f64]=4.4759381595361623e-91,[59:v128]=2d2d2d2d2d2d2d2d0000000000000032,[60:i32]=50,[61:i64]=50,[62:f32]=1.0372377e-08,[63:f64]=6.749300603603778e-67,[64:v128]=32323232323232323232323232323232,[65:i32]=842150450,[66:i64]=55,[67:f32]=7.7e-44,[68:f64]=4.576853666e-315,[69:v128]=37373737373737373737373737373737,[70:i32]=926365495,[71:i64]=3978709506094217015,[72:f32]=8.4e-44,[73:f64]=2.96e-322,[74:v128]=000000003c3c3c3c3c3c3c3c3c3c3c3c,[75:i32]=1010580540,[76:i64]=4340410370284600380,[77:f32]=0.01148897,[78:f64]=3.2e-322,[79:v128]=00000000000000410000000041414141,[80:i32]=1094795585,[81:i64]=4702111234474983745,[82:f32]=12.078431,[83:f64]=2.2616345098039214e+06,[84:v128]=00000000000000460000000000000046,[85:i32]=70,[86:i64]=1179010630,[87:f32]=12689.568,[88:f64]=3.5295369653413445e+30,[89:v128]=4646464646464646000000000000004b,[90:i32]=75,[91:i64]=75,[92:f32]=1.3323083e+07,[93:f64]=5.2285141982483265e+54,[94:v128]=4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b,[95:i32]=1263225675,[96:i64]=80,[97:f32]=1.12e-43,[98:f64]=6.657241696e-315,[99:v128]=50505050505050505050505050505050)
+	<-- 5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f
+<-- 5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f
+`, "\n"+buf.String())
+}