diff options
author | Morgan Brown <morganbr@users.noreply.github.com> | 2018-09-06 19:37:30 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-09-06 19:37:30 -0700 |
commit | 9e976d515099c7708cf26cef7520b628564f5acf (patch) | |
tree | 3a29d4011d871007e7dc24713f056aaf2af70e51 /src | |
parent | 748b5a0a5a701b7f9803021313c620413e353fdc (diff) | |
download | coreclr-9e976d515099c7708cf26cef7520b628564f5acf.tar.gz coreclr-9e976d515099c7708cf26cef7520b628564f5acf.tar.bz2 coreclr-9e976d515099c7708cf26cef7520b628564f5acf.zip |
Enable IJW Native calling managed (#19750)
* Adds back code required to make IJW native->managed calls (if the runtime is already started) and includes a simple test.
Diffstat (limited to 'src')
-rw-r--r-- | src/dlls/mscorrc/mscorrc.rc | 1 | ||||
-rw-r--r-- | src/dlls/mscorrc/resource.h | 1 | ||||
-rw-r--r-- | src/vm/ceeload.cpp | 381 | ||||
-rw-r--r-- | src/vm/ceeload.h | 9 | ||||
-rw-r--r-- | src/vm/domainfile.cpp | 4 | ||||
-rw-r--r-- | src/vm/peimage.cpp | 160 | ||||
-rw-r--r-- | src/vm/peimage.h | 44 |
7 files changed, 597 insertions, 3 deletions
diff --git a/src/dlls/mscorrc/mscorrc.rc b/src/dlls/mscorrc/mscorrc.rc index a298563cc6..713d7e0a66 100644 --- a/src/dlls/mscorrc/mscorrc.rc +++ b/src/dlls/mscorrc/mscorrc.rc @@ -1086,6 +1086,7 @@ BEGIN BFA_BAD_CA_HEADER "Malformed custom attribute header." BFA_BAD_STRING_TOKEN "Bad string token." BFA_BAD_STRING_TOKEN_RANGE "No string associated with token." + BFA_FIXUP_WRONG_PLATFORM "Image has a platform-specific fixup type that is not compatible with this platform." BFA_UNEXPECTED_GENERIC_TOKENTYPE "Token specifying generic type must be either a typeref or typedef." BFA_MDARRAY_BADRANK "Array rank may not be zero." BFA_SDARRAY_BADRANK "Single-dimensional array rank must be one." diff --git a/src/dlls/mscorrc/resource.h b/src/dlls/mscorrc/resource.h index d58780f8f9..0a42dad28e 100644 --- a/src/dlls/mscorrc/resource.h +++ b/src/dlls/mscorrc/resource.h @@ -540,6 +540,7 @@ #define BFA_BAD_CA_HEADER 0x2050 #define BFA_BAD_STRING_TOKEN 0x2052 #define BFA_BAD_STRING_TOKEN_RANGE 0x2053 +#define BFA_FIXUP_WRONG_PLATFORM 0x2054 #define BFA_UNEXPECTED_GENERIC_TOKENTYPE 0x2055 #define BFA_MDARRAY_BADRANK 0x2056 #define BFA_SDARRAY_BADRANK 0x2057 diff --git a/src/vm/ceeload.cpp b/src/vm/ceeload.cpp index b3d2d59cb3..19c5167005 100644 --- a/src/vm/ceeload.cpp +++ b/src/vm/ceeload.cpp @@ -6390,8 +6390,7 @@ MethodDesc *Module::FindMethod(mdToken pMethod) CONTRACT_VIOLATION(ThrowsViolation); char szMethodName [MAX_CLASSNAME_LENGTH]; CEEInfo::findNameOfToken(this, pMethod, szMethodName, COUNTOF (szMethodName)); - // This used to be LF_IJW, but changed to LW_INTEROP to reclaim a bit in our log facilities - // IJW itself is not supported in coreclr so this code should never be run. + // This used to be IJW, but changed to LW_INTEROP to reclaim a bit in our log facilities LOG((LF_INTEROP, LL_INFO10, "Failed to find Method: %s for Vtable Fixup\n", szMethodName)); #endif // _DEBUG } @@ -6837,7 +6836,379 @@ void Module::NotifyDebuggerUnload(AppDomain *pDomain) g_pDebugInterface->UnloadModule(this, pDomain); } +#if !defined(CROSSGEN_COMPILE) +//================================================================================= +mdToken GetTokenForVTableEntry(HINSTANCE hInst, BYTE **ppVTEntry) +{ + CONTRACTL{ + NOTHROW; + } CONTRACTL_END; + + mdToken tok =(mdToken)(UINT_PTR)*ppVTEntry; + _ASSERTE(TypeFromToken(tok) == mdtMethodDef || TypeFromToken(tok) == mdtMemberRef); + return tok; +} + +//================================================================================= +void SetTargetForVTableEntry(HINSTANCE hInst, BYTE **ppVTEntry, BYTE *pTarget) +{ + CONTRACTL{ + THROWS; + } CONTRACTL_END; + + DWORD oldProtect; + if (!ClrVirtualProtect(ppVTEntry, sizeof(BYTE*), PAGE_READWRITE, &oldProtect)) + { + + // This is very bad. We are not going to be able to update header. + _ASSERTE(!"SetTargetForVTableEntry(): VirtualProtect() changing IJW thunk vtable to R/W failed.\n"); + ThrowLastError(); + } + + *ppVTEntry = pTarget; + + DWORD ignore; + if (!ClrVirtualProtect(ppVTEntry, sizeof(BYTE*), oldProtect, &ignore)) + { + // This is not so bad, we're already done the update, we just didn't return the thunk table to read only + _ASSERTE(!"SetTargetForVTableEntry(): VirtualProtect() changing IJW thunk vtable back to RO failed.\n"); + } +} + +//================================================================================= +BYTE * GetTargetForVTableEntry(HINSTANCE hInst, BYTE **ppVTEntry) +{ + CONTRACTL{ + NOTHROW; + } CONTRACTL_END; + + return *ppVTEntry; +} + +//====================================================================================== +// Fixup vtables stored in the header to contain pointers to method desc +// prestubs rather than metadata method tokens. +void Module::FixupVTables() +{ + CONTRACTL{ + INSTANCE_CHECK; + STANDARD_VM_CHECK; + } CONTRACTL_END; + + + // If we've already fixed up, or this is not an IJW module, just return. + // NOTE: This relies on ILOnly files not having fixups. If this changes, + // we need to change this conditional. + if (IsIJWFixedUp() || m_file->IsILOnly()) { + return; + } + + HINSTANCE hInstThis = GetFile()->GetIJWBase(); + + // <REVISIT_TODO>@todo: workaround!</REVISIT_TODO> + // If we are compiling in-process, we don't want to fixup the vtables - as it + // will have side effects on the other copy of the module! + if (SystemDomain::GetCurrentDomain()->IsPassiveDomain()) { + return; + } + +#ifdef FEATURE_PREJIT + // We delayed filling in this value until the LoadLibrary occurred + if (HasTls() && HasNativeImage()) { + CORCOMPILE_EE_INFO_TABLE *pEEInfo = GetNativeImage()->GetNativeEEInfoTable(); + pEEInfo->rvaStaticTlsIndex = GetTlsIndex(); + } +#endif + // Get vtable fixup data + COUNT_T cFixupRecords; + IMAGE_COR_VTABLEFIXUP *pFixupTable = m_file->GetVTableFixups(&cFixupRecords); + + // No records then return + if (cFixupRecords == 0) { + return; + } + + // Now, we need to take a lock to serialize fixup. + PEImage::IJWFixupData *pData = PEImage::GetIJWData(m_file->GetIJWBase()); + + // If it's already been fixed (in some other appdomain), record the fact and return + if (pData->IsFixedUp()) { + SetIsIJWFixedUp(); + return; + } + + ////////////////////////////////////////////////////// + // + // This is done in three stages: + // 1. We enumerate the types we'll need to load + // 2. We load the types + // 3. We create and install the thunks + // + + COUNT_T cVtableThunks = 0; + struct MethodLoadData + { + mdToken token; + MethodDesc *pMD; + }; + MethodLoadData *rgMethodsToLoad = NULL; + COUNT_T cMethodsToLoad = 0; + + // + // Stage 1 + // + + // Each fixup entry describes a vtable, so iterate the vtables and sum their counts + { + DWORD iFixup; + for (iFixup = 0; iFixup < cFixupRecords; iFixup++) + cVtableThunks += pFixupTable[iFixup].Count; + } + + Thread *pThread = GetThread(); + StackingAllocator *pAlloc = &pThread->m_MarshalAlloc; + CheckPointHolder cph(pAlloc->GetCheckpoint()); + + // Allocate the working array of tokens. + cMethodsToLoad = cVtableThunks; + + rgMethodsToLoad = new (pAlloc) MethodLoadData[cMethodsToLoad]; + memset(rgMethodsToLoad, 0, cMethodsToLoad * sizeof(MethodLoadData)); + + // Now take the IJW module lock and get all the tokens + { + // Take the lock + CrstHolder lockHolder(pData->GetLock()); + + // If someone has beaten us, just return + if (pData->IsFixedUp()) + { + SetIsIJWFixedUp(); + return; + } + + COUNT_T iCurMethod = 0; + + if (cFixupRecords != 0) + { + for (COUNT_T iFixup = 0; iFixup < cFixupRecords; iFixup++) + { + // Vtables can be 32 or 64 bit. + if ((pFixupTable[iFixup].Type == (COR_VTABLE_PTRSIZED)) || + (pFixupTable[iFixup].Type == (COR_VTABLE_PTRSIZED | COR_VTABLE_FROM_UNMANAGED)) || + (pFixupTable[iFixup].Type == (COR_VTABLE_PTRSIZED | COR_VTABLE_FROM_UNMANAGED_RETAIN_APPDOMAIN))) + { + const BYTE** pPointers = (const BYTE **)m_file->GetVTable(pFixupTable[iFixup].RVA); + for (int iMethod = 0; iMethod < pFixupTable[iFixup].Count; iMethod++) + { + if (pData->IsMethodFixedUp(iFixup, iMethod)) + continue; + mdToken mdTok = GetTokenForVTableEntry(hInstThis, (BYTE **)(pPointers + iMethod)); + CONSISTENCY_CHECK(mdTok != mdTokenNil); + rgMethodsToLoad[iCurMethod++].token = mdTok; + } + } + } + } + + } + + // + // Stage 2 - Load the types + // + + { + for (COUNT_T iCurMethod = 0; iCurMethod < cMethodsToLoad; iCurMethod++) + { + mdToken curTok = rgMethodsToLoad[iCurMethod].token; + if (!GetMDImport()->IsValidToken(curTok)) + { + _ASSERTE(!"Invalid token in v-table fix-up table"); + ThrowHR(COR_E_BADIMAGEFORMAT); + } + + + // Find the method desc + MethodDesc *pMD; + + { + CONTRACT_VIOLATION(LoadsTypeViolation); + pMD = FindMethodThrowing(curTok); + } + + CONSISTENCY_CHECK(CheckPointer(pMD)); + rgMethodsToLoad[iCurMethod].pMD = pMD; + } + } + + // + // Stage 3 - Create the thunk data + // + { + // Take the lock + CrstHolder lockHolder(pData->GetLock()); + + // If someone has beaten us, just return + if (pData->IsFixedUp()) + { + SetIsIJWFixedUp(); + return; + } + + // This phase assumes there is only one AppDomain and that thunks + // can all safely point directly to the method in the current AppDomain + + AppDomain *pAppDomain = GetAppDomain(); + + // Used to index into rgMethodsToLoad + COUNT_T iCurMethod = 0; + + + // Each fixup entry describes a vtable (each slot contains a metadata token + // at this stage). + DWORD iFixup; + for (iFixup = 0; iFixup < cFixupRecords; iFixup++) + cVtableThunks += pFixupTable[iFixup].Count; + + DWORD dwIndex = 0; + DWORD dwThunkIndex = 0; + + // Now to fill in the thunk table. + for (iFixup = 0; iFixup < cFixupRecords; iFixup++) + { + // Tables may contain zero fixups, in which case the RVA is null, which triggers an assert + if (pFixupTable[iFixup].Count == 0) + continue; + + const BYTE** pPointers = (const BYTE **) + m_file->GetVTable(pFixupTable[iFixup].RVA); + + // Vtables can be 32 or 64 bit. + if (pFixupTable[iFixup].Type == COR_VTABLE_PTRSIZED) + { + for (int iMethod = 0; iMethod < pFixupTable[iFixup].Count; iMethod++) + { + if (pData->IsMethodFixedUp(iFixup, iMethod)) + continue; + + mdToken mdTok = rgMethodsToLoad[iCurMethod].token; + MethodDesc *pMD = rgMethodsToLoad[iCurMethod].pMD; + iCurMethod++; + +#ifdef _DEBUG + if (pMD->IsNDirect()) + { + LOG((LF_INTEROP, LL_INFO10, "[0x%lx] <-- PINV thunk for \"%s\" (target = 0x%lx)\n", + (size_t)&(pPointers[iMethod]), pMD->m_pszDebugMethodName, + (size_t)(((NDirectMethodDesc*)pMD)->GetNDirectTarget()))); + } +#endif // _DEBUG + + CONSISTENCY_CHECK(dwThunkIndex < cVtableThunks); + + // Point the local vtable slot to the thunk we created + SetTargetForVTableEntry(hInstThis, (BYTE **)&pPointers[iMethod], (BYTE *)pMD->GetMultiCallableAddrOfCode()); + + pData->MarkMethodFixedUp(iFixup, iMethod); + + dwThunkIndex++; + } + + } + else if (pFixupTable[iFixup].Type == (COR_VTABLE_PTRSIZED | COR_VTABLE_FROM_UNMANAGED) || + (pFixupTable[iFixup].Type == (COR_VTABLE_PTRSIZED | COR_VTABLE_FROM_UNMANAGED_RETAIN_APPDOMAIN))) + { + for (int iMethod = 0; iMethod < pFixupTable[iFixup].Count; iMethod++) + { + if (pData->IsMethodFixedUp(iFixup, iMethod)) + continue; + + mdToken mdTok = rgMethodsToLoad[iCurMethod].token; + MethodDesc *pMD = rgMethodsToLoad[iCurMethod].pMD; + iCurMethod++; + LOG((LF_INTEROP, LL_INFO10, "[0x%p] <-- VTable thunk for \"%s\" (pMD = 0x%p)\n", + (UINT_PTR)&(pPointers[iMethod]), pMD->m_pszDebugMethodName, pMD)); + + UMEntryThunk *pUMEntryThunk = (UMEntryThunk*)(void*)(GetDllThunkHeap()->AllocAlignedMem(sizeof(UMEntryThunk), CODE_SIZE_ALIGN)); // UMEntryThunk contains code + FillMemory(pUMEntryThunk, sizeof(*pUMEntryThunk), 0); + + UMThunkMarshInfo *pUMThunkMarshInfo = (UMThunkMarshInfo*)(void*)(GetThunkHeap()->AllocAlignedMem(sizeof(UMThunkMarshInfo), CODE_SIZE_ALIGN)); + FillMemory(pUMThunkMarshInfo, sizeof(*pUMThunkMarshInfo), 0); + + pUMThunkMarshInfo->LoadTimeInit(pMD); + pUMEntryThunk->LoadTimeInit(NULL, NULL, pUMThunkMarshInfo, pMD, pAppDomain->GetId()); + SetTargetForVTableEntry(hInstThis, (BYTE **)&pPointers[iMethod], (BYTE *)pUMEntryThunk->GetCode()); + + pData->MarkMethodFixedUp(iFixup, iMethod); + } + } + else if ((pFixupTable[iFixup].Type & COR_VTABLE_NOT_PTRSIZED) == COR_VTABLE_NOT_PTRSIZED) + { + // fixup type doesn't match the platform + THROW_BAD_FORMAT(BFA_FIXUP_WRONG_PLATFORM, this); + } + else + { + _ASSERTE(!"Unknown vtable fixup type"); + } + } + + // Indicate that this module has been fixed before releasing the lock + pData->SetIsFixedUp(); // On the data + SetIsIJWFixedUp(); // On the module + } // End of Stage 3 +} + +// Self-initializing accessor for m_pThunkHeap +LoaderHeap *Module::GetDllThunkHeap() +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + } + CONTRACTL_END; + return PEImage::GetDllThunkHeap(GetFile()->GetIJWBase()); + +} + +LoaderHeap *Module::GetThunkHeap() +{ + CONTRACT(LoaderHeap *) + { + INSTANCE_CHECK; + THROWS; + GC_NOTRIGGER; + MODE_ANY; + INJECT_FAULT(COMPlusThrowOM()); + POSTCONDITION(CheckPointer(RETVAL)); + } + CONTRACT_END + + if (!m_pThunkHeap) + { + size_t * pPrivatePCLBytes = NULL; + size_t * pGlobalPCLBytes = NULL; + + COUNTER_ONLY(pPrivatePCLBytes = &(GetPerfCounters().m_Loading.cbLoaderHeapSize)); + + LoaderHeap *pNewHeap = new LoaderHeap(VIRTUAL_ALLOC_RESERVE_GRANULARITY, // DWORD dwReserveBlockSize + 0, // DWORD dwCommitBlockSize + pPrivatePCLBytes, + ThunkHeapStubManager::g_pManager->GetRangeList(), + TRUE); // BOOL fMakeExecutable + + if (FastInterlockCompareExchangePointer(&m_pThunkHeap, pNewHeap, 0) != 0) + { + delete pNewHeap; + } + } + + RETURN m_pThunkHeap; +} +#endif // !CROSSGEN_COMPILE #ifdef FEATURE_NATIVE_IMAGE_GENERATION @@ -12492,7 +12863,11 @@ void Module::DeleteProfilingData() } #endif //FEATURE_PREJIT - +void Module::SetIsIJWFixedUp() +{ + LIMITED_METHOD_CONTRACT; + FastInterlockOr(&m_dwTransientFlags, IS_IJW_FIXED_UP); +} #ifdef FEATURE_PREJIT /* static */ diff --git a/src/vm/ceeload.h b/src/vm/ceeload.h index 73f1a8f145..d8a278e544 100644 --- a/src/vm/ceeload.h +++ b/src/vm/ceeload.h @@ -1740,6 +1740,7 @@ protected: void ApplyMetaData(); + void FixupVTables(); void FreeClassTables(); @@ -3156,6 +3157,14 @@ public: } #endif // FEATURE_PREJIT + // LoaderHeap for storing IJW thunks + PTR_LoaderHeap m_pThunkHeap; + + // Self-initializing accessor for IJW thunk heap + LoaderHeap *GetThunkHeap(); + // Self-initializing accessor for domain-independent IJW thunk heap + LoaderHeap *GetDllThunkHeap(); + void EnumRegularStaticGCRefs (AppDomain* pAppDomain, promote_func* fn, ScanContext* sc); protected: diff --git a/src/vm/domainfile.cpp b/src/vm/domainfile.cpp index 6b30ee7c3a..12d3f3c579 100644 --- a/src/vm/domainfile.cpp +++ b/src/vm/domainfile.cpp @@ -1075,6 +1075,10 @@ void DomainFile::VtableFixups() { WRAPPER_NO_CONTRACT; +#if !defined(CROSSGEN_COMPILE) + if (!GetCurrentModule()->IsResource()) + GetCurrentModule()->FixupVTables(); +#endif // !CROSSGEN_COMPILE } void DomainFile::FinishLoad() diff --git a/src/vm/peimage.cpp b/src/vm/peimage.cpp index 821dc3a8fc..6b066ff2f5 100644 --- a/src/vm/peimage.cpp +++ b/src/vm/peimage.cpp @@ -28,6 +28,8 @@ CrstStatic PEImage::s_hashLock; PtrHashMap *PEImage::s_Images = NULL; +CrstStatic PEImage::s_ijwHashLock; +PtrHashMap *PEImage::s_ijwFixupDataHash; extern LocaleID g_lcid; // fusion path comparison lcid @@ -54,6 +56,12 @@ void PEImage::Startup() LockOwner lock = { &s_hashLock, IsOwnerOfCrst }; s_Images = ::new PtrHashMap; s_Images->Init(CompareImage, FALSE, &lock); + + s_ijwHashLock.Init(CrstIJWHash, CRST_REENTRANCY); + LockOwner ijwLock = { &s_ijwHashLock, IsOwnerOfCrst }; + s_ijwFixupDataHash = ::new PtrHashMap; + s_ijwFixupDataHash->Init(CompareIJWDataBase, FALSE, &ijwLock); + PEImageLayout::Startup(); #ifdef FEATURE_USE_LCID g_lcid = MAKELCID(LOCALE_INVARIANT, SORT_DEFAULT); @@ -196,6 +204,20 @@ PEImage::~PEImage() } +/* static */ +BOOL PEImage::CompareIJWDataBase(UPTR base, UPTR mapping) +{ + CONTRACTL{ + PRECONDITION(CheckStartup()); + PRECONDITION(CheckPointer((BYTE *)(base << 1))); + PRECONDITION(CheckPointer((IJWFixupData *)mapping)); + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + } CONTRACTL_END; + + return ((BYTE *)(base << 1) == ((IJWFixupData*)mapping)->GetBase()); +} // Thread stress #if 0 @@ -686,7 +708,145 @@ void DECLSPEC_NORETURN PEImage::ThrowFormat(HRESULT hrError) EEFileLoadException::Throw(m_path, hrError); } +#if !defined(CROSSGEN_COMPILE) + +//may outlive PEImage +PEImage::IJWFixupData::IJWFixupData(void *pBase) + : m_lock(CrstIJWFixupData), + m_base(pBase), m_flags(0), m_DllThunkHeap(NULL), m_iNextFixup(0), m_iNextMethod(0) +{ + WRAPPER_NO_CONTRACT; +} + +PEImage::IJWFixupData::~IJWFixupData() +{ + WRAPPER_NO_CONTRACT; + if (m_DllThunkHeap) + delete m_DllThunkHeap; +} + + +// Self-initializing accessor for m_DllThunkHeap +LoaderHeap *PEImage::IJWFixupData::GetThunkHeap() +{ + CONTRACT(LoaderHeap *) + { + INSTANCE_CHECK; + THROWS; + GC_NOTRIGGER; + MODE_ANY; + INJECT_FAULT(COMPlusThrowOM()); + POSTCONDITION(CheckPointer(RETVAL)); + } + CONTRACT_END + + if (!m_DllThunkHeap) + { + size_t * pPrivatePCLBytes = NULL; + size_t * pGlobalPCLBytes = NULL; + + COUNTER_ONLY(pPrivatePCLBytes = &(GetPerfCounters().m_Loading.cbLoaderHeapSize)); + + LoaderHeap *pNewHeap = new LoaderHeap(VIRTUAL_ALLOC_RESERVE_GRANULARITY, // DWORD dwReserveBlockSize + 0, // DWORD dwCommitBlockSize + pPrivatePCLBytes, + ThunkHeapStubManager::g_pManager->GetRangeList(), + TRUE); // BOOL fMakeExecutable + + if (FastInterlockCompareExchangePointer((PVOID*)&m_DllThunkHeap, (VOID*)pNewHeap, (VOID*)0) != 0) + { + delete pNewHeap; + } + } + + RETURN m_DllThunkHeap; +} + +void PEImage::IJWFixupData::MarkMethodFixedUp(COUNT_T iFixup, COUNT_T iMethod) +{ + LIMITED_METHOD_CONTRACT; + // supports only sequential fixup/method + _ASSERTE((iFixup == m_iNextFixup + 1 && iMethod == 0) || //first method of the next fixup or + (iFixup == m_iNextFixup && iMethod == m_iNextMethod)); //the method that was next to fixup + + m_iNextFixup = iFixup; + m_iNextMethod = iMethod + 1; +} + +BOOL PEImage::IJWFixupData::IsMethodFixedUp(COUNT_T iFixup, COUNT_T iMethod) +{ + LIMITED_METHOD_CONTRACT; + if (iFixup < m_iNextFixup) + return TRUE; + if (iFixup > m_iNextFixup) + return FALSE; + if (iMethod < m_iNextMethod) + return TRUE; + + return FALSE; +} + +/*static */ +PTR_LoaderHeap PEImage::GetDllThunkHeap(void *pBase) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + } + CONTRACTL_END; + return GetIJWData(pBase)->GetThunkHeap(); +} + +/* static */ +PEImage::IJWFixupData *PEImage::GetIJWData(void *pBase) +{ + CONTRACTL{ + THROWS; + GC_TRIGGERS; + MODE_ANY; + INJECT_FAULT(COMPlusThrowOM();); + } CONTRACTL_END + + // Take the IJW hash lock + CrstHolder hashLockHolder(&s_ijwHashLock); + + // Try to find the data + IJWFixupData *pData = (IJWFixupData *)s_ijwFixupDataHash->LookupValue((UPTR)pBase, pBase); + + // No data, must create + if ((UPTR)pData == (UPTR)INVALIDENTRY) + { + pData = new IJWFixupData(pBase); + s_ijwFixupDataHash->InsertValue((UPTR)pBase, pData); + } + + // Return the new data + return (pData); +} + +/* static */ +void PEImage::UnloadIJWModule(void *pBase) +{ + CONTRACTL{ + NOTHROW; + GC_TRIGGERS; + MODE_ANY; + } CONTRACTL_END + + // Take the IJW hash lock + CrstHolder hashLockHolder(&s_ijwHashLock); + + // Try to delete the hash entry + IJWFixupData *pData = (IJWFixupData *)s_ijwFixupDataHash->DeleteValue((UPTR)pBase, pBase); + + // Now delete the data + if ((UPTR)pData != (UPTR)INVALIDENTRY) + delete pData; +} +#endif // !CROSSGEN_COMPILE diff --git a/src/vm/peimage.h b/src/vm/peimage.h index 22aed04b0e..f4e2924723 100644 --- a/src/vm/peimage.h +++ b/src/vm/peimage.h @@ -271,6 +271,7 @@ private: }; static BOOL CompareImage(UPTR image1, UPTR image2); + static BOOL CompareIJWDataBase(UPTR base, UPTR mapping); void DECLSPEC_NORETURN ThrowFormat(HRESULT hr); @@ -341,6 +342,49 @@ private: BOOL m_bSignatureInfoCached; HRESULT m_hrSignatureInfoStatus; DWORD m_dwSignatureInfo; + + //@TODO:workaround: Remove this when we have one PEImage per mapped image, + //@TODO:workaround: and move the lock there + // This is for IJW thunk initialization, as it is no longer guaranteed + // that the initialization will occur under the loader lock. + static CrstStatic s_ijwHashLock; + static PtrHashMap *s_ijwFixupDataHash; + +public: + class IJWFixupData + { + private: + Crst m_lock; + void *m_base; + DWORD m_flags; + PTR_LoaderHeap m_DllThunkHeap; + + // the fixup for the next iteration in FixupVTables + // we use it to make sure that we do not try to fix up the same entry twice + // if there was a pass that was aborted in the middle + COUNT_T m_iNextFixup; + COUNT_T m_iNextMethod; + + enum { + e_FIXED_UP = 0x1 + }; + + public: + IJWFixupData(void *pBase); + ~IJWFixupData(); + void *GetBase() { LIMITED_METHOD_CONTRACT; return m_base; } + Crst *GetLock() { LIMITED_METHOD_CONTRACT; return &m_lock; } + BOOL IsFixedUp() { LIMITED_METHOD_CONTRACT; return m_flags & e_FIXED_UP; } + void SetIsFixedUp() { LIMITED_METHOD_CONTRACT; m_flags |= e_FIXED_UP; } + PTR_LoaderHeap GetThunkHeap(); + void MarkMethodFixedUp(COUNT_T iFixup, COUNT_T iMethod); + BOOL IsMethodFixedUp(COUNT_T iFixup, COUNT_T iMethod); + }; + + static IJWFixupData *GetIJWData(void *pBase); + static PTR_LoaderHeap GetDllThunkHeap(void *pBase); + static void UnloadIJWModule(void *pBase); + private: DWORD m_dwPEKind; DWORD m_dwMachine; |