text: // Licensed to the .NET Foundation under one or more agreements.
  // The .NET Foundation licenses this file to you under the MIT license.
  // See the LICENSE file in the project root for more information.
  #include "common.h"
  
  #include "CommonTypes.h"
  #include "CommonMacros.h"
  #include "daccess.h"
  #include "PalRedhawkCommon.h"
  #include "CommonMacros.inl"
  #include "volatile.h"
  #include "PalRedhawk.h"
  #include "rhassert.h"
  
  #include "slist.h"
  #include "gcrhinterface.h"
  #include "shash.h"
  #include "RWLock.h"
  #include "varint.h"
  #include "holder.h"
  #include "rhbinder.h"
  #include "Crst.h"
  #include "RuntimeInstance.h"
  #include "event.h"
  #include "regdisplay.h"
  #include "StackFrameIterator.h"
  #include "thread.h"
  #include "threadstore.h"
  #include "threadstore.inl"
  
  #include "eetype.h"
  #include "TypeManager.h"
  #include "eetype.inl"
  #include "ObjectLayout.h"
  
  #include "GCMemoryHelpers.h"
  #include "GCMemoryHelpers.inl"
  
  #if defined(USE_PORTABLE_HELPERS)
  
  EXTERN_C REDHAWK_API void* REDHAWK_CALLCONV RhpGcAlloc(EEType *pEEType, UInt32 uFlags, UIntNative cbSize, void * pTransitionFrame);
  EXTERN_C REDHAWK_API void* REDHAWK_CALLCONV RhpPublishObject(void* pObject, UIntNative cbSize);
  
  struct gc_alloc_context
  {
      UInt8*         alloc_ptr;
      UInt8*         alloc_limit;
      __int64        alloc_bytes; //Number of bytes allocated on SOH by this context
      __int64        alloc_bytes_loh; //Number of bytes allocated on LOH by this context
      void*          gc_reserved_1;
      void*          gc_reserved_2;
      int            alloc_count;
  };
  
  //
  // Allocations
  //
  COOP_PINVOKE_HELPER(Object *, RhpNewFast, (EEType* pEEType))
  {
      ASSERT(!pEEType->RequiresAlign8());
      ASSERT(!pEEType->HasFinalizer());
  
      Thread * pCurThread = ThreadStore::GetCurrentThread();
      gc_alloc_context * acontext = pCurThread->GetAllocContext();
      Object * pObject;
  
      size_t size = pEEType->get_BaseSize();
  
      UInt8* result = acontext->alloc_ptr;
      UInt8* advance = result + size;
      if (advance <= acontext->alloc_limit)
      {
          acontext->alloc_ptr = advance;
          pObject = (Object *)result;
          pObject->set_EEType(pEEType);
          return pObject;
      }
  
      pObject = (Object *)RhpGcAlloc(pEEType, 0, size, NULL);
      if (pObject == nullptr)
      {
          ASSERT_UNCONDITIONALLY("NYI");  // TODO: Throw OOM
      }
      pObject->set_EEType(pEEType);
  
      if (size >= RH_LARGE_OBJECT_SIZE)
          RhpPublishObject(pObject, size);
  
      return pObject;
  }
  
  #define GC_ALLOC_FINALIZE 0x1 // TODO: Defined in gc.h
  
  COOP_PINVOKE_HELPER(Object *, RhpNewFinalizable, (EEType* pEEType))
  {
      ASSERT(!pEEType->RequiresAlign8());
      ASSERT(pEEType->HasFinalizer());
  
      size_t size = pEEType->get_BaseSize();
  
      Object * pObject = (Object *)RhpGcAlloc(pEEType, GC_ALLOC_FINALIZE, size, NULL);
      if (pObject == nullptr)
      {
          ASSERT_UNCONDITIONALLY("NYI");  // TODO: Throw OOM
      }
      pObject->set_EEType(pEEType);
  
      if (size >= RH_LARGE_OBJECT_SIZE)
          RhpPublishObject(pObject, size);
  
      return pObject;
  }
  
  COOP_PINVOKE_HELPER(Array *, RhpNewArray, (EEType * pArrayEEType, int numElements))
  {
      ASSERT_MSG(!pArrayEEType->RequiresAlign8(), "NYI");
  
      Thread * pCurThread = ThreadStore::GetCurrentThread();
      gc_alloc_context * acontext = pCurThread->GetAllocContext();
      Array * pObject;
  
      if (numElements < 0)
      {
          ASSERT_UNCONDITIONALLY("NYI");  // TODO: Throw overflow
      }
  
      size_t size;
  #ifndef BIT64
      // if the element count is <= 0x10000, no overflow is possible because the component size is
      // <= 0xffff, and thus the product is <= 0xffff0000, and the base size is only ~12 bytes
      if (numElements > 0x10000)
      {
          // Perform the size computation using 64-bit integeres to detect overflow
          uint64_t size64 = (uint64_t)pArrayEEType->get_BaseSize() + ((uint64_t)numElements * (uint64_t)pArrayEEType->get_ComponentSize());
          size64 = (size64 + (sizeof(UIntNative)-1)) & ~(sizeof(UIntNative)-1);
  
          size = (size_t)size64;
          if (size != size64)
          {
              ASSERT_UNCONDITIONALLY("NYI");  // TODO: Throw overflow
          }
      }
      else
  #endif // !BIT64
      {
          size = (size_t)pArrayEEType->get_BaseSize() + ((size_t)numElements * (size_t)pArrayEEType->get_ComponentSize());
          size = ALIGN_UP(size, sizeof(UIntNative));
      }
  
      UInt8* result = acontext->alloc_ptr;
      UInt8* advance = result + size;
      if (advance <= acontext->alloc_limit)
      {
          acontext->alloc_ptr = advance;
          pObject = (Array *)result;
          pObject->set_EEType(pArrayEEType);
          pObject->InitArrayLength((UInt32)numElements);
          return pObject;
      }
  
      pObject = (Array *)RhpGcAlloc(pArrayEEType, 0, size, NULL);
      if (pObject == nullptr)
      {
          ASSERT_UNCONDITIONALLY("NYI");  // TODO: Throw OOM
      }
      pObject->set_EEType(pArrayEEType);
      pObject->InitArrayLength((UInt32)numElements);
  
      if (size >= RH_LARGE_OBJECT_SIZE)
          RhpPublishObject(pObject, size);
  
      return pObject;
  }
  
  COOP_PINVOKE_HELPER(String *, RhNewString, (EEType * pArrayEEType, int numElements))
  {
      // TODO: Implement. We tail call to RhpNewArray for now since there's a bunch of TODOs in the places
      // that matter anyway.
      return (String*)RhpNewArray(pArrayEEType, numElements);
  }
  
  #endif
  #if defined(USE_PORTABLE_HELPERS)
  
  #ifdef _ARM_
  COOP_PINVOKE_HELPER(Object *, RhpNewFinalizableAlign8, (EEType* pEEType))
  {
      Object * pObject = nullptr;
      /* TODO */ ASSERT_UNCONDITIONALLY("NYI");
      return pObject;
  }
  
  COOP_PINVOKE_HELPER(Object *, RhpNewFastMisalign, (EEType* pEEType))
  {
      Object * pObject = nullptr;
      /* TODO */ ASSERT_UNCONDITIONALLY("NYI");
      return pObject;
  }
  
  COOP_PINVOKE_HELPER(Object *, RhpNewFastAlign8, (EEType* pEEType))
  {
      Object * pObject = nullptr;
      /* TODO */ ASSERT_UNCONDITIONALLY("NYI");
      return pObject;
  }
  
  COOP_PINVOKE_HELPER(Array *, RhpNewArrayAlign8, (EEType * pArrayEEType, int numElements))
  {
      Array * pObject = nullptr;
      /* TODO */ ASSERT_UNCONDITIONALLY("NYI");
      return pObject;
  }
  #endif
  
  COOP_PINVOKE_HELPER(void, RhpInitialDynamicInterfaceDispatch, ())
  {
      ASSERT_UNCONDITIONALLY("NYI");
  }
  
  COOP_PINVOKE_HELPER(void, RhpInterfaceDispatch1, ())
  {
      ASSERT_UNCONDITIONALLY("NYI");
  }
  
  COOP_PINVOKE_HELPER(void, RhpInterfaceDispatch2, ())
  {
      ASSERT_UNCONDITIONALLY("NYI");
  }
  
  COOP_PINVOKE_HELPER(void, RhpInterfaceDispatch4, ())
  {
      ASSERT_UNCONDITIONALLY("NYI");
  }
  
  COOP_PINVOKE_HELPER(void, RhpInterfaceDispatch8, ())
  {
      ASSERT_UNCONDITIONALLY("NYI");
  }
  
  COOP_PINVOKE_HELPER(void, RhpInterfaceDispatch16, ())
  {
      ASSERT_UNCONDITIONALLY("NYI");
  }
  
  COOP_PINVOKE_HELPER(void, RhpInterfaceDispatch32, ())
  {
      ASSERT_UNCONDITIONALLY("NYI");
  }
  
  COOP_PINVOKE_HELPER(void, RhpInterfaceDispatch64, ())
  {
      ASSERT_UNCONDITIONALLY("NYI");
  }
  
  COOP_PINVOKE_HELPER(void, RhpVTableOffsetDispatch, ())
  {
      ASSERT_UNCONDITIONALLY("NYI");
  }
  
  COOP_PINVOKE_HELPER(void, RhpTailCallTLSDispatchCell, ())
  {
      ASSERT_UNCONDITIONALLY("NYI");
  }
  
  COOP_PINVOKE_HELPER(void, RhpCastableObjectDispatchHelper, ())
  {
      ASSERT_UNCONDITIONALLY("NYI");
  }
  
  COOP_PINVOKE_HELPER(void, RhpCastableObjectDispatchHelper_TailCalled, ())
  {
      ASSERT_UNCONDITIONALLY("NYI");
  }
  
  COOP_PINVOKE_HELPER(void, RhpCastableObjectDispatch_CommonStub, ())
  {
      ASSERT_UNCONDITIONALLY("NYI");
  }
  
  // @TODO Implement UniversalTransition
  EXTERN_C void * ReturnFromUniversalTransition;
  void * ReturnFromUniversalTransition;
  
  // @TODO Implement UniversalTransition_DebugStepTailCall
  EXTERN_C void * ReturnFromUniversalTransition_DebugStepTailCall;
  void * ReturnFromUniversalTransition_DebugStepTailCall;
  
  #endif // USE_PORTABLE_HELPERS
  
  // @TODO Implement CallDescrThunk
  EXTERN_C void * ReturnFromCallDescrThunk;
  #ifdef USE_PORTABLE_HELPERS
  void * ReturnFromCallDescrThunk;
  #endif
  
  #if defined(USE_PORTABLE_HELPERS) || defined(PLATFORM_UNIX)
  #if !defined (_ARM64_)
  // 
  // Return address hijacking
  //
  COOP_PINVOKE_HELPER(void, RhpGcProbeHijackScalar, ())
  {
      ASSERT_UNCONDITIONALLY("NYI");
  }
  COOP_PINVOKE_HELPER(void, RhpGcProbeHijackObject, ())
  {
      ASSERT_UNCONDITIONALLY("NYI");
  }
  COOP_PINVOKE_HELPER(void, RhpGcProbeHijackByref, ())
  {
      ASSERT_UNCONDITIONALLY("NYI");
  }
  COOP_PINVOKE_HELPER(void, RhpGcStressHijackScalar, ())
  {
      ASSERT_UNCONDITIONALLY("NYI");
  }
  COOP_PINVOKE_HELPER(void, RhpGcStressHijackObject, ())
  {
      ASSERT_UNCONDITIONALLY("NYI");
  }
  COOP_PINVOKE_HELPER(void, RhpGcStressHijackByref, ())
  {
      ASSERT_UNCONDITIONALLY("NYI");
  }
  #endif
  #endif // defined(USE_PORTABLE_HELPERS) || defined(PLATFORM_UNIX)
  
  #if defined(USE_PORTABLE_HELPERS)
  
  #if !defined (_ARM64_)
  COOP_PINVOKE_HELPER(void, RhpAssignRef, (Object ** dst, Object * ref))
  {
      // @TODO: USE_PORTABLE_HELPERS - Null check
      *dst = ref;
      InlineWriteBarrier(dst, ref);
  }
  
  COOP_PINVOKE_HELPER(void, RhpCheckedAssignRef, (Object ** dst, Object * ref))
  {
      // @TODO: USE_PORTABLE_HELPERS - Null check
      *dst = ref;
      InlineCheckedWriteBarrier(dst, ref);
  }
  #endif
  
  COOP_PINVOKE_HELPER(Object *, RhpCheckedLockCmpXchg, (Object ** location, Object * value, Object * comparand))
  {
      // @TODO: USE_PORTABLE_HELPERS - Null check
      Object * ret = (Object *)PalInterlockedCompareExchangePointer((void * volatile *)location, value, comparand);
      InlineCheckedWriteBarrier(location, value);
      return ret;
  }
  
  COOP_PINVOKE_HELPER(Object *, RhpCheckedXchg, (Object ** location, Object * value))
  {
      // @TODO: USE_PORTABLE_HELPERS - Null check
      Object * ret = (Object *)PalInterlockedExchangePointer((void * volatile *)location, value);
      InlineCheckedWriteBarrier(location, value);
      return ret;
  }
  
  COOP_PINVOKE_HELPER(Int32, RhpLockCmpXchg32, (Int32 * location, Int32 value, Int32 comparand))
  {
      // @TODO: USE_PORTABLE_HELPERS - Null check
      return PalInterlockedCompareExchange(location, value, comparand);
  }
  
  COOP_PINVOKE_HELPER(Int64, RhpLockCmpXchg64, (Int64 * location, Int64 value, Int64 comparand))
  {
      // @TODO: USE_PORTABLE_HELPERS - Null check
      return PalInterlockedCompareExchange64(location, value, comparand);
  }
  
  #endif // USE_PORTABLE_HELPERS
  
  #if !defined(_ARM64_)
  COOP_PINVOKE_HELPER(void, RhpMemoryBarrier, ())
  {
      PalMemoryBarrier();
  }
  #endif
  
  #if defined(USE_PORTABLE_HELPERS)
  EXTERN_C REDHAWK_API void* __cdecl RhAllocateThunksMapping()
  {
      return NULL;
  }
  
  COOP_PINVOKE_HELPER(void *, RhpGetThunksBase, ())
  {
      return NULL;
  }
  
  COOP_PINVOKE_HELPER(int, RhpGetNumThunkBlocksPerMapping, ())
  {
      ASSERT_UNCONDITIONALLY("NYI");
      return 0;
  }
  
  COOP_PINVOKE_HELPER(int, RhpGetNumThunksPerBlock, ())
  {
      ASSERT_UNCONDITIONALLY("NYI");
      return 0;
  }
  
  COOP_PINVOKE_HELPER(int, RhpGetThunkSize, ())
  {
      ASSERT_UNCONDITIONALLY("NYI");
      return 0;
  }
  
  COOP_PINVOKE_HELPER(void*, RhpGetThunkDataBlockAddress, (void* pThunkStubAddress))
  {
      ASSERT_UNCONDITIONALLY("NYI");
      return NULL;
  }
  
  COOP_PINVOKE_HELPER(void*, RhpGetThunkStubsBlockAddress, (void* pThunkDataAddress))
  {
      ASSERT_UNCONDITIONALLY("NYI");
      return NULL;
  }
  
  COOP_PINVOKE_HELPER(int, RhpGetThunkBlockSize, ())
  {
      ASSERT_UNCONDITIONALLY("NYI");
      return NULL;
  }
  
  COOP_PINVOKE_HELPER(void, RhCallDescrWorker, (void * callDescr))
  {
      ASSERT_UNCONDITIONALLY("NYI");
  }
  
  #ifdef CALLDESCR_FPARGREGSARERETURNREGS
  COOP_PINVOKE_HELPER(void, CallingConventionConverter_GetStubs, (UIntNative* pReturnVoidStub, UIntNative* pReturnIntegerStub, UIntNative* pCommonStub))
  #else
  COOP_PINVOKE_HELPER(void, CallingConventionConverter_GetStubs, (UIntNative* pReturnVoidStub, UIntNative* pReturnIntegerStub, UIntNative* pCommonStub, UIntNative* pReturnFloatingPointReturn4Thunk, UIntNative* pReturnFloatingPointReturn8Thunk))
  #endif
  {
      ASSERT_UNCONDITIONALLY("NYI");
  }
  
  COOP_PINVOKE_HELPER(void *, RhGetCommonStubAddress, ())
  {
      ASSERT_UNCONDITIONALLY("NYI");
      return NULL;
  }
  
  COOP_PINVOKE_HELPER(void *, RhGetCurrentThunkContext, ())
  {
      ASSERT_UNCONDITIONALLY("NYI");
      return NULL;
  }
  
  #endif
  
  COOP_PINVOKE_HELPER(void, RhpGcPoll, ())
  {
      // TODO: implement
  }
  