package wazevoapi

import (
	
	
	
	
	
	
)

// These consts are used various places in the wazevo implementations.
// Instead of defining them in each file, we define them here so that we can quickly iterate on
// debugging without spending "where do we have debug logging?" time.

// ----- Debug logging -----
// These consts must be disabled by default. Enable them only when debugging.

const (
	FrontEndLoggingEnabled = false
	SSALoggingEnabled      = false
	RegAllocLoggingEnabled = false
)

// ----- Output prints -----
// These consts must be disabled by default. Enable them only when debugging.

const (
	PrintSSA                                 = false
	PrintOptimizedSSA                        = false
	PrintSSAToBackendIRLowering              = false
	PrintRegisterAllocated                   = false
	PrintFinalizedMachineCode                = false
	PrintMachineCodeHexPerFunction           = printMachineCodeHexPerFunctionUnmodified || PrintMachineCodeHexPerFunctionDisassemblable //nolint
	printMachineCodeHexPerFunctionUnmodified = false
	// PrintMachineCodeHexPerFunctionDisassemblable prints the machine code while modifying the actual result
	// to make it disassemblable. This is useful when debugging the final machine code. See the places where this is used for detail.
	// When this is enabled, functions must not be called.
	PrintMachineCodeHexPerFunctionDisassemblable = false
)

// printTarget is the function index to print the machine code. This is used for debugging to print the machine code
// of a specific function.
const printTarget = -1

// PrintEnabledIndex returns true if the current function index is the print target.
func ( context.Context) bool {
	if printTarget == -1 {
		return true
	}
	return GetCurrentFunctionIndex() == printTarget
}

// ----- Validations -----
const (
	// SSAValidationEnabled enables the SSA validation. This is disabled by default since the operation is expensive.
	SSAValidationEnabled = false
)

// ----- Stack Guard Check -----
const (
	// StackGuardCheckEnabled enables the stack guard check to ensure that our stack bounds check works correctly.
	StackGuardCheckEnabled       = false
	StackGuardCheckGuardPageSize = 8096
)

// CheckStackGuardPage checks the given stack guard page is not corrupted.
func ( []byte) {
	for  := 0;  < StackGuardCheckGuardPageSize; ++ {
		if [] != 0 {
			panic(
				fmt.Sprintf("BUG: stack guard page is corrupted:\n\tguard_page=%s\n\tstack=%s",
					hex.EncodeToString([:StackGuardCheckGuardPageSize]),
					hex.EncodeToString([StackGuardCheckGuardPageSize:]),
				))
		}
	}
}

// ----- Deterministic compilation verifier -----

const (
	// DeterministicCompilationVerifierEnabled enables the deterministic compilation verifier. This is disabled by default
	// since the operation is expensive. But when in doubt, enable this to make sure the compilation is deterministic.
	DeterministicCompilationVerifierEnabled = false
	DeterministicCompilationVerifyingIter   = 5
)

type (
	verifierState struct {
		initialCompilationDone bool
		maybeRandomizedIndexes []int
		r                      *rand.Rand
		values                 map[string]string
	}
	verifierStateContextKey struct{}
	currentFunctionNameKey  struct{}
	currentFunctionIndexKey struct{}
)

// NewDeterministicCompilationVerifierContext creates a new context with the deterministic compilation verifier used per wasm.Module.
func ( context.Context,  int) context.Context {
	 := make([]int, )
	for  := range  {
		[] = 
	}
	 := rand.New(rand.NewSource(time.Now().UnixNano()))
	return context.WithValue(, verifierStateContextKey{}, &verifierState{
		r: , maybeRandomizedIndexes: , values: map[string]string{},
	})
}

// DeterministicCompilationVerifierRandomizeIndexes randomizes the indexes for the deterministic compilation verifier.
// To get the randomized index, use DeterministicCompilationVerifierGetRandomizedLocalFunctionIndex.
func ( context.Context) {
	 := .Value(verifierStateContextKey{}).(*verifierState)
	if !.initialCompilationDone {
		// If this is the first attempt, we use the index as-is order.
		.initialCompilationDone = true
		return
	}
	 := .r
	.Shuffle(len(.maybeRandomizedIndexes), func(,  int) {
		.maybeRandomizedIndexes[], .maybeRandomizedIndexes[] = .maybeRandomizedIndexes[], .maybeRandomizedIndexes[]
	})
}

// DeterministicCompilationVerifierGetRandomizedLocalFunctionIndex returns the randomized index for the given `index`
// which is assigned by DeterministicCompilationVerifierRandomizeIndexes.
func ( context.Context,  int) int {
	 := .Value(verifierStateContextKey{}).(*verifierState)
	 := .maybeRandomizedIndexes[]
	return 
}

// VerifyOrSetDeterministicCompilationContextValue verifies that the `newValue` is the same as the previous value for the given `scope`
// and the current function name. If the previous value doesn't exist, it sets the value to the given `newValue`.
//
// If the verification fails, this prints the diff and exits the process.
func ( context.Context,  string,  string) {
	 := .Value(currentFunctionNameKey{}).(string)
	 :=  + ": " + 
	 := .Value(verifierStateContextKey{}).(*verifierState)
	,  := .values[]
	if ! {
		.values[] = 
		return
	}
	if  !=  {
		fmt.Printf(
			`BUG: Deterministic compilation failed for function%s at scope="%s".

This is mostly due to (but might not be limited to):
	* Resetting ssa.Builder, backend.Compiler or frontend.Compiler, etc doens't work as expected, and the compilation has been affected by the previous iterations.
	* Using a map with non-deterministic iteration order.

---------- [old] ----------
%s

---------- [new] ----------
%s
`,
			, , , ,
		)
		os.Exit(1)
	}
}

// nolint
const NeedFunctionNameInContext = PrintSSA ||
	PrintOptimizedSSA ||
	PrintSSAToBackendIRLowering ||
	PrintRegisterAllocated ||
	PrintFinalizedMachineCode ||
	PrintMachineCodeHexPerFunction ||
	DeterministicCompilationVerifierEnabled ||
	PerfMapEnabled

// SetCurrentFunctionName sets the current function name to the given `functionName`.
func ( context.Context,  int,  string) context.Context {
	 = context.WithValue(, currentFunctionNameKey{}, )
	 = context.WithValue(, currentFunctionIndexKey{}, )
	return 
}

// GetCurrentFunctionName returns the current function name.
func ( context.Context) string {
	,  := .Value(currentFunctionNameKey{}).(string)
	return 
}

// GetCurrentFunctionIndex returns the current function index.
func ( context.Context) int {
	,  := .Value(currentFunctionIndexKey{}).(int)
	return 
}