diff options
author | Vladimir Sadov <vsadov@microsoft.com> | 2019-05-02 22:16:31 -0700 |
---|---|---|
committer | Jan Kotas <jkotas@microsoft.com> | 2019-05-02 22:16:31 -0700 |
commit | b271aff1fa54c1385143f3b45c1bf3af01c901cd (patch) | |
tree | 69c76676a56a28979fd1c5c66db9d096afa98c6e /src/vm | |
parent | dd814e26e2206c36589f88b2c58a6f3695f7dc4e (diff) | |
download | coreclr-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.cpp | 28 | ||||
-rw-r--r-- | src/vm/comutilnative.h | 4 | ||||
-rw-r--r-- | src/vm/crossloaderallocatorhash.inl | 4 | ||||
-rw-r--r-- | src/vm/customattribute.cpp | 4 | ||||
-rw-r--r-- | src/vm/ecalllist.h | 2 | ||||
-rw-r--r-- | src/vm/fieldmarshaler.cpp | 2 | ||||
-rw-r--r-- | src/vm/gchelpers.cpp | 435 | ||||
-rw-r--r-- | src/vm/gchelpers.h | 90 | ||||
-rw-r--r-- | src/vm/i386/jitinterfacex86.cpp | 118 | ||||
-rw-r--r-- | src/vm/ilmarshalers.cpp | 4 | ||||
-rw-r--r-- | src/vm/interpreter.cpp | 2 | ||||
-rw-r--r-- | src/vm/jithelpers.cpp | 61 | ||||
-rw-r--r-- | src/vm/object.h | 6 | ||||
-rw-r--r-- | src/vm/qcall.cpp | 2 | ||||
-rw-r--r-- | src/vm/runtimehandles.cpp | 14 | ||||
-rw-r--r-- | src/vm/typeparse.cpp | 2 |
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++) |