diff options
author | Jiyoung Yun <jy910.yun@samsung.com> | 2017-04-27 16:54:50 +0900 |
---|---|---|
committer | Jiyoung Yun <jy910.yun@samsung.com> | 2017-04-27 16:54:50 +0900 |
commit | 5b975f8233e8c8d17b215372f89ca713b45d6a0b (patch) | |
tree | 0267bcc331458a01f4c26fafd28110a72273beb3 /src/vm | |
parent | a56e30c8d33048216567753d9d3fefc2152af8ac (diff) | |
download | coreclr-5b975f8233e8c8d17b215372f89ca713b45d6a0b.tar.gz coreclr-5b975f8233e8c8d17b215372f89ca713b45d6a0b.tar.bz2 coreclr-5b975f8233e8c8d17b215372f89ca713b45d6a0b.zip |
Imported Upstream version 2.0.0.11599upstream/2.0.0.11599
Diffstat (limited to 'src/vm')
57 files changed, 1536 insertions, 628 deletions
diff --git a/src/vm/CMakeLists.txt b/src/vm/CMakeLists.txt index 26fcacf4af..da1aa8fe62 100644 --- a/src/vm/CMakeLists.txt +++ b/src/vm/CMakeLists.txt @@ -317,6 +317,7 @@ if(CLR_CMAKE_TARGET_ARCH_AMD64) ${ARCH_SOURCES_DIR}/JitHelpers_FastWriteBarriers.asm ${ARCH_SOURCES_DIR}/JitHelpers_InlineGetAppDomain.asm ${ARCH_SOURCES_DIR}/JitHelpers_InlineGetThread.asm + ${ARCH_SOURCES_DIR}/JitHelpers_SingleAppDomain.asm ${ARCH_SOURCES_DIR}/JitHelpers_Slow.asm ${ARCH_SOURCES_DIR}/PInvokeStubs.asm ${ARCH_SOURCES_DIR}/RedirectedHandledJITCase.asm @@ -363,6 +364,7 @@ else(WIN32) ${ARCH_SOURCES_DIR}/getstate.S ${ARCH_SOURCES_DIR}/jithelpers_fast.S ${ARCH_SOURCES_DIR}/jithelpers_fastwritebarriers.S + ${ARCH_SOURCES_DIR}/jithelpers_singleappdomain.S ${ARCH_SOURCES_DIR}/jithelpers_slow.S ${ARCH_SOURCES_DIR}/pinvokestubs.S ${ARCH_SOURCES_DIR}/theprestubamd64.S diff --git a/src/vm/amd64/JitHelpers_SingleAppDomain.asm b/src/vm/amd64/JitHelpers_SingleAppDomain.asm new file mode 100644 index 0000000000..f1b267435a --- /dev/null +++ b/src/vm/amd64/JitHelpers_SingleAppDomain.asm @@ -0,0 +1,64 @@ +; 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. + +; ==++== +; + +; +; ==--== +; *********************************************************************** +; File: JitHelpers_SingleAppDomain.asm +; +; Notes: JIT Static access helpers when coreclr host specifies single +; appdomain flag +; *********************************************************************** + +include AsmMacros.inc +include asmconstants.inc + +; Min amount of stack space that a nested function should allocate. +MIN_SIZE equ 28h + +extern JIT_GetSharedNonGCStaticBase_Helper:proc +extern JIT_GetSharedGCStaticBase_Helper:proc + +LEAF_ENTRY JIT_GetSharedNonGCStaticBase_SingleAppDomain, _TEXT + ; If class is not initialized, bail to C++ helper + test byte ptr [rcx + OFFSETOF__DomainLocalModule__m_pDataBlob + rdx], 1 + jz CallHelper + mov rax, rcx + REPRET + + align 16 + CallHelper: + ; Tail call JIT_GetSharedNonGCStaticBase_Helper + jmp JIT_GetSharedNonGCStaticBase_Helper +LEAF_END JIT_GetSharedNonGCStaticBase_SingleAppDomain, _TEXT + +LEAF_ENTRY JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain, _TEXT + mov rax, rcx + ret +LEAF_END JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain, _TEXT + +LEAF_ENTRY JIT_GetSharedGCStaticBase_SingleAppDomain, _TEXT + ; If class is not initialized, bail to C++ helper + test byte ptr [rcx + OFFSETOF__DomainLocalModule__m_pDataBlob + rdx], 1 + jz CallHelper + + mov rax, [rcx + OFFSETOF__DomainLocalModule__m_pGCStatics] + REPRET + + align 16 + CallHelper: + ; Tail call Jit_GetSharedGCStaticBase_Helper + jmp JIT_GetSharedGCStaticBase_Helper +LEAF_END JIT_GetSharedGCStaticBase_SingleAppDomain, _TEXT + +LEAF_ENTRY JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain, _TEXT + mov rax, [rcx + OFFSETOF__DomainLocalModule__m_pGCStatics] + ret +LEAF_END JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain, _TEXT + + end + diff --git a/src/vm/amd64/jithelpers_singleappdomain.S b/src/vm/amd64/jithelpers_singleappdomain.S new file mode 100644 index 0000000000..307d86b7fe --- /dev/null +++ b/src/vm/amd64/jithelpers_singleappdomain.S @@ -0,0 +1,49 @@ +// 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. + +.intel_syntax noprefix +#include "unixasmmacros.inc" +#include "asmconstants.h" + +// +// JIT Static access helpers when coreclr host specifies single +// appdomain flag +// + +LEAF_ENTRY JIT_GetSharedNonGCStaticBase_SingleAppDomain, _TEXT + // If class is not initialized, bail to C++ helper + test byte ptr [rdi + OFFSETOF__DomainLocalModule__m_pDataBlob + rsi], 1 + jz CallHelper + mov rax, rdi + rep ret + +.balign 16 +CallHelper: + // Tail call JIT_GetSharedNonGCStaticBase_Helper + jmp C_FUNC(JIT_GetSharedNonGCStaticBase_Helper) +LEAF_END_MARKED JIT_GetSharedNonGCStaticBase_SingleAppDomain, _TEXT + +LEAF_ENTRY JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain, _TEXT + mov rax, rdi + ret +LEAF_END JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain, _TEXT + +LEAF_ENTRY JIT_GetSharedGCStaticBase_SingleAppDomain, _TEXT + // If class is not initialized, bail to C++ helper + test byte ptr [rdi + OFFSETOF__DomainLocalModule__m_pDataBlob + rsi], 1 + jz CallHelper1 + + mov rax, [rdi + OFFSETOF__DomainLocalModule__m_pGCStatics] + rep ret + +.balign 16 +CallHelper1: + // Tail call Jit_GetSharedGCStaticBase_Helper + jmp C_FUNC(JIT_GetSharedGCStaticBase_Helper) +LEAF_END JIT_GetSharedGCStaticBase_SingleAppDomain, _TEXT + +LEAF_ENTRY JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain, _TEXT + mov rax, [rdi + OFFSETOF__DomainLocalModule__m_pGCStatics] + ret +LEAF_END JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain, _TEXT diff --git a/src/vm/amd64/unixstubs.cpp b/src/vm/amd64/unixstubs.cpp index 2904149084..76d3cf1890 100644 --- a/src/vm/amd64/unixstubs.cpp +++ b/src/vm/amd64/unixstubs.cpp @@ -37,7 +37,7 @@ extern "C" " mov %%edx, 12(%[result])\n" \ : "=a"(eax) /*output in eax*/\ : "a"(arg), [result]"r"(result) /*inputs - arg in eax, result in any register*/\ - : "eax", "rbx", "ecx", "edx", "memory" /* registers that are clobbered, *result is clobbered */ + : "rbx", "ecx", "edx", "memory" /* registers that are clobbered, *result is clobbered */ ); return eax; } @@ -52,7 +52,7 @@ extern "C" " mov %%edx, 12(%[result])\n" \ : "=a"(eax) /*output in eax*/\ : "c"(arg1), "a"(arg2), [result]"r"(result) /*inputs - arg1 in ecx, arg2 in eax, result in any register*/\ - : "eax", "rbx", "ecx", "edx", "memory" /* registers that are clobbered, *result is clobbered */ + : "rbx", "edx", "memory" /* registers that are clobbered, *result is clobbered */ ); return eax; } @@ -63,7 +63,7 @@ extern "C" __asm(" xgetbv\n" \ : "=a"(eax) /*output in eax*/\ : "c"(0) /*inputs - 0 in ecx*/\ - : "eax", "edx" /* registers that are clobbered*/ + : "edx" /* registers that are clobbered*/ ); // check OS has enabled both XMM and YMM state support return ((eax & 0x06) == 0x06) ? 1 : 0; diff --git a/src/vm/appdomain.cpp b/src/vm/appdomain.cpp index 5bfb12fc6b..bd05991ea2 100644 --- a/src/vm/appdomain.cpp +++ b/src/vm/appdomain.cpp @@ -741,7 +741,7 @@ BaseDomain::BaseDomain() #ifndef CROSSGEN_COMPILE // Note that m_handleStore is overridden by app domains - m_handleStore = GCHandleTableUtilities::GetGCHandleTable()->GetGlobalHandleStore(); + m_handleStore = GCHandleUtilities::GetGCHandleManager()->GetGlobalHandleStore(); #else m_handleStore = NULL; #endif @@ -4273,11 +4273,16 @@ void AppDomain::Init() // default domain cannot be unloaded. if (GetId().m_dwId == DefaultADID) { - m_handleStore = GCHandleTableUtilities::GetGCHandleTable()->GetGlobalHandleStore(); + m_handleStore = GCHandleUtilities::GetGCHandleManager()->GetGlobalHandleStore(); } else { - m_handleStore = GCHandleTableUtilities::GetGCHandleTable()->CreateHandleStore((void*)(uintptr_t)m_dwIndex.m_dwIndex); + m_handleStore = GCHandleUtilities::GetGCHandleManager()->CreateHandleStore((void*)(uintptr_t)m_dwIndex.m_dwIndex); + } + + if (!m_handleStore) + { + COMPlusThrowOM(); } #endif // CROSSGEN_COMPILE @@ -4578,9 +4583,9 @@ void AppDomain::Terminate() BaseDomain::Terminate(); - if (m_handleStore) + if (m_handleStore) { - GCHandleTableUtilities::GetGCHandleTable()->DestroyHandleStore(m_handleStore); + GCHandleUtilities::GetGCHandleManager()->DestroyHandleStore(m_handleStore); m_handleStore = NULL; } @@ -4679,7 +4684,8 @@ OBJECTREF AppDomain::GetExposedObject() obj = (APPDOMAINREF) AllocateObject(pMT); obj->SetDomain(this); - if(StoreFirstObjectInHandle(m_ExposedObject, (OBJECTREF) obj) == FALSE) { + if (!StoreFirstObjectInHandle(m_ExposedObject, (OBJECTREF) obj)) + { obj = (APPDOMAINREF) GetRawExposedObject(); _ASSERTE(obj); } @@ -9197,8 +9203,8 @@ void AppDomain::ClearGCHandles() // Keep async pin handles alive by moving them to default domain HandleAsyncPinHandles(); - // Remove our handle table as a source of GC roots - GCHandleTableUtilities::GetGCHandleTable()->UprootHandleStore(m_handleStore); + // Remove our handle store as a source of GC roots + m_handleStore->Uproot(); } // When an AD is unloaded, we will release all objects in this AD. @@ -9247,15 +9253,13 @@ void AppDomain::ClearGCRoots() // this point, so only need to synchronize the preemptive mode threads. ExecutionManager::Unload(GetLoaderAllocator()); - IGCHandleTable* pHandleTable = GCHandleTableUtilities::GetGCHandleTable(); - while ((pThread = ThreadStore::GetAllThreadList(pThread, 0, 0)) != NULL) { // Delete the thread local static store pThread->DeleteThreadStaticData(this); // <TODO>@TODO: A pre-allocated AppDomainUnloaded exception might be better.</TODO> - if (pHandleTable->ContainsHandle(m_handleStore, pThread->m_LastThrownObjectHandle)) + if (m_handleStore->ContainsHandle(pThread->m_LastThrownObjectHandle)) { // Never delete a handle to a preallocated exception object. if (!CLRException::IsPreallocatedExceptionHandle(pThread->m_LastThrownObjectHandle)) diff --git a/src/vm/appdomain.hpp b/src/vm/appdomain.hpp index 898e50f1c2..a5bd00d36b 100644 --- a/src/vm/appdomain.hpp +++ b/src/vm/appdomain.hpp @@ -28,7 +28,7 @@ #include "ilstubcache.h" #include "testhookmgr.h" #include "gcheaputilities.h" -#include "gchandletableutilities.h" +#include "gchandleutilities.h" #include "../binder/inc/applicationcontext.hpp" #include "rejit.h" @@ -1245,8 +1245,13 @@ public: { WRAPPER_NO_CONTRACT; - IGCHandleTable *pHandleTable = GCHandleTableUtilities::GetGCHandleTable(); - return pHandleTable->CreateHandleOfType(m_handleStore, OBJECTREFToObject(object), type); + OBJECTHANDLE hnd = m_handleStore->CreateHandleOfType(OBJECTREFToObject(object), type); + if (!hnd) + { + COMPlusThrowOM(); + } + + return hnd; } OBJECTHANDLE CreateHandle(OBJECTREF object) @@ -1319,7 +1324,7 @@ public: { CONTRACTL { - THROWS; + NOTHROW; GC_NOTRIGGER; MODE_COOPERATIVE; } @@ -1339,14 +1344,19 @@ public: { CONTRACTL { - THROWS; + NOTHROW; GC_NOTRIGGER; MODE_COOPERATIVE; } CONTRACTL_END; - IGCHandleTable *pHandleTable = GCHandleTableUtilities::GetGCHandleTable(); - return pHandleTable->CreateDependentHandle(m_handleStore, OBJECTREFToObject(primary), OBJECTREFToObject(secondary)); + OBJECTHANDLE hnd = m_handleStore->CreateDependentHandle(OBJECTREFToObject(primary), OBJECTREFToObject(secondary)); + if (!hnd) + { + COMPlusThrowOM(); + } + + return hnd; } #endif // DACCESS_COMPILE && !CROSSGEN_COMPILE @@ -1402,7 +1412,7 @@ protected: CLRPrivBinderCoreCLR *m_pTPABinderContext; // Reference to the binding context that holds TPA list details - void* m_handleStore; + IGCHandleStore* m_handleStore; // The large heap handle table. LargeHeapHandleTable *m_pLargeHeapHandleTable; diff --git a/src/vm/argdestination.h b/src/vm/argdestination.h index 8a3fb4fdf2..8ab0a5664b 100644 --- a/src/vm/argdestination.h +++ b/src/vm/argdestination.h @@ -30,6 +30,9 @@ public: LIMITED_METHOD_CONTRACT; #if defined(UNIX_AMD64_ABI) && defined(FEATURE_UNIX_AMD64_STRUCT_PASSING) _ASSERTE((argLocDescForStructInRegs != NULL) || (offset != TransitionBlock::StructInRegsOffset)); +#elif defined(_TARGET_ARM64_) + // This assert is not interesting on arm64. argLocDescForStructInRegs could be + // initialized if the args are being enregistered. #else _ASSERTE(argLocDescForStructInRegs == NULL); #endif @@ -42,6 +45,46 @@ public: return dac_cast<PTR_VOID>(dac_cast<TADDR>(m_base) + m_offset); } +#if defined(_TARGET_ARM64_) +#ifndef DACCESS_COMPILE + + // Returns true if the ArgDestination represents an HFA struct + bool IsHFA() + { + return m_argLocDescForStructInRegs != NULL; + } + + // Copy struct argument into registers described by the current ArgDestination. + // Arguments: + // src = source data of the structure + // fieldBytes - size of the structure + void CopyHFAStructToRegister(void *src, int fieldBytes) + { + // We are either copying either a float or double HFA and need to + // enregister each field. + + int floatRegCount = m_argLocDescForStructInRegs->m_cFloatReg; + bool typeFloat = m_argLocDescForStructInRegs->m_isSinglePrecision; + void* dest = this->GetDestinationAddress(); + + if (typeFloat) + { + for (int i = 0; i < floatRegCount; ++i) + { + // Copy 4 bytes on 8 bytes alignment + *((UINT64*)dest + i) = *((UINT32*)src + i); + } + } + else + { + // We can just do a memcpy. + memcpyNoGCRefs(dest, src, fieldBytes); + } + } + +#endif // !DACCESS_COMPILE +#endif // defined(_TARGET_ARM64_) + #if defined(UNIX_AMD64_ABI) && defined(FEATURE_UNIX_AMD64_STRUCT_PASSING) // Returns true if the ArgDestination represents a struct passed in registers. diff --git a/src/vm/arm64/asmconstants.h b/src/vm/arm64/asmconstants.h index b0300ca324..12b72f9249 100644 --- a/src/vm/arm64/asmconstants.h +++ b/src/vm/arm64/asmconstants.h @@ -167,5 +167,11 @@ ASMCONSTANTS_C_ASSERT(ResolveCacheElem__target == offsetof(ResolveCacheElem, tar ASMCONSTANTS_C_ASSERT(ResolveCacheElem__pNext == offsetof(ResolveCacheElem, pNext)); #endif // CROSSGEN_COMPILE +#define DomainLocalModule__m_pDataBlob 0x30 +#define DomainLocalModule__m_pGCStatics 0x20 +ASMCONSTANTS_C_ASSERT(DomainLocalModule__m_pDataBlob == offsetof(DomainLocalModule, m_pDataBlob)); +ASMCONSTANTS_C_ASSERT(DomainLocalModule__m_pGCStatics == offsetof(DomainLocalModule, m_pGCStatics)); + + #undef ASMCONSTANTS_RUNTIME_ASSERT #undef ASMCONSTANTS_C_ASSERT diff --git a/src/vm/arm64/asmhelpers.S b/src/vm/arm64/asmhelpers.S index ef6b5cfffe..15b8057ed6 100644 --- a/src/vm/arm64/asmhelpers.S +++ b/src/vm/arm64/asmhelpers.S @@ -1192,9 +1192,9 @@ NESTED_END StubDispatchFixupStub, _TEXT // On exit: // buffer pointed to by x1 on entry contains the float or double argument as appropriate // - LEAF_ENTRY getFPReturn +LEAF_ENTRY getFPReturn, _TEXT str d0, [x1] - LEAF_END +LEAF_END getFPReturn, _TEXT // ------------------------------------------------------------------ // Function used by COM interop to set floating point return value (since it's not in the same @@ -1208,7 +1208,64 @@ NESTED_END StubDispatchFixupStub, _TEXT // s0 : float result if x0 == 4 // d0 : double result if x0 == 8 // - LEAF_ENTRY setFPReturn +LEAF_ENTRY setFPReturn, _TEXT fmov d0, x1 - LEAF_END +LEAF_END setFPReturn, _TEXT #endif + +// +// JIT Static access helpers when coreclr host specifies single appdomain flag +// + +// ------------------------------------------------------------------ +// void* JIT_GetSharedNonGCStaticBase(SIZE_T moduleDomainID, DWORD dwClassDomainID) + +LEAF_ENTRY JIT_GetSharedNonGCStaticBase_SingleAppDomain, _TEXT + // If class is not initialized, bail to C++ helper + add x2, x0, #DomainLocalModule__m_pDataBlob + ldrb w2, [x2, w1, UXTW] + tst w2, #1 + beq LOCAL_LABEL(JIT_GetSharedNonGCStaticBase_SingleAppDomain_CallHelper) + + ret lr + +LOCAL_LABEL(JIT_GetSharedNonGCStaticBase_SingleAppDomain_CallHelper): + // Tail call JIT_GetSharedNonGCStaticBase_Helper + b C_FUNC(JIT_GetSharedNonGCStaticBase_Helper) +LEAF_END JIT_GetSharedNonGCStaticBase_SingleAppDomain, _TEXT + + +// ------------------------------------------------------------------ +// void* JIT_GetSharedNonGCStaticBaseNoCtor(SIZE_T moduleDomainID, DWORD dwClassDomainID) + +LEAF_ENTRY JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain, _TEXT + ret lr +LEAF_END JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain, _TEXT + + +// ------------------------------------------------------------------ +// void* JIT_GetSharedGCStaticBase(SIZE_T moduleDomainID, DWORD dwClassDomainID) + +LEAF_ENTRY JIT_GetSharedGCStaticBase_SingleAppDomain, _TEXT + // If class is not initialized, bail to C++ helper + add x2, x0, #DomainLocalModule__m_pDataBlob + ldrb w2, [x2, w1, UXTW] + tst w2, #1 + beq LOCAL_LABEL(JIT_GetSharedGCStaticBase_SingleAppDomain_CallHelper) + + ldr x0, [x0, #DomainLocalModule__m_pGCStatics] + ret lr + +LOCAL_LABEL(JIT_GetSharedGCStaticBase_SingleAppDomain_CallHelper): + // Tail call Jit_GetSharedGCStaticBase_Helper + b C_FUNC(JIT_GetSharedGCStaticBase_Helper) +LEAF_END JIT_GetSharedGCStaticBase_SingleAppDomain, _TEXT + + +// ------------------------------------------------------------------ +// void* JIT_GetSharedGCStaticBaseNoCtor(SIZE_T moduleDomainID, DWORD dwClassDomainID) + +LEAF_ENTRY JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain, _TEXT + ldr x0, [x0, #DomainLocalModule__m_pGCStatics] + ret lr +LEAF_END JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain, _TEXT diff --git a/src/vm/arm64/asmhelpers.asm b/src/vm/arm64/asmhelpers.asm index e8b16ded6a..24b26eb1c9 100644 --- a/src/vm/arm64/asmhelpers.asm +++ b/src/vm/arm64/asmhelpers.asm @@ -52,6 +52,9 @@ IMPORT $g_GCShadowEnd #endif // WRITE_BARRIER_CHECK + IMPORT JIT_GetSharedNonGCStaticBase_Helper + IMPORT JIT_GetSharedGCStaticBase_Helper + TEXTAREA ;; LPVOID __stdcall GetCurrentIP(void); @@ -1326,5 +1329,62 @@ Fail LEAF_END #endif +; +; JIT Static access helpers when coreclr host specifies single appdomain flag +; + +; ------------------------------------------------------------------ +; void* JIT_GetSharedNonGCStaticBase(SIZE_T moduleDomainID, DWORD dwClassDomainID) + + LEAF_ENTRY JIT_GetSharedNonGCStaticBase_SingleAppDomain + ; If class is not initialized, bail to C++ helper + add x2, x0, #DomainLocalModule__m_pDataBlob + ldrb w2, [x2, w1] + tst w2, #1 + beq CallHelper1 + + ret lr + +CallHelper1 + ; Tail call JIT_GetSharedNonGCStaticBase_Helper + b JIT_GetSharedNonGCStaticBase_Helper + LEAF_END + + +; ------------------------------------------------------------------ +; void* JIT_GetSharedNonGCStaticBaseNoCtor(SIZE_T moduleDomainID, DWORD dwClassDomainID) + + LEAF_ENTRY JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain + ret lr + LEAF_END + + +; ------------------------------------------------------------------ +; void* JIT_GetSharedGCStaticBase(SIZE_T moduleDomainID, DWORD dwClassDomainID) + + LEAF_ENTRY JIT_GetSharedGCStaticBase_SingleAppDomain + ; If class is not initialized, bail to C++ helper + add x2, x0, #DomainLocalModule__m_pDataBlob + ldrb w2, [x2, w1] + tst w2, #1 + beq CallHelper2 + + ldr x0, [x0, #DomainLocalModule__m_pGCStatics] + ret lr + +CallHelper2 + ; Tail call Jit_GetSharedGCStaticBase_Helper + b JIT_GetSharedGCStaticBase_Helper + LEAF_END + + +; ------------------------------------------------------------------ +; void* JIT_GetSharedGCStaticBaseNoCtor(SIZE_T moduleDomainID, DWORD dwClassDomainID) + + LEAF_ENTRY JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain + ldr x0, [x0, #DomainLocalModule__m_pGCStatics] + ret lr + LEAF_END + ; Must be at very end of file END diff --git a/src/vm/arm64/stubs.cpp b/src/vm/arm64/stubs.cpp index f56f6ab625..0c7eb4dfba 100644 --- a/src/vm/arm64/stubs.cpp +++ b/src/vm/arm64/stubs.cpp @@ -15,6 +15,11 @@ #include "virtualcallstub.h" #include "jitinterface.h" +EXTERN_C void JIT_GetSharedNonGCStaticBase_SingleAppDomain(); +EXTERN_C void JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain(); +EXTERN_C void JIT_GetSharedGCStaticBase_SingleAppDomain(); +EXTERN_C void JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain(); + #ifndef DACCESS_COMPILE //----------------------------------------------------------------------- // InstructionFormat for B.cond @@ -1078,10 +1083,18 @@ void JIT_TailCall() _ASSERTE(!"ARM64:NYI"); } +#if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE) void InitJITHelpers1() { - return; + if(IsSingleAppDomain()) + { + SetJitHelperFunction(CORINFO_HELP_GETSHARED_GCSTATIC_BASE, JIT_GetSharedGCStaticBase_SingleAppDomain); + SetJitHelperFunction(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE, JIT_GetSharedNonGCStaticBase_SingleAppDomain); + SetJitHelperFunction(CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR, JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain); + SetJitHelperFunction(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR,JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain); + } } +#endif // !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE) EXTERN_C void __stdcall ProfileEnterNaked(UINT_PTR clientData) { diff --git a/src/vm/assembly.cpp b/src/vm/assembly.cpp index 75430644c3..92c1ebd817 100644 --- a/src/vm/assembly.cpp +++ b/src/vm/assembly.cpp @@ -1849,10 +1849,7 @@ HRESULT RunMain(MethodDesc *pFD , else { *pParam->piRetVal = (INT32)threadStart.Call_RetArgSlot(&stackVar); - if (pParam->stringArgs == NULL) - { - SetLatchedExitCode(*pParam->piRetVal); - } + SetLatchedExitCode(*pParam->piRetVal); } GCPROTECT_END(); diff --git a/src/vm/callingconvention.h b/src/vm/callingconvention.h index cde2ba465a..b707b4bc8c 100644 --- a/src/vm/callingconvention.h +++ b/src/vm/callingconvention.h @@ -34,21 +34,26 @@ BOOL IsRetBuffPassedAsFirstArg(); // and possibly on to the stack as well. struct ArgLocDesc { - int m_idxFloatReg; // First floating point register used (or -1) - int m_cFloatReg; // Count of floating point registers used (or 0) + int m_idxFloatReg; // First floating point register used (or -1) + int m_cFloatReg; // Count of floating point registers used (or 0) - int m_idxGenReg; // First general register used (or -1) - int m_cGenReg; // Count of general registers used (or 0) + int m_idxGenReg; // First general register used (or -1) + int m_cGenReg; // Count of general registers used (or 0) - int m_idxStack; // First stack slot used (or -1) - int m_cStack; // Count of stack slots used (or 0) + int m_idxStack; // First stack slot used (or -1) + int m_cStack; // Count of stack slots used (or 0) #if defined(UNIX_AMD64_ABI) && defined(FEATURE_UNIX_AMD64_STRUCT_PASSING) - EEClass* m_eeClass; // For structs passed in register, it points to the EEClass of the struct + EEClass* m_eeClass; // For structs passed in register, it points to the EEClass of the struct #endif // UNIX_AMD64_ABI && FEATURE_UNIX_AMD64_STRUCT_PASSING +#if defined(_TARGET_ARM64_) + bool m_isSinglePrecision; // For determining if HFA is single or double + // precision +#endif // defined(_TARGET_ARM64_) + #if defined(_TARGET_ARM_) BOOL m_fRequires64BitAlignment; // True if the argument should always be aligned (in registers or on the stack #endif @@ -70,6 +75,9 @@ struct ArgLocDesc #if defined(_TARGET_ARM_) m_fRequires64BitAlignment = FALSE; #endif +#if defined(_TARGET_ARM64_) + m_isSinglePrecision = FALSE; +#endif // defined(_TARGET_ARM64_) #if defined(UNIX_AMD64_ABI) && defined(FEATURE_UNIX_AMD64_STRUCT_PASSING) m_eeClass = NULL; #endif @@ -490,7 +498,7 @@ public: ArgLocDesc* GetArgLocDescForStructInRegs() { -#if defined(UNIX_AMD64_ABI) && defined(FEATURE_UNIX_AMD64_STRUCT_PASSING) +#if (defined(UNIX_AMD64_ABI) && defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)) || defined (_TARGET_ARM64_) return m_hasArgLocDescForStructInRegs ? &m_argLocDescForStructInRegs : NULL; #else return NULL; @@ -556,7 +564,10 @@ public: if (!m_argTypeHandle.IsNull() && m_argTypeHandle.IsHFA()) { CorElementType type = m_argTypeHandle.GetHFAType(); - pLoc->m_cFloatReg = (type == ELEMENT_TYPE_R4)? GetArgSize()/sizeof(float): GetArgSize()/sizeof(double); + bool isFloatType = (type == ELEMENT_TYPE_R4); + + pLoc->m_cFloatReg = isFloatType ? GetArgSize()/sizeof(float): GetArgSize()/sizeof(double); + pLoc->m_isSinglePrecision = isFloatType; } else { @@ -639,7 +650,7 @@ protected: CorElementType m_argType; int m_argSize; TypeHandle m_argTypeHandle; -#if defined(_TARGET_AMD64_) && defined(UNIX_AMD64_ABI) && defined(FEATURE_UNIX_AMD64_STRUCT_PASSING) +#if (defined(_TARGET_AMD64_) && defined(UNIX_AMD64_ABI) && defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)) || defined(_TARGET_ARM64_) ArgLocDesc m_argLocDescForStructInRegs; bool m_hasArgLocDescForStructInRegs; #endif // _TARGET_AMD64_ && UNIX_AMD64_ABI && FEATURE_UNIX_AMD64_STRUCT_PASSING @@ -1103,7 +1114,9 @@ int ArgIteratorTemplate<ARGITERATOR_BASE>::GetNextOffset() // Handle HFAs: packed structures of 1-4 floats or doubles that are passed in FP argument // registers if possible. if (thValueType.IsHFA()) + { fFloatingPoint = true; + } #endif break; @@ -1255,7 +1268,17 @@ int ArgIteratorTemplate<ARGITERATOR_BASE>::GetNextOffset() if (thValueType.IsHFA()) { CorElementType type = thValueType.GetHFAType(); + bool isFloatType = (type == ELEMENT_TYPE_R4); + cFPRegs = (type == ELEMENT_TYPE_R4)? (argSize/sizeof(float)): (argSize/sizeof(double)); + + m_argLocDescForStructInRegs.Init(); + m_argLocDescForStructInRegs.m_cFloatReg = cFPRegs; + m_argLocDescForStructInRegs.m_idxFloatReg = m_idxFPReg; + + m_argLocDescForStructInRegs.m_isSinglePrecision = isFloatType; + + m_hasArgLocDescForStructInRegs = true; } else { diff --git a/src/vm/ceemain.cpp b/src/vm/ceemain.cpp index 6b0c0dfbba..9cce46d2f0 100644 --- a/src/vm/ceemain.cpp +++ b/src/vm/ceemain.cpp @@ -869,7 +869,7 @@ void EEStartupHelper(COINITIEE fFlags) // Initialize remoting - if (!GCHandleTableUtilities::GetGCHandleTable()->Initialize()) + if (!GCHandleUtilities::GetGCHandleManager()->Initialize()) { IfFailGo(E_OUTOFMEMORY); } @@ -1880,7 +1880,7 @@ part2: #ifdef SHOULD_WE_CLEANUP if (!g_fFastExitProcess) { - GCHandleTableUtilities::GetGCHandleTable()->Shutdown(); + GCHandleUtilities::GetGCHandleManager()->Shutdown(); } #endif /* SHOULD_WE_CLEANUP */ @@ -2386,7 +2386,7 @@ BOOL CanRunManagedCode(LoaderLockCheck::kind checkKind, HINSTANCE hInst /*= 0*/) // no longer maintains a ref count since the EE doesn't support being // unloaded and re-loaded. It simply ensures the EE has been started. // --------------------------------------------------------------------------- -HRESULT STDMETHODCALLTYPE CoInitializeEE(DWORD fFlags) +HRESULT STDAPICALLTYPE CoInitializeEE(DWORD fFlags) { CONTRACTL { @@ -2417,7 +2417,7 @@ HRESULT STDMETHODCALLTYPE CoInitializeEE(DWORD fFlags) // Description: // Must be called by client on shut down in order to free up the system. // --------------------------------------------------------------------------- -void STDMETHODCALLTYPE CoUninitializeEE(BOOL fIsDllUnloading) +void STDAPICALLTYPE CoUninitializeEE(BOOL fIsDllUnloading) { LIMITED_METHOD_CONTRACT; //BEGIN_ENTRYPOINT_VOIDRET; @@ -2483,17 +2483,17 @@ void InitializeGarbageCollector() IGCToCLR* gcToClr = nullptr; #endif - IGCHandleTable *pGcHandleTable; + IGCHandleManager *pGcHandleManager; IGCHeap *pGCHeap; - if (!InitializeGarbageCollector(gcToClr, &pGCHeap, &pGcHandleTable, &g_gc_dac_vars)) + if (!InitializeGarbageCollector(gcToClr, &pGCHeap, &pGcHandleManager, &g_gc_dac_vars)) { ThrowOutOfMemory(); } assert(pGCHeap != nullptr); g_pGCHeap = pGCHeap; - g_pGCHandleTable = pGcHandleTable; + g_pGCHandleManager = pGcHandleManager; g_gcDacGlobals = &g_gc_dac_vars; // Apparently the Windows linker removes global variables if they are never diff --git a/src/vm/codeman.cpp b/src/vm/codeman.cpp index 73b4c06565..a30e70e7fa 100644 --- a/src/vm/codeman.cpp +++ b/src/vm/codeman.cpp @@ -3177,8 +3177,8 @@ void EEJitManager::RemoveJitData (CodeHeader * pCHdr, size_t GCinfo_len, size_t LCGMethodResolver * pResolver = pMD->AsDynamicMethodDesc()->GetLCGMethodResolver(); - // Clear the pointer only if it matches what we are about to free. There may be cases where the JIT is reentered and - // the method JITed multiple times. + // Clear the pointer only if it matches what we are about to free. + // There can be cases where the JIT is reentered and we JITed the method multiple times. if (pResolver->m_recordCodePointer == codeStart) pResolver->m_recordCodePointer = NULL; } @@ -4885,7 +4885,7 @@ void ExecutionManager::Unload(LoaderAllocator *pLoaderAllocator) */ StackwalkCache::Invalidate(pLoaderAllocator); - JumpStubCache * pJumpStubCache = (JumpStubCache *)pLoaderAllocator->m_pJumpStubCache; + JumpStubCache * pJumpStubCache = (JumpStubCache *) pLoaderAllocator->m_pJumpStubCache; if (pJumpStubCache != NULL) { delete pJumpStubCache; @@ -4954,18 +4954,33 @@ PCODE ExecutionManager::jumpStub(MethodDesc* pMD, PCODE target, PCODE jumpStub = NULL; if (pLoaderAllocator == NULL) + { pLoaderAllocator = pMD->GetLoaderAllocatorForCode(); + } _ASSERTE(pLoaderAllocator != NULL); - bool isLCG = pMD && pMD->IsLCGMethod(); + bool isLCG = pMD && pMD->IsLCGMethod(); + LCGMethodResolver * pResolver = nullptr; + JumpStubCache * pJumpStubCache = (JumpStubCache *) pLoaderAllocator->m_pJumpStubCache; - CrstHolder ch(&m_JumpStubCrst); + if (isLCG) + { + pResolver = pMD->AsDynamicMethodDesc()->GetLCGMethodResolver(); + pJumpStubCache = pResolver->m_pJumpStubCache; + } - JumpStubCache * pJumpStubCache = (JumpStubCache *)pLoaderAllocator->m_pJumpStubCache; + CrstHolder ch(&m_JumpStubCrst); if (pJumpStubCache == NULL) { pJumpStubCache = new JumpStubCache(); - pLoaderAllocator->m_pJumpStubCache = pJumpStubCache; + if (isLCG) + { + pResolver->m_pJumpStubCache = pJumpStubCache; + } + else + { + pLoaderAllocator->m_pJumpStubCache = pJumpStubCache; + } } if (isLCG) @@ -5018,9 +5033,19 @@ PCODE ExecutionManager::getNextJumpStub(MethodDesc* pMD, PCODE target, POSTCONDITION(RETVAL != NULL); } CONTRACT_END; - BYTE * jumpStub = NULL; - bool isLCG = pMD && pMD->IsLCGMethod(); - JumpStubBlockHeader ** ppHead = isLCG ? &(pMD->AsDynamicMethodDesc()->GetLCGMethodResolver()->m_jumpStubBlock) : &(((JumpStubCache *)(pLoaderAllocator->m_pJumpStubCache))->m_pBlocks); + DWORD numJumpStubs = DEFAULT_JUMPSTUBS_PER_BLOCK; // a block of 32 JumpStubs + BYTE * jumpStub = NULL; + bool isLCG = pMD && pMD->IsLCGMethod(); + JumpStubCache * pJumpStubCache = (JumpStubCache *) pLoaderAllocator->m_pJumpStubCache; + + if (isLCG) + { + LCGMethodResolver * pResolver; + pResolver = pMD->AsDynamicMethodDesc()->GetLCGMethodResolver(); + pJumpStubCache = pResolver->m_pJumpStubCache; + } + + JumpStubBlockHeader ** ppHead = &(pJumpStubCache->m_pBlocks); JumpStubBlockHeader * curBlock = *ppHead; // allocate a new jumpstub from 'curBlock' if it is not fully allocated @@ -5039,7 +5064,6 @@ PCODE ExecutionManager::getNextJumpStub(MethodDesc* pMD, PCODE target, goto DONE; } } - curBlock = curBlock->m_next; } @@ -5047,6 +5071,24 @@ PCODE ExecutionManager::getNextJumpStub(MethodDesc* pMD, PCODE target, if (isLCG) { + // For LCG we request a small block of 4 jumpstubs, because we can not share them + // with any other methods and very frequently our method only needs one jump stub. + // Using 4 gives a request size of (32 + 4*12) or 80 bytes. + // Also note that request sizes are rounded up to a multiples of 16. + // The request size is calculated into 'blockSize' in allocJumpStubBlock. + // For x64 the value of BACK_TO_BACK_JUMP_ALLOCATE_SIZE is 12 bytes + // and the sizeof(JumpStubBlockHeader) is 32. + // + + numJumpStubs = 4; + +#ifdef _TARGET_AMD64_ + // Note this these values are not requirements, instead we are + // just confirming the values that are mentioned in the comments. + _ASSERTE(BACK_TO_BACK_JUMP_ALLOCATE_SIZE == 12); + _ASSERTE(sizeof(JumpStubBlockHeader) == 32); +#endif + // Increment counter of LCG jump stub block allocations m_LCG_JumpStubBlockAllocCount++; } @@ -5056,9 +5098,12 @@ PCODE ExecutionManager::getNextJumpStub(MethodDesc* pMD, PCODE target, m_normal_JumpStubBlockAllocCount++; } - // allocJumpStubBlock will allocate from the LoaderCodeHeap for normal methods and HostCodeHeap for LCG methods - // this can throw an OM exception - curBlock = ExecutionManager::GetEEJitManager()->allocJumpStubBlock(pMD, DEFAULT_JUMPSTUBS_PER_BLOCK, loAddr, hiAddr, pLoaderAllocator); + // allocJumpStubBlock will allocate from the LoaderCodeHeap for normal methods + // and will alocate from a HostCodeHeap for LCG methods. + // + // note that this can throw an OOM exception + + curBlock = ExecutionManager::GetEEJitManager()->allocJumpStubBlock(pMD, numJumpStubs, loAddr, hiAddr, pLoaderAllocator); jumpStub = (BYTE *) curBlock + sizeof(JumpStubBlockHeader) + ((size_t) curBlock->m_used * BACK_TO_BACK_JUMP_ALLOCATE_SIZE); @@ -5078,25 +5123,16 @@ DONE: emitBackToBackJump(jumpStub, (void*) target); - if (isLCG) - { - // always get a new jump stub for LCG method - // We don't share jump stubs among different LCG methods so that the jump stubs used - // by every LCG method can be cleaned up individually - // There is not much benefit to share jump stubs within one LCG method anyway. - } - else - { - JumpStubCache * pJumpStubCache = (JumpStubCache *)pLoaderAllocator->m_pJumpStubCache; - _ASSERTE(pJumpStubCache != NULL); + // We always add the new jumpstub to the jumpStubCache + // + _ASSERTE(pJumpStubCache != NULL); - JumpStubEntry entry; + JumpStubEntry entry; - entry.m_target = target; - entry.m_jumpStub = (PCODE)jumpStub; + entry.m_target = target; + entry.m_jumpStub = (PCODE)jumpStub; - pJumpStubCache->m_Table.Add(entry); - } + pJumpStubCache->m_Table.Add(entry); curBlock->m_used++; // record that we have used up one more jumpStub in the block @@ -5556,9 +5592,9 @@ BOOL NativeImageJitManager::JitCodeToMethodInfo(RangeSection * pRangeSection, g_IBCLogger.LogMethodCodeAccess(*ppMethodDesc); } - //Get the function entry that corresponds to the real method desc. + // Get the function entry that corresponds to the real method desc. _ASSERTE((RelativePc >= RUNTIME_FUNCTION__BeginAddress(FunctionEntry))); - + if (pCodeInfo) { pCodeInfo->m_relOffset = (DWORD) diff --git a/src/vm/codeman.h b/src/vm/codeman.h index 5fbddea875..9d7ed4d62f 100644 --- a/src/vm/codeman.h +++ b/src/vm/codeman.h @@ -1490,6 +1490,7 @@ private: static unsigned m_LCG_JumpStubBlockAllocCount; static unsigned m_LCG_JumpStubBlockFullCount; +public: struct JumpStubCache { JumpStubCache() diff --git a/src/vm/compile.cpp b/src/vm/compile.cpp index 09925cd219..91615851c7 100644 --- a/src/vm/compile.cpp +++ b/src/vm/compile.cpp @@ -3140,8 +3140,8 @@ HRESULT NGenModulePdbWriter::WritePDBData() SString dllPath = pLoadedLayout->GetPath(); if (!dllPath.EndsWithCaseInsensitive(L".ni.dll") && !dllPath.EndsWithCaseInsensitive(L".ni.exe")) { - SString::Iterator fileNameStart = dllPath.Begin(); - dllPath.FindBack(fileNameStart, '\\'); + SString::Iterator fileNameStart = dllPath.End(); + dllPath.FindBack(fileNameStart, DIRECTORY_SEPARATOR_STR_W); SString::Iterator ext = dllPath.End(); dllPath.FindBack(ext, '.'); diff --git a/src/vm/corhost.cpp b/src/vm/corhost.cpp index 75adbada94..fd27a7a4e7 100644 --- a/src/vm/corhost.cpp +++ b/src/vm/corhost.cpp @@ -75,7 +75,7 @@ SVAL_IMPL_INIT(ECustomDumpFlavor, CCLRErrorReportingManager, g_ECustomDumpFlavor #ifndef DACCESS_COMPILE extern void STDMETHODCALLTYPE EEShutDown(BOOL fIsDllUnloading); -extern HRESULT STDMETHODCALLTYPE CoInitializeEE(DWORD fFlags); +extern HRESULT STDAPICALLTYPE CoInitializeEE(DWORD fFlags); extern void PrintToStdOutA(const char *pszString); extern void PrintToStdOutW(const WCHAR *pwzString); extern BOOL g_fEEHostedStartup; @@ -1201,6 +1201,11 @@ HRESULT GetCLRRuntimeHost(REFIID riid, IUnknown **ppUnk) STDMETHODIMP CorHost2::UnloadAppDomain(DWORD dwDomainId, BOOL fWaitUntilDone) { + return UnloadAppDomain2(dwDomainId, fWaitUntilDone, nullptr); +} + +STDMETHODIMP CorHost2::UnloadAppDomain2(DWORD dwDomainId, BOOL fWaitUntilDone, int *pLatchedExitCode) +{ WRAPPER_NO_CONTRACT; STATIC_CONTRACT_SO_TOLERANT; @@ -1249,14 +1254,23 @@ STDMETHODIMP CorHost2::UnloadAppDomain(DWORD dwDomainId, BOOL fWaitUntilDone) } END_ENTRYPOINT_NOTHROW; + if (pLatchedExitCode) + { + *pLatchedExitCode = GetLatchedExitCode(); + } + return hr; } - else - return CorRuntimeHostBase::UnloadAppDomain(dwDomainId, fWaitUntilDone); + return CorRuntimeHostBase::UnloadAppDomain2(dwDomainId, fWaitUntilDone, pLatchedExitCode); } -HRESULT CorRuntimeHostBase::UnloadAppDomain(DWORD dwDomainId, BOOL fSync) +HRESULT CorRuntimeHostBase::UnloadAppDomain(DWORD dwDomainId, BOOL fWaitUntilDone) +{ + return UnloadAppDomain2(dwDomainId, fWaitUntilDone, nullptr); +} + +HRESULT CorRuntimeHostBase::UnloadAppDomain2(DWORD dwDomainId, BOOL fWaitUntilDone, int *pLatchedExitCode) { CONTRACTL { @@ -1282,7 +1296,7 @@ HRESULT CorRuntimeHostBase::UnloadAppDomain(DWORD dwDomainId, BOOL fSync) // // However, for a thread that holds the loader lock, unloading the appDomain is // not a supported scenario. Thus, we should not be ending up in this code - // path for the FAULT violation. + // path for the FAULT violation. // // Hence, the CONTRACT_VIOLATION below for overriding the FORBID_FAULT // for this scope only. @@ -1292,18 +1306,23 @@ HRESULT CorRuntimeHostBase::UnloadAppDomain(DWORD dwDomainId, BOOL fSync) ) { return HOST_E_CLRNOTAVAILABLE; - } + } } - + BEGIN_ENTRYPOINT_NOTHROW; // We do not use BEGIN_EXTERNAL_ENTRYPOINT here because // we do not want to setup Thread. Process may be OOM, and we want Unload // to work. - hr = AppDomain::UnloadById(ADID(dwDomainId), fSync); + hr = AppDomain::UnloadById(ADID(dwDomainId), fWaitUntilDone); END_ENTRYPOINT_NOTHROW; + if (pLatchedExitCode) + { + *pLatchedExitCode = GetLatchedExitCode(); + } + return hr; } @@ -1404,6 +1423,14 @@ HRESULT CorHost2::QueryInterface(REFIID riid, void **ppUnk) *ppUnk = static_cast<ICLRRuntimeHost2 *>(this); } + else if (riid == IID_ICLRRuntimeHost4) + { + ULONG version = 4; + if (m_Version == 0) + FastInterlockCompareExchange((LONG*)&m_Version, version, 0); + + *ppUnk = static_cast<ICLRRuntimeHost4 *>(this); + } else if (riid == IID_ICLRExecutionManager) { ULONG version = 2; diff --git a/src/vm/dynamicmethod.cpp b/src/vm/dynamicmethod.cpp index 3eec125247..2a61f97afd 100644 --- a/src/vm/dynamicmethod.cpp +++ b/src/vm/dynamicmethod.cpp @@ -917,7 +917,7 @@ void LCGMethodResolver::Reset() m_DynamicStringLiterals = NULL; m_recordCodePointer = NULL; m_UsedIndCellList = NULL; - m_jumpStubBlock = NULL; + m_pJumpStubCache = NULL; m_next = NULL; m_Code = NULL; } @@ -1035,19 +1035,24 @@ void LCGMethodResolver::Destroy(BOOL fDomainUnload) m_recordCodePointer = NULL; } - JumpStubBlockHeader* current = m_jumpStubBlock; - JumpStubBlockHeader* next; - while (current) + if (m_pJumpStubCache != NULL) { - next = current->m_next; + JumpStubBlockHeader* current = m_pJumpStubCache->m_pBlocks; + while (current) + { + JumpStubBlockHeader* next = current->m_next; + + HostCodeHeap *pHeap = current->GetHostCodeHeap(); + LOG((LF_BCL, LL_INFO1000, "Level3 - Resolver {0x%p} - Release reference to heap {%p, vt(0x%x)} \n", current, pHeap, *(size_t*)pHeap)); + pHeap->m_pJitManager->FreeCodeMemory(pHeap, current); - HostCodeHeap *pHeap = current->GetHostCodeHeap(); - LOG((LF_BCL, LL_INFO1000, "Level3 - Resolver {0x%p} - Release reference to heap {%p, vt(0x%x)} \n", current, pHeap, *(size_t*)pHeap)); - pHeap->m_pJitManager->FreeCodeMemory(pHeap, current); + current = next; + } + m_pJumpStubCache->m_pBlocks = NULL; - current = next; + delete m_pJumpStubCache; + m_pJumpStubCache = NULL; } - m_jumpStubBlock = NULL; if (m_managedResolver) { diff --git a/src/vm/dynamicmethod.h b/src/vm/dynamicmethod.h index a96200ba4f..f9a92b0af0 100644 --- a/src/vm/dynamicmethod.h +++ b/src/vm/dynamicmethod.h @@ -107,6 +107,7 @@ class LCGMethodResolver : public DynamicResolver friend class ExecutionManager; friend class EEJitManager; friend class HostCodeHeap; + friend struct ExecutionManager::JumpStubCache; public: void Destroy(BOOL fDomainUnload = FALSE); @@ -162,7 +163,7 @@ private: ChunkAllocator m_jitTempData; DynamicStringLiteral* m_DynamicStringLiterals; IndCellList * m_UsedIndCellList; // list to keep track of all the indirection cells used by the jitted code - JumpStubBlockHeader* m_jumpStubBlock; + ExecutionManager::JumpStubCache * m_pJumpStubCache; }; // class LCGMethodResolver //--------------------------------------------------------------------------------------- diff --git a/src/vm/ecalllist.h b/src/vm/ecalllist.h index 6ed29b8611..5c3e5f82ba 100644 --- a/src/vm/ecalllist.h +++ b/src/vm/ecalllist.h @@ -946,6 +946,7 @@ FCFuncStart(gInteropMarshalFuncs) FCFuncElement("DestroyStructure", MarshalNative::DestroyStructure) FCFuncElement("UnsafeAddrOfPinnedArrayElement", MarshalNative::FCUnsafeAddrOfPinnedArrayElement) FCFuncElement("GetExceptionCode", ExceptionNative::GetExceptionCode) + FCFuncElement("GetExceptionPointers", ExceptionNative::GetExceptionPointers) QCFuncElement("GetHINSTANCE", COMModule::GetHINSTANCE) FCFuncElement("OffsetOfHelper", MarshalNative::OffsetOfHelper) diff --git a/src/vm/eetwain.cpp b/src/vm/eetwain.cpp index 2886daa8f6..4a02be7b82 100644 --- a/src/vm/eetwain.cpp +++ b/src/vm/eetwain.cpp @@ -4368,7 +4368,6 @@ bool EECodeManager::EnumGcRefs( PREGDISPLAY pContext, } } - bool willContinueExecution = !(flags & ExecutionAborted); unsigned pushedSize = 0; @@ -4663,60 +4662,69 @@ bool EECodeManager::EnumGcRefs( PREGDISPLAY pContext, /* Process the untracked frame variable table */ - count = info.untrackedCnt; - int lastStkOffs = 0; - while (count-- > 0) +#if defined(WIN64EXCEPTIONS) // funclets + // Filters are the only funclet that run during the 1st pass, and must have + // both the leaf and the parent frame reported. In order to avoid double + // reporting of the untracked variables, do not report them for the filter. + if (!pCodeInfo->GetJitManager()->IsFilterFunclet(pCodeInfo)) +#endif // WIN64EXCEPTIONS { - int stkOffs = fastDecodeSigned(table); - stkOffs = lastStkOffs - stkOffs; - lastStkOffs = stkOffs; - - _ASSERTE(0 == ~OFFSET_MASK % sizeof(void*)); - - lowBits = OFFSET_MASK & stkOffs; - stkOffs &= ~OFFSET_MASK; - - ptrAddr = argBase + stkOffs; - if (info.doubleAlign && stkOffs >= int(info.stackSize - sizeof(void*))) { - // We encode the arguments as if they were ESP based variables even though they aren't - // If this frame would have ben an ESP based frame, This fake frame is one DWORD - // smaller than the real frame because it did not push EBP but the real frame did. - // Thus to get the correct EBP relative offset we have to ajust by info.stackSize-sizeof(void*) - ptrAddr = EBP + (stkOffs-(info.stackSize - sizeof(void*))); - } + count = info.untrackedCnt; + int lastStkOffs = 0; + while (count-- > 0) + { + int stkOffs = fastDecodeSigned(table); + stkOffs = lastStkOffs - stkOffs; + lastStkOffs = stkOffs; + + _ASSERTE(0 == ~OFFSET_MASK % sizeof(void*)); + + lowBits = OFFSET_MASK & stkOffs; + stkOffs &= ~OFFSET_MASK; + + ptrAddr = argBase + stkOffs; + if (info.doubleAlign && stkOffs >= int(info.stackSize - sizeof(void*))) { + // We encode the arguments as if they were ESP based variables even though they aren't + // If this frame would have ben an ESP based frame, This fake frame is one DWORD + // smaller than the real frame because it did not push EBP but the real frame did. + // Thus to get the correct EBP relative offset we have to ajust by info.stackSize-sizeof(void*) + ptrAddr = EBP + (stkOffs-(info.stackSize - sizeof(void*))); + } #ifdef _DEBUG - if (dspPtr) - { - printf(" Untracked %s%s local at [E", - (lowBits & pinned_OFFSET_FLAG) ? "pinned " : "", - (lowBits & byref_OFFSET_FLAG) ? "byref" : ""); + if (dspPtr) + { + printf(" Untracked %s%s local at [E", + (lowBits & pinned_OFFSET_FLAG) ? "pinned " : "", + (lowBits & byref_OFFSET_FLAG) ? "byref" : ""); - int dspOffs = ptrAddr; - char frameType; + int dspOffs = ptrAddr; + char frameType; - if (info.ebpFrame) { - dspOffs -= EBP; - frameType = 'B'; - } - else { - dspOffs -= ESP; - frameType = 'S'; + if (info.ebpFrame) { + dspOffs -= EBP; + frameType = 'B'; + } + else { + dspOffs -= ESP; + frameType = 'S'; + } + + if (dspOffs < 0) + printf("%cP-%02XH]: ", frameType, -dspOffs); + else + printf("%cP+%02XH]: ", frameType, +dspOffs); } +#endif - if (dspOffs < 0) - printf("%cP-%02XH]: ", frameType, -dspOffs); - else - printf("%cP+%02XH]: ", frameType, +dspOffs); + _ASSERTE((pinned_OFFSET_FLAG == GC_CALL_PINNED) && + (byref_OFFSET_FLAG == GC_CALL_INTERIOR)); + pCallBack(hCallBack, (OBJECTREF*)(size_t)ptrAddr, lowBits | CHECK_APP_DOMAIN + DAC_ARG(DacSlotLocation(info.ebpFrame ? REGI_EBP : REGI_ESP, + info.ebpFrame ? EBP - ptrAddr : ptrAddr - ESP, + true))); } -#endif - _ASSERTE((pinned_OFFSET_FLAG == GC_CALL_PINNED) && - (byref_OFFSET_FLAG == GC_CALL_INTERIOR)); - pCallBack(hCallBack, (OBJECTREF*)(size_t)ptrAddr, lowBits | CHECK_APP_DOMAIN - DAC_ARG(DacSlotLocation(info.ebpFrame ? REGI_EBP : REGI_ESP, - info.ebpFrame ? EBP - ptrAddr : ptrAddr - ESP, - true))); } #if VERIFY_GC_TABLES diff --git a/src/vm/exceptionhandling.cpp b/src/vm/exceptionhandling.cpp index 31b85bdb0a..7030ef5e91 100644 --- a/src/vm/exceptionhandling.cpp +++ b/src/vm/exceptionhandling.cpp @@ -135,7 +135,7 @@ void FixContext(PCONTEXT pContextRecord) #ifdef _TARGET_X86_ size_t resumeSp = EECodeManager::GetResumeSp(pContextRecord); - FIXUPREG(ResumeEsp, resumeSp); + FIXUPREG(Esp, resumeSp); #endif // _TARGET_X86_ #undef FIXUPREG @@ -1011,6 +1011,10 @@ ProcessCLRException(IN PEXCEPTION_RECORD pExceptionRecord CEHelper::SetupCorruptionSeverityForActiveException((STState == ExceptionTracker::STS_FirstRethrowFrame), (pTracker->GetPreviousExceptionTracker() != NULL), CEHelper::ShouldTreatActiveExceptionAsNonCorrupting()); } + + // Failfast if exception indicates corrupted process state + if (pTracker->GetCorruptionSeverity() == ProcessCorrupting) + EEPOLICY_HANDLE_FATAL_ERROR(pExceptionRecord->ExceptionCode); } #endif // FEATURE_CORRUPTING_EXCEPTIONS @@ -1071,9 +1075,11 @@ ProcessCLRException(IN PEXCEPTION_RECORD pExceptionRecord CLRUnwindStatus status; +#ifdef USE_PER_FRAME_PINVOKE_INIT // Refer to comment in ProcessOSExceptionNotification about ICF and codegen difference. - ARM_ONLY(InlinedCallFrame *pICFSetAsLimitFrame = NULL;) - + InlinedCallFrame *pICFSetAsLimitFrame = NULL; +#endif // USE_PER_FRAME_PINVOKE_INIT + status = pTracker->ProcessOSExceptionNotification( pExceptionRecord, pContextRecord, @@ -1081,7 +1087,11 @@ ProcessCLRException(IN PEXCEPTION_RECORD pExceptionRecord dwExceptionFlags, sf, pThread, - STState ARM_ARG((PVOID)pICFSetAsLimitFrame)); + STState +#ifdef USE_PER_FRAME_PINVOKE_INIT + , (PVOID)pICFSetAsLimitFrame +#endif // USE_PER_FRAME_PINVOKE_INIT + ); if (FirstPassComplete == status) { @@ -1184,7 +1194,7 @@ ProcessCLRException(IN PEXCEPTION_RECORD pExceptionRecord CONSISTENCY_CHECK(pLimitFrame > dac_cast<PTR_VOID>(GetSP(pContextRecord))); -#if defined(_TARGET_ARM_) +#ifdef USE_PER_FRAME_PINVOKE_INIT if (pICFSetAsLimitFrame != NULL) { _ASSERTE(pICFSetAsLimitFrame == pLimitFrame); @@ -1196,7 +1206,7 @@ ProcessCLRException(IN PEXCEPTION_RECORD pExceptionRecord // the next pinvoke callsite does not see the frame as active. pICFSetAsLimitFrame->Reset(); } -#endif // defined(_TARGET_ARM_) +#endif // USE_PER_FRAME_PINVOKE_INIT pThread->SetFrame(pLimitFrame); @@ -1653,7 +1663,11 @@ CLRUnwindStatus ExceptionTracker::ProcessOSExceptionNotification( DWORD dwExceptionFlags, StackFrame sf, Thread* pThread, - StackTraceState STState ARM_ARG(PVOID pICFSetAsLimitFrame)) + StackTraceState STState +#ifdef USE_PER_FRAME_PINVOKE_INIT + , PVOID pICFSetAsLimitFrame +#endif // USE_PER_FRAME_PINVOKE_INIT +) { CONTRACTL { @@ -1719,10 +1733,10 @@ CLRUnwindStatus ExceptionTracker::ProcessOSExceptionNotification( this->m_EnclosingClauseInfoForGCReporting.SetEnclosingClauseCallerSP(uCallerSP); } -#if defined(_TARGET_ARM_) +#ifdef USE_PER_FRAME_PINVOKE_INIT // Refer to detailed comment below. PTR_Frame pICFForUnwindTarget = NULL; -#endif // defined(_TARGET_ARM_) +#endif // USE_PER_FRAME_PINVOKE_INIT CheckForRudeAbort(pThread, fIsFirstPass); @@ -1751,7 +1765,7 @@ CLRUnwindStatus ExceptionTracker::ProcessOSExceptionNotification( while (((UINT_PTR)pFrame) < uCallerSP) { -#if defined(_TARGET_ARM_) +#ifdef USE_PER_FRAME_PINVOKE_INIT // InlinedCallFrames (ICF) are allocated, initialized and linked to the Frame chain // by the code generated by the JIT for a method containing a PInvoke. // @@ -1956,7 +1970,7 @@ lExit: if (fTargetUnwind && (status == SecondPassComplete)) { -#if defined(_TARGET_ARM_) +#ifdef USE_PER_FRAME_PINVOKE_INIT // If we have got a ICF to set as the LimitFrame, do that now. // The Frame chain is still intact and would be updated using // the LimitFrame (done after the catch handler returns). @@ -1968,7 +1982,7 @@ lExit: m_pLimitFrame = pICFForUnwindTarget; pICFSetAsLimitFrame = (PVOID)pICFForUnwindTarget; } -#endif // _TARGET_ARM_ +#endif // USE_PER_FRAME_PINVOKE_INIT // Since second pass is complete and we have reached // the frame containing the catch funclet, reset the enclosing diff --git a/src/vm/exceptionhandling.h b/src/vm/exceptionhandling.h index 97f1526621..6d1f2b42a8 100644 --- a/src/vm/exceptionhandling.h +++ b/src/vm/exceptionhandling.h @@ -10,6 +10,11 @@ #ifdef WIN64EXCEPTIONS +#if defined(_TARGET_ARM_) || defined(_TARGET_X86_) +#define USE_PER_FRAME_PINVOKE_INIT +#endif // _TARGET_ARM_ || _TARGET_X86_ + + // This address lies in the NULL pointer partition of the process memory. // Accessing it will result in AV. #define INVALID_RESUME_ADDRESS 0x000000000000bad0 @@ -203,7 +208,11 @@ public: DWORD dwExceptionFlags, StackFrame sf, Thread* pThread, - StackTraceState STState ARM_ARG(PVOID pICFSetAsLimitFrame)); + StackTraceState STState +#ifdef USE_PER_FRAME_PINVOKE_INIT + , PVOID pICFSetAsLimitFrame +#endif // USE_PER_FRAME_PINVOKE_INIT + ); CLRUnwindStatus ProcessExplicitFrame( CrawlFrame* pcfThisFrame, diff --git a/src/vm/exstate.cpp b/src/vm/exstate.cpp index c598412547..0dc902a1f1 100644 --- a/src/vm/exstate.cpp +++ b/src/vm/exstate.cpp @@ -102,7 +102,7 @@ void ThreadExceptionState::FreeAllStackTraces() } } -void ThreadExceptionState::ClearThrowablesForUnload(void* handleStore) +void ThreadExceptionState::ClearThrowablesForUnload(IGCHandleStore* handleStore) { WRAPPER_NO_CONTRACT; @@ -112,13 +112,11 @@ void ThreadExceptionState::ClearThrowablesForUnload(void* handleStore) ExInfo* pNode = &m_currentExInfo; #endif // WIN64EXCEPTIONS - IGCHandleTable *pHandleTable = GCHandleTableUtilities::GetGCHandleTable(); - for ( ; pNode != NULL; pNode = pNode->m_pPrevNestedInfo) { - if (pHandleTable->ContainsHandle(handleStore, pNode->m_hThrowable)) + if (handleStore->ContainsHandle(pNode->m_hThrowable)) { pNode->DestroyExceptionHandle(); } diff --git a/src/vm/exstate.h b/src/vm/exstate.h index 104c76c77b..ba2ce2dba5 100644 --- a/src/vm/exstate.h +++ b/src/vm/exstate.h @@ -56,7 +56,7 @@ class ThreadExceptionState public: void FreeAllStackTraces(); - void ClearThrowablesForUnload(void* handleStore); + void ClearThrowablesForUnload(IGCHandleStore* handleStore); #ifdef _DEBUG typedef enum diff --git a/src/vm/frames.h b/src/vm/frames.h index 747cbd6d68..681e566e2b 100644 --- a/src/vm/frames.h +++ b/src/vm/frames.h @@ -2330,11 +2330,7 @@ public: virtual void GcScanRoots(promote_func *fn, ScanContext* sc); #ifdef _TARGET_X86_ - virtual void UpdateRegDisplay(const PREGDISPLAY pRD) - { - WRAPPER_NO_CONTRACT; - UpdateRegDisplayHelper(pRD, 0); - } + virtual void UpdateRegDisplay(const PREGDISPLAY pRD); #endif virtual ETransitionType GetTransitionType() diff --git a/src/vm/gcenv.ee.cpp b/src/vm/gcenv.ee.cpp index 54c7991ee9..63c4ffea10 100644 --- a/src/vm/gcenv.ee.cpp +++ b/src/vm/gcenv.ee.cpp @@ -1275,9 +1275,17 @@ void GCToEEInterface::StompWriteBarrier(WriteBarrierParameters* args) // We need to make sure that other threads executing checked write barriers // will see the g_card_table update before g_lowest/highest_address updates. // Otherwise, the checked write barrier may AV accessing the old card table - // with address that it does not cover. Write barriers access card table - // without memory barriers for performance reasons, so we need to flush - // the store buffers here. + // with address that it does not cover. + // + // Even x86's total store ordering is insufficient here because threads reading + // g_card_table do so via the instruction cache, whereas g_lowest/highest_address + // are read via the data cache. + // + // The g_card_table update is covered by section 8.1.3 of the Intel Software + // Development Manual, Volume 3A (System Programming Guide, Part 1), about + // "cross-modifying code": We need all _executing_ threads to invalidate + // their instruction cache, which FlushProcessWriteBuffers achieves by sending + // an IPI (inter-process interrupt). FlushProcessWriteBuffers(); g_lowest_address = args->lowest_address; diff --git a/src/vm/gcenv.os.cpp b/src/vm/gcenv.os.cpp index 6c08558e03..77be88c96d 100644 --- a/src/vm/gcenv.os.cpp +++ b/src/vm/gcenv.os.cpp @@ -329,11 +329,7 @@ bool GCToOSInterface::GetCurrentProcessAffinityMask(uintptr_t* processMask, uint { LIMITED_METHOD_CONTRACT; -#ifndef FEATURE_PAL return !!::GetProcessAffinityMask(GetCurrentProcess(), (PDWORD_PTR)processMask, (PDWORD_PTR)systemMask); -#else - return false; -#endif } // Get number of processors assigned to the current process @@ -700,3 +696,208 @@ void CLRCriticalSection::Leave() WRAPPER_NO_CONTRACT; UnsafeLeaveCriticalSection(&m_cs); } + +// An implementatino of GCEvent that delegates to +// a CLREvent, which in turn delegates to the PAL. This event +// is also host-aware. +class GCEvent::Impl +{ +private: + CLREvent m_event; + +public: + Impl() = default; + + bool IsValid() + { + WRAPPER_NO_CONTRACT; + + return !!m_event.IsValid(); + } + + void CloseEvent() + { + WRAPPER_NO_CONTRACT; + + assert(m_event.IsValid()); + m_event.CloseEvent(); + } + + void Set() + { + WRAPPER_NO_CONTRACT; + + assert(m_event.IsValid()); + m_event.Set(); + } + + void Reset() + { + WRAPPER_NO_CONTRACT; + + assert(m_event.IsValid()); + m_event.Reset(); + } + + uint32_t Wait(uint32_t timeout, bool alertable) + { + WRAPPER_NO_CONTRACT; + + assert(m_event.IsValid()); + return m_event.Wait(timeout, alertable); + } + + bool CreateAutoEvent(bool initialState) + { + CONTRACTL { + NOTHROW; + GC_NOTRIGGER; + } CONTRACTL_END; + + return !!m_event.CreateAutoEventNoThrow(initialState); + } + + bool CreateManualEvent(bool initialState) + { + CONTRACTL { + NOTHROW; + GC_NOTRIGGER; + } CONTRACTL_END; + + return !!m_event.CreateManualEventNoThrow(initialState); + } + + bool CreateOSAutoEvent(bool initialState) + { + CONTRACTL { + NOTHROW; + GC_NOTRIGGER; + } CONTRACTL_END; + + return !!m_event.CreateOSAutoEventNoThrow(initialState); + } + + bool CreateOSManualEvent(bool initialState) + { + CONTRACTL { + NOTHROW; + GC_NOTRIGGER; + } CONTRACTL_END; + + return !!m_event.CreateOSManualEventNoThrow(initialState); + } +}; + +GCEvent::GCEvent() + : m_impl(nullptr) +{ +} + +void GCEvent::CloseEvent() +{ + WRAPPER_NO_CONTRACT; + + assert(m_impl != nullptr); + m_impl->CloseEvent(); +} + +void GCEvent::Set() +{ + WRAPPER_NO_CONTRACT; + + assert(m_impl != nullptr); + m_impl->Set(); +} + +void GCEvent::Reset() +{ + WRAPPER_NO_CONTRACT; + + assert(m_impl != nullptr); + m_impl->Reset(); +} + +uint32_t GCEvent::Wait(uint32_t timeout, bool alertable) +{ + WRAPPER_NO_CONTRACT; + + assert(m_impl != nullptr); + return m_impl->Wait(timeout, alertable); +} + +bool GCEvent::CreateManualEventNoThrow(bool initialState) +{ + CONTRACTL { + NOTHROW; + GC_NOTRIGGER; + } CONTRACTL_END; + + assert(m_impl == nullptr); + NewHolder<GCEvent::Impl> event = new (nothrow) GCEvent::Impl(); + if (!event) + { + return false; + } + + event->CreateManualEvent(initialState); + m_impl = event.Extract(); + return true; +} + +bool GCEvent::CreateAutoEventNoThrow(bool initialState) +{ + CONTRACTL { + NOTHROW; + GC_NOTRIGGER; + } CONTRACTL_END; + + assert(m_impl == nullptr); + NewHolder<GCEvent::Impl> event = new (nothrow) GCEvent::Impl(); + if (!event) + { + return false; + } + + event->CreateAutoEvent(initialState); + m_impl = event.Extract(); + return IsValid(); +} + +bool GCEvent::CreateOSAutoEventNoThrow(bool initialState) +{ + CONTRACTL { + NOTHROW; + GC_NOTRIGGER; + } CONTRACTL_END; + + assert(m_impl == nullptr); + NewHolder<GCEvent::Impl> event = new (nothrow) GCEvent::Impl(); + if (!event) + { + return false; + } + + event->CreateOSAutoEvent(initialState); + m_impl = event.Extract(); + return IsValid(); +} + +bool GCEvent::CreateOSManualEventNoThrow(bool initialState) +{ + CONTRACTL { + NOTHROW; + GC_NOTRIGGER; + } CONTRACTL_END; + + assert(m_impl == nullptr); + NewHolder<GCEvent::Impl> event = new (nothrow) GCEvent::Impl(); + if (!event) + { + return false; + } + + event->CreateOSManualEvent(initialState); + m_impl = event.Extract(); + return IsValid(); +} + diff --git a/src/vm/gchandletableutilities.h b/src/vm/gchandletableutilities.h deleted file mode 100644 index 6e32add8ac..0000000000 --- a/src/vm/gchandletableutilities.h +++ /dev/null @@ -1,354 +0,0 @@ -// 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. - -#ifndef _GCHANDLETABLEUTILITIES_H_ -#define _GCHANDLETABLEUTILITIES_H_ - -#include "gcinterface.h" - -#ifdef FEATURE_COMINTEROP -#include <weakreference.h> -#endif - -extern "C" IGCHandleTable* g_pGCHandleTable; - -class GCHandleTableUtilities -{ -public: - // Retrieves the GC handle table. - static IGCHandleTable* GetGCHandleTable() - { - LIMITED_METHOD_CONTRACT; - - assert(g_pGCHandleTable != nullptr); - return g_pGCHandleTable; - } - -private: - // This class should never be instantiated. - GCHandleTableUtilities() = delete; -}; - -void ValidateHandleAndAppDomain(OBJECTHANDLE handle); - -// Given a handle, returns an OBJECTREF for the object it refers to. -inline OBJECTREF ObjectFromHandle(OBJECTHANDLE handle) -{ - _ASSERTE(handle); - -#ifdef _DEBUG_IMPL - ValidateHandleAndAppDomain(handle); -#endif // _DEBUG_IMPL - - // Wrap the raw OBJECTREF and return it - return UNCHECKED_OBJECTREF_TO_OBJECTREF(*PTR_UNCHECKED_OBJECTREF(handle)); -} - -// Quick inline check for whether a handle is null -inline BOOL IsHandleNullUnchecked(OBJECTHANDLE handle) -{ - LIMITED_METHOD_CONTRACT; - - return (handle == NULL || (*(_UNCHECKED_OBJECTREF *)handle) == NULL); -} - -inline BOOL ObjectHandleIsNull(OBJECTHANDLE handle) -{ - LIMITED_METHOD_CONTRACT; - - return *(Object **)handle == NULL; -} - -#ifndef DACCESS_COMPILE - -// Handle creation convenience functions - -inline OBJECTHANDLE CreateHandle(void* table, OBJECTREF object) -{ - return GCHandleTableUtilities::GetGCHandleTable()->CreateHandleOfType(table, OBJECTREFToObject(object), HNDTYPE_DEFAULT); -} - -inline OBJECTHANDLE CreateWeakHandle(void* table, OBJECTREF object) -{ - return GCHandleTableUtilities::GetGCHandleTable()->CreateHandleOfType(table, OBJECTREFToObject(object), HNDTYPE_WEAK_DEFAULT); -} - -inline OBJECTHANDLE CreateShortWeakHandle(void* table, OBJECTREF object) -{ - return GCHandleTableUtilities::GetGCHandleTable()->CreateHandleOfType(table, OBJECTREFToObject(object), HNDTYPE_WEAK_SHORT); -} - -inline OBJECTHANDLE CreateLongWeakHandle(void* table, OBJECTREF object) -{ - return GCHandleTableUtilities::GetGCHandleTable()->CreateHandleOfType(table, OBJECTREFToObject(object), HNDTYPE_WEAK_LONG); -} - -inline OBJECTHANDLE CreateStrongHandle(void* table, OBJECTREF object) -{ - return GCHandleTableUtilities::GetGCHandleTable()->CreateHandleOfType(table, OBJECTREFToObject(object), HNDTYPE_STRONG); -} - -inline OBJECTHANDLE CreatePinningHandle(void* table, OBJECTREF object) -{ - return GCHandleTableUtilities::GetGCHandleTable()->CreateHandleOfType(table, OBJECTREFToObject(object), HNDTYPE_PINNED); -} - -inline OBJECTHANDLE CreateAsyncPinningHandle(void* table, OBJECTREF object) -{ - return GCHandleTableUtilities::GetGCHandleTable()->CreateHandleOfType(table, OBJECTREFToObject(object), HNDTYPE_ASYNCPINNED); -} - -inline OBJECTHANDLE CreateRefcountedHandle(void* table, OBJECTREF object) -{ - return GCHandleTableUtilities::GetGCHandleTable()->CreateHandleOfType(table, OBJECTREFToObject(object), HNDTYPE_REFCOUNTED); -} - -inline OBJECTHANDLE CreateSizedRefHandle(void* table, OBJECTREF object) -{ - return GCHandleTableUtilities::GetGCHandleTable()->CreateHandleOfType(table, OBJECTREFToObject(object), HNDTYPE_SIZEDREF); -} - -inline OBJECTHANDLE CreateSizedRefHandle(void* table, OBJECTREF object, int heapToAffinitizeTo) -{ - return GCHandleTableUtilities::GetGCHandleTable()->CreateHandleOfType(table, OBJECTREFToObject(object), HNDTYPE_SIZEDREF, heapToAffinitizeTo); -} - -// Global handle creation convenience functions - -inline OBJECTHANDLE CreateGlobalHandle(OBJECTREF object) -{ - CONDITIONAL_CONTRACT_VIOLATION(ModeViolation, object == NULL); - return GCHandleTableUtilities::GetGCHandleTable()->CreateGlobalHandleOfType(OBJECTREFToObject(object), HNDTYPE_DEFAULT); -} - -inline OBJECTHANDLE CreateGlobalWeakHandle(OBJECTREF object) -{ - return GCHandleTableUtilities::GetGCHandleTable()->CreateGlobalHandleOfType(OBJECTREFToObject(object), HNDTYPE_WEAK_DEFAULT); -} - -inline OBJECTHANDLE CreateGlobalShortWeakHandle(OBJECTREF object) -{ - CONDITIONAL_CONTRACT_VIOLATION(ModeViolation, object == NULL); - return GCHandleTableUtilities::GetGCHandleTable()->CreateGlobalHandleOfType(OBJECTREFToObject(object), HNDTYPE_WEAK_SHORT); -} - -inline OBJECTHANDLE CreateGlobalLongWeakHandle(OBJECTREF object) -{ - return GCHandleTableUtilities::GetGCHandleTable()->CreateGlobalHandleOfType(OBJECTREFToObject(object), HNDTYPE_WEAK_LONG); -} - -inline OBJECTHANDLE CreateGlobalStrongHandle(OBJECTREF object) -{ - CONDITIONAL_CONTRACT_VIOLATION(ModeViolation, object == NULL); - return GCHandleTableUtilities::GetGCHandleTable()->CreateGlobalHandleOfType(OBJECTREFToObject(object), HNDTYPE_STRONG); -} - -inline OBJECTHANDLE CreateGlobalPinningHandle(OBJECTREF object) -{ - return GCHandleTableUtilities::GetGCHandleTable()->CreateGlobalHandleOfType(OBJECTREFToObject(object), HNDTYPE_PINNED); -} - -inline OBJECTHANDLE CreateGlobalRefcountedHandle(OBJECTREF object) -{ - return GCHandleTableUtilities::GetGCHandleTable()->CreateGlobalHandleOfType(OBJECTREFToObject(object), HNDTYPE_REFCOUNTED); -} - -// Special handle creation convenience functions - -#ifdef FEATURE_COMINTEROP -inline OBJECTHANDLE CreateWinRTWeakHandle(void* table, OBJECTREF object, IWeakReference* pWinRTWeakReference) -{ - return GCHandleTableUtilities::GetGCHandleTable()->CreateHandleWithExtraInfo(table, - OBJECTREFToObject(object), - HNDTYPE_WEAK_WINRT, - (void*)pWinRTWeakReference); -} -#endif // FEATURE_COMINTEROP - -// Creates a variable-strength handle -inline OBJECTHANDLE CreateVariableHandle(void* table, OBJECTREF object, uint32_t type) -{ - return GCHandleTableUtilities::GetGCHandleTable()->CreateHandleWithExtraInfo(table, - OBJECTREFToObject(object), - HNDTYPE_VARIABLE, - (void*)((uintptr_t)type)); -} - -// Handle destruction convenience functions - -inline void DestroyHandle(OBJECTHANDLE handle) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - CAN_TAKE_LOCK; - SO_TOLERANT; - } - CONTRACTL_END; - - GCHandleTableUtilities::GetGCHandleTable()->DestroyHandleOfType(handle, HNDTYPE_DEFAULT); -} - -inline void DestroyWeakHandle(OBJECTHANDLE handle) -{ - GCHandleTableUtilities::GetGCHandleTable()->DestroyHandleOfType(handle, HNDTYPE_WEAK_DEFAULT); -} - -inline void DestroyShortWeakHandle(OBJECTHANDLE handle) -{ - GCHandleTableUtilities::GetGCHandleTable()->DestroyHandleOfType(handle, HNDTYPE_WEAK_SHORT); -} - -inline void DestroyLongWeakHandle(OBJECTHANDLE handle) -{ - GCHandleTableUtilities::GetGCHandleTable()->DestroyHandleOfType(handle, HNDTYPE_WEAK_LONG); -} - -inline void DestroyStrongHandle(OBJECTHANDLE handle) -{ - GCHandleTableUtilities::GetGCHandleTable()->DestroyHandleOfType(handle, HNDTYPE_STRONG); -} - -inline void DestroyPinningHandle(OBJECTHANDLE handle) -{ - GCHandleTableUtilities::GetGCHandleTable()->DestroyHandleOfType(handle, HNDTYPE_PINNED); -} - -inline void DestroyAsyncPinningHandle(OBJECTHANDLE handle) -{ - GCHandleTableUtilities::GetGCHandleTable()->DestroyHandleOfType(handle, HNDTYPE_ASYNCPINNED); -} - -inline void DestroyRefcountedHandle(OBJECTHANDLE handle) -{ - GCHandleTableUtilities::GetGCHandleTable()->DestroyHandleOfType(handle, HNDTYPE_REFCOUNTED); -} - -inline void DestroyDependentHandle(OBJECTHANDLE handle) -{ - GCHandleTableUtilities::GetGCHandleTable()->DestroyHandleOfType(handle, HNDTYPE_DEPENDENT); -} - -inline void DestroyVariableHandle(OBJECTHANDLE handle) -{ - GCHandleTableUtilities::GetGCHandleTable()->DestroyHandleOfType(handle, HNDTYPE_VARIABLE); -} - -inline void DestroyGlobalHandle(OBJECTHANDLE handle) -{ - GCHandleTableUtilities::GetGCHandleTable()->DestroyHandleOfType(handle, HNDTYPE_DEFAULT); -} - -inline void DestroyGlobalWeakHandle(OBJECTHANDLE handle) -{ - GCHandleTableUtilities::GetGCHandleTable()->DestroyHandleOfType(handle, HNDTYPE_WEAK_DEFAULT); -} - -inline void DestroyGlobalShortWeakHandle(OBJECTHANDLE handle) -{ - GCHandleTableUtilities::GetGCHandleTable()->DestroyHandleOfType(handle, HNDTYPE_WEAK_SHORT); -} - -inline void DestroyGlobalLongWeakHandle(OBJECTHANDLE handle) -{ - GCHandleTableUtilities::GetGCHandleTable()->DestroyHandleOfType(handle, HNDTYPE_WEAK_LONG); -} - -inline void DestroyGlobalStrongHandle(OBJECTHANDLE handle) -{ - GCHandleTableUtilities::GetGCHandleTable()->DestroyHandleOfType(handle, HNDTYPE_STRONG); -} - -inline void DestroyGlobalPinningHandle(OBJECTHANDLE handle) -{ - GCHandleTableUtilities::GetGCHandleTable()->DestroyHandleOfType(handle, HNDTYPE_PINNED); -} - -inline void DestroyGlobalRefcountedHandle(OBJECTHANDLE handle) -{ - GCHandleTableUtilities::GetGCHandleTable()->DestroyHandleOfType(handle, HNDTYPE_REFCOUNTED); -} - -inline void DestroyTypedHandle(OBJECTHANDLE handle) -{ - GCHandleTableUtilities::GetGCHandleTable()->DestroyHandleOfUnknownType(handle); -} - -#ifdef FEATURE_COMINTEROP -inline void DestroyWinRTWeakHandle(OBJECTHANDLE handle) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - CAN_TAKE_LOCK; - SO_TOLERANT; - } - CONTRACTL_END; - - // Release the WinRT weak reference if we have one. We're assuming that this will not reenter the - // runtime, since if we are pointing at a managed object, we should not be using HNDTYPE_WEAK_WINRT - // but rather HNDTYPE_WEAK_SHORT or HNDTYPE_WEAK_LONG. - void* pExtraInfo = GCHandleTableUtilities::GetGCHandleTable()->GetExtraInfoFromHandle(handle); - IWeakReference* pWinRTWeakReference = reinterpret_cast<IWeakReference*>(pExtraInfo); - if (pWinRTWeakReference != nullptr) - { - pWinRTWeakReference->Release(); - } - - GCHandleTableUtilities::GetGCHandleTable()->DestroyHandleOfType(handle, HNDTYPE_WEAK_WINRT); -} -#endif - -// Handle holders/wrappers - -#ifndef FEATURE_REDHAWK -typedef Wrapper<OBJECTHANDLE, DoNothing<OBJECTHANDLE>, DestroyHandle> OHWrapper; -typedef Wrapper<OBJECTHANDLE, DoNothing<OBJECTHANDLE>, DestroyPinningHandle, NULL> PinningHandleHolder; -typedef Wrapper<OBJECTHANDLE, DoNothing<OBJECTHANDLE>, DestroyAsyncPinningHandle, NULL> AsyncPinningHandleHolder; -typedef Wrapper<OBJECTHANDLE, DoNothing<OBJECTHANDLE>, DestroyRefcountedHandle> RefCountedOHWrapper; - -typedef Holder<OBJECTHANDLE, DoNothing<OBJECTHANDLE>, DestroyLongWeakHandle> LongWeakHandleHolder; -typedef Holder<OBJECTHANDLE, DoNothing<OBJECTHANDLE>, DestroyGlobalStrongHandle> GlobalStrongHandleHolder; -typedef Holder<OBJECTHANDLE, DoNothing<OBJECTHANDLE>, DestroyGlobalShortWeakHandle> GlobalShortWeakHandleHolder; - -class RCOBJECTHANDLEHolder : public RefCountedOHWrapper -{ -public: - FORCEINLINE RCOBJECTHANDLEHolder(OBJECTHANDLE p = NULL) : RefCountedOHWrapper(p) - { - LIMITED_METHOD_CONTRACT; - } - FORCEINLINE void operator=(OBJECTHANDLE p) - { - WRAPPER_NO_CONTRACT; - - RefCountedOHWrapper::operator=(p); - } -}; - -class OBJECTHANDLEHolder : public OHWrapper -{ -public: - FORCEINLINE OBJECTHANDLEHolder(OBJECTHANDLE p = NULL) : OHWrapper(p) - { - LIMITED_METHOD_CONTRACT; - } - FORCEINLINE void operator=(OBJECTHANDLE p) - { - WRAPPER_NO_CONTRACT; - - OHWrapper::operator=(p); - } -}; - -#endif // !FEATURE_REDHAWK - -#endif // !DACCESS_COMPILE - -#endif // _GCHANDLETABLEUTILITIES_H_ - diff --git a/src/vm/gchandleutilities.h b/src/vm/gchandleutilities.h new file mode 100644 index 0000000000..665c1da453 --- /dev/null +++ b/src/vm/gchandleutilities.h @@ -0,0 +1,495 @@ +// 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. + +#ifndef _GCHANDLEUTILITIES_H_ +#define _GCHANDLEUTILITIES_H_ + +#include "gcinterface.h" + +#ifdef FEATURE_COMINTEROP +#include <weakreference.h> +#endif + +extern "C" IGCHandleManager* g_pGCHandleManager; + +class GCHandleUtilities +{ +public: + // Retrieves the GC handle table. + static IGCHandleManager* GetGCHandleManager() + { + LIMITED_METHOD_CONTRACT; + + assert(g_pGCHandleManager != nullptr); + return g_pGCHandleManager; + } + +private: + // This class should never be instantiated. + GCHandleUtilities() = delete; +}; + +void ValidateObjectAndAppDomain(OBJECTREF objRef, ADIndex appDomainIndex); +void ValidateHandleAssignment(OBJECTHANDLE handle, OBJECTREF objRef); + +// Given a handle, returns an OBJECTREF for the object it refers to. +inline OBJECTREF ObjectFromHandle(OBJECTHANDLE handle) +{ + _ASSERTE(handle); + +#ifdef _DEBUG_IMPL + DWORD context = (DWORD)GCHandleUtilities::GetGCHandleManager()->GetHandleContext(handle); + OBJECTREF objRef = ObjectToOBJECTREF(*(Object**)handle); + + ValidateObjectAndAppDomain(objRef, ADIndex(context)); +#endif // _DEBUG_IMPL + + // Wrap the raw OBJECTREF and return it + return UNCHECKED_OBJECTREF_TO_OBJECTREF(*PTR_UNCHECKED_OBJECTREF(handle)); +} + +// Quick inline check for whether a handle is null +inline BOOL IsHandleNullUnchecked(OBJECTHANDLE handle) +{ + LIMITED_METHOD_CONTRACT; + + return (handle == NULL || (*(_UNCHECKED_OBJECTREF *)handle) == NULL); +} + +inline BOOL ObjectHandleIsNull(OBJECTHANDLE handle) +{ + LIMITED_METHOD_CONTRACT; + + return *(Object **)handle == NULL; +} + +#ifndef DACCESS_COMPILE + +// Handle creation convenience functions + +inline OBJECTHANDLE CreateHandle(IGCHandleStore* store, OBJECTREF object) +{ + OBJECTHANDLE hnd = store->CreateHandleOfType(OBJECTREFToObject(object), HNDTYPE_DEFAULT); + if (!hnd) + { + COMPlusThrowOM(); + } + + return hnd; +} + +inline OBJECTHANDLE CreateWeakHandle(IGCHandleStore* store, OBJECTREF object) +{ + OBJECTHANDLE hnd = store->CreateHandleOfType(OBJECTREFToObject(object), HNDTYPE_WEAK_DEFAULT); + if (!hnd) + { + COMPlusThrowOM(); + } + + return hnd; +} + +inline OBJECTHANDLE CreateShortWeakHandle(IGCHandleStore* store, OBJECTREF object) +{ + OBJECTHANDLE hnd = store->CreateHandleOfType(OBJECTREFToObject(object), HNDTYPE_WEAK_SHORT); + if (!hnd) + { + COMPlusThrowOM(); + } + + return hnd; +} + +inline OBJECTHANDLE CreateLongWeakHandle(IGCHandleStore* store, OBJECTREF object) +{ + OBJECTHANDLE hnd = store->CreateHandleOfType(OBJECTREFToObject(object), HNDTYPE_WEAK_LONG); + if (!hnd) + { + COMPlusThrowOM(); + } + + return hnd; +} + +inline OBJECTHANDLE CreateStrongHandle(IGCHandleStore* store, OBJECTREF object) +{ + OBJECTHANDLE hnd = store->CreateHandleOfType(OBJECTREFToObject(object), HNDTYPE_STRONG); + if (!hnd) + { + COMPlusThrowOM(); + } + + return hnd; +} + +inline OBJECTHANDLE CreatePinningHandle(IGCHandleStore* store, OBJECTREF object) +{ + OBJECTHANDLE hnd = store->CreateHandleOfType(OBJECTREFToObject(object), HNDTYPE_PINNED); + if (!hnd) + { + COMPlusThrowOM(); + } + + return hnd; +} + +inline OBJECTHANDLE CreateAsyncPinningHandle(IGCHandleStore* store, OBJECTREF object) +{ + OBJECTHANDLE hnd = store->CreateHandleOfType(OBJECTREFToObject(object), HNDTYPE_ASYNCPINNED); + if (!hnd) + { + COMPlusThrowOM(); + } + + return hnd; +} + +inline OBJECTHANDLE CreateRefcountedHandle(IGCHandleStore* store, OBJECTREF object) +{ + OBJECTHANDLE hnd = store->CreateHandleOfType(OBJECTREFToObject(object), HNDTYPE_REFCOUNTED); + if (!hnd) + { + COMPlusThrowOM(); + } + + return hnd; +} + +inline OBJECTHANDLE CreateSizedRefHandle(IGCHandleStore* store, OBJECTREF object) +{ + OBJECTHANDLE hnd = store->CreateHandleOfType(OBJECTREFToObject(object), HNDTYPE_SIZEDREF); + if (!hnd) + { + COMPlusThrowOM(); + } + + return hnd; +} + +inline OBJECTHANDLE CreateSizedRefHandle(IGCHandleStore* store, OBJECTREF object, int heapToAffinitizeTo) +{ + OBJECTHANDLE hnd = store->CreateHandleOfType(OBJECTREFToObject(object), HNDTYPE_SIZEDREF, heapToAffinitizeTo); + if (!hnd) + { + COMPlusThrowOM(); + } + + return hnd; +} + +// Global handle creation convenience functions + +inline OBJECTHANDLE CreateGlobalHandle(OBJECTREF object) +{ + CONDITIONAL_CONTRACT_VIOLATION(ModeViolation, object == NULL); + OBJECTHANDLE hnd = GCHandleUtilities::GetGCHandleManager()->CreateGlobalHandleOfType(OBJECTREFToObject(object), HNDTYPE_DEFAULT); + if (!hnd) + { + COMPlusThrowOM(); + } + + return hnd; +} + +inline OBJECTHANDLE CreateGlobalWeakHandle(OBJECTREF object) +{ + OBJECTHANDLE hnd = GCHandleUtilities::GetGCHandleManager()->CreateGlobalHandleOfType(OBJECTREFToObject(object), HNDTYPE_WEAK_DEFAULT); + if (!hnd) + { + COMPlusThrowOM(); + } + + return hnd; +} + +inline OBJECTHANDLE CreateGlobalShortWeakHandle(OBJECTREF object) +{ + CONDITIONAL_CONTRACT_VIOLATION(ModeViolation, object == NULL); + OBJECTHANDLE hnd = GCHandleUtilities::GetGCHandleManager()->CreateGlobalHandleOfType(OBJECTREFToObject(object), HNDTYPE_WEAK_SHORT); + if (!hnd) + { + COMPlusThrowOM(); + } + + return hnd; +} + +inline OBJECTHANDLE CreateGlobalLongWeakHandle(OBJECTREF object) +{ + OBJECTHANDLE hnd = GCHandleUtilities::GetGCHandleManager()->CreateGlobalHandleOfType(OBJECTREFToObject(object), HNDTYPE_WEAK_LONG); + if (!hnd) + { + COMPlusThrowOM(); + } + + return hnd; +} + +inline OBJECTHANDLE CreateGlobalStrongHandle(OBJECTREF object) +{ + CONDITIONAL_CONTRACT_VIOLATION(ModeViolation, object == NULL); + OBJECTHANDLE hnd = GCHandleUtilities::GetGCHandleManager()->CreateGlobalHandleOfType(OBJECTREFToObject(object), HNDTYPE_STRONG); + if (!hnd) + { + COMPlusThrowOM(); + } + + return hnd; +} + +inline OBJECTHANDLE CreateGlobalPinningHandle(OBJECTREF object) +{ + OBJECTHANDLE hnd = GCHandleUtilities::GetGCHandleManager()->CreateGlobalHandleOfType(OBJECTREFToObject(object), HNDTYPE_PINNED); + if (!hnd) + { + COMPlusThrowOM(); + } + + return hnd; +} + +inline OBJECTHANDLE CreateGlobalRefcountedHandle(OBJECTREF object) +{ + OBJECTHANDLE hnd = GCHandleUtilities::GetGCHandleManager()->CreateGlobalHandleOfType(OBJECTREFToObject(object), HNDTYPE_REFCOUNTED); + if (!hnd) + { + COMPlusThrowOM(); + } + + return hnd; +} + +// Special handle creation convenience functions + +#ifdef FEATURE_COMINTEROP +inline OBJECTHANDLE CreateWinRTWeakHandle(IGCHandleStore* store, OBJECTREF object, IWeakReference* pWinRTWeakReference) +{ + OBJECTHANDLE hnd = store->CreateHandleWithExtraInfo(OBJECTREFToObject(object), HNDTYPE_WEAK_WINRT, (void*)pWinRTWeakReference); + if (!hnd) + { + COMPlusThrowOM(); + } + + return hnd; +} +#endif // FEATURE_COMINTEROP + +// Creates a variable-strength handle +inline OBJECTHANDLE CreateVariableHandle(IGCHandleStore* store, OBJECTREF object, uint32_t type) +{ + OBJECTHANDLE hnd = store->CreateHandleWithExtraInfo(OBJECTREFToObject(object), HNDTYPE_VARIABLE, (void*)((uintptr_t)type)); + if (!hnd) + { + COMPlusThrowOM(); + } + + return hnd; +} + +// Handle object manipulation convenience functions + +inline void StoreObjectInHandle(OBJECTHANDLE handle, OBJECTREF object) +{ + ValidateHandleAssignment(handle, object); + + GCHandleUtilities::GetGCHandleManager()->StoreObjectInHandle(handle, OBJECTREFToObject(object)); +} + +inline bool StoreFirstObjectInHandle(OBJECTHANDLE handle, OBJECTREF object) +{ + ValidateHandleAssignment(handle, object); + + return GCHandleUtilities::GetGCHandleManager()->StoreObjectInHandleIfNull(handle, OBJECTREFToObject(object)); +} + +inline void* InterlockedCompareExchangeObjectInHandle(OBJECTHANDLE handle, OBJECTREF object, OBJECTREF comparandObject) +{ + ValidateHandleAssignment(handle, object); + + return GCHandleUtilities::GetGCHandleManager()->InterlockedCompareExchangeObjectInHandle(handle, OBJECTREFToObject(object), OBJECTREFToObject(comparandObject)); +} + +inline void ResetOBJECTHANDLE(OBJECTHANDLE handle) +{ + GCHandleUtilities::GetGCHandleManager()->StoreObjectInHandle(handle, NULL); +} + +// Handle destruction convenience functions + +inline void DestroyHandle(OBJECTHANDLE handle) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + CAN_TAKE_LOCK; + SO_TOLERANT; + } + CONTRACTL_END; + + GCHandleUtilities::GetGCHandleManager()->DestroyHandleOfType(handle, HNDTYPE_DEFAULT); +} + +inline void DestroyWeakHandle(OBJECTHANDLE handle) +{ + GCHandleUtilities::GetGCHandleManager()->DestroyHandleOfType(handle, HNDTYPE_WEAK_DEFAULT); +} + +inline void DestroyShortWeakHandle(OBJECTHANDLE handle) +{ + GCHandleUtilities::GetGCHandleManager()->DestroyHandleOfType(handle, HNDTYPE_WEAK_SHORT); +} + +inline void DestroyLongWeakHandle(OBJECTHANDLE handle) +{ + GCHandleUtilities::GetGCHandleManager()->DestroyHandleOfType(handle, HNDTYPE_WEAK_LONG); +} + +inline void DestroyStrongHandle(OBJECTHANDLE handle) +{ + GCHandleUtilities::GetGCHandleManager()->DestroyHandleOfType(handle, HNDTYPE_STRONG); +} + +inline void DestroyPinningHandle(OBJECTHANDLE handle) +{ + GCHandleUtilities::GetGCHandleManager()->DestroyHandleOfType(handle, HNDTYPE_PINNED); +} + +inline void DestroyAsyncPinningHandle(OBJECTHANDLE handle) +{ + GCHandleUtilities::GetGCHandleManager()->DestroyHandleOfType(handle, HNDTYPE_ASYNCPINNED); +} + +inline void DestroyRefcountedHandle(OBJECTHANDLE handle) +{ + GCHandleUtilities::GetGCHandleManager()->DestroyHandleOfType(handle, HNDTYPE_REFCOUNTED); +} + +inline void DestroyDependentHandle(OBJECTHANDLE handle) +{ + GCHandleUtilities::GetGCHandleManager()->DestroyHandleOfType(handle, HNDTYPE_DEPENDENT); +} + +inline void DestroyVariableHandle(OBJECTHANDLE handle) +{ + GCHandleUtilities::GetGCHandleManager()->DestroyHandleOfType(handle, HNDTYPE_VARIABLE); +} + +inline void DestroyGlobalHandle(OBJECTHANDLE handle) +{ + GCHandleUtilities::GetGCHandleManager()->DestroyHandleOfType(handle, HNDTYPE_DEFAULT); +} + +inline void DestroyGlobalWeakHandle(OBJECTHANDLE handle) +{ + GCHandleUtilities::GetGCHandleManager()->DestroyHandleOfType(handle, HNDTYPE_WEAK_DEFAULT); +} + +inline void DestroyGlobalShortWeakHandle(OBJECTHANDLE handle) +{ + GCHandleUtilities::GetGCHandleManager()->DestroyHandleOfType(handle, HNDTYPE_WEAK_SHORT); +} + +inline void DestroyGlobalLongWeakHandle(OBJECTHANDLE handle) +{ + GCHandleUtilities::GetGCHandleManager()->DestroyHandleOfType(handle, HNDTYPE_WEAK_LONG); +} + +inline void DestroyGlobalStrongHandle(OBJECTHANDLE handle) +{ + GCHandleUtilities::GetGCHandleManager()->DestroyHandleOfType(handle, HNDTYPE_STRONG); +} + +inline void DestroyGlobalPinningHandle(OBJECTHANDLE handle) +{ + GCHandleUtilities::GetGCHandleManager()->DestroyHandleOfType(handle, HNDTYPE_PINNED); +} + +inline void DestroyGlobalRefcountedHandle(OBJECTHANDLE handle) +{ + GCHandleUtilities::GetGCHandleManager()->DestroyHandleOfType(handle, HNDTYPE_REFCOUNTED); +} + +inline void DestroyTypedHandle(OBJECTHANDLE handle) +{ + GCHandleUtilities::GetGCHandleManager()->DestroyHandleOfUnknownType(handle); +} + +#ifdef FEATURE_COMINTEROP +inline void DestroyWinRTWeakHandle(OBJECTHANDLE handle) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + CAN_TAKE_LOCK; + SO_TOLERANT; + } + CONTRACTL_END; + + // Release the WinRT weak reference if we have one. We're assuming that this will not reenter the + // runtime, since if we are pointing at a managed object, we should not be using HNDTYPE_WEAK_WINRT + // but rather HNDTYPE_WEAK_SHORT or HNDTYPE_WEAK_LONG. + void* pExtraInfo = GCHandleUtilities::GetGCHandleManager()->GetExtraInfoFromHandle(handle); + IWeakReference* pWinRTWeakReference = reinterpret_cast<IWeakReference*>(pExtraInfo); + if (pWinRTWeakReference != nullptr) + { + pWinRTWeakReference->Release(); + } + + GCHandleUtilities::GetGCHandleManager()->DestroyHandleOfType(handle, HNDTYPE_WEAK_WINRT); +} +#endif + +// Handle holders/wrappers + +#ifndef FEATURE_REDHAWK +typedef Wrapper<OBJECTHANDLE, DoNothing<OBJECTHANDLE>, DestroyHandle> OHWrapper; +typedef Wrapper<OBJECTHANDLE, DoNothing<OBJECTHANDLE>, DestroyPinningHandle, NULL> PinningHandleHolder; +typedef Wrapper<OBJECTHANDLE, DoNothing<OBJECTHANDLE>, DestroyAsyncPinningHandle, NULL> AsyncPinningHandleHolder; +typedef Wrapper<OBJECTHANDLE, DoNothing<OBJECTHANDLE>, DestroyRefcountedHandle> RefCountedOHWrapper; + +typedef Holder<OBJECTHANDLE, DoNothing<OBJECTHANDLE>, DestroyLongWeakHandle> LongWeakHandleHolder; +typedef Holder<OBJECTHANDLE, DoNothing<OBJECTHANDLE>, DestroyGlobalStrongHandle> GlobalStrongHandleHolder; +typedef Holder<OBJECTHANDLE, DoNothing<OBJECTHANDLE>, DestroyGlobalShortWeakHandle> GlobalShortWeakHandleHolder; +typedef Holder<OBJECTHANDLE, DoNothing<OBJECTHANDLE>, ResetOBJECTHANDLE> ObjectInHandleHolder; + +class RCOBJECTHANDLEHolder : public RefCountedOHWrapper +{ +public: + FORCEINLINE RCOBJECTHANDLEHolder(OBJECTHANDLE p = NULL) : RefCountedOHWrapper(p) + { + LIMITED_METHOD_CONTRACT; + } + FORCEINLINE void operator=(OBJECTHANDLE p) + { + WRAPPER_NO_CONTRACT; + + RefCountedOHWrapper::operator=(p); + } +}; + +class OBJECTHANDLEHolder : public OHWrapper +{ +public: + FORCEINLINE OBJECTHANDLEHolder(OBJECTHANDLE p = NULL) : OHWrapper(p) + { + LIMITED_METHOD_CONTRACT; + } + FORCEINLINE void operator=(OBJECTHANDLE p) + { + WRAPPER_NO_CONTRACT; + + OHWrapper::operator=(p); + } +}; + +#endif // !FEATURE_REDHAWK + +#endif // !DACCESS_COMPILE + +#endif // _GCHANDLEUTILITIES_H_ + diff --git a/src/vm/gcheaputilities.cpp b/src/vm/gcheaputilities.cpp index e15558335e..cd7afede70 100644 --- a/src/vm/gcheaputilities.cpp +++ b/src/vm/gcheaputilities.cpp @@ -25,7 +25,7 @@ uint32_t* g_card_bundle_table = nullptr; // This is the global GC heap, maintained by the VM. GPTR_IMPL(IGCHeap, g_pGCHeap); -IGCHandleTable* g_pGCHandleTable = nullptr; +IGCHandleManager* g_pGCHandleManager = nullptr; GcDacVars g_gc_dac_vars; GPTR_IMPL(GcDacVars, g_gcDacGlobals); @@ -40,17 +40,12 @@ bool g_sw_ww_enabled_for_gc_heap = false; gc_alloc_context g_global_alloc_context = {}; // Debug-only validation for handle. -void ValidateHandleAndAppDomain(OBJECTHANDLE handle) + +void ValidateObjectAndAppDomain(OBJECTREF objRef, ADIndex appDomainIndex) { #ifdef _DEBUG_IMPL - OBJECTREF objRef = ObjectToOBJECTREF(*(Object**)handle); VALIDATEOBJECTREF(objRef); - IGCHandleTable *pHandleTable = GCHandleTableUtilities::GetGCHandleTable(); - - DWORD context = (DWORD)pHandleTable->GetHandleContext(handle); - - ADIndex appDomainIndex = ADIndex(context); AppDomain *domain = SystemDomain::GetAppDomainAtIndex(appDomainIndex); // Access to a handle in an unloaded domain is not allowed @@ -72,3 +67,25 @@ void ValidateHandleAndAppDomain(OBJECTHANDLE handle) #endif // CHECK_APP_DOMAIN_LEAKS #endif // _DEBUG_IMPL } + +void ValidateHandleAssignment(OBJECTHANDLE handle, OBJECTREF objRef) +{ +#ifdef _DEBUG_IMPL + _ASSERTE(handle); + +#ifdef DEBUG_DestroyedHandleValue + // Verify that we are not trying to access a freed handle. + _ASSERTE("Attempt to access destroyed handle." && *(_UNCHECKED_OBJECTREF*)handle != DEBUG_DestroyedHandleValue); +#endif + + ADIndex appDomainIndex = HndGetHandleADIndex(handle); + + AppDomain *unloadingDomain = SystemDomain::AppDomainBeingUnloaded(); + if (unloadingDomain && unloadingDomain->GetIndex() == appDomainIndex && unloadingDomain->NoAccessToHandleTable()) + { + _ASSERTE (!"Access to a handle in unloaded domain is not allowed"); + } + + ValidateObjectAndAppDomain(objRef, appDomainIndex); +#endif // _DEBUG_IMPL +}
\ No newline at end of file diff --git a/src/vm/gdbjit.cpp b/src/vm/gdbjit.cpp index fe8e211e5b..ace6b76d97 100644 --- a/src/vm/gdbjit.cpp +++ b/src/vm/gdbjit.cpp @@ -1095,7 +1095,7 @@ ClassTypeInfo::ClassTypeInfo(TypeHandle typeHandle, int num_members, FunctionMem { case ELEMENT_TYPE_VALUETYPE: case ELEMENT_TYPE_CLASS: - m_type_size = pMT->IsValueType() ? typeHandle.GetSize() : typeHandle.AsMethodTable()->GetClass()->GetSize(); + m_type_size = pMT->IsValueType() ? typeHandle.GetSize() : typeHandle.AsMethodTable()->GetBaseSize(); break; case ELEMENT_TYPE_ARRAY: case ELEMENT_TYPE_SZARRAY: diff --git a/src/vm/hosting.cpp b/src/vm/hosting.cpp index 620b9d6800..d47bc28238 100644 --- a/src/vm/hosting.cpp +++ b/src/vm/hosting.cpp @@ -444,6 +444,11 @@ LPVOID EEHeapAllocInProcessHeap(DWORD dwFlags, SIZE_T dwBytes) WRAPPER_NO_CONTRACT; STATIC_CONTRACT_SO_TOLERANT; +#ifdef _DEBUG + // Check whether (indispensable) implicit casting in ClrAllocInProcessHeapBootstrap is safe. + static FastAllocInProcessHeapFunc pFunc = EEHeapAllocInProcessHeap; +#endif + static HANDLE ProcessHeap = NULL; // We need to guarentee a very small stack consumption in allocating. And we can't allow @@ -506,6 +511,11 @@ BOOL EEHeapFreeInProcessHeap(DWORD dwFlags, LPVOID lpMem) } CONTRACTL_END; +#ifdef _DEBUG + // Check whether (indispensable) implicit casting in ClrFreeInProcessHeapBootstrap is safe. + static FastFreeInProcessHeapFunc pFunc = EEHeapFreeInProcessHeap; +#endif + // Take a look at comment in EEHeapFree and EEHeapAllocInProcessHeap, obviously someone // needs to take a little time to think more about this code. //CONTRACT_VIOLATION(SOToleranceViolation); diff --git a/src/vm/i386/asmhelpers.S b/src/vm/i386/asmhelpers.S index 98525aceee..75f4a26a80 100644 --- a/src/vm/i386/asmhelpers.S +++ b/src/vm/i386/asmhelpers.S @@ -439,6 +439,7 @@ NESTED_ENTRY OnHijackTripThread, _TEXT, NoHandler sub esp,12 push esp + CHECK_STACK_ALIGNMENT call C_FUNC(OnHijackWorker) // unused space for floating point state @@ -474,6 +475,7 @@ NESTED_ENTRY OnHijackFPTripThread, _TEXT, NoHandler fstp QWORD PTR [esp] push esp + CHECK_STACK_ALIGNMENT call C_FUNC(OnHijackWorker) // restore top of the floating point stack @@ -752,8 +754,10 @@ NESTED_ENTRY StubDispatchFixupStub, _TEXT, NoHandler mov esi, esp - push 0 - push 0 +.att_syntax + pushl $0 + pushl $0 +.intel_syntax noprefix push eax // siteAddrForRegisterIndirect (for tailcalls) push esi // pTransitionBlock @@ -784,8 +788,10 @@ NESTED_ENTRY ExternalMethodFixupStub, _TEXT_ NoHandler // EAX is return address into CORCOMPILE_EXTERNAL_METHOD_THUNK. Subtract 5 to get start address. sub eax, 5 - push 0 - push 0 +.att_syntax + pushl $0 + pushl $0 +.intel_syntax noprefix push eax @@ -811,6 +817,14 @@ PATCH_LABEL ExternalMethodFixupPatchLabel NESTED_END ExternalMethodFixupStub, _TEXT #ifdef FEATURE_READYTORUN +NESTED_ENTRY DynamicHelperArgsStub, _TEXT, NoHandler + .cfi_def_cfa_offset 16 + CHECK_STACK_ALIGNMENT + call eax + add esp, 12 + ret +NESTED_END DynamicHelperArgsStub, _TEXT + // ========================================================================== NESTED_ENTRY DelayLoad_MethodCall, _TEXT, NoHandler STUB_PROLOG_2_HIDDEN_ARGS @@ -967,6 +981,7 @@ NESTED_ENTRY DelayLoad_Helper\suffix, _TEXT, NoHandler push eax // indirection cell address. push esi // pTransitionBlock + CHECK_STACK_ALIGNMENT call C_FUNC(DynamicHelperWorker) test eax,eax jnz LOCAL_LABEL(TailCallDelayLoad_Helper\suffix) diff --git a/src/vm/i386/cgenx86.cpp b/src/vm/i386/cgenx86.cpp index 4c83265ff4..14909b93e5 100644 --- a/src/vm/i386/cgenx86.cpp +++ b/src/vm/i386/cgenx86.cpp @@ -331,7 +331,6 @@ void TransitionFrame::UpdateRegDisplayHelper(const PREGDISPLAY pRD, UINT cbStack pRD->pCurrentContext->Eip = *PTR_PCODE(pRD->PCTAddr);; pRD->pCurrentContext->Esp = CallerSP; - pRD->pCurrentContext->ResumeEsp = CallerSP + cbStackPop; UpdateRegDisplayFromCalleeSavedRegisters(pRD, regs); ClearRegDisplayArgumentAndScratchRegisters(pRD); @@ -384,7 +383,7 @@ void HelperMethodFrame::UpdateRegDisplay(const PREGDISPLAY pRD) #endif // DACCESS_COMPILE pRD->pCurrentContext->Eip = pRD->ControlPC = m_MachState.GetRetAddr(); - pRD->pCurrentContext->Esp = pRD->pCurrentContext->ResumeEsp = pRD->SP = (DWORD) m_MachState.esp(); + pRD->pCurrentContext->Esp = pRD->SP = (DWORD) m_MachState.esp(); #define CALLEE_SAVED_REGISTER(regname) pRD->pCurrentContext->regname = *((DWORD*) m_MachState.p##regname()); ENUM_CALLEE_SAVED_REGISTERS(); @@ -689,7 +688,6 @@ void InlinedCallFrame::UpdateRegDisplay(const PREGDISPLAY pRD) pRD->pCurrentContext->Eip = *PTR_PCODE(pRD->PCTAddr); pRD->pCurrentContext->Esp = (DWORD) dac_cast<TADDR>(m_pCallSiteSP); - pRD->pCurrentContext->ResumeEsp = (DWORD) dac_cast<TADDR>(m_pCallSiteSP) + stackArgSize; pRD->pCurrentContext->Ebp = (DWORD) m_pCalleeSavedFP; ClearRegDisplayArgumentAndScratchRegisters(pRD); @@ -829,7 +827,7 @@ void HijackFrame::UpdateRegDisplay(const PREGDISPLAY pRD) pRD->IsCallerSPValid = FALSE; // Don't add usage of this field. This is only temporary. pRD->pCurrentContext->Eip = *PTR_PCODE(pRD->PCTAddr); - pRD->pCurrentContext->Esp = pRD->pCurrentContext->ResumeEsp = (DWORD)(pRD->PCTAddr + sizeof(TADDR)); + pRD->pCurrentContext->Esp = (DWORD)(pRD->PCTAddr + sizeof(TADDR)); #define RESTORE_REG(reg) { pRD->pCurrentContext->reg = m_Args->reg; pRD->pCurrentContextPointers->reg = &m_Args->reg; } #define CALLEE_SAVED_REGISTER(reg) RESTORE_REG(reg) @@ -908,7 +906,7 @@ void TailCallFrame::UpdateRegDisplay(const PREGDISPLAY pRD) pRD->IsCallerSPValid = FALSE; // Don't add usage of this field. This is only temporary. pRD->pCurrentContext->Eip = *PTR_PCODE(pRD->PCTAddr); - pRD->pCurrentContext->Esp = pRD->pCurrentContext->ResumeEsp = (DWORD)(pRD->PCTAddr + sizeof(TADDR)); + pRD->pCurrentContext->Esp = (DWORD)(pRD->PCTAddr + sizeof(TADDR)); UpdateRegDisplayFromCalleeSavedRegisters(pRD, &m_regs); ClearRegDisplayArgumentAndScratchRegisters(pRD); @@ -934,6 +932,14 @@ void TailCallFrame::UpdateRegDisplay(const PREGDISPLAY pRD) RETURN; } +#ifdef FEATURE_READYTORUN +void DynamicHelperFrame::UpdateRegDisplay(const PREGDISPLAY pRD) +{ + WRAPPER_NO_CONTRACT; + UpdateRegDisplayHelper(pRD, 0); +} +#endif // FEATURE_READYTORUN + //------------------------------------------------------------------------ // This is declared as returning WORD instead of PRD_TYPE because of // header issues with cgencpu.h including dbginterface.h. @@ -1878,23 +1884,47 @@ PCODE DynamicHelpers::CreateReturnIndirConst(LoaderAllocator * pAllocator, TADDR END_DYNAMIC_HELPER_EMIT(); } +EXTERN_C VOID DynamicHelperArgsStub(); + PCODE DynamicHelpers::CreateHelperWithTwoArgs(LoaderAllocator * pAllocator, TADDR arg, PCODE target) { +#ifdef UNIX_X86_ABI + BEGIN_DYNAMIC_HELPER_EMIT(18); +#else BEGIN_DYNAMIC_HELPER_EMIT(12); +#endif +#ifdef UNIX_X86_ABI + // sub esp, 8 + *p++ = 0x83; + *p++ = 0xec; + *p++ = 0x8; +#else // pop eax *p++ = 0x58; +#endif // push arg *p++ = 0x68; *(INT32 *)p = arg; p += 4; +#ifdef UNIX_X86_ABI + // mov eax, target + *p++ = 0xB8; + *(INT32 *)p = target; + p += 4; +#else // push eax *p++ = 0x50; +#endif *p++ = X86_INSTR_JMP_REL32; // jmp rel32 +#ifdef UNIX_X86_ABI + *(INT32 *)p = rel32UsingJumpStub((INT32 *)p, (PCODE)DynamicHelperArgsStub); +#else *(INT32 *)p = rel32UsingJumpStub((INT32 *)p, target); +#endif p += 4; END_DYNAMIC_HELPER_EMIT(); @@ -1902,10 +1932,21 @@ PCODE DynamicHelpers::CreateHelperWithTwoArgs(LoaderAllocator * pAllocator, TADD PCODE DynamicHelpers::CreateHelperWithTwoArgs(LoaderAllocator * pAllocator, TADDR arg, TADDR arg2, PCODE target) { +#ifdef UNIX_X86_ABI + BEGIN_DYNAMIC_HELPER_EMIT(23); +#else BEGIN_DYNAMIC_HELPER_EMIT(17); +#endif +#ifdef UNIX_X86_ABI + // sub esp, 4 + *p++ = 0x83; + *p++ = 0xec; + *p++ = 0x4; +#else // pop eax *p++ = 0x58; +#endif // push arg *p++ = 0x68; @@ -1917,11 +1958,22 @@ PCODE DynamicHelpers::CreateHelperWithTwoArgs(LoaderAllocator * pAllocator, TADD *(INT32 *)p = arg2; p += 4; +#ifdef UNIX_X86_ABI + // mov eax, target + *p++ = 0xB8; + *(INT32 *)p = target; + p += 4; +#else // push eax *p++ = 0x50; +#endif *p++ = X86_INSTR_JMP_REL32; // jmp rel32 +#ifdef UNIX_X86_ABI + *(INT32 *)p = rel32UsingJumpStub((INT32 *)p, (PCODE)DynamicHelperArgsStub); +#else *(INT32 *)p = rel32UsingJumpStub((INT32 *)p, target); +#endif p += 4; END_DYNAMIC_HELPER_EMIT(); diff --git a/src/vm/i386/ehhelpers.S b/src/vm/i386/ehhelpers.S index 43ef37fa24..7516db5019 100644 --- a/src/vm/i386/ehhelpers.S +++ b/src/vm/i386/ehhelpers.S @@ -100,4 +100,4 @@ NESTED_ENTRY CallEHFilterFunclet, _TEXT, NoHandler ret 16 -NESTED_END CallEHFunclet, _TEXT +NESTED_END CallEHFilterFunclet, _TEXT diff --git a/src/vm/i386/excepx86.cpp b/src/vm/i386/excepx86.cpp index 2c863b2ec3..8c65db75a7 100644 --- a/src/vm/i386/excepx86.cpp +++ b/src/vm/i386/excepx86.cpp @@ -1088,6 +1088,11 @@ CPFH_RealFirstPassHandler( // ExceptionContinueSearch, etc. // of the active exception. CEHelper::SetupCorruptionSeverityForActiveException(bRethrownException, bNestedException, CEHelper::ShouldTreatActiveExceptionAsNonCorrupting()); + + // Failfast if exception indicates corrupted process state + if (pExInfo->GetCorruptionSeverity() == ProcessCorrupting) + EEPOLICY_HANDLE_FATAL_ERROR(exceptionCode); + END_SO_INTOLERANT_CODE; } #endif // FEATURE_CORRUPTING_EXCEPTIONS @@ -3703,6 +3708,13 @@ AdjustContextForVirtualStub( pExceptionRecord->ExceptionAddress = (PVOID)callsite; SetIP(pContext, callsite); +#ifdef HAVE_GCCOVER + // Modify LastAVAddress saved in thread to distinguish between fake & real AV + // See comments in IsGcMarker in file excep.cpp for more details + pThread->SetLastAVAddress((LPVOID)GetIP(pContext)); +#endif + + // put ESP back to what it was before the call. SetSP(pContext, dac_cast<PCODE>(dac_cast<PTR_BYTE>(GetSP(pContext)) + sizeof(void*))); diff --git a/src/vm/i386/gmsx86.cpp b/src/vm/i386/gmsx86.cpp index 840a50d045..2852b924ab 100644 --- a/src/vm/i386/gmsx86.cpp +++ b/src/vm/i386/gmsx86.cpp @@ -1295,10 +1295,10 @@ void LazyMachState::unwindLazyState(LazyMachState* baseState, ctx.Esi = lazyState->_esi = baseState->_esi; ctx.Ebx = lazyState->_ebx = baseState->_ebx; - nonVolRegPtrs.Edi = &(lazyState->_edi); - nonVolRegPtrs.Esi = &(lazyState->_esi); - nonVolRegPtrs.Ebx = &(lazyState->_ebx); - nonVolRegPtrs.Ebp = &(lazyState->_ebp); + nonVolRegPtrs.Edi = &(baseState->_edi); + nonVolRegPtrs.Esi = &(baseState->_esi); + nonVolRegPtrs.Ebx = &(baseState->_ebx); + nonVolRegPtrs.Ebp = &(baseState->_ebp); PCODE pvControlPc; diff --git a/src/vm/jitinterface.cpp b/src/vm/jitinterface.cpp index 338c274014..5ef7700896 100644 --- a/src/vm/jitinterface.cpp +++ b/src/vm/jitinterface.cpp @@ -6921,18 +6921,7 @@ bool getILIntrinsicImplementation(MethodDesc * ftn, return true; } } - else if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__BYREF_LESSTHAN)->GetMemberDef()) - { - // Compare the two arguments - static const BYTE ilcode[] = { CEE_LDARG_0, CEE_LDARG_1, CEE_PREFIX1, (CEE_CLT & 0xFF), CEE_RET }; - methInfo->ILCode = const_cast<BYTE*>(ilcode); - methInfo->ILCodeSize = sizeof(ilcode); - methInfo->maxStack = 2; - methInfo->EHcount = 0; - methInfo->options = (CorInfoOptions)0; - return true; - } - else if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__GET_ARRAY_DATA)->GetMemberDef()) + else if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__GET_RAW_SZ_ARRAY_DATA)->GetMemberDef()) { mdToken tokArrayPinningHelper = MscorlibBinder::GetField(FIELD__ARRAY_PINNING_HELPER__M_ARRAY_DATA)->GetMemberDef(); @@ -8634,7 +8623,7 @@ CorInfoIntrinsics CEEInfo::getIntrinsicID(CORINFO_METHOD_HANDLE methodHnd, else { MethodTable * pMT = method->GetMethodTable(); - if (pMT->IsByRefLike() && pMT->GetModule()->IsSystem()) + if (pMT->GetModule()->IsSystem() && pMT->IsByRefLike()) { if (pMT->HasSameTypeDefAs(g_pByReferenceClass)) { @@ -8648,10 +8637,25 @@ CorInfoIntrinsics CEEInfo::getIntrinsicID(CORINFO_METHOD_HANDLE methodHnd, _ASSERTE(strcmp(method->GetName(), "get_Value") == 0); result = CORINFO_INTRINSIC_ByReference_Value; } - *pMustExpand = true; + if (pMustExpand != nullptr) + { + *pMustExpand = true; + } + } + else if (pMT->HasSameTypeDefAs(MscorlibBinder::GetClass(CLASS__SPAN))) + { + if (method->HasSameMethodDefAs(MscorlibBinder::GetMethod(METHOD__SPAN__GET_ITEM))) + { + result = CORINFO_INTRINSIC_Span_GetItem; + } + } + else if (pMT->HasSameTypeDefAs(MscorlibBinder::GetClass(CLASS__READONLY_SPAN))) + { + if (method->HasSameMethodDefAs(MscorlibBinder::GetMethod(METHOD__READONLY_SPAN__GET_ITEM))) + { + result = CORINFO_INTRINSIC_ReadOnlySpan_GetItem; + } } - - // TODO-SPAN: Span<T> intrinsics for optimizations } } diff --git a/src/vm/jitinterfacegen.cpp b/src/vm/jitinterfacegen.cpp index ce4c1e90e3..8d1c8cdf67 100644 --- a/src/vm/jitinterfacegen.cpp +++ b/src/vm/jitinterfacegen.cpp @@ -61,6 +61,11 @@ extern "C" void* JIT_GetSharedNonGCStaticBaseNoCtor_Slow(SIZE_T moduleDomainID, extern "C" void* JIT_GetSharedGCStaticBase_Slow(SIZE_T moduleDomainID, DWORD dwModuleClassID); extern "C" void* JIT_GetSharedGCStaticBaseNoCtor_Slow(SIZE_T moduleDomainID, DWORD dwModuleClassID); +extern "C" void* JIT_GetSharedNonGCStaticBase_SingleAppDomain(SIZE_T moduleDomainID, DWORD dwModuleClassID); +extern "C" void* JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain(SIZE_T moduleDomainID, DWORD dwModuleClassID); +extern "C" void* JIT_GetSharedGCStaticBase_SingleAppDomain(SIZE_T moduleDomainID, DWORD dwModuleClassID); +extern "C" void* JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain(SIZE_T moduleDomainID, DWORD dwModuleClassID); + #ifdef _TARGET_AMD64_ extern WriteBarrierManager g_WriteBarrierManager; #endif // _TARGET_AMD64_ @@ -283,7 +288,17 @@ void InitJITHelpers1() SetJitHelperFunction(CORINFO_HELP_MON_ENTER_STATIC, JIT_MonEnterStatic_Slow); SetJitHelperFunction(CORINFO_HELP_MON_EXIT_STATIC, JIT_MonExitStatic_Slow); } +#endif + if(IsSingleAppDomain()) + { + SetJitHelperFunction(CORINFO_HELP_GETSHARED_GCSTATIC_BASE, JIT_GetSharedGCStaticBase_SingleAppDomain); + SetJitHelperFunction(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE, JIT_GetSharedNonGCStaticBase_SingleAppDomain); + SetJitHelperFunction(CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR, JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain); + SetJitHelperFunction(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR,JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain); + } +#ifndef FEATURE_IMPLICIT_TLS + else if (gAppDomainTLSIndex >= TLS_MINIMUM_AVAILABLE) { SetJitHelperFunction(CORINFO_HELP_GETSHARED_GCSTATIC_BASE, JIT_GetSharedGCStaticBase_Slow); diff --git a/src/vm/method.cpp b/src/vm/method.cpp index a72b07b404..77a6a0d37f 100644 --- a/src/vm/method.cpp +++ b/src/vm/method.cpp @@ -2404,7 +2404,7 @@ BOOL MethodDesc::IsFCallOrIntrinsic() if (IsFCall() || IsArray()) return TRUE; - // Intrinsic methods on ByReference<T> or Span<T> + // Intrinsic methods on ByReference<T>, Span<T>, or ReadOnlySpan<T> MethodTable * pMT = GetMethodTable(); if (pMT->IsByRefLike() && pMT->GetModule()->IsSystem()) return TRUE; diff --git a/src/vm/methodtable.h b/src/vm/methodtable.h index d5cb5ba866..df60fca09d 100644 --- a/src/vm/methodtable.h +++ b/src/vm/methodtable.h @@ -414,19 +414,13 @@ struct MethodTableWriteableData }; DWORD m_dwFlags; // Lot of empty bits here. -private: /* * m_hExposedClassObject is LoaderAllocator slot index to - * a RuntimeType instance for this class. But - * do NOT use it for Arrays or remoted objects! All arrays of objects - * share the same MethodTable/EEClass. - * @GENERICS: this used to live in EEClass but now lives here because it is per-instantiation data - * only set in code:MethodTable.GetManagedClassObject + * a RuntimeType instance for this class. */ LOADERHANDLE m_hExposedClassObject; #ifdef _DEBUG -public: // to avoid verify same method table too many times when it's not changing, we cache the GC count // on which the method table is verified. When fast GC STRESS is turned on, we only verify the MT if // current GC count is bigger than the number. Note most thing which will invalidate a MT will require a diff --git a/src/vm/methodtable.inl b/src/vm/methodtable.inl index c762512bf1..9b72d24d0f 100644 --- a/src/vm/methodtable.inl +++ b/src/vm/methodtable.inl @@ -1770,10 +1770,6 @@ FORCEINLINE OBJECTREF MethodTable::GetManagedClassObjectIfExists() return NULL; } - // Only code:MethodTable::GetManagedClassObject sets m_pExposedClassObject and it insures that - // remoted objects and arrays don't get in. - _ASSERTE(!IsArray() && !IsTransparentProxy()); - COMPILER_ASSUME(retVal != NULL); return retVal; } diff --git a/src/vm/mscorlib.h b/src/vm/mscorlib.h index 244b6900ba..87927f687d 100644 --- a/src/vm/mscorlib.h +++ b/src/vm/mscorlib.h @@ -653,7 +653,9 @@ DEFINE_CLASS(NULLABLE, System, Nullable`1) DEFINE_CLASS(BYREFERENCE, System, ByReference`1) DEFINE_CLASS(SPAN, System, Span`1) +DEFINE_METHOD(SPAN, GET_ITEM, get_Item, NoSig) DEFINE_CLASS(READONLY_SPAN, System, ReadOnlySpan`1) +DEFINE_METHOD(READONLY_SPAN, GET_ITEM, get_Item, NoSig) // Keep this in sync with System.Globalization.NumberFormatInfo DEFINE_CLASS_U(Globalization, NumberFormatInfo, NumberFormatInfo) @@ -805,8 +807,7 @@ DEFINE_METHOD(JIT_HELPERS, UNSAFE_ENUM_CAST, UnsafeEnumCast, NoSi DEFINE_METHOD(JIT_HELPERS, UNSAFE_ENUM_CAST_LONG, UnsafeEnumCastLong, NoSig) DEFINE_METHOD(JIT_HELPERS, UNSAFE_CAST_TO_STACKPTR,UnsafeCastToStackPointer, NoSig) #endif // _DEBUG -DEFINE_METHOD(JIT_HELPERS, BYREF_LESSTHAN, ByRefLessThan, NoSig) -DEFINE_METHOD(JIT_HELPERS, GET_ARRAY_DATA, GetArrayData, NoSig) +DEFINE_METHOD(JIT_HELPERS, GET_RAW_SZ_ARRAY_DATA, GetRawSzArrayData, NoSig) DEFINE_CLASS(UNSAFE, CompilerServices, Unsafe) DEFINE_METHOD(UNSAFE, AS_POINTER, AsPointer, NoSig) diff --git a/src/vm/object.cpp b/src/vm/object.cpp index 1725ef7db4..3e3f6d120a 100644 --- a/src/vm/object.cpp +++ b/src/vm/object.cpp @@ -1592,6 +1592,14 @@ void STDCALL CopyValueClassArgUnchecked(ArgDestination *argDest, void* src, Meth return; } +#elif defined(_TARGET_ARM64_) + + if (argDest->IsHFA()) + { + argDest->CopyHFAStructToRegister(src, pMT->GetAlignedNumInstanceFieldBytes()); + return; + } + #endif // UNIX_AMD64_ABI && FEATURE_UNIX_AMD64_STRUCT_PASSING // destOffset is only valid for Nullable<T> passed in registers _ASSERTE(destOffset == 0); diff --git a/src/vm/object.h b/src/vm/object.h index fad5f74f39..cb3743cdb9 100644 --- a/src/vm/object.h +++ b/src/vm/object.h @@ -634,10 +634,10 @@ class Object LIMITED_METHOD_CONTRACT; SUPPORTS_DAC; - // lose GC marking bit and the pinning bit + // lose GC marking bit and the reserved bit // A method table pointer should always be aligned. During GC we set the least - // significant bit for marked objects and we set the second to least significant - // bit for pinned objects. So if we want the actual MT pointer during a GC + // significant bit for marked objects, and the second to least significant + // bit is reserved. So if we want the actual MT pointer during a GC // we must zero out the lowest 2 bits. return dac_cast<PTR_MethodTable>((dac_cast<TADDR>(m_pMethTab)) & ~((UINT_PTR)3)); } @@ -3012,8 +3012,8 @@ class SafeBuffer : SafeHandle public: static FCDECL1(UINT, SizeOfType, ReflectClassBaseObject* typeUNSAFE); static FCDECL1(UINT, AlignedSizeOfType, ReflectClassBaseObject* typeUNSAFE); - static FCDECL3(void, PtrToStructure, BYTE* ptr, FC_TypedByRef structure, UINT32 sizeofT); - static FCDECL3(void, StructureToPtr, FC_TypedByRef structure, BYTE* ptr, UINT32 sizeofT); + static FCDECL3_IVI(void, PtrToStructure, BYTE* ptr, FC_TypedByRef structure, UINT32 sizeofT); + static FCDECL3_VII(void, StructureToPtr, FC_TypedByRef structure, BYTE* ptr, UINT32 sizeofT); }; #ifdef USE_CHECKED_OBJECTREFS diff --git a/src/vm/peimagelayout.cpp b/src/vm/peimagelayout.cpp index fb2ce5760c..24166817bb 100644 --- a/src/vm/peimagelayout.cpp +++ b/src/vm/peimagelayout.cpp @@ -155,6 +155,17 @@ void PEImageLayout::ApplyBaseRelocations() { PIMAGE_BASE_RELOCATION r = (PIMAGE_BASE_RELOCATION)(dir + dirPos); + COUNT_T fixupsSize = VAL32(r->SizeOfBlock); + + USHORT *fixups = (USHORT *) (r + 1); + + _ASSERTE(fixupsSize > sizeof(IMAGE_BASE_RELOCATION)); + _ASSERTE((fixupsSize - sizeof(IMAGE_BASE_RELOCATION)) % 2 == 0); + + COUNT_T fixupsCount = (fixupsSize - sizeof(IMAGE_BASE_RELOCATION)) / 2; + + _ASSERTE((BYTE *)(fixups + fixupsCount) <= (BYTE *)(dir + dirSize)); + DWORD rva = VAL32(r->VirtualAddress); BYTE * pageAddress = (BYTE *)GetBase() + rva; @@ -172,7 +183,9 @@ void PEImageLayout::ApplyBaseRelocations() dwOldProtection = 0; } - IMAGE_SECTION_HEADER *pSection = RvaToSection(rva); + USHORT fixup = VAL16(fixups[0]); + + IMAGE_SECTION_HEADER *pSection = RvaToSection(rva + (fixup & 0xfff)); PREFIX_ASSUME(pSection != NULL); pWriteableRegion = (BYTE*)GetRvaData(VAL32(pSection->VirtualAddress)); @@ -199,17 +212,6 @@ void PEImageLayout::ApplyBaseRelocations() } } - COUNT_T fixupsSize = VAL32(r->SizeOfBlock); - - USHORT *fixups = (USHORT *) (r + 1); - - _ASSERTE(fixupsSize > sizeof(IMAGE_BASE_RELOCATION)); - _ASSERTE((fixupsSize - sizeof(IMAGE_BASE_RELOCATION)) % 2 == 0); - - COUNT_T fixupsCount = (fixupsSize - sizeof(IMAGE_BASE_RELOCATION)) / 2; - - _ASSERTE((BYTE *)(fixups + fixupsCount) <= (BYTE *)(dir + dirSize)); - for (COUNT_T fixupIndex = 0; fixupIndex < fixupsCount; fixupIndex++) { USHORT fixup = VAL16(fixups[fixupIndex]); diff --git a/src/vm/safehandle.cpp b/src/vm/safehandle.cpp index 828b221025..d79c5a749a 100644 --- a/src/vm/safehandle.cpp +++ b/src/vm/safehandle.cpp @@ -483,7 +483,7 @@ FCIMPL1(UINT, SafeBuffer::AlignedSizeOfType, ReflectClassBaseObject* typeUNSAFE) } FCIMPLEND -FCIMPL3(void, SafeBuffer::PtrToStructure, BYTE* ptr, FC_TypedByRef structure, UINT32 sizeofT) +FCIMPL3_IVI(void, SafeBuffer::PtrToStructure, BYTE* ptr, FC_TypedByRef structure, UINT32 sizeofT) { FCALL_CONTRACT; @@ -494,7 +494,7 @@ FCIMPL3(void, SafeBuffer::PtrToStructure, BYTE* ptr, FC_TypedByRef structure, UI } FCIMPLEND -FCIMPL3(void, SafeBuffer::StructureToPtr, FC_TypedByRef structure, BYTE* ptr, UINT32 sizeofT) +FCIMPL3_VII(void, SafeBuffer::StructureToPtr, FC_TypedByRef structure, BYTE* ptr, UINT32 sizeofT) { FCALL_CONTRACT; diff --git a/src/vm/siginfo.cpp b/src/vm/siginfo.cpp index b9955eca68..82aef45026 100644 --- a/src/vm/siginfo.cpp +++ b/src/vm/siginfo.cpp @@ -1199,7 +1199,10 @@ TypeHandle SigPointer::GetTypeHandleThrowing( PREFIX_ASSUME(pZapSigContext != NULL); pModule = pZapSigContext->GetZapSigModule()->GetModuleFromIndex(ix); - if (pModule != NULL) + + // For ReadyToRunCompilation we return a null TypeHandle when we reference a non-local module + // + if ((pModule != NULL) && pModule->IsInCurrentVersionBubble()) { thRet = psig.GetTypeHandleThrowing(pModule, pTypeContext, diff --git a/src/vm/stubhelpers.cpp b/src/vm/stubhelpers.cpp index 0a5c143bf4..db593c66e9 100644 --- a/src/vm/stubhelpers.cpp +++ b/src/vm/stubhelpers.cpp @@ -182,7 +182,7 @@ void StubHelpers::ProcessByrefValidationList() #endif // VERIFY_HEAP -FCIMPL1(double, StubHelpers::DateMarshaler__ConvertToNative, INT64 managedDate) +FCIMPL1_V(double, StubHelpers::DateMarshaler__ConvertToNative, INT64 managedDate) { FCALL_CONTRACT; diff --git a/src/vm/stubhelpers.h b/src/vm/stubhelpers.h index f7577d7a44..31693be38a 100644 --- a/src/vm/stubhelpers.h +++ b/src/vm/stubhelpers.h @@ -46,7 +46,7 @@ public: // PInvoke stub helpers //------------------------------------------------------- - static FCDECL1(double, DateMarshaler__ConvertToNative, INT64 managedDate); + static FCDECL1_V(double, DateMarshaler__ConvertToNative, INT64 managedDate); static FCDECL1_V(INT64, DateMarshaler__ConvertToManaged, double nativeDate); static FCDECL4(void, ValueClassMarshaler__ConvertToNative, LPVOID pDest, LPVOID pSrc, MethodTable* pMT, OBJECTREF *ppCleanupWorkListOnStack); diff --git a/src/vm/threads.cpp b/src/vm/threads.cpp index a126d1c816..c36232ecb5 100644 --- a/src/vm/threads.cpp +++ b/src/vm/threads.cpp @@ -5074,7 +5074,7 @@ void Thread::SafeUpdateLastThrownObject(void) { EX_TRY { - IGCHandleTable *pHandleTable = GCHandleTableUtilities::GetGCHandleTable(); + IGCHandleManager *pHandleTable = GCHandleUtilities::GetGCHandleManager(); // Creating a duplicate handle here ensures that the AD of the last thrown object // matches the domain of the current throwable. diff --git a/src/vm/threads.h b/src/vm/threads.h index a055f2e9e0..34fca24c4f 100644 --- a/src/vm/threads.h +++ b/src/vm/threads.h @@ -143,7 +143,7 @@ #include "mscoree.h" #include "appdomainstack.h" #include "gcheaputilities.h" -#include "gchandletableutilities.h" +#include "gchandleutilities.h" #include "gcinfotypes.h" #include <clrhost.h> @@ -6735,30 +6735,29 @@ public: Thread::TriggersGC(GetThread()); \ } while(0) +#else // ENABLE_CONTRACTS_IMPL + +#define BEGINFORBIDGC() +#define ENDFORBIDGC() +#define TRIGGERSGC_NOSTOMP() ANNOTATION_GC_TRIGGERS +#define TRIGGERSGC() ANNOTATION_GC_TRIGGERS + +#endif // ENABLE_CONTRACTS_IMPL inline BOOL GC_ON_TRANSITIONS(BOOL val) { WRAPPER_NO_CONTRACT; +#ifdef _DEBUG Thread* thread = GetThread(); if (thread == 0) return(FALSE); BOOL ret = thread->m_GCOnTransitionsOK; thread->m_GCOnTransitionsOK = val; return(ret); +#else // _DEBUG + return FALSE; +#endif // !_DEBUG } -#else // _DEBUG_IMPL - -#define BEGINFORBIDGC() -#define ENDFORBIDGC() -#define TRIGGERSGC_NOSTOMP() ANNOTATION_GC_TRIGGERS -#define TRIGGERSGC() ANNOTATION_GC_TRIGGERS - -inline BOOL GC_ON_TRANSITIONS(BOOL val) { - return FALSE; -} - -#endif // _DEBUG_IMPL - #ifdef _DEBUG inline void ENABLESTRESSHEAP() { WRAPPER_NO_CONTRACT; diff --git a/src/vm/threadsuspend.cpp b/src/vm/threadsuspend.cpp index ab1f2bbff5..65495940ed 100644 --- a/src/vm/threadsuspend.cpp +++ b/src/vm/threadsuspend.cpp @@ -7181,7 +7181,7 @@ void ThreadSuspend::RestartEE(BOOL bFinishedGC, BOOL SuspendSucceded) // // Any threads that are waiting in WaitUntilGCComplete will continue now. // - GCHeapUtilities::GetGCHeap()->GetWaitForGCEvent()->Set(); + GCHeapUtilities::GetGCHeap()->SetWaitForGCEvent(); _ASSERTE(IsGCSpecialThread() || ThreadStore::HoldingThreadStore()); ResumeRuntime(bFinishedGC, SuspendSucceded); @@ -7307,7 +7307,7 @@ retry_for_debugger: // // First, we reset the event that we're about to tell other threads to wait for. // - GCHeapUtilities::GetGCHeap()->GetWaitForGCEvent()->Reset(); + GCHeapUtilities::GetGCHeap()->ResetWaitForGCEvent(); // // Remember that we're the one doing the GC. Actually, maybe we're not doing a GC - diff --git a/src/vm/typedesc.cpp b/src/vm/typedesc.cpp index 9d84c01488..d05cb558bc 100644 --- a/src/vm/typedesc.cpp +++ b/src/vm/typedesc.cpp @@ -837,6 +837,12 @@ OBJECTREF ParamTypeDesc::GetManagedClassObject() pLoaderAllocator->ClearHandle(hExposedClassObject); } + if (OwnsTemplateMethodTable()) + { + // Set the handle on template methodtable as well to make Object.GetType for arrays take the fast path + EnsureWritablePages(m_TemplateMT.GetValue()->GetWriteableDataForWrite())->m_hExposedClassObject = m_hExposedClassObject; + } + // Log the TypeVarTypeDesc access g_IBCLogger.LogTypeMethodTableWriteableAccess(&th); diff --git a/src/vm/util.cpp b/src/vm/util.cpp index 70ed0e27ca..da7d18c390 100644 --- a/src/vm/util.cpp +++ b/src/vm/util.cpp @@ -2525,12 +2525,12 @@ HMODULE CLRGetCurrentModuleHandle() #endif // !FEATURE_PAL -extern LPVOID EEHeapAllocInProcessHeap(DWORD dwFlags, SIZE_T dwBytes); -extern BOOL EEHeapFreeInProcessHeap(DWORD dwFlags, LPVOID lpMem); -extern void ShutdownRuntimeWithoutExiting(int exitCode); -extern BOOL IsRuntimeStarted(DWORD *pdwStartupFlags); +LPVOID EEHeapAllocInProcessHeap(DWORD dwFlags, SIZE_T dwBytes); +BOOL EEHeapFreeInProcessHeap(DWORD dwFlags, LPVOID lpMem); +void ShutdownRuntimeWithoutExiting(int exitCode); +BOOL IsRuntimeStarted(DWORD *pdwStartupFlags); -void * __stdcall GetCLRFunction(LPCSTR FunctionName) +void *GetCLRFunction(LPCSTR FunctionName) { void* func = NULL; |