///|
/// Version of the Wasmoon internal JIT calling and runtime contract.
pub const WASMOON_JIT_ABI_VERSION : Int = 3

///|
/// Revision of the current semantic-MachV target code generator.
///
/// Advance this value whenever compiler changes can alter emitted code while
/// preserving the artifact format and JIT ABI. Persistent caches use it as part
/// of their compatibility identity.
pub const WASMOON_CODEGEN_REVISION : String = "machv-vcode-7"

///|
extern "c" fn host_operating_system_abi_tag() -> Int = "wasmoon_jit_host_operating_system_abi"

///|
fn artifact_architecture(target : NativeTarget) -> @code_object.Architecture {
  match target {
    X64 => X64
    AArch64 => AArch64
  }
}

///|
pub fn host_native_target() -> NativeTarget raise JitPipelineError {
  match c_jit_host_target_arch() {
    1 => X64
    2 => AArch64
    value => raise UnsupportedHostArchitecture(tag=value)
  }
}

///|
pub fn artifact_module_identity(
  name : String,
  source_module : Bytes,
  semantic_features : Bytes,
) -> @artifact.ModuleIdentity {
  {
    name,
    source_digest: {
      bytes: Bytes::from_iter(@crypto.sha256(source_module).iter()),
    },
    semantic_features_digest: {
      bytes: Bytes::from_iter(@crypto.sha256(semantic_features).iter()),
    },
  }
}

///|
/// Build the exact compatibility manifest for a selected target.
///
/// `required_cpu_features` contains only optional features beyond the baseline
/// architecture contract. AArch64 Advanced SIMD and x64 SSE2 are baseline
/// requirements of the corresponding Wasmoon targets and are therefore not
/// repeated here.
pub fn build_artifact_manifest(
  target : NativeTarget,
  operating_system_abi : @artifact.OperatingSystemAbi,
  module_identity~ : @artifact.ModuleIdentity,
  policy~ : @artifact.CompilationPolicy,
  required_cpu_features? : Array[@artifact.CpuFeature] = [],
) -> @artifact.CompatibilityManifest {
  {
    format_version: @artifact.FORMAT_VERSION,
    target: {
      architecture: artifact_architecture(target),
      operating_system_abi,
      endianness: Little,
      pointer_width: Bits64,
    },
    required_cpu_features: required_cpu_features.copy(),
    jit_abi_version: WASMOON_JIT_ABI_VERSION,
    codegen_revision: WASMOON_CODEGEN_REVISION,
    module_identity,
    policy,
  }
}

///|
pub fn host_operating_system_abi() -> @artifact.OperatingSystemAbi raise JitPipelineError {
  match host_operating_system_abi_tag() {
    1 => MacOS
    2 => LinuxGnu
    3 => LinuxMusl
    4 => WindowsMsvc
    value => raise UnsupportedHostOsAbi(tag=value)
  }
}

///|
/// Build a manifest for the current process without guessing an unsupported
/// architecture or operating-system ABI.
pub fn build_host_artifact_manifest(
  module_identity~ : @artifact.ModuleIdentity,
  policy~ : @artifact.CompilationPolicy,
  required_cpu_features? : Array[@artifact.CpuFeature] = [],
) -> @artifact.CompatibilityManifest raise JitPipelineError {
  build_artifact_manifest(
    host_native_target(),
    host_operating_system_abi(),
    module_identity~,
    policy~,
    required_cpu_features~,
  )
}

///|
pub fn artifact_compatibility(
  manifest : @artifact.CompatibilityManifest,
  available_cpu_features~ : Array[@artifact.CpuFeature],
  runtime_symbols~ : Array[@semantic_machv.ExternalSymbol],
  data_symbols~ : Array[@semantic_machv.DataSymbol],
) -> ArtifactCompatibility {
  {
    target: manifest.target,
    available_cpu_features: available_cpu_features.copy(),
    jit_abi_version: manifest.jit_abi_version,
    codegen_revision: manifest.codegen_revision,
    module_identity: manifest.module_identity,
    policy: manifest.policy,
    runtime_symbols: runtime_symbols.copy(),
    data_symbols: data_symbols.copy(),
  }
}

///|
fn wasm_value_type(ty : @types.ValueType) -> @semantic_machv.ValueType {
  match ty {
    I32 => I32
    I64 => I64
    F32 => F32
    F64 => F64
    V128 => V128
    FuncRef
    | ExternRef
    | RefFunc
    | RefExtern
    | RefFuncTyped(_)
    | RefNullFuncTyped(_)
    | AnyRef
    | ExnRef
    | StructRef
    | ArrayRef
    | RefStruct(_)
    | RefNullStruct(_)
    | RefArray(_)
    | RefNullArray(_)
    | RefAny
    | RefEq
    | RefNullEq
    | RefI31
    | RefNullI31
    | RefStructAbs
    | RefArrayAbs
    | RefNone
    | NullRef
    | NullFuncRef
    | NullExnRef
    | NullExternRef => GcRef64
  }
}

///|
pub fn wasm_function_signature(
  function_type : @types.FuncType,
) -> @semantic_machv.Signature {
  @semantic_machv.Signature::new(
    function_type.params.map(wasm_value_type),
    function_type.results.map(wasm_value_type),
  )
}

///|
fn wasm_function_symbol(function_index : Int) -> String {
  "wasm.func.\{function_index}"
}

///|
pub fn wasm_import_identity(
  function_index : Int,
  module_name : String,
  function_name : String,
  function_type : @types.FuncType,
) -> @artifact.ImportIdentity {
  {
    function_index,
    module_name,
    function_name,
    symbol: @semantic_machv.ExternalSymbol::new(
      wasm_function_symbol(function_index),
    ),
    signature: wasm_function_signature(function_type),
  }
}

///|
fn artifact_function_from_code_object(
  object : @code_object.UnlinkedCodeObject,
  frame_size~ : Int,
  function_index~ : Int,
  signature~ : @semantic_machv.Signature,
) -> @artifact.FunctionCode {
  {
    identity: {
      function_index,
      symbol: @semantic_machv.CodeSymbol::new(
        wasm_function_symbol(function_index),
      ),
      signature,
    },
    entry_offset: 0,
    frame_size,
    code: object.code(),
    relocations: object.relocations(),
    sources: object.sources(),
    traps: object.traps(),
    safepoints: object.safepoints(),
    unwind: object.unwind(),
  }
}

///|
/// Compile one verified Wasm MilkIR body directly into the final unlinked
/// artifact representation. Symbolic relocations are retained unchanged.
pub fn compile_wasm_body_artifact_function(
  function : @milkir.Function,
  validation_context : @wasm_milkir.WasmValidationContext,
  target : NativeTarget,
  function_index~ : Int,
  signature~ : @semantic_machv.Signature,
  use_subtype_indirect_check? : Bool = true,
  canonical_type_indices? : Array[Int] = [],
) -> @artifact.FunctionCode raise JitPipelineError {
  if function_index < 0 {
    raise InvalidFunctionIndex(index=function_index)
  }
  match target {
    AArch64 => {
      let compiled = compile_wasm_body_aarch64_target(
        function,
        validation_context,
        use_subtype_indirect_check,
        canonical_type_indices,
        record_metrics=@perf.enabled(),
      )
      artifact_function_from_code_object(
        compiled.object,
        frame_size=compiled.frame_size,
        function_index~,
        signature~,
      )
    }
    X64 => {
      let compiled = compile_wasm_body_x64_target(
        function,
        validation_context,
        use_subtype_indirect_check,
        canonical_type_indices,
        record_metrics=@perf.enabled(),
      )
      artifact_function_from_code_object(
        compiled.object,
        frame_size=compiled.frame_size,
        function_index~,
        signature~,
      )
    }
  }
}