From d42f6c7a0ff3a18d2495e2527b4ae68825a42e02 Mon Sep 17 00:00:00 2001 From: Eugene Rozenfeld Date: Mon, 19 Nov 2018 13:25:56 -0800 Subject: [PATCH] Disable object stack allocation verification under GCStress. ObjectStackAllocationTests use GC.GetAllocatedBytesForCurrentThread to verify object stack allocations. Under GCStress the vm may initiate additional heap allocations in GCHeap::StressHeap (see the call to 'pGenGCHeap->allocate' below). This change re-enables ObjectStackAllocationTests and updates then to not verify stack allocations under GCStress. It's useful to run the tests even without the verification to catch crashes, gc asserts, etc. ``` if (Interlocked::Increment(&OneAtATime) == 0 && !TrackAllocations()) // Messing with object sizes can confuse the profiler (see ICorProfilerInfo::GetObjectSize) { StringObject* str; // If the current string is used up if (HndFetchHandle(m_StressObjs[m_CurStressObj]) == 0) { // Populate handles with strings int i = m_CurStressObj; while(HndFetchHandle(m_StressObjs[i]) == 0) { _ASSERTE(m_StressObjs[i] != 0); unsigned strLen = (LARGE_OBJECT_SIZE - 32) / sizeof(WCHAR); unsigned strSize = PtrAlign(StringObject::GetSize(strLen)); // update the cached type handle before allocating SetTypeHandleOnThreadForAlloc(TypeHandle(g_pStringClass)); str = (StringObject*) pGenGCHeap->allocate (strSize, acontext); if (str) { str->SetMethodTable (g_pStringClass); str->SetStringLength (strLen); HndAssignHandle(m_StressObjs[i], ObjectToOBJECTREF(str)); } i = (i + 1) % NUM_HEAP_STRESS_OBJS; if (i == m_CurStressObj) break; } // advance the current handle to the next string m_CurStressObj = (m_CurStressObj + 1) % NUM_HEAP_STRESS_OBJS; } // Get the current string str = (StringObject*) OBJECTREFToObject(HndFetchHandle(m_StressObjs[m_CurStressObj])); if (str) { // Chop off the end of the string and form a new object out of it. // This will 'free' an object at the begining of the heap, which will // force data movement. Note that we can only do this so many times. // before we have to move on to the next string. unsigned sizeOfNewObj = (unsigned)Align(min_obj_size * 31); if (str->GetStringLength() > sizeOfNewObj / sizeof(WCHAR)) { unsigned sizeToNextObj = (unsigned)Align(size(str)); uint8_t* freeObj = ((uint8_t*) str) + sizeToNextObj - sizeOfNewObj; pGenGCHeap->make_unused_array (freeObj, sizeOfNewObj); str->SetStringLength(str->GetStringLength() - (sizeOfNewObj / sizeof(WCHAR))); } else { // Let the string itself become garbage. // will be realloced next time around HndAssignHandle(m_StressObjs[m_CurStressObj], 0); } } } Interlocked::Decrement(&OneAtATime); ``` Commit migrated from https://github.com/dotnet/coreclr/commit/5ef00810b53dcb7cbc4f2cb152ca6af971284e82 --- .../ObjectStackAllocationTests.cs | 55 ++++++++++++++++------ .../ObjectStackAllocationTests.csproj | 2 - 2 files changed, 40 insertions(+), 17 deletions(-) diff --git a/src/coreclr/tests/src/JIT/opt/ObjectStackAllocation/ObjectStackAllocationTests.cs b/src/coreclr/tests/src/JIT/opt/ObjectStackAllocation/ObjectStackAllocationTests.cs index b016368..fc4fc15 100644 --- a/src/coreclr/tests/src/JIT/opt/ObjectStackAllocation/ObjectStackAllocationTests.cs +++ b/src/coreclr/tests/src/JIT/opt/ObjectStackAllocation/ObjectStackAllocationTests.cs @@ -69,6 +69,13 @@ namespace ObjectStackAllocation public SimpleStruct s; } + enum AllocationKind + { + Heap, + Stack, + Undefined + } + class Tests { static volatile int f1 = 5; @@ -80,32 +87,43 @@ namespace ObjectStackAllocation public static int Main() { - bool spcOptimizationEnabled = SPCOptimizationsEnabled(); + AllocationKind expectedAllocationKind = AllocationKind.Stack; + if (GCStressEnabled()) { + expectedAllocationKind = AllocationKind.Undefined; + } + else if (!SPCOptimizationsEnabled()) { + expectedAllocationKind = AllocationKind.Heap; + } - CallTestAndVerifyAllocation(AllocateSimpleClassAndAddFields, 12, !spcOptimizationEnabled); + CallTestAndVerifyAllocation(AllocateSimpleClassAndAddFields, 12, expectedAllocationKind); - CallTestAndVerifyAllocation(AllocateSimpleClassesAndEQCompareThem, 0, !spcOptimizationEnabled); + CallTestAndVerifyAllocation(AllocateSimpleClassesAndEQCompareThem, 0, expectedAllocationKind); - CallTestAndVerifyAllocation(AllocateSimpleClassesAndNECompareThem, 1, !spcOptimizationEnabled); + CallTestAndVerifyAllocation(AllocateSimpleClassesAndNECompareThem, 1, expectedAllocationKind); - CallTestAndVerifyAllocation(AllocateSimpleClassAndCheckType, 1, !spcOptimizationEnabled); + CallTestAndVerifyAllocation(AllocateSimpleClassAndCheckType, 1, expectedAllocationKind); - CallTestAndVerifyAllocation(AllocateSimpleClassAndCast, 7, !spcOptimizationEnabled); + CallTestAndVerifyAllocation(AllocateSimpleClassAndCast, 7, expectedAllocationKind); - CallTestAndVerifyAllocation(AllocateSimpleClassAndGetField, 7, !spcOptimizationEnabled); + CallTestAndVerifyAllocation(AllocateSimpleClassAndGetField, 7, expectedAllocationKind); - CallTestAndVerifyAllocation(AllocateClassWithNestedStructAndGetField, 5, !spcOptimizationEnabled); + CallTestAndVerifyAllocation(AllocateClassWithNestedStructAndGetField, 5, expectedAllocationKind); - CallTestAndVerifyAllocation(AllocateClassWithNestedStructAndAddFields, 24, !spcOptimizationEnabled); + CallTestAndVerifyAllocation(AllocateClassWithNestedStructAndAddFields, 24, expectedAllocationKind); + + // The remaining tests currently never allocate on the stack + if (expectedAllocationKind == AllocationKind.Stack) { + expectedAllocationKind = AllocationKind.Heap; + } // Stack allocation of classes with GC fields is currently disabled - CallTestAndVerifyAllocation(AllocateSimpleClassWithGCFieldAndAddFields, 12, true); + CallTestAndVerifyAllocation(AllocateSimpleClassWithGCFieldAndAddFields, 12, expectedAllocationKind); // Assigning class ref to a field of another object currently always disables stack allocation - CallTestAndVerifyAllocation(AllocateSimpleClassAndAssignRefToAField, 12, true); + CallTestAndVerifyAllocation(AllocateSimpleClassAndAssignRefToAField, 12, expectedAllocationKind); // Stack allocation of boxed structs is currently disabled - CallTestAndVerifyAllocation(BoxSimpleStructAndAddFields, 12, true); + CallTestAndVerifyAllocation(BoxSimpleStructAndAddFields, 12, expectedAllocationKind); return methodResult; } @@ -119,8 +137,15 @@ namespace ObjectStackAllocation return ((debuggableAttribute == null) || !debuggableAttribute.IsJITOptimizerDisabled); } - static void CallTestAndVerifyAllocation(Test test, int expectedResult, bool expectHeapAllocations) + static bool GCStressEnabled() + { + return Environment.GetEnvironmentVariable("COMPlus_GCStress") != null; + } + + static void CallTestAndVerifyAllocation(Test test, int expectedResult, AllocationKind expectedAllocationsKind) { + // Run the test once to exclude any allocations during jitting, etc. + //test(); long allocatedBytesBefore = GC.GetAllocatedBytesForCurrentThread(); int testResult = test(); long allocatedBytesAfter = GC.GetAllocatedBytesForCurrentThread(); @@ -130,11 +155,11 @@ namespace ObjectStackAllocation Console.WriteLine($"FAILURE ({methodName}): expected {expectedResult}, got {testResult}"); methodResult = -1; } - else if (!expectHeapAllocations && (allocatedBytesBefore != allocatedBytesAfter)) { + else if ((expectedAllocationsKind == AllocationKind.Stack) && (allocatedBytesBefore != allocatedBytesAfter)) { Console.WriteLine($"FAILURE ({methodName}): unexpected allocation of {allocatedBytesAfter - allocatedBytesBefore} bytes"); methodResult = -1; } - else if (expectHeapAllocations && (allocatedBytesBefore == allocatedBytesAfter)) { + else if ((expectedAllocationsKind == AllocationKind.Heap) && (allocatedBytesBefore == allocatedBytesAfter)) { Console.WriteLine($"FAILURE ({methodName}): unexpected stack allocation"); methodResult = -1; } diff --git a/src/coreclr/tests/src/JIT/opt/ObjectStackAllocation/ObjectStackAllocationTests.csproj b/src/coreclr/tests/src/JIT/opt/ObjectStackAllocation/ObjectStackAllocationTests.csproj index 5fd0c6f..b6efc07 100644 --- a/src/coreclr/tests/src/JIT/opt/ObjectStackAllocation/ObjectStackAllocationTests.csproj +++ b/src/coreclr/tests/src/JIT/opt/ObjectStackAllocation/ObjectStackAllocationTests.csproj @@ -10,8 +10,6 @@ Exe {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} ..\..\ - - true -- 2.7.4