package wazevo

import (
	
	
	
	
	
	
	
	
	
	

	
	
	
	
	
	
	
	
	
	
)

type (
	compiledModuleWithCount struct {
		*compiledModule
		refCount int
	}
	// engine implements wasm.Engine.
	engine struct {
		wazeroVersion   string
		fileCache       filecache.Cache
		compiledModules map[wasm.ModuleID]*compiledModuleWithCount
		// sortedCompiledModules is a list of compiled modules sorted by the initial address of the executable.
		sortedCompiledModules []*compiledModule
		mux                   sync.RWMutex
		// sharedFunctions is compiled functions shared by all modules.
		sharedFunctions *sharedFunctions
		// setFinalizer defaults to runtime.SetFinalizer, but overridable for tests.
		setFinalizer func(obj interface{}, finalizer interface{})

		// The followings are reused for compiling shared functions.
		machine backend.Machine
		be      backend.Compiler
	}

	sharedFunctions struct {
		// The compiled trampolines executable.
		executable []byte
		// memoryGrowAddress is the address of memory.grow builtin function.
		memoryGrowAddress *byte
		// checkModuleExitCodeAddress is the address of checking module instance exit code.
		// This is used when ensureTermination is true.
		checkModuleExitCodeAddress *byte
		// stackGrowAddress is the address of growing stack builtin function.
		stackGrowAddress *byte
		// tableGrowAddress is the address of table.grow builtin function.
		tableGrowAddress *byte
		// refFuncAddress is the address of ref.func builtin function.
		refFuncAddress *byte
		// memoryWait32Address is the address of memory.wait32 builtin function
		memoryWait32Address *byte
		// memoryWait64Address is the address of memory.wait64 builtin function
		memoryWait64Address *byte
		// memoryNotifyAddress is the address of memory.notify builtin function
		memoryNotifyAddress *byte
		listenerTrampolines listenerTrampolines
	}

	listenerTrampolines = map[*wasm.FunctionType]struct {
		executable []byte
		before     *byte
		after      *byte
	}

	// compiledModule is a compiled variant of a wasm.Module and ready to be used for instantiation.
	compiledModule struct {
		*executables
		// functionOffsets maps a local function index to the offset in the executable.
		functionOffsets           []int
		parent                    *engine
		module                    *wasm.Module
		ensureTermination         bool
		listeners                 []experimental.FunctionListener
		listenerBeforeTrampolines []*byte
		listenerAfterTrampolines  []*byte

		// The followings are only available for non host modules.

		offsets         wazevoapi.ModuleContextOffsetData
		sharedFunctions *sharedFunctions
		sourceMap       sourceMap
	}

	executables struct {
		executable         []byte
		entryPreambles     []byte
		entryPreamblesPtrs []*byte
	}
)

// sourceMap is a mapping from the offset of the executable to the offset of the original wasm binary.
type sourceMap struct {
	// executableOffsets is a sorted list of offsets of the executable. This is index-correlated with wasmBinaryOffsets,
	// in other words executableOffsets[i] is the offset of the executable which corresponds to the offset of a Wasm
	// binary pointed by wasmBinaryOffsets[i].
	executableOffsets []uintptr
	// wasmBinaryOffsets is the counterpart of executableOffsets.
	wasmBinaryOffsets []uint64
}

var _ wasm.Engine = (*engine)(nil)

// NewEngine returns the implementation of wasm.Engine.
func ( context.Context,  api.CoreFeatures,  filecache.Cache) wasm.Engine {
	 := newMachine()
	 := backend.NewCompiler(, , ssa.NewBuilder())
	 := &engine{
		compiledModules: make(map[wasm.ModuleID]*compiledModuleWithCount),
		setFinalizer:    runtime.SetFinalizer,
		machine:         ,
		be:              ,
		fileCache:       ,
		wazeroVersion:   version.GetWazeroVersion(),
	}
	.compileSharedFunctions()
	return 
}

// CompileModule implements wasm.Engine.
func ( *engine) ( context.Context,  *wasm.Module,  []experimental.FunctionListener,  bool) ( error) {
	if wazevoapi.PerfMapEnabled {
		wazevoapi.PerfMap.Lock()
		defer wazevoapi.PerfMap.Unlock()
	}

	if , ,  := .getCompiledModule(, , );  { // cache hit!
		return nil
	} else if  != nil {
		return 
	}

	if wazevoapi.DeterministicCompilationVerifierEnabled {
		 = wazevoapi.NewDeterministicCompilationVerifierContext(, len(.CodeSection))
	}
	,  := .compileModule(, , , )
	if  != nil {
		return 
	}
	if ,  = .addCompiledModule(, );  != nil {
		return 
	}

	if wazevoapi.DeterministicCompilationVerifierEnabled {
		for  := 0;  < wazevoapi.DeterministicCompilationVerifyingIter; ++ {
			,  := .compileModule(, , , )
			if  != nil {
				return 
			}
		}
	}

	if len() > 0 {
		.listeners = 
		.listenerBeforeTrampolines = make([]*byte, len(.TypeSection))
		.listenerAfterTrampolines = make([]*byte, len(.TypeSection))
		for  := range .TypeSection {
			 := &.TypeSection[]
			,  := .getListenerTrampolineForType()
			.listenerBeforeTrampolines[] = 
			.listenerAfterTrampolines[] = 
		}
	}
	return nil
}

func ( *executables) ( *wasm.Module,  backend.Machine,  backend.Compiler) {
	if len(.TypeSection) == 0 {
		return
	}

	var  []byte
	 := make([]int, len(.TypeSection))

	for  := range  {
		 := &.TypeSection[]
		 := frontend.SignatureForWasmFunctionType()
		.Init()
		 := .CompileEntryPreamble(&)
		 = append(, ...)
		 := 15 & -len() // Align 16-bytes boundary.
		 = append(, make([]byte, )...)
		[] = len() + 
	}

	.entryPreambles = mmapExecutable()
	.entryPreamblesPtrs = make([]*byte, len())

	 := 0
	for ,  := range  {
		 := &.entryPreambles[]
		.entryPreamblesPtrs[] = 
		 += 

		if wazevoapi.PerfMapEnabled {
			 := &.TypeSection[]
			wazevoapi.PerfMap.AddEntry(uintptr(unsafe.Pointer()),
				uint64(), fmt.Sprintf("entry_preamble::type=%s", .String()))
		}
	}
}

func ( *engine) ( context.Context,  *wasm.Module,  []experimental.FunctionListener,  bool) (*compiledModule, error) {
	if .IsHostModule {
		return .compileHostModule(, , )
	}

	 := len() > 0
	 := &compiledModule{
		offsets: wazevoapi.NewModuleContextOffsetData(, ), parent: , module: ,
		ensureTermination: ,
		executables:       &executables{},
	}

	,  := int(.ImportFunctionCount), len(.FunctionSection)
	if  == 0 {
		return , nil
	}

	 := newMachine()
	,  := newEngineRelocator(, , )
	if  != nil {
		return nil, 
	}

	 := .DWARFLines != nil

	 := ssa.NewBuilder()
	 := backend.NewCompiler(, , )
	.executables.compileEntryPreambles(, , )
	.functionOffsets = make([]int, )

	var  []int
	if wazevoapi.DeterministicCompilationVerifierEnabled {
		// The compilation must be deterministic regardless of the order of functions being compiled.
		 = wazevoapi.DeterministicCompilationVerifierRandomizeIndexes()
	}

	if  := experimental.GetCompilationWorkers();  <= 1 {
		// Compile with a single goroutine.
		 := frontend.NewFrontendCompiler(, , &.offsets, , , )

		for  := range .CodeSection {
			if wazevoapi.DeterministicCompilationVerifierEnabled {
				 = []
			}

			 := wasm.Index( + )
			 := functionContext(, , , )

			 := len() >  && [] != nil
			, ,  := .compileLocalWasmFunction(, , wasm.Index(), , , , )
			if  != nil {
				return nil, fmt.Errorf("compile function %d/%d: %v", , len(.CodeSection)-1, )
			}

			.appendFunction(, , , , , , , .SourceOffsetInfo())
		}
	} else {
		// Compile with N worker goroutines.
		// Collect compiled functions across workers in a slice,
		// to be added to the relocator in-order and resolved serially at the end.
		// This uses more memory and CPU (across cores), but can be significantly faster.
		type  struct {
			        context.Context
			        int
			        wasm.Index
			        []byte
			 []backend.RelocationInfo
			 []backend.SourceOffsetInfo
		}

		 := make([], len(.CodeSection))
		,  := context.WithCancelCause()
		defer (nil)

		var  atomic.Uint32
		var  sync.WaitGroup
		.Add()

		for range  {
			go func() {
				defer .Done()

				// Creates new compiler instances which are reused for each function.
				 := newMachine()
				 := ssa.NewBuilder()
				 := backend.NewCompiler(, , )
				 := frontend.NewFrontendCompiler(, , &.offsets, , , )

				for {
					if  := .Err();  != nil {
						// Compilation canceled!
						return
					}

					 := int(.Add(1)) - 1
					if  >= len(.CodeSection) {
						return
					}

					if wazevoapi.DeterministicCompilationVerifierEnabled {
						 = []
					}

					 := wasm.Index( + )
					 := functionContext(, , , )

					 := len() >  && [] != nil
					, ,  := .compileLocalWasmFunction(, , wasm.Index(), , , , )
					if  != nil {
						(fmt.Errorf("compile function %d/%d: %v", , len(.CodeSection)-1, ))
						return
					}

					[] = {
						, , , ,
						// These slices are internal to the backend compiler and since we are going to buffer them instead
						// of process them immediately we need to copy the memory.
						slices.Clone(),
						slices.Clone(.SourceOffsetInfo()),
					}
				}
			}()
		}

		.Wait()
		if  := context.Cause();  != nil {
			return nil, 
		}

		for  := range  {
			 := &[]
			.appendFunction(., , , ., ., ., ., .)
		}
	}

	// Allocate executable memory and then copy the generated machine code.
	,  := platform.MmapCodeSegment(.totalSize)
	if  != nil {
		panic()
	}
	.executable = 

	for ,  := range .bodies {
		 := .functionOffsets[]
		copy([:], )
	}

	if wazevoapi.PerfMapEnabled {
		wazevoapi.PerfMap.Flush(uintptr(unsafe.Pointer(&[0])), .functionOffsets)
	}

	if  {
		for  := range .sourceMap.executableOffsets {
			.sourceMap.executableOffsets[] += uintptr(unsafe.Pointer(&.executable[0]))
		}
	}

	.resolveRelocations(, , )

	if  = platform.MprotectCodeSegment();  != nil {
		return nil, 
	}
	.sharedFunctions = .sharedFunctions
	.setFinalizer(.executables, executablesFinalizer)
	return , nil
}

func functionContext( context.Context,  *wasm.Module,  int,  wasm.Index) context.Context {
	if wazevoapi.NeedFunctionNameInContext {
		 := .FunctionDefinition()
		 := .DebugName()
		if len(.ExportNames()) > 0 {
			 = .ExportNames()[0]
		}
		 = wazevoapi.SetCurrentFunctionName(, , fmt.Sprintf("[%d/%d]%s", , len(.CodeSection)-1, ))
	}
	return 
}

type engineRelocator struct {
	bodies                      [][]byte
	refToBinaryOffset           []int
	rels                        []backend.RelocationInfo
	totalSize                   int // Total binary size of the executable.
	trampolineInterval          int
	callTrampolineIslandSize    int
	callTrampolineIslandOffsets []int // Holds the offsets of trampoline islands.
}

func newEngineRelocator(
	 backend.Machine,
	,  int,
) ( engineRelocator,  error) {
	// Trampoline relocation related variables.
	.trampolineInterval, .callTrampolineIslandSize,  = .CallTrampolineIslandInfo()
	.refToBinaryOffset = make([]int, +)
	.bodies = make([][]byte, 0, )
	return
}

func ( *engineRelocator) ( backend.Machine,  []byte,  int) {
	// Resolve relocations for local function calls.
	if len(.rels) > 0 {
		.ResolveRelocations(.refToBinaryOffset, , , .rels, .callTrampolineIslandOffsets)
	}
}

func ( *engineRelocator) (
	 context.Context,
	 *wasm.Module,
	 *compiledModule,
	 int,  wasm.Index,
	 []byte,
	 []backend.RelocationInfo,
	 []backend.SourceOffsetInfo,
) {
	// Align 16-bytes boundary.
	.totalSize = (.totalSize + 15) &^ 15
	.functionOffsets[] = .totalSize

	 := .DWARFLines != nil
	if  {
		// At the beginning of the function, we add the offset of the function body so that
		// we can resolve the source location of the call site of before listener call.
		.sourceMap.executableOffsets = append(.sourceMap.executableOffsets, uintptr(.totalSize))
		.sourceMap.wasmBinaryOffsets = append(.sourceMap.wasmBinaryOffsets, .CodeSection[].BodyOffsetInCodeSection)

		for ,  := range  {
			.sourceMap.executableOffsets = append(.sourceMap.executableOffsets, uintptr(.totalSize)+uintptr(.ExecutableOffset))
			.sourceMap.wasmBinaryOffsets = append(.sourceMap.wasmBinaryOffsets, uint64(.SourceOffset))
		}
	}

	 := frontend.FunctionIndexToFuncRef()
	.refToBinaryOffset[] = .totalSize

	// At this point, relocation offsets are relative to the start of the function body,
	// so we adjust it to the start of the executable.
	.rels = slices.Grow(.rels, len())
	for ,  := range  {
		.Offset += int64(.totalSize)
		.rels = append(.rels, )
	}

	.totalSize += len()
	.bodies = append(.bodies, )
	if wazevoapi.PrintMachineCodeHexPerFunction {
		fmt.Printf("[[[machine code for %s]]]\n%s\n\n", wazevoapi.GetCurrentFunctionName(), hex.EncodeToString())
	}

	if .callTrampolineIslandSize > 0 {
		// If the total size exceeds the trampoline interval, we need to add a trampoline island.
		if .totalSize/.trampolineInterval > len(.callTrampolineIslandOffsets) {
			.callTrampolineIslandOffsets = append(.callTrampolineIslandOffsets, .totalSize)
			.totalSize += .callTrampolineIslandSize
		}
	}
}

func ( *engine) (
	 context.Context,
	 *wasm.Module,
	 wasm.Index,
	 *frontend.Compiler,
	 ssa.Builder,
	 backend.Compiler,
	 bool,
) ( []byte,  []backend.RelocationInfo,  error) {
	 := .FunctionSection[]
	 := &.TypeSection[]
	 := &.CodeSection[]

	// Initializes both frontend and backend compilers.
	.Init(, , , .LocalTypes, .Body, , .BodyOffsetInCodeSection)
	.Init()

	// Lower Wasm to SSA.
	.LowerToSSA()
	if wazevoapi.PrintSSA && wazevoapi.PrintEnabledIndex() {
		fmt.Printf("[[[SSA for %s]]]%s\n", wazevoapi.GetCurrentFunctionName(), .Format())
	}

	if wazevoapi.DeterministicCompilationVerifierEnabled {
		wazevoapi.VerifyOrSetDeterministicCompilationContextValue(, "SSA", .Format())
	}

	// Run SSA-level optimization passes.
	.RunPasses()

	if wazevoapi.PrintOptimizedSSA && wazevoapi.PrintEnabledIndex() {
		fmt.Printf("[[[Optimized SSA for %s]]]%s\n", wazevoapi.GetCurrentFunctionName(), .Format())
	}

	if wazevoapi.DeterministicCompilationVerifierEnabled {
		wazevoapi.VerifyOrSetDeterministicCompilationContextValue(, "Optimized SSA", .Format())
	}

	// Now our ssaBuilder contains the necessary information to further lower them to
	// machine code.
	, ,  := .Compile()
	if  != nil {
		return nil, nil, fmt.Errorf("ssa->machine code: %v", )
	}

	// TODO: optimize as zero copy.
	return slices.Clone(), , nil
}

func ( *engine) ( context.Context,  *wasm.Module,  []experimental.FunctionListener) (*compiledModule, error) {
	 := newMachine()
	 := backend.NewCompiler(, , ssa.NewBuilder())

	 := len(.CodeSection)
	 := &compiledModule{module: , listeners: , executables: &executables{}}
	.functionOffsets = make([]int, )
	 := 0 // Total binary size of the executable.
	 := make([][]byte, )
	var  ssa.Signature
	for  := range .CodeSection {
		 = ( + 15) &^ 15
		.functionOffsets[] = 

		 := .FunctionSection[]
		 := &.TypeSection[]

		// We can relax until the index fits together in ExitCode as we do in wazevoapi.ExitCodeCallGoModuleFunctionWithIndex.
		// However, 1 << 16 should be large enough for a real use case.
		const  = 1 << 16
		if  >=  {
			return nil, fmt.Errorf("too many host functions (maximum %d)", )
		}

		.ID = ssa.SignatureID() // This is important since we reuse the `machine` which caches the ABI based on the SignatureID.
		.Params = append(.Params[:0],
			ssa.TypeI64, // First argument must be exec context.
			ssa.TypeI64, // The second argument is the moduleContextOpaque of this host module.
		)
		for ,  := range .Params {
			.Params = append(.Params, frontend.WasmTypeToSSAType())
		}

		.Results = .Results[:0]
		for ,  := range .Results {
			.Results = append(.Results, frontend.WasmTypeToSSAType())
		}

		 := &.CodeSection[]
		if .GoFunc == nil {
			panic("BUG: GoFunc must be set for host module")
		}

		 := len() > 0 && [] != nil
		var  wazevoapi.ExitCode
		 := .GoFunc
		switch .(type) {
		case api.GoModuleFunction:
			 = wazevoapi.ExitCodeCallGoModuleFunctionWithIndex(, )
		case api.GoFunction:
			 = wazevoapi.ExitCodeCallGoFunctionWithIndex(, )
		}

		.Init()
		.CompileGoFunctionTrampoline(, &, true)
		if  := .Finalize();  != nil {
			return nil, 
		}
		 := .Buf()

		if wazevoapi.PerfMapEnabled {
			 := .FunctionDefinition(wasm.Index()).DebugName()
			wazevoapi.PerfMap.AddModuleEntry(,
				int64(),
				uint64(len()),
				fmt.Sprintf("trampoline:%s", ))
		}

		// TODO: optimize as zero copy.
		[] = slices.Clone()
		 += len()
	}

	if  == 0 {
		// Empty module.
		return , nil
	}

	// Allocate executable memory and then copy the generated machine code.
	,  := platform.MmapCodeSegment()
	if  != nil {
		panic()
	}
	.executable = 

	for ,  := range  {
		 := .functionOffsets[]
		copy([:], )
	}

	if wazevoapi.PerfMapEnabled {
		wazevoapi.PerfMap.Flush(uintptr(unsafe.Pointer(&[0])), .functionOffsets)
	}

	if  = platform.MprotectCodeSegment();  != nil {
		return nil, 
	}
	.setFinalizer(.executables, executablesFinalizer)
	return , nil
}

// Close implements wasm.Engine.
func ( *engine) () ( error) {
	.mux.Lock()
	defer .mux.Unlock()
	.sortedCompiledModules = nil
	.compiledModules = nil
	.sharedFunctions = nil
	return nil
}

// CompiledModuleCount implements wasm.Engine.
func ( *engine) () uint32 {
	.mux.RLock()
	defer .mux.RUnlock()
	return uint32(len(.compiledModules))
}

// DeleteCompiledModule implements wasm.Engine.
func ( *engine) ( *wasm.Module) {
	.mux.Lock()
	defer .mux.Unlock()
	,  := .compiledModules[.ID]
	if ! {
		return
	}
	.refCount--
	if .refCount > 0 {
		return
	}
	if len(.executable) > 0 {
		.deleteCompiledModuleFromSortedList(.compiledModule)
	}
	delete(.compiledModules, .ID)
}

func ( *engine) ( *compiledModule) {
	 := uintptr(unsafe.Pointer(&.executable[0]))

	 := sort.Search(len(.sortedCompiledModules), func( int) bool {
		return uintptr(unsafe.Pointer(&.sortedCompiledModules[].executable[0])) >= 
	})
	.sortedCompiledModules = append(.sortedCompiledModules, nil)
	copy(.sortedCompiledModules[+1:], .sortedCompiledModules[:])
	.sortedCompiledModules[] = 
}

func ( *engine) ( *compiledModule) {
	 := uintptr(unsafe.Pointer(&.executable[0]))

	 := sort.Search(len(.sortedCompiledModules), func( int) bool {
		return uintptr(unsafe.Pointer(&.sortedCompiledModules[].executable[0])) >= 
	})
	if  >= len(.sortedCompiledModules) {
		return
	}
	copy(.sortedCompiledModules[:], .sortedCompiledModules[+1:])
	.sortedCompiledModules = .sortedCompiledModules[:len(.sortedCompiledModules)-1]
}

func ( *engine) ( uintptr) *compiledModule {
	.mux.RLock()
	defer .mux.RUnlock()

	 := sort.Search(len(.sortedCompiledModules), func( int) bool {
		return uintptr(unsafe.Pointer(&.sortedCompiledModules[].executable[0])) > 
	})
	 -= 1
	if  < 0 {
		return nil
	}
	 := .sortedCompiledModules[]
	if checkAddrInBytes(, .executable) {
		// If a module is already deleted, the found module may have been wrong.
		return 
	}
	return nil
}

func checkAddrInBytes( uintptr,  []byte) bool {
	return uintptr(unsafe.Pointer(&[0])) <=  &&  <= uintptr(unsafe.Pointer(&[len()-1]))
}

// NewModuleEngine implements wasm.Engine.
func ( *engine) ( *wasm.Module,  *wasm.ModuleInstance) (wasm.ModuleEngine, error) {
	 := &moduleEngine{}

	// Note: imported functions are resolved in moduleEngine.ResolveImportedFunction.
	.importedFunctions = make([]importedFunction, .ImportFunctionCount)

	,  := .getCompiledModuleFromMemory(, false)
	if ! {
		return nil, errors.New("source module must be compiled before instantiation")
	}
	.parent = 
	.module = 
	.listeners = .listeners

	if .IsHostModule {
		.opaque = buildHostModuleOpaque(, .listeners)
		.opaquePtr = &.opaque[0]
	} else {
		if  := .offsets.TotalSize;  != 0 {
			 := newAlignedOpaque()
			.opaque = 
			.opaquePtr = &[0]
		}
	}
	return , nil
}

func ( *engine) () {
	var  [8]int
	var  []byte

	 := func( int,  []byte) {
		 = append(, ...)
		 := 15 & -len() // Align 16-bytes boundary.
		 = append(, make([]byte, )...)
		[] = len() + 
	}

	.be.Init()
	(0,
		.machine.CompileGoFunctionTrampoline(wazevoapi.ExitCodeGrowMemory, &ssa.Signature{
			Params:  []ssa.Type{ssa.TypeI64 /* exec context */, ssa.TypeI32},
			Results: []ssa.Type{ssa.TypeI32},
		}, false))

	.be.Init()
	(1,
		.machine.CompileGoFunctionTrampoline(wazevoapi.ExitCodeTableGrow, &ssa.Signature{
			Params:  []ssa.Type{ssa.TypeI64 /* exec context */, ssa.TypeI32 /* table index */, ssa.TypeI32 /* num */, ssa.TypeI64 /* ref */},
			Results: []ssa.Type{ssa.TypeI32},
		}, false))

	.be.Init()
	(2,
		.machine.CompileGoFunctionTrampoline(wazevoapi.ExitCodeCheckModuleExitCode, &ssa.Signature{
			Params:  []ssa.Type{ssa.TypeI32 /* exec context */},
			Results: []ssa.Type{ssa.TypeI32},
		}, false))

	.be.Init()
	(3,
		.machine.CompileGoFunctionTrampoline(wazevoapi.ExitCodeRefFunc, &ssa.Signature{
			Params:  []ssa.Type{ssa.TypeI64 /* exec context */, ssa.TypeI32 /* function index */},
			Results: []ssa.Type{ssa.TypeI64}, // returns the function reference.
		}, false))

	.be.Init()
	(4, .machine.CompileStackGrowCallSequence())

	.be.Init()
	(5,
		.machine.CompileGoFunctionTrampoline(wazevoapi.ExitCodeMemoryWait32, &ssa.Signature{
			// exec context, timeout, expected, addr
			Params: []ssa.Type{ssa.TypeI64, ssa.TypeI64, ssa.TypeI32, ssa.TypeI64},
			// Returns the status.
			Results: []ssa.Type{ssa.TypeI32},
		}, false))

	.be.Init()
	(6,
		.machine.CompileGoFunctionTrampoline(wazevoapi.ExitCodeMemoryWait64, &ssa.Signature{
			// exec context, timeout, expected, addr
			Params: []ssa.Type{ssa.TypeI64, ssa.TypeI64, ssa.TypeI64, ssa.TypeI64},
			// Returns the status.
			Results: []ssa.Type{ssa.TypeI32},
		}, false))

	.be.Init()
	(7,
		.machine.CompileGoFunctionTrampoline(wazevoapi.ExitCodeMemoryNotify, &ssa.Signature{
			// exec context, count, addr
			Params: []ssa.Type{ssa.TypeI64, ssa.TypeI32, ssa.TypeI64},
			// Returns the number notified.
			Results: []ssa.Type{ssa.TypeI32},
		}, false))

	 := &sharedFunctions{
		executable:          mmapExecutable(),
		listenerTrampolines: make(listenerTrampolines),
	}
	.setFinalizer(, sharedFunctionsFinalizer)

	 := 0
	.memoryGrowAddress = &.executable[]
	 += [0]
	.tableGrowAddress = &.executable[]
	 += [1]
	.checkModuleExitCodeAddress = &.executable[]
	 += [2]
	.refFuncAddress = &.executable[]
	 += [3]
	.stackGrowAddress = &.executable[]
	 += [4]
	.memoryWait32Address = &.executable[]
	 += [5]
	.memoryWait64Address = &.executable[]
	 += [6]
	.memoryNotifyAddress = &.executable[]

	if wazevoapi.PerfMapEnabled {
		wazevoapi.PerfMap.AddEntry(uintptr(unsafe.Pointer(.memoryGrowAddress)), uint64([0]), "memory_grow_trampoline")
		wazevoapi.PerfMap.AddEntry(uintptr(unsafe.Pointer(.tableGrowAddress)), uint64([1]), "table_grow_trampoline")
		wazevoapi.PerfMap.AddEntry(uintptr(unsafe.Pointer(.checkModuleExitCodeAddress)), uint64([2]), "check_module_exit_code_trampoline")
		wazevoapi.PerfMap.AddEntry(uintptr(unsafe.Pointer(.refFuncAddress)), uint64([3]), "ref_func_trampoline")
		wazevoapi.PerfMap.AddEntry(uintptr(unsafe.Pointer(.stackGrowAddress)), uint64([4]), "stack_grow_trampoline")
		wazevoapi.PerfMap.AddEntry(uintptr(unsafe.Pointer(.memoryWait32Address)), uint64([5]), "memory_wait32_trampoline")
		wazevoapi.PerfMap.AddEntry(uintptr(unsafe.Pointer(.memoryWait64Address)), uint64([6]), "memory_wait64_trampoline")
		wazevoapi.PerfMap.AddEntry(uintptr(unsafe.Pointer(.memoryNotifyAddress)), uint64([7]), "memory_notify_trampoline")
	}

	.sharedFunctions = 
}

func sharedFunctionsFinalizer( *sharedFunctions) {
	if  := platform.MunmapCodeSegment(.executable);  != nil {
		panic()
	}
	for ,  := range .listenerTrampolines {
		if  := platform.MunmapCodeSegment(.executable);  != nil {
			panic()
		}
	}

	.executable = nil
	.listenerTrampolines = nil
}

func executablesFinalizer( *executables) {
	if len(.executable) > 0 {
		if  := platform.MunmapCodeSegment(.executable);  != nil {
			panic()
		}
	}
	.executable = nil

	if len(.entryPreambles) > 0 {
		if  := platform.MunmapCodeSegment(.entryPreambles);  != nil {
			panic()
		}
	}
	.entryPreambles = nil
	.entryPreamblesPtrs = nil
}

func mmapExecutable( []byte) []byte {
	,  := platform.MmapCodeSegment(len())
	if  != nil {
		panic()
	}

	copy(, )

	if  = platform.MprotectCodeSegment();  != nil {
		panic()
	}
	return 
}

func ( *compiledModule) ( uintptr) wasm.Index {
	 -= uintptr(unsafe.Pointer(&.executable[0]))
	 := .functionOffsets
	 := sort.Search(len(), func( int) bool {
		return [] > int()
	})
	--
	if  < 0 {
		panic("BUG")
	}
	return wasm.Index()
}

func ( *engine) ( *wasm.FunctionType) (,  *byte) {
	.mux.Lock()
	defer .mux.Unlock()

	,  := .sharedFunctions.listenerTrampolines[]
	if ! {
		var  []byte
		,  := frontend.SignatureForListener()

		.be.Init()
		 := .machine.CompileGoFunctionTrampoline(wazevoapi.ExitCodeCallListenerBefore, , false)
		 = append(, ...)

		 := 15 & -len() // Align 16-bytes boundary.
		 = append(, make([]byte, )...)
		 := len()

		.be.Init()
		 = .machine.CompileGoFunctionTrampoline(wazevoapi.ExitCodeCallListenerAfter, , false)
		 = append(, ...)

		.executable = mmapExecutable()
		.before = &.executable[0]
		.after = &.executable[]

		.sharedFunctions.listenerTrampolines[] = 
	}
	return .before, .after
}

func ( *compiledModule) ( uintptr) uint64 {
	 := .sourceMap.executableOffsets
	if len() == 0 {
		return 0
	}

	 := sort.Search(len(), func( int) bool {
		return [] >= 
	})

	--
	if  < 0 {
		return 0
	}
	return .sourceMap.wasmBinaryOffsets[]
}