Repository: tetratelabs/wazero
Pull request #1627 (2023-08-14 04:16:58)

wazevo: adds support for memory.grow,size instructions
#1496 


Patch:
diff --git a/internal/engine/wazevo/backend/isa/arm64/abi_go_call.go b/internal/engine/wazevo/backend/isa/arm64/abi_go_call.go
new file mode 100644
index 00000000..e4df1872
--- /dev/null
+++ b/internal/engine/wazevo/backend/isa/arm64/abi_go_call.go
@@ -0,0 +1,250 @@
+package arm64
+
+import (
+	"github.com/tetratelabs/wazero/internal/engine/wazevo/backend"
+	"github.com/tetratelabs/wazero/internal/engine/wazevo/backend/regalloc"
+	"github.com/tetratelabs/wazero/internal/engine/wazevo/ssa"
+	"github.com/tetratelabs/wazero/internal/engine/wazevo/wazevoapi"
+)
+
+var calleeSavedRegistersPlusLinkRegSorted = []regalloc.VReg{
+	x18VReg, x19VReg, x20VReg, x21VReg, x22VReg, x23VReg, x24VReg, x25VReg, x26VReg, x28VReg, lrVReg,
+	v18VReg, v19VReg, v20VReg, v21VReg, v22VReg, v23VReg, v24VReg, v25VReg, v26VReg, v27VReg, v28VReg, v29VReg, v30VReg, v31VReg,
+}
+
+// CompileGoFunctionTrampoline implements backend.Machine.
+func (m *machine) CompileGoFunctionTrampoline(exitCode wazevoapi.ExitCode, sig *ssa.Signature) {
+	cur := m.allocateInstr()
+	cur.asNop0()
+	m.rootInstr = cur
+
+	// Execution context is always the first argument.
+	execCtrPtr := x0VReg
+
+	// Save the callee saved registers.
+	cur = m.saveRegistersInExecutionContext(cur, calleeSavedRegistersPlusLinkRegSorted)
+
+	// Next, we need to store all the arguments to the execution context.
+
+	stackPtrReg := x15VReg // Caller save, so we can use it for whatever we want.
+	imm12Op, ok := asImm12Operand(wazevoapi.ExecutionContextOffsets.GoFunctionCallStackBegin.U64())
+	if !ok {
+		panic("BUG: too large or un-aligned offset for Go function call stack in execution context")
+	}
+
+	goCallStackPtrCalc := m.allocateInstr()
+	goCallStackPtrCalc.asALU(aluOpAdd, operandNR(stackPtrReg), operandNR(execCtrPtr), imm12Op, true)
+	goCallStackPtrCalc.prev = cur
+	cur.next = goCallStackPtrCalc
+	cur = goCallStackPtrCalc
+
+	abi := m.getOrCreateABIImpl(sig)
+	for _, arg := range abi.args[1:] { // Skips exec context.
+		if arg.Kind == backend.ABIArgKindReg {
+			store := m.allocateInstr()
+			v := arg.Reg
+			var sizeInBits byte
+			switch arg.Type {
+			case ssa.TypeI32, ssa.TypeF32, ssa.TypeI64, ssa.TypeF64:
+				sizeInBits = 64 // We use uint64 for all basic types, except SIMD v128.
+			default:
+				panic("TODO")
+			}
+			store.asStore(operandNR(v),
+				addressMode{
+					kind: addressModeKindPostIndex,
+					rn:   stackPtrReg, imm: int64(sizeInBits / 8),
+				}, sizeInBits)
+			store.prev = cur
+			cur.next = store
+			cur = store
+		} else {
+			// We can temporarily load the argument to the tmp register, and then store it to the stack.
+			panic("TODO: many params for Go function call")
+		}
+	}
+
+	// Set the exit status on the execution context.
+	cur = m.setExitCode(cur, x0VReg, exitCode)
+
+	// Save the current stack pointer.
+	cur = m.saveCurrentStackPointer(cur, x0VReg)
+
+	// Exit the execution.
+	cur = m.storeReturnAddressAndExit(cur)
+
+	// After the call, we need to restore the callee saved registers.
+	cur = m.restoreRegistersInExecutionContext(cur, calleeSavedRegistersPlusLinkRegSorted)
+
+	// Finally, we move the results into the right places from the execution context's Go function call stack.
+	goCallStackPtrCalc2 := m.allocateInstr()
+	goCallStackPtrCalc2.asALU(aluOpAdd, operandNR(stackPtrReg), operandNR(execCtrPtr), imm12Op, true)
+	goCallStackPtrCalc2.prev = cur
+	cur.next = goCallStackPtrCalc2
+	cur = goCallStackPtrCalc2
+
+	for i := range abi.rets {
+		r := &abi.rets[i]
+		if r.Kind == backend.ABIArgKindReg {
+			loadIntoTmp := m.allocateInstr()
+			movTmpToReg := m.allocateInstr()
+
+			mode := addressMode{kind: addressModeKindPostIndex, rn: stackPtrReg}
+			switch r.Type {
+			case ssa.TypeI32:
+				mode.imm = 8 // We use uint64 for all basic types, except SIMD v128.
+				loadIntoTmp.asULoad(operandNR(tmpRegVReg), mode, 32)
+				movTmpToReg.asMove32(r.Reg, tmpRegVReg)
+			case ssa.TypeI64:
+				mode.imm = 8 // We use uint64 for all basic types, except SIMD v128.
+				loadIntoTmp.asULoad(operandNR(tmpRegVReg), mode, 64)
+				movTmpToReg.asMove64(r.Reg, tmpRegVReg)
+			case ssa.TypeF32:
+				mode.imm = 8 // We use uint64 for all basic types, except SIMD v128.
+				loadIntoTmp.asFpuLoad(operandNR(tmpRegVReg), mode, 32)
+				movTmpToReg.asFpuMov64(r.Reg, tmpRegVReg)
+			case ssa.TypeF64:
+				mode.imm = 8 // We use uint64 for all basic types, except SIMD v128.
+				loadIntoTmp.asFpuLoad(operandNR(tmpRegVReg), mode, 64)
+				movTmpToReg.asFpuMov64(r.Reg, tmpRegVReg)
+			}
+			loadIntoTmp.prev = cur
+			cur.next = loadIntoTmp
+			cur = loadIntoTmp
+
+			movTmpToReg.prev = cur
+			cur.next = movTmpToReg
+			cur = movTmpToReg
+		} else {
+			// We can temporarily load the argument to the tmp register, and then store it to the stack.
+			panic("TODO: many params for Go function call")
+		}
+	}
+
+	ret := m.allocateInstrAfterLowering()
+	ret.asRet(nil)
+	ret.prev = cur
+	cur.next = ret
+}
+
+func (m *machine) saveRegistersInExecutionContext(cur *instruction, regs []regalloc.VReg) *instruction {
+	offset := wazevoapi.ExecutionContextOffsets.SavedRegistersBegin.I64()
+	for _, v := range regs {
+		store := m.allocateInstrAfterLowering()
+		var sizeInBits byte
+		switch v.RegType() {
+		case regalloc.RegTypeInt:
+			sizeInBits = 64
+		case regalloc.RegTypeFloat:
+			sizeInBits = 128
+		}
+		store.asStore(operandNR(v),
+			addressMode{
+				kind: addressModeKindRegUnsignedImm12,
+				// Execution context is always the first argument.
+				rn: x0VReg, imm: offset,
+			}, sizeInBits)
+		store.prev = cur
+		cur.next = store
+		cur = store
+		offset += 16 // Imm12 must be aligned 16 for vector regs, so we unconditionally store regs at the offset of multiple of 16.
+	}
+	return cur
+}
+
+func (m *machine) restoreRegistersInExecutionContext(cur *instruction, regs []regalloc.VReg) *instruction {
+	offset := wazevoapi.ExecutionContextOffsets.SavedRegistersBegin.I64()
+	for _, v := range regs {
+		load := m.allocateInstrAfterLowering()
+		var as func(dst operand, amode addressMode, sizeInBits byte)
+		var sizeInBits byte
+		switch v.RegType() {
+		case regalloc.RegTypeInt:
+			as = load.asULoad
+			sizeInBits = 64
+		case regalloc.RegTypeFloat:
+			as = load.asFpuLoad
+			sizeInBits = 128
+		}
+		as(operandNR(v),
+			addressMode{
+				kind: addressModeKindRegUnsignedImm12,
+				// Execution context is always the first argument.
+				rn: x0VReg, imm: offset,
+			}, sizeInBits)
+		load.prev = cur
+		cur.next = load
+		cur = load
+		offset += 16 // Imm12 must be aligned 16 for vector regs, so we unconditionally load regs at the offset of multiple of 16.
+	}
+	return cur
+}
+
+func (m *machine) setExitCode(cur *instruction, execCtr regalloc.VReg, exitCode wazevoapi.ExitCode) *instruction {
+	// Set the exit status on the execution context.
+	// 	movz tmp, #wazevoapi.ExitCodeGrowStack
+	// 	str tmp, [exec_context]
+	loadStatusConst := m.allocateInstrAfterLowering()
+	loadStatusConst.asMOVZ(tmpRegVReg, uint64(exitCode), 0, true)
+	loadStatusConst.prev = cur
+	cur.next = loadStatusConst
+	cur = loadStatusConst
+	setExistStatus := m.allocateInstrAfterLowering()
+	setExistStatus.asStore(operandNR(tmpRegVReg),
+		addressMode{
+			kind: addressModeKindRegUnsignedImm12,
+			rn:   execCtr, imm: wazevoapi.ExecutionContextOffsets.ExitCodeOffset.I64(),
+		}, 32)
+	setExistStatus.prev = cur
+	cur.next = setExistStatus
+	cur = setExistStatus
+	return cur
+}
+
+func (m *machine) storeReturnAddressAndExit(cur *instruction) *instruction {
+	// Read the return address into tmp, and store it in the execution context.
+	adr := m.allocateInstrAfterLowering()
+	adr.asAdr(tmpRegVReg, exitSequenceSize+8)
+	adr.prev = cur
+	cur.next = adr
+	cur = adr
+	storeReturnAddr := m.allocateInstrAfterLowering()
+	storeReturnAddr.asStore(operandNR(tmpRegVReg),
+		addressMode{
+			kind: addressModeKindRegUnsignedImm12,
+			// Execution context is always the first argument.
+			rn: x0VReg, imm: wazevoapi.ExecutionContextOffsets.GoCallReturnAddress.I64(),
+		}, 64)
+	storeReturnAddr.prev = cur
+	cur.next = storeReturnAddr
+	cur = storeReturnAddr
+
+	// Exit the execution.
+	trapSeq := m.allocateInstrAfterLowering()
+	trapSeq.asExitSequence(x0VReg)
+	trapSeq.prev = cur
+	cur.next = trapSeq
+	cur = trapSeq
+	return cur
+}
+
+func (m *machine) saveCurrentStackPointer(cur *instruction, execCtr regalloc.VReg) *instruction {
+	// Save the current stack pointer:
+	// 	mov tmp, sp,
+	// 	str tmp, [exec_ctx, #stackPointerBeforeGoCall]
+	movSp := m.allocateInstrAfterLowering()
+	movSp.asMove64(tmpRegVReg, spVReg)
+	movSp.prev = cur
+	cur.next = movSp
+	cur = movSp
+	strSp := m.allocateInstrAfterLowering()
+	strSp.asStore(operandNR(tmpRegVReg),
+		addressMode{
+			kind: addressModeKindRegUnsignedImm12,
+			rn:   execCtr, imm: wazevoapi.ExecutionContextOffsets.StackPointerBeforeGrow.I64(),
+		}, 64)
+	strSp.prev = cur
+	cur.next = strSp
+	cur = strSp
+	return cur
+}
diff --git a/internal/engine/wazevo/backend/isa/arm64/abi_go_entry_arm64.go b/internal/engine/wazevo/backend/isa/arm64/abi_go_entry_arm64.go
index e2b03f4b..85c0e010 100644
--- a/internal/engine/wazevo/backend/isa/arm64/abi_go_entry_arm64.go
+++ b/internal/engine/wazevo/backend/isa/arm64/abi_go_entry_arm64.go
@@ -4,6 +4,6 @@ package arm64
 // This implements wazevo.entrypoint, and see the comments there for detail.
 func entrypoint(executable *byte, executionContextPtr uintptr, moduleContextPtr *byte, paramResultPtr *uint64, goAllocatedStackSlicePtr uintptr)
 
-// afterStackGrowEntrypoint enters the machine code after growing the stack.
-// This implements wazevo.afterStackGrowEntrypoint, and see the comments there for detail.
-func afterStackGrowEntrypoint(executable *byte, executionContextPtr uintptr, stackPointer uintptr)
+// afterGoFunctionCallEntrypoint enters the machine code after growing the stack.
+// This implements wazevo.afterGoFunctionCallEntrypoint, and see the comments there for detail.
+func afterGoFunctionCallEntrypoint(executable *byte, executionContextPtr uintptr, stackPointer uintptr)
diff --git a/internal/engine/wazevo/backend/isa/arm64/abi_go_entry_arm64.s b/internal/engine/wazevo/backend/isa/arm64/abi_go_entry_arm64.s
index fd72e2b2..1a0fd8b3 100644
--- a/internal/engine/wazevo/backend/isa/arm64/abi_go_entry_arm64.s
+++ b/internal/engine/wazevo/backend/isa/arm64/abi_go_entry_arm64.s
@@ -12,7 +12,7 @@ TEXT ·entrypoint(SB), NOSPLIT|NOFRAME, $0-40
 	MOVD goAllocatedStackSlicePtr+32(FP), R26
 	JMP  (R27)
 
-TEXT ·afterStackGrowEntrypoint(SB), NOSPLIT|NOFRAME, $0-24
+TEXT ·afterGoFunctionCallEntrypoint(SB), NOSPLIT|NOFRAME, $0-24
 	MOVD goCallReturnAddress+0(FP), R20
 	MOVD executionContextPtr+8(FP), R0
 	MOVD stackPointer+16(FP), R19
diff --git a/internal/engine/wazevo/backend/isa/arm64/instr.go b/internal/engine/wazevo/backend/isa/arm64/instr.go
index 6cb60155..cdf5b365 100644
--- a/internal/engine/wazevo/backend/isa/arm64/instr.go
+++ b/internal/engine/wazevo/backend/isa/arm64/instr.go
@@ -723,7 +723,7 @@ func (i *instruction) String() (str string) {
 			formatVRegSized(i.rd.nr(), 64),
 			formatVRegSized(i.rn.nr(), 64))
 	case mov32:
-		panic("TODO")
+		str = fmt.Sprintf("mov %s, %s", formatVRegSized(i.rd.nr(), 32), formatVRegSized(i.rn.nr(), 32))
 	case movZ:
 		size := is64SizeBitToSize(i.u3)
 		str = fmt.Sprintf("movz %s, #%#x, LSL %d", formatVRegSized(i.rd.nr(), size), uint16(i.u1), i.u2*16)
diff --git a/internal/engine/wazevo/backend/isa/arm64/machine_pro_epi_logue.go b/internal/engine/wazevo/backend/isa/arm64/machine_pro_epi_logue.go
index 3b3623e5..dda78451 100644
--- a/internal/engine/wazevo/backend/isa/arm64/machine_pro_epi_logue.go
+++ b/internal/engine/wazevo/backend/isa/arm64/machine_pro_epi_logue.go
@@ -320,65 +320,13 @@ func (m *machine) insertStackBoundsCheck(requiredStackSize int64, cur *instructi
 	cur = cbr
 
 	// Save the callee saved and argument registers.
-	offset := wazevoapi.ExecutionContextOffsets.SavedRegistersBegin.I64()
-	for _, v := range saveRequiredRegs {
-		store := m.allocateInstrAfterLowering()
-		var sizeInBits byte
-		switch v.RegType() {
-		case regalloc.RegTypeInt:
-			sizeInBits = 64
-		case regalloc.RegTypeFloat:
-			sizeInBits = 128
-		}
-		store.asStore(operandNR(v),
-			addressMode{
-				kind: addressModeKindRegUnsignedImm12,
-				// Execution context is always the first argument.
-				rn: x0VReg, imm: offset,
-			}, sizeInBits)
-		store.prev = cur
-		cur.next = store
-		cur = store
-		offset += 16 // Imm12 must be aligned 16 for vector regs, so we unconditionally store regs at the offset of multiple of 16.
-	}
+	cur = m.saveRegistersInExecutionContext(cur, saveRequiredRegs)
 
-	// Save the current stack pointer:
-	// 	mov tmp, sp,
-	// 	str tmp, [exec_ctx, #stackPointerBeforeGrow]
-	movSp := m.allocateInstrAfterLowering()
-	movSp.asMove64(tmpRegVReg, spVReg)
-	movSp.prev = cur
-	cur.next = movSp
-	cur = movSp
-	strSp := m.allocateInstrAfterLowering()
-	strSp.asStore(operandNR(tmpRegVReg),
-		addressMode{
-			kind: addressModeKindRegUnsignedImm12,
-			// Execution context is always the first argument.
-			rn: x0VReg, imm: wazevoapi.ExecutionContextOffsets.StackPointerBeforeGrow.I64(),
-		}, 64)
-	strSp.prev = cur
-	cur.next = strSp
-	cur = strSp
+	// Save the current stack pointer.
+	cur = m.saveCurrentStackPointer(cur, x0VReg)
 
 	// Set the exit status on the execution context.
-	// 	movz tmp, #wazevoapi.ExitCodeGrowStack
-	// 	str tmp, [exec_context]
-	loadStatusConst := m.allocateInstrAfterLowering()
-	loadStatusConst.asMOVZ(tmpRegVReg, uint64(wazevoapi.ExitCodeGrowStack), 0, true)
-	loadStatusConst.prev = cur
-	cur.next = loadStatusConst
-	cur = loadStatusConst
-	setExistStatus := m.allocateInstrAfterLowering()
-	setExistStatus.asStore(operandNR(tmpRegVReg),
-		addressMode{
-			kind: addressModeKindRegUnsignedImm12,
-			// Execution context is always the first argument.
-			rn: x0VReg, imm: wazevoapi.ExecutionContextOffsets.ExitCodeOffset.I64(),
-		}, 32)
-	setExistStatus.prev = cur
-	cur.next = setExistStatus
-	cur = setExistStatus
+	cur = m.setExitCode(cur, x0VReg, wazevoapi.ExitCodeGrowStack)
 
 	// Set the required stack size and set it to the exec context.
 	{
@@ -403,55 +351,11 @@ func (m *machine) insertStackBoundsCheck(requiredStackSize int64, cur *instructi
 		cur = setRequiredStackSize
 	}
 
-	// Read the return address into tmp, and store it in the execution context.
-	adr := m.allocateInstrAfterLowering()
-	adr.asAdr(tmpRegVReg, exitSequenceSize+8)
-	adr.prev = cur
-	cur.next = adr
-	cur = adr
-	storeReturnAddr := m.allocateInstrAfterLowering()
-	storeReturnAddr.asStore(operandNR(tmpRegVReg),
-		addressMode{
-			kind: addressModeKindRegUnsignedImm12,
-			// Execution context is always the first argument.
-			rn: x0VReg, imm: wazevoapi.ExecutionContextOffsets.GoCallReturnAddress.I64(),
-		}, 64)
-	storeReturnAddr.prev = cur
-	cur.next = storeReturnAddr
-	cur = storeReturnAddr
-
 	// Exit the execution.
-	trapSeq := m.allocateInstrAfterLowering()
-	trapSeq.asExitSequence(x0VReg)
-	trapSeq.prev = cur
-	cur.next = trapSeq
-	cur = trapSeq
+	cur = m.storeReturnAddressAndExit(cur)
 
 	// After the exit, restore the saved registers.
-	offset = wazevoapi.ExecutionContextOffsets.SavedRegistersBegin.I64()
-	for _, v := range saveRequiredRegs {
-		load := m.allocateInstrAfterLowering()
-		var as func(dst operand, amode addressMode, sizeInBits byte)
-		var sizeInBits byte
-		switch v.RegType() {
-		case regalloc.RegTypeInt:
-			as = load.asULoad
-			sizeInBits = 64
-		case regalloc.RegTypeFloat:
-			as = load.asFpuLoad
-			sizeInBits = 128
-		}
-		as(operandNR(v),
-			addressMode{
-				kind: addressModeKindRegUnsignedImm12,
-				// Execution context is always the first argument.
-				rn: x0VReg, imm: offset,
-			}, sizeInBits)
-		load.prev = cur
-		cur.next = load
-		cur = load
-		offset += 16 // Imm12 must be aligned 16 for vector regs, so we unconditionally load regs at the offset of multiple of 16.
-	}
+	cur = m.restoreRegistersInExecutionContext(cur, saveRequiredRegs)
 
 	// Now that we know the entire code, we can finalize how many bytes
 	// we have to skip when the stack size is sufficient.
diff --git a/internal/engine/wazevo/backend/machine.go b/internal/engine/wazevo/backend/machine.go
index ebd76ffd..f9bbaeee 100644
--- a/internal/engine/wazevo/backend/machine.go
+++ b/internal/engine/wazevo/backend/machine.go
@@ -3,6 +3,7 @@ package backend
 import (
 	"github.com/tetratelabs/wazero/internal/engine/wazevo/backend/regalloc"
 	"github.com/tetratelabs/wazero/internal/engine/wazevo/ssa"
+	"github.com/tetratelabs/wazero/internal/engine/wazevo/wazevoapi"
 )
 
 type (
@@ -94,5 +95,8 @@ type (
 
 		// Encode encodes the machine instructions to the Compiler.
 		Encode()
+
+		// CompileGoFunctionTrampoline compiles the trampoline function  to call a Go function of the given exit code and signature.
+		CompileGoFunctionTrampoline(exitCode wazevoapi.ExitCode, sig *ssa.Signature)
 	}
 )
diff --git a/internal/engine/wazevo/call_engine.go b/internal/engine/wazevo/call_engine.go
index dfae774d..283d1cbc 100644
--- a/internal/engine/wazevo/call_engine.go
+++ b/internal/engine/wazevo/call_engine.go
@@ -51,15 +51,17 @@ type (
 		stackBottomPtr *byte
 		// goCallReturnAddress holds the return address to go back to the caller of the Go function.
 		goCallReturnAddress *byte
-		// stackPointerBeforeGrow holds the stack pointer before stack grow.
-		stackPointerBeforeGrow uintptr
+		// stackPointerBeforeGoCall holds the stack pointer before calling a Go function.
+		stackPointerBeforeGoCall uintptr
 		// stackGrowRequiredSize holds the required size of stack grow.
 		stackGrowRequiredSize uintptr
-		// _ is needed to align .savedRegisters at 16 bytes boundary.
-		_ uint64
+		// memoryGrowTrampolineAddress holds the address of memory grow trampoline function.
+		memoryGrowTrampolineAddress *byte
 		// savedRegisters is the opaque spaces for save/restore registers.
 		// We want to align 16 bytes for each register, so we use [64][2]uint64.
 		savedRegisters [64][2]uint64
+
+		goFunctionCallStack [128]uint64
 	}
 )
 
@@ -117,17 +119,40 @@ func (c *callEngine) CallWithStack(ctx context.Context, paramResultStack []uint6
 				return err
 			}
 			c.execCtx.exitCode = wazevoapi.ExitCodeOK
-			afterStackGrowEntrypoint(c.execCtx.goCallReturnAddress, c.execCtxPtr, newsp)
+			afterGoFunctionCallEntrypoint(c.execCtx.goCallReturnAddress, c.execCtxPtr, newsp)
 		case wazevoapi.ExitCodeUnreachable:
 			return wasmruntime.ErrRuntimeUnreachable
 		case wazevoapi.ExitCodeMemoryOutOfBounds:
 			return wasmruntime.ErrRuntimeOutOfBoundsMemoryAccess
+		case wazevoapi.ExitCodeGrowMemory:
+			mod := moduleInstanceFromPtr(c.execCtx.callerModuleContextPtr)
+			mem := mod.MemoryInstance
+			argRes := &c.execCtx.goFunctionCallStack[0]
+			if res, ok := mem.Grow(uint32(*argRes)); !ok {
+				*argRes = uint64(0xffffffff) // = -1 in signed 32-bit integer.
+			} else {
+				*argRes = uint64(res)
+				if mod.Source.MemorySection != nil {
+					var opaque []byte
+					sh := (*reflect.SliceHeader)(unsafe.Pointer(&opaque))
+					sh.Data = uintptr(unsafe.Pointer(c.execCtx.callerModuleContextPtr))
+					sh.Len = 24
+					sh.Cap = 24
+					putLocalMemory(opaque, 8, mem)
+				}
+			}
+			c.execCtx.exitCode = wazevoapi.ExitCodeOK
+			afterGoFunctionCallEntrypoint(c.execCtx.goCallReturnAddress, c.execCtxPtr, c.execCtx.stackPointerBeforeGoCall)
 		default:
 			panic("BUG")
 		}
 	}
 }
 
+func moduleInstanceFromPtr(ptr *byte) *wasm.ModuleInstance {
+	return *(**wasm.ModuleInstance)(unsafe.Pointer(ptr))
+}
+
 const callStackCeiling = uintptr(5000000) // in uint64 (8 bytes) == 40000000 bytes in total == 40mb.
 
 // growStack grows the stack, and returns the new stack pointer.
@@ -141,7 +166,7 @@ func (c *callEngine) growStack() (newSP uintptr, err error) {
 	newLen := 2*currentLen + c.execCtx.stackGrowRequiredSize
 	newStack := make([]byte, newLen)
 
-	relSp := c.stackTop - c.execCtx.stackPointerBeforeGrow
+	relSp := c.stackTop - c.execCtx.stackPointerBeforeGoCall
 
 	// Copy the existing contents in the previous Go-allocated stack into the new one.
 	var prevStackAligned, newStackAligned []byte
diff --git a/internal/engine/wazevo/engine.go b/internal/engine/wazevo/engine.go
index 66376cdc..6fd38a1f 100644
--- a/internal/engine/wazevo/engine.go
+++ b/internal/engine/wazevo/engine.go
@@ -25,13 +25,21 @@ type (
 		mux               sync.RWMutex
 		rels              []backend.RelocationInfo
 		refToBinaryOffset map[ssa.FuncRef]int
+		// builtinFunctions is hods compiled builtin function trampolines.
+		builtinFunctions *builtinFunctions
+	}
+
+	builtinFunctions struct {
+		// memoryGrowExecutable is a compiled executable for memory.grow builtin function.
+		memoryGrowExecutable []byte
 	}
 
 	// compiledModule is a compiled variant of a wasm.Module and ready to be used for instantiation.
 	compiledModule struct {
-		executable      []byte
-		functionOffsets []compiledFunctionOffset
-		offsets         wazevoapi.ModuleContextOffsetData
+		executable       []byte
+		functionOffsets  []compiledFunctionOffset
+		offsets          wazevoapi.ModuleContextOffsetData
+		builtinFunctions *builtinFunctions
 	}
 
 	// compiledFunctionOffset tells us that where in the executable a function begins.
@@ -47,7 +55,10 @@ var _ wasm.Engine = (*engine)(nil)
 
 // NewEngine returns the implementation of wasm.Engine.
 func NewEngine(_ context.Context, _ api.CoreFeatures, _ filecache.Cache) wasm.Engine {
-	return &engine{compiledModules: make(map[wasm.ModuleID]*compiledModule), refToBinaryOffset: make(map[ssa.FuncRef]int)}
+	e := &engine{compiledModules: make(map[wasm.ModuleID]*compiledModule), refToBinaryOffset: make(map[ssa.FuncRef]int)}
+
+	e.compileBuiltinFunctions()
+	return e
 }
 
 // CompileModule implements wasm.Engine.
@@ -164,6 +175,9 @@ func (e *engine) CompileModule(_ context.Context, module *wasm.Module, _ []exper
 		}
 	}
 	e.compiledModules[module.ID] = cm
+	cm.builtinFunctions = e.builtinFunctions
+
+	// TODO: finalizer.
 	return nil
 }
 
@@ -177,6 +191,7 @@ func (e *engine) Close() (err error) {
 		cm.functionOffsets = nil
 	}
 	e.compiledModules = nil
+	e.builtinFunctions = nil
 	return nil
 }
 
@@ -220,3 +235,36 @@ func (e *engine) NewModuleEngine(m *wasm.Module, mi *wasm.ModuleInstance) (wasm.
 	}
 	return me, nil
 }
+
+func (e *engine) compileBuiltinFunctions() {
+	e.builtinFunctions = &builtinFunctions{}
+	{
+		machine := newMachine()
+		be := backend.NewCompiler(machine, ssa.NewBuilder())
+		machine.CompileGoFunctionTrampoline(wazevoapi.ExitCodeGrowMemory, &ssa.Signature{
+			Params:  []ssa.Type{ssa.TypeI32 /* exec context */, ssa.TypeI32},
+			Results: []ssa.Type{ssa.TypeI32},
+		})
+		be.Encode()
+		src := be.Buf()
+
+		executable, err := platform.MmapCodeSegment(len(src))
+		if err != nil {
+			panic(err)
+		}
+
+		copy(executable, src)
+
+		if runtime.GOARCH == "arm64" {
+			// On arm64, we cannot give all of rwx at the same time, so we change it to exec.
+			if err = platform.MprotectRX(executable); err != nil {
+				panic(err)
+			}
+		}
+		e.builtinFunctions.memoryGrowExecutable = executable
+	}
+
+	// TODO: table grow, etc.
+
+	// TODO: finalizer.
+}
diff --git a/internal/engine/wazevo/entrypoint_arm64.go b/internal/engine/wazevo/entrypoint_arm64.go
index 79454654..efe8e943 100644
--- a/internal/engine/wazevo/entrypoint_arm64.go
+++ b/internal/engine/wazevo/entrypoint_arm64.go
@@ -9,5 +9,5 @@ func entrypoint(executable *byte, executionContextPtr uintptr, moduleContextPtr
 
 // entrypoint is implemented by the backend.
 //
-//go:linkname afterStackGrowEntrypoint github.com/tetratelabs/wazero/internal/engine/wazevo/backend/isa/arm64.afterStackGrowEntrypoint
-func afterStackGrowEntrypoint(executable *byte, executionContextPtr uintptr, stackPointer uintptr)
+//go:linkname afterGoFunctionCallEntrypoint github.com/tetratelabs/wazero/internal/engine/wazevo/backend/isa/arm64.afterGoFunctionCallEntrypoint
+func afterGoFunctionCallEntrypoint(executable *byte, executionContextPtr uintptr, stackPointer uintptr)
diff --git a/internal/engine/wazevo/entrypoint_others.go b/internal/engine/wazevo/entrypoint_others.go
index cfdbc296..c364f72e 100644
--- a/internal/engine/wazevo/entrypoint_others.go
+++ b/internal/engine/wazevo/entrypoint_others.go
@@ -10,6 +10,6 @@ func entrypoint(executable *byte, executionContextPtr uintptr, moduleContextPtr
 	panic(runtime.GOARCH)
 }
 
-func afterStackGrowEntrypoint(executable *byte, executionContextPtr uintptr, stackPointer uintptr) {
+func afterGoFunctionCallEntrypoint(executable *byte, executionContextPtr uintptr, stackPointer uintptr) {
 	panic(runtime.GOARCH)
 }
diff --git a/internal/engine/wazevo/frontend/frontend.go b/internal/engine/wazevo/frontend/frontend.go
index 8e2e9318..f59a7d95 100644
--- a/internal/engine/wazevo/frontend/frontend.go
+++ b/internal/engine/wazevo/frontend/frontend.go
@@ -17,8 +17,9 @@ type Compiler struct {
 	m      *wasm.Module
 	offset *wazevoapi.ModuleContextOffsetData
 	// ssaBuilder is a ssa.Builder used by this frontend.
-	ssaBuilder ssa.Builder
-	signatures map[*wasm.FunctionType]*ssa.Signature
+	ssaBuilder    ssa.Builder
+	signatures    map[*wasm.FunctionType]*ssa.Signature
+	memoryGrowSig ssa.Signature
 
 	// Followings are reset by per function.
 
@@ -51,7 +52,7 @@ func NewFrontendCompiler(m *wasm.Module, ssaBuilder ssa.Builder, offset *wazevoa
 		offset:              offset,
 	}
 
-	c.signatures = make(map[*wasm.FunctionType]*ssa.Signature, len(m.TypeSection))
+	c.signatures = make(map[*wasm.FunctionType]*ssa.Signature, len(m.TypeSection)+1)
 	for i := range m.TypeSection {
 		wasmSig := &m.TypeSection[i]
 		sig := &ssa.Signature{
@@ -71,6 +72,16 @@ func NewFrontendCompiler(m *wasm.Module, ssaBuilder ssa.Builder, offset *wazevoa
 		c.signatures[wasmSig] = sig
 		c.ssaBuilder.DeclareSignature(sig)
 	}
+
+	c.memoryGrowSig = ssa.Signature{
+		ID: ssa.SignatureID(len(m.TypeSection)),
+		// Takes execution context and the page size to grow.
+		Params: []ssa.Type{ssa.TypeI32, ssa.TypeI32},
+		// Returns the new size.
+		Results: []ssa.Type{ssa.TypeI32},
+	}
+	c.ssaBuilder.DeclareSignature(&c.memoryGrowSig)
+
 	return c
 }
 
diff --git a/internal/engine/wazevo/frontend/lower.go b/internal/engine/wazevo/frontend/lower.go
index 63d01de7..0e568949 100644
--- a/internal/engine/wazevo/frontend/lower.go
+++ b/internal/engine/wazevo/frontend/lower.go
@@ -448,6 +448,54 @@ func (c *Compiler) lowerOpcode(op wasm.Opcode) {
 		variable := c.localVariable(index)
 		v := state.pop()
 		builder.DefineVariableInCurrentBB(variable, v)
+	case wasm.OpcodeMemorySize:
+		state.pc++ // skips the memory index.
+		if state.unreachable {
+			return
+		}
+
+		var memSizeInBytes ssa.Value
+		if c.offset.LocalMemoryBegin < 0 {
+			panic("TODO: imported memory")
+		} else {
+			load := builder.AllocateInstruction()
+			load.AsLoad(c.moduleCtxPtrValue, c.offset.LocalMemoryLen().U32(), ssa.TypeI32)
+			builder.InsertInstruction(load)
+			memSizeInBytes = load.Return()
+		}
+
+		amount := builder.AllocateInstruction()
+		amount.AsIconst32(uint32(wasm.MemoryPageSizeInBits))
+		builder.InsertInstruction(amount)
+		memSize := builder.AllocateInstruction()
+		memSize.AsUshr(memSizeInBytes, amount.Return())
+		builder.InsertInstruction(memSize)
+		state.push(memSize.Return())
+
+	case wasm.OpcodeMemoryGrow:
+		state.pc++ // skips the memory index.
+		if state.unreachable {
+			return
+		}
+
+		c.storeCallerModuleContext()
+
+		pages := state.pop()
+		loadPtr := builder.AllocateInstruction()
+		loadPtr.AsLoad(c.execCtxPtrValue,
+			wazevoapi.ExecutionContextOffsets.MemoryGrowTrampolineAddress.U32(), ssa.TypeI64)
+		builder.InsertInstruction(loadPtr)
+
+		// TODO: reuse the slice.
+		args := []ssa.Value{c.execCtxPtrValue, pages}
+		callGrow := builder.AllocateInstruction()
+		callGrow.AsCallIndirect(loadPtr.Return(), &c.memoryGrowSig, args)
+		builder.InsertInstruction(callGrow)
+
+		state.push(callGrow.Return())
+
+		// After the memory grow, reload the cached memory base and len.
+		c.reloadMemoryBaseLen()
 	case wasm.OpcodeI32Load,
 		wasm.OpcodeI64Load,
 		wasm.OpcodeF32Load,
@@ -851,8 +899,7 @@ func (c *Compiler) reloadAfterCall() {
 
 	// After calling any function, memory buffer might have changed. So we need to re-defined the variable.
 	if c.needMemory {
-		_ = c.getMemoryBaseValue(true)
-		_ = c.getMemoryLenValue(true)
+		c.reloadMemoryBaseLen()
 	}
 
 	// Also, any mutable Global can change.
@@ -861,6 +908,11 @@ func (c *Compiler) reloadAfterCall() {
 	}
 }
 
+func (c *Compiler) reloadMemoryBaseLen() {
+	_ = c.getMemoryBaseValue(true)
+	_ = c.getMemoryLenValue(true)
+}
+
 // globalInstanceValueOffset is the offsetOf .Value field of wasm.GlobalInstance.
 const globalInstanceValueOffset = 8
 
@@ -909,17 +961,29 @@ func (c *Compiler) getMemoryBaseValue(forceReload bool) ssa.Value {
 	if c.offset.LocalMemoryBegin < 0 {
 		panic("TODO: imported memory")
 	}
-	return c.getModuleCtxValueI32Or64(c.memoryBaseVariable, c.offset.LocalMemoryBase(), false, forceReload)
+
+	variable := c.memoryBaseVariable
+	builder := c.ssaBuilder
+	if !forceReload {
+		if v := builder.FindValue(variable); v.Valid() {
+			return v
+		}
+	}
+
+	load := builder.AllocateInstruction()
+	load.AsLoad(c.moduleCtxPtrValue, c.offset.LocalMemoryBase().U32(), ssa.TypeI64)
+	builder.InsertInstruction(load)
+	ret := load.Return()
+	builder.DefineVariableInCurrentBB(variable, ret)
+	return ret
 }
 
 func (c *Compiler) getMemoryLenValue(forceReload bool) ssa.Value {
 	if c.offset.LocalMemoryBegin < 0 {
 		panic("TODO: imported memory")
 	}
-	return c.getModuleCtxValueI32Or64(c.memoryLenVariable, c.offset.LocalMemoryLen(), true, forceReload)
-}
 
-func (c *Compiler) getModuleCtxValueI32Or64(variable ssa.Variable, offset wazevoapi.Offset, zeroExt bool, forceReload bool) ssa.Value {
+	variable := c.memoryLenVariable
 	builder := c.ssaBuilder
 	if !forceReload {
 		if v := builder.FindValue(variable); v.Valid() {
@@ -927,11 +991,7 @@ func (c *Compiler) getModuleCtxValueI32Or64(variable ssa.Variable, offset wazevo
 		}
 	}
 	load := builder.AllocateInstruction()
-	if zeroExt {
-		load.AsExtLoad(ssa.OpcodeUload32, c.moduleCtxPtrValue, uint32(offset), true)
-	} else {
-		load.AsExtLoad(ssa.OpcodeLoad, c.moduleCtxPtrValue, uint32(offset), true)
-	}
+	load.AsExtLoad(ssa.OpcodeUload32, c.moduleCtxPtrValue, c.offset.LocalMemoryLen().U32(), true)
 	builder.InsertInstruction(load)
 	ret := load.Return()
 	builder.DefineVariableInCurrentBB(variable, ret)
diff --git a/internal/engine/wazevo/module_engine.go b/internal/engine/wazevo/module_engine.go
index a8415dc4..7e73997a 100644
--- a/internal/engine/wazevo/module_engine.go
+++ b/internal/engine/wazevo/module_engine.go
@@ -5,6 +5,7 @@ import (
 	"unsafe"
 
 	"github.com/tetratelabs/wazero/api"
+	"github.com/tetratelabs/wazero/internal/engine/wazevo/wazevoapi"
 	"github.com/tetratelabs/wazero/internal/wasm"
 )
 
@@ -40,16 +41,24 @@ type (
 	moduleContextOpaque []byte
 )
 
+func putLocalMemory(opaque []byte, offset wazevoapi.Offset, mem *wasm.MemoryInstance) {
+	b := uint64(uintptr(unsafe.Pointer(&mem.Buffer[0])))
+	s := uint64(len(mem.Buffer))
+	binary.LittleEndian.PutUint64(opaque[offset:], b)
+	binary.LittleEndian.PutUint64(opaque[offset+8:], s)
+}
+
 func (m *moduleEngine) setupOpaque() {
 	inst := m.module
 	offsets := &m.parent.offsets
 	opaque := m.opaque
 
+	binary.LittleEndian.PutUint64(opaque[offsets.ModuleInstanceOffset:],
+		uint64(uintptr(unsafe.Pointer(m.module))),
+	)
+
 	if lm := offsets.LocalMemoryBegin; lm >= 0 {
-		b := uint64(uintptr(unsafe.Pointer(&inst.MemoryInstance.Buffer[0])))
-		s := uint64(len(inst.MemoryInstance.Buffer))
-		binary.LittleEndian.PutUint64(opaque[lm:], b)
-		binary.LittleEndian.PutUint64(opaque[lm+8:], s)
+		putLocalMemory(opaque, lm, inst.MemoryInstance)
 	}
 
 	if im := offsets.ImportedMemoryBegin; im >= 0 {
@@ -92,6 +101,8 @@ func (m *moduleEngine) NewFunction(index wasm.Index) api.Function {
 		parent:                 m,
 		sizeOfParamResultSlice: sizeOfParamResultSlice,
 	}
+
+	ce.execCtx.memoryGrowTrampolineAddress = &m.parent.builtinFunctions.memoryGrowExecutable[0]
 	ce.init()
 	return ce
 }
diff --git a/internal/engine/wazevo/ssa/instructions.go b/internal/engine/wazevo/ssa/instructions.go
index b29cd7ba..405a11de 100644
--- a/internal/engine/wazevo/ssa/instructions.go
+++ b/internal/engine/wazevo/ssa/instructions.go
@@ -1247,7 +1247,6 @@ func (i *Instruction) AsBrnz(v Value, args []Value, target BasicBlock) {
 // AsCall initializes this instruction as a call instruction with OpcodeCall.
 func (i *Instruction) AsCall(ref FuncRef, sig *Signature, args []Value) {
 	i.opcode = OpcodeCall
-	i.typ = TypeF64
 	i.u64 = uint64(ref)
 	i.vs = args
 	i.v = Value(sig.ID)
diff --git a/internal/engine/wazevo/wazevoapi/exitcode.go b/internal/engine/wazevo/wazevoapi/exitcode.go
index 8cee3ea3..bf6eca72 100644
--- a/internal/engine/wazevo/wazevoapi/exitcode.go
+++ b/internal/engine/wazevo/wazevoapi/exitcode.go
@@ -6,6 +6,7 @@ type ExitCode uint32
 const (
 	ExitCodeOK ExitCode = iota
 	ExitCodeGrowStack
+	ExitCodeGrowMemory
 	ExitCodeUnreachable
 	ExitCodeMemoryOutOfBounds
 )
diff --git a/internal/engine/wazevo/wazevoapi/offsetdata.go b/internal/engine/wazevo/wazevoapi/offsetdata.go
index 55bbb832..9941198c 100644
--- a/internal/engine/wazevo/wazevoapi/offsetdata.go
+++ b/internal/engine/wazevo/wazevoapi/offsetdata.go
@@ -3,16 +3,18 @@ package wazevoapi
 import "github.com/tetratelabs/wazero/internal/wasm"
 
 var ExecutionContextOffsets = ExecutionContextOffsetData{
-	ExitCodeOffset:         0,
-	CallerModuleContextPtr: 8,
-	OriginalFramePointer:   16,
-	OriginalStackPointer:   24,
-	GoReturnAddress:        32,
-	StackBottomPtr:         40,
-	GoCallReturnAddress:    48,
-	StackPointerBeforeGrow: 56,
-	StackGrowRequiredSize:  64,
-	SavedRegistersBegin:    80,
+	ExitCodeOffset:              0,
+	CallerModuleContextPtr:      8,
+	OriginalFramePointer:        16,
+	OriginalStackPointer:        24,
+	GoReturnAddress:             32,
+	StackBottomPtr:              40,
+	GoCallReturnAddress:         48,
+	StackPointerBeforeGrow:      56,
+	StackGrowRequiredSize:       64,
+	MemoryGrowTrampolineAddress: 72,
+	SavedRegistersBegin:         80,
+	GoFunctionCallStackBegin:    1104,
 }
 
 // ExecutionContextOffsetData allows the compilers to get the information about offsets to the fields of wazevo.executionContext,
@@ -32,18 +34,23 @@ type ExecutionContextOffsetData struct {
 	StackBottomPtr Offset
 	// GoCallReturnAddress is an offset of `goCallReturnAddress` field in wazevo.executionContext
 	GoCallReturnAddress Offset
-	// GoCallReturnAddress is an offset of `stackPointerBeforeGrow` field in wazevo.executionContext
+	// GoCallReturnAddress is an offset of `stackPointerBeforeGoCall` field in wazevo.executionContext
 	StackPointerBeforeGrow Offset
 	// StackGrowRequiredSize is an offset of `stackGrowRequiredSize` field in wazevo.executionContext
 	StackGrowRequiredSize Offset
+	// MemoryGrowTrampolineAddress is an offset of `memoryGrowTrampolineAddress` field in wazevo.executionContext
+	MemoryGrowTrampolineAddress Offset
 	// GoCallReturnAddress is an offset of the first element of `savedRegisters` field in wazevo.executionContext
 	SavedRegistersBegin Offset
+	// GoFunctionCallStackBegin is an offset of the first element of `goFunctionCallStack` field in wazevo.executionContext
+	GoFunctionCallStackBegin Offset
 }
 
 // ModuleContextOffsetData allows the compilers to get the information about offsets to the fields of wazevo.moduleContextOpaque,
 // This is unique per module.
 type ModuleContextOffsetData struct {
 	TotalSize int
+	ModuleInstanceOffset,
 	LocalMemoryBegin, ImportedMemoryBegin, ImportedFunctionsBegin,
 	GlobalsBegin Offset
 }
@@ -72,6 +79,11 @@ func (o Offset) I64() int64 {
 	return int64(o)
 }
 
+// U64 encodes an Offset as int64 for convenience.
+func (o Offset) U64() uint64 {
+	return uint64(o)
+}
+
 // LocalMemoryBase returns an offset of the first byte of the local memory.
 func (m *ModuleContextOffsetData) LocalMemoryBase() Offset {
 	return m.LocalMemoryBegin
@@ -90,12 +102,15 @@ func (m *ModuleContextOffsetData) LocalMemoryLen() Offset {
 func NewModuleContextOffsetData(m *wasm.Module) ModuleContextOffsetData {
 	ret := ModuleContextOffsetData{}
 	var offset Offset
+
+	ret.ModuleInstanceOffset = 0
+	offset += 8
+
 	if m.MemorySection != nil {
 		ret.LocalMemoryBegin = offset
 		// buffer base + memory size.
 		const localMemorySizeInOpaqueVMContext = 16
 		offset += localMemorySizeInOpaqueVMContext
-		ret.TotalSize += localMemorySizeInOpaqueVMContext
 	} else {
 		// Indicates that there's no local memory
 		ret.LocalMemoryBegin = -1
@@ -106,7 +121,6 @@ func NewModuleContextOffsetData(m *wasm.Module) ModuleContextOffsetData {
 		const importedMemorySizeInOpaqueVMCContext = 8
 		ret.ImportedMemoryBegin = offset
 		offset += importedMemorySizeInOpaqueVMCContext
-		ret.TotalSize += importedMemorySizeInOpaqueVMCContext
 	} else {
 		// Indicates that there's no imported memory
 		ret.ImportedMemoryBegin = -1
@@ -117,7 +131,6 @@ func NewModuleContextOffsetData(m *wasm.Module) ModuleContextOffsetData {
 		// Each function consists of the pointer to the executable and the pointer to its moduleContextOpaque (16 bytes).
 		size := int(m.ImportFunctionCount) * 16
 		offset += Offset(size)
-		ret.TotalSize += size
 	} else {
 		ret.ImportedFunctionsBegin = -1
 	}
@@ -125,9 +138,11 @@ func NewModuleContextOffsetData(m *wasm.Module) ModuleContextOffsetData {
 	if globals := int(m.ImportGlobalCount) + len(m.GlobalSection); globals > 0 {
 		ret.GlobalsBegin = offset
 		// Pointers to *wasm.GlobalInstance.
-		ret.TotalSize += globals * 8
+		offset += Offset(globals) * 8
 	} else {
 		ret.GlobalsBegin = -1
 	}
+
+	ret.TotalSize = int(offset)
 	return ret
 }


Test patch:
diff --git a/internal/engine/wazevo/backend/backend_test.go b/internal/engine/wazevo/backend/backend_test.go
index 9d6f0d4b..63f1ec4a 100644
--- a/internal/engine/wazevo/backend/backend_test.go
+++ b/internal/engine/wazevo/backend/backend_test.go
@@ -229,7 +229,7 @@ L1 (SSA Block: blk0):
 L3 (SSA Block: blk1):
 	ret
 L2 (SSA Block: blk2):
-	movz x27, #0x2, LSL 0
+	movz x27, #0x3, LSL 0
 	str w27, [x0?]
 	exit_sequence w0?
 `,
@@ -242,7 +242,7 @@ L3 (SSA Block: blk1):
 	ldr x30, [sp], #0x10
 	ret
 L2 (SSA Block: blk2):
-	movz x27, #0x2, LSL 0
+	movz x27, #0x3, LSL 0
 	str w27, [x0]
 	exit_sequence w0
 `,
@@ -1856,8 +1856,8 @@ L1 (SSA Block: blk0):
 	mov x1?, x1
 	mov x2?, x2
 	str x1?, [x0?, #0x8]
-	ldr x3?, [x1?]
-	ldr x4?, [x1?, #0x8]
+	ldr x3?, [x1?, #0x8]
+	ldr x4?, [x1?, #0x10]
 	mov x0, x0?
 	mov x1, x4?
 	mov x2, x2?
@@ -1870,8 +1870,8 @@ L1 (SSA Block: blk0):
 L1 (SSA Block: blk0):
 	str x30, [sp, #-0x10]!
 	str x1, [x0, #0x8]
-	ldr x8, [x1]
-	ldr x1, [x1, #0x8]
+	ldr x8, [x1, #0x8]
+	ldr x1, [x1, #0x10]
 	bl w8
 	ldr x30, [sp], #0x10
 	ret
@@ -1885,14 +1885,14 @@ L1 (SSA Block: blk0):
 	mov x1?, x1
 	mov x2?, x2
 	uxtw x4?, w2?
-	ldr w5?, [x1?, #0x8]
+	ldr w5?, [x1?, #0x10]
 	add x6?, x4?, #0x4
 	subs xzr, x5?, x6?
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x0?]
 	exit_sequence w0?
-	ldr x8?, [x1?]
+	ldr x8?, [x1?, #0x8]
 	add x11?, x8?, x4?
 	ldr w10?, [x11?]
 	mov x0, x10?
@@ -1902,14 +1902,14 @@ L1 (SSA Block: blk0):
 L1 (SSA Block: blk0):
 	str x30, [sp, #-0x10]!
 	uxtw x8, w2
-	ldr w10, [x1, #0x8]
+	ldr w10, [x1, #0x10]
 	add x9, x8, #0x4
 	subs xzr, x10, x9
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x0]
 	exit_sequence w0
-	ldr x9, [x1]
+	ldr x9, [x1, #0x8]
 	add x8, x9, x8
 	ldr w0, [x8]
 	ldr x30, [sp], #0x10
@@ -1924,21 +1924,21 @@ L1 (SSA Block: blk0):
 	mov x1?, x1
 	mov x2?, x2
 	uxtw x4?, w2?
-	ldr w5?, [x1?, #0x8]
+	ldr w5?, [x1?, #0x10]
 	add x6?, x4?, #0x4
 	subs xzr, x5?, x6?
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x0?]
 	exit_sequence w0?
-	ldr x8?, [x1?]
+	ldr x8?, [x1?, #0x8]
 	add x200?, x8?, x4?
 	ldr w10?, [x200?]
 	uxtw x12?, w2?
 	add x13?, x12?, #0x8
 	subs xzr, x5?, x13?
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x0?]
 	exit_sequence w0?
 	add x199?, x8?, x12?
@@ -1947,7 +1947,7 @@ L1 (SSA Block: blk0):
 	add x19?, x18?, #0x4
 	subs xzr, x5?, x19?
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x0?]
 	exit_sequence w0?
 	add x198?, x8?, x18?
@@ -1956,7 +1956,7 @@ L1 (SSA Block: blk0):
 	add x25?, x24?, #0x8
 	subs xzr, x5?, x25?
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x0?]
 	exit_sequence w0?
 	add x197?, x8?, x24?
@@ -1965,7 +1965,7 @@ L1 (SSA Block: blk0):
 	add x31?, x30?, #0x13
 	subs xzr, x5?, x31?
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x0?]
 	exit_sequence w0?
 	add x196?, x8?, x30?
@@ -1974,7 +1974,7 @@ L1 (SSA Block: blk0):
 	add x37?, x36?, #0x17
 	subs xzr, x5?, x37?
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x0?]
 	exit_sequence w0?
 	add x195?, x8?, x36?
@@ -1983,7 +1983,7 @@ L1 (SSA Block: blk0):
 	add x43?, x42?, #0x13
 	subs xzr, x5?, x43?
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x0?]
 	exit_sequence w0?
 	add x194?, x8?, x42?
@@ -1992,7 +1992,7 @@ L1 (SSA Block: blk0):
 	add x49?, x48?, #0x17
 	subs xzr, x5?, x49?
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x0?]
 	exit_sequence w0?
 	add x193?, x8?, x48?
@@ -2001,7 +2001,7 @@ L1 (SSA Block: blk0):
 	add x55?, x54?, #0x1
 	subs xzr, x5?, x55?
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x0?]
 	exit_sequence w0?
 	add x192?, x8?, x54?
@@ -2010,7 +2010,7 @@ L1 (SSA Block: blk0):
 	add x61?, x60?, #0x10
 	subs xzr, x5?, x61?
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x0?]
 	exit_sequence w0?
 	add x191?, x8?, x60?
@@ -2019,7 +2019,7 @@ L1 (SSA Block: blk0):
 	add x67?, x66?, #0x1
 	subs xzr, x5?, x67?
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x0?]
 	exit_sequence w0?
 	add x190?, x8?, x66?
@@ -2028,7 +2028,7 @@ L1 (SSA Block: blk0):
 	add x73?, x72?, #0x10
 	subs xzr, x5?, x73?
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x0?]
 	exit_sequence w0?
 	add x189?, x8?, x72?
@@ -2037,7 +2037,7 @@ L1 (SSA Block: blk0):
 	add x79?, x78?, #0x2
 	subs xzr, x5?, x79?
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x0?]
 	exit_sequence w0?
 	add x188?, x8?, x78?
@@ -2046,7 +2046,7 @@ L1 (SSA Block: blk0):
 	add x85?, x84?, #0x11
 	subs xzr, x5?, x85?
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x0?]
 	exit_sequence w0?
 	add x187?, x8?, x84?
@@ -2055,7 +2055,7 @@ L1 (SSA Block: blk0):
 	add x91?, x90?, #0x2
 	subs xzr, x5?, x91?
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x0?]
 	exit_sequence w0?
 	add x186?, x8?, x90?
@@ -2064,7 +2064,7 @@ L1 (SSA Block: blk0):
 	add x97?, x96?, #0x11
 	subs xzr, x5?, x97?
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x0?]
 	exit_sequence w0?
 	add x185?, x8?, x96?
@@ -2073,7 +2073,7 @@ L1 (SSA Block: blk0):
 	add x103?, x102?, #0x1
 	subs xzr, x5?, x103?
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x0?]
 	exit_sequence w0?
 	add x184?, x8?, x102?
@@ -2082,7 +2082,7 @@ L1 (SSA Block: blk0):
 	add x109?, x108?, #0x10
 	subs xzr, x5?, x109?
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x0?]
 	exit_sequence w0?
 	add x183?, x8?, x108?
@@ -2091,7 +2091,7 @@ L1 (SSA Block: blk0):
 	add x115?, x114?, #0x1
 	subs xzr, x5?, x115?
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x0?]
 	exit_sequence w0?
 	add x182?, x8?, x114?
@@ -2100,7 +2100,7 @@ L1 (SSA Block: blk0):
 	add x121?, x120?, #0x10
 	subs xzr, x5?, x121?
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x0?]
 	exit_sequence w0?
 	add x181?, x8?, x120?
@@ -2109,7 +2109,7 @@ L1 (SSA Block: blk0):
 	add x127?, x126?, #0x2
 	subs xzr, x5?, x127?
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x0?]
 	exit_sequence w0?
 	add x180?, x8?, x126?
@@ -2118,7 +2118,7 @@ L1 (SSA Block: blk0):
 	add x133?, x132?, #0x11
 	subs xzr, x5?, x133?
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x0?]
 	exit_sequence w0?
 	add x179?, x8?, x132?
@@ -2127,7 +2127,7 @@ L1 (SSA Block: blk0):
 	add x139?, x138?, #0x2
 	subs xzr, x5?, x139?
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x0?]
 	exit_sequence w0?
 	add x178?, x8?, x138?
@@ -2136,7 +2136,7 @@ L1 (SSA Block: blk0):
 	add x145?, x144?, #0x11
 	subs xzr, x5?, x145?
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x0?]
 	exit_sequence w0?
 	add x177?, x8?, x144?
@@ -2145,7 +2145,7 @@ L1 (SSA Block: blk0):
 	add x151?, x150?, #0x4
 	subs xzr, x5?, x151?
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x0?]
 	exit_sequence w0?
 	add x176?, x8?, x150?
@@ -2154,7 +2154,7 @@ L1 (SSA Block: blk0):
 	add x157?, x156?, #0x13
 	subs xzr, x5?, x157?
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x0?]
 	exit_sequence w0?
 	add x175?, x8?, x156?
@@ -2163,7 +2163,7 @@ L1 (SSA Block: blk0):
 	add x163?, x162?, #0x4
 	subs xzr, x5?, x163?
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x0?]
 	exit_sequence w0?
 	add x174?, x8?, x162?
@@ -2172,7 +2172,7 @@ L1 (SSA Block: blk0):
 	add x169?, x168?, #0x13
 	subs xzr, x5?, x169?
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x0?]
 	exit_sequence w0?
 	add x173?, x8?, x168?
@@ -2223,21 +2223,21 @@ L1 (SSA Block: blk0):
 	str x28, [sp, #-0x10]!
 	mov x8, x0
 	uxtw x11, w2
-	ldr w9, [x1, #0x8]
+	ldr w9, [x1, #0x10]
 	add x10, x11, #0x4
 	subs xzr, x9, x10
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x8]
 	exit_sequence w8
-	ldr x10, [x1]
+	ldr x10, [x1, #0x8]
 	add x11, x10, x11
 	ldr w0, [x11]
 	uxtw x12, w2
 	add x11, x12, #0x8
 	subs xzr, x9, x11
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x8]
 	exit_sequence w8
 	add x11, x10, x12
@@ -2246,7 +2246,7 @@ L1 (SSA Block: blk0):
 	add x11, x12, #0x4
 	subs xzr, x9, x11
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x8]
 	exit_sequence w8
 	add x11, x10, x12
@@ -2255,7 +2255,7 @@ L1 (SSA Block: blk0):
 	add x11, x12, #0x8
 	subs xzr, x9, x11
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x8]
 	exit_sequence w8
 	add x11, x10, x12
@@ -2264,7 +2264,7 @@ L1 (SSA Block: blk0):
 	add x11, x12, #0x13
 	subs xzr, x9, x11
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x8]
 	exit_sequence w8
 	add x11, x10, x12
@@ -2273,7 +2273,7 @@ L1 (SSA Block: blk0):
 	add x12, x13, #0x17
 	subs xzr, x9, x12
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x8]
 	exit_sequence w8
 	add x12, x10, x13
@@ -2282,7 +2282,7 @@ L1 (SSA Block: blk0):
 	add x12, x13, #0x13
 	subs xzr, x9, x12
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x8]
 	exit_sequence w8
 	add x12, x10, x13
@@ -2291,7 +2291,7 @@ L1 (SSA Block: blk0):
 	add x12, x13, #0x17
 	subs xzr, x9, x12
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x8]
 	exit_sequence w8
 	add x12, x10, x13
@@ -2300,7 +2300,7 @@ L1 (SSA Block: blk0):
 	add x12, x13, #0x1
 	subs xzr, x9, x12
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x8]
 	exit_sequence w8
 	add x12, x10, x13
@@ -2309,7 +2309,7 @@ L1 (SSA Block: blk0):
 	add x12, x13, #0x10
 	subs xzr, x9, x12
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x8]
 	exit_sequence w8
 	add x12, x10, x13
@@ -2318,7 +2318,7 @@ L1 (SSA Block: blk0):
 	add x12, x13, #0x1
 	subs xzr, x9, x12
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x8]
 	exit_sequence w8
 	add x12, x10, x13
@@ -2327,7 +2327,7 @@ L1 (SSA Block: blk0):
 	add x12, x13, #0x10
 	subs xzr, x9, x12
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x8]
 	exit_sequence w8
 	add x12, x10, x13
@@ -2336,7 +2336,7 @@ L1 (SSA Block: blk0):
 	add x12, x13, #0x2
 	subs xzr, x9, x12
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x8]
 	exit_sequence w8
 	add x12, x10, x13
@@ -2345,7 +2345,7 @@ L1 (SSA Block: blk0):
 	add x13, x14, #0x11
 	subs xzr, x9, x13
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x8]
 	exit_sequence w8
 	add x13, x10, x14
@@ -2354,7 +2354,7 @@ L1 (SSA Block: blk0):
 	add x14, x15, #0x2
 	subs xzr, x9, x14
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x8]
 	exit_sequence w8
 	add x14, x10, x15
@@ -2363,7 +2363,7 @@ L1 (SSA Block: blk0):
 	add x15, x16, #0x11
 	subs xzr, x9, x15
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x8]
 	exit_sequence w8
 	add x15, x10, x16
@@ -2372,7 +2372,7 @@ L1 (SSA Block: blk0):
 	add x16, x17, #0x1
 	subs xzr, x9, x16
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x8]
 	exit_sequence w8
 	add x16, x10, x17
@@ -2381,7 +2381,7 @@ L1 (SSA Block: blk0):
 	add x17, x18, #0x10
 	subs xzr, x9, x17
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x8]
 	exit_sequence w8
 	add x17, x10, x18
@@ -2390,7 +2390,7 @@ L1 (SSA Block: blk0):
 	add x18, x19, #0x1
 	subs xzr, x9, x18
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x8]
 	exit_sequence w8
 	add x18, x10, x19
@@ -2399,7 +2399,7 @@ L1 (SSA Block: blk0):
 	add x19, x20, #0x10
 	subs xzr, x9, x19
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x8]
 	exit_sequence w8
 	add x19, x10, x20
@@ -2408,7 +2408,7 @@ L1 (SSA Block: blk0):
 	add x20, x21, #0x2
 	subs xzr, x9, x20
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x8]
 	exit_sequence w8
 	add x20, x10, x21
@@ -2417,7 +2417,7 @@ L1 (SSA Block: blk0):
 	add x21, x22, #0x11
 	subs xzr, x9, x21
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x8]
 	exit_sequence w8
 	add x21, x10, x22
@@ -2426,7 +2426,7 @@ L1 (SSA Block: blk0):
 	add x22, x23, #0x2
 	subs xzr, x9, x22
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x8]
 	exit_sequence w8
 	add x22, x10, x23
@@ -2435,7 +2435,7 @@ L1 (SSA Block: blk0):
 	add x23, x24, #0x11
 	subs xzr, x9, x23
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x8]
 	exit_sequence w8
 	add x23, x10, x24
@@ -2444,7 +2444,7 @@ L1 (SSA Block: blk0):
 	add x24, x25, #0x4
 	subs xzr, x9, x24
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x8]
 	exit_sequence w8
 	add x24, x10, x25
@@ -2453,7 +2453,7 @@ L1 (SSA Block: blk0):
 	add x25, x26, #0x13
 	subs xzr, x9, x25
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x8]
 	exit_sequence w8
 	add x25, x10, x26
@@ -2462,7 +2462,7 @@ L1 (SSA Block: blk0):
 	add x26, x28, #0x4
 	subs xzr, x9, x26
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x8]
 	exit_sequence w8
 	add x26, x10, x28
@@ -2471,7 +2471,7 @@ L1 (SSA Block: blk0):
 	add x28, x29, #0x13
 	subs xzr, x9, x28
 	b.hs #0x20
-	movz x27, #0x3, LSL 0
+	movz x27, #0x4, LSL 0
 	str w27, [x8]
 	exit_sequence w8
 	add x8, x10, x29
@@ -2514,25 +2514,25 @@ L1 (SSA Block: blk0):
 L1 (SSA Block: blk0):
 	mov x0?, x0
 	mov x1?, x1
-	ldr x2?, [x1?]
+	ldr x2?, [x1?, #0x8]
 	ldr w3?, [x2?, #0x8]
-	ldr x4?, [x1?, #0x8]
+	ldr x4?, [x1?, #0x10]
 	ldr x5?, [x4?, #0x8]
-	ldr x6?, [x1?, #0x10]
+	ldr x6?, [x1?, #0x18]
 	ldr s7?, [x6?, #0x8]
-	ldr x8?, [x1?, #0x18]
+	ldr x8?, [x1?, #0x20]
 	ldr d9?, [x8?, #0x8]
 	str x1?, [x0?, #0x8]
 	mov x0, x0?
 	mov x1, x1?
 	bl f1
-	ldr x10?, [x1?]
+	ldr x10?, [x1?, #0x8]
 	ldr w11?, [x10?, #0x8]
-	ldr x12?, [x1?, #0x8]
+	ldr x12?, [x1?, #0x10]
 	ldr x13?, [x12?, #0x8]
-	ldr x14?, [x1?, #0x10]
+	ldr x14?, [x1?, #0x18]
 	ldr s15?, [x14?, #0x8]
-	ldr x16?, [x1?, #0x18]
+	ldr x16?, [x1?, #0x20]
 	ldr d17?, [x16?, #0x8]
 	mov q3.8b, q17?.8b
 	mov q2.8b, q15?.8b
@@ -2549,13 +2549,13 @@ L1 (SSA Block: blk0):
 	str x30, [sp, #-0x10]!
 	sub sp, sp, #0x20
 	mov x10, x1
-	ldr x8, [x10]
+	ldr x8, [x10, #0x8]
 	ldr w8, [x8, #0x8]
-	ldr x9, [x10, #0x8]
+	ldr x9, [x10, #0x10]
 	ldr x9, [x9, #0x8]
-	ldr x11, [x10, #0x10]
-	ldr s0, [x11, #0x8]
 	ldr x11, [x10, #0x18]
+	ldr s0, [x11, #0x8]
+	ldr x11, [x10, #0x20]
 	ldr d1, [x11, #0x8]
 	str x10, [x0, #0x8]
 	mov x1, x10
@@ -2570,13 +2570,13 @@ L1 (SSA Block: blk0):
 	ldr x9, [sp, #0xc]
 	ldr w8, [sp, #0x8]
 	ldr x10, [sp]
-	ldr x11, [x10]
-	ldr w2, [x11, #0x8]
 	ldr x11, [x10, #0x8]
-	ldr x3, [x11, #0x8]
+	ldr w2, [x11, #0x8]
 	ldr x11, [x10, #0x10]
+	ldr x3, [x11, #0x8]
+	ldr x11, [x10, #0x18]
 	ldr s2, [x11, #0x8]
-	ldr x10, [x10, #0x18]
+	ldr x10, [x10, #0x20]
 	ldr d3, [x10, #0x8]
 	mov x1, x9
 	mov x0, x8
@@ -2592,16 +2592,16 @@ L1 (SSA Block: blk0):
 			afterLoweringARM64: `
 L1 (SSA Block: blk0):
 	mov x1?, x1
-	ldr x3?, [x1?]
+	ldr x3?, [x1?, #0x8]
 	orr w13?, wzr, #0x1
 	str w13?, [x3?, #0x8]
-	ldr x5?, [x1?, #0x8]
+	ldr x5?, [x1?, #0x10]
 	orr x12?, xzr, #0x2
 	str x12?, [x5?, #0x8]
-	ldr x7?, [x1?, #0x10]
+	ldr x7?, [x1?, #0x18]
 	ldr s11?, #8; b 8; data.f32 3.000000
 	str s11?, [x7?, #0x8]
-	ldr x9?, [x1?, #0x18]
+	ldr x9?, [x1?, #0x20]
 	ldr d10?, #8; b 16; data.f64 4.000000
 	str d10?, [x9?, #0x8]
 	ret
@@ -2609,16 +2609,16 @@ L1 (SSA Block: blk0):
 			afterFinalizeARM64: `
 L1 (SSA Block: blk0):
 	str x30, [sp, #-0x10]!
-	ldr x9, [x1]
+	ldr x9, [x1, #0x8]
 	orr w8, wzr, #0x1
 	str w8, [x9, #0x8]
-	ldr x9, [x1, #0x8]
+	ldr x9, [x1, #0x10]
 	orr x8, xzr, #0x2
 	str x8, [x9, #0x8]
-	ldr x8, [x1, #0x10]
+	ldr x8, [x1, #0x18]
 	ldr s8, #8; b 8; data.f32 3.000000
 	str s8, [x8, #0x8]
-	ldr x8, [x1, #0x18]
+	ldr x8, [x1, #0x20]
 	ldr d8, #8; b 16; data.f64 4.000000
 	str d8, [x8, #0x8]
 	ldr x30, [sp], #0x10
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
new file mode 100644
index 00000000..a4997a93
--- /dev/null
+++ b/internal/engine/wazevo/backend/isa/arm64/abi_go_call_test.go
@@ -0,0 +1,120 @@
+package arm64
+
+import (
+	"encoding/hex"
+	"fmt"
+	"sort"
+	"testing"
+
+	"github.com/tetratelabs/wazero/internal/engine/wazevo/backend/regalloc"
+	"github.com/tetratelabs/wazero/internal/engine/wazevo/ssa"
+	"github.com/tetratelabs/wazero/internal/engine/wazevo/wazevoapi"
+	"github.com/tetratelabs/wazero/internal/testing/require"
+)
+
+func Test_calleeSavedRegistersPlusLinkRegSorted(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)
+}
+
+func TestMachine_CompileGoFunctionTrampoline(t *testing.T) {
+	for _, tc := range []struct {
+		name     string
+		exitCode wazevoapi.ExitCode
+		sig      *ssa.Signature
+		exp      string
+	}{
+		{
+			name:     "grow memory",
+			exitCode: wazevoapi.ExitCodeGrowMemory,
+			sig: &ssa.Signature{
+				Params:  []ssa.Type{ssa.TypeI32, ssa.TypeI32},
+				Results: []ssa.Type{ssa.TypeI32},
+			},
+			exp: `
+	str x18, [x0, #0x50]
+	str x19, [x0, #0x60]
+	str x20, [x0, #0x70]
+	str x21, [x0, #0x80]
+	str x22, [x0, #0x90]
+	str x23, [x0, #0xa0]
+	str x24, [x0, #0xb0]
+	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]
+	add x15, x0, #0x450
+	str x1, [x15], #0x8
+	movz x27, #0x2, LSL 0
+	str w27, [x0]
+	mov x27, sp
+	str x27, [x0, #0x38]
+	adr x27, #0x1c
+	str x27, [x0, #0x30]
+	exit_sequence w0
+	ldr x18, [x0, #0x50]
+	ldr x19, [x0, #0x60]
+	ldr x20, [x0, #0x70]
+	ldr x21, [x0, #0x80]
+	ldr x22, [x0, #0x90]
+	ldr x23, [x0, #0xa0]
+	ldr x24, [x0, #0xb0]
+	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 x15, x0, #0x450
+	ldr w27, [x15], #0x8
+	mov w0, w27
+	ret
+`,
+		},
+	} {
+		t.Run(tc.name, func(t *testing.T) {
+			_, _, m := newSetupWithMockContext()
+			m.CompileGoFunctionTrampoline(tc.exitCode, tc.sig)
+
+			fmt.Println(m.Format())
+			require.Equal(t, tc.exp, m.Format())
+
+			m.Encode()
+			fmt.Println(hex.EncodeToString(m.compiler.Buf()))
+		})
+	}
+}
diff --git a/internal/engine/wazevo/backend/machine_test.go b/internal/engine/wazevo/backend/machine_test.go
index 589b1405..db585d17 100644
--- a/internal/engine/wazevo/backend/machine_test.go
+++ b/internal/engine/wazevo/backend/machine_test.go
@@ -3,6 +3,7 @@ package backend
 import (
 	"github.com/tetratelabs/wazero/internal/engine/wazevo/backend/regalloc"
 	"github.com/tetratelabs/wazero/internal/engine/wazevo/ssa"
+	"github.com/tetratelabs/wazero/internal/engine/wazevo/wazevoapi"
 )
 
 // mockMachine implements Machine for testing.
@@ -23,6 +24,11 @@ type mockMachine struct {
 	rinfo                  *regalloc.RegisterInfo
 }
 
+func (m mockMachine) CompileGoFunctionTrampoline(exitCode wazevoapi.ExitCode, sig *ssa.Signature) {
+	// TODO implement me
+	panic("implement me")
+}
+
 // Encode implements Machine.Encode.
 func (m mockMachine) Encode() {
 	// TODO implement me
diff --git a/internal/engine/wazevo/call_engine_test.go b/internal/engine/wazevo/call_engine_test.go
index 37115cde..c7c7123e 100644
--- a/internal/engine/wazevo/call_engine_test.go
+++ b/internal/engine/wazevo/call_engine_test.go
@@ -31,8 +31,8 @@ func TestCallEngine_growStack(t *testing.T) {
 			stack:    s,
 			stackTop: uintptr(unsafe.Pointer(&s[15])),
 			execCtx: executionContext{
-				stackGrowRequiredSize:  160,
-				stackPointerBeforeGrow: uintptr(unsafe.Pointer(&s[10])),
+				stackGrowRequiredSize:    160,
+				stackPointerBeforeGoCall: uintptr(unsafe.Pointer(&s[10])),
 			},
 		}
 		newSP, err := c.growStack()
diff --git a/internal/engine/wazevo/e2e_test.go b/internal/engine/wazevo/e2e_test.go
index 092c0a0a..8cc28aa3 100644
--- a/internal/engine/wazevo/e2e_test.go
+++ b/internal/engine/wazevo/e2e_test.go
@@ -22,7 +22,6 @@ func TestE2E(t *testing.T) {
 		params, expResults []uint64
 		expErr             string
 	}
-	// const i32, i64, f32, f64 = wasm.ValueTypeI32, wasm.ValueTypeI64, wasm.ValueTypeF32, wasm.ValueTypeF64
 	for _, tc := range []struct {
 		name        string
 		imported, m *wasm.Module
@@ -135,6 +134,11 @@ func TestE2E(t *testing.T) {
 				1, 2, uint64(math.Float32bits(3.0)), math.Float64bits(4.0),
 			}}},
 		},
+		{
+			name:  "memory_size_grow",
+			m:     testcases.MemorySizeGrow.Module,
+			calls: []callCase{{expResults: []uint64{1, 2, 0xffffffff}}},
+		},
 	} {
 		tc := tc
 		t.Run(tc.name, func(t *testing.T) {
diff --git a/internal/engine/wazevo/frontend/frontend_test.go b/internal/engine/wazevo/frontend/frontend_test.go
index ca677d9f..d83cefa8 100644
--- a/internal/engine/wazevo/frontend/frontend_test.go
+++ b/internal/engine/wazevo/frontend/frontend_test.go
@@ -867,11 +867,11 @@ blk3: () <-- (blk2)
 blk0: (exec_ctx:i64, module_ctx:i64, v2:i32)
 	v3:i64 = Iconst_64 0x4
 	v4:i64 = UExtend v2, 32->64
-	v5:i64 = Uload32 module_ctx, 0x8
+	v5:i64 = Uload32 module_ctx, 0x10
 	v6:i64 = Iadd v4, v3
 	v7:i32 = Icmp ge_u, v5, v6
 	ExitIfNotZero v7, exec_ctx, memory_out_of_bounds
-	v8:i64 = Load module_ctx, 0x0
+	v8:i64 = Load module_ctx, 0x8
 	v9:i64 = Iadd v8, v4
 	v10:i32 = Load v9, 0x0
 	Jump blk_ret, v10
@@ -892,8 +892,8 @@ blk0: (exec_ctx:i64, module_ctx:i64, v2:i32)
 blk1: () <-- (blk0)
 	Store module_ctx, exec_ctx, 0x8
 	Call f1:sig1, exec_ctx, module_ctx
-	v5:i64 = Load module_ctx, 0x0
-	v6:i64 = Uload32 module_ctx, 0x8
+	v5:i64 = Load module_ctx, 0x8
+	v6:i64 = Uload32 module_ctx, 0x10
 	Jump blk3, v2
 
 blk2: () <-- (blk0)
@@ -902,11 +902,11 @@ blk2: () <-- (blk0)
 blk3: (v7:i32) <-- (blk1,blk2)
 	v8:i64 = Iconst_64 0x4
 	v9:i64 = UExtend v7, 32->64
-	v10:i64 = Uload32 module_ctx, 0x8
+	v10:i64 = Uload32 module_ctx, 0x10
 	v11:i64 = Iadd v9, v8
 	v12:i32 = Icmp ge_u, v10, v11
 	ExitIfNotZero v12, exec_ctx, memory_out_of_bounds
-	v13:i64 = Load module_ctx, 0x0
+	v13:i64 = Load module_ctx, 0x8
 	v14:i64 = Iadd v13, v9
 	v15:i32 = Load v14, 0x0
 	Jump blk_ret, v15
@@ -932,11 +932,11 @@ blk2: () <-- (blk0)
 blk3: () <-- (blk1,blk2)
 	v8:i64 = Iconst_64 0x4
 	v9:i64 = UExtend v2, 32->64
-	v10:i64 = Uload32 module_ctx, 0x8
+	v10:i64 = Uload32 module_ctx, 0x10
 	v11:i64 = Iadd v9, v8
 	v12:i32 = Icmp ge_u, v10, v11
 	ExitIfNotZero v12, exec_ctx, memory_out_of_bounds
-	v13:i64 = Load module_ctx, 0x0
+	v13:i64 = Load module_ctx, 0x8
 	v14:i64 = Iadd v13, v9
 	v15:i32 = Load v14, 0x0
 	Jump blk_ret, v15
@@ -950,8 +950,8 @@ signatures:
 
 blk0: (exec_ctx:i64, module_ctx:i64, v2:i32)
 	Store module_ctx, exec_ctx, 0x8
-	v3:i64 = Load module_ctx, 0x0
-	v4:i64 = Load module_ctx, 0x8
+	v3:i64 = Load module_ctx, 0x8
+	v4:i64 = Load module_ctx, 0x10
 	v5:i32 = CallIndirect v3:sig0, exec_ctx, v4, v2
 	Jump blk_ret, v5
 `,
@@ -962,11 +962,11 @@ blk0: (exec_ctx:i64, module_ctx:i64, v2:i32)
 blk0: (exec_ctx:i64, module_ctx:i64, v2:i32)
 	v3:i64 = Iconst_64 0x4
 	v4:i64 = UExtend v2, 32->64
-	v5:i64 = Uload32 module_ctx, 0x8
+	v5:i64 = Uload32 module_ctx, 0x10
 	v6:i64 = Iadd v4, v3
 	v7:i32 = Icmp ge_u, v5, v6
 	ExitIfNotZero v7, exec_ctx, memory_out_of_bounds
-	v8:i64 = Load module_ctx, 0x0
+	v8:i64 = Load module_ctx, 0x8
 	v9:i64 = Iadd v8, v4
 	v10:i32 = Load v9, 0x0
 	v11:i64 = Iconst_64 0x8
@@ -1166,13 +1166,13 @@ blk0: (exec_ctx:i64, module_ctx:i64, v2:i32)
 			m:    testcases.GlobalsGet.Module,
 			exp: `
 blk0: (exec_ctx:i64, module_ctx:i64)
-	v2:i64 = Load module_ctx, 0x0
+	v2:i64 = Load module_ctx, 0x8
 	v3:i32 = Load v2, 0x8
-	v4:i64 = Load module_ctx, 0x8
+	v4:i64 = Load module_ctx, 0x10
 	v5:i64 = Load v4, 0x8
-	v6:i64 = Load module_ctx, 0x10
+	v6:i64 = Load module_ctx, 0x18
 	v7:f32 = Load v6, 0x8
-	v8:i64 = Load module_ctx, 0x18
+	v8:i64 = Load module_ctx, 0x20
 	v9:f64 = Load v8, 0x8
 	Jump blk_ret, v3, v5, v7, v9
 `,
@@ -1183,16 +1183,16 @@ blk0: (exec_ctx:i64, module_ctx:i64)
 			exp: `
 blk0: (exec_ctx:i64, module_ctx:i64)
 	v2:i32 = Iconst_32 0x1
-	v3:i64 = Load module_ctx, 0x0
+	v3:i64 = Load module_ctx, 0x8
 	Store v2, v3, 0x8
 	v4:i64 = Iconst_64 0x2
-	v5:i64 = Load module_ctx, 0x8
+	v5:i64 = Load module_ctx, 0x10
 	Store v4, v5, 0x8
 	v6:f32 = F32const 3.000000
-	v7:i64 = Load module_ctx, 0x10
+	v7:i64 = Load module_ctx, 0x18
 	Store v6, v7, 0x8
 	v8:f64 = F64const 4.000000
-	v9:i64 = Load module_ctx, 0x18
+	v9:i64 = Load module_ctx, 0x20
 	Store v8, v9, 0x8
 	Jump blk_ret, v2, v4, v6, v8
 `,
@@ -1205,23 +1205,23 @@ signatures:
 	sig1: i64i64_v
 
 blk0: (exec_ctx:i64, module_ctx:i64)
-	v2:i64 = Load module_ctx, 0x0
+	v2:i64 = Load module_ctx, 0x8
 	v3:i32 = Load v2, 0x8
-	v4:i64 = Load module_ctx, 0x8
+	v4:i64 = Load module_ctx, 0x10
 	v5:i64 = Load v4, 0x8
-	v6:i64 = Load module_ctx, 0x10
+	v6:i64 = Load module_ctx, 0x18
 	v7:f32 = Load v6, 0x8
-	v8:i64 = Load module_ctx, 0x18
+	v8:i64 = Load module_ctx, 0x20
 	v9:f64 = Load v8, 0x8
 	Store module_ctx, exec_ctx, 0x8
 	Call f1:sig1, exec_ctx, module_ctx
-	v10:i64 = Load module_ctx, 0x0
+	v10:i64 = Load module_ctx, 0x8
 	v11:i32 = Load v10, 0x8
-	v12:i64 = Load module_ctx, 0x8
+	v12:i64 = Load module_ctx, 0x10
 	v13:i64 = Load v12, 0x8
-	v14:i64 = Load module_ctx, 0x10
+	v14:i64 = Load module_ctx, 0x18
 	v15:f32 = Load v14, 0x8
-	v16:i64 = Load module_ctx, 0x18
+	v16:i64 = Load module_ctx, 0x20
 	v17:f64 = Load v16, 0x8
 	Jump blk_ret, v3, v5, v7, v9, v11, v13, v15, v17
 `,
@@ -1230,25 +1230,69 @@ signatures:
 	sig1: i64i64_v
 
 blk0: (exec_ctx:i64, module_ctx:i64)
-	v2:i64 = Load module_ctx, 0x0
+	v2:i64 = Load module_ctx, 0x8
 	v3:i32 = Load v2, 0x8
-	v4:i64 = Load module_ctx, 0x8
+	v4:i64 = Load module_ctx, 0x10
 	v5:i64 = Load v4, 0x8
-	v6:i64 = Load module_ctx, 0x10
+	v6:i64 = Load module_ctx, 0x18
 	v7:f32 = Load v6, 0x8
-	v8:i64 = Load module_ctx, 0x18
+	v8:i64 = Load module_ctx, 0x20
 	v9:f64 = Load v8, 0x8
 	Store module_ctx, exec_ctx, 0x8
 	Call f1:sig1, exec_ctx, module_ctx
-	v10:i64 = Load module_ctx, 0x0
+	v10:i64 = Load module_ctx, 0x8
 	v11:i32 = Load v10, 0x8
-	v12:i64 = Load module_ctx, 0x8
+	v12:i64 = Load module_ctx, 0x10
 	v13:i64 = Load v12, 0x8
-	v14:i64 = Load module_ctx, 0x10
+	v14:i64 = Load module_ctx, 0x18
 	v15:f32 = Load v14, 0x8
-	v16:i64 = Load module_ctx, 0x18
+	v16:i64 = Load module_ctx, 0x20
 	v17:f64 = Load v16, 0x8
 	Jump blk_ret, v3, v5, v7, v9, v11, v13, v15, v17
+`,
+		},
+		{
+			name: "memory_size_grow",
+			m:    testcases.MemorySizeGrow.Module,
+			exp: `
+signatures:
+	sig1: i32i32_i32
+
+blk0: (exec_ctx:i64, module_ctx:i64)
+	v2:i32 = Iconst_32 0x1
+	Store module_ctx, exec_ctx, 0x8
+	v3:i64 = Load exec_ctx, 0x48
+	v4:i32 = CallIndirect v3:sig1, exec_ctx, v2
+	v5:i64 = Load module_ctx, 0x8
+	v6:i64 = Uload32 module_ctx, 0x10
+	v7:i32 = Load module_ctx, 0x10
+	v8:i32 = Iconst_32 0x10
+	v9:i32 = Ushr v7, v8
+	v10:i32 = Iconst_32 0x1
+	Store module_ctx, exec_ctx, 0x8
+	v11:i64 = Load exec_ctx, 0x48
+	v12:i32 = CallIndirect v11:sig1, exec_ctx, v10
+	v13:i64 = Load module_ctx, 0x8
+	v14:i64 = Uload32 module_ctx, 0x10
+	Jump blk_ret, v4, v9, v12
+`,
+			expAfterOpt: `
+signatures:
+	sig1: i32i32_i32
+
+blk0: (exec_ctx:i64, module_ctx:i64)
+	v2:i32 = Iconst_32 0x1
+	Store module_ctx, exec_ctx, 0x8
+	v3:i64 = Load exec_ctx, 0x48
+	v4:i32 = CallIndirect v3:sig1, exec_ctx, v2
+	v7:i32 = Load module_ctx, 0x10
+	v8:i32 = Iconst_32 0x10
+	v9:i32 = Ushr v7, v8
+	v10:i32 = Iconst_32 0x1
+	Store module_ctx, exec_ctx, 0x8
+	v11:i64 = Load exec_ctx, 0x48
+	v12:i32 = CallIndirect v11:sig1, exec_ctx, v10
+	Jump blk_ret, v4, v9, v12
 `,
 		},
 	} {
diff --git a/internal/engine/wazevo/testcases/testcases.go b/internal/engine/wazevo/testcases/testcases.go
index a01d7f54..30a929ed 100644
--- a/internal/engine/wazevo/testcases/testcases.go
+++ b/internal/engine/wazevo/testcases/testcases.go
@@ -798,6 +798,24 @@ var (
 		},
 	}
 
+	MemorySizeGrow = TestCase{
+		Name: "memory_size_grow",
+		Module: &wasm.Module{
+			TypeSection:     []wasm.FunctionType{{Results: []wasm.ValueType{i32, i32, i32}}},
+			ExportSection:   []wasm.Export{{Name: ExportName, Type: wasm.ExternTypeFunc, Index: 0}},
+			MemorySection:   &wasm.Memory{Min: 1, Max: 2, IsMaxEncoded: true},
+			FunctionSection: []wasm.Index{0},
+			CodeSection: []wasm.Code{{Body: []byte{
+				wasm.OpcodeI32Const, 1,
+				wasm.OpcodeMemoryGrow, 0, // return 1.
+				wasm.OpcodeMemorySize, 0, // return 2.
+				wasm.OpcodeI32Const, 1,
+				wasm.OpcodeMemoryGrow, 0, // return -1 since already maximum size.
+				wasm.OpcodeEnd,
+			}}},
+		},
+	}
+
 	MemoryLoadBasic2 = TestCase{
 		Name: "memory_load_basic2",
 		Module: &wasm.Module{
diff --git a/internal/engine/wazevo/wazevo_test.go b/internal/engine/wazevo/wazevo_test.go
index 335ceb5c..812d40b3 100644
--- a/internal/engine/wazevo/wazevo_test.go
+++ b/internal/engine/wazevo/wazevo_test.go
@@ -55,8 +55,11 @@ func Test_ExecutionContextOffsets(t *testing.T) {
 	require.Equal(t, wazevoapi.Offset(unsafe.Offsetof(execCtx.originalStackPointer)), offsets.OriginalStackPointer)
 	require.Equal(t, wazevoapi.Offset(unsafe.Offsetof(execCtx.goReturnAddress)), offsets.GoReturnAddress)
 	require.Equal(t, wazevoapi.Offset(unsafe.Offsetof(execCtx.goCallReturnAddress)), offsets.GoCallReturnAddress)
-	require.Equal(t, wazevoapi.Offset(unsafe.Offsetof(execCtx.stackPointerBeforeGrow)), offsets.StackPointerBeforeGrow)
+	require.Equal(t, wazevoapi.Offset(unsafe.Offsetof(execCtx.stackPointerBeforeGoCall)), offsets.StackPointerBeforeGrow)
 	require.Equal(t, wazevoapi.Offset(unsafe.Offsetof(execCtx.stackGrowRequiredSize)), offsets.StackGrowRequiredSize)
+	require.Equal(t, wazevoapi.Offset(unsafe.Offsetof(execCtx.memoryGrowTrampolineAddress)), offsets.MemoryGrowTrampolineAddress)
+	require.Equal(t, wazevoapi.Offset(unsafe.Offsetof(execCtx.savedRegisters))%16, wazevoapi.Offset(0),
+		"SavedRegistersBegin must be aligned to 16 bytes")
 	require.Equal(t, wazevoapi.Offset(unsafe.Offsetof(execCtx.savedRegisters)), offsets.SavedRegistersBegin)
-	require.Equal(t, wazevoapi.Offset(unsafe.Offsetof(execCtx.savedRegisters))%16, wazevoapi.Offset(0))
+	require.Equal(t, wazevoapi.Offset(unsafe.Offsetof(execCtx.goFunctionCallStack)), offsets.GoFunctionCallStackBegin)
 }
diff --git a/internal/engine/wazevo/wazevoapi/offsetdata_test.go b/internal/engine/wazevo/wazevoapi/offsetdata_test.go
index dea56b70..a0245f99 100644
--- a/internal/engine/wazevo/wazevoapi/offsetdata_test.go
+++ b/internal/engine/wazevo/wazevoapi/offsetdata_test.go
@@ -21,18 +21,18 @@ func TestNewModuleContextOffsetData(t *testing.T) {
 				ImportedMemoryBegin:    -1,
 				ImportedFunctionsBegin: -1,
 				GlobalsBegin:           -1,
-				TotalSize:              0,
+				TotalSize:              8,
 			},
 		},
 		{
 			name: "local mem",
 			m:    &wasm.Module{MemorySection: &wasm.Memory{}},
 			exp: ModuleContextOffsetData{
-				LocalMemoryBegin:       0,
+				LocalMemoryBegin:       8,
 				ImportedMemoryBegin:    -1,
 				ImportedFunctionsBegin: -1,
 				GlobalsBegin:           -1,
-				TotalSize:              16,
+				TotalSize:              24,
 			},
 		},
 		{
@@ -40,10 +40,10 @@ func TestNewModuleContextOffsetData(t *testing.T) {
 			m:    &wasm.Module{ImportMemoryCount: 1},
 			exp: ModuleContextOffsetData{
 				LocalMemoryBegin:       -1,
-				ImportedMemoryBegin:    0,
+				ImportedMemoryBegin:    8,
 				ImportedFunctionsBegin: -1,
 				GlobalsBegin:           -1,
-				TotalSize:              8,
+				TotalSize:              16,
 			},
 		},
 		{
@@ -52,9 +52,9 @@ func TestNewModuleContextOffsetData(t *testing.T) {
 			exp: ModuleContextOffsetData{
 				LocalMemoryBegin:       -1,
 				ImportedMemoryBegin:    -1,
-				ImportedFunctionsBegin: 0,
+				ImportedFunctionsBegin: 8,
 				GlobalsBegin:           -1,
-				TotalSize:              160,
+				TotalSize:              168,
 			},
 		},
 		{
@@ -62,10 +62,10 @@ func TestNewModuleContextOffsetData(t *testing.T) {
 			m:    &wasm.Module{ImportMemoryCount: 1, ImportFunctionCount: 10},
 			exp: ModuleContextOffsetData{
 				LocalMemoryBegin:       -1,
-				ImportedMemoryBegin:    0,
-				ImportedFunctionsBegin: 8,
+				ImportedMemoryBegin:    8,
+				ImportedFunctionsBegin: 16,
 				GlobalsBegin:           -1,
-				TotalSize:              168,
+				TotalSize:              176,
 			},
 		},
 		{
@@ -77,11 +77,11 @@ func TestNewModuleContextOffsetData(t *testing.T) {
 				GlobalSection:       make([]wasm.Global, 20),
 			},
 			exp: ModuleContextOffsetData{
-				LocalMemoryBegin:       0,
+				LocalMemoryBegin:       8,
 				ImportedMemoryBegin:    -1,
-				ImportedFunctionsBegin: 16,
-				GlobalsBegin:           16 + 16*10,
-				TotalSize:              16 + 16*10 + 8*30,
+				ImportedFunctionsBegin: 24,
+				GlobalsBegin:           24 + 16*10,
+				TotalSize:              24 + 16*10 + 8*30,
 			},
 		},
 	} {