// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#ifndef __GCENV_BASE_INCLUDED__
#define __GCENV_BASE_INCLUDED__
//
// Sets up basic environment for CLR GC
//

#include <minipal/utils.h>

#ifdef _MSC_VER
#include <intrin.h>
#endif // _MSC_VER

#if !defined(_MSC_VER)
#ifdef __sun
#include <alloca.h>
#endif
#define _alloca alloca
#endif //_MSC_VER

#ifndef _MSC_VER
#define __stdcall
#ifdef __GNUC__
#define __forceinline __attribute__((always_inline)) inline
#else // __GNUC__
#define __forceinline inline
#endif // __GNUC__
// [LOCALGC TODO] is there a better place for this?
#define NOINLINE __attribute__((noinline))
#else // !_MSC_VER
#define NOINLINE __declspec(noinline)
#endif // _MSC_VER

#ifdef _MSC_VER
#define __UNREACHABLE() __assume(0)
#else
#define __UNREACHABLE() __builtin_unreachable()
#endif

#ifndef SIZE_T_MAX
#define SIZE_T_MAX ((size_t)-1)
#endif
#ifndef SSIZE_T_MAX
#define SSIZE_T_MAX ((ptrdiff_t)(SIZE_T_MAX / 2))
#endif

#ifndef _INC_WINDOWS
// -----------------------------------------------------------------------------------------------------------
//
// Aliases for Win32 types
//

typedef int BOOL;
typedef uint32_t DWORD;
typedef uint64_t DWORD64;
#ifdef _MSC_VER
typedef unsigned long ULONG;
#else
typedef uint32_t ULONG;
#endif
// -----------------------------------------------------------------------------------------------------------
// HRESULT subset.

#ifdef TARGET_UNIX
typedef int32_t HRESULT;
#else
// this must exactly match the typedef used by windows.h
typedef long HRESULT;
#endif

#define SUCCEEDED(_hr)          ((HRESULT)(_hr) >= 0)
#define FAILED(_hr)             ((HRESULT)(_hr) < 0)

inline HRESULT HRESULT_FROM_WIN32(unsigned long x)
{
    return (HRESULT)(x) <= 0 ? (HRESULT)(x) : (HRESULT) (((x) & 0x0000FFFF) | (7 << 16) | 0x80000000);
}

#define S_OK                                   0x0
#define E_FAIL                                 0x80004005
#define E_OUTOFMEMORY                          0x8007000E
#define COR_E_EXECUTIONENGINE                  0x80131506
#define CLR_E_GC_BAD_AFFINITY_CONFIG           0x8013200A
#define CLR_E_GC_BAD_AFFINITY_CONFIG_FORMAT    0x8013200B
#define CLR_E_GC_BAD_HARD_LIMIT                0x8013200D
#define CLR_E_GC_LARGE_PAGE_MISSING_HARD_LIMIT 0x8013200E
#define CLR_E_GC_BAD_REGION_SIZE               0x8013200F

#define NOERROR                 0x0
#define ERROR_TIMEOUT           1460

#define TRUE true
#define FALSE false

#define CALLBACK __stdcall
#define FORCEINLINE __forceinline

#define INFINITE 0xFFFFFFFF

#define ZeroMemory(Destination,Length) memset((Destination),0,(Length))

#define C_ASSERT(cond) static_assert( cond, #cond )

#define UNREFERENCED_PARAMETER(P)          (void)(P)

#ifdef TARGET_UNIX
#define _vsnprintf_s(string, sizeInBytes, count, format, args) vsnprintf(string, sizeInBytes, format, args)
#define sprintf_s snprintf
#define _snprintf_s(string, sizeInBytes, count, format, ...) \
  snprintf(string, sizeInBytes, format, ## __VA_ARGS__)
#endif

#ifdef UNICODE
#define _tfopen _wfopen
#else
#define _tfopen fopen
#endif

#define WINAPI __stdcall

typedef DWORD (WINAPI *PTHREAD_START_ROUTINE)(void* lpThreadParameter);

#define WAIT_OBJECT_0           0
#define WAIT_TIMEOUT            258
#define WAIT_FAILED             0xFFFFFFFF

#if defined(_MSC_VER)
 #if defined(HOST_ARM)

  __forceinline void YieldProcessor() { }
  extern "C" void __emit(const unsigned __int32 opcode);
  #pragma intrinsic(__emit)
  #define MemoryBarrier() { __emit(0xF3BF); __emit(0x8F5F); }

 #elif defined(HOST_ARM64)

  extern "C" void __yield(void);
  #pragma intrinsic(__yield)
  __forceinline void YieldProcessor() { __yield();}

  extern "C" void __dmb(const unsigned __int32 _Type);
  #pragma intrinsic(__dmb)
  #define MemoryBarrier() { __dmb(_ARM64_BARRIER_SY); }

 #elif defined(HOST_AMD64)

  extern "C" void
  _mm_pause (
      void
      );

  extern "C" void
  _mm_mfence (
      void
      );

  #pragma intrinsic(_mm_pause)
  #pragma intrinsic(_mm_mfence)

  #define YieldProcessor _mm_pause
  #define MemoryBarrier _mm_mfence

 #elif defined(HOST_X86)

  #define YieldProcessor() __asm { rep nop }
  #define MemoryBarrier() MemoryBarrierImpl()
  __forceinline void MemoryBarrierImpl()
  {
      int32_t Barrier;
      __asm {
          xchg Barrier, eax
      }
  }

 #else // !HOST_ARM && !HOST_AMD64 && !HOST_X86
  #error Unsupported architecture
 #endif
#else // _MSC_VER

#if defined(__i386__) || defined(__x86_64__)

#if __has_builtin(__builtin_ia32_pause)
 // clang added this intrinsic in 3.8
 // gcc added this intrinsic by 4.7.1
 #define YieldProcessor __builtin_ia32_pause
#endif // __has_builtin(__builtin_ia32_pause)

#if __has_builtin(__builtin_ia32_mfence)
 // clang has had this intrinsic since at least 3.0
 // gcc has had this intrinsic since forever
 #define MemoryBarrier __builtin_ia32_mfence
#endif // __has_builtin(__builtin_ia32_mfence)

// If we don't have intrinsics, we can do some inline asm instead.
#ifndef YieldProcessor
 #define YieldProcessor() asm volatile ("pause")
#endif // YieldProcessor

#ifndef MemoryBarrier
 #define MemoryBarrier() asm volatile ("mfence")
#endif // MemoryBarrier

#endif // defined(__i386__) || defined(__x86_64__)

#if defined(__arm__) || defined(__aarch64__)
 #define YieldProcessor() asm volatile ("yield")
 #define MemoryBarrier __sync_synchronize
#endif // __arm__ || __aarch64__

#ifdef __loongarch64
 #define YieldProcessor() __asm__ volatile( "dbar 0; \n")
 #define MemoryBarrier __sync_synchronize
#endif // __loongarch64

#ifdef __riscv
 #define YieldProcessor() asm volatile( ".word 0x0100000f");
 #define MemoryBarrier __sync_synchronize
#endif // __riscv

#endif // _MSC_VER

#ifdef _MSC_VER
#pragma intrinsic(_BitScanForward)
#pragma intrinsic(_BitScanReverse)
#if _WIN64
 #pragma intrinsic(_BitScanForward64)
 #pragma intrinsic(_BitScanReverse64)
#endif
#endif // _MSC_VER

// Cross-platform wrapper for the _BitScanForward compiler intrinsic.
// A value is unconditionally stored through the bitIndex argument,
// but callers should only rely on it when the function returns TRUE;
// otherwise, the stored value is undefined and varies by implementation
// and hardware platform.
inline uint8_t BitScanForward(uint32_t *bitIndex, uint32_t mask)
{
#ifdef _MSC_VER
    return _BitScanForward((unsigned long*)bitIndex, mask);
#else // _MSC_VER
    int iIndex = __builtin_ffs(mask);
    *bitIndex = static_cast<uint32_t>(iIndex - 1);
    // Both GCC and Clang generate better, smaller code if we check whether the
    // mask was/is zero rather than the equivalent check that iIndex is zero.
    return mask != 0 ? TRUE : FALSE;
#endif // _MSC_VER
}

// Cross-platform wrapper for the _BitScanForward64 compiler intrinsic.
// A value is unconditionally stored through the bitIndex argument,
// but callers should only rely on it when the function returns TRUE;
// otherwise, the stored value is undefined and varies by implementation
// and hardware platform.
inline uint8_t BitScanForward64(uint32_t *bitIndex, uint64_t mask)
{
#ifdef _MSC_VER
 #if _WIN64
    return _BitScanForward64((unsigned long*)bitIndex, mask);
 #else
    // MSVC targeting a 32-bit target does not support this intrinsic.
    // We can fake it using two successive invocations of _BitScanForward.
    uint32_t hi = (mask >> 32) & 0xFFFFFFFF;
    uint32_t lo = mask & 0xFFFFFFFF;
    uint32_t fakeBitIndex = 0;

    uint8_t result = BitScanForward(bitIndex, lo);
    if (result == 0)
    {
        result = BitScanForward(&fakeBitIndex, hi);
        if (result != 0)
        {
            *bitIndex = fakeBitIndex + 32;
        }
    }

    return result;
 #endif // _WIN64
#else
    int iIndex = __builtin_ffsll(mask);
    *bitIndex = static_cast<uint32_t>(iIndex - 1);
    // Both GCC and Clang generate better, smaller code if we check whether the
    // mask was/is zero rather than the equivalent check that iIndex is zero.
    return mask != 0 ? TRUE : FALSE;
#endif // _MSC_VER
}

// Cross-platform wrapper for the _BitScanReverse compiler intrinsic.
inline uint8_t BitScanReverse(uint32_t *bitIndex, uint32_t mask)
{
#ifdef _MSC_VER
    return _BitScanReverse((unsigned long*)bitIndex, mask);
#else // _MSC_VER
    // The result of __builtin_clz is undefined when mask is zero,
    // but it's still OK to call the intrinsic in that case (just don't use the output).
    // Unconditionally calling the intrinsic in this way allows the compiler to
    // emit branchless code for this function when possible (depending on how the
    // intrinsic is implemented for the target platform).
    int lzcount = __builtin_clz(mask);
    *bitIndex = static_cast<uint32_t>(31 - lzcount);
    return mask != 0 ? TRUE : FALSE;
#endif // _MSC_VER
}

// Cross-platform wrapper for the _BitScanReverse64 compiler intrinsic.
inline uint8_t BitScanReverse64(uint32_t *bitIndex, uint64_t mask)
{
#ifdef _MSC_VER
 #if _WIN64
    return _BitScanReverse64((unsigned long*)bitIndex, mask);
 #else
    // MSVC targeting a 32-bit target does not support this intrinsic.
    // We can fake it checking whether the upper 32 bits are zeros (or not)
    // then calling _BitScanReverse() on either the upper or lower 32 bits.
    uint32_t upper = static_cast<uint32_t>(mask >> 32);

    if (upper != 0)
    {
        uint8_t result = _BitScanReverse((unsigned long*)bitIndex, upper);
        *bitIndex += 32;
        return result;
    }

    return _BitScanReverse((unsigned long*)bitIndex, static_cast<uint32_t>(mask));
 #endif // _WIN64
#else
    // The result of __builtin_clzll is undefined when mask is zero,
    // but it's still OK to call the intrinsic in that case (just don't use the output).
    // Unconditionally calling the intrinsic in this way allows the compiler to
    // emit branchless code for this function when possible (depending on how the
    // intrinsic is implemented for the target platform).
    int lzcount = __builtin_clzll(mask);
    *bitIndex = static_cast<uint32_t>(63 - lzcount);
    return mask != 0 ? TRUE : FALSE;
#endif // _MSC_VER
}

// Aligns a size_t to the specified alignment. Alignment must be a power
// of two.
inline size_t ALIGN_UP(size_t val, size_t alignment)
{
    // alignment factor must be power of two
    assert((alignment & (alignment - 1)) == 0);
    size_t result = (val + (alignment - 1)) & ~(alignment - 1);
    assert(result >= val);
    return result;
}

// Aligns a pointer to the specified alignment. Alignment must be a power
// of two.
inline uint8_t* ALIGN_UP(uint8_t* ptr, size_t alignment)
{
    size_t as_size_t = reinterpret_cast<size_t>(ptr);
    return reinterpret_cast<uint8_t*>(ALIGN_UP(as_size_t, alignment));
}

// Aligns a size_t to the specified alignment by rounding down. Alignment must
// be a power of two.
inline size_t ALIGN_DOWN(size_t val, size_t alignment)
{
    // alignment factor must be power of two.
    assert((alignment & (alignment - 1)) == 0);
    size_t result = val & ~(alignment - 1);
    return result;
}

// Aligns a pointer to the specified alignment by rounding down. Alignment
// must be a power of two.
inline uint8_t* ALIGN_DOWN(uint8_t* ptr, size_t alignment)
{
    size_t as_size_t = reinterpret_cast<size_t>(ptr);
    return reinterpret_cast<uint8_t*>(ALIGN_DOWN(as_size_t, alignment));
}

// Aligns a void pointer to the specified alignment by rounding down. Alignment
// must be a power of two.
inline void* ALIGN_DOWN(void* ptr, size_t alignment)
{
    size_t as_size_t = reinterpret_cast<size_t>(ptr);
    return reinterpret_cast<void*>(ALIGN_DOWN(as_size_t, alignment));
}

typedef struct _PROCESSOR_NUMBER {
    uint16_t Group;
    uint8_t Number;
    uint8_t Reserved;
} PROCESSOR_NUMBER, *PPROCESSOR_NUMBER;
#endif // _INC_WINDOWS

// -----------------------------------------------------------------------------------------------------------
//
// The subset of the contract code required by the GC/HandleTable sources. If NativeAOT moves to support
// contracts these local definitions will disappear and be replaced by real implementations.
//

#define LEAF_CONTRACT
#define LIMITED_METHOD_CONTRACT
#define LIMITED_METHOD_DAC_CONTRACT
#define WRAPPER_CONTRACT
#define WRAPPER_NO_CONTRACT
#define STATIC_CONTRACT_LEAF
#define STATIC_CONTRACT_DEBUG_ONLY
#define STATIC_CONTRACT_NOTHROW
#define STATIC_CONTRACT_CAN_TAKE_LOCK
#define STATIC_CONTRACT_GC_NOTRIGGER
#define STATIC_CONTRACT_MODE_COOPERATIVE
#define CONTRACTL
#define CONTRACT(_expr)
#define CONTRACT_VOID
#define THROWS
#define NOTHROW
#define INSTANCE_CHECK
#define MODE_COOPERATIVE
#define MODE_ANY
#define GC_TRIGGERS
#define GC_NOTRIGGER
#define CAN_TAKE_LOCK
#define SUPPORTS_DAC
#define FORBID_FAULT
#define CONTRACTL_END
#define CONTRACT_END
#define TRIGGERSGC()
#define WRAPPER(_contract)
#define DISABLED(_contract)
#define INJECT_FAULT(_expr)
#define INJECTFAULT_GCHEAP 0x2
#define FAULT_NOT_FATAL()
#define BEGIN_DEBUG_ONLY_CODE
#define END_DEBUG_ONLY_CODE
#define BEGIN_GETTHREAD_ALLOWED
#define END_GETTHREAD_ALLOWED
#define LEAF_DAC_CONTRACT
#define PRECONDITION(_expr)
#define POSTCONDITION(_expr)
#define RETURN return
#define CONDITIONAL_CONTRACT_VIOLATION(_violation, _expr)

// -----------------------------------------------------------------------------------------------------------
//
// Data access macros
//
typedef uintptr_t TADDR;
#define PTR_TO_TADDR(ptr) ((TADDR)(ptr))

#define DPTR(type) type*
#define SPTR(type) type*
typedef DPTR(size_t)    PTR_size_t;
typedef DPTR(uint8_t)   PTR_uint8_t;

// -----------------------------------------------------------------------------------------------------------

#define DATA_ALIGNMENT sizeof(uintptr_t)
#define RAW_KEYWORD(x) x

#ifdef _MSC_VER
#define DECLSPEC_ALIGN(x)   __declspec(align(x))
#else
#define DECLSPEC_ALIGN(x)   __attribute__((aligned(x)))
#endif

#ifndef _ASSERTE
#define _ASSERTE(_expr) ASSERT(_expr)
#endif
#define CONSISTENCY_CHECK(_expr) ASSERT(_expr)
#define PREFIX_ASSUME(cond) ASSERT(cond)
#define EEPOLICY_HANDLE_FATAL_ERROR(error) ASSERT(!"EEPOLICY_HANDLE_FATAL_ERROR")
#define UI64(_literal) _literal##ULL

class ObjHeader;
class MethodTable;
class Object;
class ArrayBase;

typedef DPTR(Object) PTR_Object;
typedef DPTR(PTR_Object) PTR_PTR_Object;

typedef PTR_Object OBJECTREF;
typedef PTR_PTR_Object PTR_OBJECTREF;
typedef PTR_Object _UNCHECKED_OBJECTREF;
typedef PTR_PTR_Object PTR_UNCHECKED_OBJECTREF;

// With no object reference wrapping the following macros are very simple.
#define ObjectToOBJECTREF(_obj) (OBJECTREF)(_obj)
#define OBJECTREFToObject(_obj) (Object*)(_obj)

#define VALIDATEOBJECTREF(_objref) (void)_objref;

class Thread;

inline bool dbgOnly_IsSpecialEEThread()
{
    return false;
}

//
// Performance logging
//

//#include "etmdummy.h"
//#define ETW_EVENT_ENABLED(e,f) false

namespace ETW
{
    typedef  enum _GC_ROOT_KIND {
        GC_ROOT_STACK = 0,
        GC_ROOT_FQ = 1,
        GC_ROOT_HANDLES = 2,
        GC_ROOT_OLDER = 3,
        GC_ROOT_SIZEDREF = 4,
        GC_ROOT_OVERFLOW = 5,
        GC_ROOT_DH_HANDLES = 6,
        GC_ROOT_NEW_FQ = 7,
        GC_ROOT_STEAL = 8,
        GC_ROOT_BGC = 9
    } GC_ROOT_KIND;
};

inline bool FitsInU1(uint64_t val)
{
    return val == (uint64_t)(uint8_t)val;
}

#endif // __GCENV_BASE_INCLUDED__
