diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets index 2c1e91afc8ba16..b3ce3dc5f56cf1 100644 --- a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets +++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets @@ -236,6 +236,8 @@ The .NET Foundation licenses this file to you under the MIT license. + + diff --git a/src/coreclr/nativeaot/Runtime/CMakeLists.txt b/src/coreclr/nativeaot/Runtime/CMakeLists.txt index 9f3a80c702358e..b4f63dc5faca0d 100644 --- a/src/coreclr/nativeaot/Runtime/CMakeLists.txt +++ b/src/coreclr/nativeaot/Runtime/CMakeLists.txt @@ -338,6 +338,7 @@ convert_to_absolute_path(VXSORT_SOURCES ${VXSORT_SOURCES}) convert_to_absolute_path(DUMMY_VXSORT_SOURCES ${DUMMY_VXSORT_SOURCES}) if(NOT CLR_CMAKE_TARGET_ARCH_WASM) + add_subdirectory(datadescriptor) add_subdirectory(Full) else() add_subdirectory(Portable) diff --git a/src/coreclr/nativeaot/Runtime/Full/CMakeLists.txt b/src/coreclr/nativeaot/Runtime/Full/CMakeLists.txt index 74cdeca700a1ae..56fc4a3d7d6e0e 100644 --- a/src/coreclr/nativeaot/Runtime/Full/CMakeLists.txt +++ b/src/coreclr/nativeaot/Runtime/Full/CMakeLists.txt @@ -24,11 +24,11 @@ endif (CLR_CMAKE_TARGET_WIN32) add_library(Runtime.WorkstationGC STATIC ${COMMON_RUNTIME_SOURCES} ${FULL_RUNTIME_SOURCES} ${RUNTIME_ARCH_ASM_OBJECTS}) add_dependencies(Runtime.WorkstationGC aot_eventing_headers) -target_link_libraries(Runtime.WorkstationGC PRIVATE aotminipal) +target_link_libraries(Runtime.WorkstationGC PRIVATE aotminipal nativeaot_cdac_contract_descriptor nativeaot_gc_wks_descriptor) add_library(Runtime.ServerGC STATIC ${COMMON_RUNTIME_SOURCES} ${FULL_RUNTIME_SOURCES} ${SERVER_GC_SOURCES} ${RUNTIME_ARCH_ASM_OBJECTS}) add_dependencies(Runtime.ServerGC aot_eventing_headers) -target_link_libraries(Runtime.ServerGC PRIVATE aotminipal) +target_link_libraries(Runtime.ServerGC PRIVATE aotminipal nativeaot_cdac_contract_descriptor nativeaot_gc_svr_descriptor) add_library(standalonegc-disabled STATIC ${STANDALONEGC_DISABLED_SOURCES}) add_dependencies(standalonegc-disabled aot_eventing_headers) diff --git a/src/coreclr/nativeaot/Runtime/RuntimeInstance.h b/src/coreclr/nativeaot/Runtime/RuntimeInstance.h index 7f6b7ac6195c8e..43ad527ed8bf94 100644 --- a/src/coreclr/nativeaot/Runtime/RuntimeInstance.h +++ b/src/coreclr/nativeaot/Runtime/RuntimeInstance.h @@ -11,6 +11,7 @@ class TypeManager; enum GenericVarianceType : uint8_t; #include "ICodeManager.h" +#include "cdacdata.h" extern "C" void PopulateDebugHeaders(); @@ -20,6 +21,7 @@ class RuntimeInstance friend struct DefaultSListTraits; friend class Thread; friend void PopulateDebugHeaders(); + friend struct ::cdac_data; PTR_ThreadStore m_pThreadStore; HANDLE m_hPalInstance; // this is the HANDLE passed into DllMain @@ -114,6 +116,10 @@ class RuntimeInstance }; typedef DPTR(RuntimeInstance) PTR_RuntimeInstance; +template<> struct cdac_data +{ + static constexpr size_t ThreadStore = offsetof(RuntimeInstance, m_pThreadStore); +}; PTR_RuntimeInstance GetRuntimeInstance(); diff --git a/src/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txt b/src/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txt new file mode 100644 index 00000000000000..feabf0b62d2c2a --- /dev/null +++ b/src/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txt @@ -0,0 +1,48 @@ +set(CMAKE_INCLUDE_CURRENT_DIR OFF) + +# cDAC contract descriptor for NativeAOT +# +# This uses the shared datadescriptor infrastructure from +# src/coreclr/debug/datadescriptor-shared/ to generate a +# DotNetRuntimeContractDescriptor symbol in the NativeAOT runtime. +# +# Include directories and compile definitions are inherited from the parent +# Runtime/CMakeLists.txt directory scope. The interface targets below only +# need to add the datadescriptor-specific include path. + +include(${CLR_DIR}/clrdatadescriptors.cmake) + +add_library(nativeaot_descriptor_interface INTERFACE) +target_include_directories(nativeaot_descriptor_interface INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR}) +add_dependencies(nativeaot_descriptor_interface Runtime.WorkstationGC) +generate_data_descriptors( + LIBRARY_NAME nativeaot_cdac_contract_descriptor + CONTRACT_NAME "DotNetRuntimeContractDescriptor" + INTERFACE_TARGET nativeaot_descriptor_interface + EXPORT_VISIBLE) + +# GC contract descriptors (workstation + server). +# The GC has its own data descriptor exposed as a sub-descriptor via gc_descriptor in GcDacVars. +set(GC_DESCRIPTOR_DIR "${CLR_DIR}/gc/datadescriptor") + +add_library(nativeaot_gc_wks_descriptor_interface INTERFACE) +target_include_directories(nativeaot_gc_wks_descriptor_interface INTERFACE + ${GC_DESCRIPTOR_DIR} + ${GC_DIR}) +add_dependencies(nativeaot_gc_wks_descriptor_interface Runtime.WorkstationGC) +generate_data_descriptors( + LIBRARY_NAME nativeaot_gc_wks_descriptor + CONTRACT_NAME "GCContractDescriptorWKS" + INTERFACE_TARGET nativeaot_gc_wks_descriptor_interface) + +add_library(nativeaot_gc_svr_descriptor_interface INTERFACE) +target_include_directories(nativeaot_gc_svr_descriptor_interface INTERFACE + ${GC_DESCRIPTOR_DIR} + ${GC_DIR}) +add_dependencies(nativeaot_gc_svr_descriptor_interface Runtime.WorkstationGC) +target_compile_definitions(nativeaot_gc_svr_descriptor_interface INTERFACE -DSERVER_GC) +generate_data_descriptors( + LIBRARY_NAME nativeaot_gc_svr_descriptor + CONTRACT_NAME "GCContractDescriptorSVR" + INTERFACE_TARGET nativeaot_gc_svr_descriptor_interface) diff --git a/src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.h b/src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.h new file mode 100644 index 00000000000000..31f9f945e7f2cb --- /dev/null +++ b/src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.h @@ -0,0 +1,27 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// This header provides the includes needed for datadescriptor.inc to use +// offsetof() on NativeAOT runtime data structures. +// +// Note: Some NativeAOT types have private members that offsetof() cannot access +// from this compilation unit. For those types, we use known offset constants +// validated at build time by AsmOffsetsVerify.cpp and DebugHeader.cpp static_asserts. + +#include "common.h" +#include "gcenv.h" +#include "gcheaputilities.h" +#include "gcinterface.dac.h" +#include "rhassert.h" +#include "TargetPtrs.h" +#include "PalLimitedContext.h" +#include "Pal.h" +#include "holder.h" +#include "RuntimeInstance.h" +#include "regdisplay.h" +#include "StackFrameIterator.h" +#include "thread.h" +#include "threadstore.h" + +#include +#include diff --git a/src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc b/src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc new file mode 100644 index 00000000000000..fa71924c6120f0 --- /dev/null +++ b/src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc @@ -0,0 +1,140 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// +// No include guards. This file is included multiple times. +// +// NativeAOT data descriptor declarations for the cDAC contract system. +// This file defines the types, fields, and globals that diagnostic tools +// need to inspect NativeAOT runtime state. +// +// When modifying this file (adding/removing types, fields, or globals), you must also: +// 1. Update the corresponding contract doc in docs/design/datacontracts/.md +// 2. Update the managed data class in src/native/managed/cdac/.../Data/.cs +// 3. Update the contract implementation in src/native/managed/cdac/.../Contracts/.cs +// 4. Update the mock descriptors and tests in src/native/managed/cdac/tests/. + +CDAC_BASELINE("empty") +CDAC_TYPES_BEGIN() + +// ======================== +// Thread and ThreadStore +// ======================== + +CDAC_TYPE_BEGIN(Thread) +CDAC_TYPE_INDETERMINATE(Thread) +CDAC_TYPE_FIELD(Thread, T_UINT64, OSId, offsetof(RuntimeThreadLocals, m_threadId)) +CDAC_TYPE_FIELD(Thread, T_UINT32, State, offsetof(RuntimeThreadLocals, m_ThreadStateFlags)) +CDAC_TYPE_FIELD(Thread, T_POINTER, LinkNext, offsetof(RuntimeThreadLocals, m_pNext)) +CDAC_TYPE_FIELD(Thread, T_POINTER, ExceptionTracker, offsetof(RuntimeThreadLocals, m_pExInfoStackHead)) +CDAC_TYPE_FIELD(Thread, T_POINTER, CachedStackBase, offsetof(RuntimeThreadLocals, m_pStackHigh)) +CDAC_TYPE_FIELD(Thread, T_POINTER, CachedStackLimit, offsetof(RuntimeThreadLocals, m_pStackLow)) +CDAC_TYPE_FIELD(Thread, TYPE(RuntimeThreadLocals), RuntimeThreadLocals, offsetof(RuntimeThreadLocals, m_eeAllocContext)) +CDAC_TYPE_FIELD(Thread, T_POINTER, TransitionFrame, offsetof(RuntimeThreadLocals, m_pTransitionFrame)) +CDAC_TYPE_END(Thread) + +CDAC_TYPE_BEGIN(ThreadStore) +CDAC_TYPE_INDETERMINATE(ThreadStore) +CDAC_TYPE_FIELD(ThreadStore, T_POINTER, FirstThreadLink, cdac_data::FirstThreadLink) +CDAC_TYPE_END(ThreadStore) + +CDAC_TYPE_BEGIN(RuntimeThreadLocals) +CDAC_TYPE_INDETERMINATE(RuntimeThreadLocals) +CDAC_TYPE_FIELD(RuntimeThreadLocals, TYPE(EEAllocContext), AllocContext, offsetof(RuntimeThreadLocals, m_eeAllocContext)) +CDAC_TYPE_END(RuntimeThreadLocals) + +// ======================== +// Allocation Context +// ======================== + +CDAC_TYPE_BEGIN(EEAllocContext) +CDAC_TYPE_INDETERMINATE(EEAllocContext) +CDAC_TYPE_FIELD(EEAllocContext, TYPE(GCAllocContext), GCAllocationContext, offsetof(ee_alloc_context, m_rgbAllocContextBuffer)) +CDAC_TYPE_END(EEAllocContext) + +CDAC_TYPE_BEGIN(GCAllocContext) +CDAC_TYPE_INDETERMINATE(GCAllocContext) +CDAC_TYPE_FIELD(GCAllocContext, T_POINTER, Pointer, offsetof(gc_alloc_context, alloc_ptr)) +CDAC_TYPE_FIELD(GCAllocContext, T_POINTER, Limit, offsetof(gc_alloc_context, alloc_limit)) +CDAC_TYPE_FIELD(GCAllocContext, T_INT64, AllocBytes, offsetof(gc_alloc_context, alloc_bytes)) +CDAC_TYPE_FIELD(GCAllocContext, T_INT64, AllocBytesLoh, offsetof(gc_alloc_context, alloc_bytes_uoh)) +CDAC_TYPE_END(GCAllocContext) + +// ======================== +// MethodTable (EEType) +// ======================== + +CDAC_TYPE_BEGIN(MethodTable) +CDAC_TYPE_INDETERMINATE(MethodTable) +CDAC_TYPE_FIELD(MethodTable, T_UINT32, Flags, cdac_data::Flags) +CDAC_TYPE_FIELD(MethodTable, T_UINT32, BaseSize, cdac_data::BaseSize) +CDAC_TYPE_FIELD(MethodTable, T_POINTER, RelatedType, cdac_data::RelatedType) +CDAC_TYPE_FIELD(MethodTable, T_UINT16, NumVtableSlots, cdac_data::NumVtableSlots) +CDAC_TYPE_FIELD(MethodTable, T_UINT16, NumInterfaces, cdac_data::NumInterfaces) +CDAC_TYPE_FIELD(MethodTable, T_UINT32, HashCode, cdac_data::HashCode) +CDAC_TYPE_FIELD(MethodTable, T_POINTER, VTable, cdac_data::VTable) +CDAC_TYPE_END(MethodTable) + +// ======================== +// Exception Info +// ======================== + +CDAC_TYPE_BEGIN(ExInfo) +CDAC_TYPE_INDETERMINATE(ExInfo) +CDAC_TYPE_FIELD(ExInfo, T_POINTER, PreviousNestedInfo, offsetof(ExInfo, m_pPrevExInfo)) +CDAC_TYPE_FIELD(ExInfo, T_POINTER, ThrownObject, offsetof(ExInfo, m_exception)) +CDAC_TYPE_END(ExInfo) + +// ======================== +// RuntimeInstance +// ======================== + +CDAC_TYPE_BEGIN(RuntimeInstance) +CDAC_TYPE_INDETERMINATE(RuntimeInstance) +CDAC_TYPE_FIELD(RuntimeInstance, T_POINTER, ThreadStore, cdac_data::ThreadStore) +CDAC_TYPE_END(RuntimeInstance) + +CDAC_TYPES_END() + +// ======================== +// Globals +// ======================== + +CDAC_GLOBALS_BEGIN() + +CDAC_GLOBAL_POINTER(RuntimeInstance, &g_pTheRuntimeInstance) + +CDAC_GLOBAL_POINTER(FreeObjectMethodTable, &g_pFreeObjectEEType) + +CDAC_GLOBAL_POINTER(GCLowestAddress, &g_lowest_address) +CDAC_GLOBAL_POINTER(GCHighestAddress, &g_highest_address) + +// NativeAOT MethodTable flag constants (accessed via cdac_data friend) +CDAC_GLOBAL(MethodTableEETypeKindMask, uint32, cdac_data::EETypeKindMask) +CDAC_GLOBAL(MethodTableHasComponentSizeFlag, uint32, cdac_data::HasComponentSizeFlag) +CDAC_GLOBAL(MethodTableHasFinalizerFlag, uint32, cdac_data::HasFinalizerFlag) +CDAC_GLOBAL(MethodTableHasPointersFlag, uint32, cdac_data::HasPointersFlag) +CDAC_GLOBAL(MethodTableIsGenericFlag, uint32, cdac_data::IsGenericFlag) +CDAC_GLOBAL(MethodTableElementTypeMask, uint32, cdac_data::ElementTypeMask) +CDAC_GLOBAL(MethodTableElementTypeShift, uint32, cdac_data::ElementTypeShift) + +// Thread state flag constants +CDAC_GLOBAL(ThreadStateFlagAttached, uint32, 0x00000001) +CDAC_GLOBAL(ThreadStateFlagDetached, uint32, 0x00000002) + +// Object contract globals +#ifdef TARGET_64BIT +CDAC_GLOBAL(ObjectToMethodTableUnmask, uint8, 7) +#else +CDAC_GLOBAL(ObjectToMethodTableUnmask, uint8, 3) +#endif + +// Contracts: declare which contracts this runtime supports +CDAC_GLOBAL_CONTRACT(Thread, 1001) +CDAC_GLOBAL_CONTRACT(Exception, 1) +CDAC_GLOBAL_CONTRACT(RuntimeTypeSystem, 1001) + +// GC sub-descriptor: the GC populates gc_descriptor during GC_Initialize. +// It is important for subdescriptor pointers to be the last pointers. +CDAC_GLOBAL_SUB_DESCRIPTOR(GC, &(g_gc_dac_vars.gc_descriptor)) + +CDAC_GLOBALS_END() diff --git a/src/coreclr/nativeaot/Runtime/inc/MethodTable.h b/src/coreclr/nativeaot/Runtime/inc/MethodTable.h index 89ff445f6174d9..77c2ceec275a4b 100644 --- a/src/coreclr/nativeaot/Runtime/inc/MethodTable.h +++ b/src/coreclr/nativeaot/Runtime/inc/MethodTable.h @@ -12,6 +12,9 @@ class MethodTable; class TypeManager; struct TypeManagerHandle; +// cdac_data template for exposing private members to the cDAC data descriptor. +#include "cdacdata.h" + //------------------------------------------------------------------------------------------------- // The subset of TypeFlags that NativeAOT knows about at runtime // This should match the TypeFlags enum in the managed type system. @@ -86,6 +89,7 @@ class MethodTable { friend class AsmOffsets; friend void PopulateDebugHeaders(); + friend struct ::cdac_data; private: struct RelatedTypeUnion @@ -346,4 +350,23 @@ class MethodTable UInt32_BOOL SanityCheck() { return Validate(); } }; +template<> struct cdac_data +{ + static constexpr size_t Flags = offsetof(MethodTable, m_uFlags); + static constexpr size_t BaseSize = offsetof(MethodTable, m_uBaseSize); + static constexpr size_t RelatedType = offsetof(MethodTable, m_RelatedType); + static constexpr size_t NumVtableSlots = offsetof(MethodTable, m_usNumVtableSlots); + static constexpr size_t NumInterfaces = offsetof(MethodTable, m_usNumInterfaces); + static constexpr size_t HashCode = offsetof(MethodTable, m_uHashCode); + static constexpr size_t VTable = offsetof(MethodTable, m_VTable); + + static constexpr uint32_t EETypeKindMask = MethodTable::EETypeKindMask; + static constexpr uint32_t HasComponentSizeFlag = MethodTable::HasComponentSizeFlag; + static constexpr uint32_t HasFinalizerFlag = MethodTable::HasFinalizerFlag; + static constexpr uint32_t HasPointersFlag = MethodTable::HasPointersFlag; + static constexpr uint32_t IsGenericFlag = MethodTable::IsGenericFlag; + static constexpr uint32_t ElementTypeMask = MethodTable::ElementTypeMask; + static constexpr uint32_t ElementTypeShift = MethodTable::ElementTypeShift; +}; + #pragma warning(pop) diff --git a/src/coreclr/nativeaot/Runtime/threadstore.h b/src/coreclr/nativeaot/Runtime/threadstore.h index d2347f9a631ffa..f87730e08fc574 100644 --- a/src/coreclr/nativeaot/Runtime/threadstore.h +++ b/src/coreclr/nativeaot/Runtime/threadstore.h @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. #include "Crst.h" +#include "cdacdata.h" class Thread; class CLREventStatic; @@ -20,6 +21,7 @@ extern "C" void PopulateDebugHeaders(); class ThreadStore { friend void PopulateDebugHeaders(); + friend struct ::cdac_data; SList m_ThreadList; PTR_RuntimeInstance m_pRuntimeInstance; @@ -68,6 +70,11 @@ class ThreadStore }; typedef DPTR(ThreadStore) PTR_ThreadStore; +template<> struct cdac_data +{ + static constexpr size_t FirstThreadLink = offsetof(ThreadStore, m_ThreadList); +}; + ThreadStore * GetThreadStore(); #define FOREACH_THREAD(p_thread_name) \