diff --git a/docs/design/coreclr/botr/readytorun-format.md b/docs/design/coreclr/botr/readytorun-format.md index fa6bb18b114c9..2c63997332e48 100644 --- a/docs/design/coreclr/botr/readytorun-format.md +++ b/docs/design/coreclr/botr/readytorun-format.md @@ -798,6 +798,8 @@ enum ReadyToRunHelper READYTORUN_HELPER_GenericNonGcTlsBase = 0x67, READYTORUN_HELPER_VirtualFuncPtr = 0x68, READYTORUN_HELPER_IsInstanceOfException = 0x69, + READYTORUN_HELPER_NewMaybeFrozenArray = 0x6A, + READYTORUN_HELPER_NewMaybeFrozenObject = 0x6B, // Long mul/div/shift ops READYTORUN_HELPER_LMul = 0xC0, diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 4e80bb79ca8b9..93f6768028449 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -404,6 +404,7 @@ enum CorInfoHelpFunc which is the right helper to use to allocate an object of a given type. */ CORINFO_HELP_NEWFAST, + CORINFO_HELP_NEWFAST_MAYBEFROZEN, // allocator for objects that *might* allocate them on a frozen segment CORINFO_HELP_NEWSFAST, // allocator for small, non-finalizer, non-array object CORINFO_HELP_NEWSFAST_FINALIZE, // allocator for small, finalizable, non-array object CORINFO_HELP_NEWSFAST_ALIGN8, // allocator for small, non-finalizer, non-array object, 8 byte aligned @@ -412,6 +413,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_MAYBEFROZEN, // allocator for arrays that *might* allocate them 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 @@ -583,8 +585,6 @@ enum CorInfoHelpFunc CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE, // Convert from a TypeHandle (native structure pointer) to RuntimeTypeHandle at run-time CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE_MAYBENULL, // Convert from a TypeHandle (native structure pointer) to RuntimeTypeHandle at run-time, handle might point to a null type - CORINFO_HELP_ARE_TYPES_EQUIVALENT, // Check whether two TypeHandles (native structure pointers) are equivalent - CORINFO_HELP_VIRTUAL_FUNC_PTR, // look up a virtual method at run-time // Not a real helpers. Instead of taking handle arguments, these helpers point to a small stub that loads the handle argument and calls the static helper. @@ -2619,12 +2619,6 @@ class ICorStaticInfo CORINFO_CLASS_HANDLE parent // base type ) = 0; - // TRUE if cls1 and cls2 are considered equivalent types. - virtual bool areTypesEquivalent( - CORINFO_CLASS_HANDLE cls1, - CORINFO_CLASS_HANDLE cls2 - ) = 0; - // See if a cast from fromClass to toClass will succeed, fail, or needs // to be resolved at runtime. virtual TypeCompareState compareTypesForCast( diff --git a/src/coreclr/inc/corjitflags.h b/src/coreclr/inc/corjitflags.h index c90753bb4d55c..4d511aa6f7470 100644 --- a/src/coreclr/inc/corjitflags.h +++ b/src/coreclr/inc/corjitflags.h @@ -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 *_MAYBEFROZEN allocators CORJIT_FLAG_UNUSED9 = 16, CORJIT_FLAG_UNUSED10 = 17, diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h index 18ea19b28df17..cf4c94498c33a 100644 --- a/src/coreclr/inc/icorjitinfoimpl_generated.h +++ b/src/coreclr/inc/icorjitinfoimpl_generated.h @@ -339,10 +339,6 @@ bool canCast( CORINFO_CLASS_HANDLE child, CORINFO_CLASS_HANDLE parent) override; -bool areTypesEquivalent( - CORINFO_CLASS_HANDLE cls1, - CORINFO_CLASS_HANDLE cls2) override; - TypeCompareState compareTypesForCast( CORINFO_CLASS_HANDLE fromClass, CORINFO_CLASS_HANDLE toClass) override; diff --git a/src/coreclr/inc/jiteeversionguid.h b/src/coreclr/inc/jiteeversionguid.h index be6cc1e7f4f8d..d539e04c6b168 100644 --- a/src/coreclr/inc/jiteeversionguid.h +++ b/src/coreclr/inc/jiteeversionguid.h @@ -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} }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/coreclr/inc/jithelpers.h b/src/coreclr/inc/jithelpers.h index 30f8fe38ae450..1d498c3589347 100644 --- a/src/coreclr/inc/jithelpers.h +++ b/src/coreclr/inc/jithelpers.h @@ -70,6 +70,7 @@ // Allocating a new object JITHELPER(CORINFO_HELP_NEWFAST, JIT_New, CORINFO_HELP_SIG_REG_ONLY) + JITHELPER(CORINFO_HELP_NEWFAST_MAYBEFROZEN, JIT_NewMaybeFrozen,CORINFO_HELP_SIG_REG_ONLY) DYNAMICJITHELPER(CORINFO_HELP_NEWSFAST, JIT_New, CORINFO_HELP_SIG_REG_ONLY) JITHELPER(CORINFO_HELP_NEWSFAST_FINALIZE, NULL, CORINFO_HELP_SIG_REG_ONLY) DYNAMICJITHELPER(CORINFO_HELP_NEWSFAST_ALIGN8, JIT_New, CORINFO_HELP_SIG_REG_ONLY) @@ -78,6 +79,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_MAYBEFROZEN, JIT_NewArr1MaybeFrozen,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) @@ -252,8 +254,6 @@ JITHELPER(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE, JIT_GetRuntimeType, CORINFO_HELP_SIG_REG_ONLY) JITHELPER(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE_MAYBENULL, JIT_GetRuntimeType_MaybeNull, CORINFO_HELP_SIG_REG_ONLY) - JITHELPER(CORINFO_HELP_ARE_TYPES_EQUIVALENT, NULL, CORINFO_HELP_SIG_REG_ONLY) - JITHELPER(CORINFO_HELP_VIRTUAL_FUNC_PTR, JIT_VirtualFunctionPointer, CORINFO_HELP_SIG_4_STACK) JITHELPER(CORINFO_HELP_READYTORUN_NEW, NULL, CORINFO_HELP_SIG_NO_ALIGN_STUB) diff --git a/src/coreclr/inc/readytorun.h b/src/coreclr/inc/readytorun.h index 4754e0a294fe8..e138058b3666a 100644 --- a/src/coreclr/inc/readytorun.h +++ b/src/coreclr/inc/readytorun.h @@ -18,7 +18,7 @@ // src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs // src/coreclr/nativeaot/Runtime/inc/ModuleHeaders.h #define READYTORUN_MAJOR_VERSION 0x0009 -#define READYTORUN_MINOR_VERSION 0x0000 +#define READYTORUN_MINOR_VERSION 0x0001 #define MINIMUM_READYTORUN_MAJOR_VERSION 0x009 @@ -30,6 +30,7 @@ // R2R 6.0 is not backward compatible with 5.x or earlier. // R2R Version 8.0 Changes the alignment of the Int128 type // R2R Version 9.0 adds support for the Vector512 type +// R2R Version 9.1 adds new helpers to allocate objects on frozen segments struct READYTORUN_CORE_HEADER { @@ -335,6 +336,8 @@ enum ReadyToRunHelper READYTORUN_HELPER_GenericNonGcTlsBase = 0x67, READYTORUN_HELPER_VirtualFuncPtr = 0x68, READYTORUN_HELPER_IsInstanceOfException = 0x69, + READYTORUN_HELPER_NewMaybeFrozenArray = 0x6A, + READYTORUN_HELPER_NewMaybeFrozenObject = 0x6B, // Long mul/div/shift ops READYTORUN_HELPER_LMul = 0xC0, diff --git a/src/coreclr/inc/readytorunhelpers.h b/src/coreclr/inc/readytorunhelpers.h index b9d904b9c4193..8691f9b9cb8c0 100644 --- a/src/coreclr/inc/readytorunhelpers.h +++ b/src/coreclr/inc/readytorunhelpers.h @@ -55,6 +55,8 @@ HELPER(READYTORUN_HELPER_GenericNonGcTlsBase, CORINFO_HELP_GETGENERICS_NON HELPER(READYTORUN_HELPER_VirtualFuncPtr, CORINFO_HELP_VIRTUAL_FUNC_PTR, ) HELPER(READYTORUN_HELPER_IsInstanceOfException, CORINFO_HELP_ISINSTANCEOF_EXCEPTION, ) +HELPER(READYTORUN_HELPER_NewMaybeFrozenArray, CORINFO_HELP_NEWARR_1_MAYBEFROZEN, ) +HELPER(READYTORUN_HELPER_NewMaybeFrozenObject, CORINFO_HELP_NEWFAST_MAYBEFROZEN, ) HELPER(READYTORUN_HELPER_LMul, CORINFO_HELP_LMUL, ) HELPER(READYTORUN_HELPER_LMulOfv, CORINFO_HELP_LMUL_OVF, ) diff --git a/src/coreclr/jit/ICorJitInfo_names_generated.h b/src/coreclr/jit/ICorJitInfo_names_generated.h index e554312dedb64..cb5db87194525 100644 --- a/src/coreclr/jit/ICorJitInfo_names_generated.h +++ b/src/coreclr/jit/ICorJitInfo_names_generated.h @@ -84,7 +84,6 @@ DEF_CLR_API(getBuiltinClass) DEF_CLR_API(getTypeForPrimitiveValueClass) DEF_CLR_API(getTypeForPrimitiveNumericClass) DEF_CLR_API(canCast) -DEF_CLR_API(areTypesEquivalent) DEF_CLR_API(compareTypesForCast) DEF_CLR_API(compareTypesForEquality) DEF_CLR_API(mergeClasses) diff --git a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp index 26aa42f752260..b819fc12fbce1 100644 --- a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp +++ b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp @@ -793,16 +793,6 @@ bool WrapICorJitInfo::canCast( return temp; } -bool WrapICorJitInfo::areTypesEquivalent( - CORINFO_CLASS_HANDLE cls1, - CORINFO_CLASS_HANDLE cls2) -{ - API_ENTER(areTypesEquivalent); - bool temp = wrapHnd->areTypesEquivalent(cls1, cls2); - API_LEAVE(areTypesEquivalent); - return temp; -} - TypeCompareState WrapICorJitInfo::compareTypesForCast( CORINFO_CLASS_HANDLE fromClass, CORINFO_CLASS_HANDLE toClass) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 4420a7662a36c..6b8aed34c6fb9 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -3020,10 +3020,6 @@ class Compiler GenTree* gtFoldBoxNullable(GenTree* tree); GenTree* gtFoldExprCompare(GenTree* tree); GenTree* gtFoldExprConditional(GenTree* tree); - GenTree* gtCreateHandleCompare(genTreeOps oper, - GenTree* op1, - GenTree* op2, - CorInfoInlineTypeCheck typeCheckInliningResult); GenTree* gtFoldExprCall(GenTreeCall* call); GenTree* gtFoldTypeCompare(GenTree* tree); GenTree* gtFoldTypeEqualityCall(bool isEq, GenTree* op1, GenTree* op2); diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index ae7f23375a2f8..2550514165eeb 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -2155,30 +2155,17 @@ GenTree* Compiler::getArrayLengthFromAllocation(GenTree* tree DEBUGARG(BasicBloc if (call->gtCallType == CT_HELPER) { - switch (eeGetHelperNum(call->gtCallMethHnd)) + CorInfoHelpFunc helper = eeGetHelperNum(call->gtCallMethHnd); + switch (helper) { + case CORINFO_HELP_NEWARR_1_MAYBEFROZEN: case CORINFO_HELP_NEWARR_1_DIRECT: case CORINFO_HELP_NEWARR_1_OBJ: case CORINFO_HELP_NEWARR_1_VC: case CORINFO_HELP_NEWARR_1_ALIGN8: { // This is an array allocation site. Grab the array length node. - arrayLength = call->gtArgs.GetArgByIndex(1)->GetNode(); - break; - } - - case CORINFO_HELP_READYTORUN_NEWARR_1: - { - // On arm when compiling on certain platforms for ready to - // run, a handle will be inserted before the length. To - // handle this case, we will grab the last argument as - // that's always the length. See - // CallArgs::AddFinalArgsAndDetermineABIInfo for where the - // handle is inserted. - for (CallArg& arg : call->gtArgs.Args()) - { - arrayLength = arg.GetNode(); - } + arrayLength = call->gtArgs.GetUserArgByIndex(1)->GetNode(); break; } @@ -13413,47 +13400,6 @@ GenTree* Compiler::gtFoldExprConditional(GenTree* tree) return replacement; } -//------------------------------------------------------------------------ -// gtCreateHandleCompare: generate a type handle comparison -// -// Arguments: -// oper -- comparison operation (equal/not equal) -// op1 -- first operand -// op2 -- second operand -// typeCheckInliningResult -- indicates how the comparison should happen -// -// Returns: -// Type comparison tree -// - -GenTree* Compiler::gtCreateHandleCompare(genTreeOps oper, - GenTree* op1, - GenTree* op2, - CorInfoInlineTypeCheck typeCheckInliningResult) -{ - // If we can compare pointers directly, just emit the binary operation - if (typeCheckInliningResult == CORINFO_INLINE_TYPECHECK_PASS) - { - return gtNewOperNode(oper, TYP_INT, op1, op2); - } - - assert(typeCheckInliningResult == CORINFO_INLINE_TYPECHECK_USE_HELPER); - - // Emit a call to a runtime helper - GenTree* ret = gtNewHelperCallNode(CORINFO_HELP_ARE_TYPES_EQUIVALENT, TYP_INT, op1, op2); - if (oper == GT_EQ) - { - ret = gtNewOperNode(GT_NE, TYP_INT, ret, gtNewIconNode(0, TYP_INT)); - } - else - { - assert(oper == GT_NE); - ret = gtNewOperNode(GT_EQ, TYP_INT, ret, gtNewIconNode(0, TYP_INT)); - } - - return ret; -} - //------------------------------------------------------------------------ // gtFoldTypeCompare: see if a type comparison can be further simplified // @@ -13566,9 +13512,9 @@ GenTree* Compiler::gtFoldTypeCompare(GenTree* tree) inliningKind = info.compCompHnd->canInlineTypeCheck(cls2Hnd, CORINFO_INLINE_TYPECHECK_SOURCE_TOKEN); } - assert(inliningKind == CORINFO_INLINE_TYPECHECK_PASS || inliningKind == CORINFO_INLINE_TYPECHECK_USE_HELPER); + assert(inliningKind == CORINFO_INLINE_TYPECHECK_PASS); - GenTree* compare = gtCreateHandleCompare(oper, op1ClassFromHandle, op2ClassFromHandle, inliningKind); + GenTree* compare = gtNewOperNode(oper, TYP_INT, op1ClassFromHandle, op2ClassFromHandle); // Drop any now-irrelevant flags compare->gtFlags |= tree->gtFlags & (GTF_RELOP_JMP_USED | GTF_DONT_CSE); @@ -13604,11 +13550,10 @@ GenTree* Compiler::gtFoldTypeCompare(GenTree* tree) arg2 = gtNewMethodTableLookup(arg2); - CorInfoInlineTypeCheck inliningKind = - info.compCompHnd->canInlineTypeCheck(nullptr, CORINFO_INLINE_TYPECHECK_SOURCE_VTABLE); - assert(inliningKind == CORINFO_INLINE_TYPECHECK_PASS || inliningKind == CORINFO_INLINE_TYPECHECK_USE_HELPER); + assert(info.compCompHnd->canInlineTypeCheck(nullptr, CORINFO_INLINE_TYPECHECK_SOURCE_VTABLE) == + CORINFO_INLINE_TYPECHECK_PASS); - GenTree* compare = gtCreateHandleCompare(oper, arg1, arg2, inliningKind); + GenTree* compare = gtNewOperNode(oper, TYP_INT, arg1, arg2); // Drop any now-irrelevant flags compare->gtFlags |= tree->gtFlags & (GTF_RELOP_JMP_USED | GTF_DONT_CSE); @@ -13706,7 +13651,8 @@ GenTree* Compiler::gtFoldTypeCompare(GenTree* tree) GenTree* const objMT = gtNewMethodTableLookup(objOp); // Compare the two method tables - GenTree* const compare = gtCreateHandleCompare(oper, objMT, knownMT, typeCheckInliningResult); + assert(typeCheckInliningResult == CORINFO_INLINE_TYPECHECK_PASS); + GenTree* const compare = gtNewOperNode(oper, TYP_INT, objMT, knownMT); // Drop any now irrelevant flags compare->gtFlags |= tree->gtFlags & (GTF_RELOP_JMP_USED | GTF_DONT_CSE); @@ -18380,6 +18326,7 @@ CORINFO_CLASS_HANDLE Compiler::gtGetHelperCallClassHandle(GenTreeCall* call, boo } case CORINFO_HELP_NEWARR_1_DIRECT: + case CORINFO_HELP_NEWARR_1_MAYBEFROZEN: case CORINFO_HELP_NEWARR_1_OBJ: case CORINFO_HELP_NEWARR_1_VC: case CORINFO_HELP_NEWARR_1_ALIGN8: diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index fca9e62a5825e..7ae295cb1871e 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -9734,11 +9734,57 @@ 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); + bool isFrozenAllocator = false; + // If we're jitting a static constructor and detect the following code pattern: + // + // newarr + // stsfld + // ret + // + // we emit a "frozen" allocator for newarr to, hopefully, allocate that array on a frozen segment. + // This is a very simple and conservative implementation targeting Array.Empty()'s shape + // Ideally, we want to be able to use frozen allocators more broadly, but such an analysis is + // not trivial. + // + if (((info.compFlags & FLG_CCTOR) == FLG_CCTOR) && + // Does VM allow us to use frozen allocators? + opts.jitFlags->IsSet(JitFlags::JIT_FLAG_FROZEN_ALLOC_ALLOWED)) + { + // Check next two opcodes (have to be STSFLD and RET) + 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) + { + // Check that the field is "static readonly", we don't want to waste memory + // for potentially mutable fields. + 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) + { #ifdef FEATURE_READYTORUN - if (opts.IsReadyToRun()) + if (opts.IsReadyToRun()) + { + // Need to restore array classes before creating array objects on the heap + op1 = impTokenToHandle(&resolvedToken, nullptr, true /*mustRestoreHandle*/); + } +#endif + op1 = gtNewHelperCallNode(CORINFO_HELP_NEWARR_1_MAYBEFROZEN, TYP_REF, op1, op2); + isFrozenAllocator = true; + } + } + } + } + +#ifdef FEATURE_READYTORUN + if (opts.IsReadyToRun() && !isFrozenAllocator) { - 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) @@ -9750,7 +9796,6 @@ void Compiler::impImportBlockCode(BasicBlock* block) // 3) Allocate the new array // Reason: performance (today, we'll always use the slow helper for the R2R generics case) - // Need to restore array classes before creating array objects on the heap op1 = impTokenToHandle(&resolvedToken, nullptr, true /*mustRestoreHandle*/); if (op1 == nullptr) { // compDonotInline() @@ -9759,15 +9804,15 @@ void Compiler::impImportBlockCode(BasicBlock* block) } } - if (!usingReadyToRunHelper) + if (!usingReadyToRunHelper && !isFrozenAllocator) #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); } op1->AsCall()->compileTimeHelperArgumentHandle = (CORINFO_GENERIC_HANDLE)resolvedToken.hClass; diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index e570c99e7537e..90fb4829eedc5 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -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_MAYBEFROZEN) && 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) @@ -2042,7 +2043,8 @@ GenTree* Compiler::impInitializeArrayIntrinsic(CORINFO_SIG_INFO* sig) GenTree* arrayLengthNode; #ifdef FEATURE_READYTORUN - if (newArrayCall->AsCall()->gtCallMethHnd == eeFindHelper(CORINFO_HELP_READYTORUN_NEWARR_1)) + if (newArrayCall->AsCall()->gtCallMethHnd == eeFindHelper(CORINFO_HELP_READYTORUN_NEWARR_1) || + newArrayCall->AsCall()->gtCallMethHnd == eeFindHelper(CORINFO_HELP_NEWARR_1_MAYBEFROZEN)) { // Array length is 1st argument for readytorun helper arrayLengthNode = newArrayCall->AsCall()->gtArgs.GetArgByIndex(0)->GetNode(); diff --git a/src/coreclr/jit/jitee.h b/src/coreclr/jit/jitee.h index 7d3b4f6a624b4..b55719f56e825 100644 --- a/src/coreclr/jit/jitee.h +++ b/src/coreclr/jit/jitee.h @@ -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 *_MAYBEFROZEN allocators JIT_FLAG_UNUSED9 = 16, #if defined(TARGET_X86) || defined(TARGET_AMD64) || defined(TARGET_ARM64) @@ -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); diff --git a/src/coreclr/jit/utils.cpp b/src/coreclr/jit/utils.cpp index 5dcb315af0a35..3e5ad119411e2 100644 --- a/src/coreclr/jit/utils.cpp +++ b/src/coreclr/jit/utils.cpp @@ -1318,6 +1318,7 @@ void HelperCallProperties::init() case CORINFO_HELP_NEWSFAST_ALIGN8: case CORINFO_HELP_NEWSFAST_ALIGN8_VC: case CORINFO_HELP_NEWFAST: + case CORINFO_HELP_NEWFAST_MAYBEFROZEN: case CORINFO_HELP_NEWSFAST_FINALIZE: case CORINFO_HELP_NEWSFAST_ALIGN8_FINALIZE: case CORINFO_HELP_READYTORUN_NEW: @@ -1335,6 +1336,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_MAYBEFROZEN: case CORINFO_HELP_NEWARR_1_OBJ: case CORINFO_HELP_READYTORUN_NEWARR_1: @@ -1386,7 +1388,6 @@ void HelperCallProperties::init() noThrow = true; // These return null for a failing cast break; - case CORINFO_HELP_ARE_TYPES_EQUIVALENT: case CORINFO_HELP_GETCURRENTMANAGEDTHREADID: isPure = true; noThrow = true; diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index 28d8e85abaa73..692f2d660073b 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -12187,6 +12187,14 @@ VNFunc Compiler::fgValueNumberJitHelperMethodVNFunc(CorInfoHelpFunc helpFunc) vnf = VNF_JitReadyToRunNewArr; break; + case CORINFO_HELP_NEWFAST_MAYBEFROZEN: + vnf = opts.IsReadyToRun() ? VNF_JitReadyToRunNew : VNF_JitNew; + break; + + case CORINFO_HELP_NEWARR_1_MAYBEFROZEN: + vnf = opts.IsReadyToRun() ? VNF_JitReadyToRunNewArr : VNF_JitNewArr; + break; + case CORINFO_HELP_GETGENERICS_GCSTATIC_BASE: vnf = VNF_GetgenericsGcstaticBase; break; @@ -12305,10 +12313,6 @@ VNFunc Compiler::fgValueNumberJitHelperMethodVNFunc(CorInfoHelpFunc helpFunc) vnf = VNF_TypeHandleToRuntimeTypeHandle; break; - case CORINFO_HELP_ARE_TYPES_EQUIVALENT: - vnf = VNF_AreTypesEquivalent; - break; - case CORINFO_HELP_READYTORUN_ISINSTANCEOF: vnf = VNF_ReadyToRunIsInstanceOf; break; diff --git a/src/coreclr/jit/valuenumfuncs.h b/src/coreclr/jit/valuenumfuncs.h index 6551be8772a2a..df804121eb98a 100644 --- a/src/coreclr/jit/valuenumfuncs.h +++ b/src/coreclr/jit/valuenumfuncs.h @@ -41,8 +41,6 @@ ValueNumFuncDef(ReadyToRunIsInstanceOf, 2, false, false, false) // Args: 0 ValueNumFuncDef(TypeHandleToRuntimeType, 1, false, false, false) // Args: 0: TypeHandle to translate ValueNumFuncDef(TypeHandleToRuntimeTypeHandle, 1, false, false, false) // Args: 0: TypeHandle to translate -ValueNumFuncDef(AreTypesEquivalent, 2, false, false, false) // Args: 0: first TypeHandle, 1: second TypeHandle - ValueNumFuncDef(LdElemA, 3, false, false, false) // Args: 0: array value; 1: index value; 2: type handle of element. ValueNumFuncDef(ByrefExposedLoad, 3, false, false, false) // Args: 0: type handle/id, 1: pointer value; 2: ByrefExposed heap value diff --git a/src/coreclr/nativeaot/Runtime/inc/ModuleHeaders.h b/src/coreclr/nativeaot/Runtime/inc/ModuleHeaders.h index 7d0c985486c9d..e343de0dab7a0 100644 --- a/src/coreclr/nativeaot/Runtime/inc/ModuleHeaders.h +++ b/src/coreclr/nativeaot/Runtime/inc/ModuleHeaders.h @@ -12,7 +12,7 @@ struct ReadyToRunHeaderConstants static const uint32_t Signature = 0x00525452; // 'RTR' static const uint32_t CurrentMajorVersion = 9; - static const uint32_t CurrentMinorVersion = 0; + static const uint32_t CurrentMinorVersion = 1; }; struct ReadyToRunHeader diff --git a/src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs b/src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs index f198538949666..52d098a0ebc6a 100644 --- a/src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs +++ b/src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs @@ -16,7 +16,7 @@ internal struct ReadyToRunHeaderConstants public const uint Signature = 0x00525452; // 'RTR' public const ushort CurrentMajorVersion = 9; - public const ushort CurrentMinorVersion = 0; + public const ushort CurrentMinorVersion = 1; } #if READYTORUN #pragma warning disable 0169 diff --git a/src/coreclr/tools/Common/Internal/Runtime/ReadyToRunConstants.cs b/src/coreclr/tools/Common/Internal/Runtime/ReadyToRunConstants.cs index f7761dc7872d3..f46904cab3e09 100644 --- a/src/coreclr/tools/Common/Internal/Runtime/ReadyToRunConstants.cs +++ b/src/coreclr/tools/Common/Internal/Runtime/ReadyToRunConstants.cs @@ -256,6 +256,8 @@ public enum ReadyToRunHelper GenericNonGcTlsBase = 0x67, VirtualFuncPtr = 0x68, IsInstanceOfException = 0x69, + NewMaybeFrozenArray = 0x6A, + NewMaybeFrozenObject = 0x6B, // Long mul/div/shift ops LMul = 0xC0, diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs b/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs index 2c7ba7aec14e9..06bc0f6363a09 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs @@ -47,6 +47,7 @@ public enum CorInfoHelpFunc which is the right helper to use to allocate an object of a given type. */ CORINFO_HELP_NEWFAST, + CORINFO_HELP_NEWFAST_MAYBEFROZEN, // allocator for objects that *might* allocate them on a frozen segment CORINFO_HELP_NEWSFAST, // allocator for small, non-finalizer, non-array object CORINFO_HELP_NEWSFAST_FINALIZE, // allocator for small, finalizable, non-array object CORINFO_HELP_NEWSFAST_ALIGN8, // allocator for small, non-finalizer, non-array object, 8 byte aligned @@ -55,6 +56,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_MAYBEFROZEN, // allocator for arrays that *might* allocate them 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 @@ -225,8 +227,6 @@ which is the right helper to use to allocate an object of a given type. */ CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE, // Convert from a TypeHandle (native structure pointer) to RuntimeType at run-time CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE_MAYBENULL, // Convert from a TypeHandle (native structure pointer) to RuntimeTypeHandle at run-time, handle might point to a null type - CORINFO_HELP_ARE_TYPES_EQUIVALENT, // Check whether two TypeHandles (native structure pointers) are equivalent - CORINFO_HELP_VIRTUAL_FUNC_PTR, // look up a virtual method at run-time // Not a real helpers. Instead of taking handle arguments, these helpers point to a small stub that loads the handle argument and calls the static helper. diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 9ad3bd7156dd7..6d3806f298768 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -2571,8 +2571,6 @@ private CorInfoType getTypeForPrimitiveNumericClass(CORINFO_CLASS_STRUCT_* cls) private bool canCast(CORINFO_CLASS_STRUCT_* child, CORINFO_CLASS_STRUCT_* parent) { throw new NotImplementedException("canCast"); } - private bool areTypesEquivalent(CORINFO_CLASS_STRUCT_* cls1, CORINFO_CLASS_STRUCT_* cls2) - { throw new NotImplementedException("areTypesEquivalent"); } private TypeCompareState compareTypesForCast(CORINFO_CLASS_STRUCT_* fromClass, CORINFO_CLASS_STRUCT_* toClass) { diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs index 55c7d70b6618a..3c7f632ef8e7b 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs @@ -1195,21 +1195,6 @@ private static byte _canCast(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLA } } - [UnmanagedCallersOnly] - private static byte _areTypesEquivalent(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls1, CORINFO_CLASS_STRUCT_* cls2) - { - var _this = GetThis(thisHandle); - try - { - return _this.areTypesEquivalent(cls1, cls2) ? (byte)1 : (byte)0; - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default; - } - } - [UnmanagedCallersOnly] private static TypeCompareState _compareTypesForCast(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* fromClass, CORINFO_CLASS_STRUCT_* toClass) { @@ -2745,7 +2730,7 @@ private static uint _getJitFlags(IntPtr thisHandle, IntPtr* ppException, CORJIT_ private static IntPtr GetUnmanagedCallbacks() { - void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 185); + void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 184); callbacks[0] = (delegate* unmanaged)&_isIntrinsic; callbacks[1] = (delegate* unmanaged)&_getMethodAttribs; @@ -2827,111 +2812,110 @@ private static IntPtr GetUnmanagedCallbacks() callbacks[77] = (delegate* unmanaged)&_getTypeForPrimitiveValueClass; callbacks[78] = (delegate* unmanaged)&_getTypeForPrimitiveNumericClass; callbacks[79] = (delegate* unmanaged)&_canCast; - callbacks[80] = (delegate* unmanaged)&_areTypesEquivalent; - callbacks[81] = (delegate* unmanaged)&_compareTypesForCast; - callbacks[82] = (delegate* unmanaged)&_compareTypesForEquality; - callbacks[83] = (delegate* unmanaged)&_mergeClasses; - callbacks[84] = (delegate* unmanaged)&_isMoreSpecificType; - callbacks[85] = (delegate* unmanaged)&_isEnum; - callbacks[86] = (delegate* unmanaged)&_getParentType; - callbacks[87] = (delegate* unmanaged)&_getChildType; - callbacks[88] = (delegate* unmanaged)&_satisfiesClassConstraints; - callbacks[89] = (delegate* unmanaged)&_isSDArray; - callbacks[90] = (delegate* unmanaged)&_getArrayRank; - callbacks[91] = (delegate* unmanaged)&_getArrayIntrinsicID; - callbacks[92] = (delegate* unmanaged)&_getArrayInitializationData; - callbacks[93] = (delegate* unmanaged)&_canAccessClass; - callbacks[94] = (delegate* unmanaged)&_printFieldName; - callbacks[95] = (delegate* unmanaged)&_getFieldClass; - callbacks[96] = (delegate* unmanaged)&_getFieldType; - callbacks[97] = (delegate* unmanaged)&_getFieldOffset; - callbacks[98] = (delegate* unmanaged)&_getFieldInfo; - callbacks[99] = (delegate* unmanaged)&_getThreadLocalFieldInfo; - callbacks[100] = (delegate* unmanaged)&_getThreadLocalStaticBlocksInfo; - callbacks[101] = (delegate* unmanaged)&_isFieldStatic; - callbacks[102] = (delegate* unmanaged)&_getArrayOrStringLength; - callbacks[103] = (delegate* unmanaged)&_getBoundaries; - callbacks[104] = (delegate* unmanaged)&_setBoundaries; - callbacks[105] = (delegate* unmanaged)&_getVars; - callbacks[106] = (delegate* unmanaged)&_setVars; - callbacks[107] = (delegate* unmanaged)&_reportRichMappings; - callbacks[108] = (delegate* unmanaged)&_allocateArray; - callbacks[109] = (delegate* unmanaged)&_freeArray; - callbacks[110] = (delegate* unmanaged)&_getArgNext; - callbacks[111] = (delegate* unmanaged)&_getArgType; - callbacks[112] = (delegate* unmanaged)&_getExactClasses; - callbacks[113] = (delegate* unmanaged)&_getArgClass; - callbacks[114] = (delegate* unmanaged)&_getHFAType; - callbacks[115] = (delegate* unmanaged)&_GetErrorHRESULT; - callbacks[116] = (delegate* unmanaged)&_GetErrorMessage; - callbacks[117] = (delegate* unmanaged)&_FilterException; - callbacks[118] = (delegate* unmanaged)&_ThrowExceptionForJitResult; - callbacks[119] = (delegate* unmanaged)&_ThrowExceptionForHelper; - callbacks[120] = (delegate* unmanaged)&_runWithErrorTrap; - callbacks[121] = (delegate* unmanaged)&_runWithSPMIErrorTrap; - callbacks[122] = (delegate* unmanaged)&_getEEInfo; - callbacks[123] = (delegate* unmanaged)&_getJitTimeLogFilename; - callbacks[124] = (delegate* unmanaged)&_getMethodDefFromMethod; - callbacks[125] = (delegate* unmanaged)&_printMethodName; - callbacks[126] = (delegate* unmanaged)&_getMethodNameFromMetadata; - callbacks[127] = (delegate* unmanaged)&_getMethodHash; - callbacks[128] = (delegate* unmanaged)&_findNameOfToken; - callbacks[129] = (delegate* unmanaged)&_getSystemVAmd64PassStructInRegisterDescriptor; - callbacks[130] = (delegate* unmanaged)&_getLoongArch64PassStructInRegisterFlags; - callbacks[131] = (delegate* unmanaged)&_getRISCV64PassStructInRegisterFlags; - callbacks[132] = (delegate* unmanaged)&_getThreadTLSIndex; - callbacks[133] = (delegate* unmanaged)&_getInlinedCallFrameVptr; - callbacks[134] = (delegate* unmanaged)&_getAddrOfCaptureThreadGlobal; - callbacks[135] = (delegate* unmanaged)&_getHelperFtn; - callbacks[136] = (delegate* unmanaged)&_getFunctionEntryPoint; - callbacks[137] = (delegate* unmanaged)&_getFunctionFixedEntryPoint; - callbacks[138] = (delegate* unmanaged)&_getMethodSync; - callbacks[139] = (delegate* unmanaged)&_getLazyStringLiteralHelper; - callbacks[140] = (delegate* unmanaged)&_embedModuleHandle; - callbacks[141] = (delegate* unmanaged)&_embedClassHandle; - callbacks[142] = (delegate* unmanaged)&_embedMethodHandle; - callbacks[143] = (delegate* unmanaged)&_embedFieldHandle; - callbacks[144] = (delegate* unmanaged)&_embedGenericHandle; - callbacks[145] = (delegate* unmanaged)&_getLocationOfThisType; - callbacks[146] = (delegate* unmanaged)&_getAddressOfPInvokeTarget; - callbacks[147] = (delegate* unmanaged)&_GetCookieForPInvokeCalliSig; - callbacks[148] = (delegate* unmanaged)&_canGetCookieForPInvokeCalliSig; - callbacks[149] = (delegate* unmanaged)&_getJustMyCodeHandle; - callbacks[150] = (delegate* unmanaged)&_GetProfilingHandle; - callbacks[151] = (delegate* unmanaged)&_getCallInfo; - callbacks[152] = (delegate* unmanaged)&_canAccessFamily; - callbacks[153] = (delegate* unmanaged)&_isRIDClassDomainID; - callbacks[154] = (delegate* unmanaged)&_getClassDomainID; - callbacks[155] = (delegate* unmanaged)&_getStaticFieldContent; - callbacks[156] = (delegate* unmanaged)&_getObjectContent; - callbacks[157] = (delegate* unmanaged)&_getStaticFieldCurrentClass; - callbacks[158] = (delegate* unmanaged)&_getVarArgsHandle; - callbacks[159] = (delegate* unmanaged)&_canGetVarArgsHandle; - callbacks[160] = (delegate* unmanaged)&_constructStringLiteral; - callbacks[161] = (delegate* unmanaged)&_emptyStringLiteral; - callbacks[162] = (delegate* unmanaged)&_getFieldThreadLocalStoreID; - callbacks[163] = (delegate* unmanaged)&_GetDelegateCtor; - callbacks[164] = (delegate* unmanaged)&_MethodCompileComplete; - callbacks[165] = (delegate* unmanaged)&_getTailCallHelpers; - callbacks[166] = (delegate* unmanaged)&_convertPInvokeCalliToCall; - callbacks[167] = (delegate* unmanaged)&_notifyInstructionSetUsage; - callbacks[168] = (delegate* unmanaged)&_updateEntryPointForTailCall; - callbacks[169] = (delegate* unmanaged)&_allocMem; - callbacks[170] = (delegate* unmanaged)&_reserveUnwindInfo; - callbacks[171] = (delegate* unmanaged)&_allocUnwindInfo; - callbacks[172] = (delegate* unmanaged)&_allocGCInfo; - callbacks[173] = (delegate* unmanaged)&_setEHcount; - callbacks[174] = (delegate* unmanaged)&_setEHinfo; - callbacks[175] = (delegate* unmanaged)&_logMsg; - callbacks[176] = (delegate* unmanaged)&_doAssert; - callbacks[177] = (delegate* unmanaged)&_reportFatalError; - callbacks[178] = (delegate* unmanaged)&_getPgoInstrumentationResults; - callbacks[179] = (delegate* unmanaged)&_allocPgoInstrumentationBySchema; - callbacks[180] = (delegate* unmanaged)&_recordCallSite; - callbacks[181] = (delegate* unmanaged)&_recordRelocation; - callbacks[182] = (delegate* unmanaged)&_getRelocTypeHint; - callbacks[183] = (delegate* unmanaged)&_getExpectedTargetArchitecture; - callbacks[184] = (delegate* unmanaged)&_getJitFlags; + callbacks[80] = (delegate* unmanaged)&_compareTypesForCast; + callbacks[81] = (delegate* unmanaged)&_compareTypesForEquality; + callbacks[82] = (delegate* unmanaged)&_mergeClasses; + callbacks[83] = (delegate* unmanaged)&_isMoreSpecificType; + callbacks[84] = (delegate* unmanaged)&_isEnum; + callbacks[85] = (delegate* unmanaged)&_getParentType; + callbacks[86] = (delegate* unmanaged)&_getChildType; + callbacks[87] = (delegate* unmanaged)&_satisfiesClassConstraints; + callbacks[88] = (delegate* unmanaged)&_isSDArray; + callbacks[89] = (delegate* unmanaged)&_getArrayRank; + callbacks[90] = (delegate* unmanaged)&_getArrayIntrinsicID; + callbacks[91] = (delegate* unmanaged)&_getArrayInitializationData; + callbacks[92] = (delegate* unmanaged)&_canAccessClass; + callbacks[93] = (delegate* unmanaged)&_printFieldName; + callbacks[94] = (delegate* unmanaged)&_getFieldClass; + callbacks[95] = (delegate* unmanaged)&_getFieldType; + callbacks[96] = (delegate* unmanaged)&_getFieldOffset; + callbacks[97] = (delegate* unmanaged)&_getFieldInfo; + callbacks[98] = (delegate* unmanaged)&_getThreadLocalFieldInfo; + callbacks[99] = (delegate* unmanaged)&_getThreadLocalStaticBlocksInfo; + callbacks[100] = (delegate* unmanaged)&_isFieldStatic; + callbacks[101] = (delegate* unmanaged)&_getArrayOrStringLength; + callbacks[102] = (delegate* unmanaged)&_getBoundaries; + callbacks[103] = (delegate* unmanaged)&_setBoundaries; + callbacks[104] = (delegate* unmanaged)&_getVars; + callbacks[105] = (delegate* unmanaged)&_setVars; + callbacks[106] = (delegate* unmanaged)&_reportRichMappings; + callbacks[107] = (delegate* unmanaged)&_allocateArray; + callbacks[108] = (delegate* unmanaged)&_freeArray; + callbacks[109] = (delegate* unmanaged)&_getArgNext; + callbacks[110] = (delegate* unmanaged)&_getArgType; + callbacks[111] = (delegate* unmanaged)&_getExactClasses; + callbacks[112] = (delegate* unmanaged)&_getArgClass; + callbacks[113] = (delegate* unmanaged)&_getHFAType; + callbacks[114] = (delegate* unmanaged)&_GetErrorHRESULT; + callbacks[115] = (delegate* unmanaged)&_GetErrorMessage; + callbacks[116] = (delegate* unmanaged)&_FilterException; + callbacks[117] = (delegate* unmanaged)&_ThrowExceptionForJitResult; + callbacks[118] = (delegate* unmanaged)&_ThrowExceptionForHelper; + callbacks[119] = (delegate* unmanaged)&_runWithErrorTrap; + callbacks[120] = (delegate* unmanaged)&_runWithSPMIErrorTrap; + callbacks[121] = (delegate* unmanaged)&_getEEInfo; + callbacks[122] = (delegate* unmanaged)&_getJitTimeLogFilename; + callbacks[123] = (delegate* unmanaged)&_getMethodDefFromMethod; + callbacks[124] = (delegate* unmanaged)&_printMethodName; + callbacks[125] = (delegate* unmanaged)&_getMethodNameFromMetadata; + callbacks[126] = (delegate* unmanaged)&_getMethodHash; + callbacks[127] = (delegate* unmanaged)&_findNameOfToken; + callbacks[128] = (delegate* unmanaged)&_getSystemVAmd64PassStructInRegisterDescriptor; + callbacks[129] = (delegate* unmanaged)&_getLoongArch64PassStructInRegisterFlags; + callbacks[130] = (delegate* unmanaged)&_getRISCV64PassStructInRegisterFlags; + callbacks[131] = (delegate* unmanaged)&_getThreadTLSIndex; + callbacks[132] = (delegate* unmanaged)&_getInlinedCallFrameVptr; + callbacks[133] = (delegate* unmanaged)&_getAddrOfCaptureThreadGlobal; + callbacks[134] = (delegate* unmanaged)&_getHelperFtn; + callbacks[135] = (delegate* unmanaged)&_getFunctionEntryPoint; + callbacks[136] = (delegate* unmanaged)&_getFunctionFixedEntryPoint; + callbacks[137] = (delegate* unmanaged)&_getMethodSync; + callbacks[138] = (delegate* unmanaged)&_getLazyStringLiteralHelper; + callbacks[139] = (delegate* unmanaged)&_embedModuleHandle; + callbacks[140] = (delegate* unmanaged)&_embedClassHandle; + callbacks[141] = (delegate* unmanaged)&_embedMethodHandle; + callbacks[142] = (delegate* unmanaged)&_embedFieldHandle; + callbacks[143] = (delegate* unmanaged)&_embedGenericHandle; + callbacks[144] = (delegate* unmanaged)&_getLocationOfThisType; + callbacks[145] = (delegate* unmanaged)&_getAddressOfPInvokeTarget; + callbacks[146] = (delegate* unmanaged)&_GetCookieForPInvokeCalliSig; + callbacks[147] = (delegate* unmanaged)&_canGetCookieForPInvokeCalliSig; + callbacks[148] = (delegate* unmanaged)&_getJustMyCodeHandle; + callbacks[149] = (delegate* unmanaged)&_GetProfilingHandle; + callbacks[150] = (delegate* unmanaged)&_getCallInfo; + callbacks[151] = (delegate* unmanaged)&_canAccessFamily; + callbacks[152] = (delegate* unmanaged)&_isRIDClassDomainID; + callbacks[153] = (delegate* unmanaged)&_getClassDomainID; + callbacks[154] = (delegate* unmanaged)&_getStaticFieldContent; + callbacks[155] = (delegate* unmanaged)&_getObjectContent; + callbacks[156] = (delegate* unmanaged)&_getStaticFieldCurrentClass; + callbacks[157] = (delegate* unmanaged)&_getVarArgsHandle; + callbacks[158] = (delegate* unmanaged)&_canGetVarArgsHandle; + callbacks[159] = (delegate* unmanaged)&_constructStringLiteral; + callbacks[160] = (delegate* unmanaged)&_emptyStringLiteral; + callbacks[161] = (delegate* unmanaged)&_getFieldThreadLocalStoreID; + callbacks[162] = (delegate* unmanaged)&_GetDelegateCtor; + callbacks[163] = (delegate* unmanaged)&_MethodCompileComplete; + callbacks[164] = (delegate* unmanaged)&_getTailCallHelpers; + callbacks[165] = (delegate* unmanaged)&_convertPInvokeCalliToCall; + callbacks[166] = (delegate* unmanaged)&_notifyInstructionSetUsage; + callbacks[167] = (delegate* unmanaged)&_updateEntryPointForTailCall; + callbacks[168] = (delegate* unmanaged)&_allocMem; + callbacks[169] = (delegate* unmanaged)&_reserveUnwindInfo; + callbacks[170] = (delegate* unmanaged)&_allocUnwindInfo; + callbacks[171] = (delegate* unmanaged)&_allocGCInfo; + callbacks[172] = (delegate* unmanaged)&_setEHcount; + callbacks[173] = (delegate* unmanaged)&_setEHinfo; + callbacks[174] = (delegate* unmanaged)&_logMsg; + callbacks[175] = (delegate* unmanaged)&_doAssert; + callbacks[176] = (delegate* unmanaged)&_reportFatalError; + callbacks[177] = (delegate* unmanaged)&_getPgoInstrumentationResults; + callbacks[178] = (delegate* unmanaged)&_allocPgoInstrumentationBySchema; + callbacks[179] = (delegate* unmanaged)&_recordCallSite; + callbacks[180] = (delegate* unmanaged)&_recordRelocation; + callbacks[181] = (delegate* unmanaged)&_getRelocTypeHint; + callbacks[182] = (delegate* unmanaged)&_getExpectedTargetArchitecture; + callbacks[183] = (delegate* unmanaged)&_getJitFlags; return (IntPtr)callbacks; } diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs index 68895109bb56d..cedbbda36b704 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs @@ -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 *_MAYBEFROZEN 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 diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt index 870d86df9136d..b9f8aa66f259e 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -239,7 +239,6 @@ FUNCTIONS CorInfoType getTypeForPrimitiveValueClass(CORINFO_CLASS_HANDLE cls) CorInfoType getTypeForPrimitiveNumericClass(CORINFO_CLASS_HANDLE cls) bool canCast(CORINFO_CLASS_HANDLE child, CORINFO_CLASS_HANDLE parent) - bool areTypesEquivalent(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2) TypeCompareState compareTypesForCast(CORINFO_CLASS_HANDLE fromClass, CORINFO_CLASS_HANDLE toClass) TypeCompareState compareTypesForEquality(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2) CORINFO_CLASS_HANDLE mergeClasses(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2) diff --git a/src/coreclr/tools/ILVerification/ILImporter.StackValue.cs b/src/coreclr/tools/ILVerification/ILImporter.StackValue.cs index 09b1890d91ea4..18c9736aeb3f5 100644 --- a/src/coreclr/tools/ILVerification/ILImporter.StackValue.cs +++ b/src/coreclr/tools/ILVerification/ILImporter.StackValue.cs @@ -611,7 +611,8 @@ bool IsAssignable(StackValue src, StackValue dst) return FALSE; // Structures are compatible if they are equivalent - return jitInfo->areTypesEquivalent(child.m_cls, parent.m_cls); + // return jitInfo->areTypesEquivalent(child.m_cls, parent.m_cls); + return child.m_cls == parent.m_cls; } else if (parent.IsByRef()) { diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilationBuilder.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilationBuilder.cs index 33388962e8679..573eacc1fcc4c 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilationBuilder.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilationBuilder.cs @@ -291,6 +291,10 @@ public override ICompilation ToCompilation() break; } + // Always allow frozen allocators for R2R (NativeAOT is able to preinitialize objects on + // frozen segments without JIT's help) + corJitFlags.Add(CorJitFlag.CORJIT_FLAG_FROZEN_ALLOC_ALLOWED); + if (!_isJitInitialized) { JitConfigProvider.Initialize(_context.Target, corJitFlags, _ryujitOptions, _jitPath); diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs index e0617683dce46..f73c55cd0dc67 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs @@ -898,6 +898,12 @@ private ISymbolNode GetHelperFtnUncached(CorInfoHelpFunc ftnNum) case CorInfoHelpFunc.CORINFO_HELP_NEWARR_1_DIRECT: id = ReadyToRunHelper.NewArray; break; + case CorInfoHelpFunc.CORINFO_HELP_NEWARR_1_MAYBEFROZEN: + id = ReadyToRunHelper.NewMaybeFrozenArray; + break; + case CorInfoHelpFunc.CORINFO_HELP_NEWFAST_MAYBEFROZEN: + id = ReadyToRunHelper.NewMaybeFrozenObject; + break; case CorInfoHelpFunc.CORINFO_HELP_VIRTUAL_FUNC_PTR: id = ReadyToRunHelper.VirtualFuncPtr; break; diff --git a/src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ReadyToRunSignature.cs b/src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ReadyToRunSignature.cs index 2d123c39d6178..8d325f467d600 100644 --- a/src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ReadyToRunSignature.cs +++ b/src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ReadyToRunSignature.cs @@ -1774,6 +1774,14 @@ private void ParseHelper(StringBuilder builder) builder.Append("NEW_ARRAY"); break; + case ReadyToRunHelper.NewMaybeFrozenArray: + builder.Append("NEW_MAYBEFROZEN_ARRAY"); + break; + + case ReadyToRunHelper.NewMaybeFrozenObject: + builder.Append("NEW_MAYBEFROZEN_OBJECT"); + break; + case ReadyToRunHelper.CheckCastAny: builder.Append("CHECK_CAST_ANY"); break; diff --git a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h index 038abebbeceac..62db21d2232e2 100644 --- a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h +++ b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h @@ -91,7 +91,6 @@ struct JitInterfaceCallbacks CorInfoType (* getTypeForPrimitiveValueClass)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls); CorInfoType (* getTypeForPrimitiveNumericClass)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls); bool (* canCast)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE child, CORINFO_CLASS_HANDLE parent); - bool (* areTypesEquivalent)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2); TypeCompareState (* compareTypesForCast)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE fromClass, CORINFO_CLASS_HANDLE toClass); TypeCompareState (* compareTypesForEquality)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2); CORINFO_CLASS_HANDLE (* mergeClasses)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2); @@ -992,16 +991,6 @@ class JitInterfaceWrapper : public ICorJitInfo return temp; } - virtual bool areTypesEquivalent( - CORINFO_CLASS_HANDLE cls1, - CORINFO_CLASS_HANDLE cls2) -{ - CorInfoExceptionClass* pException = nullptr; - bool temp = _callbacks->areTypesEquivalent(_thisHandle, &pException, cls1, cls2); - if (pException != nullptr) throw pException; - return temp; -} - virtual TypeCompareState compareTypesForCast( CORINFO_CLASS_HANDLE fromClass, CORINFO_CLASS_HANDLE toClass) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h index 0a26a5d05774f..19a0600b3f582 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h @@ -18,7 +18,6 @@ LWM(AllocPgoInstrumentationBySchema, DWORDLONG, Agnostic_AllocPgoInstrumentationBySchema) LWM(GetPgoInstrumentationResults, DWORDLONG, Agnostic_GetPgoInstrumentationResults) -LWM(AreTypesEquivalent, DLDL, DWORD) LWM(AsCorInfoType, DWORDLONG, DWORD) LWM(CanAccessClass, Agnostic_CanAccessClassIn, Agnostic_CanAccessClassOut) LWM(CanAccessFamily, DLDL, DWORD) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index 43032b7616103..469ff6f6d56d9 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -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: @@ -6194,37 +6196,6 @@ CORINFO_FIELD_HANDLE MethodContext::repEmbedFieldHandle(CORINFO_FIELD_HANDLE han return (CORINFO_FIELD_HANDLE)value.B; } -void MethodContext::recAreTypesEquivalent(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2, bool result) -{ - if (AreTypesEquivalent == nullptr) - AreTypesEquivalent = new LightWeightMap(); - - DLDL key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.A = CastHandle(cls1); - key.B = CastHandle(cls2); - - DWORD value = result ? 1 : 0; - AreTypesEquivalent->Add(key, value); - DEBUG_REC(dmpAreTypesEquivalent(key, value)); -} -void MethodContext::dmpAreTypesEquivalent(DLDL key, DWORD value) -{ - printf("AreTypesEquivalent NYI"); -} -bool MethodContext::repAreTypesEquivalent(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2) -{ - DLDL key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.A = CastHandle(cls1); - key.B = CastHandle(cls2); - - DWORD value = LookupByKeyOrMiss(AreTypesEquivalent, key, ": key %016" PRIX64 " %016" PRIX64 "", key.A, key.B); - - DEBUG_REP(dmpAreTypesEquivalent(key, value)); - return value != 0; -} - void MethodContext::recCompareTypesForCast(CORINFO_CLASS_HANDLE fromClass, CORINFO_CLASS_HANDLE toClass, TypeCompareState result) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h index d8935bb4f806b..53b3b02f745ea 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h @@ -777,10 +777,6 @@ class MethodContext void dmpEmbedFieldHandle(DWORDLONG key, DLDL value); CORINFO_FIELD_HANDLE repEmbedFieldHandle(CORINFO_FIELD_HANDLE handle, void** ppIndirection); - void recAreTypesEquivalent(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2, bool result); - void dmpAreTypesEquivalent(DLDL key, DWORD value); - bool repAreTypesEquivalent(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2); - void recCompareTypesForCast(CORINFO_CLASS_HANDLE fromClass, CORINFO_CLASS_HANDLE toClass, TypeCompareState result); void dmpCompareTypesForCast(DLDL key, DWORD value); TypeCompareState repCompareTypesForCast(CORINFO_CLASS_HANDLE fromClass, CORINFO_CLASS_HANDLE toClass); @@ -986,7 +982,7 @@ class MethodContext enum mcPackets { - Packet_AreTypesEquivalent = 1, + //Packet_AreTypesEquivalent = 1, Packet_AsCorInfoType = 2, Packet_CanAccessClass = 3, Packet_CanAccessFamily = 4, diff --git a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp index 6adbb6ac6f624..96249dde36c0d 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -898,15 +898,6 @@ bool interceptor_ICJI::canCast(CORINFO_CLASS_HANDLE child, // subtype (extends p return temp; } -// TRUE if cls1 and cls2 are considered equivalent types. -bool interceptor_ICJI::areTypesEquivalent(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2) -{ - mc->cr->AddCall("areTypesEquivalent"); - bool temp = original_ICorJitInfo->areTypesEquivalent(cls1, cls2); - mc->recAreTypesEquivalent(cls1, cls2, temp); - return temp; -} - // See if a cast from fromClass to toClass will succeed, fail, or needs // to be resolved at runtime. TypeCompareState interceptor_ICJI::compareTypesForCast(CORINFO_CLASS_HANDLE fromClass, CORINFO_CLASS_HANDLE toClass) diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp index e4aa9e7e69af8..58dc80abec8e1 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp @@ -650,14 +650,6 @@ bool interceptor_ICJI::canCast( return original_ICorJitInfo->canCast(child, parent); } -bool interceptor_ICJI::areTypesEquivalent( - CORINFO_CLASS_HANDLE cls1, - CORINFO_CLASS_HANDLE cls2) -{ - mcs->AddCall("areTypesEquivalent"); - return original_ICorJitInfo->areTypesEquivalent(cls1, cls2); -} - TypeCompareState interceptor_ICJI::compareTypesForCast( CORINFO_CLASS_HANDLE fromClass, CORINFO_CLASS_HANDLE toClass) diff --git a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp index d832d82b4f3b5..a9dced511ddce 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp @@ -570,13 +570,6 @@ bool interceptor_ICJI::canCast( return original_ICorJitInfo->canCast(child, parent); } -bool interceptor_ICJI::areTypesEquivalent( - CORINFO_CLASS_HANDLE cls1, - CORINFO_CLASS_HANDLE cls2) -{ - return original_ICorJitInfo->areTypesEquivalent(cls1, cls2); -} - TypeCompareState interceptor_ICJI::compareTypesForCast( CORINFO_CLASS_HANDLE fromClass, CORINFO_CLASS_HANDLE toClass) diff --git a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp index 3b25e9ad9f076..9915b4699eeeb 100644 --- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp @@ -759,13 +759,6 @@ bool MyICJI::canCast(CORINFO_CLASS_HANDLE child, // subtype (extends parent) return jitInstance->mc->repCanCast(child, parent); } -// TRUE if cls1 and cls2 are considered equivalent types. -bool MyICJI::areTypesEquivalent(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2) -{ - jitInstance->mc->cr->AddCall("areTypesEquivalent"); - return jitInstance->mc->repAreTypesEquivalent(cls1, cls2); -} - // See if a cast from fromClass to toClass will succeed, fail, or needs // to be resolved at runtime. TypeCompareState MyICJI::compareTypesForCast(CORINFO_CLASS_HANDLE fromClass, CORINFO_CLASS_HANDLE toClass) diff --git a/src/coreclr/vm/frozenobjectheap.cpp b/src/coreclr/vm/frozenobjectheap.cpp index 036177d1b7e95..46c0dce83ce5c 100644 --- a/src/coreclr/vm/frozenobjectheap.cpp +++ b/src/coreclr/vm/frozenobjectheap.cpp @@ -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)); diff --git a/src/coreclr/vm/gchelpers.cpp b/src/coreclr/vm/gchelpers.cpp index cccf11914aad2..e3c882f623b24 100644 --- a/src/coreclr/vm/gchelpers.cpp +++ b/src/coreclr/vm/gchelpers.cpp @@ -493,6 +493,83 @@ OBJECTREF AllocateSzArray(MethodTable* pArrayMT, INT32 cElements, GC_ALLOC_FLAGS return ObjectToOBJECTREF((Object*)orArray); } +OBJECTREF TryAllocateFrozenSzArray(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 NULL; + } + + // 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 NULL; + } +#ifdef FEATURE_64BIT_ALIGNMENT + MethodTable* pElementMT = pArrayMT->GetArrayElementTypeHandle().GetMethodTable(); + if (pElementMT->RequiresAlign8() && pElementMT->IsValueType()) + { + return NULL; + } +#endif + + FrozenObjectHeapManager* foh = SystemDomain::GetFrozenObjectHeapManager(); + ArrayBase* orArray = static_cast(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 NULL; + } + 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 { @@ -1036,6 +1113,37 @@ OBJECTREF AllocateObject(MethodTable *pMT return UNCHECKED_OBJECTREF_TO_OBJECTREF(oref); } +OBJECTREF TryAllocateFrozenObject(MethodTable* pObjMT) +{ + CONTRACTL { + THROWS; + GC_TRIGGERS; + MODE_COOPERATIVE; + PRECONDITION(CheckPointer(pObjMT)); + PRECONDITION(pObjMT->CheckInstanceActivated()); + } CONTRACTL_END; + + SetTypeHandleOnThreadForAlloc(TypeHandle(pObjMT)); + + if (pObjMT->ContainsPointers() || pObjMT->IsComObjectType()) + { + return NULL; + } + +#ifdef FEATURE_64BIT_ALIGNMENT + if (pObjMT->RequiresAlign8()) + { + // Custom alignment is not supported for frozen objects yet. + return NULL; + } +#endif // FEATURE_64BIT_ALIGNMENT + + FrozenObjectHeapManager* foh = SystemDomain::GetFrozenObjectHeapManager(); + Object* orObject = foh->TryAllocateObject(pObjMT, PtrAlign(pObjMT->GetBaseSize()), /*publish*/ true); + + return ObjectToOBJECTREF(orObject); +} + //======================================================================== // // WRITE BARRIER HELPERS diff --git a/src/coreclr/vm/gchelpers.h b/src/coreclr/vm/gchelpers.h index 3a0382f6f6bb6..3528ef8bb47b4 100644 --- a/src/coreclr/vm/gchelpers.h +++ b/src/coreclr/vm/gchelpers.h @@ -23,6 +23,12 @@ 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 on a frozen segment +// Returns nullptr if it's not possible. +OBJECTREF TryAllocateFrozenSzArray(MethodTable* pArrayMT, INT32 length); +// Same for non-array objects +OBJECTREF TryAllocateFrozenObject(MethodTable* pObjMT); + // 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); diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index a6654618a9541..084281763c010 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -2404,6 +2404,37 @@ HCIMPL1(Object*, JIT_New, CORINFO_CLASS_HANDLE typeHnd_) } HCIMPLEND +/*************************************************************/ +HCIMPL1(Object*, JIT_NewMaybeFrozen, CORINFO_CLASS_HANDLE typeHnd_) +{ + FCALL_CONTRACT; + + OBJECTREF newobj = NULL; + HELPER_METHOD_FRAME_BEGIN_RET_0(); // Set up a frame + + TypeHandle typeHnd(typeHnd_); + + _ASSERTE(!typeHnd.IsTypeDesc()); // heap objects must have method tables + MethodTable* pMT = typeHnd.AsMethodTable(); + _ASSERTE(pMT->IsRestored_NoLogging()); + +#ifdef _DEBUG + if (g_pConfig->FastGCStressLevel()) { + GetThread()->DisableStressHeap(); + } +#endif // _DEBUG + + newobj = TryAllocateFrozenObject(pMT); + if (newobj == NULL) + { + // Fallback to normal heap allocation. + newobj = AllocateObject(pMT); + } + + HELPER_METHOD_FRAME_END(); + return(OBJECTREFToObject(newobj)); +} +HCIMPLEND //======================================================================== @@ -2719,6 +2750,53 @@ HCIMPL2(Object*, JIT_NewArr1, CORINFO_CLASS_HANDLE arrayMT, INT_PTR size) } HCIMPLEND + +/*************************************************************/ +HCIMPL2(Object*, JIT_NewArr1MaybeFrozen, 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 = TryAllocateFrozenSzArray(pArrayMT, (INT32)size); + if (newArray == NULL) + { + // Fallback to default heap allocation + newArray = AllocateSzArray(pArrayMT, (INT32)size); + } + _ASSERTE(newArray != NULL); + + HELPER_METHOD_FRAME_END(); + + return(OBJECTREFToObject(newArray)); +} +HCIMPLEND + /*************************************************************/ HCIMPL3(Object*, JIT_NewMDArr, CORINFO_CLASS_HANDLE classHnd, unsigned dwNumArgs, INT32 * pArgList) { diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 30ba16e9770ea..62a4400c7d86c 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -747,7 +747,7 @@ size_t CEEInfo::printObjectDescription ( } else { - _ASSERTE(!"Unexpected object type"); + obj->GetMethodTable()->_GetFullyQualifiedNameForClass(stackStr); } const UTF8* utf8data = stackStr.GetUTF8(); @@ -4205,29 +4205,6 @@ bool CEEInfo::canCast( return result; } -/*********************************************************************/ -// TRUE if cls1 and cls2 are considered equivalent types. -bool CEEInfo::areTypesEquivalent( - CORINFO_CLASS_HANDLE cls1, - CORINFO_CLASS_HANDLE cls2) -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_PREEMPTIVE; - } CONTRACTL_END; - - bool result = false; - - JIT_TO_EE_TRANSITION(); - - result = !!((TypeHandle)cls1).IsEquivalentTo((TypeHandle)cls2); - - EE_TO_JIT_TRANSITION(); - - return result; -} - /*********************************************************************/ // See if a cast from fromClass to toClass will succeed, fail, or needs // to be resolved at runtime. @@ -6157,20 +6134,33 @@ bool CEEInfo::isObjectImmutable(CORINFO_OBJECT_HANDLE objHandle) _ASSERT(objHandle != NULL); -#ifdef DEBUG + bool isImmutable = false; + JIT_TO_EE_TRANSITION(); GCX_COOP(); OBJECTREF obj = getObjectFromJitHandle(objHandle); MethodTable* type = obj->GetMethodTable(); - _ASSERTE(type->IsString() || type == g_pRuntimeTypeClass); + if (type->IsString() || type == g_pRuntimeTypeClass) + { + // These types are always immutable + isImmutable = true; + } + else if (type->IsArray() && ((ArrayBase*)OBJECTREFToObject(obj))->GetComponentSize() == 0) + { + // Empty arrays are always immutable + isImmutable = true; + } + else if (type->IsDelegate() || type->GetNumInstanceFields() == 0) + { + // Delegates and types without fields are always immutable + isImmutable = true; + } EE_TO_JIT_TRANSITION(); -#endif - // All currently allocated frozen objects can be treated as immutable - return true; + return isImmutable; } /***********************************************************************/ @@ -12869,6 +12859,12 @@ CORJIT_FLAGS GetCompileFlags(MethodDesc * ftn, CORJIT_FLAGS flags, CORINFO_METHO flags.Set(CORJIT_FLAGS::CORJIT_FLAG_PROF_NO_PINVOKE_INLINE); #endif // PROFILING_SUPPORTED + // Don't allow allocations on FOH from collectible contexts to avoid memory leaks + if (!ftn->GetLoaderAllocator()->CanUnload()) + { + flags.Set(CORJIT_FLAGS::CORJIT_FLAG_FROZEN_ALLOC_ALLOWED); + } + // Set optimization flags if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_MIN_OPT)) { diff --git a/src/coreclr/vm/object.h b/src/coreclr/vm/object.h index d608fe0493a55..cca2b7e8ba849 100644 --- a/src/coreclr/vm/object.h +++ b/src/coreclr/vm/object.h @@ -522,6 +522,7 @@ class ArrayBase : public Object friend class CObjectHeader; friend class Object; friend OBJECTREF AllocateSzArray(MethodTable *pArrayMT, INT32 length, GC_ALLOC_FLAGS flags); + friend OBJECTREF TryAllocateFrozenSzArray(MethodTable* pArrayMT, INT32 length); friend OBJECTREF AllocateArrayEx(MethodTable *pArrayMT, INT32 *pArgs, DWORD dwNumArgs, GC_ALLOC_FLAGS flags); 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);