summaryrefslogtreecommitdiff
path: root/src/vm/loaderallocator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/loaderallocator.cpp')
-rw-r--r--src/vm/loaderallocator.cpp249
1 files changed, 143 insertions, 106 deletions
diff --git a/src/vm/loaderallocator.cpp b/src/vm/loaderallocator.cpp
index cb5f81752d..46358f79d0 100644
--- a/src/vm/loaderallocator.cpp
+++ b/src/vm/loaderallocator.cpp
@@ -701,6 +701,8 @@ BOOL QCALLTYPE LoaderAllocator::Destroy(QCall::LoaderAllocatorHandle pLoaderAllo
return ret;
} // LoaderAllocator::Destroy
+#define MAX_LOADERALLOCATOR_HANDLE 0x40000000
+
// Returns NULL if the managed LoaderAllocator object was already collected.
LOADERHANDLE LoaderAllocator::AllocateHandle(OBJECTREF value)
{
@@ -714,32 +716,6 @@ LOADERHANDLE LoaderAllocator::AllocateHandle(OBJECTREF value)
LOADERHANDLE retVal;
- GCPROTECT_BEGIN(value);
- CrstHolder ch(&m_crstLoaderAllocator);
-
- retVal = AllocateHandle_Unlocked(value);
- GCPROTECT_END();
-
- return retVal;
-}
-
-#define MAX_LOADERALLOCATOR_HANDLE 0x40000000
-
-// Returns NULL if the managed LoaderAllocator object was already collected.
-LOADERHANDLE LoaderAllocator::AllocateHandle_Unlocked(OBJECTREF valueUNSAFE)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- }
- CONTRACTL_END;
-
- _ASSERTE(m_crstLoaderAllocator.OwnedByCurrentThread());
-
- UINT_PTR retVal;
-
struct _gc
{
OBJECTREF value;
@@ -752,57 +728,106 @@ LOADERHANDLE LoaderAllocator::AllocateHandle_Unlocked(OBJECTREF valueUNSAFE)
GCPROTECT_BEGIN(gc);
- gc.value = valueUNSAFE;
+ gc.value = value;
+ // The handle table is read locklessly, be careful
+ if (IsCollectible())
{
- // The handle table is read locklessly, be careful
- if (IsCollectible())
+ gc.loaderAllocator = (LOADERALLOCATORREF)ObjectFromHandle(m_hLoaderAllocatorObjectHandle);
+ if (gc.loaderAllocator == NULL)
+ { // The managed LoaderAllocator is already collected, we cannot allocate any exposed managed objects for it
+ retVal = NULL;
+ }
+ else
{
- gc.loaderAllocator = (LOADERALLOCATORREF)ObjectFromHandle(m_hLoaderAllocatorObjectHandle);
- if (gc.loaderAllocator == NULL)
- { // The managed LoaderAllocator is already collected, we cannot allocate any exposed managed objects for it
- retVal = NULL;
- }
- else
- {
- DWORD slotsUsed = gc.loaderAllocator->GetSlotsUsed();
+ DWORD slotsUsed;
+ DWORD numComponents;
- if (slotsUsed > MAX_LOADERALLOCATOR_HANDLE)
+ do
+ {
{
- COMPlusThrowOM();
+ CrstHolder ch(&m_crstLoaderAllocator);
+
+ gc.handleTable = gc.loaderAllocator->GetHandleTable();
+
+ if (!m_freeHandleIndexesStack.IsEmpty())
+ {
+ // Reuse a handle slot that was previously freed
+ DWORD freeHandleIndex = m_freeHandleIndexesStack.Pop();
+ gc.handleTable->SetAt(freeHandleIndex, gc.value);
+ retVal = (UINT_PTR)((freeHandleIndex + 1) << 1);
+ break;
+ }
+
+ slotsUsed = gc.loaderAllocator->GetSlotsUsed();
+
+ if (slotsUsed > MAX_LOADERALLOCATOR_HANDLE)
+ {
+ COMPlusThrowOM();
+ }
+
+ numComponents = gc.handleTable->GetNumComponents();
+
+ if (slotsUsed < numComponents)
+ {
+ // The handle table is large enough, allocate next slot from it
+ gc.handleTable->SetAt(slotsUsed, gc.value);
+ gc.loaderAllocator->SetSlotsUsed(slotsUsed + 1);
+ retVal = (UINT_PTR)((slotsUsed + 1) << 1);
+ break;
+ }
}
- gc.handleTable = gc.loaderAllocator->GetHandleTable();
- /* If we need to enlarge the table, do it now. */
- if (slotsUsed >= gc.handleTable->GetNumComponents())
+ // We need to enlarge the handle table
+ gc.handleTableOld = gc.handleTable;
+
+ DWORD newSize = numComponents * 2;
+ gc.handleTable = (PTRARRAYREF)AllocateObjectArray(newSize, g_pObjectClass);
+
{
- gc.handleTableOld = gc.handleTable;
+ CrstHolder ch(&m_crstLoaderAllocator);
- DWORD newSize = gc.handleTable->GetNumComponents() * 2;
- gc.handleTable = (PTRARRAYREF)AllocateObjectArray(newSize, g_pObjectClass);
+ if (gc.loaderAllocator->GetHandleTable() == gc.handleTableOld)
+ {
+ /* Copy out of old array */
+ memmoveGCRefs(gc.handleTable->GetDataPtr(), gc.handleTableOld->GetDataPtr(), slotsUsed * sizeof(Object *));
+ gc.loaderAllocator->SetHandleTable(gc.handleTable);
+ }
+ else
+ {
+ // Another thread has beaten us on enlarging the handle array, use the handle table it has allocated
+ gc.handleTable = gc.loaderAllocator->GetHandleTable();
+ }
+
+ numComponents = gc.handleTable->GetNumComponents();
- /* Copy out of old array */
- memmoveGCRefs(gc.handleTable->GetDataPtr(), gc.handleTableOld->GetDataPtr(), slotsUsed * sizeof(Object *));
- gc.loaderAllocator->SetHandleTable(gc.handleTable);
+ if (slotsUsed < numComponents)
+ {
+ // The handle table is large enough, allocate next slot from it
+ gc.handleTable->SetAt(slotsUsed, gc.value);
+ gc.loaderAllocator->SetSlotsUsed(slotsUsed + 1);
+ retVal = (UINT_PTR)((slotsUsed + 1) << 1);
+ break;
+ }
}
- gc.handleTable->SetAt(slotsUsed, gc.value);
- gc.loaderAllocator->SetSlotsUsed(slotsUsed + 1);
- retVal = (UINT_PTR)((slotsUsed + 1) << 1);
- }
- }
- else
- {
- OBJECTREF* pRef = GetDomain()->AllocateObjRefPtrsInLargeTable(1);
- SetObjectReference(pRef, gc.value, IsDomainNeutral() ? NULL : GetDomain()->AsAppDomain());
- retVal = (((UINT_PTR)pRef) + 1);
+ // Loop in the unlikely case that another thread has beaten us on the handle array enlarging, but
+ // all the slots were used up before the current thread was scheduled.
+ }
+ while (true);
}
}
+ else
+ {
+ OBJECTREF* pRef = GetDomain()->AllocateObjRefPtrsInLargeTable(1);
+ SetObjectReference(pRef, gc.value, IsDomainNeutral() ? NULL : GetDomain()->AsAppDomain());
+ retVal = (((UINT_PTR)pRef) + 1);
+ }
GCPROTECT_END();
- return (LOADERHANDLE)retVal;
-} // LoaderAllocator::AllocateHandle_Unlocked
+ return retVal;
+}
OBJECTREF LoaderAllocator::GetHandleValue(LOADERHANDLE handle)
{
@@ -820,18 +845,32 @@ OBJECTREF LoaderAllocator::GetHandleValue(LOADERHANDLE handle)
return objRet;
}
-void LoaderAllocator::ClearHandle(LOADERHANDLE handle)
+void LoaderAllocator::FreeHandle(LOADERHANDLE handle)
{
CONTRACTL
{
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
PRECONDITION(handle != NULL);
}
CONTRACTL_END;
SetHandleValue(handle, NULL);
+
+ if ((((UINT_PTR)handle) & 1) == 0)
+ {
+ // The slot value doesn't have the low bit set, so it is an index to the handle table.
+ // In this case, push the index of the handle to the stack of freed indexes for
+ // reuse.
+ CrstHolder ch(&m_crstLoaderAllocator);
+
+ UINT_PTR index = (((UINT_PTR)handle) >> 1) - 1;
+ // The Push can fail due to OOM. Ignore this failure, it is better than crashing. The
+ // only effect is that the slot will not be reused in the future if the runtime survives
+ // the low memory situation.
+ m_freeHandleIndexesStack.Push((DWORD)index);
+ }
}
OBJECTREF LoaderAllocator::CompareExchangeValueInHandle(LOADERHANDLE handle, OBJECTREF valueUNSAFE, OBJECTREF compareUNSAFE)
@@ -860,34 +899,32 @@ OBJECTREF LoaderAllocator::CompareExchangeValueInHandle(LOADERHANDLE handle, OBJ
gc.value = valueUNSAFE;
gc.compare = compareUNSAFE;
- /* The handle table is read locklessly, be careful */
+ if ((((UINT_PTR)handle) & 1) != 0)
{
- CrstHolder ch(&m_crstLoaderAllocator);
-
- if ((((UINT_PTR)handle) & 1) != 0)
+ OBJECTREF *ptr = (OBJECTREF *)(((UINT_PTR)handle) - 1);
+ gc.previous = *ptr;
+ if ((*ptr) == gc.compare)
{
- OBJECTREF *ptr = (OBJECTREF *)(((UINT_PTR)handle) - 1);
- gc.previous = *ptr;
- if ((*ptr) == gc.compare)
- {
- SetObjectReference(ptr, gc.value, IsDomainNeutral() ? NULL : GetDomain()->AsAppDomain());
- }
+ SetObjectReference(ptr, gc.value, IsDomainNeutral() ? NULL : GetDomain()->AsAppDomain());
}
- else
- {
- _ASSERTE(!ObjectHandleIsNull(m_hLoaderAllocatorObjectHandle));
+ }
+ else
+ {
+ /* The handle table is read locklessly, be careful */
+ CrstHolder ch(&m_crstLoaderAllocator);
- UINT_PTR index = (((UINT_PTR)handle) >> 1) - 1;
- LOADERALLOCATORREF loaderAllocator = (LOADERALLOCATORREF)ObjectFromHandle(m_hLoaderAllocatorObjectHandle);
- PTRARRAYREF handleTable = loaderAllocator->GetHandleTable();
+ _ASSERTE(!ObjectHandleIsNull(m_hLoaderAllocatorObjectHandle));
- gc.previous = handleTable->GetAt(index);
- if (gc.previous == gc.compare)
- {
- handleTable->SetAt(index, gc.value);
- }
+ UINT_PTR index = (((UINT_PTR)handle) >> 1) - 1;
+ LOADERALLOCATORREF loaderAllocator = (LOADERALLOCATORREF)ObjectFromHandle(m_hLoaderAllocatorObjectHandle);
+ PTRARRAYREF handleTable = loaderAllocator->GetHandleTable();
+
+ gc.previous = handleTable->GetAt(index);
+ if (gc.previous == gc.compare)
+ {
+ handleTable->SetAt(index, gc.value);
}
- } // End critical section
+ }
retVal = gc.previous;
GCPROTECT_END();
@@ -899,35 +936,35 @@ void LoaderAllocator::SetHandleValue(LOADERHANDLE handle, OBJECTREF value)
{
CONTRACTL
{
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
PRECONDITION(handle != NULL);
}
CONTRACTL_END;
+ GCX_COOP();
+
GCPROTECT_BEGIN(value);
- // The handle table is read locklessly, be careful
+ // If the slot value does have the low bit set, then it is a simple pointer to the value
+ // Otherwise, we will need a more complicated operation to clear the value.
+ if ((((UINT_PTR)handle) & 1) != 0)
+ {
+ OBJECTREF *ptr = (OBJECTREF *)(((UINT_PTR)handle) - 1);
+ SetObjectReference(ptr, value, IsDomainNeutral() ? NULL : GetDomain()->AsAppDomain());
+ }
+ else
{
+ // The handle table is read locklessly, be careful
CrstHolder ch(&m_crstLoaderAllocator);
- // If the slot value does have the low bit set, then it is a simple pointer to the value
- // Otherwise, we will need a more complicated operation to clear the value.
- if ((((UINT_PTR)handle) & 1) != 0)
- {
- OBJECTREF *ptr = (OBJECTREF *)(((UINT_PTR)handle) - 1);
- SetObjectReference(ptr, value, IsDomainNeutral() ? NULL : GetDomain()->AsAppDomain());
- }
- else
- {
- _ASSERTE(!ObjectHandleIsNull(m_hLoaderAllocatorObjectHandle));
+ _ASSERTE(!ObjectHandleIsNull(m_hLoaderAllocatorObjectHandle));
- UINT_PTR index = (((UINT_PTR)handle) >> 1) - 1;
- LOADERALLOCATORREF loaderAllocator = (LOADERALLOCATORREF)ObjectFromHandle(m_hLoaderAllocatorObjectHandle);
- PTRARRAYREF handleTable = loaderAllocator->GetHandleTable();
- handleTable->SetAt(index, value);
- }
+ UINT_PTR index = (((UINT_PTR)handle) >> 1) - 1;
+ LOADERALLOCATORREF loaderAllocator = (LOADERALLOCATORREF)ObjectFromHandle(m_hLoaderAllocatorObjectHandle);
+ PTRARRAYREF handleTable = loaderAllocator->GetHandleTable();
+ handleTable->SetAt(index, value);
}
GCPROTECT_END();
@@ -1001,7 +1038,7 @@ void LoaderAllocator::Init(BaseDomain *pDomain, BYTE *pExecutableHeapMemory)
m_pDomain = pDomain;
- m_crstLoaderAllocator.Init(CrstLoaderAllocator);
+ m_crstLoaderAllocator.Init(CrstLoaderAllocator, (CrstFlags)CRST_UNSAFE_COOPGC);
//
// Initialize the heaps