summaryrefslogtreecommitdiff
path: root/src/vm
diff options
context:
space:
mode:
authorMorgan Brown <morganbr@users.noreply.github.com>2018-09-06 19:37:30 -0700
committerGitHub <noreply@github.com>2018-09-06 19:37:30 -0700
commit9e976d515099c7708cf26cef7520b628564f5acf (patch)
tree3a29d4011d871007e7dc24713f056aaf2af70e51 /src/vm
parent748b5a0a5a701b7f9803021313c620413e353fdc (diff)
downloadcoreclr-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/vm')
-rw-r--r--src/vm/ceeload.cpp381
-rw-r--r--src/vm/ceeload.h9
-rw-r--r--src/vm/domainfile.cpp4
-rw-r--r--src/vm/peimage.cpp160
-rw-r--r--src/vm/peimage.h44
5 files changed, 595 insertions, 3 deletions
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;