Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/coreclr/inc/corinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,7 @@ enum CorInfoHelpFunc
CORINFO_HELP_NEW_MDARR,// multi-dim array helper for arrays Rank != 1 (with or without lower bounds - dimensions passed in as unmanaged array)
CORINFO_HELP_NEW_MDARR_RARE,// rare multi-dim array helper (Rank == 1)
CORINFO_HELP_NEWARR_1_DIRECT, // helper for any one dimensional array creation
CORINFO_HELP_NEWARR_1_FROZEN, // helper for any one dimensional array creation on a frozen segment
CORINFO_HELP_NEWARR_1_OBJ, // optimized 1-D object arrays
CORINFO_HELP_NEWARR_1_VC, // optimized 1-D value class arrays
CORINFO_HELP_NEWARR_1_ALIGN8, // like VC, but aligns the array start
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/inc/corjitflags.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class CORJIT_FLAGS
CORJIT_FLAG_OSR = 13, // Generate alternate method for On Stack Replacement

CORJIT_FLAG_ALT_JIT = 14, // JIT should consider itself an ALT_JIT
CORJIT_FLAG_UNUSED8 = 15,
CORJIT_FLAG_FROZEN_ALLOC_ALLOWED = 15, // JIT is allowed to use *_FROZEN allocators
CORJIT_FLAG_UNUSED9 = 16,
CORJIT_FLAG_UNUSED10 = 17,

Expand Down
10 changes: 5 additions & 5 deletions src/coreclr/inc/jiteeversionguid.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ typedef const GUID *LPCGUID;
#define GUID_DEFINED
#endif // !GUID_DEFINED

constexpr GUID JITEEVersionIdentifier = { /* 387bcec3-9a71-4422-a11c-e7ce3b73c592 */
0x387bcec3,
0x9a71,
0x4422,
{0xa1, 0x1c, 0xe7, 0xce, 0x3b, 0x73, 0xc5, 0x92}
constexpr GUID JITEEVersionIdentifier = { /* 4e6355a0-3844-45e2-8cef-082c18217e14 */
0x4e6355a0,
0x3844,
0x45e2,
{0x8c, 0xef, 0x8, 0x2c, 0x18, 0x21, 0x7e, 0x14}
};

//////////////////////////////////////////////////////////////////////////////////////////////////////////
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/inc/jithelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
JITHELPER(CORINFO_HELP_NEW_MDARR, JIT_NewMDArr,CORINFO_HELP_SIG_4_STACK)
JITHELPER(CORINFO_HELP_NEW_MDARR_RARE, JIT_NewMDArr,CORINFO_HELP_SIG_4_STACK)
JITHELPER(CORINFO_HELP_NEWARR_1_DIRECT, JIT_NewArr1,CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_NEWARR_1_FROZEN, JIT_NewArr1Frozen,CORINFO_HELP_SIG_REG_ONLY)
DYNAMICJITHELPER(CORINFO_HELP_NEWARR_1_OBJ, JIT_NewArr1,CORINFO_HELP_SIG_REG_ONLY)
DYNAMICJITHELPER(CORINFO_HELP_NEWARR_1_VC, JIT_NewArr1,CORINFO_HELP_SIG_REG_ONLY)
DYNAMICJITHELPER(CORINFO_HELP_NEWARR_1_ALIGN8, JIT_NewArr1,CORINFO_HELP_SIG_REG_ONLY)
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/jit/gentree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2158,6 +2158,7 @@ GenTree* Compiler::getArrayLengthFromAllocation(GenTree* tree DEBUGARG(BasicBloc
switch (eeGetHelperNum(call->gtCallMethHnd))
{
case CORINFO_HELP_NEWARR_1_DIRECT:
case CORINFO_HELP_NEWARR_1_FROZEN:
case CORINFO_HELP_NEWARR_1_OBJ:
case CORINFO_HELP_NEWARR_1_VC:
case CORINFO_HELP_NEWARR_1_ALIGN8:
Expand Down Expand Up @@ -18300,6 +18301,7 @@ CORINFO_CLASS_HANDLE Compiler::gtGetHelperCallClassHandle(GenTreeCall* call, boo
}

case CORINFO_HELP_NEWARR_1_DIRECT:
case CORINFO_HELP_NEWARR_1_FROZEN:
case CORINFO_HELP_NEWARR_1_OBJ:
case CORINFO_HELP_NEWARR_1_VC:
case CORINFO_HELP_NEWARR_1_ALIGN8:
Expand Down
50 changes: 46 additions & 4 deletions src/coreclr/jit/importer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9810,11 +9810,13 @@ void Compiler::impImportBlockCode(BasicBlock* block)
// So if we have an int, explicitly extend it to be a native int.
op2 = impImplicitIorI4Cast(op2, TYP_I_IMPL);

CorInfoHelpFunc helper = CORINFO_HELP_UNDEF;

#ifdef FEATURE_READYTORUN
if (opts.IsReadyToRun())
{
op1 = impReadyToRunHelperToTree(&resolvedToken, CORINFO_HELP_READYTORUN_NEWARR_1, TYP_REF, nullptr,
op2);
helper = CORINFO_HELP_READYTORUN_NEWARR_1;
op1 = impReadyToRunHelperToTree(&resolvedToken, helper, TYP_REF, nullptr, op2);
usingReadyToRunHelper = (op1 != nullptr);

if (!usingReadyToRunHelper)
Expand All @@ -9839,11 +9841,51 @@ void Compiler::impImportBlockCode(BasicBlock* block)
#endif
{
/* Create a call to 'new' */
helper = info.compCompHnd->getNewArrHelper(resolvedToken.hClass);

// Note that this only works for shared generic code because the same helper is used for all
// reference array types
op1 =
gtNewHelperCallNode(info.compCompHnd->getNewArrHelper(resolvedToken.hClass), TYP_REF, op1, op2);
op1 = gtNewHelperCallNode(helper, TYP_REF, op1, op2);
}

// If we're jitting a static constructor and detect the following code pattern:
//
// newarr
// stsfld
// ret
//
// We replace default heap allocator for newarr with the one that prefers frozen segments.
// This is a very simple and conservative implementation targeting Array.Empty<T>(), ideally
// we want to be able to use frozen allocators more broadly, but that analysis is not trivial.
//
if (((info.compFlags & FLG_CCTOR) == FLG_CCTOR) &&
// Does VM allow us to use frozen allocators? (e.g. are we in a non-collectible assembly)
opts.jitFlags->IsSet(JitFlags::JIT_FLAG_FROZEN_ALLOC_ALLOWED))
{
// Check next two opcodes
const BYTE* nextOpcode1 = codeAddr + sizeof(mdToken);
const BYTE* nextOpcode2 = nextOpcode1 + sizeof(mdToken) + 1;
if (nextOpcode2 <= codeEndp && getU1LittleEndian(nextOpcode1) == CEE_STSFLD)
{
if (getU1LittleEndian(nextOpcode2) == CEE_RET)
{
// TODO in this PR: R2R
if (helper == CORINFO_HELP_NEWARR_1_OBJ || helper == CORINFO_HELP_NEWARR_1_VC)
{
// Check that the field is "static readonly"
CORINFO_RESOLVED_TOKEN fldToken;
impResolveToken(nextOpcode1 + 1, &fldToken, CORINFO_TOKENKIND_Field);
CORINFO_FIELD_INFO fi;
eeGetFieldInfo(&fldToken, CORINFO_ACCESS_SET, &fi);
unsigned flagsToCheck = CORINFO_FLG_FIELD_STATIC | CORINFO_FLG_FIELD_FINAL;
if ((fi.fieldFlags & flagsToCheck) == flagsToCheck)
{
// Replace the helper with the frozen version
op1->AsCall()->gtCallMethHnd = eeFindHelper(CORINFO_HELP_NEWARR_1_FROZEN);
}
}
}
}
}

op1->AsCall()->compileTimeHelperArgumentHandle = (CORINFO_GENERIC_HANDLE)resolvedToken.hClass;
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/jit/importercalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1872,6 +1872,7 @@ GenTree* Compiler::impInitializeArrayIntrinsic(CORINFO_SIG_INFO* sig)
bool isMDArray = false;

if (newArrayCall->AsCall()->gtCallMethHnd != eeFindHelper(CORINFO_HELP_NEWARR_1_DIRECT) &&
newArrayCall->AsCall()->gtCallMethHnd != eeFindHelper(CORINFO_HELP_NEWARR_1_FROZEN) &&
newArrayCall->AsCall()->gtCallMethHnd != eeFindHelper(CORINFO_HELP_NEWARR_1_OBJ) &&
newArrayCall->AsCall()->gtCallMethHnd != eeFindHelper(CORINFO_HELP_NEWARR_1_VC) &&
newArrayCall->AsCall()->gtCallMethHnd != eeFindHelper(CORINFO_HELP_NEWARR_1_ALIGN8)
Expand Down
3 changes: 2 additions & 1 deletion src/coreclr/jit/jitee.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class JitFlags
JIT_FLAG_OSR = 13, // Generate alternate version for On Stack Replacement

JIT_FLAG_ALT_JIT = 14, // JIT should consider itself an ALT_JIT
JIT_FLAG_UNUSED8 = 15,
JIT_FLAG_FROZEN_ALLOC_ALLOWED = 15, // JIT is allowed to use *_FROZEN allocators
JIT_FLAG_UNUSED9 = 16,

#if defined(TARGET_X86) || defined(TARGET_AMD64) || defined(TARGET_ARM64)
Expand Down Expand Up @@ -187,6 +187,7 @@ class JitFlags
#endif

FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_ALT_JIT, JIT_FLAG_ALT_JIT);
FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_FROZEN_ALLOC_ALLOWED, JIT_FLAG_FROZEN_ALLOC_ALLOWED);
FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_MAKEFINALCODE, JIT_FLAG_MAKEFINALCODE);
FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_READYTORUN, JIT_FLAG_READYTORUN);
FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_PROF_ENTERLEAVE, JIT_FLAG_PROF_ENTERLEAVE);
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/jit/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1335,6 +1335,7 @@ void HelperCallProperties::init()
case CORINFO_HELP_NEW_MDARR:
case CORINFO_HELP_NEW_MDARR_RARE:
case CORINFO_HELP_NEWARR_1_DIRECT:
case CORINFO_HELP_NEWARR_1_FROZEN:
case CORINFO_HELP_NEWARR_1_OBJ:
case CORINFO_HELP_READYTORUN_NEWARR_1:

Expand Down
1 change: 1 addition & 0 deletions src/coreclr/jit/valuenum.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12172,6 +12172,7 @@ VNFunc Compiler::fgValueNumberJitHelperMethodVNFunc(CorInfoHelpFunc helpFunc)
break;

case CORINFO_HELP_NEWARR_1_DIRECT:
case CORINFO_HELP_NEWARR_1_FROZEN:
case CORINFO_HELP_NEWARR_1_OBJ:
case CORINFO_HELP_NEWARR_1_VC:
case CORINFO_HELP_NEWARR_1_ALIGN8:
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ which is the right helper to use to allocate an object of a given type. */
CORINFO_HELP_NEW_MDARR, // multi-dim array helper for arrays Rank != 1 (with or without lower bounds - dimensions passed in as unmanaged array)
CORINFO_HELP_NEW_MDARR_RARE, // rare multi-dim array helper (Rank == 1)
CORINFO_HELP_NEWARR_1_DIRECT, // helper for any one dimensional array creation
CORINFO_HELP_NEWARR_1_FROZEN, // helper for any one dimensional array creation on a frozen segment
CORINFO_HELP_NEWARR_1_OBJ, // optimized 1-D object arrays
CORINFO_HELP_NEWARR_1_VC, // optimized 1-D value class arrays
CORINFO_HELP_NEWARR_1_ALIGN8, // like VC, but aligns the array start
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1411,6 +1411,7 @@ public enum CorJitFlag : uint
CORJIT_FLAG_UNUSED6 = 12,
CORJIT_FLAG_OSR = 13, // Generate alternate version for On Stack Replacement
CORJIT_FLAG_ALT_JIT = 14, // JIT should consider itself an ALT_JIT
CORJIT_FLAG_FROZEN_ALLOC_ALLOWED = 15, // JIT is allowed to use *_FROZEN allocators
CORJIT_FLAG_UNUSED10 = 17,
CORJIT_FLAG_MAKEFINALCODE = 18, // Use the final code generator, i.e., not the interpreter.
CORJIT_FLAG_READYTORUN = 19, // Use version-resilient code generation
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1201,6 +1201,8 @@ const char* CorJitFlagToString(CORJIT_FLAGS::CorJitFlag flag)
return "CORJIT_FLAG_OSR";
case CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_ALT_JIT:
return "CORJIT_FLAG_ALT_JIT";
case CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_FROZEN_ALLOC_ALLOWED:
return "CORJIT_FLAG_FROZEN_ALLOC_ALLOWED";
case CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_MAKEFINALCODE:
return "CORJIT_FLAG_MAKEFINALCODE";
case CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_READYTORUN:
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/vm/frozenobjectheap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ Object* FrozenObjectSegment::TryAllocateObject(PTR_MethodTable type, size_t obje
{
_ASSERT(m_pStart != nullptr && m_Size > 0 && m_SegmentHandle != nullptr); // Expected to be inited
_ASSERT(IS_ALIGNED(m_pCurrent, DATA_ALIGNMENT));
_ASSERT(IS_ALIGNED(objectSize, DATA_ALIGNMENT));
_ASSERT(objectSize <= FOH_COMMIT_SIZE);
_ASSERT(m_pCurrent >= m_pStart + sizeof(ObjHeader));

Expand Down
85 changes: 85 additions & 0 deletions src/coreclr/vm/gchelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,91 @@ OBJECTREF AllocateSzArray(MethodTable* pArrayMT, INT32 cElements, GC_ALLOC_FLAGS
return ObjectToOBJECTREF((Object*)orArray);
}

// Same as AllocateSzArray but attempts to allocate the array on a frozen segment.
// It fallbacks to AllocateSzArray if it fails to allocate on a frozen segment.
OBJECTREF AllocateFrozenSzArray(MethodTable* pArrayMT, INT32 cElements)
{
CONTRACTL{
THROWS;
GC_TRIGGERS;
MODE_COOPERATIVE;
} CONTRACTL_END;

SetTypeHandleOnThreadForAlloc(TypeHandle(pArrayMT));

_ASSERTE(pArrayMT->CheckInstanceActivated());
_ASSERTE(pArrayMT->GetInternalCorElementType() == ELEMENT_TYPE_SZARRAY);

// The initial validation is copied from AllocateSzArray impl

CorElementType elemType = pArrayMT->GetArrayElementType();

if (pArrayMT->ContainsPointers() && cElements > 0)
{
// For arrays with GC pointers we can only work with empty arrays
return AllocateSzArray(pArrayMT, cElements);
}

if (pArrayMT->Collectible())
{
// Ignore arrays of collectible types
return AllocateSzArray(pArrayMT, cElements);
}

// Disallow the creation of void[] (an array of System.Void)
if (elemType == ELEMENT_TYPE_VOID)
COMPlusThrow(kArgumentException);

if (cElements < 0)
COMPlusThrow(kOverflowException);

if ((SIZE_T)cElements > MaxArrayLength())
ThrowOutOfMemoryDimensionsExceeded();

SIZE_T componentSize = pArrayMT->GetComponentSize();
#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

// FrozenObjectHeapManager doesn't yet support objects with a custom alignment,
// so we give up on arrays of value types requiring 8 byte alignment on 32bit platforms.
if ((DATA_ALIGNMENT < sizeof(double)) && (elemType == ELEMENT_TYPE_R8))
{
return AllocateSzArray(pArrayMT, cElements);
}
#ifdef FEATURE_64BIT_ALIGNMENT
MethodTable* pElementMT = pArrayMT->GetArrayElementTypeHandle().GetMethodTable();
if (pElementMT->RequiresAlign8() && pElementMT->IsValueType())
{
return AllocateSzArray(pArrayMT, cElements);
}
#endif

FrozenObjectHeapManager* foh = SystemDomain::GetFrozenObjectHeapManager();
ArrayBase* orArray = static_cast<ArrayBase*>(foh->TryAllocateObject(pArrayMT, PtrAlign(totalSize), /*publish*/ false));
if (orArray == nullptr)
{
// We failed to allocate on a frozen segment, fallback to AllocateSzArray
// E.g. if the array is too big to fit on a frozen segment
return AllocateSzArray(pArrayMT, cElements);
}
orArray->m_NumComponents = cElements;

// Publish needs to be postponed in this case because we need to specify array length
PublishObjectAndNotify(orArray, GC_ALLOC_NO_FLAGS);

return ObjectToOBJECTREF(orArray);
}

void ThrowOutOfMemoryDimensionsExceeded()
{
CONTRACTL {
Expand Down
3 changes: 3 additions & 0 deletions src/coreclr/vm/gchelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
OBJECTREF AllocateSzArray(MethodTable *pArrayMT, INT32 length, GC_ALLOC_FLAGS flags = GC_ALLOC_NO_FLAGS);
OBJECTREF AllocateSzArray(TypeHandle arrayType, INT32 length, GC_ALLOC_FLAGS flags = GC_ALLOC_NO_FLAGS);

// Allocate single-dimensional array with a hint to prefer frozen segments
OBJECTREF AllocateFrozenSzArray(MethodTable* pArrayMT, INT32 length);

// 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);
OBJECTREF AllocateArrayEx(TypeHandle arrayType, INT32 *pArgs, DWORD dwNumArgs, GC_ALLOC_FLAGS flags = GC_ALLOC_NO_FLAGS);
Expand Down
40 changes: 40 additions & 0 deletions src/coreclr/vm/jithelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2719,6 +2719,46 @@ HCIMPL2(Object*, JIT_NewArr1, CORINFO_CLASS_HANDLE arrayMT, INT_PTR size)
}
HCIMPLEND


/*************************************************************/
HCIMPL2(Object*, JIT_NewArr1Frozen, CORINFO_CLASS_HANDLE arrayMT, INT_PTR size)
{
FCALL_CONTRACT;

OBJECTREF newArray = NULL;

HELPER_METHOD_FRAME_BEGIN_RET_0(); // Set up a frame

MethodTable* pArrayMT = (MethodTable*)arrayMT;

_ASSERTE(pArrayMT->IsFullyLoaded());
_ASSERTE(pArrayMT->IsArray());
_ASSERTE(!pArrayMT->IsMultiDimArray());

if (size < 0)
COMPlusThrow(kOverflowException);

#ifdef HOST_64BIT
// Even though ECMA allows using a native int as the argument to newarr instruction
// (therefore size is INT_PTR), ArrayBase::m_NumComponents is 32-bit, so even on 64-bit
// platforms we can't create an array whose size exceeds 32 bits.
if (size > INT_MAX)
EX_THROW(EEMessageException, (kOverflowException, IDS_EE_ARRAY_DIMENSIONS_EXCEEDED));
#endif

#ifdef _DEBUG
if (g_pConfig->FastGCStressLevel()) {
GetThread()->DisableStressHeap();
}
#endif // _DEBUG

newArray = AllocateFrozenSzArray(pArrayMT, (INT32)size);
HELPER_METHOD_FRAME_END();

return(OBJECTREFToObject(newArray));
}
HCIMPLEND

/*************************************************************/
HCIMPL3(Object*, JIT_NewMDArr, CORINFO_CLASS_HANDLE classHnd, unsigned dwNumArgs, INT32 * pArgList)
{
Expand Down
Loading