package wazevo

import (
	
	
	
	
	
	

	
	
	
	
	
	
	
	
)

type (
	// callEngine implements api.Function.
	callEngine struct {
		internalapi.WazeroOnly
		stack []byte
		// stackTop is the pointer to the *aligned* top of the stack. This must be updated
		// whenever the stack is changed. This is passed to the assembly function
		// at the very beginning of api.Function Call/CallWithStack.
		stackTop uintptr
		// executable is the pointer to the executable code for this function.
		executable         *byte
		preambleExecutable *byte
		// parent is the *moduleEngine from which this callEngine is created.
		parent *moduleEngine
		// indexInModule is the index of the function in the module.
		indexInModule wasm.Index
		// sizeOfParamResultSlice is the size of the parameter/result slice.
		sizeOfParamResultSlice int
		requiredParams         int
		// execCtx holds various information to be read/written by assembly functions.
		execCtx executionContext
		// execCtxPtr holds the pointer to the executionContext which doesn't change after callEngine is created.
		execCtxPtr        uintptr
		numberOfResults   int
		stackIteratorImpl stackIterator
	}

	// executionContext is the struct to be read/written by assembly functions.
	executionContext struct {
		// exitCode holds the wazevoapi.ExitCode describing the state of the function execution.
		exitCode wazevoapi.ExitCode
		// callerModuleContextPtr holds the moduleContextOpaque for Go function calls.
		callerModuleContextPtr *byte
		// originalFramePointer holds the original frame pointer of the caller of the assembly function.
		originalFramePointer uintptr
		// originalStackPointer holds the original stack pointer of the caller of the assembly function.
		originalStackPointer uintptr
		// goReturnAddress holds the return address to go back to the caller of the assembly function.
		goReturnAddress uintptr
		// stackBottomPtr holds the pointer to the bottom of the stack.
		stackBottomPtr *byte
		// goCallReturnAddress holds the return address to go back to the caller of the Go function.
		goCallReturnAddress *byte
		// stackPointerBeforeGoCall holds the stack pointer before calling a Go function.
		stackPointerBeforeGoCall *uint64
		// stackGrowRequiredSize holds the required size of stack grow.
		stackGrowRequiredSize uintptr
		// memoryGrowTrampolineAddress holds the address of memory grow trampoline function.
		memoryGrowTrampolineAddress *byte
		// stackGrowCallTrampolineAddress holds the address of stack grow trampoline function.
		stackGrowCallTrampolineAddress *byte
		// checkModuleExitCodeTrampolineAddress holds the address of check-module-exit-code function.
		checkModuleExitCodeTrampolineAddress *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
		// goFunctionCallCalleeModuleContextOpaque is the pointer to the target Go function's moduleContextOpaque.
		goFunctionCallCalleeModuleContextOpaque uintptr
		// tableGrowTrampolineAddress holds the address of table grow trampoline function.
		tableGrowTrampolineAddress *byte
		// refFuncTrampolineAddress holds the address of ref-func trampoline function.
		refFuncTrampolineAddress *byte
		// memmoveAddress holds the address of memmove function implemented by Go runtime. See memmove.go.
		memmoveAddress uintptr
		// framePointerBeforeGoCall holds the frame pointer before calling a Go function. Note: only used in amd64.
		framePointerBeforeGoCall uintptr
		// memoryWait32TrampolineAddress holds the address of memory_wait32 trampoline function.
		memoryWait32TrampolineAddress *byte
		// memoryWait32TrampolineAddress holds the address of memory_wait64 trampoline function.
		memoryWait64TrampolineAddress *byte
		// memoryNotifyTrampolineAddress holds the address of the memory_notify trampoline function.
		memoryNotifyTrampolineAddress *byte
	}
)

func ( *callEngine) () int {
	const  = 10240
	 := 
	 := .sizeOfParamResultSlice * 8 * 2 // * 8 because uint64 is 8 bytes, and *2 because we need both separated param/result slots.
	 :=  + 32 + 16               // 32 is enough to accommodate the call frame info, and 16 exists just in case when []byte is not aligned to 16 bytes.
	if  >  {
		 = 
	}
	return 
}

func ( *callEngine) () {
	 := .requiredInitialStackSize()
	if wazevoapi.StackGuardCheckEnabled {
		 += wazevoapi.StackGuardCheckGuardPageSize
	}
	.stack = make([]byte, )
	.stackTop = alignedStackTop(.stack)
	if wazevoapi.StackGuardCheckEnabled {
		.execCtx.stackBottomPtr = &.stack[wazevoapi.StackGuardCheckGuardPageSize]
	} else {
		.execCtx.stackBottomPtr = &.stack[0]
	}
	.execCtxPtr = uintptr(unsafe.Pointer(&.execCtx))
}

// alignedStackTop returns 16-bytes aligned stack top of given stack.
// 16 bytes should be good for all platform (arm64/amd64).
func alignedStackTop( []byte) uintptr {
	 := uintptr(unsafe.Pointer(&[len()-1]))
	return  - ( & (16 - 1))
}

// Definition implements api.Function.
func ( *callEngine) () api.FunctionDefinition {
	return .parent.module.Source.FunctionDefinition(.indexInModule)
}

// Call implements api.Function.
func ( *callEngine) ( context.Context,  ...uint64) ([]uint64, error) {
	if .requiredParams != len() {
		return nil, fmt.Errorf("expected %d params, but passed %d", .requiredParams, len())
	}
	 := make([]uint64, .sizeOfParamResultSlice)
	copy(, )
	if  := .callWithStack(, );  != nil {
		return nil, 
	}
	return [:.numberOfResults], nil
}

func ( *callEngine) ( wasmdebug.ErrorBuilder,  uintptr) ( api.FunctionDefinition,  experimental.FunctionListener) {
	 := .parent.parent.parent
	 := .compiledModuleOfAddr()
	if  == nil {
		// This case, the module might have been closed and deleted from the engine.
		// We fall back to searching the imported modules that can be referenced from this callEngine.

		// First, we check itself.
		if checkAddrInBytes(, .parent.parent.executable) {
			 = .parent.parent
		} else {
			// Otherwise, search all imported modules. TODO: maybe recursive, but not sure it's useful in practice.
			 := .parent
			for  := range .importedFunctions {
				 := .importedFunctions[].me.parent
				if checkAddrInBytes(, .executable) {
					 = 
					break
				}
			}
		}
	}

	if  != nil {
		 := .functionIndexOf()
		 = .module.FunctionDefinition(.module.ImportFunctionCount + )
		var  []string
		if  := .module.DWARFLines;  != nil {
			 := .getSourceOffset()
			 = .Line()
		}
		.AddFrame(.DebugName(), .ParamTypes(), .ResultTypes(), )
		if len(.listeners) > 0 {
			 = .listeners[]
		}
	}
	return
}

// CallWithStack implements api.Function.
func ( *callEngine) ( context.Context,  []uint64) ( error) {
	if .sizeOfParamResultSlice > len() {
		return fmt.Errorf("need %d params, but stack size is %d", .sizeOfParamResultSlice, len())
	}
	return .callWithStack(, )
}

// CallWithStack implements api.Function.
func ( *callEngine) ( context.Context,  []uint64) ( error) {
	 := .Value(expctxkeys.EnableSnapshotterKey{}) != nil
	if  {
		 = context.WithValue(, expctxkeys.SnapshotterKey{}, )
	}

	if wazevoapi.StackGuardCheckEnabled {
		defer func() {
			wazevoapi.CheckStackGuardPage(.stack)
		}()
	}

	 := .parent
	 := .parent.ensureTermination
	 := .module
	if  {
		select {
		case <-.Done():
			// If the provided context is already done, close the module and return the error.
			.CloseWithCtxErr()
			return .FailIfClosed()
		default:
		}
	}

	var  *uint64
	if len() > 0 {
		 = &[0]
	}
	defer func() {
		 := recover()
		if ,  := .(*snapshot);  {
			// A snapshot that wasn't handled was created by a different call engine possibly from a nested wasm invocation,
			// let it propagate up to be handled by the caller.
			panic()
		}
		if  != nil {
			type  struct {
				 api.FunctionDefinition
				 experimental.FunctionListener
			}

			var  []
			 := wasmdebug.NewErrorBuilder()
			,  := .addFrame(, uintptr(unsafe.Pointer(.execCtx.goCallReturnAddress)))
			if  != nil {
				 = append(, {, })
			}
			 := unwindStack(
				uintptr(unsafe.Pointer(.execCtx.stackPointerBeforeGoCall)),
				.execCtx.framePointerBeforeGoCall,
				.stackTop,
				nil,
			)
			for ,  := range [:len()-1] { // the last return addr is the trampoline, so we skip it.
				,  = .addFrame(, )
				if  != nil {
					 = append(, {, })
				}
			}
			 = .FromRecovered()

			for ,  := range  {
				..Abort(, , ., )
			}
		} else {
			if  != wasmruntime.ErrRuntimeStackOverflow { // Stackoverflow case shouldn't be panic (to avoid extreme stack unwinding).
				 = .parent.module.FailIfClosed()
			}
		}

		if  != nil {
			// Ensures that we can reuse this callEngine even after an error.
			.execCtx.exitCode = wazevoapi.ExitCodeOK
		}
	}()

	if  {
		 := .CloseModuleOnCanceledOrTimeout()
		defer ()
	}

	if .stackTop&(16-1) != 0 {
		panic("BUG: stack must be aligned to 16 bytes")
	}
	entrypoint(.preambleExecutable, .executable, .execCtxPtr, .parent.opaquePtr, , .stackTop)
	for {
		switch  := .execCtx.exitCode;  & wazevoapi.ExitCodeMask {
		case wazevoapi.ExitCodeOK:
			return nil
		case wazevoapi.ExitCodeGrowStack:
			 := uintptr(unsafe.Pointer(.execCtx.stackPointerBeforeGoCall))
			 := .stackTop
			 := .stack
			var ,  uintptr
			if wazevoapi.StackGuardCheckEnabled {
				, ,  = .growStackWithGuarded()
			} else {
				, ,  = .growStack()
			}
			if  != nil {
				return 
			}
			adjustClonedStack(, , , , .stackTop)
			// Old stack must be alive until the new stack is adjusted.
			runtime.KeepAlive()
			.execCtx.exitCode = wazevoapi.ExitCodeOK
			afterGoFunctionCallEntrypoint(.execCtx.goCallReturnAddress, .execCtxPtr, , )
		case wazevoapi.ExitCodeGrowMemory:
			 := .callerModuleInstance()
			 := .MemoryInstance
			 := goCallStackView(.execCtx.stackPointerBeforeGoCall)
			 := &[0]
			if ,  := .Grow(uint32(*)); ! {
				* = uint64(0xffffffff) // = -1 in signed 32-bit integer.
			} else {
				* = uint64()
			}
			.execCtx.exitCode = wazevoapi.ExitCodeOK
			afterGoFunctionCallEntrypoint(.execCtx.goCallReturnAddress, .execCtxPtr, uintptr(unsafe.Pointer(.execCtx.stackPointerBeforeGoCall)), .execCtx.framePointerBeforeGoCall)
		case wazevoapi.ExitCodeTableGrow:
			 := .callerModuleInstance()
			 := goCallStackView(.execCtx.stackPointerBeforeGoCall)
			, ,  := uint32([0]), uint32([1]), uintptr([2])
			 := .Tables[]
			[0] = uint64(uint32(int32(.Grow(, ))))
			.execCtx.exitCode = wazevoapi.ExitCodeOK
			afterGoFunctionCallEntrypoint(.execCtx.goCallReturnAddress, .execCtxPtr,
				uintptr(unsafe.Pointer(.execCtx.stackPointerBeforeGoCall)), .execCtx.framePointerBeforeGoCall)
		case wazevoapi.ExitCodeCallGoFunction:
			 := wazevoapi.GoFunctionIndexFromExitCode()
			 := hostModuleGoFuncFromOpaque[api.GoFunction](, .execCtx.goFunctionCallCalleeModuleContextOpaque)
			func() {
				if  {
					defer snapshotRecoverFn()
				}
				.Call(, goCallStackView(.execCtx.stackPointerBeforeGoCall))
			}()
			// Back to the native code.
			.execCtx.exitCode = wazevoapi.ExitCodeOK
			afterGoFunctionCallEntrypoint(.execCtx.goCallReturnAddress, .execCtxPtr,
				uintptr(unsafe.Pointer(.execCtx.stackPointerBeforeGoCall)), .execCtx.framePointerBeforeGoCall)
		case wazevoapi.ExitCodeCallGoFunctionWithListener:
			 := wazevoapi.GoFunctionIndexFromExitCode()
			 := hostModuleGoFuncFromOpaque[api.GoFunction](, .execCtx.goFunctionCallCalleeModuleContextOpaque)
			 := hostModuleListenersSliceFromOpaque(.execCtx.goFunctionCallCalleeModuleContextOpaque)
			 := goCallStackView(.execCtx.stackPointerBeforeGoCall)
			// Call Listener.Before.
			 := .callerModuleInstance()
			 := []
			 := hostModuleFromOpaque(.execCtx.goFunctionCallCalleeModuleContextOpaque)
			 := .FunctionDefinition(wasm.Index())
			.Before(, , , , .stackIterator(true))
			// Call into the Go function.
			func() {
				if  {
					defer snapshotRecoverFn()
				}
				.Call(, )
			}()
			// Call Listener.After.
			.After(, , , )
			// Back to the native code.
			.execCtx.exitCode = wazevoapi.ExitCodeOK
			afterGoFunctionCallEntrypoint(.execCtx.goCallReturnAddress, .execCtxPtr,
				uintptr(unsafe.Pointer(.execCtx.stackPointerBeforeGoCall)), .execCtx.framePointerBeforeGoCall)
		case wazevoapi.ExitCodeCallGoModuleFunction:
			 := wazevoapi.GoFunctionIndexFromExitCode()
			 := hostModuleGoFuncFromOpaque[api.GoModuleFunction](, .execCtx.goFunctionCallCalleeModuleContextOpaque)
			 := .callerModuleInstance()
			func() {
				if  {
					defer snapshotRecoverFn()
				}
				.Call(, , goCallStackView(.execCtx.stackPointerBeforeGoCall))
			}()
			// Back to the native code.
			.execCtx.exitCode = wazevoapi.ExitCodeOK
			afterGoFunctionCallEntrypoint(.execCtx.goCallReturnAddress, .execCtxPtr,
				uintptr(unsafe.Pointer(.execCtx.stackPointerBeforeGoCall)), .execCtx.framePointerBeforeGoCall)
		case wazevoapi.ExitCodeCallGoModuleFunctionWithListener:
			 := wazevoapi.GoFunctionIndexFromExitCode()
			 := hostModuleGoFuncFromOpaque[api.GoModuleFunction](, .execCtx.goFunctionCallCalleeModuleContextOpaque)
			 := hostModuleListenersSliceFromOpaque(.execCtx.goFunctionCallCalleeModuleContextOpaque)
			 := goCallStackView(.execCtx.stackPointerBeforeGoCall)
			// Call Listener.Before.
			 := .callerModuleInstance()
			 := []
			 := hostModuleFromOpaque(.execCtx.goFunctionCallCalleeModuleContextOpaque)
			 := .FunctionDefinition(wasm.Index())
			.Before(, , , , .stackIterator(true))
			// Call into the Go function.
			func() {
				if  {
					defer snapshotRecoverFn()
				}
				.Call(, , )
			}()
			// Call Listener.After.
			.After(, , , )
			// Back to the native code.
			.execCtx.exitCode = wazevoapi.ExitCodeOK
			afterGoFunctionCallEntrypoint(.execCtx.goCallReturnAddress, .execCtxPtr,
				uintptr(unsafe.Pointer(.execCtx.stackPointerBeforeGoCall)), .execCtx.framePointerBeforeGoCall)
		case wazevoapi.ExitCodeCallListenerBefore:
			 := goCallStackView(.execCtx.stackPointerBeforeGoCall)
			 := wasm.Index([0])
			 := .callerModuleInstance()
			 := .Engine.(*moduleEngine).listeners[]
			 := .Source.FunctionDefinition( + .Source.ImportFunctionCount)
			.Before(, , , [1:], .stackIterator(false))
			.execCtx.exitCode = wazevoapi.ExitCodeOK
			afterGoFunctionCallEntrypoint(.execCtx.goCallReturnAddress, .execCtxPtr,
				uintptr(unsafe.Pointer(.execCtx.stackPointerBeforeGoCall)), .execCtx.framePointerBeforeGoCall)
		case wazevoapi.ExitCodeCallListenerAfter:
			 := goCallStackView(.execCtx.stackPointerBeforeGoCall)
			 := wasm.Index([0])
			 := .callerModuleInstance()
			 := .Engine.(*moduleEngine).listeners[]
			 := .Source.FunctionDefinition( + .Source.ImportFunctionCount)
			.After(, , , [1:])
			.execCtx.exitCode = wazevoapi.ExitCodeOK
			afterGoFunctionCallEntrypoint(.execCtx.goCallReturnAddress, .execCtxPtr,
				uintptr(unsafe.Pointer(.execCtx.stackPointerBeforeGoCall)), .execCtx.framePointerBeforeGoCall)
		case wazevoapi.ExitCodeCheckModuleExitCode:
			// Note: this operation must be done in Go, not native code. The reason is that
			// native code cannot be preempted and that means it can block forever if there are not
			// enough OS threads (which we don't have control over).
			if  := .FailIfClosed();  != nil {
				panic()
			}
			.execCtx.exitCode = wazevoapi.ExitCodeOK
			afterGoFunctionCallEntrypoint(.execCtx.goCallReturnAddress, .execCtxPtr,
				uintptr(unsafe.Pointer(.execCtx.stackPointerBeforeGoCall)), .execCtx.framePointerBeforeGoCall)
		case wazevoapi.ExitCodeRefFunc:
			 := .callerModuleInstance()
			 := goCallStackView(.execCtx.stackPointerBeforeGoCall)
			 := wasm.Index([0])
			 := .Engine.FunctionInstanceReference()
			[0] = uint64()
			.execCtx.exitCode = wazevoapi.ExitCodeOK
			afterGoFunctionCallEntrypoint(.execCtx.goCallReturnAddress, .execCtxPtr,
				uintptr(unsafe.Pointer(.execCtx.stackPointerBeforeGoCall)), .execCtx.framePointerBeforeGoCall)
		case wazevoapi.ExitCodeMemoryWait32:
			 := .callerModuleInstance()
			 := .MemoryInstance
			if !.Shared {
				panic(wasmruntime.ErrRuntimeExpectedSharedMemory)
			}

			 := goCallStackView(.execCtx.stackPointerBeforeGoCall)
			, ,  := int64([0]), uint32([1]), uintptr([2])
			 := uintptr(unsafe.Pointer(&.Buffer[0]))

			 := uint32( - )
			 := .Wait32(, , , func( *wasm.MemoryInstance,  uint32) uint32 {
				 := unsafe.Add(unsafe.Pointer(&.Buffer[0]), )
				return atomic.LoadUint32((*uint32)())
			})
			[0] = 
			.execCtx.exitCode = wazevoapi.ExitCodeOK
			afterGoFunctionCallEntrypoint(.execCtx.goCallReturnAddress, .execCtxPtr,
				uintptr(unsafe.Pointer(.execCtx.stackPointerBeforeGoCall)), .execCtx.framePointerBeforeGoCall)
		case wazevoapi.ExitCodeMemoryWait64:
			 := .callerModuleInstance()
			 := .MemoryInstance
			if !.Shared {
				panic(wasmruntime.ErrRuntimeExpectedSharedMemory)
			}

			 := goCallStackView(.execCtx.stackPointerBeforeGoCall)
			, ,  := int64([0]), uint64([1]), uintptr([2])
			 := uintptr(unsafe.Pointer(&.Buffer[0]))

			 := uint32( - )
			 := .Wait64(, , , func( *wasm.MemoryInstance,  uint32) uint64 {
				 := unsafe.Add(unsafe.Pointer(&.Buffer[0]), )
				return atomic.LoadUint64((*uint64)())
			})
			[0] = uint64()
			.execCtx.exitCode = wazevoapi.ExitCodeOK
			afterGoFunctionCallEntrypoint(.execCtx.goCallReturnAddress, .execCtxPtr,
				uintptr(unsafe.Pointer(.execCtx.stackPointerBeforeGoCall)), .execCtx.framePointerBeforeGoCall)
		case wazevoapi.ExitCodeMemoryNotify:
			 := .callerModuleInstance()
			 := .MemoryInstance

			 := goCallStackView(.execCtx.stackPointerBeforeGoCall)
			,  := uint32([0]), [1]
			 := uint32(uintptr() - uintptr(unsafe.Pointer(&.Buffer[0])))
			 := .Notify(, )
			[0] = uint64()
			.execCtx.exitCode = wazevoapi.ExitCodeOK
			afterGoFunctionCallEntrypoint(.execCtx.goCallReturnAddress, .execCtxPtr,
				uintptr(unsafe.Pointer(.execCtx.stackPointerBeforeGoCall)), .execCtx.framePointerBeforeGoCall)
		case wazevoapi.ExitCodeUnreachable:
			panic(wasmruntime.ErrRuntimeUnreachable)
		case wazevoapi.ExitCodeMemoryOutOfBounds:
			panic(wasmruntime.ErrRuntimeOutOfBoundsMemoryAccess)
		case wazevoapi.ExitCodeTableOutOfBounds:
			panic(wasmruntime.ErrRuntimeInvalidTableAccess)
		case wazevoapi.ExitCodeIndirectCallNullPointer:
			panic(wasmruntime.ErrRuntimeInvalidTableAccess)
		case wazevoapi.ExitCodeIndirectCallTypeMismatch:
			panic(wasmruntime.ErrRuntimeIndirectCallTypeMismatch)
		case wazevoapi.ExitCodeIntegerOverflow:
			panic(wasmruntime.ErrRuntimeIntegerOverflow)
		case wazevoapi.ExitCodeIntegerDivisionByZero:
			panic(wasmruntime.ErrRuntimeIntegerDivideByZero)
		case wazevoapi.ExitCodeInvalidConversionToInteger:
			panic(wasmruntime.ErrRuntimeInvalidConversionToInteger)
		case wazevoapi.ExitCodeUnalignedAtomic:
			panic(wasmruntime.ErrRuntimeUnalignedAtomic)
		default:
			panic("BUG")
		}
	}
}

func ( *callEngine) () *wasm.ModuleInstance {
	return moduleInstanceFromOpaquePtr(.execCtx.callerModuleContextPtr)
}

const callStackCeiling = uintptr(50000000) // in uint64 (8 bytes) == 400000000 bytes in total == 400mb.

func ( *callEngine) () ( uintptr,  uintptr,  error) {
	if wazevoapi.StackGuardCheckEnabled {
		wazevoapi.CheckStackGuardPage(.stack)
	}
	, ,  = .growStack()
	if  != nil {
		return
	}
	if wazevoapi.StackGuardCheckEnabled {
		.execCtx.stackBottomPtr = &.stack[wazevoapi.StackGuardCheckGuardPageSize]
	}
	return
}

// growStack grows the stack, and returns the new stack pointer.
func ( *callEngine) () (,  uintptr,  error) {
	 := uintptr(len(.stack))
	if callStackCeiling <  {
		 = wasmruntime.ErrRuntimeStackOverflow
		return
	}

	 := 2* + .execCtx.stackGrowRequiredSize + 16 // Stack might be aligned to 16 bytes, so add 16 bytes just in case.
	, , .stackTop, .stack = .cloneStack()
	.execCtx.stackBottomPtr = &.stack[0]
	return
}

func ( *callEngine) ( uintptr) (, ,  uintptr,  []byte) {
	 = make([]byte, )

	 := .stackTop - uintptr(unsafe.Pointer(.execCtx.stackPointerBeforeGoCall))
	 := .stackTop - .execCtx.framePointerBeforeGoCall

	// Copy the existing contents in the previous Go-allocated stack into the new one.
	var ,  []byte
	{
		//nolint:staticcheck
		 := (*reflect.SliceHeader)(unsafe.Pointer(&))
		.Data = .stackTop - 
		.Len = int()
		.Cap = int()
	}
	 = alignedStackTop()
	{
		 =  - 
		 =  - 
		//nolint:staticcheck
		 := (*reflect.SliceHeader)(unsafe.Pointer(&))
		.Data = 
		.Len = int()
		.Cap = int()
	}
	copy(, )
	return
}

func ( *callEngine) ( bool) experimental.StackIterator {
	.stackIteratorImpl.reset(, )
	return &.stackIteratorImpl
}

// stackIterator implements experimental.StackIterator.
type stackIterator struct {
	retAddrs      []uintptr
	retAddrCursor int
	eng           *engine
	pc            uint64

	currentDef *wasm.FunctionDefinition
}

func ( *stackIterator) ( *callEngine,  bool) {
	if  {
		.retAddrs = append(.retAddrs[:0], uintptr(unsafe.Pointer(.execCtx.goCallReturnAddress)))
	} else {
		.retAddrs = .retAddrs[:0]
	}
	.retAddrs = unwindStack(uintptr(unsafe.Pointer(.execCtx.stackPointerBeforeGoCall)), .execCtx.framePointerBeforeGoCall, .stackTop, .retAddrs)
	.retAddrs = .retAddrs[:len(.retAddrs)-1] // the last return addr is the trampoline, so we skip it.
	.retAddrCursor = 0
	.eng = .parent.parent.parent
}

// Next implements the same method as documented on experimental.StackIterator.
func ( *stackIterator) () bool {
	if .retAddrCursor >= len(.retAddrs) {
		return false
	}

	 := .retAddrs[.retAddrCursor]
	 := .eng.compiledModuleOfAddr()
	if  != nil {
		 := .functionIndexOf()
		 := .module.FunctionDefinition(.module.ImportFunctionCount + )
		.currentDef = 
		.retAddrCursor++
		.pc = uint64()
		return true
	}
	return false
}

// ProgramCounter implements the same method as documented on experimental.StackIterator.
func ( *stackIterator) () experimental.ProgramCounter {
	return experimental.ProgramCounter(.pc)
}

// Function implements the same method as documented on experimental.StackIterator.
func ( *stackIterator) () experimental.InternalFunction {
	return 
}

// Definition implements the same method as documented on experimental.InternalFunction.
func ( *stackIterator) () api.FunctionDefinition {
	return .currentDef
}

// SourceOffsetForPC implements the same method as documented on experimental.InternalFunction.
func ( *stackIterator) ( experimental.ProgramCounter) uint64 {
	 := uintptr()
	 := .eng.compiledModuleOfAddr()
	return .getSourceOffset()
}

// snapshot implements experimental.Snapshot
type snapshot struct {
	sp, fp, top    uintptr
	returnAddress  *byte
	stack          []byte
	savedRegisters [64][2]uint64
	ret            []uint64
	c              *callEngine
}

// Snapshot implements the same method as documented on experimental.Snapshotter.
func ( *callEngine) () experimental.Snapshot {
	 := .execCtx.goCallReturnAddress
	,  := .stackTop, uintptr(unsafe.Pointer(.execCtx.stackPointerBeforeGoCall))
	, , ,  := .cloneStack(uintptr(len(.stack)) + 16)
	adjustClonedStack(, , , , )
	return &snapshot{
		sp:             ,
		fp:             ,
		top:            ,
		savedRegisters: .execCtx.savedRegisters,
		returnAddress:  ,
		stack:          ,
		c:              ,
	}
}

// Restore implements the same method as documented on experimental.Snapshot.
func ( *snapshot) ( []uint64) {
	.ret = 
	panic()
}

func ( *snapshot) () {
	 := *(**uint64)(unsafe.Pointer(&.sp))
	 := goCallStackView()
	copy(, .ret)

	 := .c
	.stack = .stack
	.stackTop = .top
	 := &.execCtx
	.stackBottomPtr = &.stack[0]
	.stackPointerBeforeGoCall = 
	.framePointerBeforeGoCall = .fp
	.goCallReturnAddress = .returnAddress
	.savedRegisters = .savedRegisters
}

// Error implements the same method on error.
func ( *snapshot) () string {
	return "unhandled snapshot restore, this generally indicates restore was called from a different " +
		"exported function invocation than snapshot"
}

func snapshotRecoverFn( *callEngine) {
	if  := recover();  != nil {
		if ,  := .(*snapshot);  && .c ==  {
			.doRestore()
		} else {
			panic()
		}
	}
}