summaryrefslogtreecommitdiff
path: root/src/vm
diff options
context:
space:
mode:
authorVladimir Sadov <vsadov@microsoft.com>2019-05-02 22:16:31 -0700
committerJan Kotas <jkotas@microsoft.com>2019-05-02 22:16:31 -0700
commitb271aff1fa54c1385143f3b45c1bf3af01c901cd (patch)
tree69c76676a56a28979fd1c5c66db9d096afa98c6e /src/vm
parentdd814e26e2206c36589f88b2c58a6f3695f7dc4e (diff)
downloadcoreclr-b271aff1fa54c1385143f3b45c1bf3af01c901cd.tar.gz
coreclr-b271aff1fa54c1385143f3b45c1bf3af01c901cd.tar.bz2
coreclr-b271aff1fa54c1385143f3b45c1bf3af01c901cd.zip
System.GC.AllocateUninitializedArray (#24096)
* Do not expand to allocation_quantum in SOH when GC_ALLOC_ZEROING_OPTIONAL * short-circuit short arrays to use `new T[size]` * Clean syncblock of large-aligned objects on ARM32 * specialize single-dimensional path AllocateSzArray * Unit tests * Some PR feedback. Made AllocateUninitializedArray not be trimmed away. * PR feedback on gchelpers - replaced use of multiple bool parameters with flags enum - merged some methods with nearly identical implementation - switched callers to use AllocateSzArray vs. AllocateArrayEx where appropriate. * PR feedback. Removed X86 specific array/string allocation helpers.
Diffstat (limited to 'src/vm')
-rw-r--r--src/vm/comutilnative.cpp28
-rw-r--r--src/vm/comutilnative.h4
-rw-r--r--src/vm/crossloaderallocatorhash.inl4
-rw-r--r--src/vm/customattribute.cpp4
-rw-r--r--src/vm/ecalllist.h2
-rw-r--r--src/vm/fieldmarshaler.cpp2
-rw-r--r--src/vm/gchelpers.cpp435
-rw-r--r--src/vm/gchelpers.h90
-rw-r--r--src/vm/i386/jitinterfacex86.cpp118
-rw-r--r--src/vm/ilmarshalers.cpp4
-rw-r--r--src/vm/interpreter.cpp2
-rw-r--r--src/vm/jithelpers.cpp61
-rw-r--r--src/vm/object.h6
-rw-r--r--src/vm/qcall.cpp2
-rw-r--r--src/vm/runtimehandles.cpp14
-rw-r--r--src/vm/typeparse.cpp2
16 files changed, 288 insertions, 490 deletions
diff --git a/src/vm/comutilnative.cpp b/src/vm/comutilnative.cpp
index d8c73fcb73..46cdbad829 100644
--- a/src/vm/comutilnative.cpp
+++ b/src/vm/comutilnative.cpp
@@ -1260,6 +1260,34 @@ FCIMPL0(INT64, GCInterface::GetAllocatedBytesForCurrentThread)
}
FCIMPLEND
+/*===============================AllocateNewArray===============================
+**Action: Allocates a new array object. Allows passing extra flags
+**Returns: The allocated array.
+**Arguments: elementTypeHandle -> type of the element,
+** length -> number of elements,
+** zeroingOptional -> whether caller prefers to skip clearing the content of the array, if possible.
+**Exceptions: IDS_EE_ARRAY_DIMENSIONS_EXCEEDED when size is too large. OOM if can't allocate.
+==============================================================================*/
+FCIMPL3(Object*, GCInterface::AllocateNewArray, void* arrayTypeHandle, INT32 length, CLR_BOOL zeroingOptional)
+{
+ CONTRACTL {
+ FCALL_CHECK;
+ PRECONDITION(length >= 0);
+ } CONTRACTL_END;
+
+ OBJECTREF pRet = NULL;
+ TypeHandle arrayType = TypeHandle::FromPtr(arrayTypeHandle);
+
+ HELPER_METHOD_FRAME_BEGIN_RET_0();
+
+ pRet = AllocateSzArray(arrayType, length, zeroingOptional ? GC_ALLOC_ZEROING_OPTIONAL : GC_ALLOC_NO_FLAGS);
+
+ HELPER_METHOD_FRAME_END();
+
+ return OBJECTREFToObject(pRet);
+}
+FCIMPLEND
+
#ifdef FEATURE_BASICFREEZE
/*===============================RegisterFrozenSegment===============================
diff --git a/src/vm/comutilnative.h b/src/vm/comutilnative.h
index 67c111bbb4..24cb85e323 100644
--- a/src/vm/comutilnative.h
+++ b/src/vm/comutilnative.h
@@ -138,7 +138,9 @@ public:
static FCDECL1(void, ReRegisterForFinalize, Object *obj);
static FCDECL2(int, CollectionCount, INT32 generation, INT32 getSpecialGCCount);
- static FCDECL0(INT64, GetAllocatedBytesForCurrentThread);
+ static FCDECL0(INT64, GetAllocatedBytesForCurrentThread);
+
+ static FCDECL3(Object*, AllocateNewArray, void* elementTypeHandle, INT32 length, CLR_BOOL zeroingOptional);
#ifdef FEATURE_BASICFREEZE
static
diff --git a/src/vm/crossloaderallocatorhash.inl b/src/vm/crossloaderallocatorhash.inl
index de7f31a0ca..04a98a858b 100644
--- a/src/vm/crossloaderallocatorhash.inl
+++ b/src/vm/crossloaderallocatorhash.inl
@@ -80,7 +80,7 @@ template <class TKey_, class TValue_>
if (*pKeyValueStore == NULL)
{
- *pKeyValueStore = AllocatePrimitiveArray(ELEMENT_TYPE_I1, IsNull(value) ? sizeof(TKey) : sizeof(TKey) + sizeof(TValue), FALSE);
+ *pKeyValueStore = AllocatePrimitiveArray(ELEMENT_TYPE_I1, IsNull(value) ? sizeof(TKey) : sizeof(TKey) + sizeof(TValue));
updatedKeyValueStore = true;
TKey* pKeyLoc = (TKey*)((I1ARRAYREF)*pKeyValueStore)->GetDirectPointerToNonObjectElements();
*pKeyLoc = key;
@@ -108,7 +108,7 @@ template <class TKey_, class TValue_>
COMPlusThrow(kOverflowException);
// Allocate the new array.
- I1ARRAYREF newKeyValueStore = (I1ARRAYREF)AllocatePrimitiveArray(ELEMENT_TYPE_I1, newSize*sizeof(TValue) + sizeof(TKey), FALSE);
+ I1ARRAYREF newKeyValueStore = (I1ARRAYREF)AllocatePrimitiveArray(ELEMENT_TYPE_I1, newSize*sizeof(TValue) + sizeof(TKey));
// Since, AllocatePrimitiveArray may have triggered a GC, recapture all data pointers from GC objects
void* pStartOfNewArray = newKeyValueStore->GetDirectPointerToNonObjectElements();
diff --git a/src/vm/customattribute.cpp b/src/vm/customattribute.cpp
index 2a8d5b0236..6edda673ea 100644
--- a/src/vm/customattribute.cpp
+++ b/src/vm/customattribute.cpp
@@ -170,7 +170,7 @@ CustomAttributeManagedValues Attribute::GetManagedCaValue(CaValue* pCaVal)
if (length != (ULONG)-1)
{
- gc.array = (CaValueArrayREF)AllocateValueSzArray(MscorlibBinder::GetClass(CLASS__CUSTOM_ATTRIBUTE_ENCODED_ARGUMENT), length);
+ gc.array = (CaValueArrayREF)AllocateSzArray(TypeHandle(MscorlibBinder::GetClass(CLASS__CUSTOM_ATTRIBUTE_ENCODED_ARGUMENT)).MakeSZArray(), length);
CustomAttributeValue* pValues = gc.array->GetDirectPointerToNonObjectElements();
for (COUNT_T i = 0; i < length; i ++)
@@ -1310,7 +1310,7 @@ void COMCustomAttribute::ReadArray(Assembly *pCtorAssembly,
TypeHandle arrayHandle = ClassLoader::LoadArrayTypeThrowing(th);
if (arrayHandle.IsNull())
goto badBlob;
- *pArray = (BASEARRAYREF)AllocateArrayEx(arrayHandle, &bounds, 1);
+ *pArray = (BASEARRAYREF)AllocateSzArray(arrayHandle, bounds);
BOOL fSuccess;
switch (elementSize)
{
diff --git a/src/vm/ecalllist.h b/src/vm/ecalllist.h
index 34aead9373..4c7fffc74f 100644
--- a/src/vm/ecalllist.h
+++ b/src/vm/ecalllist.h
@@ -782,6 +782,8 @@ FCFuncStart(gGCInterfaceFuncs)
FCFuncElement("_GetAllocatedBytesForCurrentThread", GCInterface::GetAllocatedBytesForCurrentThread)
+ FCFuncElement("AllocateNewArray", GCInterface::AllocateNewArray)
+
#ifdef FEATURE_BASICFREEZE
QCFuncElement("_RegisterFrozenSegment", GCInterface::RegisterFrozenSegment)
QCFuncElement("_UnregisterFrozenSegment", GCInterface::UnregisterFrozenSegment)
diff --git a/src/vm/fieldmarshaler.cpp b/src/vm/fieldmarshaler.cpp
index a8676d65bd..0629525b02 100644
--- a/src/vm/fieldmarshaler.cpp
+++ b/src/vm/fieldmarshaler.cpp
@@ -2826,7 +2826,7 @@ VOID FieldMarshaler_FixedArray::UpdateCLRImpl(const VOID *pNativeValue, OBJECTRE
CONTRACTL_END;
// Allocate the value class array.
- *ppProtectedCLRValue = AllocateArrayEx(m_arrayType.GetValue(), (INT32*)&m_numElems, 1);
+ *ppProtectedCLRValue = AllocateSzArray(m_arrayType.GetValue(), (INT32)m_numElems);
// Marshal the contents from the native array to the managed array.
const OleVariant::Marshaler *pMarshaler = OleVariant::GetMarshalerForVarType(m_vt, TRUE);
diff --git a/src/vm/gchelpers.cpp b/src/vm/gchelpers.cpp
index fbc2cf1073..8cb4fee9b0 100644
--- a/src/vm/gchelpers.cpp
+++ b/src/vm/gchelpers.cpp
@@ -205,11 +205,11 @@ inline void CheckObjectSize(size_t alloc_size)
// While this is a choke point into allocating an object, it is primitive (it does not want to know about
// MethodTable and thus does not initialize that pointer. It also does not know if the object is finalizable
// or contains pointers. Thus we quickly wrap this function in more user-friendly ones that know about
-// MethodTables etc. (see code:FastAllocatePrimitiveArray code:AllocateArrayEx code:AllocateObject)
+// MethodTables etc. (see code:AllocateSzArray code:AllocateArrayEx code:AllocateObject)
//
// You can get an exhaustive list of code sites that allocate GC objects by finding all calls to
// code:ProfilerObjectAllocatedCallback (since the profiler has to hook them all).
-inline Object* Alloc(size_t size, BOOL bFinalize, BOOL bContainsPointers )
+inline Object* Alloc(size_t size, GC_ALLOC_FLAGS flags)
{
CONTRACTL {
THROWS;
@@ -227,8 +227,8 @@ inline Object* Alloc(size_t size, BOOL bFinalize, BOOL bContainsPointers )
}
#endif
- DWORD flags = ((bContainsPointers ? GC_ALLOC_CONTAINS_REF : 0) |
- (bFinalize ? GC_ALLOC_FINALIZE : 0));
+ if (flags & GC_ALLOC_CONTAINS_REF)
+ flags &= ~GC_ALLOC_ZEROING_OPTIONAL;
Object *retVal = NULL;
CheckObjectSize(size);
@@ -259,7 +259,7 @@ inline Object* Alloc(size_t size, BOOL bFinalize, BOOL bContainsPointers )
#ifdef FEATURE_64BIT_ALIGNMENT
// Helper for allocating 8-byte aligned objects (on platforms where this doesn't happen naturally, e.g. 32-bit
// platforms).
-inline Object* AllocAlign8(size_t size, BOOL bFinalize, BOOL bContainsPointers, BOOL bAlignBias)
+inline Object* AllocAlign8(size_t size, GC_ALLOC_FLAGS flags)
{
CONTRACTL {
THROWS;
@@ -267,9 +267,8 @@ inline Object* AllocAlign8(size_t size, BOOL bFinalize, BOOL bContainsPointers,
MODE_COOPERATIVE; // returns an objref without pinning it => cooperative
} CONTRACTL_END;
- DWORD flags = ((bContainsPointers ? GC_ALLOC_CONTAINS_REF : 0) |
- (bFinalize ? GC_ALLOC_FINALIZE : 0) |
- (bAlignBias ? GC_ALLOC_ALIGN8_BIAS : 0));
+ if (flags & GC_ALLOC_CONTAINS_REF)
+ flags &= ~ GC_ALLOC_ZEROING_OPTIONAL;
Object *retVal = NULL;
CheckObjectSize(size);
@@ -303,7 +302,7 @@ inline Object* AllocAlign8(size_t size, BOOL bFinalize, BOOL bContainsPointers,
//
// One (and only?) example of where this is needed is 8 byte aligning of arrays of doubles. See
// code:EEConfig.GetDoubleArrayToLargeObjectHeapThreshold and code:CORINFO_HELP_NEWARR_1_ALIGN8 for more.
-inline Object* AllocLHeap(size_t size, BOOL bFinalize, BOOL bContainsPointers )
+inline Object* AllocLHeap(size_t size, GC_ALLOC_FLAGS flags)
{
CONTRACTL {
THROWS;
@@ -322,8 +321,8 @@ inline Object* AllocLHeap(size_t size, BOOL bFinalize, BOOL bContainsPointers )
}
#endif
- DWORD flags = ((bContainsPointers ? GC_ALLOC_CONTAINS_REF : 0) |
- (bFinalize ? GC_ALLOC_FINALIZE : 0));
+ if (flags & GC_ALLOC_CONTAINS_REF)
+ flags &= ~GC_ALLOC_ZEROING_OPTIONAL;
Object *retVal = NULL;
CheckObjectSize(size);
@@ -408,15 +407,179 @@ inline SIZE_T MaxArrayLength(SIZE_T componentSize)
return (componentSize == 1) ? 0X7FFFFFC7 : 0X7FEFFFFF;
}
-OBJECTREF AllocateValueSzArray(TypeHandle elementType, INT32 length)
+OBJECTREF AllocateSzArray(TypeHandle arrayType, INT32 cElements, GC_ALLOC_FLAGS flags, BOOL bAllocateInLargeHeap)
{
- CONTRACTL {
+ CONTRACTL{
THROWS;
GC_TRIGGERS;
MODE_COOPERATIVE; // returns an objref without pinning it => cooperative
} CONTRACTL_END;
- return AllocateArrayEx(elementType.MakeSZArray(), &length, 1);
+ ArrayTypeDesc* arrayDesc = arrayType.AsArray();
+ MethodTable* pArrayMT = arrayDesc->GetMethodTable();
+
+ return AllocateSzArray(pArrayMT, cElements, flags, bAllocateInLargeHeap);
+}
+
+OBJECTREF AllocateSzArray(MethodTable* pArrayMT, INT32 cElements, GC_ALLOC_FLAGS flags, BOOL bAllocateInLargeHeap)
+{
+ CONTRACTL{
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE; // returns an objref without pinning it => cooperative
+ } CONTRACTL_END;
+
+ SetTypeHandleOnThreadForAlloc(TypeHandle(pArrayMT));
+
+ _ASSERTE(pArrayMT->CheckInstanceActivated());
+ _ASSERTE(pArrayMT->GetInternalCorElementType() == ELEMENT_TYPE_SZARRAY);
+
+ CorElementType elemType = pArrayMT->GetArrayElementType();
+
+ // Disallow the creation of void[] (an array of System.Void)
+ if (elemType == ELEMENT_TYPE_VOID)
+ COMPlusThrow(kArgumentException);
+
+ // IBC Log MethodTable access
+ g_IBCLogger.LogMethodTableAccess(pArrayMT);
+
+ if (cElements < 0)
+ COMPlusThrow(kOverflowException);
+
+ SIZE_T componentSize = pArrayMT->GetComponentSize();
+ if ((SIZE_T)cElements > MaxArrayLength(componentSize))
+ ThrowOutOfMemoryDimensionsExceeded();
+
+ // Allocate the space from the GC heap
+#ifdef _TARGET_64BIT_
+ // POSITIVE_INT32 * UINT16 + SMALL_CONST
+ // this cannot overflow on 64bit
+ size_t totalSize = cElements * componentSize + pArrayMT->GetBaseSize();
+
+#else
+ S_SIZE_T safeTotalSize = S_SIZE_T((DWORD)cElements) * S_SIZE_T((DWORD)componentSize) + S_SIZE_T((DWORD)pArrayMT->GetBaseSize());
+ if (safeTotalSize.IsOverflow())
+ ThrowOutOfMemoryDimensionsExceeded();
+
+ size_t totalSize = safeTotalSize.Value();
+#endif
+
+#ifdef FEATURE_DOUBLE_ALIGNMENT_HINT
+ if ((elemType == ELEMENT_TYPE_R8) &&
+ ((DWORD)cElements >= g_pConfig->GetDoubleArrayToLargeObjectHeapThreshold()))
+ {
+ STRESS_LOG2(LF_GC, LL_INFO10, "Allocating double MD array of size %d and length %d to large object heap\n", totalSize, cElements);
+ bAllocateInLargeHeap = TRUE;
+ }
+#endif
+
+ flags |= (pArrayMT->ContainsPointers() ? GC_ALLOC_CONTAINS_REF : GC_ALLOC_NO_FLAGS);
+
+ ArrayBase* orArray = NULL;
+ if (bAllocateInLargeHeap)
+ {
+ orArray = (ArrayBase*)AllocLHeap(totalSize, flags);
+ orArray->SetArrayMethodTableForLargeObject(pArrayMT);
+ }
+ else
+ {
+ if ((DATA_ALIGNMENT < sizeof(double)) && (elemType == ELEMENT_TYPE_R8))
+ {
+ // Creation of an array of doubles, not in the large object heap.
+ // We want to align the doubles to 8 byte boundaries, but the GC gives us pointers aligned
+ // to 4 bytes only (on 32 bit platforms). To align, we ask for 12 bytes more to fill with a
+ // dummy object.
+ // If the GC gives us a 8 byte aligned address, we use it for the array and place the dummy
+ // object after the array, otherwise we put the dummy object first, shifting the base of
+ // the array to an 8 byte aligned address.
+ //
+ // Note: on 64 bit platforms, the GC always returns 8 byte aligned addresses, and we don't
+ // execute this code because DATA_ALIGNMENT < sizeof(double) is false.
+
+ _ASSERTE(DATA_ALIGNMENT == sizeof(double) / 2);
+ _ASSERTE((MIN_OBJECT_SIZE % sizeof(double)) == DATA_ALIGNMENT); // used to change alignment
+ _ASSERTE(pArrayMT->GetComponentSize() == sizeof(double));
+ _ASSERTE(g_pObjectClass->GetBaseSize() == MIN_OBJECT_SIZE);
+ _ASSERTE(totalSize < totalSize + MIN_OBJECT_SIZE);
+ orArray = (ArrayBase*)Alloc(totalSize + MIN_OBJECT_SIZE, flags);
+
+ Object* orDummyObject;
+ if ((size_t)orArray % sizeof(double))
+ {
+ orDummyObject = orArray;
+ orArray = (ArrayBase*)((size_t)orArray + MIN_OBJECT_SIZE);
+ }
+ else
+ {
+ orDummyObject = (Object*)((size_t)orArray + totalSize);
+ }
+ _ASSERTE(((size_t)orArray % sizeof(double)) == 0);
+ orDummyObject->SetMethodTable(g_pObjectClass);
+ }
+ else
+ {
+#ifdef FEATURE_64BIT_ALIGNMENT
+ MethodTable* pElementMT = pArrayMT->GetApproxArrayElementTypeHandle().GetMethodTable();
+ if (pElementMT->RequiresAlign8() && pElementMT->IsValueType())
+ {
+ // This platform requires that certain fields are 8-byte aligned (and the runtime doesn't provide
+ // this guarantee implicitly, e.g. on 32-bit platforms). Since it's the array payload, not the
+ // header that requires alignment we need to be careful. However it just so happens that all the
+ // cases we care about (single and multi-dim arrays of value types) have an even number of DWORDs
+ // in their headers so the alignment requirements for the header and the payload are the same.
+ _ASSERTE(((pArrayMT->GetBaseSize() - SIZEOF_OBJHEADER) & 7) == 0);
+ orArray = (ArrayBase*)AllocAlign8(totalSize, flags);
+ }
+ else
+#endif
+ {
+ orArray = (ArrayBase*)Alloc(totalSize, flags);
+ }
+ }
+ orArray->SetArrayMethodTable(pArrayMT);
+ }
+
+ // Initialize Object
+ orArray->m_NumComponents = cElements;
+
+ if (bAllocateInLargeHeap ||
+ (totalSize >= g_pConfig->GetGCLOHThreshold()))
+ {
+ GCHeapUtilities::GetGCHeap()->PublishObject((BYTE*)orArray);
+ }
+
+#ifdef _LOGALLOC
+ LogAlloc(totalSize, pArrayMT, orArray);
+#endif // _LOGALLOC
+
+#ifdef _DEBUG
+ // Ensure the typehandle has been interned prior to allocation.
+ // This is important for OOM reliability.
+ OBJECTREF objref = ObjectToOBJECTREF((Object *) orArray);
+ GCPROTECT_BEGIN(objref);
+
+ orArray->GetTypeHandle();
+
+ GCPROTECT_END();
+ orArray = (ArrayBase *) OBJECTREFToObject(objref);
+#endif
+
+ // Notify the profiler of the allocation
+ // do this after initializing bounds so callback has size information
+ if (TrackAllocations())
+ {
+ ProfileTrackArrayAlloc(orArray);
+ }
+
+#ifdef FEATURE_EVENT_TRACE
+ // Send ETW event for allocation
+ if(ETW::TypeSystemLog::IsHeapAllocEventEnabled())
+ {
+ ETW::TypeSystemLog::SendObjectAllocatedEvent(orArray);
+ }
+#endif // FEATURE_EVENT_TRACE
+
+ return ObjectToOBJECTREF((Object *) orArray);
}
void ThrowOutOfMemoryDimensionsExceeded()
@@ -437,7 +600,7 @@ void ThrowOutOfMemoryDimensionsExceeded()
//
// This is wrapper overload to handle TypeHandle arrayType
//
-OBJECTREF AllocateArrayEx(TypeHandle arrayType, INT32 *pArgs, DWORD dwNumArgs, BOOL bAllocateInLargeHeap)
+OBJECTREF AllocateArrayEx(TypeHandle arrayType, INT32 *pArgs, DWORD dwNumArgs, GC_ALLOC_FLAGS flags, BOOL bAllocateInLargeHeap)
{
CONTRACTL
{
@@ -447,7 +610,7 @@ OBJECTREF AllocateArrayEx(TypeHandle arrayType, INT32 *pArgs, DWORD dwNumArgs, B
ArrayTypeDesc* arrayDesc = arrayType.AsArray();
MethodTable* pArrayMT = arrayDesc->GetMethodTable();
- return AllocateArrayEx(pArrayMT, pArgs, dwNumArgs, bAllocateInLargeHeap);
+ return AllocateArrayEx(pArrayMT, pArgs, dwNumArgs, flags, bAllocateInLargeHeap);
}
//
@@ -457,7 +620,7 @@ OBJECTREF AllocateArrayEx(TypeHandle arrayType, INT32 *pArgs, DWORD dwNumArgs, B
// allocate sub-arrays and fill them in.
//
// For arrays with lower bounds, pBounds is <lower bound 1>, <count 1>, <lower bound 2>, ...
-OBJECTREF AllocateArrayEx(MethodTable *pArrayMT, INT32 *pArgs, DWORD dwNumArgs, BOOL bAllocateInLargeHeap)
+OBJECTREF AllocateArrayEx(MethodTable *pArrayMT, INT32 *pArgs, DWORD dwNumArgs, GC_ALLOC_FLAGS flags, BOOL bAllocateInLargeHeap)
{
CONTRACTL {
THROWS;
@@ -505,12 +668,9 @@ OBJECTREF AllocateArrayEx(MethodTable *pArrayMT, INT32 *pArgs, DWORD dwNumArgs,
// Morph a ARRAY rank 1 with 0 lower bound into an SZARRAY
if (rank == 1 && (dwNumArgs == 1 || pArgs[0] == 0))
- { // lower bound is zero
-
- // This recursive call doesn't go any farther, because the dwNumArgs will be 1,
- // so don't bother with stack probe.
+ {
TypeHandle szArrayType = ClassLoader::LoadArrayTypeThrowing(pArrayMT->GetApproxArrayElementTypeHandle(), ELEMENT_TYPE_SZARRAY, 1);
- return AllocateArrayEx(szArrayType, &pArgs[dwNumArgs - 1], 1, bAllocateInLargeHeap);
+ return AllocateSzArray(szArrayType, pArgs[dwNumArgs - 1], flags, bAllocateInLargeHeap);
}
providedLowerBounds = (dwNumArgs == 2*rank);
@@ -554,11 +714,18 @@ OBJECTREF AllocateArrayEx(MethodTable *pArrayMT, INT32 *pArgs, DWORD dwNumArgs,
ThrowOutOfMemoryDimensionsExceeded();
// Allocate the space from the GC heap
- S_SIZE_T safeTotalSize = S_SIZE_T(cElements) * S_SIZE_T(componentSize) + S_SIZE_T(pArrayMT->GetBaseSize());
+#ifdef _TARGET_64BIT_
+ // POSITIVE_INT32 * UINT16 + SMALL_CONST
+ // this cannot overflow on 64bit
+ size_t totalSize = cElements * componentSize + pArrayMT->GetBaseSize();
+
+#else
+ S_SIZE_T safeTotalSize = S_SIZE_T((DWORD)cElements) * S_SIZE_T((DWORD)componentSize) + S_SIZE_T((DWORD)pArrayMT->GetBaseSize());
if (safeTotalSize.IsOverflow())
ThrowOutOfMemoryDimensionsExceeded();
size_t totalSize = safeTotalSize.Value();
+#endif
#ifdef FEATURE_DOUBLE_ALIGNMENT_HINT
if ((elemType == ELEMENT_TYPE_R8) &&
@@ -569,9 +736,11 @@ OBJECTREF AllocateArrayEx(MethodTable *pArrayMT, INT32 *pArgs, DWORD dwNumArgs,
}
#endif
+ flags |= (pArrayMT->ContainsPointers() ? GC_ALLOC_CONTAINS_REF : GC_ALLOC_NO_FLAGS);
+
if (bAllocateInLargeHeap)
{
- orArray = (ArrayBase *) AllocLHeap(totalSize, FALSE, pArrayMT->ContainsPointers());
+ orArray = (ArrayBase *) AllocLHeap(totalSize, flags);
orArray->SetArrayMethodTableForLargeObject(pArrayMT);
}
else
@@ -586,12 +755,12 @@ OBJECTREF AllocateArrayEx(MethodTable *pArrayMT, INT32 *pArgs, DWORD dwNumArgs,
// cases we care about (single and multi-dim arrays of value types) have an even number of DWORDs
// in their headers so the alignment requirements for the header and the payload are the same.
_ASSERTE(((pArrayMT->GetBaseSize() - SIZEOF_OBJHEADER) & 7) == 0);
- orArray = (ArrayBase *) AllocAlign8(totalSize, FALSE, pArrayMT->ContainsPointers(), FALSE);
+ orArray = (ArrayBase *) AllocAlign8(totalSize, flags);
}
else
#endif
{
- orArray = (ArrayBase *) Alloc(totalSize, FALSE, pArrayMT->ContainsPointers());
+ orArray = (ArrayBase *) Alloc(totalSize, flags);
}
orArray->SetArrayMethodTable(pArrayMT);
}
@@ -670,7 +839,7 @@ OBJECTREF AllocateArrayEx(MethodTable *pArrayMT, INT32 *pArgs, DWORD dwNumArgs,
TypeHandle subArrayType = pArrayMT->GetApproxArrayElementTypeHandle();
for (UINT32 i = 0; i < cElements; i++)
{
- OBJECTREF obj = AllocateArrayEx(subArrayType, &pArgs[1], dwNumArgs-1, bAllocateInLargeHeap);
+ OBJECTREF obj = AllocateArrayEx(subArrayType, &pArgs[1], dwNumArgs-1, flags, bAllocateInLargeHeap);
outerArray->SetAt(i, obj);
}
@@ -690,7 +859,7 @@ OBJECTREF AllocateArrayEx(MethodTable *pArrayMT, INT32 *pArgs, DWORD dwNumArgs,
/*
* Allocates a single dimensional array of primitive types.
*/
-OBJECTREF AllocatePrimitiveArray(CorElementType type, DWORD cElements, BOOL bAllocateInLargeHeap)
+OBJECTREF AllocatePrimitiveArray(CorElementType type, DWORD cElements)
{
CONTRACTL
{
@@ -701,7 +870,6 @@ OBJECTREF AllocatePrimitiveArray(CorElementType type, DWORD cElements, BOOL bA
}
CONTRACTL_END
-
// Allocating simple primite arrays is done in various places as internal storage.
// Because this is unlikely to result in any bad recursions, we will override the type limit
// here rather forever chase down all the callers.
@@ -716,139 +884,13 @@ OBJECTREF AllocatePrimitiveArray(CorElementType type, DWORD cElements, BOOL bA
TypeHandle typHnd = ClassLoader::LoadArrayTypeThrowing(elemType, ELEMENT_TYPE_SZARRAY, 0);
g_pPredefinedArrayTypes[type] = typHnd.AsArray();
}
- return FastAllocatePrimitiveArray(g_pPredefinedArrayTypes[type]->GetMethodTable(), cElements, bAllocateInLargeHeap);
-}
-
-/*
- * Allocates a single dimensional array of primitive types.
- */
-
-OBJECTREF FastAllocatePrimitiveArray(MethodTable* pMT, DWORD cElements, BOOL bAllocateInLargeHeap)
-{
- CONTRACTL {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE; // returns an objref without pinning it => cooperative
- PRECONDITION(pMT->CheckInstanceActivated());
- } CONTRACTL_END;
-
-#ifdef _DEBUG
- if (g_pConfig->ShouldInjectFault(INJECTFAULT_GCHEAP))
- {
- char *a = new char;
- delete a;
- }
-#endif
-
- _ASSERTE(pMT && pMT->IsArray());
- _ASSERTE(pMT->IsRestored_NoLogging());
- _ASSERTE(CorTypeInfo::IsPrimitiveType(pMT->GetArrayElementType()) &&
- g_pPredefinedArrayTypes[pMT->GetArrayElementType()] != NULL);
-
- g_IBCLogger.LogMethodTableAccess(pMT);
- SetTypeHandleOnThreadForAlloc(TypeHandle(pMT));
-
- SIZE_T componentSize = pMT->GetComponentSize();
- if (cElements > MaxArrayLength(componentSize))
- ThrowOutOfMemory();
-
- S_SIZE_T safeTotalSize = S_SIZE_T(cElements) * S_SIZE_T(componentSize) + S_SIZE_T(pMT->GetBaseSize());
- if (safeTotalSize.IsOverflow())
- ThrowOutOfMemory();
-
- size_t totalSize = safeTotalSize.Value();
-
- BOOL bPublish = bAllocateInLargeHeap;
-
- ArrayBase* orObject;
- if (bAllocateInLargeHeap)
- {
- orObject = (ArrayBase*) AllocLHeap(totalSize, FALSE, FALSE);
- }
- else
- {
- ArrayTypeDesc *pArrayR8TypeDesc = g_pPredefinedArrayTypes[ELEMENT_TYPE_R8];
- if (DATA_ALIGNMENT < sizeof(double) && pArrayR8TypeDesc != NULL && pMT == pArrayR8TypeDesc->GetMethodTable() &&
- (totalSize < g_pConfig->GetGCLOHThreshold() - MIN_OBJECT_SIZE))
- {
- // Creation of an array of doubles, not in the large object heap.
- // We want to align the doubles to 8 byte boundaries, but the GC gives us pointers aligned
- // to 4 bytes only (on 32 bit platforms). To align, we ask for 12 bytes more to fill with a
- // dummy object.
- // If the GC gives us a 8 byte aligned address, we use it for the array and place the dummy
- // object after the array, otherwise we put the dummy object first, shifting the base of
- // the array to an 8 byte aligned address.
- // Note: on 64 bit platforms, the GC always returns 8 byte aligned addresses, and we don't
- // execute this code because DATA_ALIGNMENT < sizeof(double) is false.
-
- _ASSERTE(DATA_ALIGNMENT == sizeof(double)/2);
- _ASSERTE((MIN_OBJECT_SIZE % sizeof(double)) == DATA_ALIGNMENT); // used to change alignment
- _ASSERTE(pMT->GetComponentSize() == sizeof(double));
- _ASSERTE(g_pObjectClass->GetBaseSize() == MIN_OBJECT_SIZE);
- _ASSERTE(totalSize < totalSize + MIN_OBJECT_SIZE);
- orObject = (ArrayBase*) Alloc(totalSize + MIN_OBJECT_SIZE, FALSE, FALSE);
-
- Object *orDummyObject;
- if((size_t)orObject % sizeof(double))
- {
- orDummyObject = orObject;
- orObject = (ArrayBase*) ((size_t)orObject + MIN_OBJECT_SIZE);
- }
- else
- {
- orDummyObject = (Object*) ((size_t)orObject + totalSize);
- }
- _ASSERTE(((size_t)orObject % sizeof(double)) == 0);
- orDummyObject->SetMethodTable(g_pObjectClass);
- }
- else
- {
- orObject = (ArrayBase*) Alloc(totalSize, FALSE, FALSE);
- bPublish = (totalSize >= g_pConfig->GetGCLOHThreshold());
- }
- }
-
- // Initialize Object
- orObject->SetArrayMethodTable( pMT );
- _ASSERTE(orObject->GetMethodTable() != NULL);
- orObject->m_NumComponents = cElements;
-
- if (bPublish)
- {
- GCHeapUtilities::GetGCHeap()->PublishObject((BYTE*)orObject);
- }
-
- // Notify the profiler of the allocation
- if (TrackAllocations())
- {
- OBJECTREF objref = ObjectToOBJECTREF((Object*)orObject);
- GCPROTECT_BEGIN(objref);
- ProfilerObjectAllocatedCallback(objref, (ClassID) orObject->GetTypeHandle().AsPtr());
- GCPROTECT_END();
-
- orObject = (ArrayBase *) OBJECTREFToObject(objref);
- }
-
-#ifdef FEATURE_EVENT_TRACE
- // Send ETW event for allocation
- if(ETW::TypeSystemLog::IsHeapAllocEventEnabled())
- {
- ETW::TypeSystemLog::SendObjectAllocatedEvent(orObject);
- }
-#endif // FEATURE_EVENT_TRACE
-
- // IBC Log MethodTable access
- g_IBCLogger.LogMethodTableAccess(pMT);
-
- LogAlloc(totalSize, pMT, orObject);
-
- return( ObjectToOBJECTREF((Object*)orObject) );
+ return AllocateSzArray(g_pPredefinedArrayTypes[type]->GetMethodTable(), cElements);
}
//
// Allocate an array which is the same size as pRef. However, do not zero out the array.
//
-OBJECTREF DupArrayForCloning(BASEARRAYREF pRef, BOOL bAllocateInLargeHeap)
+OBJECTREF DupArrayForCloning(BASEARRAYREF pRef)
{
CONTRACTL {
THROWS;
@@ -877,61 +919,14 @@ OBJECTREF DupArrayForCloning(BASEARRAYREF pRef, BOOL bAllocateInLargeHeap)
numArgs = 1;
args[0] = pRef->GetNumComponents();
}
- return AllocateArrayEx(TypeHandle(&arrayType), args, numArgs, bAllocateInLargeHeap);
-}
-
-#if defined(_TARGET_X86_)
-
-// The fast version always allocates in the normal heap
-OBJECTREF AllocatePrimitiveArray(CorElementType type, DWORD cElements)
-{
- CONTRACTL {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE; // returns an objref without pinning it => cooperative
- } CONTRACTL_END;
-
- return OBJECTREF( HCCALL2(fastPrimitiveArrayAllocator, type, cElements) );
+ return AllocateArrayEx(TypeHandle(&arrayType), args, numArgs, GC_ALLOC_ZEROING_OPTIONAL);
}
-// The fast version always allocates in the normal heap
-OBJECTREF AllocateObjectArray(DWORD cElements, TypeHandle ElementType)
-{
- CONTRACTL {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE; // returns an objref without pinning it => cooperative
- } CONTRACTL_END;
-
-
- OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
-
- // We must call this here to ensure the typehandle for this object is
- // interned before the object is allocated. As soon as the object is allocated,
- // the profiler could do a heapwalk and it expects to find an interned
- // typehandle for every object in the heap.
- TypeHandle ArrayType = ClassLoader::LoadArrayTypeThrowing(ElementType);
-
- return OBJECTREF( HCCALL2(fastObjectArrayAllocator, ArrayType.AsArray()->GetTemplateMethodTable(), cElements));
-}
-
-STRINGREF AllocateString( DWORD cchStringLength )
-{
- CONTRACTL {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE; // returns an objref without pinning it => cooperative
- } CONTRACTL_END;
-
- return STRINGREF(HCCALL1(fastStringAllocator, cchStringLength));
-}
-
-#endif
//
// Helper for parts of the EE which are allocating arrays
//
-OBJECTREF AllocateObjectArray(DWORD cElements, TypeHandle elementType, BOOL bAllocateInLargeHeap)
+OBJECTREF AllocateObjectArray(DWORD cElements, TypeHandle elementType, BOOL bAllocateInLargeHeap)
{
CONTRACTL {
THROWS;
@@ -950,14 +945,10 @@ OBJECTREF AllocateObjectArray(DWORD cElements, TypeHandle elementType, BOOL bA
_ASSERTE(arrayType.GetInternalCorElementType() == ELEMENT_TYPE_SZARRAY);
#endif //_DEBUG
- return AllocateArrayEx(ClassLoader::LoadArrayTypeThrowing(elementType),
- (INT32 *)(&cElements),
- 1,
- bAllocateInLargeHeap);
+ return AllocateSzArray(ClassLoader::LoadArrayTypeThrowing(elementType), (INT32) cElements, GC_ALLOC_NO_FLAGS, bAllocateInLargeHeap);
}
-
-STRINGREF SlowAllocateString( DWORD cchStringLength )
+STRINGREF AllocateString( DWORD cchStringLength )
{
CONTRACTL {
THROWS;
@@ -978,7 +969,7 @@ STRINGREF SlowAllocateString( DWORD cchStringLength )
// Limit the maximum string size to <2GB to mitigate risk of security issues caused by 32-bit integer
// overflows in buffer size calculations.
//
- // If the value below is changed, also change SlowAllocateUtf8String.
+ // If the value below is changed, also change AllocateUtf8String.
if (cchStringLength > 0x3FFFFFDF)
ThrowOutOfMemory();
@@ -987,7 +978,7 @@ STRINGREF SlowAllocateString( DWORD cchStringLength )
SetTypeHandleOnThreadForAlloc(TypeHandle(g_pStringClass));
- orObject = (StringObject *)Alloc( ObjectSize, FALSE, FALSE );
+ orObject = (StringObject *)Alloc( ObjectSize, GC_ALLOC_NO_FLAGS);
// Object is zero-init already
_ASSERTE( orObject->HasEmptySyncBlockInfo() );
@@ -1027,7 +1018,7 @@ STRINGREF SlowAllocateString( DWORD cchStringLength )
}
#ifdef FEATURE_UTF8STRING
-UTF8STRINGREF SlowAllocateUtf8String(DWORD cchStringLength)
+UTF8STRINGREF AllocateUtf8String(DWORD cchStringLength)
{
CONTRACTL{
THROWS;
@@ -1062,7 +1053,7 @@ UTF8STRINGREF SlowAllocateUtf8String(DWORD cchStringLength)
SetTypeHandleOnThreadForAlloc(TypeHandle(g_pUtf8StringClass));
- orObject = (Utf8StringObject *)Alloc(ObjectSize, FALSE, FALSE);
+ orObject = (Utf8StringObject *)Alloc(ObjectSize, GC_ALLOC_NO_FLAGS);
// Object is zero-init already
_ASSERTE(orObject->HasEmptySyncBlockInfo());
@@ -1176,6 +1167,8 @@ OBJECTREF AllocateObject(MethodTable *pMT
#endif // FEATURE_COMINTEROP
{
DWORD baseSize = pMT->GetBaseSize();
+ GC_ALLOC_FLAGS flags = ((pMT->ContainsPointers() ? GC_ALLOC_CONTAINS_REF : GC_ALLOC_NO_FLAGS) |
+ (pMT->HasFinalizer() ? GC_ALLOC_FINALIZE : GC_ALLOC_NO_FLAGS));
#ifdef FEATURE_64BIT_ALIGNMENT
if (pMT->RequiresAlign8())
@@ -1187,17 +1180,13 @@ OBJECTREF AllocateObject(MethodTable *pMT
// first field is aligned relative to the header) and true for boxed value types (where we can't
// do the same padding without introducing more complexity in type layout and unboxing stubs).
_ASSERTE(sizeof(Object) == 4);
- orObject = (Object *) AllocAlign8(baseSize,
- pMT->HasFinalizer(),
- pMT->ContainsPointers(),
- pMT->IsValueType());
+ flags |= pMT->IsValueType() ? GC_ALLOC_ALIGN8_BIAS : GC_ALLOC_NO_FLAGS;
+ orObject = (Object *) AllocAlign8(baseSize, flags);
}
else
#endif // FEATURE_64BIT_ALIGNMENT
{
- orObject = (Object *) Alloc(baseSize,
- pMT->HasFinalizer(),
- pMT->ContainsPointers());
+ orObject = (Object*)Alloc(baseSize, flags);
}
// verify zero'd memory (at least for sync block)
diff --git a/src/vm/gchelpers.h b/src/vm/gchelpers.h
index 33a94270fc..5fe51ce6c7 100644
--- a/src/vm/gchelpers.h
+++ b/src/vm/gchelpers.h
@@ -20,94 +20,28 @@
//
//========================================================================
-OBJECTREF AllocateValueSzArray(TypeHandle elementType, INT32 length);
- // The main Array allocation routine, can do multi-dimensional
-OBJECTREF AllocateArrayEx(MethodTable *pArrayMT, INT32 *pArgs, DWORD dwNumArgs, BOOL bAllocateInLargeHeap = FALSE);
-OBJECTREF AllocateArrayEx(TypeHandle arrayClass, INT32 *pArgs, DWORD dwNumArgs, BOOL bAllocateInLargeHeap = FALSE);
- // Optimized verion of above
-OBJECTREF FastAllocatePrimitiveArray(MethodTable* arrayType, DWORD cElements, BOOL bAllocateInLargeHeap = FALSE);
+// Allocate single-dimensional array given array type
+OBJECTREF AllocateSzArray(MethodTable *pArrayMT, INT32 length, GC_ALLOC_FLAGS flags = GC_ALLOC_NO_FLAGS, BOOL bAllocateInLargeHeap = FALSE);
+OBJECTREF AllocateSzArray(TypeHandle arrayType, INT32 length, GC_ALLOC_FLAGS flags = GC_ALLOC_NO_FLAGS, BOOL bAllocateInLargeHeap = FALSE);
+// The main Array allocation routine, can do multi-dimensional
+OBJECTREF AllocateArrayEx(MethodTable *pArrayMT, INT32 *pArgs, DWORD dwNumArgs, GC_ALLOC_FLAGS flags = GC_ALLOC_NO_FLAGS, BOOL bAllocateInLargeHeap = FALSE);
+OBJECTREF AllocateArrayEx(TypeHandle arrayType, INT32 *pArgs, DWORD dwNumArgs, GC_ALLOC_FLAGS flags = GC_ALLOC_NO_FLAGS, BOOL bAllocateInLargeHeap = FALSE);
-#if defined(_TARGET_X86_)
-
- // for x86, we generate efficient allocators for some special cases
- // these are called via inline wrappers that call the generated allocators
- // via function pointers.
-
-
- // Create a SD array of primitive types
-typedef HCCALL2_PTR(Object*, FastPrimitiveArrayAllocatorFuncPtr, CorElementType type, DWORD cElements);
-
-extern FastPrimitiveArrayAllocatorFuncPtr fastPrimitiveArrayAllocator;
-
- // The fast version always allocates in the normal heap
+// Create a SD array of primitive types given an element type
OBJECTREF AllocatePrimitiveArray(CorElementType type, DWORD cElements);
- // The slow version is distinguished via overloading by an additional parameter
-OBJECTREF AllocatePrimitiveArray(CorElementType type, DWORD cElements, BOOL bAllocateInLargeHeap);
-
-
-// Allocate SD array of object pointers.
-typedef HCCALL2_PTR(Object*, FastObjectArrayAllocatorFuncPtr, MethodTable *pArrayMT, DWORD cElements);
-
-extern FastObjectArrayAllocatorFuncPtr fastObjectArrayAllocator;
-
- // The fast version always allocates in the normal heap
-OBJECTREF AllocateObjectArray(DWORD cElements, TypeHandle ElementType);
-
- // The slow version is distinguished via overloading by an additional parameter
-OBJECTREF AllocateObjectArray(DWORD cElements, TypeHandle ElementType, BOOL bAllocateInLargeHeap);
-
-
- // Allocate string
-typedef HCCALL1_PTR(StringObject*, FastStringAllocatorFuncPtr, DWORD cchArrayLength);
-
-extern FastStringAllocatorFuncPtr fastStringAllocator;
-
-STRINGREF AllocateString( DWORD cchStringLength );
-
- // The slow version, implemented in gcscan.cpp
-STRINGREF SlowAllocateString( DWORD cchStringLength );
-
-#ifdef FEATURE_UTF8STRING
-UTF8STRINGREF SlowAllocateUtf8String( DWORD cchStringLength );
-#endif // FEATURE_UTF8STRING
-
-#else
-
-// On other platforms, go to the (somewhat less efficient) implementations in gcscan.cpp
-
- // Create a SD array of primitive types
-OBJECTREF AllocatePrimitiveArray(CorElementType type, DWORD cElements, BOOL bAllocateInLargeHeap = FALSE);
-
- // Allocate SD array of object pointers
+// Allocate SD array of object types given an element type
OBJECTREF AllocateObjectArray(DWORD cElements, TypeHandle ElementType, BOOL bAllocateInLargeHeap = FALSE);
-STRINGREF SlowAllocateString( DWORD cchStringLength );
-
-#ifdef FEATURE_UTF8STRING
-UTF8STRINGREF SlowAllocateUtf8String( DWORD cchStringLength );
-#endif // FEATURE_UTF8STRING
-
-inline STRINGREF AllocateString( DWORD cchStringLength )
-{
- WRAPPER_NO_CONTRACT;
-
- return SlowAllocateString( cchStringLength );
-}
-
-#endif
+// Allocate a string
+STRINGREF AllocateString( DWORD cchStringLength );
#ifdef FEATURE_UTF8STRING
-inline UTF8STRINGREF AllocateUtf8String(DWORD cchStringLength)
-{
- WRAPPER_NO_CONTRACT;
-
- return SlowAllocateUtf8String(cchStringLength);
-}
+UTF8STRINGREF AllocateUtf8String( DWORD cchStringLength );
#endif // FEATURE_UTF8STRING
-OBJECTREF DupArrayForCloning(BASEARRAYREF pRef, BOOL bAllocateInLargeHeap = FALSE);
+OBJECTREF DupArrayForCloning(BASEARRAYREF pRef);
// The JIT requests the EE to specify an allocation helper to use at each new-site.
// The EE makes this choice based on whether context boundaries may be involved,
diff --git a/src/vm/i386/jitinterfacex86.cpp b/src/vm/i386/jitinterfacex86.cpp
index 68cf72d8d8..2444a7bf9f 100644
--- a/src/vm/i386/jitinterfacex86.cpp
+++ b/src/vm/i386/jitinterfacex86.cpp
@@ -45,7 +45,6 @@ public:
OBJ_ARRAY = 0x4,
ALIGN8 = 0x8, // insert a dummy object to insure 8 byte alignment (until the next GC)
ALIGN8OBJ = 0x10,
- NO_FRAME = 0x20, // call is from unmanaged code - don't try to put up a frame
};
static void *GenAllocSFast(Flags flags);
@@ -767,47 +766,6 @@ void *JIT_TrialAlloc::GenBox(Flags flags)
return (void *)pStub->GetEntryPoint();
}
-
-HCIMPL2_RAW(Object*, UnframedAllocateObjectArray, MethodTable *pArrayMT, DWORD cElements)
-{
- // This isn't _really_ an FCALL and therefore shouldn't have the
- // SO_TOLERANT part of the FCALL_CONTRACT b/c it is not entered
- // from managed code.
- CONTRACTL {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- } CONTRACTL_END;
-
- return OBJECTREFToObject(AllocateArrayEx(pArrayMT,
- (INT32 *)(&cElements),
- 1,
- FALSE));
-}
-HCIMPLEND_RAW
-
-
-HCIMPL2_RAW(Object*, UnframedAllocatePrimitiveArray, CorElementType type, DWORD cElements)
-{
- // This isn't _really_ an FCALL and therefore shouldn't have the
- // SO_TOLERANT part of the FCALL_CONTRACT b/c it is not entered
- // from managed code.
- CONTRACTL {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- } CONTRACTL_END;
-
- return OBJECTREFToObject( AllocatePrimitiveArray(type, cElements, FALSE) );
-}
-HCIMPLEND_RAW
-
-HCIMPL1_RAW(PTR_MethodTable, UnframedGetTemplateMethodTable, ArrayTypeDesc *arrayDesc)
-{
- return arrayDesc->GetTemplateMethodTable();
-}
-HCIMPLEND_RAW
-
void *JIT_TrialAlloc::GenAllocArray(Flags flags)
{
STANDARD_VM_CONTRACT;
@@ -832,29 +790,6 @@ void *JIT_TrialAlloc::GenAllocArray(Flags flags)
// push edx
sl.X86EmitPushReg(kEDX);
- if (flags & NO_FRAME)
- {
- if ((flags & OBJ_ARRAY) == 0)
- {
- // mov ecx,[g_pPredefinedArrayTypes+ecx*4]
- sl.Emit8(0x8b);
- sl.Emit16(0x8d0c);
- sl.Emit32((int)(size_t)&g_pPredefinedArrayTypes);
-
- // test ecx,ecx
- sl.Emit16(0xc985);
-
- // je noLock
- sl.X86EmitCondJump(noLock, X86CondCode::kJZ);
-
- sl.X86EmitPushReg(kEDX);
- sl.X86EmitCall(sl.NewExternalCodeLabel((LPVOID)UnframedGetTemplateMethodTable), 0);
- sl.X86EmitPopReg(kEDX);
-
- sl.X86EmitMovRegReg(kECX, kEAX);
- }
- }
-
// Do a conservative check here. This is to avoid doing overflow checks within this function. We'll
// still have to do a size check before running through the body of EmitCore. The way we do the check
// against the allocation quantum there requires that we not overflow when adding the size to the
@@ -979,28 +914,9 @@ void *JIT_TrialAlloc::GenAllocArray(Flags flags)
// pop ecx - array method table
sl.X86EmitPopReg(kECX);
- CodeLabel * target;
- if (flags & NO_FRAME)
- {
- if (flags & OBJ_ARRAY)
- {
- // Jump to the unframed helper
- target = sl.NewExternalCodeLabel((LPVOID)UnframedAllocateObjectArray);
- _ASSERTE(target->e.m_pExternalAddress);
- }
- else
- {
- // Jump to the unframed helper
- target = sl.NewExternalCodeLabel((LPVOID)UnframedAllocatePrimitiveArray);
- _ASSERTE(target->e.m_pExternalAddress);
- }
- }
- else
- {
- // Jump to the framed helper
- target = sl.NewExternalCodeLabel((LPVOID)JIT_NewArr1);
- _ASSERTE(target->e.m_pExternalAddress);
- }
+ // Jump to the framed helper
+ CodeLabel * target = sl.NewExternalCodeLabel((LPVOID)JIT_NewArr1);
+ _ASSERTE(target->e.m_pExternalAddress);
sl.X86EmitNearJump(target);
Stub *pStub = sl.Link(SystemDomain::GetGlobalLoaderAllocator()->GetExecutableHeap());
@@ -1087,31 +1003,14 @@ void *JIT_TrialAlloc::GenAllocString(Flags flags)
// pop ecx - element count
sl.X86EmitPopReg(kECX);
- CodeLabel * target;
- if (flags & NO_FRAME)
- {
- // Jump to the unframed helper
- target = sl.NewExternalCodeLabel((LPVOID)UnframedAllocateString);
- }
- else
- {
- // Jump to the framed helper
- target = sl.NewExternalCodeLabel((LPVOID)FramedAllocateString);
- }
+ // Jump to the framed helper
+ CodeLabel * target = sl.NewExternalCodeLabel((LPVOID)FramedAllocateString);
sl.X86EmitNearJump(target);
Stub *pStub = sl.Link(SystemDomain::GetGlobalLoaderAllocator()->GetExecutableHeap());
return (void *)pStub->GetEntryPoint();
}
-
-
-FastStringAllocatorFuncPtr fastStringAllocator = UnframedAllocateString;
-
-FastObjectArrayAllocatorFuncPtr fastObjectArrayAllocator = UnframedAllocateObjectArray;
-
-FastPrimitiveArrayAllocatorFuncPtr fastPrimitiveArrayAllocator = UnframedAllocatePrimitiveArray;
-
// For this helper,
// If bCCtorCheck == true
// ECX contains the domain neutral module ID
@@ -1350,16 +1249,9 @@ void InitJITHelpers1()
pMethodAddresses[5] = JIT_TrialAlloc::GenAllocArray((JIT_TrialAlloc::Flags)(flags|JIT_TrialAlloc::ALIGN8));
SetJitHelperFunction(CORINFO_HELP_NEWARR_1_ALIGN8, pMethodAddresses[5]);
- fastObjectArrayAllocator = (FastObjectArrayAllocatorFuncPtr)JIT_TrialAlloc::GenAllocArray((JIT_TrialAlloc::Flags)(flags|JIT_TrialAlloc::NO_FRAME|JIT_TrialAlloc::OBJ_ARRAY));
- fastPrimitiveArrayAllocator = (FastPrimitiveArrayAllocatorFuncPtr)JIT_TrialAlloc::GenAllocArray((JIT_TrialAlloc::Flags)(flags|JIT_TrialAlloc::NO_FRAME));
-
// If allocation logging is on, then we divert calls to FastAllocateString to an Ecall method, not this
// generated method. Find this workaround in Ecall::Init() in ecall.cpp.
ECall::DynamicallyAssignFCallImpl((PCODE) JIT_TrialAlloc::GenAllocString(flags), ECall::FastAllocateString);
-
- // generate another allocator for use from unmanaged code (won't need a frame)
- fastStringAllocator = (FastStringAllocatorFuncPtr) JIT_TrialAlloc::GenAllocString((JIT_TrialAlloc::Flags)(flags|JIT_TrialAlloc::NO_FRAME));
- //UnframedAllocateString;
}
// Replace static helpers with faster assembly versions
diff --git a/src/vm/ilmarshalers.cpp b/src/vm/ilmarshalers.cpp
index 0a4a1d900a..19db7dff73 100644
--- a/src/vm/ilmarshalers.cpp
+++ b/src/vm/ilmarshalers.cpp
@@ -4359,7 +4359,7 @@ FCIMPL4(void, MngdNativeArrayMarshaler::ConvertSpaceToManaged, MngdNativeArrayMa
//
// Allocate array
//
- SetObjectReference(pManagedHome, AllocateArrayEx(pThis->m_Array, &cElements, 1));
+ SetObjectReference(pManagedHome, AllocateSzArray(pThis->m_Array, cElements));
}
HELPER_METHOD_FRAME_END();
}
@@ -5392,7 +5392,7 @@ FCIMPL4(void, MngdHiddenLengthArrayMarshaler::ConvertSpaceToManaged, MngdHiddenL
{
TypeHandle elementType(pThis->m_pElementMT);
TypeHandle arrayType = ClassLoader::LoadArrayTypeThrowing(elementType);
- SetObjectReference(pManagedHome, AllocateArrayEx(arrayType, &cElements, 1));
+ SetObjectReference(pManagedHome, AllocateSzArray(arrayType, cElements));
}
HELPER_METHOD_FRAME_END();
diff --git a/src/vm/interpreter.cpp b/src/vm/interpreter.cpp
index 0670dc92b9..37eba9008e 100644
--- a/src/vm/interpreter.cpp
+++ b/src/vm/interpreter.cpp
@@ -5995,7 +5995,7 @@ void Interpreter::NewArr()
pArrayMT->CheckRunClassInitThrowing();
INT32 size32 = (INT32)sz;
- Object* newarray = OBJECTREFToObject(AllocateArrayEx(pArrayMT, &size32, 1));
+ Object* newarray = OBJECTREFToObject(AllocateSzArray(pArrayMT, size32));
GCX_FORBID();
OpStackTypeSet(stkInd, InterpreterType(CORINFO_TYPE_CLASS));
diff --git a/src/vm/jithelpers.cpp b/src/vm/jithelpers.cpp
index 11d07e6296..261b9acb61 100644
--- a/src/vm/jithelpers.cpp
+++ b/src/vm/jithelpers.cpp
@@ -2868,7 +2868,7 @@ HCIMPL1_RAW(StringObject*, UnframedAllocateString, DWORD stringLength)
} CONTRACTL_END;
STRINGREF result;
- result = SlowAllocateString(stringLength);
+ result = AllocateString(stringLength);
return((StringObject*) OBJECTREFToObject(result));
}
@@ -2881,7 +2881,7 @@ HCIMPL1(StringObject*, FramedAllocateString, DWORD stringLength)
STRINGREF result = NULL;
HELPER_METHOD_FRAME_BEGIN_RET_0(); // Set up a frame
- result = SlowAllocateString(stringLength);
+ result = AllocateString(stringLength);
HELPER_METHOD_FRAME_END();
return((StringObject*) OBJECTREFToObject(result));
@@ -2896,7 +2896,7 @@ HCIMPL1(Utf8StringObject*, FramedAllocateUtf8String, DWORD stringLength)
UTF8STRINGREF result = NULL;
HELPER_METHOD_FRAME_BEGIN_RET_0(); // Set up a frame
- result = SlowAllocateUtf8String(stringLength);
+ result = AllocateUtf8String(stringLength);
HELPER_METHOD_FRAME_END();
return((Utf8StringObject*) OBJECTREFToObject(result));
@@ -3136,62 +3136,13 @@ HCIMPL2(Object*, JIT_NewArr1, CORINFO_CLASS_HANDLE arrayMT, INT_PTR size)
EX_THROW(EEMessageException, (kOverflowException, IDS_EE_ARRAY_DIMENSIONS_EXCEEDED));
#endif
- //
- // is this a primitive type?
- //
-
- CorElementType elemType = pArrayMT->GetArrayElementType();
-
- if (CorTypeInfo::IsPrimitiveType(elemType)
-#ifdef FEATURE_64BIT_ALIGNMENT
- // On platforms where 64-bit types require 64-bit alignment and don't obtain it naturally force us
- // through the slow path where this will be handled.
- && (elemType != ELEMENT_TYPE_I8)
- && (elemType != ELEMENT_TYPE_U8)
- && (elemType != ELEMENT_TYPE_R8)
-#endif
- )
- {
#ifdef _DEBUG
- if (g_pConfig->FastGCStressLevel()) {
- GetThread()->DisableStressHeap();
- }
-#endif // _DEBUG
-
- // Disallow the creation of void[] (an array of System.Void)
- if (elemType == ELEMENT_TYPE_VOID)
- COMPlusThrow(kArgumentException);
-
- BOOL bAllocateInLargeHeap = FALSE;
-#ifdef FEATURE_DOUBLE_ALIGNMENT_HINT
- if ((elemType == ELEMENT_TYPE_R8) &&
- (static_cast<DWORD>(size) >= g_pConfig->GetDoubleArrayToLargeObjectHeapThreshold()))
- {
- STRESS_LOG1(LF_GC, LL_INFO10, "Allocating double array of size %d to large object heap\n", size);
- bAllocateInLargeHeap = TRUE;
- }
-#endif
-
- if (g_pPredefinedArrayTypes[elemType] == NULL)
- {
- TypeHandle elemTypeHnd = TypeHandle(MscorlibBinder::GetElementType(elemType));
-
- g_pPredefinedArrayTypes[elemType] = ClassLoader::LoadArrayTypeThrowing(elemTypeHnd, ELEMENT_TYPE_SZARRAY, 0).AsArray();
- }
-
- newArray = FastAllocatePrimitiveArray(pArrayMT, static_cast<DWORD>(size), bAllocateInLargeHeap);
+ if (g_pConfig->FastGCStressLevel()) {
+ GetThread()->DisableStressHeap();
}
- else
- {
-#ifdef _DEBUG
- if (g_pConfig->FastGCStressLevel()) {
- GetThread()->DisableStressHeap();
- }
#endif // _DEBUG
- INT32 size32 = (INT32)size;
- newArray = AllocateArrayEx(pArrayMT, &size32, 1);
- }
+ newArray = AllocateSzArray(pArrayMT, (INT32)size);
HELPER_METHOD_FRAME_END();
return(OBJECTREFToObject(newArray));
diff --git a/src/vm/object.h b/src/vm/object.h
index 173036d249..4842a95b33 100644
--- a/src/vm/object.h
+++ b/src/vm/object.h
@@ -553,8 +553,8 @@ class ArrayBase : public Object
friend class GCHeap;
friend class CObjectHeader;
friend class Object;
- friend OBJECTREF AllocateArrayEx(MethodTable *pArrayMT, INT32 *pArgs, DWORD dwNumArgs, BOOL bAllocateInLargeHeap);
- friend OBJECTREF FastAllocatePrimitiveArray(MethodTable* arrayType, DWORD cElements, BOOL bAllocateInLargeHeap);
+ friend OBJECTREF AllocateSzArray(MethodTable *pArrayMT, INT32 length, GC_ALLOC_FLAGS flags, BOOL bAllocateInLargeHeap);
+ friend OBJECTREF AllocateArrayEx(MethodTable *pArrayMT, INT32 *pArgs, DWORD dwNumArgs, GC_ALLOC_FLAGS flags, BOOL bAllocateInLargeHeap);
friend FCDECL2(Object*, JIT_NewArr1VC_MP_FastPortable, CORINFO_CLASS_HANDLE arrayMT, INT_PTR size);
friend FCDECL2(Object*, JIT_NewArr1OBJ_MP_FastPortable, CORINFO_CLASS_HANDLE arrayMT, INT_PTR size);
friend class JIT_TrialAlloc;
@@ -721,7 +721,7 @@ class PtrArray : public ArrayBase
{
friend class GCHeap;
friend class ClrDataAccess;
- friend OBJECTREF AllocateArrayEx(MethodTable *pArrayMT, INT32 *pArgs, DWORD dwNumArgs, BOOL bAllocateInLargeHeap);
+ friend OBJECTREF AllocateArrayEx(MethodTable *pArrayMT, INT32 *pArgs, DWORD dwNumArgs, DWORD flags, BOOL bAllocateInLargeHeap);
friend class JIT_TrialAlloc;
friend class CheckAsmOffsets;
diff --git a/src/vm/qcall.cpp b/src/vm/qcall.cpp
index 1b7bbda3b7..bcad868343 100644
--- a/src/vm/qcall.cpp
+++ b/src/vm/qcall.cpp
@@ -72,7 +72,7 @@ void QCall::ObjectHandleOnStack::SetGuidArray(const GUID * p, COUNT_T length)
GCX_COOP();
TypeHandle typeHandle = MscorlibBinder::GetClass(CLASS__GUID);
- BASEARRAYREF arr = (BASEARRAYREF) AllocateValueSzArray(typeHandle, length);
+ BASEARRAYREF arr = (BASEARRAYREF) AllocateSzArray(typeHandle.MakeSZArray(), length);
memcpyNoGCRefs(arr->GetDataPtr(), p, length * sizeof(GUID));
Set(arr);
}
diff --git a/src/vm/runtimehandles.cpp b/src/vm/runtimehandles.cpp
index 911dcab150..1880d41773 100644
--- a/src/vm/runtimehandles.cpp
+++ b/src/vm/runtimehandles.cpp
@@ -764,7 +764,7 @@ PTRARRAYREF CopyRuntimeTypeHandles(TypeHandle * prgTH, FixupPointer<TypeHandle>
GCPROTECT_BEGIN(refArray);
TypeHandle thRuntimeType = TypeHandle(MscorlibBinder::GetClass(arrayElemType));
TypeHandle arrayHandle = ClassLoader::LoadArrayTypeThrowing(thRuntimeType, ELEMENT_TYPE_SZARRAY);
- refArray = (PTRARRAYREF)AllocateArrayEx(arrayHandle, &numTypeHandles, 1);
+ refArray = (PTRARRAYREF)AllocateSzArray(arrayHandle, numTypeHandles);
for (INT32 i = 0; i < numTypeHandles; i++)
{
@@ -852,7 +852,7 @@ FCIMPL1(PtrArray*, RuntimeTypeHandle::GetInterfaces, ReflectClassBaseObject *pTy
if (ifaceCount > 0)
{
TypeHandle arrayHandle = ClassLoader::LoadArrayTypeThrowing(TypeHandle(g_pRuntimeTypeClass), ELEMENT_TYPE_SZARRAY);
- refRetVal = (PTRARRAYREF)AllocateArrayEx(arrayHandle, &ifaceCount, 1);
+ refRetVal = (PTRARRAYREF)AllocateSzArray(arrayHandle, ifaceCount);
// populate type array
UINT i = 0;
@@ -1957,7 +1957,7 @@ FCIMPL3(Object *, SignatureNative::GetCustomModifiers, SignatureNative* pSignatu
MethodTable *pMT = MscorlibBinder::GetClass(CLASS__TYPE);
TypeHandle arrayHandle = ClassLoader::LoadArrayTypeThrowing(TypeHandle(pMT), ELEMENT_TYPE_SZARRAY);
- gc.retVal = (PTRARRAYREF) AllocateArrayEx(arrayHandle, &cMods, 1);
+ gc.retVal = (PTRARRAYREF) AllocateSzArray(arrayHandle, cMods);
while(cMods != 0)
{
@@ -2107,7 +2107,7 @@ FCIMPL6(void, SignatureNative::GetSignature,
INT32 nArgs = msig.NumFixedArgs();
TypeHandle arrayHandle = ClassLoader::LoadArrayTypeThrowing(TypeHandle(g_pRuntimeTypeClass), ELEMENT_TYPE_SZARRAY);
- PTRARRAYREF ptrArrayarguments = (PTRARRAYREF) AllocateArrayEx(arrayHandle, &nArgs, 1);
+ PTRARRAYREF ptrArrayarguments = (PTRARRAYREF) AllocateSzArray(arrayHandle, nArgs);
gc.pSig->SetArgumentArray(ptrArrayarguments);
for (INT32 i = 0; i < nArgs; i++)
@@ -2509,7 +2509,7 @@ FCIMPL2(RuntimeMethodBody *, RuntimeMethodHandle::GetMethodBody, ReflectMethodOb
// Allocate the array of exception clauses.
INT32 cEh = (INT32)header.EHCount();
const COR_ILMETHOD_SECT_EH* ehInfo = header.EH;
- gc.TempArray = (BASEARRAYREF) AllocateArrayEx(thEHClauseArray, &cEh, 1);
+ gc.TempArray = (BASEARRAYREF) AllocateSzArray(thEHClauseArray, cEh);
SetObjectReference((OBJECTREF*)&gc.MethodBodyObj->_exceptionClauses, gc.TempArray);
@@ -2545,7 +2545,7 @@ FCIMPL2(RuntimeMethodBody *, RuntimeMethodHandle::GetMethodBody, ReflectMethodOb
&sigTypeContext,
MetaSig::sigLocalVars);
INT32 cLocals = metaSig.NumFixedArgs();
- gc.TempArray = (BASEARRAYREF) AllocateArrayEx(thLocalVariableArray, &cLocals, 1);
+ gc.TempArray = (BASEARRAYREF) AllocateSzArray(thLocalVariableArray, cLocals);
SetObjectReference((OBJECTREF*)&gc.MethodBodyObj->_localVariables, gc.TempArray);
for (INT32 i = 0; i < cLocals; i ++)
@@ -2570,7 +2570,7 @@ FCIMPL2(RuntimeMethodBody *, RuntimeMethodHandle::GetMethodBody, ReflectMethodOb
else
{
INT32 cLocals = 0;
- gc.TempArray = (BASEARRAYREF) AllocateArrayEx(thLocalVariableArray, &cLocals, 1);
+ gc.TempArray = (BASEARRAYREF) AllocateSzArray(thLocalVariableArray, cLocals);
SetObjectReference((OBJECTREF*)&gc.MethodBodyObj->_localVariables, gc.TempArray);
}
}
diff --git a/src/vm/typeparse.cpp b/src/vm/typeparse.cpp
index 0794454be2..6d621bebab 100644
--- a/src/vm/typeparse.cpp
+++ b/src/vm/typeparse.cpp
@@ -1267,7 +1267,7 @@ TypeHandle TypeName::GetTypeFromAsm()
if (cGenericArgs > 0)
{
TypeHandle arrayHandle = ClassLoader::LoadArrayTypeThrowing(TypeHandle(g_pRuntimeTypeClass), ELEMENT_TYPE_SZARRAY);
- gc.refGenericArguments = (PTRARRAYREF)AllocateArrayEx(arrayHandle, &cGenericArgs, 1);
+ gc.refGenericArguments = (PTRARRAYREF)AllocateSzArray(arrayHandle, cGenericArgs);
}
// Instantiate generic arguments
for (INT32 i = 0; i < cGenericArgs; i++)