From 9c15c1f95d8f880513dc73cbd5fab42fd215b614 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Tue, 13 Sep 2022 23:16:01 +0200 Subject: [PATCH 01/39] Allocate Type objects on Frozen Heap --- src/coreclr/inc/corinfo.h | 4 + src/coreclr/inc/icorjitinfoimpl_generated.h | 3 + src/coreclr/inc/jiteeversionguid.h | 10 +- src/coreclr/jit/ICorJitInfo_API_names.h | 1 + src/coreclr/jit/ICorJitInfo_API_wrapper.hpp | 9 + src/coreclr/jit/importer.cpp | 17 +- .../tools/Common/JitInterface/CorInfoBase.cs | 237 ++++++++++-------- .../tools/Common/JitInterface/CorInfoImpl.cs | 7 + .../ThunkGenerator/ThunkInput.txt | 1 + .../tools/aot/jitinterface/jitinterface.h | 10 + .../tools/superpmi/superpmi-shared/lwmlist.h | 1 + .../superpmi-shared/methodcontext.cpp | 23 ++ .../superpmi/superpmi-shared/methodcontext.h | 5 + .../superpmi-shim-collector/icorjitinfo.cpp | 8 + .../superpmi-shim-counter/icorjitinfo.cpp | 7 + .../superpmi-shim-simple/icorjitinfo.cpp | 6 + .../tools/superpmi/superpmi/icorjitinfo.cpp | 7 + src/coreclr/vm/frozenobjectheap.cpp | 9 + src/coreclr/vm/frozenobjectheap.h | 1 + src/coreclr/vm/jitinterface.cpp | 32 +++ src/coreclr/vm/methodtable.cpp | 15 +- src/coreclr/vm/methodtable.h | 2 +- src/coreclr/vm/methodtable.inl | 12 +- 23 files changed, 307 insertions(+), 120 deletions(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 2be3d438c9327d..09d9a651352c0e 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -2475,6 +2475,10 @@ class ICorStaticInfo CORINFO_CLASS_HANDLE cls ) = 0; + virtual void* getRuntimeTypePointer( + CORINFO_CLASS_HANDLE cls + ) = 0; + virtual bool getReadyToRunHelper( CORINFO_RESOLVED_TOKEN * pResolvedToken, CORINFO_LOOKUP_KIND * pGenericLookupKind, diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h index 3a5a164e9aa717..5f2d3b88ac208a 100644 --- a/src/coreclr/inc/icorjitinfoimpl_generated.h +++ b/src/coreclr/inc/icorjitinfoimpl_generated.h @@ -280,6 +280,9 @@ CorInfoHelpFunc getBoxHelper( CorInfoHelpFunc getUnBoxHelper( CORINFO_CLASS_HANDLE cls) override; +void* getRuntimeTypePointer( + CORINFO_CLASS_HANDLE cls) override; + bool getReadyToRunHelper( CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_LOOKUP_KIND* pGenericLookupKind, diff --git a/src/coreclr/inc/jiteeversionguid.h b/src/coreclr/inc/jiteeversionguid.h index 68d305e4f5d5d8..46f90221f4a9e8 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 = { /* 0cd8b9d4-04f4-45a7-b16b-7f24b7c0a454 */ - 0x0cd8b9d4, - 0x04f4, - 0x45a7, - {0xb1, 0x6b, 0x7f, 0x24, 0xb7, 0xc0, 0xa4, 0x54} +constexpr GUID JITEEVersionIdentifier = { /* 104b5beb-d585-4d52-b08a-d5c6938603fc */ + 0x104b5beb, + 0xd585, + 0x4d52, + {0xb0, 0x8a, 0xd5, 0xc6, 0x93, 0x86, 0x3, 0xfc} }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/coreclr/jit/ICorJitInfo_API_names.h b/src/coreclr/jit/ICorJitInfo_API_names.h index 0c5af5b9e802a3..24a1f903e20786 100644 --- a/src/coreclr/jit/ICorJitInfo_API_names.h +++ b/src/coreclr/jit/ICorJitInfo_API_names.h @@ -70,6 +70,7 @@ DEF_CLR_API(getSharedCCtorHelper) DEF_CLR_API(getTypeForBox) DEF_CLR_API(getBoxHelper) DEF_CLR_API(getUnBoxHelper) +DEF_CLR_API(getRuntimeTypePointer) DEF_CLR_API(getReadyToRunHelper) DEF_CLR_API(getReadyToRunDelegateCtorHelper) DEF_CLR_API(getHelperName) diff --git a/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp b/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp index 96139cc6cd4ef0..ff7cf2035b97f8 100644 --- a/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp +++ b/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp @@ -652,6 +652,15 @@ CorInfoHelpFunc WrapICorJitInfo::getUnBoxHelper( return temp; } +void* WrapICorJitInfo::getRuntimeTypePointer( + CORINFO_CLASS_HANDLE cls) +{ + API_ENTER(getRuntimeTypePointer); + void* temp = wrapHnd->getRuntimeTypePointer(cls); + API_LEAVE(getRuntimeTypePointer); + return temp; +} + bool WrapICorJitInfo::getReadyToRunHelper( CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_LOOKUP_KIND* pGenericLookupKind, diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 634a4ee22902dd..4395618dcae487 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -4046,7 +4046,22 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis, op1 = impPopStack().val; // Replace helper with a more specialized helper that returns RuntimeType if (typeHandleHelper == CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE) - { + { + CORINFO_CLASS_HANDLE hClass = + gtGetHelperArgClassHandle(op1->AsCall()->gtArgs.GetArgByIndex(0)->GetEarlyNode()); + if (!opts.IsReadyToRun() && (hClass != NO_CLASS_HANDLE)) + { + void* ptr = info.compCompHnd->getRuntimeTypePointer(hClass); + if (ptr != nullptr) + { + // Temp Hack: pretend we're a string literal :-) + setMethodHasFrozenString(); + retNode = gtNewIconEmbHndNode(ptr, nullptr, GTF_ICON_STR_HDL, nullptr); + retNode->gtType = TYP_REF; + INDEBUG(retNode->AsIntCon()->gtTargetHandle = (size_t)ptr); + break; + } + } typeHandleHelper = CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE; } else diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs b/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs index 2aa2105765b84d..a8cbd191399fe5 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs @@ -987,6 +987,21 @@ private static CorInfoHelpFunc _getUnBoxHelper(IntPtr thisHandle, IntPtr* ppExce } } + [UnmanagedCallersOnly] + private static void* _getRuntimeTypePointer(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) + { + var _this = GetThis(thisHandle); + try + { + return _this.getRuntimeTypePointer(cls); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default; + } + } + [UnmanagedCallersOnly] private static byte _getReadyToRunHelper(IntPtr thisHandle, IntPtr* ppException, CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_LOOKUP_KIND* pGenericLookupKind, CorInfoHelpFunc id, CORINFO_CONST_LOOKUP* pLookup) { @@ -2592,9 +2607,10 @@ private static uint _getJitFlags(IntPtr thisHandle, IntPtr* ppException, CORJIT_ } } + private static IntPtr GetUnmanagedCallbacks() { - void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 175); + void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 176); callbacks[0] = (delegate* unmanaged)&_isIntrinsic; callbacks[1] = (delegate* unmanaged)&_getMethodAttribs; @@ -2662,115 +2678,116 @@ private static IntPtr GetUnmanagedCallbacks() callbacks[63] = (delegate* unmanaged)&_getTypeForBox; callbacks[64] = (delegate* unmanaged)&_getBoxHelper; callbacks[65] = (delegate* unmanaged)&_getUnBoxHelper; - callbacks[66] = (delegate* unmanaged)&_getReadyToRunHelper; - callbacks[67] = (delegate* unmanaged)&_getReadyToRunDelegateCtorHelper; - callbacks[68] = (delegate* unmanaged)&_getHelperName; - callbacks[69] = (delegate* unmanaged)&_initClass; - callbacks[70] = (delegate* unmanaged)&_classMustBeLoadedBeforeCodeIsRun; - callbacks[71] = (delegate* unmanaged)&_getBuiltinClass; - callbacks[72] = (delegate* unmanaged)&_getTypeForPrimitiveValueClass; - callbacks[73] = (delegate* unmanaged)&_getTypeForPrimitiveNumericClass; - callbacks[74] = (delegate* unmanaged)&_canCast; - callbacks[75] = (delegate* unmanaged)&_areTypesEquivalent; - callbacks[76] = (delegate* unmanaged)&_compareTypesForCast; - callbacks[77] = (delegate* unmanaged)&_compareTypesForEquality; - callbacks[78] = (delegate* unmanaged)&_mergeClasses; - callbacks[79] = (delegate* unmanaged)&_isMoreSpecificType; - callbacks[80] = (delegate* unmanaged)&_getParentType; - callbacks[81] = (delegate* unmanaged)&_getChildType; - callbacks[82] = (delegate* unmanaged)&_satisfiesClassConstraints; - callbacks[83] = (delegate* unmanaged)&_isSDArray; - callbacks[84] = (delegate* unmanaged)&_getArrayRank; - callbacks[85] = (delegate* unmanaged)&_getArrayIntrinsicID; - callbacks[86] = (delegate* unmanaged)&_getArrayInitializationData; - callbacks[87] = (delegate* unmanaged)&_canAccessClass; - callbacks[88] = (delegate* unmanaged)&_getFieldName; - callbacks[89] = (delegate* unmanaged)&_getFieldClass; - callbacks[90] = (delegate* unmanaged)&_getFieldType; - callbacks[91] = (delegate* unmanaged)&_getFieldOffset; - callbacks[92] = (delegate* unmanaged)&_getFieldInfo; - callbacks[93] = (delegate* unmanaged)&_isFieldStatic; - callbacks[94] = (delegate* unmanaged)&_getBoundaries; - callbacks[95] = (delegate* unmanaged)&_setBoundaries; - callbacks[96] = (delegate* unmanaged)&_getVars; - callbacks[97] = (delegate* unmanaged)&_setVars; - callbacks[98] = (delegate* unmanaged)&_reportRichMappings; - callbacks[99] = (delegate* unmanaged)&_allocateArray; - callbacks[100] = (delegate* unmanaged)&_freeArray; - callbacks[101] = (delegate* unmanaged)&_getArgNext; - callbacks[102] = (delegate* unmanaged)&_getArgType; - callbacks[103] = (delegate* unmanaged)&_getExactClasses; - callbacks[104] = (delegate* unmanaged)&_getArgClass; - callbacks[105] = (delegate* unmanaged)&_getHFAType; - callbacks[106] = (delegate* unmanaged)&_GetErrorHRESULT; - callbacks[107] = (delegate* unmanaged)&_GetErrorMessage; - callbacks[108] = (delegate* unmanaged)&_FilterException; - callbacks[109] = (delegate* unmanaged)&_ThrowExceptionForJitResult; - callbacks[110] = (delegate* unmanaged)&_ThrowExceptionForHelper; - callbacks[111] = (delegate* unmanaged)&_runWithErrorTrap; - callbacks[112] = (delegate* unmanaged)&_runWithSPMIErrorTrap; - callbacks[113] = (delegate* unmanaged)&_getEEInfo; - callbacks[114] = (delegate* unmanaged)&_getJitTimeLogFilename; - callbacks[115] = (delegate* unmanaged)&_getMethodDefFromMethod; - callbacks[116] = (delegate* unmanaged)&_getMethodName; - callbacks[117] = (delegate* unmanaged)&_getMethodNameFromMetadata; - callbacks[118] = (delegate* unmanaged)&_getMethodHash; - callbacks[119] = (delegate* unmanaged)&_findNameOfToken; - callbacks[120] = (delegate* unmanaged)&_getSystemVAmd64PassStructInRegisterDescriptor; - callbacks[121] = (delegate* unmanaged)&_getLoongArch64PassStructInRegisterFlags; - callbacks[122] = (delegate* unmanaged)&_getThreadTLSIndex; - callbacks[123] = (delegate* unmanaged)&_getInlinedCallFrameVptr; - callbacks[124] = (delegate* unmanaged)&_getAddrOfCaptureThreadGlobal; - callbacks[125] = (delegate* unmanaged)&_getHelperFtn; - callbacks[126] = (delegate* unmanaged)&_getFunctionEntryPoint; - callbacks[127] = (delegate* unmanaged)&_getFunctionFixedEntryPoint; - callbacks[128] = (delegate* unmanaged)&_getMethodSync; - callbacks[129] = (delegate* unmanaged)&_getLazyStringLiteralHelper; - callbacks[130] = (delegate* unmanaged)&_embedModuleHandle; - callbacks[131] = (delegate* unmanaged)&_embedClassHandle; - callbacks[132] = (delegate* unmanaged)&_embedMethodHandle; - callbacks[133] = (delegate* unmanaged)&_embedFieldHandle; - callbacks[134] = (delegate* unmanaged)&_embedGenericHandle; - callbacks[135] = (delegate* unmanaged)&_getLocationOfThisType; - callbacks[136] = (delegate* unmanaged)&_getAddressOfPInvokeTarget; - callbacks[137] = (delegate* unmanaged)&_GetCookieForPInvokeCalliSig; - callbacks[138] = (delegate* unmanaged)&_canGetCookieForPInvokeCalliSig; - callbacks[139] = (delegate* unmanaged)&_getJustMyCodeHandle; - callbacks[140] = (delegate* unmanaged)&_GetProfilingHandle; - callbacks[141] = (delegate* unmanaged)&_getCallInfo; - callbacks[142] = (delegate* unmanaged)&_canAccessFamily; - callbacks[143] = (delegate* unmanaged)&_isRIDClassDomainID; - callbacks[144] = (delegate* unmanaged)&_getClassDomainID; - callbacks[145] = (delegate* unmanaged)&_getFieldAddress; - callbacks[146] = (delegate* unmanaged)&_getStaticFieldCurrentClass; - callbacks[147] = (delegate* unmanaged)&_getVarArgsHandle; - callbacks[148] = (delegate* unmanaged)&_canGetVarArgsHandle; - callbacks[149] = (delegate* unmanaged)&_constructStringLiteral; - callbacks[150] = (delegate* unmanaged)&_emptyStringLiteral; - callbacks[151] = (delegate* unmanaged)&_getFieldThreadLocalStoreID; - callbacks[152] = (delegate* unmanaged)&_addActiveDependency; - callbacks[153] = (delegate* unmanaged)&_GetDelegateCtor; - callbacks[154] = (delegate* unmanaged)&_MethodCompileComplete; - callbacks[155] = (delegate* unmanaged)&_getTailCallHelpers; - callbacks[156] = (delegate* unmanaged)&_convertPInvokeCalliToCall; - callbacks[157] = (delegate* unmanaged)&_notifyInstructionSetUsage; - callbacks[158] = (delegate* unmanaged)&_updateEntryPointForTailCall; - callbacks[159] = (delegate* unmanaged)&_allocMem; - callbacks[160] = (delegate* unmanaged)&_reserveUnwindInfo; - callbacks[161] = (delegate* unmanaged)&_allocUnwindInfo; - callbacks[162] = (delegate* unmanaged)&_allocGCInfo; - callbacks[163] = (delegate* unmanaged)&_setEHcount; - callbacks[164] = (delegate* unmanaged)&_setEHinfo; - callbacks[165] = (delegate* unmanaged)&_logMsg; - callbacks[166] = (delegate* unmanaged)&_doAssert; - callbacks[167] = (delegate* unmanaged)&_reportFatalError; - callbacks[168] = (delegate* unmanaged)&_getPgoInstrumentationResults; - callbacks[169] = (delegate* unmanaged)&_allocPgoInstrumentationBySchema; - callbacks[170] = (delegate* unmanaged)&_recordCallSite; - callbacks[171] = (delegate* unmanaged)&_recordRelocation; - callbacks[172] = (delegate* unmanaged)&_getRelocTypeHint; - callbacks[173] = (delegate* unmanaged)&_getExpectedTargetArchitecture; - callbacks[174] = (delegate* unmanaged)&_getJitFlags; + callbacks[66] = (delegate* unmanaged)&_getRuntimeTypePointer; + callbacks[67] = (delegate* unmanaged)&_getReadyToRunHelper; + callbacks[68] = (delegate* unmanaged)&_getReadyToRunDelegateCtorHelper; + callbacks[69] = (delegate* unmanaged)&_getHelperName; + callbacks[70] = (delegate* unmanaged)&_initClass; + callbacks[71] = (delegate* unmanaged)&_classMustBeLoadedBeforeCodeIsRun; + callbacks[72] = (delegate* unmanaged)&_getBuiltinClass; + callbacks[73] = (delegate* unmanaged)&_getTypeForPrimitiveValueClass; + callbacks[74] = (delegate* unmanaged)&_getTypeForPrimitiveNumericClass; + callbacks[75] = (delegate* unmanaged)&_canCast; + callbacks[76] = (delegate* unmanaged)&_areTypesEquivalent; + callbacks[77] = (delegate* unmanaged)&_compareTypesForCast; + callbacks[78] = (delegate* unmanaged)&_compareTypesForEquality; + callbacks[79] = (delegate* unmanaged)&_mergeClasses; + callbacks[80] = (delegate* unmanaged)&_isMoreSpecificType; + callbacks[81] = (delegate* unmanaged)&_getParentType; + callbacks[82] = (delegate* unmanaged)&_getChildType; + callbacks[83] = (delegate* unmanaged)&_satisfiesClassConstraints; + callbacks[84] = (delegate* unmanaged)&_isSDArray; + callbacks[85] = (delegate* unmanaged)&_getArrayRank; + callbacks[86] = (delegate* unmanaged)&_getArrayIntrinsicID; + callbacks[87] = (delegate* unmanaged)&_getArrayInitializationData; + callbacks[88] = (delegate* unmanaged)&_canAccessClass; + callbacks[89] = (delegate* unmanaged)&_getFieldName; + callbacks[90] = (delegate* unmanaged)&_getFieldClass; + callbacks[91] = (delegate* unmanaged)&_getFieldType; + callbacks[92] = (delegate* unmanaged)&_getFieldOffset; + callbacks[93] = (delegate* unmanaged)&_getFieldInfo; + callbacks[94] = (delegate* unmanaged)&_isFieldStatic; + callbacks[95] = (delegate* unmanaged)&_getBoundaries; + callbacks[96] = (delegate* unmanaged)&_setBoundaries; + callbacks[97] = (delegate* unmanaged)&_getVars; + callbacks[98] = (delegate* unmanaged)&_setVars; + callbacks[99] = (delegate* unmanaged)&_reportRichMappings; + callbacks[100] = (delegate* unmanaged)&_allocateArray; + callbacks[101] = (delegate* unmanaged)&_freeArray; + callbacks[102] = (delegate* unmanaged)&_getArgNext; + callbacks[103] = (delegate* unmanaged)&_getArgType; + callbacks[104] = (delegate* unmanaged)&_getExactClasses; + callbacks[105] = (delegate* unmanaged)&_getArgClass; + callbacks[106] = (delegate* unmanaged)&_getHFAType; + callbacks[107] = (delegate* unmanaged)&_GetErrorHRESULT; + callbacks[108] = (delegate* unmanaged)&_GetErrorMessage; + callbacks[109] = (delegate* unmanaged)&_FilterException; + callbacks[110] = (delegate* unmanaged)&_ThrowExceptionForJitResult; + callbacks[111] = (delegate* unmanaged)&_ThrowExceptionForHelper; + callbacks[112] = (delegate* unmanaged)&_runWithErrorTrap; + callbacks[113] = (delegate* unmanaged)&_runWithSPMIErrorTrap; + callbacks[114] = (delegate* unmanaged)&_getEEInfo; + callbacks[115] = (delegate* unmanaged)&_getJitTimeLogFilename; + callbacks[116] = (delegate* unmanaged)&_getMethodDefFromMethod; + callbacks[117] = (delegate* unmanaged)&_getMethodName; + callbacks[118] = (delegate* unmanaged)&_getMethodNameFromMetadata; + callbacks[119] = (delegate* unmanaged)&_getMethodHash; + callbacks[120] = (delegate* unmanaged)&_findNameOfToken; + callbacks[121] = (delegate* unmanaged)&_getSystemVAmd64PassStructInRegisterDescriptor; + callbacks[122] = (delegate* unmanaged)&_getLoongArch64PassStructInRegisterFlags; + callbacks[123] = (delegate* unmanaged)&_getThreadTLSIndex; + callbacks[124] = (delegate* unmanaged)&_getInlinedCallFrameVptr; + callbacks[125] = (delegate* unmanaged)&_getAddrOfCaptureThreadGlobal; + callbacks[126] = (delegate* unmanaged)&_getHelperFtn; + callbacks[127] = (delegate* unmanaged)&_getFunctionEntryPoint; + callbacks[128] = (delegate* unmanaged)&_getFunctionFixedEntryPoint; + callbacks[129] = (delegate* unmanaged)&_getMethodSync; + callbacks[130] = (delegate* unmanaged)&_getLazyStringLiteralHelper; + callbacks[131] = (delegate* unmanaged)&_embedModuleHandle; + callbacks[132] = (delegate* unmanaged)&_embedClassHandle; + callbacks[133] = (delegate* unmanaged)&_embedMethodHandle; + callbacks[134] = (delegate* unmanaged)&_embedFieldHandle; + callbacks[135] = (delegate* unmanaged)&_embedGenericHandle; + callbacks[136] = (delegate* unmanaged)&_getLocationOfThisType; + callbacks[137] = (delegate* unmanaged)&_getAddressOfPInvokeTarget; + callbacks[138] = (delegate* unmanaged)&_GetCookieForPInvokeCalliSig; + callbacks[139] = (delegate* unmanaged)&_canGetCookieForPInvokeCalliSig; + callbacks[140] = (delegate* unmanaged)&_getJustMyCodeHandle; + callbacks[141] = (delegate* unmanaged)&_GetProfilingHandle; + callbacks[142] = (delegate* unmanaged)&_getCallInfo; + callbacks[143] = (delegate* unmanaged)&_canAccessFamily; + callbacks[144] = (delegate* unmanaged)&_isRIDClassDomainID; + callbacks[145] = (delegate* unmanaged)&_getClassDomainID; + callbacks[146] = (delegate* unmanaged)&_getFieldAddress; + callbacks[147] = (delegate* unmanaged)&_getStaticFieldCurrentClass; + callbacks[148] = (delegate* unmanaged)&_getVarArgsHandle; + callbacks[149] = (delegate* unmanaged)&_canGetVarArgsHandle; + callbacks[150] = (delegate* unmanaged)&_constructStringLiteral; + callbacks[151] = (delegate* unmanaged)&_emptyStringLiteral; + callbacks[152] = (delegate* unmanaged)&_getFieldThreadLocalStoreID; + callbacks[153] = (delegate* unmanaged)&_addActiveDependency; + callbacks[154] = (delegate* unmanaged)&_GetDelegateCtor; + callbacks[155] = (delegate* unmanaged)&_MethodCompileComplete; + callbacks[156] = (delegate* unmanaged)&_getTailCallHelpers; + callbacks[157] = (delegate* unmanaged)&_convertPInvokeCalliToCall; + callbacks[158] = (delegate* unmanaged)&_notifyInstructionSetUsage; + callbacks[159] = (delegate* unmanaged)&_updateEntryPointForTailCall; + callbacks[160] = (delegate* unmanaged)&_allocMem; + callbacks[161] = (delegate* unmanaged)&_reserveUnwindInfo; + callbacks[162] = (delegate* unmanaged)&_allocUnwindInfo; + callbacks[163] = (delegate* unmanaged)&_allocGCInfo; + callbacks[164] = (delegate* unmanaged)&_setEHcount; + callbacks[165] = (delegate* unmanaged)&_setEHinfo; + callbacks[166] = (delegate* unmanaged)&_logMsg; + callbacks[167] = (delegate* unmanaged)&_doAssert; + callbacks[168] = (delegate* unmanaged)&_reportFatalError; + callbacks[169] = (delegate* unmanaged)&_getPgoInstrumentationResults; + callbacks[170] = (delegate* unmanaged)&_allocPgoInstrumentationBySchema; + callbacks[171] = (delegate* unmanaged)&_recordCallSite; + callbacks[172] = (delegate* unmanaged)&_recordRelocation; + callbacks[173] = (delegate* unmanaged)&_getRelocTypeHint; + callbacks[174] = (delegate* unmanaged)&_getExpectedTargetArchitecture; + callbacks[175] = (delegate* unmanaged)&_getJitFlags; return (IntPtr)callbacks; } diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 14846a61a087b7..439d82aa67c7e0 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -2304,6 +2304,13 @@ private CorInfoHelpFunc getUnBoxHelper(CORINFO_CLASS_STRUCT_* cls) return type.IsNullable ? CorInfoHelpFunc.CORINFO_HELP_UNBOX_NULLABLE : CorInfoHelpFunc.CORINFO_HELP_UNBOX; } +#pragma warning disable CA1822 // Mark members as static + private void* getRuntimeTypePointer(CORINFO_CLASS_STRUCT_* cls) +#pragma warning restore CA1822 // Mark members as static + { + return (void*)IntPtr.Zero; + } + private byte* getHelperName(CorInfoHelpFunc helpFunc) { return (byte*)GetPin(StringToUTF8(helpFunc.ToString())); diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt index b69ab664bd4834..b09991de6b6f94 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -221,6 +221,7 @@ FUNCTIONS CORINFO_CLASS_HANDLE getTypeForBox(CORINFO_CLASS_HANDLE cls) CorInfoHelpFunc getBoxHelper(CORINFO_CLASS_HANDLE cls) CorInfoHelpFunc getUnBoxHelper(CORINFO_CLASS_HANDLE cls) + void* getRuntimeTypePointer(CORINFO_CLASS_HANDLE cls) bool getReadyToRunHelper(CORINFO_RESOLVED_TOKEN * pResolvedToken, CORINFO_LOOKUP_KIND * pGenericLookupKind, CorInfoHelpFunc id, CORINFO_CONST_LOOKUP *pLookup) void getReadyToRunDelegateCtorHelper(CORINFO_RESOLVED_TOKEN * pTargetMethod, mdToken targetConstraint, CORINFO_CLASS_HANDLE delegateType, CORINFO_LOOKUP *pLookup) const char* getHelperName(CorInfoHelpFunc helpFunc) diff --git a/src/coreclr/tools/aot/jitinterface/jitinterface.h b/src/coreclr/tools/aot/jitinterface/jitinterface.h index 96cb5bbb409677..d83968fa3c7d8d 100644 --- a/src/coreclr/tools/aot/jitinterface/jitinterface.h +++ b/src/coreclr/tools/aot/jitinterface/jitinterface.h @@ -77,6 +77,7 @@ struct JitInterfaceCallbacks CORINFO_CLASS_HANDLE (* getTypeForBox)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls); CorInfoHelpFunc (* getBoxHelper)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls); CorInfoHelpFunc (* getUnBoxHelper)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls); + void* (* getRuntimeTypePointer)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls); bool (* getReadyToRunHelper)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_LOOKUP_KIND* pGenericLookupKind, CorInfoHelpFunc id, CORINFO_CONST_LOOKUP* pLookup); void (* getReadyToRunDelegateCtorHelper)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_RESOLVED_TOKEN* pTargetMethod, unsigned int targetConstraint, CORINFO_CLASS_HANDLE delegateType, CORINFO_LOOKUP* pLookup); const char* (* getHelperName)(void * thisHandle, CorInfoExceptionClass** ppException, CorInfoHelpFunc helpFunc); @@ -841,6 +842,15 @@ class JitInterfaceWrapper : public ICorJitInfo return temp; } + virtual void* getRuntimeTypePointer( + CORINFO_CLASS_HANDLE cls) +{ + CorInfoExceptionClass* pException = nullptr; + void* temp = _callbacks->getRuntimeTypePointer(_thisHandle, &pException, cls); + if (pException != nullptr) throw pException; + return temp; +} + virtual bool getReadyToRunHelper( CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_LOOKUP_KIND* pGenericLookupKind, diff --git a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h index ce147abc89be60..36744c42e7e514 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h @@ -138,6 +138,7 @@ LWM(GetTypeForPrimitiveValueClass, DWORDLONG, DWORD) LWM(GetTypeForPrimitiveNumericClass, DWORDLONG, DWORD) LWM(GetUnboxedEntry, DWORDLONG, DLD); LWM(GetUnBoxHelper, DWORDLONG, DWORD) +LWM(GetRuntimeTypePointer, DWORDLONG, DWORDLONG) LWM(GetVarArgsHandle, GetVarArgsHandleValue, DLDL) LWM(GetVars, DWORDLONG, Agnostic_GetVars) LWM(InitClass, Agnostic_InitClass, DWORD) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index 7bac6fdb36575d..1a58accad32cac 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -2186,6 +2186,29 @@ CorInfoHelpFunc MethodContext::repGetUnBoxHelper(CORINFO_CLASS_HANDLE cls) return result; } +void MethodContext::recGetRuntimeTypePointer(CORINFO_CLASS_HANDLE cls, void* result) +{ + if (GetRuntimeTypePointer == nullptr) + GetRuntimeTypePointer = new LightWeightMap(); + + DWORDLONG key = CastHandle(cls); + DWORDLONG value = (DWORDLONG)result; + GetRuntimeTypePointer->Add(key, value); + DEBUG_REC(dmpGetRuntimeTypePointer(key, value)); +} +void MethodContext::dmpGetRuntimeTypePointer(DWORDLONG key, DWORDLONG value) +{ + printf("GetRuntimeTypePointer key cls-%016llX, value res-%016llX", key, value); +} +void* MethodContext::repGetRuntimeTypePointer(CORINFO_CLASS_HANDLE cls) +{ + DWORDLONG key = CastHandle(cls); + AssertMapAndKeyExist(GetRuntimeTypePointer, key, ": key %016llX", key); + DWORDLONG value = GetRuntimeTypePointer->Get(key); + DEBUG_REP(dmpGetRuntimeTypePointer(key, value)); + return (void*)value; +} + void MethodContext::recGetReadyToRunHelper(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_LOOKUP_KIND* pGenericLookupKind, CorInfoHelpFunc id, diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h index f9769119e20b5d..178512f3902da0 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h @@ -310,6 +310,10 @@ class MethodContext void dmpGetUnBoxHelper(DWORDLONG key, DWORD value); CorInfoHelpFunc repGetUnBoxHelper(CORINFO_CLASS_HANDLE cls); + void recGetRuntimeTypePointer(CORINFO_CLASS_HANDLE cls, void* result); + void dmpGetRuntimeTypePointer(DWORDLONG key, DWORDLONG value); + void* repGetRuntimeTypePointer(CORINFO_CLASS_HANDLE cls); + void recGetReadyToRunHelper(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_LOOKUP_KIND* pGenericLookupKind, CorInfoHelpFunc id, @@ -1129,6 +1133,7 @@ enum mcPackets Packet_UpdateEntryPointForTailCall = 193, Packet_GetLoongArch64PassStructInRegisterFlags = 194, Packet_GetExactClasses = 195, + Packet_GetRuntimeTypePointer = 196, }; void SetDebugDumpVariables(); diff --git a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp index ceb3f0b9e38ba8..4f9fdc855ecb3f 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -779,6 +779,14 @@ CorInfoHelpFunc interceptor_ICJI::getUnBoxHelper(CORINFO_CLASS_HANDLE cls) return temp; } +void* interceptor_ICJI::getRuntimeTypePointer(CORINFO_CLASS_HANDLE cls) +{ + mc->cr->AddCall("getRuntimeTypePointer"); + void* temp = original_ICorJitInfo->getRuntimeTypePointer(cls); + mc->recGetRuntimeTypePointer(cls, temp); + return temp; +} + bool interceptor_ICJI::getReadyToRunHelper(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_LOOKUP_KIND* pGenericLookupKind, CorInfoHelpFunc id, diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp index 4f8ed3ab023d68..6df44aa06851fd 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp @@ -535,6 +535,13 @@ CorInfoHelpFunc interceptor_ICJI::getUnBoxHelper( return original_ICorJitInfo->getUnBoxHelper(cls); } +void* interceptor_ICJI::getRuntimeTypePointer( + CORINFO_CLASS_HANDLE cls) +{ + mcs->AddCall("getRuntimeTypePointer"); + return original_ICorJitInfo->getRuntimeTypePointer(cls); +} + bool interceptor_ICJI::getReadyToRunHelper( CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_LOOKUP_KIND* pGenericLookupKind, diff --git a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp index 7da0d2ebb4a45b..7785eb7d1685cc 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp @@ -469,6 +469,12 @@ CorInfoHelpFunc interceptor_ICJI::getUnBoxHelper( return original_ICorJitInfo->getUnBoxHelper(cls); } +void* interceptor_ICJI::getRuntimeTypePointer( + CORINFO_CLASS_HANDLE cls) +{ + return original_ICorJitInfo->getRuntimeTypePointer(cls); +} + bool interceptor_ICJI::getReadyToRunHelper( CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_LOOKUP_KIND* pGenericLookupKind, diff --git a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp index 218123a05d8917..c2c0999cdd92f6 100644 --- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp @@ -663,6 +663,13 @@ CorInfoHelpFunc MyICJI::getUnBoxHelper(CORINFO_CLASS_HANDLE cls) return result; } +void* MyICJI::getRuntimeTypePointer(CORINFO_CLASS_HANDLE cls) +{ + jitInstance->mc->cr->AddCall("getRuntimeTypePointer"); + void* result = jitInstance->mc->repGetRuntimeTypePointer(cls); + return result; +} + bool MyICJI::getReadyToRunHelper(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_LOOKUP_KIND* pGenericLookupKind, CorInfoHelpFunc id, diff --git a/src/coreclr/vm/frozenobjectheap.cpp b/src/coreclr/vm/frozenobjectheap.cpp index cedade43fa1251..8b78984515f404 100644 --- a/src/coreclr/vm/frozenobjectheap.cpp +++ b/src/coreclr/vm/frozenobjectheap.cpp @@ -85,6 +85,15 @@ Object* FrozenObjectHeapManager::TryAllocateObject(PTR_MethodTable type, size_t #endif // !FEATURE_BASICFREEZE } +// Does object belong to a frozen segment? +bool FrozenObjectHeapManager::IsFromFrozenSegment(Object* object) +{ +#ifdef FEATURE_BASICFREEZE + return GCHeapUtilities::GetGCHeap()->IsInFrozenSegment(object); +#else + return false; +#endif +} FrozenObjectSegment::FrozenObjectSegment(): m_pStart(nullptr), diff --git a/src/coreclr/vm/frozenobjectheap.h b/src/coreclr/vm/frozenobjectheap.h index 703c3aaa6fc458..068b81431b7192 100644 --- a/src/coreclr/vm/frozenobjectheap.h +++ b/src/coreclr/vm/frozenobjectheap.h @@ -28,6 +28,7 @@ class FrozenObjectHeapManager public: FrozenObjectHeapManager(); Object* TryAllocateObject(PTR_MethodTable type, size_t objectSize); + bool IsFromFrozenSegment(Object* object); private: Crst m_Crst; diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index bc146b76ef9119..0527f4f24b247e 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -5945,6 +5945,38 @@ CorInfoHelpFunc CEEInfo::getUnBoxHelper(CORINFO_CLASS_HANDLE clsHnd) return CORINFO_HELP_UNBOX; } +/***********************************************************************/ +void* CEEInfo::getRuntimeTypePointer(CORINFO_CLASS_HANDLE clsHnd) +{ + LIMITED_METHOD_CONTRACT; + + void* pointer = nullptr; + + JIT_TO_EE_TRANSITION(); + + GCX_COOP(); + + TypeHandle typeHnd(clsHnd); + if (!typeHnd.IsNull() && !typeHnd.IsTypeDesc() && typeHnd.IsFullyLoaded()) + { + MethodTable* pMT = typeHnd.AsMethodTable(); + if (!typeHnd.IsCanonicalSubtype()) + { + // We probably don't want to allocate a RuntimeHelper as part of this query + // hence, use IfExists + bool isPinned; + Object* obj = OBJECTREFToObject(pMT->GetManagedClassObjectIfExists(&isPinned)); + if (obj != nullptr && isPinned) + { + pointer = (void*)obj; + } + } + } + EE_TO_JIT_TRANSITION(); + + return pointer; +} + /***********************************************************************/ bool CEEInfo::getReadyToRunHelper( CORINFO_RESOLVED_TOKEN * pResolvedToken, diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index e61162ac553c89..dce3b162aed1a2 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -4222,9 +4222,20 @@ OBJECTREF MethodTable::GetManagedClassObject() REFLECTCLASSBASEREF refClass = NULL; GCPROTECT_BEGIN(refClass); - refClass = (REFLECTCLASSBASEREF) AllocateObject(g_pRuntimeTypeClass); - LoaderAllocator *pLoaderAllocator = GetLoaderAllocator(); + LoaderAllocator* pLoaderAllocator = GetLoaderAllocator(); + if (!pLoaderAllocator->CanUnload()) + { + // Allocate RuntimeType on a frozen segment + FrozenObjectHeapManager* foh = SystemDomain::GetFrozenObjectHeapManager(); + size_t objSize = g_pRuntimeTypeClass->GetBaseSize(); + refClass = ObjectToOBJECTREF(foh->TryAllocateObject(g_pRuntimeTypeClass, objSize)); + } + + if (refClass == NULL) + { + refClass = (REFLECTCLASSBASEREF)AllocateObject(g_pRuntimeTypeClass); + } ((ReflectClassBaseObject*)OBJECTREFToObject(refClass))->SetType(TypeHandle(this)); ((ReflectClassBaseObject*)OBJECTREFToObject(refClass))->SetKeepAlive(pLoaderAllocator->GetExposedObject()); diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index 07792d5fbf36d9..5717d6c954ce36 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -2716,7 +2716,7 @@ class MethodTable // method will get the class object. If it doesn't exist it will be created. // GetManagedClassObjectIfExists() will return null if the Type object doesn't exist. OBJECTREF GetManagedClassObject(); - OBJECTREF GetManagedClassObjectIfExists(); + OBJECTREF GetManagedClassObjectIfExists(bool* pIsPinned = nullptr); // ------------------------------------------------------------------ diff --git a/src/coreclr/vm/methodtable.inl b/src/coreclr/vm/methodtable.inl index 8f8f8178e26023..62176764fd0ff5 100644 --- a/src/coreclr/vm/methodtable.inl +++ b/src/coreclr/vm/methodtable.inl @@ -16,6 +16,7 @@ #include "methodtable.h" #include "genericdict.h" #include "threadstatics.h" +#include "frozenobjectheap.h" //========================================================================================== FORCEINLINE PTR_EEClass MethodTable::GetClass_NoLogging() @@ -1335,7 +1336,7 @@ inline OBJECTHANDLE MethodTable::GetLoaderAllocatorObjectHandle() } //========================================================================================== -FORCEINLINE OBJECTREF MethodTable::GetManagedClassObjectIfExists() +FORCEINLINE OBJECTREF MethodTable::GetManagedClassObjectIfExists(bool* pIsPinned) { LIMITED_METHOD_CONTRACT; @@ -1353,6 +1354,15 @@ FORCEINLINE OBJECTREF MethodTable::GetManagedClassObjectIfExists() } COMPILER_ASSUME(retVal != NULL); + +#ifndef DACCESS_COMPILE + if (pIsPinned != nullptr) + { + FrozenObjectHeapManager* foh = SystemDomain::GetFrozenObjectHeapManager(); + *pIsPinned = foh->IsFromFrozenSegment(OBJECTREFToObject(retVal)); + } +#endif + return retVal; } From 232033bb86c568df6df0c39a6ea00b0747c321d5 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Wed, 14 Sep 2022 01:01:52 +0200 Subject: [PATCH 02/39] Mitigate perf regressions --- src/coreclr/jit/assertionprop.cpp | 2 +- src/coreclr/jit/compiler.cpp | 5 +++++ src/coreclr/jit/compiler.h | 10 +++++----- src/coreclr/jit/emit.cpp | 4 ++++ src/coreclr/jit/gentree.cpp | 13 +++++++++---- src/coreclr/jit/gentree.h | 1 + src/coreclr/jit/importer.cpp | 23 ++++------------------- src/coreclr/jit/morph.cpp | 20 ++++++++++++++++++++ src/coreclr/jit/optcse.cpp | 2 +- src/coreclr/jit/valuenum.cpp | 4 +++- src/coreclr/vm/jitinterface.cpp | 6 ++---- src/coreclr/vm/methodtable.cpp | 27 ++++++++++++++++++++++++++- src/coreclr/vm/methodtable.h | 3 ++- src/coreclr/vm/methodtable.inl | 10 +--------- 14 files changed, 84 insertions(+), 46 deletions(-) diff --git a/src/coreclr/jit/assertionprop.cpp b/src/coreclr/jit/assertionprop.cpp index b140c8caf8aa8c..8db5d573623eea 100644 --- a/src/coreclr/jit/assertionprop.cpp +++ b/src/coreclr/jit/assertionprop.cpp @@ -2149,7 +2149,7 @@ void Compiler::optDebugCheckAssertion(AssertionDsc* assertion) break; case O1K_LCLVAR: assert((lvaGetDesc(assertion->op1.lcl.lclNum)->lvType != TYP_REF) || - (assertion->op2.u1.iconVal == 0) || doesMethodHaveFrozenString()); + (assertion->op2.u1.iconVal == 0) || doesMethodHaveFrozenObjects()); break; case O1K_VALUE_NUMBER: assert((vnStore->TypeOfVN(assertion->op1.vn) != TYP_REF) || (assertion->op2.u1.iconVal == 0)); diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index 573708a6c7bef1..c7506c92483534 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -9426,6 +9426,11 @@ void cTreeFlags(Compiler* comp, GenTree* tree) chars += printf("[ICON_STR_HDL]"); break; + case GTF_ICON_TYPE_HDL: + + chars += printf("[ICON_TYPE_HDL]"); + break; + case GTF_ICON_CONST_PTR: chars += printf("[ICON_CONST_PTR]"); diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index f98fe75b61bd25..4811d81ece9f9f 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -6808,7 +6808,7 @@ class Compiler #define OMF_HAS_EXPRUNTIMELOOKUP 0x00000080 // Method contains a runtime lookup to an expandable dictionary. #define OMF_HAS_PATCHPOINT 0x00000100 // Method contains patchpoints #define OMF_NEEDS_GCPOLLS 0x00000200 // Method needs GC polls -#define OMF_HAS_FROZEN_STRING 0x00000400 // Method has a frozen string (REF constant int), currently only on NativeAOT. +#define OMF_HAS_FROZEN_OBJECTS 0x00000400 // Method has a frozen string (REF constant int), currently only on NativeAOT. #define OMF_HAS_PARTIAL_COMPILATION_PATCHPOINT 0x00000800 // Method contains partial compilation patchpoints #define OMF_HAS_TAILCALL_SUCCESSOR 0x00001000 // Method has potential tail call in a non BBJ_RETURN block #define OMF_HAS_MDNEWARRAY 0x00002000 // Method contains 'new' of an MD array @@ -6833,14 +6833,14 @@ class Compiler void addFatPointerCandidate(GenTreeCall* call); - bool doesMethodHaveFrozenString() const + bool doesMethodHaveFrozenObjects() const { - return (optMethodFlags & OMF_HAS_FROZEN_STRING) != 0; + return (optMethodFlags & OMF_HAS_FROZEN_OBJECTS) != 0; } - void setMethodHasFrozenString() + void setMethodHasFrozenObjects() { - optMethodFlags |= OMF_HAS_FROZEN_STRING; + optMethodFlags |= OMF_HAS_FROZEN_OBJECTS; } bool doesMethodHaveGuardedDevirtualization() const diff --git a/src/coreclr/jit/emit.cpp b/src/coreclr/jit/emit.cpp index b9130fa443efda..58157b28483834 100644 --- a/src/coreclr/jit/emit.cpp +++ b/src/coreclr/jit/emit.cpp @@ -4167,6 +4167,10 @@ void emitter::emitDispCommentForHandle(size_t handle, size_t cookie, GenTreeFlag str = "string handle"; #endif } + else if (flag == GTF_ICON_TYPE_HDL) + { + str = "Type handle"; + } else if (flag == GTF_ICON_CLASS_HDL) { str = emitComp->eeGetClassName(reinterpret_cast(handle)); diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 9913e6f2ce4d7e..57a30e529d6d26 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -6911,9 +6911,9 @@ GenTree* Compiler::gtNewIndOfIconHandleNode(var_types indType, size_t addr, GenT // This indirection also is invariant. indNode->gtFlags |= GTF_IND_INVARIANT; - if (iconFlags == GTF_ICON_STR_HDL) + if ((iconFlags == GTF_ICON_STR_HDL) || (iconFlags == GTF_ICON_TYPE_HDL)) { - // String literals are never null + // String literals and frozen type objects are never null indNode->gtFlags |= GTF_IND_NONNULL; } } @@ -6990,7 +6990,7 @@ GenTree* Compiler::gtNewStringLiteralNode(InfoAccessType iat, void* pValue) switch (iat) { case IAT_VALUE: - setMethodHasFrozenString(); + setMethodHasFrozenObjects(); tree = gtNewIconEmbHndNode(pValue, nullptr, GTF_ICON_STR_HDL, nullptr); tree->gtType = TYP_REF; #ifdef DEBUG @@ -11114,6 +11114,10 @@ void Compiler::gtDispConst(GenTree* tree) printf(" 0x%X [ICON_STR_HDL]", dspPtr(tree->AsIntCon()->gtIconVal)); } } + else if (tree->IsIconHandle(GTF_ICON_TYPE_HDL)) + { + printf(" 0x%X [ICON_TYPE_HDL]", dspPtr(tree->AsIntCon()->gtIconVal)); + } else { ssize_t dspIconVal = @@ -11172,8 +11176,9 @@ void Compiler::gtDispConst(GenTree* tree) case GTF_ICON_STATIC_HDL: printf(" static"); break; + case GTF_ICON_TYPE_HDL: case GTF_ICON_STR_HDL: - unreached(); // This case is handled above + unreached(); // These cases are handled above break; case GTF_ICON_CONST_PTR: printf(" const ptr"); diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index 205644138c2168..00bd3a536b1886 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -555,6 +555,7 @@ enum GenTreeFlags : unsigned int GTF_ICON_FIELD_HDL = 0x04000000, // GT_CNS_INT -- constant is a field handle GTF_ICON_STATIC_HDL = 0x05000000, // GT_CNS_INT -- constant is a handle to static data GTF_ICON_STR_HDL = 0x06000000, // GT_CNS_INT -- constant is a string handle + GTF_ICON_TYPE_HDL = 0x12000000, // GT_CNS_INT -- constant is a Type handle GTF_ICON_CONST_PTR = 0x07000000, // GT_CNS_INT -- constant is a pointer to immutable data, (e.g. IAT_PPVALUE) GTF_ICON_GLOBAL_PTR = 0x08000000, // GT_CNS_INT -- constant is a pointer to mutable data (e.g. from the VM state) GTF_ICON_VARG_HDL = 0x09000000, // GT_CNS_INT -- constant is a var arg cookie handle diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 4395618dcae487..88ee85b65a89be 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -4046,22 +4046,7 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis, op1 = impPopStack().val; // Replace helper with a more specialized helper that returns RuntimeType if (typeHandleHelper == CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE) - { - CORINFO_CLASS_HANDLE hClass = - gtGetHelperArgClassHandle(op1->AsCall()->gtArgs.GetArgByIndex(0)->GetEarlyNode()); - if (!opts.IsReadyToRun() && (hClass != NO_CLASS_HANDLE)) - { - void* ptr = info.compCompHnd->getRuntimeTypePointer(hClass); - if (ptr != nullptr) - { - // Temp Hack: pretend we're a string literal :-) - setMethodHasFrozenString(); - retNode = gtNewIconEmbHndNode(ptr, nullptr, GTF_ICON_STR_HDL, nullptr); - retNode->gtType = TYP_REF; - INDEBUG(retNode->AsIntCon()->gtTargetHandle = (size_t)ptr); - break; - } - } + { typeHandleHelper = CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE; } else @@ -22959,9 +22944,9 @@ bool Compiler::impCanSkipCovariantStoreCheck(GenTree* value, GenTree* array) return true; } // Non-0 const refs can only occur with frozen objects - assert(value->IsIconHandle(GTF_ICON_STR_HDL)); - assert(doesMethodHaveFrozenString() || - (compIsForInlining() && impInlineInfo->InlinerCompiler->doesMethodHaveFrozenString())); + assert(value->IsIconHandle(GTF_ICON_STR_HDL) || value->IsIconHandle(GTF_ICON_TYPE_HDL)); + assert(doesMethodHaveFrozenObjects() || + (compIsForInlining() && impInlineInfo->InlinerCompiler->doesMethodHaveFrozenObjects())); } // Try and get a class handle for the array diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 3b72edc3f912e9..8aafcc6123a7e6 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -8312,6 +8312,26 @@ GenTree* Compiler::fgMorphCall(GenTreeCall* call) call = fgMorphArgs(call); noway_assert(call->gtOper == GT_CALL); + // Try to replace CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE with a constant gc handle + // pointing to a frozen segment + if (!gtIsActiveCSE_Candidate(call) && gtIsTypeHandleToRuntimeTypeHelper(call)) + { + GenTree* argNode = call->AsCall()->gtArgs.GetArgByIndex(0)->GetNode(); + CORINFO_CLASS_HANDLE hClass = gtGetHelperArgClassHandle(argNode); + if (!opts.IsReadyToRun() && (hClass != NO_CLASS_HANDLE) && !gtIsActiveCSE_Candidate(argNode)) + { + void* ptr = info.compCompHnd->getRuntimeTypePointer(hClass); + if (ptr != nullptr) + { + setMethodHasFrozenObjects(); + GenTree* retNode = gtNewIconEmbHndNode(ptr, nullptr, GTF_ICON_TYPE_HDL, nullptr); + retNode->gtType = TYP_REF; + INDEBUG(retNode->AsIntCon()->gtTargetHandle = (size_t)ptr); + return fgMorphTree(retNode); + } + } + } + // Assign DEF flags if it produces a definition from "return buffer". fgAssignSetVarDef(call); if (call->OperRequiresAsgFlag()) diff --git a/src/coreclr/jit/optcse.cpp b/src/coreclr/jit/optcse.cpp index 76912c0e174ac4..f7ac2c91329660 100644 --- a/src/coreclr/jit/optcse.cpp +++ b/src/coreclr/jit/optcse.cpp @@ -811,7 +811,7 @@ bool Compiler::optValnumCSE_Locate() if (!enableConstCSE && // Unconditionally allow these constant handles to be CSE'd !tree->IsIconHandle(GTF_ICON_STATIC_HDL) && !tree->IsIconHandle(GTF_ICON_CLASS_HDL) && - !tree->IsIconHandle(GTF_ICON_STR_HDL)) + !tree->IsIconHandle(GTF_ICON_STR_HDL) && !tree->IsIconHandle(GTF_ICON_TYPE_HDL)) { continue; } diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index 9b6238101fab22..a6d0a4eb84d6ae 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -5254,6 +5254,7 @@ GenTreeFlags ValueNumStore::GetFoldedArithOpResultHandleFlags(ValueNum vn) case GTF_ICON_FIELD_HDL: case GTF_ICON_TOKEN_HDL: case GTF_ICON_STR_HDL: + case GTF_ICON_TYPE_HDL: case GTF_ICON_CONST_PTR: case GTF_ICON_VARG_HDL: case GTF_ICON_PINVKI_HDL: @@ -8162,7 +8163,8 @@ void Compiler::fgValueNumberTreeConst(GenTree* tree) } else { - assert(tree->IsIconHandle(GTF_ICON_STR_HDL)); // Constant object can be only frozen string. + // Constant object can be only frozen string and frozen Type. + assert(tree->IsIconHandle(GTF_ICON_STR_HDL) || tree->IsIconHandle(GTF_ICON_TYPE_HDL)); tree->gtVNPair.SetBoth( vnStore->VNForHandle(ssize_t(tree->AsIntConCommon()->IconValue()), tree->GetIconHandleFlag())); } diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 0527f4f24b247e..6d8b82a7aff0db 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -5962,11 +5962,9 @@ void* CEEInfo::getRuntimeTypePointer(CORINFO_CLASS_HANDLE clsHnd) MethodTable* pMT = typeHnd.AsMethodTable(); if (!typeHnd.IsCanonicalSubtype()) { - // We probably don't want to allocate a RuntimeHelper as part of this query - // hence, use IfExists bool isPinned; - Object* obj = OBJECTREFToObject(pMT->GetManagedClassObjectIfExists(&isPinned)); - if (obj != nullptr && isPinned) + Object* obj = OBJECTREFToObject(pMT->GetManagedClassObject(&isPinned)); + if (isPinned) { pointer = (void*)obj; } diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index dce3b162aed1a2..59921bb939817e 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -4229,7 +4229,7 @@ OBJECTREF MethodTable::GetManagedClassObject() // Allocate RuntimeType on a frozen segment FrozenObjectHeapManager* foh = SystemDomain::GetFrozenObjectHeapManager(); size_t objSize = g_pRuntimeTypeClass->GetBaseSize(); - refClass = ObjectToOBJECTREF(foh->TryAllocateObject(g_pRuntimeTypeClass, objSize)); + refClass = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(foh->TryAllocateObject(g_pRuntimeTypeClass, objSize)); } if (refClass == NULL) @@ -4254,6 +4254,31 @@ OBJECTREF MethodTable::GetManagedClassObject() RETURN(GetManagedClassObjectIfExists()); } +OBJECTREF MethodTable::GetManagedClassObject(bool* pIsPinned) +{ + CONTRACT(OBJECTREF) { + THROWS; + GC_TRIGGERS; + MODE_COOPERATIVE; + INJECT_FAULT(COMPlusThrowOM()); + POSTCONDITION(GetWriteableData()->m_hExposedClassObject != 0); + } + CONTRACT_END; + + _ASSERT(pIsPinned != nullptr); + + OBJECTREF objRef = NULL; + GCPROTECT_BEGIN(objRef); + + objRef = GetManagedClassObject(); + FrozenObjectHeapManager* foh = SystemDomain::GetFrozenObjectHeapManager(); + *pIsPinned = foh->IsFromFrozenSegment(OBJECTREFToObject(objRef)); + + GCPROTECT_END(); + + return objRef; +} + #endif //!DACCESS_COMPILE //========================================================================================== diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index 5717d6c954ce36..8cd499873fba6b 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -2716,7 +2716,8 @@ class MethodTable // method will get the class object. If it doesn't exist it will be created. // GetManagedClassObjectIfExists() will return null if the Type object doesn't exist. OBJECTREF GetManagedClassObject(); - OBJECTREF GetManagedClassObjectIfExists(bool* pIsPinned = nullptr); + OBJECTREF GetManagedClassObject(bool* pIsPinned); + OBJECTREF GetManagedClassObjectIfExists(); // ------------------------------------------------------------------ diff --git a/src/coreclr/vm/methodtable.inl b/src/coreclr/vm/methodtable.inl index 62176764fd0ff5..242f4a4d65f858 100644 --- a/src/coreclr/vm/methodtable.inl +++ b/src/coreclr/vm/methodtable.inl @@ -1336,7 +1336,7 @@ inline OBJECTHANDLE MethodTable::GetLoaderAllocatorObjectHandle() } //========================================================================================== -FORCEINLINE OBJECTREF MethodTable::GetManagedClassObjectIfExists(bool* pIsPinned) +FORCEINLINE OBJECTREF MethodTable::GetManagedClassObjectIfExists() { LIMITED_METHOD_CONTRACT; @@ -1355,14 +1355,6 @@ FORCEINLINE OBJECTREF MethodTable::GetManagedClassObjectIfExists(bool* pIsPinned COMPILER_ASSUME(retVal != NULL); -#ifndef DACCESS_COMPILE - if (pIsPinned != nullptr) - { - FrozenObjectHeapManager* foh = SystemDomain::GetFrozenObjectHeapManager(); - *pIsPinned = foh->IsFromFrozenSegment(OBJECTREFToObject(retVal)); - } -#endif - return retVal; } From f63c941d42840ae351d85eb4027036ff1b486983 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Wed, 14 Sep 2022 01:22:45 +0200 Subject: [PATCH 03/39] clean up --- src/coreclr/vm/methodtable.cpp | 1 + src/coreclr/vm/methodtable.inl | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index 59921bb939817e..a71590b2b43759 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -58,6 +58,7 @@ #include "array.h" #include "castcache.h" #include "dynamicinterfacecastable.h" +#include "frozenobjectheap.h" #ifdef FEATURE_INTERPRETER #include "interpreter.h" diff --git a/src/coreclr/vm/methodtable.inl b/src/coreclr/vm/methodtable.inl index 242f4a4d65f858..8f8f8178e26023 100644 --- a/src/coreclr/vm/methodtable.inl +++ b/src/coreclr/vm/methodtable.inl @@ -16,7 +16,6 @@ #include "methodtable.h" #include "genericdict.h" #include "threadstatics.h" -#include "frozenobjectheap.h" //========================================================================================== FORCEINLINE PTR_EEClass MethodTable::GetClass_NoLogging() @@ -1354,7 +1353,6 @@ FORCEINLINE OBJECTREF MethodTable::GetManagedClassObjectIfExists() } COMPILER_ASSUME(retVal != NULL); - return retVal; } From 841e9c723435515406001070cf04548aa02ebbee Mon Sep 17 00:00:00 2001 From: EgorBo Date: Wed, 14 Sep 2022 02:11:59 +0200 Subject: [PATCH 04/39] fix build issue? --- src/coreclr/vm/methodtable.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index a71590b2b43759..a508151231ae59 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -4257,12 +4257,12 @@ OBJECTREF MethodTable::GetManagedClassObject() OBJECTREF MethodTable::GetManagedClassObject(bool* pIsPinned) { - CONTRACT(OBJECTREF) { + CONTRACT(OBJECTREF) + { THROWS; GC_TRIGGERS; MODE_COOPERATIVE; INJECT_FAULT(COMPlusThrowOM()); - POSTCONDITION(GetWriteableData()->m_hExposedClassObject != 0); } CONTRACT_END; @@ -4277,7 +4277,7 @@ OBJECTREF MethodTable::GetManagedClassObject(bool* pIsPinned) GCPROTECT_END(); - return objRef; + RETURN(objRef); } #endif //!DACCESS_COMPILE From f168d13fced92dc5b4b564a01c1971059ab05dc3 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Wed, 14 Sep 2022 02:42:50 +0200 Subject: [PATCH 05/39] Fix eeGetCPString for string literals in JitDisasm --- src/coreclr/jit/ee_il_dll.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/ee_il_dll.cpp b/src/coreclr/jit/ee_il_dll.cpp index ccbf6d69b4b8b3..fedbae80a624c4 100644 --- a/src/coreclr/jit/ee_il_dll.cpp +++ b/src/coreclr/jit/ee_il_dll.cpp @@ -1628,7 +1628,19 @@ const WCHAR* Compiler::eeGetCPString(size_t strHandle) return (nullptr); } - CORINFO_String* asString = *((CORINFO_String**)strHandle); + CORINFO_String* asString = nullptr; + if (impGetStringClass() == *((CORINFO_CLASS_HANDLE*)strHandle)) + { + // strHandle is a frozen string + // We assume strHandle is never an "interior" pointer in a frozen string + // (jit is not expected to perform such foldings) + asString = (CORINFO_String*)strHandle; + } + else + { + // strHandle is a pinned handle to a string object + asString = *((CORINFO_String**)strHandle); + } if (ReadProcessMemory(GetCurrentProcess(), asString, buff, sizeof(buff), nullptr) == 0) { From 3e6d3bae231c4b767a65d69b334c6da44832f251 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Wed, 14 Sep 2022 14:02:28 +0200 Subject: [PATCH 06/39] clean up --- src/coreclr/inc/corinfo.h | 7 ++++ src/coreclr/jit/compiler.cpp | 4 +-- src/coreclr/jit/compiler.h | 3 +- src/coreclr/jit/ee_il_dll.cpp | 62 +++++++++++++++++------------------ src/coreclr/jit/emit.cpp | 43 ++++-------------------- src/coreclr/jit/emitxarch.cpp | 12 ------- src/coreclr/jit/gentree.cpp | 23 ++++--------- src/coreclr/jit/gentree.h | 4 +-- src/coreclr/jit/importer.cpp | 9 ++++- src/coreclr/jit/morph.cpp | 4 +-- src/coreclr/jit/optcse.cpp | 2 +- src/coreclr/jit/valuenum.cpp | 6 ++-- 12 files changed, 70 insertions(+), 109 deletions(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 09d9a651352c0e..039684b03cfbb9 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -1855,6 +1855,13 @@ struct CORINFO_String : public CORINFO_Object char16_t chars[1]; // actually of variable size }; +struct CORINFO_RuntimeType : public CORINFO_Object +{ + void* m_keepalive; + void* m_cache; + CORINFO_CLASS_HANDLE m_handle; +}; + struct CORINFO_Array : public CORINFO_Object { unsigned length; diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index c7506c92483534..2ed1d2fcf15b75 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -9426,9 +9426,9 @@ void cTreeFlags(Compiler* comp, GenTree* tree) chars += printf("[ICON_STR_HDL]"); break; - case GTF_ICON_TYPE_HDL: + case GTF_ICON_OBJ_HDL: - chars += printf("[ICON_TYPE_HDL]"); + chars += printf("[ICON_OBJ_HDL]"); break; case GTF_ICON_CONST_PTR: diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 4811d81ece9f9f..94bf1e58dc7265 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -3522,6 +3522,7 @@ class Compiler CORINFO_CLASS_HANDLE impGetRuntimeArgumentHandle(); CORINFO_CLASS_HANDLE impGetTypeHandleClass(); CORINFO_CLASS_HANDLE impGetStringClass(); + CORINFO_CLASS_HANDLE impGetRuntimeTypeClass(); CORINFO_CLASS_HANDLE impGetObjectClass(); // Returns underlying type of handles returned by ldtoken instruction @@ -7800,7 +7801,7 @@ class Compiler const char* eeGetFieldName(CORINFO_FIELD_HANDLE fieldHnd, const char** classNamePtr = nullptr); #if defined(DEBUG) - const WCHAR* eeGetCPString(size_t stringHandle); + void eePrintFrozenObjectDescription(const char* prefix, size_t handle); unsigned eeTryGetClassSize(CORINFO_CLASS_HANDLE clsHnd); const char16_t* eeGetShortClassName(CORINFO_CLASS_HANDLE clsHnd); #endif diff --git a/src/coreclr/jit/ee_il_dll.cpp b/src/coreclr/jit/ee_il_dll.cpp index fedbae80a624c4..a45932a7ce8cb2 100644 --- a/src/coreclr/jit/ee_il_dll.cpp +++ b/src/coreclr/jit/ee_il_dll.cpp @@ -1615,45 +1615,45 @@ const char16_t* Compiler::eeGetShortClassName(CORINFO_CLASS_HANDLE clsHnd) return param.classNameWidePtr; } -const WCHAR* Compiler::eeGetCPString(size_t strHandle) +void Compiler::eePrintFrozenObjectDescription(const char* prefix, size_t handle) { -#ifdef HOST_UNIX - return nullptr; -#else - char buff[512 + sizeof(CORINFO_String)]; - - // make this bulletproof, so it works even if we are wrong. - if (ReadProcessMemory(GetCurrentProcess(), (void*)strHandle, buff, 4, nullptr) == 0) + auto typeOfHandle = *((CORINFO_CLASS_HANDLE*)handle); + if (impGetStringClass() == typeOfHandle) { - return (nullptr); - } + auto asString = (CORINFO_String*)handle; - CORINFO_String* asString = nullptr; - if (impGetStringClass() == *((CORINFO_CLASS_HANDLE*)strHandle)) - { - // strHandle is a frozen string - // We assume strHandle is never an "interior" pointer in a frozen string - // (jit is not expected to perform such foldings) - asString = (CORINFO_String*)strHandle; - } - else - { - // strHandle is a pinned handle to a string object - asString = *((CORINFO_String**)strHandle); - } + const size_t maxLength = 63; + const size_t newLen = min(maxLength, asString->stringLen); - if (ReadProcessMemory(GetCurrentProcess(), asString, buff, sizeof(buff), nullptr) == 0) + // +1 for null terminator + WCHAR buf[maxLength + 1] = {0}; + wcsncpy(buf, (WCHAR*)asString->chars, newLen); + for (size_t i = 0; i < newLen; i++) + { + // Escape \n and \r symbols + if (buf[i] == L'\n' || buf[i] == L'\r') + { + buf[i] = L' '; + } + } + if (asString->stringLen > maxLength) + { + // Append "..." for long strings + buf[maxLength - 3] = L'.'; + buf[maxLength - 2] = L'.'; + buf[maxLength - 1] = L'.'; + } + printf("%s \"%S\"", prefix, buf); + } + else if (impGetRuntimeTypeClass() == typeOfHandle) { - return (nullptr); + auto asType = (CORINFO_RuntimeType*)handle; + printf("%s %s", prefix, eeGetClassName(asType->m_handle)); } - - if (asString->stringLen >= 255 || asString->chars[asString->stringLen] != 0) + else { - return nullptr; + printf("%s unknown frozen object handle", prefix); } - - return (WCHAR*)(asString->chars); -#endif // HOST_UNIX } #else // DEBUG void jitprintf(const char* fmt, ...) diff --git a/src/coreclr/jit/emit.cpp b/src/coreclr/jit/emit.cpp index 58157b28483834..344bb9cdd86583 100644 --- a/src/coreclr/jit/emit.cpp +++ b/src/coreclr/jit/emit.cpp @@ -4129,48 +4129,17 @@ void emitter::emitDispCommentForHandle(size_t handle, size_t cookie, GenTreeFlag const char* str = nullptr; if (flag == GTF_ICON_STR_HDL) + { + str = "string handle"; + } + else if (flag == GTF_ICON_OBJ_HDL) { #ifdef DEBUG - const WCHAR* wstr = emitComp->eeGetCPString(handle); - // NOTE: eGetCPString always returns nullptr on Linux/ARM - if (wstr == nullptr) - { - str = "string handle"; - } - else - { - const size_t actualLen = wcslen(wstr); - const size_t maxLength = 63; - const size_t newLen = min(maxLength, actualLen); - - // +1 for null terminator - WCHAR buf[maxLength + 1] = {0}; - wcsncpy(buf, wstr, newLen); - for (size_t i = 0; i < newLen; i++) - { - // Escape \n and \r symbols - if (buf[i] == L'\n' || buf[i] == L'\r') - { - buf[i] = L' '; - } - } - if (actualLen > maxLength) - { - // Append "..." for long strings - buf[maxLength - 3] = L'.'; - buf[maxLength - 2] = L'.'; - buf[maxLength - 1] = L'.'; - } - printf("%s \"%S\"", commentPrefix, buf); - } + emitComp->eePrintFrozenObjectDescription(commentPrefix, handle); #else - str = "string handle"; + str = "frozen object handle"; #endif } - else if (flag == GTF_ICON_TYPE_HDL) - { - str = "Type handle"; - } else if (flag == GTF_ICON_CLASS_HDL) { str = emitComp->eeGetClassName(reinterpret_cast(handle)); diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index 20a700e6913408..5e1448748cefc4 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -8756,18 +8756,6 @@ void emitter::emitDispAddrMode(instrDesc* id, bool noDetail) printf("]"); -// pretty print string if it looks like one -#ifdef DEBUG - if ((id->idGCref() == GCT_GCREF) && (id->idIns() == INS_mov) && (id->idAddr()->iiaAddrMode.amBaseReg == REG_NA)) - { - const WCHAR* str = emitComp->eeGetCPString(disp); - if (str != nullptr) - { - printf(" '%S'", str); - } - } -#endif - if (jdsc && !noDetail) { unsigned cnt = (jdsc->dsSize - 1) / TARGET_POINTER_SIZE; diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 57a30e529d6d26..80073868c698f6 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -6911,7 +6911,7 @@ GenTree* Compiler::gtNewIndOfIconHandleNode(var_types indType, size_t addr, GenT // This indirection also is invariant. indNode->gtFlags |= GTF_IND_INVARIANT; - if ((iconFlags == GTF_ICON_STR_HDL) || (iconFlags == GTF_ICON_TYPE_HDL)) + if ((iconFlags == GTF_ICON_STR_HDL) || (iconFlags == GTF_ICON_OBJ_HDL)) { // String literals and frozen type objects are never null indNode->gtFlags |= GTF_IND_NONNULL; @@ -6991,7 +6991,7 @@ GenTree* Compiler::gtNewStringLiteralNode(InfoAccessType iat, void* pValue) { case IAT_VALUE: setMethodHasFrozenObjects(); - tree = gtNewIconEmbHndNode(pValue, nullptr, GTF_ICON_STR_HDL, nullptr); + tree = gtNewIconEmbHndNode(pValue, nullptr, GTF_ICON_OBJ_HDL, nullptr); tree->gtType = TYP_REF; #ifdef DEBUG tree->AsIntCon()->gtTargetHandle = (size_t)pValue; @@ -11101,22 +11101,11 @@ void Compiler::gtDispConst(GenTree* tree) case GT_CNS_INT: if (tree->IsIconHandle(GTF_ICON_STR_HDL)) { - const WCHAR* str = eeGetCPString(tree->AsIntCon()->gtIconVal); - // If *str points to a '\0' then don't print the string's values - if ((str != nullptr) && (*str != '\0')) - { - printf(" 0x%X \"%S\"", dspPtr(tree->AsIntCon()->gtIconVal), str); - } - else // We can't print the value of the string - { - // Note that eeGetCPString isn't currently implemented on Linux/ARM - // and instead always returns nullptr - printf(" 0x%X [ICON_STR_HDL]", dspPtr(tree->AsIntCon()->gtIconVal)); - } + printf(" 0x%X [ICON_STR_HDL]", dspPtr(tree->AsIntCon()->gtIconVal)); } - else if (tree->IsIconHandle(GTF_ICON_TYPE_HDL)) + else if (tree->IsIconHandle(GTF_ICON_OBJ_HDL)) { - printf(" 0x%X [ICON_TYPE_HDL]", dspPtr(tree->AsIntCon()->gtIconVal)); + eePrintFrozenObjectDescription(" ", tree->AsIntCon()->gtIconVal); } else { @@ -11176,7 +11165,7 @@ void Compiler::gtDispConst(GenTree* tree) case GTF_ICON_STATIC_HDL: printf(" static"); break; - case GTF_ICON_TYPE_HDL: + case GTF_ICON_OBJ_HDL: case GTF_ICON_STR_HDL: unreached(); // These cases are handled above break; diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index 00bd3a536b1886..727059fa3ef088 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -554,8 +554,8 @@ enum GenTreeFlags : unsigned int GTF_ICON_METHOD_HDL = 0x03000000, // GT_CNS_INT -- constant is a method handle GTF_ICON_FIELD_HDL = 0x04000000, // GT_CNS_INT -- constant is a field handle GTF_ICON_STATIC_HDL = 0x05000000, // GT_CNS_INT -- constant is a handle to static data - GTF_ICON_STR_HDL = 0x06000000, // GT_CNS_INT -- constant is a string handle - GTF_ICON_TYPE_HDL = 0x12000000, // GT_CNS_INT -- constant is a Type handle + GTF_ICON_STR_HDL = 0x06000000, // GT_CNS_INT -- constant is a pinned handle pointing to a string object + GTF_ICON_OBJ_HDL = 0x12000000, // GT_CNS_INT -- constant is an object handle (e.g. frozen string or Type object) GTF_ICON_CONST_PTR = 0x07000000, // GT_CNS_INT -- constant is a pointer to immutable data, (e.g. IAT_PPVALUE) GTF_ICON_GLOBAL_PTR = 0x08000000, // GT_CNS_INT -- constant is a pointer to mutable data (e.g. from the VM state) GTF_ICON_VARG_HDL = 0x09000000, // GT_CNS_INT -- constant is a var arg cookie handle diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 88ee85b65a89be..6addbdd6a8ff6f 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -3034,6 +3034,13 @@ CORINFO_CLASS_HANDLE Compiler::impGetStringClass() return stringClass; } +CORINFO_CLASS_HANDLE Compiler::impGetRuntimeTypeClass() +{ + CORINFO_CLASS_HANDLE stringClass = info.compCompHnd->getBuiltinClass(CLASSID_RUNTIME_TYPE); + assert(stringClass != (CORINFO_CLASS_HANDLE) nullptr); + return stringClass; +} + CORINFO_CLASS_HANDLE Compiler::impGetObjectClass() { CORINFO_CLASS_HANDLE objectClass = info.compCompHnd->getBuiltinClass(CLASSID_SYSTEM_OBJECT); @@ -22944,7 +22951,7 @@ bool Compiler::impCanSkipCovariantStoreCheck(GenTree* value, GenTree* array) return true; } // Non-0 const refs can only occur with frozen objects - assert(value->IsIconHandle(GTF_ICON_STR_HDL) || value->IsIconHandle(GTF_ICON_TYPE_HDL)); + assert(value->IsIconHandle(GTF_ICON_OBJ_HDL)); assert(doesMethodHaveFrozenObjects() || (compIsForInlining() && impInlineInfo->InlinerCompiler->doesMethodHaveFrozenObjects())); } diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 50f63d6c787178..43bc5779032b74 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -8324,7 +8324,7 @@ GenTree* Compiler::fgMorphCall(GenTreeCall* call) if (ptr != nullptr) { setMethodHasFrozenObjects(); - GenTree* retNode = gtNewIconEmbHndNode(ptr, nullptr, GTF_ICON_TYPE_HDL, nullptr); + GenTree* retNode = gtNewIconEmbHndNode(ptr, nullptr, GTF_ICON_OBJ_HDL, nullptr); retNode->gtType = TYP_REF; INDEBUG(retNode->AsIntCon()->gtTargetHandle = (size_t)ptr); return fgMorphTree(retNode); @@ -11181,7 +11181,7 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac, bool* optA // if (!tree->AsIndir()->IsVolatile()) { - if (op1->IsIconHandle(GTF_ICON_STR_HDL)) + if (op1->IsIconHandle(GTF_ICON_OBJ_HDL)) { tree->gtFlags |= (GTF_IND_INVARIANT | GTF_IND_NONFAULTING | GTF_IND_NONNULL); } diff --git a/src/coreclr/jit/optcse.cpp b/src/coreclr/jit/optcse.cpp index f7ac2c91329660..05abdbe1245a17 100644 --- a/src/coreclr/jit/optcse.cpp +++ b/src/coreclr/jit/optcse.cpp @@ -811,7 +811,7 @@ bool Compiler::optValnumCSE_Locate() if (!enableConstCSE && // Unconditionally allow these constant handles to be CSE'd !tree->IsIconHandle(GTF_ICON_STATIC_HDL) && !tree->IsIconHandle(GTF_ICON_CLASS_HDL) && - !tree->IsIconHandle(GTF_ICON_STR_HDL) && !tree->IsIconHandle(GTF_ICON_TYPE_HDL)) + !tree->IsIconHandle(GTF_ICON_STR_HDL) && !tree->IsIconHandle(GTF_ICON_OBJ_HDL)) { continue; } diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index a6d0a4eb84d6ae..ca92b2e7a1d848 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -5254,7 +5254,7 @@ GenTreeFlags ValueNumStore::GetFoldedArithOpResultHandleFlags(ValueNum vn) case GTF_ICON_FIELD_HDL: case GTF_ICON_TOKEN_HDL: case GTF_ICON_STR_HDL: - case GTF_ICON_TYPE_HDL: + case GTF_ICON_OBJ_HDL: case GTF_ICON_CONST_PTR: case GTF_ICON_VARG_HDL: case GTF_ICON_PINVKI_HDL: @@ -8163,8 +8163,8 @@ void Compiler::fgValueNumberTreeConst(GenTree* tree) } else { - // Constant object can be only frozen string and frozen Type. - assert(tree->IsIconHandle(GTF_ICON_STR_HDL) || tree->IsIconHandle(GTF_ICON_TYPE_HDL)); + // Constant object can be only GTF_ICON_OBJ_HDL handles. + assert(tree->IsIconHandle(GTF_ICON_OBJ_HDL)); tree->gtVNPair.SetBoth( vnStore->VNForHandle(ssize_t(tree->AsIntConCommon()->IconValue()), tree->GetIconHandleFlag())); } From c8512a983fb72efe8b547a90c06d4bd03c5ed3f3 Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Sat, 17 Sep 2022 14:13:15 +0200 Subject: [PATCH 07/39] Update src/coreclr/jit/compiler.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Michal Strehovský --- src/coreclr/jit/compiler.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 94bf1e58dc7265..703f5bb885e45b 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -6809,7 +6809,7 @@ class Compiler #define OMF_HAS_EXPRUNTIMELOOKUP 0x00000080 // Method contains a runtime lookup to an expandable dictionary. #define OMF_HAS_PATCHPOINT 0x00000100 // Method contains patchpoints #define OMF_NEEDS_GCPOLLS 0x00000200 // Method needs GC polls -#define OMF_HAS_FROZEN_OBJECTS 0x00000400 // Method has a frozen string (REF constant int), currently only on NativeAOT. +#define OMF_HAS_FROZEN_OBJECTS 0x00000400 // Method has a frozen string (REF constant int) #define OMF_HAS_PARTIAL_COMPILATION_PATCHPOINT 0x00000800 // Method contains partial compilation patchpoints #define OMF_HAS_TAILCALL_SUCCESSOR 0x00001000 // Method has potential tail call in a non BBJ_RETURN block #define OMF_HAS_MDNEWARRAY 0x00002000 // Method contains 'new' of an MD array From 9d8526e401b50ac91ad61cddc64aad43c08664db Mon Sep 17 00:00:00 2001 From: EgorBo Date: Sat, 17 Sep 2022 15:06:25 +0200 Subject: [PATCH 08/39] Address some of the feedback [WIP] --- src/coreclr/inc/clrconfigvalues.h | 5 ----- src/coreclr/jit/assertionprop.cpp | 2 +- src/coreclr/jit/gentree.cpp | 2 +- src/coreclr/jit/valuenum.cpp | 2 +- src/coreclr/vm/frozenobjectheap.cpp | 23 ++--------------------- src/coreclr/vm/frozenobjectheap.h | 2 -- src/coreclr/vm/methodtable.cpp | 11 ++++++----- 7 files changed, 11 insertions(+), 36 deletions(-) diff --git a/src/coreclr/inc/clrconfigvalues.h b/src/coreclr/inc/clrconfigvalues.h index 1ce2609af45ef6..8665e544d49464 100644 --- a/src/coreclr/inc/clrconfigvalues.h +++ b/src/coreclr/inc/clrconfigvalues.h @@ -405,11 +405,6 @@ RETAIL_CONFIG_DWORD_INFO(INTERNAL_CodeHeapReserveForJumpStubs, W("CodeHeapReserv RETAIL_CONFIG_DWORD_INFO(INTERNAL_NGenReserveForJumpStubs, W("NGenReserveForJumpStubs"), 0, "Percentage of ngen image size to reserve for jump stubs") RETAIL_CONFIG_DWORD_INFO(INTERNAL_BreakOnOutOfMemoryWithinRange, W("BreakOnOutOfMemoryWithinRange"), 0, "Break before out of memory within range exception is thrown") -/// -/// Frozen segments (aka Frozen Object Heap) -/// -RETAIL_CONFIG_DWORD_INFO(INTERNAL_UseFrozenObjectHeap, W("UseFrozenObjectHeap"), 1, "Use frozen object heap for certain types of objects (e.g. string literals) as an optimization.") - /// /// Log /// diff --git a/src/coreclr/jit/assertionprop.cpp b/src/coreclr/jit/assertionprop.cpp index bc942d3f163738..1bd0c2677f7975 100644 --- a/src/coreclr/jit/assertionprop.cpp +++ b/src/coreclr/jit/assertionprop.cpp @@ -3423,7 +3423,7 @@ GenTree* Compiler::optConstantAssertionProp(AssertionDsc* curAssertion, // Make sure we don't retype const gc handles to TYP_I_IMPL // Although, it's possible for e.g. GTF_ICON_STATIC_HDL - if (!newTree->IsIntegralConst(0) && newTree->IsIconHandle(GTF_ICON_STR_HDL)) + if (!newTree->IsIntegralConst(0) && newTree->IsIconHandle(GTF_ICON_OBJ_HDL)) { if (tree->TypeIs(TYP_BYREF)) { diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 76efe4f18ffaa9..7d1204143096c4 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -11120,7 +11120,7 @@ void Compiler::gtDispConst(GenTree* tree) } else { - assert(doesMethodHaveFrozenString()); + assert(doesMethodHaveFrozenObjects()); printf(" 0x%llx", dspIconVal); } } diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index 501e154dbac4d5..ba5a4a4300dd9c 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -8163,7 +8163,7 @@ void Compiler::fgValueNumberTreeConst(GenTree* tree) } else { - assert(doesMethodHaveFrozenString()); // Constant object can be only frozen string. + assert(doesMethodHaveFrozenObjects()); tree->gtVNPair.SetBoth( vnStore->VNForHandle(ssize_t(tree->AsIntConCommon()->IconValue()), tree->GetIconHandleFlag())); } diff --git a/src/coreclr/vm/frozenobjectheap.cpp b/src/coreclr/vm/frozenobjectheap.cpp index 8b78984515f404..781c2a710f51db 100644 --- a/src/coreclr/vm/frozenobjectheap.cpp +++ b/src/coreclr/vm/frozenobjectheap.cpp @@ -11,15 +11,12 @@ FrozenObjectHeapManager::FrozenObjectHeapManager(): m_Crst(CrstFrozenObjectHeap, CRST_UNSAFE_COOPGC), - m_CurrentSegment(nullptr), - m_Enabled(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_UseFrozenObjectHeap) != 0) + m_CurrentSegment(nullptr) { } // Allocates an object of the give size (including header) on a frozen segment. -// May return nullptr in the following cases: -// 1) DOTNET_UseFrozenObjectHeap is 0 (disabled) -// 2) Object is too large (large than FOH_COMMIT_SIZE) +// May return nullptr if object is too large (larger than FOH_COMMIT_SIZE) // in such cases caller is responsible to find a more appropriate heap to allocate it Object* FrozenObjectHeapManager::TryAllocateObject(PTR_MethodTable type, size_t objectSize) { @@ -37,12 +34,6 @@ Object* FrozenObjectHeapManager::TryAllocateObject(PTR_MethodTable type, size_t CrstHolder ch(&m_Crst); - if (!m_Enabled) - { - // Disabled via DOTNET_UseFrozenObjectHeap=0 - return nullptr; - } - _ASSERT(type != nullptr); _ASSERT(FOH_COMMIT_SIZE >= MIN_OBJECT_SIZE); _ASSERT(FOH_SEGMENT_SIZE > FOH_COMMIT_SIZE); @@ -85,16 +76,6 @@ Object* FrozenObjectHeapManager::TryAllocateObject(PTR_MethodTable type, size_t #endif // !FEATURE_BASICFREEZE } -// Does object belong to a frozen segment? -bool FrozenObjectHeapManager::IsFromFrozenSegment(Object* object) -{ -#ifdef FEATURE_BASICFREEZE - return GCHeapUtilities::GetGCHeap()->IsInFrozenSegment(object); -#else - return false; -#endif -} - FrozenObjectSegment::FrozenObjectSegment(): m_pStart(nullptr), m_pCurrent(nullptr), diff --git a/src/coreclr/vm/frozenobjectheap.h b/src/coreclr/vm/frozenobjectheap.h index 068b81431b7192..50c2a15f367e42 100644 --- a/src/coreclr/vm/frozenobjectheap.h +++ b/src/coreclr/vm/frozenobjectheap.h @@ -28,13 +28,11 @@ class FrozenObjectHeapManager public: FrozenObjectHeapManager(); Object* TryAllocateObject(PTR_MethodTable type, size_t objectSize); - bool IsFromFrozenSegment(Object* object); private: Crst m_Crst; SArray m_FrozenSegments; FrozenObjectSegment* m_CurrentSegment; - bool m_Enabled; }; class FrozenObjectSegment diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index a508151231ae59..01c805ef2b6a32 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -4232,14 +4232,14 @@ OBJECTREF MethodTable::GetManagedClassObject() size_t objSize = g_pRuntimeTypeClass->GetBaseSize(); refClass = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(foh->TryAllocateObject(g_pRuntimeTypeClass, objSize)); } - - if (refClass == NULL) + else { refClass = (REFLECTCLASSBASEREF)AllocateObject(g_pRuntimeTypeClass); + ((ReflectClassBaseObject*)OBJECTREFToObject(refClass))->SetKeepAlive(pLoaderAllocator->GetExposedObject()); } + _ASSERT(refClass != NULL); ((ReflectClassBaseObject*)OBJECTREFToObject(refClass))->SetType(TypeHandle(this)); - ((ReflectClassBaseObject*)OBJECTREFToObject(refClass))->SetKeepAlive(pLoaderAllocator->GetExposedObject()); // Let all threads fight over who wins using InterlockedCompareExchange. // Only the winner can set m_ExposedClassObject from NULL. @@ -4272,8 +4272,9 @@ OBJECTREF MethodTable::GetManagedClassObject(bool* pIsPinned) GCPROTECT_BEGIN(objRef); objRef = GetManagedClassObject(); - FrozenObjectHeapManager* foh = SystemDomain::GetFrozenObjectHeapManager(); - *pIsPinned = foh->IsFromFrozenSegment(OBJECTREFToObject(objRef)); + + // Type objects in non-unloadable contexts are always "pinned" (allocated on FOH) + *pIsPinned = this->GetLoaderAllocator()->IsUnloaded(); GCPROTECT_END(); From 18e1cd447d468f6a796c7bace869c54428cc9474 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Sat, 17 Sep 2022 16:50:07 +0200 Subject: [PATCH 09/39] Address feedback --- src/coreclr/vm/jitinterface.cpp | 12 ++++++--- src/coreclr/vm/methodtable.cpp | 46 +++++++++------------------------ src/coreclr/vm/methodtable.h | 2 +- src/coreclr/vm/methodtable.inl | 35 +++++++++++++++++++++---- 4 files changed, 51 insertions(+), 44 deletions(-) diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 6d8b82a7aff0db..96865181ca2bc3 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -5962,11 +5962,15 @@ void* CEEInfo::getRuntimeTypePointer(CORINFO_CLASS_HANDLE clsHnd) MethodTable* pMT = typeHnd.AsMethodTable(); if (!typeHnd.IsCanonicalSubtype()) { - bool isPinned; - Object* obj = OBJECTREFToObject(pMT->GetManagedClassObject(&isPinned)); - if (isPinned) + // Trigger allocation if it's not allocated yet + if (pMT->GetManagedClassObject() != NULL) { - pointer = (void*)obj; + // Check if we can rely on object being effectively pinned + OBJECTREF objRef = pMT->GetPinnedManagedClassObjectIfExists(); + if (objRef != NULL) + { + pointer = (void*)OBJECTREFToObject(objRef); + } } } } diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index 01c805ef2b6a32..ebfe6523e9fe2c 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -4221,30 +4221,34 @@ OBJECTREF MethodTable::GetManagedClassObject() // Make sure that we have been restored CheckRestore(); - REFLECTCLASSBASEREF refClass = NULL; + REFLECTCLASSBASEREF refClass = NULL; GCPROTECT_BEGIN(refClass); + LOADERHANDLE exposedClassObjectHandle = NULL; LoaderAllocator* pLoaderAllocator = GetLoaderAllocator(); if (!pLoaderAllocator->CanUnload()) { // Allocate RuntimeType on a frozen segment FrozenObjectHeapManager* foh = SystemDomain::GetFrozenObjectHeapManager(); size_t objSize = g_pRuntimeTypeClass->GetBaseSize(); - refClass = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(foh->TryAllocateObject(g_pRuntimeTypeClass, objSize)); + Object* obj = foh->TryAllocateObject(g_pRuntimeTypeClass, objSize); + refClass = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(obj); + refClass->SetType(TypeHandle(this)); + exposedClassObjectHandle = (LOADERHANDLE)obj; + _ASSERT((((UINT_PTR)obj) & 1) == 0); } else { refClass = (REFLECTCLASSBASEREF)AllocateObject(g_pRuntimeTypeClass); - ((ReflectClassBaseObject*)OBJECTREFToObject(refClass))->SetKeepAlive(pLoaderAllocator->GetExposedObject()); + refClass->SetKeepAlive(pLoaderAllocator->GetExposedObject()); + refClass->SetType(TypeHandle(this)); + exposedClassObjectHandle = pLoaderAllocator->AllocateHandle(refClass); } - _ASSERT(refClass != NULL); - - ((ReflectClassBaseObject*)OBJECTREFToObject(refClass))->SetType(TypeHandle(this)); + _ASSERT(refClass != NULL); + // Let all threads fight over who wins using InterlockedCompareExchange. // Only the winner can set m_ExposedClassObject from NULL. - LOADERHANDLE exposedClassObjectHandle = pLoaderAllocator->AllocateHandle(refClass); - if (InterlockedCompareExchangeT(&GetWriteableDataForWrite()->m_hExposedClassObject, exposedClassObjectHandle, static_cast(NULL))) { pLoaderAllocator->FreeHandle(exposedClassObjectHandle); @@ -4255,32 +4259,6 @@ OBJECTREF MethodTable::GetManagedClassObject() RETURN(GetManagedClassObjectIfExists()); } -OBJECTREF MethodTable::GetManagedClassObject(bool* pIsPinned) -{ - CONTRACT(OBJECTREF) - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - INJECT_FAULT(COMPlusThrowOM()); - } - CONTRACT_END; - - _ASSERT(pIsPinned != nullptr); - - OBJECTREF objRef = NULL; - GCPROTECT_BEGIN(objRef); - - objRef = GetManagedClassObject(); - - // Type objects in non-unloadable contexts are always "pinned" (allocated on FOH) - *pIsPinned = this->GetLoaderAllocator()->IsUnloaded(); - - GCPROTECT_END(); - - RETURN(objRef); -} - #endif //!DACCESS_COMPILE //========================================================================================== diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index 8cd499873fba6b..291eb0c6869649 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -2716,8 +2716,8 @@ class MethodTable // method will get the class object. If it doesn't exist it will be created. // GetManagedClassObjectIfExists() will return null if the Type object doesn't exist. OBJECTREF GetManagedClassObject(); - OBJECTREF GetManagedClassObject(bool* pIsPinned); OBJECTREF GetManagedClassObjectIfExists(); + OBJECTREF GetPinnedManagedClassObjectIfExists(); // ------------------------------------------------------------------ diff --git a/src/coreclr/vm/methodtable.inl b/src/coreclr/vm/methodtable.inl index 8f8f8178e26023..54ba073bbbf735 100644 --- a/src/coreclr/vm/methodtable.inl +++ b/src/coreclr/vm/methodtable.inl @@ -1334,6 +1334,29 @@ inline OBJECTHANDLE MethodTable::GetLoaderAllocatorObjectHandle() return GetLoaderAllocator()->GetLoaderAllocatorObjectHandle(); } +//========================================================================================== +OBJECTREF MethodTable::GetPinnedManagedClassObjectIfExists() +{ + CONTRACT(OBJECTREF) + { + THROWS; + GC_TRIGGERS; + MODE_COOPERATIVE; + INJECT_FAULT(COMPlusThrowOM()); + } + CONTRACT_END; + + LOADERHANDLE handle = GetWriteableData_NoLogging()->GetExposedClassObjectHandle(); + // Lowest bit 0 means that ExposedClassObjectHandle points to a frozen object directly + if (handle != NULL && (((UINT_PTR)handle) & 0) == 0) + { + Object* obj = (Object*)handle; + _ASSERT(obj != nullptr); + return ObjectToOBJECTREF(obj); + } + return NULL; +} + //========================================================================================== FORCEINLINE OBJECTREF MethodTable::GetManagedClassObjectIfExists() { @@ -1342,12 +1365,14 @@ FORCEINLINE OBJECTREF MethodTable::GetManagedClassObjectIfExists() // Logging will be done by the slow path LOADERHANDLE handle = GetWriteableData_NoLogging()->GetExposedClassObjectHandle(); - OBJECTREF retVal; + // First, check if have a cached reference to an effectively pinned (allocated on FOH) object + OBJECTREF retVal = GetPinnedManagedClassObjectIfExists(); + if (retVal != NULL) + { + return retVal; + } - // GET_LOADERHANDLE_VALUE_FAST macro is inlined here to let us give hint to the compiler - // when the return value is not null. - if (!LoaderAllocator::GetHandleValueFast(handle, &retVal) && - !GetLoaderAllocator()->GetHandleValueFastPhase2(handle, &retVal)) + if (!GetLoaderAllocator()->GetHandleValueFastPhase2(handle, &retVal)) { return NULL; } From a7fea6d4f707fd8cf5fe26d9e3c8ee253848e543 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Sat, 17 Sep 2022 16:56:56 +0200 Subject: [PATCH 10/39] Fix compilation --- src/coreclr/vm/methodtable.inl | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/coreclr/vm/methodtable.inl b/src/coreclr/vm/methodtable.inl index 54ba073bbbf735..182206223441bb 100644 --- a/src/coreclr/vm/methodtable.inl +++ b/src/coreclr/vm/methodtable.inl @@ -1335,16 +1335,9 @@ inline OBJECTHANDLE MethodTable::GetLoaderAllocatorObjectHandle() } //========================================================================================== -OBJECTREF MethodTable::GetPinnedManagedClassObjectIfExists() +FORCEINLINE OBJECTREF MethodTable::GetPinnedManagedClassObjectIfExists() { - CONTRACT(OBJECTREF) - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - INJECT_FAULT(COMPlusThrowOM()); - } - CONTRACT_END; + LIMITED_METHOD_CONTRACT; LOADERHANDLE handle = GetWriteableData_NoLogging()->GetExposedClassObjectHandle(); // Lowest bit 0 means that ExposedClassObjectHandle points to a frozen object directly From f2afedc22ca0b332e47b5cea04198e63f4444f9b Mon Sep 17 00:00:00 2001 From: EgorBo Date: Sat, 17 Sep 2022 18:17:29 +0200 Subject: [PATCH 11/39] Introduce `objectToString` JIT-EE API --- src/coreclr/inc/corinfo.h | 14 +- src/coreclr/inc/icorjitinfoimpl_generated.h | 5 + src/coreclr/jit/ICorJitInfo_API_names.h | 1 + src/coreclr/jit/ICorJitInfo_API_wrapper.hpp | 11 + src/coreclr/jit/ee_il_dll.cpp | 38 +-- .../tools/Common/JitInterface/CorInfoBase.cs | 296 +++++++++--------- .../tools/Common/JitInterface/CorInfoImpl.cs | 8 + .../ThunkGenerator/ThunkInput.txt | 1 + .../tools/aot/jitinterface/jitinterface.h | 12 + .../tools/superpmi/superpmi-shared/lwmlist.h | 1 + .../superpmi-shared/methodcontext.cpp | 61 ++++ .../superpmi/superpmi-shared/methodcontext.h | 5 + .../superpmi-shim-collector/icorjitinfo.cpp | 11 + .../superpmi-shim-counter/icorjitinfo.cpp | 9 + .../superpmi-shim-simple/icorjitinfo.cpp | 8 + .../tools/superpmi/superpmi/icorjitinfo.cpp | 9 + src/coreclr/vm/jitinterface.cpp | 42 +++ 17 files changed, 353 insertions(+), 179 deletions(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 039684b03cfbb9..87f8c2964ecf38 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -1855,13 +1855,6 @@ struct CORINFO_String : public CORINFO_Object char16_t chars[1]; // actually of variable size }; -struct CORINFO_RuntimeType : public CORINFO_Object -{ - void* m_keepalive; - void* m_cache; - CORINFO_CLASS_HANDLE m_handle; -}; - struct CORINFO_Array : public CORINFO_Object { unsigned length; @@ -2272,6 +2265,13 @@ class ICorStaticInfo int bufferSize /* IN */ ) = 0; + // Calls ToString() for given pinned/frozen object handle + virtual int objectToString ( + void* handle, /* IN */ + char16_t* buffer, /* OUT */ + int bufferSize /* IN */ + ) = 0; + /**********************************************************************************/ // // ICorClassInfo diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h index 5f2d3b88ac208a..8caf56a5237ea9 100644 --- a/src/coreclr/inc/icorjitinfoimpl_generated.h +++ b/src/coreclr/inc/icorjitinfoimpl_generated.h @@ -175,6 +175,11 @@ int getStringLiteral( char16_t* buffer, int bufferSize) override; +int objectToString( + void* handle, + char16_t* buffer, + int bufferSize) override; + CorInfoType asCorInfoType( CORINFO_CLASS_HANDLE cls) override; diff --git a/src/coreclr/jit/ICorJitInfo_API_names.h b/src/coreclr/jit/ICorJitInfo_API_names.h index 24a1f903e20786..9ebd42f381af65 100644 --- a/src/coreclr/jit/ICorJitInfo_API_names.h +++ b/src/coreclr/jit/ICorJitInfo_API_names.h @@ -41,6 +41,7 @@ DEF_CLR_API(getTokenTypeAsHandle) DEF_CLR_API(isValidToken) DEF_CLR_API(isValidStringRef) DEF_CLR_API(getStringLiteral) +DEF_CLR_API(objectToString) DEF_CLR_API(asCorInfoType) DEF_CLR_API(getClassName) DEF_CLR_API(getClassNameFromMetadata) diff --git a/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp b/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp index ff7cf2035b97f8..0cbdb58c270ab9 100644 --- a/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp +++ b/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp @@ -374,6 +374,17 @@ int WrapICorJitInfo::getStringLiteral( return temp; } +int WrapICorJitInfo::objectToString( + void* handle, + char16_t* buffer, + int bufferSize) +{ + API_ENTER(objectToString); + int temp = wrapHnd->objectToString(handle, buffer, bufferSize); + API_LEAVE(objectToString); + return temp; +} + CorInfoType WrapICorJitInfo::asCorInfoType( CORINFO_CLASS_HANDLE cls) { diff --git a/src/coreclr/jit/ee_il_dll.cpp b/src/coreclr/jit/ee_il_dll.cpp index a45932a7ce8cb2..343f0f9c99648f 100644 --- a/src/coreclr/jit/ee_il_dll.cpp +++ b/src/coreclr/jit/ee_il_dll.cpp @@ -1617,42 +1617,16 @@ const char16_t* Compiler::eeGetShortClassName(CORINFO_CLASS_HANDLE clsHnd) void Compiler::eePrintFrozenObjectDescription(const char* prefix, size_t handle) { - auto typeOfHandle = *((CORINFO_CLASS_HANDLE*)handle); - if (impGetStringClass() == typeOfHandle) + const int maxStrSize = 128; + char16_t str[maxStrSize] = {0}; + int realLength = this->info.compCompHnd->objectToString((void*)handle, str, maxStrSize); + if (realLength >= 0) { - auto asString = (CORINFO_String*)handle; - - const size_t maxLength = 63; - const size_t newLen = min(maxLength, asString->stringLen); - - // +1 for null terminator - WCHAR buf[maxLength + 1] = {0}; - wcsncpy(buf, (WCHAR*)asString->chars, newLen); - for (size_t i = 0; i < newLen; i++) - { - // Escape \n and \r symbols - if (buf[i] == L'\n' || buf[i] == L'\r') - { - buf[i] = L' '; - } - } - if (asString->stringLen > maxLength) - { - // Append "..." for long strings - buf[maxLength - 3] = L'.'; - buf[maxLength - 2] = L'.'; - buf[maxLength - 1] = L'.'; - } - printf("%s \"%S\"", prefix, buf); - } - else if (impGetRuntimeTypeClass() == typeOfHandle) - { - auto asType = (CORINFO_RuntimeType*)handle; - printf("%s %s", prefix, eeGetClassName(asType->m_handle)); + printf("%s '%S'\n", prefix, str); } else { - printf("%s unknown frozen object handle", prefix); + printf("%s 'frozen object handle'\n", prefix, str); } } #else // DEBUG diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs b/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs index a8cbd191399fe5..7b753fb48a20d4 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs @@ -553,6 +553,21 @@ private static int _getStringLiteral(IntPtr thisHandle, IntPtr* ppException, COR } } + [UnmanagedCallersOnly] + private static int _objectToString(IntPtr thisHandle, IntPtr* ppException, void* handle, char* buffer, int bufferSize) + { + var _this = GetThis(thisHandle); + try + { + return _this.objectToString(handle, buffer, bufferSize); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default; + } + } + [UnmanagedCallersOnly] private static CorInfoType _asCorInfoType(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) { @@ -2610,7 +2625,7 @@ private static uint _getJitFlags(IntPtr thisHandle, IntPtr* ppException, CORJIT_ private static IntPtr GetUnmanagedCallbacks() { - void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 176); + void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 177); callbacks[0] = (delegate* unmanaged)&_isIntrinsic; callbacks[1] = (delegate* unmanaged)&_getMethodAttribs; @@ -2649,145 +2664,146 @@ private static IntPtr GetUnmanagedCallbacks() callbacks[34] = (delegate* unmanaged)&_isValidToken; callbacks[35] = (delegate* unmanaged)&_isValidStringRef; callbacks[36] = (delegate* unmanaged)&_getStringLiteral; - callbacks[37] = (delegate* unmanaged)&_asCorInfoType; - callbacks[38] = (delegate* unmanaged)&_getClassName; - callbacks[39] = (delegate* unmanaged)&_getClassNameFromMetadata; - callbacks[40] = (delegate* unmanaged)&_getTypeInstantiationArgument; - callbacks[41] = (delegate* unmanaged)&_appendClassName; - callbacks[42] = (delegate* unmanaged)&_isValueClass; - callbacks[43] = (delegate* unmanaged)&_canInlineTypeCheck; - callbacks[44] = (delegate* unmanaged)&_getClassAttribs; - callbacks[45] = (delegate* unmanaged)&_getClassModule; - callbacks[46] = (delegate* unmanaged)&_getModuleAssembly; - callbacks[47] = (delegate* unmanaged)&_getAssemblyName; - callbacks[48] = (delegate* unmanaged)&_LongLifetimeMalloc; - callbacks[49] = (delegate* unmanaged)&_LongLifetimeFree; - callbacks[50] = (delegate* unmanaged)&_getClassModuleIdForStatics; - callbacks[51] = (delegate* unmanaged)&_getClassSize; - callbacks[52] = (delegate* unmanaged)&_getHeapClassSize; - callbacks[53] = (delegate* unmanaged)&_canAllocateOnStack; - callbacks[54] = (delegate* unmanaged)&_getClassAlignmentRequirement; - callbacks[55] = (delegate* unmanaged)&_getClassGClayout; - callbacks[56] = (delegate* unmanaged)&_getClassNumInstanceFields; - callbacks[57] = (delegate* unmanaged)&_getFieldInClass; - callbacks[58] = (delegate* unmanaged)&_checkMethodModifier; - callbacks[59] = (delegate* unmanaged)&_getNewHelper; - callbacks[60] = (delegate* unmanaged)&_getNewArrHelper; - callbacks[61] = (delegate* unmanaged)&_getCastingHelper; - callbacks[62] = (delegate* unmanaged)&_getSharedCCtorHelper; - callbacks[63] = (delegate* unmanaged)&_getTypeForBox; - callbacks[64] = (delegate* unmanaged)&_getBoxHelper; - callbacks[65] = (delegate* unmanaged)&_getUnBoxHelper; - callbacks[66] = (delegate* unmanaged)&_getRuntimeTypePointer; - callbacks[67] = (delegate* unmanaged)&_getReadyToRunHelper; - callbacks[68] = (delegate* unmanaged)&_getReadyToRunDelegateCtorHelper; - callbacks[69] = (delegate* unmanaged)&_getHelperName; - callbacks[70] = (delegate* unmanaged)&_initClass; - callbacks[71] = (delegate* unmanaged)&_classMustBeLoadedBeforeCodeIsRun; - callbacks[72] = (delegate* unmanaged)&_getBuiltinClass; - callbacks[73] = (delegate* unmanaged)&_getTypeForPrimitiveValueClass; - callbacks[74] = (delegate* unmanaged)&_getTypeForPrimitiveNumericClass; - callbacks[75] = (delegate* unmanaged)&_canCast; - callbacks[76] = (delegate* unmanaged)&_areTypesEquivalent; - callbacks[77] = (delegate* unmanaged)&_compareTypesForCast; - callbacks[78] = (delegate* unmanaged)&_compareTypesForEquality; - callbacks[79] = (delegate* unmanaged)&_mergeClasses; - callbacks[80] = (delegate* unmanaged)&_isMoreSpecificType; - callbacks[81] = (delegate* unmanaged)&_getParentType; - callbacks[82] = (delegate* unmanaged)&_getChildType; - callbacks[83] = (delegate* unmanaged)&_satisfiesClassConstraints; - callbacks[84] = (delegate* unmanaged)&_isSDArray; - callbacks[85] = (delegate* unmanaged)&_getArrayRank; - callbacks[86] = (delegate* unmanaged)&_getArrayIntrinsicID; - callbacks[87] = (delegate* unmanaged)&_getArrayInitializationData; - callbacks[88] = (delegate* unmanaged)&_canAccessClass; - callbacks[89] = (delegate* unmanaged)&_getFieldName; - callbacks[90] = (delegate* unmanaged)&_getFieldClass; - callbacks[91] = (delegate* unmanaged)&_getFieldType; - callbacks[92] = (delegate* unmanaged)&_getFieldOffset; - callbacks[93] = (delegate* unmanaged)&_getFieldInfo; - callbacks[94] = (delegate* unmanaged)&_isFieldStatic; - callbacks[95] = (delegate* unmanaged)&_getBoundaries; - callbacks[96] = (delegate* unmanaged)&_setBoundaries; - callbacks[97] = (delegate* unmanaged)&_getVars; - callbacks[98] = (delegate* unmanaged)&_setVars; - callbacks[99] = (delegate* unmanaged)&_reportRichMappings; - callbacks[100] = (delegate* unmanaged)&_allocateArray; - callbacks[101] = (delegate* unmanaged)&_freeArray; - callbacks[102] = (delegate* unmanaged)&_getArgNext; - callbacks[103] = (delegate* unmanaged)&_getArgType; - callbacks[104] = (delegate* unmanaged)&_getExactClasses; - callbacks[105] = (delegate* unmanaged)&_getArgClass; - callbacks[106] = (delegate* unmanaged)&_getHFAType; - callbacks[107] = (delegate* unmanaged)&_GetErrorHRESULT; - callbacks[108] = (delegate* unmanaged)&_GetErrorMessage; - callbacks[109] = (delegate* unmanaged)&_FilterException; - callbacks[110] = (delegate* unmanaged)&_ThrowExceptionForJitResult; - callbacks[111] = (delegate* unmanaged)&_ThrowExceptionForHelper; - callbacks[112] = (delegate* unmanaged)&_runWithErrorTrap; - callbacks[113] = (delegate* unmanaged)&_runWithSPMIErrorTrap; - callbacks[114] = (delegate* unmanaged)&_getEEInfo; - callbacks[115] = (delegate* unmanaged)&_getJitTimeLogFilename; - callbacks[116] = (delegate* unmanaged)&_getMethodDefFromMethod; - callbacks[117] = (delegate* unmanaged)&_getMethodName; - callbacks[118] = (delegate* unmanaged)&_getMethodNameFromMetadata; - callbacks[119] = (delegate* unmanaged)&_getMethodHash; - callbacks[120] = (delegate* unmanaged)&_findNameOfToken; - callbacks[121] = (delegate* unmanaged)&_getSystemVAmd64PassStructInRegisterDescriptor; - callbacks[122] = (delegate* unmanaged)&_getLoongArch64PassStructInRegisterFlags; - callbacks[123] = (delegate* unmanaged)&_getThreadTLSIndex; - callbacks[124] = (delegate* unmanaged)&_getInlinedCallFrameVptr; - callbacks[125] = (delegate* unmanaged)&_getAddrOfCaptureThreadGlobal; - callbacks[126] = (delegate* unmanaged)&_getHelperFtn; - callbacks[127] = (delegate* unmanaged)&_getFunctionEntryPoint; - callbacks[128] = (delegate* unmanaged)&_getFunctionFixedEntryPoint; - callbacks[129] = (delegate* unmanaged)&_getMethodSync; - callbacks[130] = (delegate* unmanaged)&_getLazyStringLiteralHelper; - callbacks[131] = (delegate* unmanaged)&_embedModuleHandle; - callbacks[132] = (delegate* unmanaged)&_embedClassHandle; - callbacks[133] = (delegate* unmanaged)&_embedMethodHandle; - callbacks[134] = (delegate* unmanaged)&_embedFieldHandle; - callbacks[135] = (delegate* unmanaged)&_embedGenericHandle; - callbacks[136] = (delegate* unmanaged)&_getLocationOfThisType; - callbacks[137] = (delegate* unmanaged)&_getAddressOfPInvokeTarget; - callbacks[138] = (delegate* unmanaged)&_GetCookieForPInvokeCalliSig; - callbacks[139] = (delegate* unmanaged)&_canGetCookieForPInvokeCalliSig; - callbacks[140] = (delegate* unmanaged)&_getJustMyCodeHandle; - callbacks[141] = (delegate* unmanaged)&_GetProfilingHandle; - callbacks[142] = (delegate* unmanaged)&_getCallInfo; - callbacks[143] = (delegate* unmanaged)&_canAccessFamily; - callbacks[144] = (delegate* unmanaged)&_isRIDClassDomainID; - callbacks[145] = (delegate* unmanaged)&_getClassDomainID; - callbacks[146] = (delegate* unmanaged)&_getFieldAddress; - callbacks[147] = (delegate* unmanaged)&_getStaticFieldCurrentClass; - callbacks[148] = (delegate* unmanaged)&_getVarArgsHandle; - callbacks[149] = (delegate* unmanaged)&_canGetVarArgsHandle; - callbacks[150] = (delegate* unmanaged)&_constructStringLiteral; - callbacks[151] = (delegate* unmanaged)&_emptyStringLiteral; - callbacks[152] = (delegate* unmanaged)&_getFieldThreadLocalStoreID; - callbacks[153] = (delegate* unmanaged)&_addActiveDependency; - callbacks[154] = (delegate* unmanaged)&_GetDelegateCtor; - callbacks[155] = (delegate* unmanaged)&_MethodCompileComplete; - callbacks[156] = (delegate* unmanaged)&_getTailCallHelpers; - callbacks[157] = (delegate* unmanaged)&_convertPInvokeCalliToCall; - callbacks[158] = (delegate* unmanaged)&_notifyInstructionSetUsage; - callbacks[159] = (delegate* unmanaged)&_updateEntryPointForTailCall; - callbacks[160] = (delegate* unmanaged)&_allocMem; - callbacks[161] = (delegate* unmanaged)&_reserveUnwindInfo; - callbacks[162] = (delegate* unmanaged)&_allocUnwindInfo; - callbacks[163] = (delegate* unmanaged)&_allocGCInfo; - callbacks[164] = (delegate* unmanaged)&_setEHcount; - callbacks[165] = (delegate* unmanaged)&_setEHinfo; - callbacks[166] = (delegate* unmanaged)&_logMsg; - callbacks[167] = (delegate* unmanaged)&_doAssert; - callbacks[168] = (delegate* unmanaged)&_reportFatalError; - callbacks[169] = (delegate* unmanaged)&_getPgoInstrumentationResults; - callbacks[170] = (delegate* unmanaged)&_allocPgoInstrumentationBySchema; - callbacks[171] = (delegate* unmanaged)&_recordCallSite; - callbacks[172] = (delegate* unmanaged)&_recordRelocation; - callbacks[173] = (delegate* unmanaged)&_getRelocTypeHint; - callbacks[174] = (delegate* unmanaged)&_getExpectedTargetArchitecture; - callbacks[175] = (delegate* unmanaged)&_getJitFlags; + callbacks[37] = (delegate* unmanaged)&_objectToString; + callbacks[38] = (delegate* unmanaged)&_asCorInfoType; + callbacks[39] = (delegate* unmanaged)&_getClassName; + callbacks[40] = (delegate* unmanaged)&_getClassNameFromMetadata; + callbacks[41] = (delegate* unmanaged)&_getTypeInstantiationArgument; + callbacks[42] = (delegate* unmanaged)&_appendClassName; + callbacks[43] = (delegate* unmanaged)&_isValueClass; + callbacks[44] = (delegate* unmanaged)&_canInlineTypeCheck; + callbacks[45] = (delegate* unmanaged)&_getClassAttribs; + callbacks[46] = (delegate* unmanaged)&_getClassModule; + callbacks[47] = (delegate* unmanaged)&_getModuleAssembly; + callbacks[48] = (delegate* unmanaged)&_getAssemblyName; + callbacks[49] = (delegate* unmanaged)&_LongLifetimeMalloc; + callbacks[50] = (delegate* unmanaged)&_LongLifetimeFree; + callbacks[51] = (delegate* unmanaged)&_getClassModuleIdForStatics; + callbacks[52] = (delegate* unmanaged)&_getClassSize; + callbacks[53] = (delegate* unmanaged)&_getHeapClassSize; + callbacks[54] = (delegate* unmanaged)&_canAllocateOnStack; + callbacks[55] = (delegate* unmanaged)&_getClassAlignmentRequirement; + callbacks[56] = (delegate* unmanaged)&_getClassGClayout; + callbacks[57] = (delegate* unmanaged)&_getClassNumInstanceFields; + callbacks[58] = (delegate* unmanaged)&_getFieldInClass; + callbacks[59] = (delegate* unmanaged)&_checkMethodModifier; + callbacks[60] = (delegate* unmanaged)&_getNewHelper; + callbacks[61] = (delegate* unmanaged)&_getNewArrHelper; + callbacks[62] = (delegate* unmanaged)&_getCastingHelper; + callbacks[63] = (delegate* unmanaged)&_getSharedCCtorHelper; + callbacks[64] = (delegate* unmanaged)&_getTypeForBox; + callbacks[65] = (delegate* unmanaged)&_getBoxHelper; + callbacks[66] = (delegate* unmanaged)&_getUnBoxHelper; + callbacks[67] = (delegate* unmanaged)&_getRuntimeTypePointer; + callbacks[68] = (delegate* unmanaged)&_getReadyToRunHelper; + callbacks[69] = (delegate* unmanaged)&_getReadyToRunDelegateCtorHelper; + callbacks[70] = (delegate* unmanaged)&_getHelperName; + callbacks[71] = (delegate* unmanaged)&_initClass; + callbacks[72] = (delegate* unmanaged)&_classMustBeLoadedBeforeCodeIsRun; + callbacks[73] = (delegate* unmanaged)&_getBuiltinClass; + callbacks[74] = (delegate* unmanaged)&_getTypeForPrimitiveValueClass; + callbacks[75] = (delegate* unmanaged)&_getTypeForPrimitiveNumericClass; + callbacks[76] = (delegate* unmanaged)&_canCast; + callbacks[77] = (delegate* unmanaged)&_areTypesEquivalent; + callbacks[78] = (delegate* unmanaged)&_compareTypesForCast; + callbacks[79] = (delegate* unmanaged)&_compareTypesForEquality; + callbacks[80] = (delegate* unmanaged)&_mergeClasses; + callbacks[81] = (delegate* unmanaged)&_isMoreSpecificType; + callbacks[82] = (delegate* unmanaged)&_getParentType; + callbacks[83] = (delegate* unmanaged)&_getChildType; + callbacks[84] = (delegate* unmanaged)&_satisfiesClassConstraints; + callbacks[85] = (delegate* unmanaged)&_isSDArray; + callbacks[86] = (delegate* unmanaged)&_getArrayRank; + callbacks[87] = (delegate* unmanaged)&_getArrayIntrinsicID; + callbacks[88] = (delegate* unmanaged)&_getArrayInitializationData; + callbacks[89] = (delegate* unmanaged)&_canAccessClass; + callbacks[90] = (delegate* unmanaged)&_getFieldName; + callbacks[91] = (delegate* unmanaged)&_getFieldClass; + callbacks[92] = (delegate* unmanaged)&_getFieldType; + callbacks[93] = (delegate* unmanaged)&_getFieldOffset; + callbacks[94] = (delegate* unmanaged)&_getFieldInfo; + callbacks[95] = (delegate* unmanaged)&_isFieldStatic; + callbacks[96] = (delegate* unmanaged)&_getBoundaries; + callbacks[97] = (delegate* unmanaged)&_setBoundaries; + callbacks[98] = (delegate* unmanaged)&_getVars; + callbacks[99] = (delegate* unmanaged)&_setVars; + callbacks[100] = (delegate* unmanaged)&_reportRichMappings; + callbacks[101] = (delegate* unmanaged)&_allocateArray; + callbacks[102] = (delegate* unmanaged)&_freeArray; + callbacks[103] = (delegate* unmanaged)&_getArgNext; + callbacks[104] = (delegate* unmanaged)&_getArgType; + callbacks[105] = (delegate* unmanaged)&_getExactClasses; + callbacks[106] = (delegate* unmanaged)&_getArgClass; + callbacks[107] = (delegate* unmanaged)&_getHFAType; + callbacks[108] = (delegate* unmanaged)&_GetErrorHRESULT; + callbacks[109] = (delegate* unmanaged)&_GetErrorMessage; + callbacks[110] = (delegate* unmanaged)&_FilterException; + callbacks[111] = (delegate* unmanaged)&_ThrowExceptionForJitResult; + callbacks[112] = (delegate* unmanaged)&_ThrowExceptionForHelper; + callbacks[113] = (delegate* unmanaged)&_runWithErrorTrap; + callbacks[114] = (delegate* unmanaged)&_runWithSPMIErrorTrap; + callbacks[115] = (delegate* unmanaged)&_getEEInfo; + callbacks[116] = (delegate* unmanaged)&_getJitTimeLogFilename; + callbacks[117] = (delegate* unmanaged)&_getMethodDefFromMethod; + callbacks[118] = (delegate* unmanaged)&_getMethodName; + callbacks[119] = (delegate* unmanaged)&_getMethodNameFromMetadata; + callbacks[120] = (delegate* unmanaged)&_getMethodHash; + callbacks[121] = (delegate* unmanaged)&_findNameOfToken; + callbacks[122] = (delegate* unmanaged)&_getSystemVAmd64PassStructInRegisterDescriptor; + callbacks[123] = (delegate* unmanaged)&_getLoongArch64PassStructInRegisterFlags; + callbacks[124] = (delegate* unmanaged)&_getThreadTLSIndex; + callbacks[125] = (delegate* unmanaged)&_getInlinedCallFrameVptr; + callbacks[126] = (delegate* unmanaged)&_getAddrOfCaptureThreadGlobal; + callbacks[127] = (delegate* unmanaged)&_getHelperFtn; + callbacks[128] = (delegate* unmanaged)&_getFunctionEntryPoint; + callbacks[129] = (delegate* unmanaged)&_getFunctionFixedEntryPoint; + callbacks[130] = (delegate* unmanaged)&_getMethodSync; + callbacks[131] = (delegate* unmanaged)&_getLazyStringLiteralHelper; + callbacks[132] = (delegate* unmanaged)&_embedModuleHandle; + callbacks[133] = (delegate* unmanaged)&_embedClassHandle; + callbacks[134] = (delegate* unmanaged)&_embedMethodHandle; + callbacks[135] = (delegate* unmanaged)&_embedFieldHandle; + callbacks[136] = (delegate* unmanaged)&_embedGenericHandle; + callbacks[137] = (delegate* unmanaged)&_getLocationOfThisType; + callbacks[138] = (delegate* unmanaged)&_getAddressOfPInvokeTarget; + callbacks[139] = (delegate* unmanaged)&_GetCookieForPInvokeCalliSig; + callbacks[140] = (delegate* unmanaged)&_canGetCookieForPInvokeCalliSig; + callbacks[141] = (delegate* unmanaged)&_getJustMyCodeHandle; + callbacks[142] = (delegate* unmanaged)&_GetProfilingHandle; + callbacks[143] = (delegate* unmanaged)&_getCallInfo; + callbacks[144] = (delegate* unmanaged)&_canAccessFamily; + callbacks[145] = (delegate* unmanaged)&_isRIDClassDomainID; + callbacks[146] = (delegate* unmanaged)&_getClassDomainID; + callbacks[147] = (delegate* unmanaged)&_getFieldAddress; + callbacks[148] = (delegate* unmanaged)&_getStaticFieldCurrentClass; + callbacks[149] = (delegate* unmanaged)&_getVarArgsHandle; + callbacks[150] = (delegate* unmanaged)&_canGetVarArgsHandle; + callbacks[151] = (delegate* unmanaged)&_constructStringLiteral; + callbacks[152] = (delegate* unmanaged)&_emptyStringLiteral; + callbacks[153] = (delegate* unmanaged)&_getFieldThreadLocalStoreID; + callbacks[154] = (delegate* unmanaged)&_addActiveDependency; + callbacks[155] = (delegate* unmanaged)&_GetDelegateCtor; + callbacks[156] = (delegate* unmanaged)&_MethodCompileComplete; + callbacks[157] = (delegate* unmanaged)&_getTailCallHelpers; + callbacks[158] = (delegate* unmanaged)&_convertPInvokeCalliToCall; + callbacks[159] = (delegate* unmanaged)&_notifyInstructionSetUsage; + callbacks[160] = (delegate* unmanaged)&_updateEntryPointForTailCall; + callbacks[161] = (delegate* unmanaged)&_allocMem; + callbacks[162] = (delegate* unmanaged)&_reserveUnwindInfo; + callbacks[163] = (delegate* unmanaged)&_allocUnwindInfo; + callbacks[164] = (delegate* unmanaged)&_allocGCInfo; + callbacks[165] = (delegate* unmanaged)&_setEHcount; + callbacks[166] = (delegate* unmanaged)&_setEHinfo; + callbacks[167] = (delegate* unmanaged)&_logMsg; + callbacks[168] = (delegate* unmanaged)&_doAssert; + callbacks[169] = (delegate* unmanaged)&_reportFatalError; + callbacks[170] = (delegate* unmanaged)&_getPgoInstrumentationResults; + callbacks[171] = (delegate* unmanaged)&_allocPgoInstrumentationBySchema; + callbacks[172] = (delegate* unmanaged)&_recordCallSite; + callbacks[173] = (delegate* unmanaged)&_recordRelocation; + callbacks[174] = (delegate* unmanaged)&_getRelocTypeHint; + callbacks[175] = (delegate* unmanaged)&_getExpectedTargetArchitecture; + callbacks[176] = (delegate* unmanaged)&_getJitFlags; return (IntPtr)callbacks; } diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 439d82aa67c7e0..94898ef8e9757e 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -1815,6 +1815,14 @@ private int getStringLiteral(CORINFO_MODULE_STRUCT_* module, uint metaTOK, char* return str.Length; } +#pragma warning disable CA1822 // Mark members as static + private int objectToString(void* handle, char* buffer, int size) +#pragma warning restore CA1822 // Mark members as static + { + // TODO: implement + return -1; + } + private CorInfoType asCorInfoType(CORINFO_CLASS_STRUCT_* cls) { var type = HandleToObject(cls); diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt index b09991de6b6f94..216986ef15e224 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -192,6 +192,7 @@ FUNCTIONS bool isValidToken(CORINFO_MODULE_HANDLE module, unsigned metaTOK) bool isValidStringRef(CORINFO_MODULE_HANDLE module, unsigned metaTOK) int getStringLiteral(CORINFO_MODULE_HANDLE module, unsigned metaTOK, char16_t* buffer, int bufferSize) + int objectToString(void* handle, char16_t* buffer, int bufferSize) CorInfoType asCorInfoType(CORINFO_CLASS_HANDLE cls) const char* getClassName(CORINFO_CLASS_HANDLE cls) const char* getClassNameFromMetadata(CORINFO_CLASS_HANDLE cls, const char **namespaceName) diff --git a/src/coreclr/tools/aot/jitinterface/jitinterface.h b/src/coreclr/tools/aot/jitinterface/jitinterface.h index d83968fa3c7d8d..82056ad4592b8a 100644 --- a/src/coreclr/tools/aot/jitinterface/jitinterface.h +++ b/src/coreclr/tools/aot/jitinterface/jitinterface.h @@ -48,6 +48,7 @@ struct JitInterfaceCallbacks bool (* isValidToken)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_MODULE_HANDLE module, unsigned metaTOK); bool (* isValidStringRef)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_MODULE_HANDLE module, unsigned metaTOK); int (* getStringLiteral)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_MODULE_HANDLE module, unsigned metaTOK, char16_t* buffer, int bufferSize); + int (* objectToString)(void * thisHandle, CorInfoExceptionClass** ppException, void* handle, char16_t* buffer, int bufferSize); CorInfoType (* asCorInfoType)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls); const char* (* getClassName)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls); const char* (* getClassNameFromMetadata)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls, const char** namespaceName); @@ -564,6 +565,17 @@ class JitInterfaceWrapper : public ICorJitInfo return temp; } + virtual int objectToString( + void* handle, + char16_t* buffer, + int bufferSize) +{ + CorInfoExceptionClass* pException = nullptr; + int temp = _callbacks->objectToString(_thisHandle, &pException, handle, buffer, bufferSize); + if (pException != nullptr) throw pException; + return temp; +} + virtual CorInfoType asCorInfoType( CORINFO_CLASS_HANDLE cls) { diff --git a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h index 36744c42e7e514..a40f741eea317e 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h @@ -149,6 +149,7 @@ LWM(IsIntrinsicType, DWORDLONG, DWORD) LWM(IsSDArray, DWORDLONG, DWORD) LWM(IsValidStringRef, DLD, DWORD) LWM(GetStringLiteral, DLDD, DD) +LWM(ObjectToString, DLD, DD) LWM(IsValidToken, DLD, DWORD) LWM(IsValueClass, DWORDLONG, DWORD) LWM(MergeClasses, DLDL, DWORDLONG) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index 1a58accad32cac..08d2253393007e 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -4896,6 +4896,67 @@ int MethodContext::repGetStringLiteral(CORINFO_MODULE_HANDLE module, unsigned me } } +void MethodContext::recObjectToString(void* handle, char16_t* buffer, int bufferSize, int length) +{ + if (ObjectToString == nullptr) + ObjectToString = new LightWeightMap(); + + DLD key; + ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding + key.A = CastHandle(handle); + key.B = (DWORD)bufferSize; + + DWORD strBuf = (DWORD)-1; + if (buffer != nullptr && length != -1) + { + int bufferRealSize = min(length, bufferSize) * sizeof(char16_t); + strBuf = (DWORD)ObjectToString->AddBuffer((unsigned char*)buffer, (unsigned int)bufferRealSize); + } + + DD value; + value.A = (DWORD)length; + value.B = (DWORD)strBuf; + + ObjectToString->Add(key, value); + DEBUG_REC(dmpObjectToString(key, value)); +} +void MethodContext::dmpObjectToString(DLD key, DD value) +{ + printf("ObjectToString key hnd-%016llX bufSize-%u, len-%u", key.A, key.B, value.A); + ObjectToString->Unlock(); +} +int MethodContext::repObjectToString(void* handle, char16_t* buffer, int bufferSize) +{ + if (ObjectToString == nullptr) + { + return -1; + } + + DLD key; + ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding + key.A = CastHandle(handle); + key.B = (DWORD)bufferSize; + + int itemIndex = ObjectToString->GetIndex(key); + if (itemIndex < 0) + { + return -1; + } + else + { + DD value = ObjectToString->Get(key); + DEBUG_REP(dmpObjectToString(key, value)); + int srcBufferLength = (int)value.A; + if (buffer != nullptr && srcBufferLength > 0) + { + char16_t* srcBuffer = (char16_t*)ObjectToString->GetBuffer(value.B); + Assert(srcBuffer != nullptr); + memcpy(buffer, srcBuffer, min(srcBufferLength, bufferSize) * sizeof(char16_t)); + } + return srcBufferLength; + } +} + void MethodContext::recGetHelperName(CorInfoHelpFunc funcNum, const char* result) { if (GetHelperName == nullptr) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h index 178512f3902da0..6b080a45f20ce3 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h @@ -622,6 +622,10 @@ class MethodContext void dmpGetStringLiteral(DLDD key, DD value); int repGetStringLiteral(CORINFO_MODULE_HANDLE module, unsigned metaTOK, char16_t* buffer, int bufferSize); + void recObjectToString(void* handle, char16_t* buffer, int bufferSize, int length); + void dmpObjectToString(DLD key, DD value); + int repObjectToString(void* handle, char16_t* buffer, int bufferSize); + void recGetHelperName(CorInfoHelpFunc funcNum, const char* result); void dmpGetHelperName(DWORD key, DWORD value); const char* repGetHelperName(CorInfoHelpFunc funcNum); @@ -1134,6 +1138,7 @@ enum mcPackets Packet_GetLoongArch64PassStructInRegisterFlags = 194, Packet_GetExactClasses = 195, Packet_GetRuntimeTypePointer = 196, + Packet_ObjectToString = 197, }; void SetDebugDumpVariables(); diff --git a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp index 4f9fdc855ecb3f..82eae5a3510611 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -453,6 +453,17 @@ int interceptor_ICJI::getStringLiteral(CORINFO_MODULE_HANDLE module, /* IN * return temp; } +int interceptor_ICJI::objectToString(void* handle, /* IN */ + char16_t* buffer, /* OUT */ + int bufferSize /* IN */ + ) +{ + mc->cr->AddCall("objectToString"); + int temp = original_ICorJitInfo->objectToString(handle, buffer, bufferSize); + mc->recObjectToString(handle, buffer, bufferSize, temp); + return temp; +} + /**********************************************************************************/ // // ICorClassInfo diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp index 6df44aa06851fd..e49b2f81143967 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp @@ -314,6 +314,15 @@ int interceptor_ICJI::getStringLiteral( return original_ICorJitInfo->getStringLiteral(module, metaTOK, buffer, bufferSize); } +int interceptor_ICJI::objectToString( + void* handle, + char16_t* buffer, + int bufferSize) +{ + mcs->AddCall("objectToString"); + return original_ICorJitInfo->objectToString(handle, buffer, bufferSize); +} + CorInfoType interceptor_ICJI::asCorInfoType( CORINFO_CLASS_HANDLE cls) { diff --git a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp index 7785eb7d1685cc..f507034dea16aa 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp @@ -277,6 +277,14 @@ int interceptor_ICJI::getStringLiteral( return original_ICorJitInfo->getStringLiteral(module, metaTOK, buffer, bufferSize); } +int interceptor_ICJI::objectToString( + void* handle, + char16_t* buffer, + int bufferSize) +{ + return original_ICorJitInfo->objectToString(handle, buffer, bufferSize); +} + CorInfoType interceptor_ICJI::asCorInfoType( CORINFO_CLASS_HANDLE cls) { diff --git a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp index c2c0999cdd92f6..8421232c2e867a 100644 --- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp @@ -388,6 +388,15 @@ int MyICJI::getStringLiteral(CORINFO_MODULE_HANDLE module, /* IN */ return jitInstance->mc->repGetStringLiteral(module, metaTOK, buffer, bufferSize); } +int MyICJI::objectToString(void* handle, /* IN */ + char16_t* buffer, /* OUT */ + int bufferSize /* IN */ + ) +{ + jitInstance->mc->cr->AddCall("objectToString"); + return jitInstance->mc->repObjectToString(handle, buffer, bufferSize); +} + /**********************************************************************************/ // // ICorClassInfo diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 96865181ca2bc3..a17697d66c1fed 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -715,6 +715,48 @@ int CEEInfo::getStringLiteral ( return result; } +int CEEInfo::objectToString ( + void* handle, + char16_t* buffer, + int bufferSize) +{ + CONTRACTL{ + THROWS; + GC_TRIGGERS; + MODE_PREEMPTIVE; + } CONTRACTL_END; + + int result = -1; + + JIT_TO_EE_TRANSITION(); + + Object* obj = (Object*)handle; + + GCX_COOP(); + + StackSString stackStr; + + // Currently only supported for String and RuntimeType + if (obj->GetMethodTable()->IsString()) + { + ((StringObject*)obj)->GetSString(stackStr); + } + else if (obj->GetMethodTable() == g_pRuntimeTypeClass) + { + ((ReflectClassBaseObject*)obj)->GetType().GetName(stackStr); + } + + if (stackStr.GetCount() > 0) + { + result = min(bufferSize, (int)stackStr.GetCount()); + memcpy((BYTE*)buffer, stackStr.GetUnicode(), result * 2); + } + + EE_TO_JIT_TRANSITION(); + + return result; +} + /* static */ size_t CEEInfo::findNameOfToken (Module* module, mdToken metaTOK, From 6a8cedf2ce272a5613ea54825e38ee7cca02deb9 Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Sat, 17 Sep 2022 18:18:11 +0200 Subject: [PATCH 12/39] Update src/coreclr/vm/methodtable.cpp Co-authored-by: Jan Kotas --- src/coreclr/vm/methodtable.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index ebfe6523e9fe2c..ee8e5b0f31461a 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -4232,6 +4232,7 @@ OBJECTREF MethodTable::GetManagedClassObject() FrozenObjectHeapManager* foh = SystemDomain::GetFrozenObjectHeapManager(); size_t objSize = g_pRuntimeTypeClass->GetBaseSize(); Object* obj = foh->TryAllocateObject(g_pRuntimeTypeClass, objSize); + _ASSERTE(obj != NULL); refClass = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(obj); refClass->SetType(TypeHandle(this)); exposedClassObjectHandle = (LOADERHANDLE)obj; From 677f94b8a79a0de36190c1c86b279f7611957426 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Sat, 17 Sep 2022 18:51:24 +0200 Subject: [PATCH 13/39] check for unloadability in GetPinnedManagedClassObjectIfExists --- src/coreclr/vm/methodtable.inl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/vm/methodtable.inl b/src/coreclr/vm/methodtable.inl index 182206223441bb..67684fbd449885 100644 --- a/src/coreclr/vm/methodtable.inl +++ b/src/coreclr/vm/methodtable.inl @@ -1341,7 +1341,7 @@ FORCEINLINE OBJECTREF MethodTable::GetPinnedManagedClassObjectIfExists() LOADERHANDLE handle = GetWriteableData_NoLogging()->GetExposedClassObjectHandle(); // Lowest bit 0 means that ExposedClassObjectHandle points to a frozen object directly - if (handle != NULL && (((UINT_PTR)handle) & 0) == 0) + if (handle != NULL && (((UINT_PTR)handle) & 0) == 0 && !this->GetLoaderAllocator()->CanUnload()) { Object* obj = (Object*)handle; _ASSERT(obj != nullptr); From 81bacbb7ba138259569b20bfbf7702f2fa0530c3 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Sat, 17 Sep 2022 19:06:10 +0200 Subject: [PATCH 14/39] Since I still have to check CanUnload I guess I don't need the bit test --- src/coreclr/vm/methodtable.cpp | 6 +----- src/coreclr/vm/methodtable.inl | 7 ++++--- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index ee8e5b0f31461a..a57969ee9430f4 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -4234,20 +4234,16 @@ OBJECTREF MethodTable::GetManagedClassObject() Object* obj = foh->TryAllocateObject(g_pRuntimeTypeClass, objSize); _ASSERTE(obj != NULL); refClass = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(obj); - refClass->SetType(TypeHandle(this)); exposedClassObjectHandle = (LOADERHANDLE)obj; - _ASSERT((((UINT_PTR)obj) & 1) == 0); } else { refClass = (REFLECTCLASSBASEREF)AllocateObject(g_pRuntimeTypeClass); refClass->SetKeepAlive(pLoaderAllocator->GetExposedObject()); - refClass->SetType(TypeHandle(this)); exposedClassObjectHandle = pLoaderAllocator->AllocateHandle(refClass); } + refClass->SetType(TypeHandle(this)); - _ASSERT(refClass != NULL); - // Let all threads fight over who wins using InterlockedCompareExchange. // Only the winner can set m_ExposedClassObject from NULL. if (InterlockedCompareExchangeT(&GetWriteableDataForWrite()->m_hExposedClassObject, exposedClassObjectHandle, static_cast(NULL))) diff --git a/src/coreclr/vm/methodtable.inl b/src/coreclr/vm/methodtable.inl index 67684fbd449885..882f261369a09d 100644 --- a/src/coreclr/vm/methodtable.inl +++ b/src/coreclr/vm/methodtable.inl @@ -1339,9 +1339,10 @@ FORCEINLINE OBJECTREF MethodTable::GetPinnedManagedClassObjectIfExists() { LIMITED_METHOD_CONTRACT; - LOADERHANDLE handle = GetWriteableData_NoLogging()->GetExposedClassObjectHandle(); - // Lowest bit 0 means that ExposedClassObjectHandle points to a frozen object directly - if (handle != NULL && (((UINT_PTR)handle) & 0) == 0 && !this->GetLoaderAllocator()->CanUnload()) + const LOADERHANDLE handle = GetWriteableData_NoLogging()->GetExposedClassObjectHandle(); + // For a non-unloadable context, handle is expected to be either null (is not cached yet) + // or be a direct pointer to a frozen RuntimeType object + if (handle != NULL && !GetLoaderAllocator()->CanUnload()) { Object* obj = (Object*)handle; _ASSERT(obj != nullptr); From b5b7c9811b685cb5b9b62c9c1bb33133db4ccba8 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Sat, 17 Sep 2022 21:19:10 +0200 Subject: [PATCH 15/39] Address feedback --- src/coreclr/inc/crsttypes.h | 9 ++++-- .../tools/Common/JitInterface/CorInfoImpl.cs | 10 +++++-- src/coreclr/vm/appdomain.cpp | 4 +-- src/coreclr/vm/appdomain.hpp | 8 ++++- src/coreclr/vm/jitinterface.cpp | 2 +- src/coreclr/vm/methodtable.cpp | 30 +++++++++++-------- 6 files changed, 41 insertions(+), 22 deletions(-) diff --git a/src/coreclr/inc/crsttypes.h b/src/coreclr/inc/crsttypes.h index cc3d34ab58e2b9..0a5b4492d8f4b1 100644 --- a/src/coreclr/inc/crsttypes.h +++ b/src/coreclr/inc/crsttypes.h @@ -132,7 +132,8 @@ enum CrstType CrstVSDIndirectionCellLock = 114, CrstWrapperTemplate = 115, CrstFrozenObjectHeap = 116, - kNumberOfCrstTypes = 117 + CrstMethodTableExposedObject = 117, + kNumberOfCrstTypes = 118 }; #endif // __CRST_TYPES_INCLUDED @@ -259,7 +260,8 @@ int g_rgCrstLevelMap[] = 3, // CrstUnwindInfoTableLock 4, // CrstVSDIndirectionCellLock 3, // CrstWrapperTemplate - 0, // CrstFrozenObjectHeap + -1, // CrstFrozenObjectHeap + -1, // CrstMethodTableExposedObject }; // An array mapping CrstType to a stringized name. @@ -381,7 +383,8 @@ LPCSTR g_rgCrstNameMap[] = "CrstUnwindInfoTableLock", "CrstVSDIndirectionCellLock", "CrstWrapperTemplate", - "CrstFrozenObjectHeap" + "CrstFrozenObjectHeap", + "CrstMethodTableExposedObject" }; // Define a special level constant for unordered locks. diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 94898ef8e9757e..9ad1a6ea307804 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -1819,8 +1819,14 @@ private int getStringLiteral(CORINFO_MODULE_STRUCT_* module, uint metaTOK, char* private int objectToString(void* handle, char* buffer, int size) #pragma warning restore CA1822 // Mark members as static { - // TODO: implement - return -1; + Debug.Assert(size >= 0); + + // NOTE: this function is used for pinned/frozen handles + + ReadOnlySpan str = HandleToObject((IntPtr)handle).ToString(); + int maxLength = Math.Min(size, str.Length); + str.CopyTo(new Span(buffer, maxLength)); + return maxLength; } private CorInfoType asCorInfoType(CORINFO_CLASS_STRUCT_* cls) diff --git a/src/coreclr/vm/appdomain.cpp b/src/coreclr/vm/appdomain.cpp index 6fa4b73a65960a..08a41a7ea4b7ce 100644 --- a/src/coreclr/vm/appdomain.cpp +++ b/src/coreclr/vm/appdomain.cpp @@ -93,7 +93,7 @@ SPTR_IMPL(SystemDomain, SystemDomain, m_pSystemDomain); #ifndef DACCESS_COMPILE // Base Domain Statics -CrstStatic BaseDomain::m_SpecialStaticsCrst; +CrstStatic BaseDomain::m_MethodTableExposedClassObjectCrst; int BaseDomain::m_iNumberOfProcessors = 0; @@ -557,7 +557,7 @@ OBJECTHANDLE ThreadStaticHandleTable::AllocateHandles(DWORD nRequested) //***************************************************************************** void BaseDomain::Attach() { - m_SpecialStaticsCrst.Init(CrstSpecialStatics); + m_MethodTableExposedClassObjectCrst.Init(CrstMethodTableExposedObject); } BaseDomain::BaseDomain() diff --git a/src/coreclr/vm/appdomain.hpp b/src/coreclr/vm/appdomain.hpp index d56157f8e6ee6a..ecf13313bef381 100644 --- a/src/coreclr/vm/appdomain.hpp +++ b/src/coreclr/vm/appdomain.hpp @@ -1094,6 +1094,12 @@ class BaseDomain return &m_crstLoaderAllocatorReferences; } + static CrstStatic* GetMethodTableExposedClassObjectLock() + { + LIMITED_METHOD_CONTRACT; + return &m_MethodTableExposedClassObjectCrst; + } + void AssertLoadLockHeld() { _ASSERTE(m_FileLoadLock.HasLock()); @@ -1135,7 +1141,7 @@ class BaseDomain #endif // FEATURE_COMINTEROP // Protects allocation of slot IDs for thread statics - static CrstStatic m_SpecialStaticsCrst; + static CrstStatic m_MethodTableExposedClassObjectCrst; public: // Only call this routine when you can guarantee there are no diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index a17697d66c1fed..a0bb1f7ca7ef90 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -5999,7 +5999,7 @@ void* CEEInfo::getRuntimeTypePointer(CORINFO_CLASS_HANDLE clsHnd) GCX_COOP(); TypeHandle typeHnd(clsHnd); - if (!typeHnd.IsNull() && !typeHnd.IsTypeDesc() && typeHnd.IsFullyLoaded()) + if (!typeHnd.IsNull() && !typeHnd.IsTypeDesc()) { MethodTable* pMT = typeHnd.AsMethodTable(); if (!typeHnd.IsCanonicalSubtype()) diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index a57969ee9430f4..9eebe5b8326995 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -4222,36 +4222,40 @@ OBJECTREF MethodTable::GetManagedClassObject() CheckRestore(); REFLECTCLASSBASEREF refClass = NULL; - GCPROTECT_BEGIN(refClass); - LOADERHANDLE exposedClassObjectHandle = NULL; LoaderAllocator* pLoaderAllocator = GetLoaderAllocator(); if (!pLoaderAllocator->CanUnload()) { + CrstHolder exposedClassLock(AppDomain::GetMethodTableExposedClassObjectLock()); + // Allocate RuntimeType on a frozen segment + // Take a lock here since we don't want to allocate redundant objects which won't be collected + FrozenObjectHeapManager* foh = SystemDomain::GetFrozenObjectHeapManager(); size_t objSize = g_pRuntimeTypeClass->GetBaseSize(); Object* obj = foh->TryAllocateObject(g_pRuntimeTypeClass, objSize); _ASSERTE(obj != NULL); refClass = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(obj); - exposedClassObjectHandle = (LOADERHANDLE)obj; + refClass->SetType(TypeHandle(this)); + GetWriteableDataForWrite()->m_hExposedClassObject = (LOADERHANDLE)obj; } else { + GCPROTECT_BEGIN(refClass); refClass = (REFLECTCLASSBASEREF)AllocateObject(g_pRuntimeTypeClass); refClass->SetKeepAlive(pLoaderAllocator->GetExposedObject()); - exposedClassObjectHandle = pLoaderAllocator->AllocateHandle(refClass); - } - refClass->SetType(TypeHandle(this)); + LOADERHANDLE exposedClassObjectHandle = pLoaderAllocator->AllocateHandle(refClass); + refClass->SetType(TypeHandle(this)); - // Let all threads fight over who wins using InterlockedCompareExchange. - // Only the winner can set m_ExposedClassObject from NULL. - if (InterlockedCompareExchangeT(&GetWriteableDataForWrite()->m_hExposedClassObject, exposedClassObjectHandle, static_cast(NULL))) - { - pLoaderAllocator->FreeHandle(exposedClassObjectHandle); + // Let all threads fight over who wins using InterlockedCompareExchange. + // Only the winner can set m_ExposedClassObject from NULL. + if (InterlockedCompareExchangeT(&GetWriteableDataForWrite()->m_hExposedClassObject, exposedClassObjectHandle, static_cast(NULL))) + { + // GC will collect unused instance + pLoaderAllocator->FreeHandle(exposedClassObjectHandle); + } + GCPROTECT_END(); } - - GCPROTECT_END(); } RETURN(GetManagedClassObjectIfExists()); } From 608e6c91867e399f2f99112c5c8ba88bc3809c10 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Sat, 17 Sep 2022 23:53:25 +0200 Subject: [PATCH 16/39] Add more temp debug checks for ci --- src/coreclr/vm/methodtable.cpp | 3 +++ src/coreclr/vm/methodtable.h | 10 ++++------ src/coreclr/vm/methodtable.inl | 14 ++++++++++++-- src/coreclr/vm/vars.hpp | 2 ++ 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index 9eebe5b8326995..9f0bafdc979af4 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -4235,6 +4235,7 @@ OBJECTREF MethodTable::GetManagedClassObject() size_t objSize = g_pRuntimeTypeClass->GetBaseSize(); Object* obj = foh->TryAllocateObject(g_pRuntimeTypeClass, objSize); _ASSERTE(obj != NULL); + _ASSERTE((((SSIZE_T)obj) & 1) == 0); refClass = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(obj); refClass->SetType(TypeHandle(this)); GetWriteableDataForWrite()->m_hExposedClassObject = (LOADERHANDLE)obj; @@ -4245,6 +4246,8 @@ OBJECTREF MethodTable::GetManagedClassObject() refClass = (REFLECTCLASSBASEREF)AllocateObject(g_pRuntimeTypeClass); refClass->SetKeepAlive(pLoaderAllocator->GetExposedObject()); LOADERHANDLE exposedClassObjectHandle = pLoaderAllocator->AllocateHandle(refClass); + // Set the lowest bit, we use it GetPinnedManagedClassObjectIfExists as a fast detection of the unloadable context + exposedClassObjectHandle |= 1; refClass->SetType(TypeHandle(this)); // Let all threads fight over who wins using InterlockedCompareExchange. diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index 291eb0c6869649..c2a4bffe340357 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -299,11 +299,9 @@ struct MethodTableWriteableData }; DWORD m_dwFlags; // Lot of empty bits here. - /* - * m_hExposedClassObject is LoaderAllocator slot index to - * a RuntimeType instance for this class. - */ - LOADERHANDLE m_hExposedClassObject; + // Either a direct RuntimeType instance reference or a slot index in LoaderAllocator's table + // a RuntimeType instance for this class. + RUNTIMETYPEHANDLE m_hExposedClassObject; #ifdef _DEBUG // to avoid verify same method table too many times when it's not changing, we cache the GC count @@ -335,7 +333,7 @@ struct MethodTableWriteableData #endif - inline LOADERHANDLE GetExposedClassObjectHandle() const + inline RUNTIMETYPEHANDLE GetExposedClassObjectHandle() const { LIMITED_METHOD_CONTRACT; return m_hExposedClassObject; diff --git a/src/coreclr/vm/methodtable.inl b/src/coreclr/vm/methodtable.inl index 882f261369a09d..6fa44cb81209cd 100644 --- a/src/coreclr/vm/methodtable.inl +++ b/src/coreclr/vm/methodtable.inl @@ -1339,15 +1339,25 @@ FORCEINLINE OBJECTREF MethodTable::GetPinnedManagedClassObjectIfExists() { LIMITED_METHOD_CONTRACT; - const LOADERHANDLE handle = GetWriteableData_NoLogging()->GetExposedClassObjectHandle(); + const RUNTIMETYPEHANDLE handle = GetWriteableData_NoLogging()->GetExposedClassObjectHandle(); // For a non-unloadable context, handle is expected to be either null (is not cached yet) // or be a direct pointer to a frozen RuntimeType object - if (handle != NULL && !GetLoaderAllocator()->CanUnload()) + if (handle != NULL && (handle & 1) == 0) { Object* obj = (Object*)handle; _ASSERT(obj != nullptr); + _ASSERT(GCHeapUtilities::GetGCHeap()->IsInFrozenSegment(obj)); + _ASSERT(!this->GetLoaderAllocator()->CanUnload()); + INDEBUG(obj->Validate()); return ObjectToOBJECTREF(obj); } + +#ifdef _DEBUG + if (handle != NULL && (handle & 1) != 0) + { + _ASSERT(this->GetLoaderAllocator()->CanUnload()); + } +#endif return NULL; } diff --git a/src/coreclr/vm/vars.hpp b/src/coreclr/vm/vars.hpp index ca46259c8181e5..d4e3a0de77ae8a 100644 --- a/src/coreclr/vm/vars.hpp +++ b/src/coreclr/vm/vars.hpp @@ -99,6 +99,8 @@ struct LOADERHANDLE__ }; typedef TADDR LOADERHANDLE; +typedef TADDR RUNTIMETYPEHANDLE; + #ifdef DACCESS_COMPILE void OBJECTHANDLE_EnumMemoryRegions(OBJECTHANDLE handle); From be063b8814d795d0b989a2fcf24338bbb5d6099b Mon Sep 17 00:00:00 2001 From: EgorBo Date: Sun, 18 Sep 2022 13:01:31 +0200 Subject: [PATCH 17/39] Check if it reproduces because of jit --- src/coreclr/vm/methodtable.cpp | 2 +- src/coreclr/vm/vars.hpp | 10 ---------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index 9f0bafdc979af4..2de2ac2407abb8 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -4238,7 +4238,7 @@ OBJECTREF MethodTable::GetManagedClassObject() _ASSERTE((((SSIZE_T)obj) & 1) == 0); refClass = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(obj); refClass->SetType(TypeHandle(this)); - GetWriteableDataForWrite()->m_hExposedClassObject = (LOADERHANDLE)obj; + GetWriteableDataForWrite()->m_hExposedClassObject = (RUNTIMETYPEHANDLE)obj; } else { diff --git a/src/coreclr/vm/vars.hpp b/src/coreclr/vm/vars.hpp index d4e3a0de77ae8a..ccccb411fc2ef7 100644 --- a/src/coreclr/vm/vars.hpp +++ b/src/coreclr/vm/vars.hpp @@ -89,19 +89,9 @@ class Crst; class RCWCleanupList; #endif // FEATURE_COMINTEROP -// -// loader handles are opaque types that track object pointers that have a lifetime -// that matches that of a loader allocator -// -struct LOADERHANDLE__ -{ - void* unused; -}; typedef TADDR LOADERHANDLE; - typedef TADDR RUNTIMETYPEHANDLE; - #ifdef DACCESS_COMPILE void OBJECTHANDLE_EnumMemoryRegions(OBJECTHANDLE handle); void OBJECTREF_EnumMemoryRegions(OBJECTREF ref); From 59af88b7489a088dd652fd212ceeb38ad778936b Mon Sep 17 00:00:00 2001 From: EgorBo Date: Sun, 18 Sep 2022 13:01:58 +0200 Subject: [PATCH 18/39] Check if it reproduces because of jit --- src/coreclr/vm/jitinterface.cpp | 40 ++++++++++++++++----------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index a0bb1f7ca7ef90..99574c15024838 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -5996,26 +5996,26 @@ void* CEEInfo::getRuntimeTypePointer(CORINFO_CLASS_HANDLE clsHnd) JIT_TO_EE_TRANSITION(); - GCX_COOP(); - - TypeHandle typeHnd(clsHnd); - if (!typeHnd.IsNull() && !typeHnd.IsTypeDesc()) - { - MethodTable* pMT = typeHnd.AsMethodTable(); - if (!typeHnd.IsCanonicalSubtype()) - { - // Trigger allocation if it's not allocated yet - if (pMT->GetManagedClassObject() != NULL) - { - // Check if we can rely on object being effectively pinned - OBJECTREF objRef = pMT->GetPinnedManagedClassObjectIfExists(); - if (objRef != NULL) - { - pointer = (void*)OBJECTREFToObject(objRef); - } - } - } - } + //GCX_COOP(); + + //TypeHandle typeHnd(clsHnd); + //if (!typeHnd.IsNull() && !typeHnd.IsTypeDesc()) + //{ + // MethodTable* pMT = typeHnd.AsMethodTable(); + // if (!typeHnd.IsCanonicalSubtype()) + // { + // // Trigger allocation if it's not allocated yet + // if (pMT->GetManagedClassObject() != NULL) + // { + // // Check if we can rely on object being effectively pinned + // OBJECTREF objRef = pMT->GetPinnedManagedClassObjectIfExists(); + // if (objRef != NULL) + // { + // pointer = (void*)OBJECTREFToObject(objRef); + // } + // } + // } + //} EE_TO_JIT_TRANSITION(); return pointer; From a8e0786b4fca097a5b61d752d542c31ff38dda5d Mon Sep 17 00:00:00 2001 From: EgorBo Date: Sun, 18 Sep 2022 17:25:16 +0200 Subject: [PATCH 19/39] Ah, facepalm --- src/coreclr/vm/methodtable.cpp | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index 2de2ac2407abb8..0b534ac2eef84d 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -4228,17 +4228,20 @@ OBJECTREF MethodTable::GetManagedClassObject() { CrstHolder exposedClassLock(AppDomain::GetMethodTableExposedClassObjectLock()); - // Allocate RuntimeType on a frozen segment - // Take a lock here since we don't want to allocate redundant objects which won't be collected - - FrozenObjectHeapManager* foh = SystemDomain::GetFrozenObjectHeapManager(); - size_t objSize = g_pRuntimeTypeClass->GetBaseSize(); - Object* obj = foh->TryAllocateObject(g_pRuntimeTypeClass, objSize); - _ASSERTE(obj != NULL); - _ASSERTE((((SSIZE_T)obj) & 1) == 0); - refClass = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(obj); - refClass->SetType(TypeHandle(this)); - GetWriteableDataForWrite()->m_hExposedClassObject = (RUNTIMETYPEHANDLE)obj; + if (GetWriteableData()->m_hExposedClassObject == NULL) + { + // Allocate RuntimeType on a frozen segment + // Take a lock here since we don't want to allocate redundant objects which won't be collected + + FrozenObjectHeapManager* foh = SystemDomain::GetFrozenObjectHeapManager(); + size_t objSize = g_pRuntimeTypeClass->GetBaseSize(); + Object* obj = foh->TryAllocateObject(g_pRuntimeTypeClass, objSize); + _ASSERTE(obj != NULL); + _ASSERTE((((SSIZE_T)obj) & 1) == 0); + refClass = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(obj); + refClass->SetType(TypeHandle(this)); + GetWriteableDataForWrite()->m_hExposedClassObject = (RUNTIMETYPEHANDLE)obj; + } } else { From 1f9a348a7559d895815c264db0d9659abdedcf4e Mon Sep 17 00:00:00 2001 From: EgorBo Date: Sun, 18 Sep 2022 18:34:58 +0200 Subject: [PATCH 20/39] Clean up --- src/coreclr/jit/compiler.h | 3 +-- src/coreclr/jit/importer.cpp | 7 ------ src/coreclr/jit/morph.cpp | 2 +- src/coreclr/vm/jitinterface.cpp | 40 ++++++++++++++++----------------- src/coreclr/vm/methodtable.inl | 21 +++++++---------- 5 files changed, 30 insertions(+), 43 deletions(-) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 5c053215323f52..06bd5f31493425 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -3522,7 +3522,6 @@ class Compiler CORINFO_CLASS_HANDLE impGetRuntimeArgumentHandle(); CORINFO_CLASS_HANDLE impGetTypeHandleClass(); CORINFO_CLASS_HANDLE impGetStringClass(); - CORINFO_CLASS_HANDLE impGetRuntimeTypeClass(); CORINFO_CLASS_HANDLE impGetObjectClass(); // Returns underlying type of handles returned by ldtoken instruction @@ -6815,7 +6814,7 @@ class Compiler #define OMF_HAS_EXPRUNTIMELOOKUP 0x00000080 // Method contains a runtime lookup to an expandable dictionary. #define OMF_HAS_PATCHPOINT 0x00000100 // Method contains patchpoints #define OMF_NEEDS_GCPOLLS 0x00000200 // Method needs GC polls -#define OMF_HAS_FROZEN_OBJECTS 0x00000400 // Method has a frozen string (REF constant int) +#define OMF_HAS_FROZEN_OBJECTS 0x00000400 // Method has frozen objects (REF constant int) #define OMF_HAS_PARTIAL_COMPILATION_PATCHPOINT 0x00000800 // Method contains partial compilation patchpoints #define OMF_HAS_TAILCALL_SUCCESSOR 0x00001000 // Method has potential tail call in a non BBJ_RETURN block #define OMF_HAS_MDNEWARRAY 0x00002000 // Method contains 'new' of an MD array diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index dc9f94f04b6299..dfe57757da875a 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -3028,13 +3028,6 @@ CORINFO_CLASS_HANDLE Compiler::impGetStringClass() return stringClass; } -CORINFO_CLASS_HANDLE Compiler::impGetRuntimeTypeClass() -{ - CORINFO_CLASS_HANDLE stringClass = info.compCompHnd->getBuiltinClass(CLASSID_RUNTIME_TYPE); - assert(stringClass != (CORINFO_CLASS_HANDLE) nullptr); - return stringClass; -} - CORINFO_CLASS_HANDLE Compiler::impGetObjectClass() { CORINFO_CLASS_HANDLE objectClass = info.compCompHnd->getBuiltinClass(CLASSID_SYSTEM_OBJECT); diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index ff5d8d24fc7ca2..22fa136eb3b8a1 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -8318,7 +8318,7 @@ GenTree* Compiler::fgMorphCall(GenTreeCall* call) { GenTree* argNode = call->AsCall()->gtArgs.GetArgByIndex(0)->GetNode(); CORINFO_CLASS_HANDLE hClass = gtGetHelperArgClassHandle(argNode); - if (!opts.IsReadyToRun() && (hClass != NO_CLASS_HANDLE) && !gtIsActiveCSE_Candidate(argNode)) + if ((hClass != NO_CLASS_HANDLE) && !gtIsActiveCSE_Candidate(argNode)) { void* ptr = info.compCompHnd->getRuntimeTypePointer(hClass); if (ptr != nullptr) diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 99574c15024838..2d2f23d3ed45a3 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -5996,26 +5996,26 @@ void* CEEInfo::getRuntimeTypePointer(CORINFO_CLASS_HANDLE clsHnd) JIT_TO_EE_TRANSITION(); - //GCX_COOP(); - - //TypeHandle typeHnd(clsHnd); - //if (!typeHnd.IsNull() && !typeHnd.IsTypeDesc()) - //{ - // MethodTable* pMT = typeHnd.AsMethodTable(); - // if (!typeHnd.IsCanonicalSubtype()) - // { - // // Trigger allocation if it's not allocated yet - // if (pMT->GetManagedClassObject() != NULL) - // { - // // Check if we can rely on object being effectively pinned - // OBJECTREF objRef = pMT->GetPinnedManagedClassObjectIfExists(); - // if (objRef != NULL) - // { - // pointer = (void*)OBJECTREFToObject(objRef); - // } - // } - // } - //} + GCX_COOP(); + + TypeHandle typeHnd(clsHnd); + if (!typeHnd.IsNull() && !typeHnd.IsTypeDesc()) + { + MethodTable* pMT = typeHnd.AsMethodTable(); + if (!typeHnd.IsCanonicalSubtype()) + { + // Trigger allocation if it's not allocated yet + if (pMT->GetManagedClassObject() != NULL) + { + // Check if we can rely on object being effectively pinned + OBJECTREF objRef = pMT->GetPinnedManagedClassObjectIfExists(); + if (objRef != NULL) + { + pointer = (void*)OBJECTREFToObject(objRef); + } + } + } + } EE_TO_JIT_TRANSITION(); return pointer; diff --git a/src/coreclr/vm/methodtable.inl b/src/coreclr/vm/methodtable.inl index 6fa44cb81209cd..a84d7b875dd694 100644 --- a/src/coreclr/vm/methodtable.inl +++ b/src/coreclr/vm/methodtable.inl @@ -1342,22 +1342,17 @@ FORCEINLINE OBJECTREF MethodTable::GetPinnedManagedClassObjectIfExists() const RUNTIMETYPEHANDLE handle = GetWriteableData_NoLogging()->GetExposedClassObjectHandle(); // For a non-unloadable context, handle is expected to be either null (is not cached yet) // or be a direct pointer to a frozen RuntimeType object - if (handle != NULL && (handle & 1) == 0) - { - Object* obj = (Object*)handle; - _ASSERT(obj != nullptr); - _ASSERT(GCHeapUtilities::GetGCHeap()->IsInFrozenSegment(obj)); - _ASSERT(!this->GetLoaderAllocator()->CanUnload()); - INDEBUG(obj->Validate()); - return ObjectToOBJECTREF(obj); - } - -#ifdef _DEBUG - if (handle != NULL && (handle & 1) != 0) + if (handle != NULL) { + if ((handle & 1) == 0) + { + Object* obj = reinterpret_cast(handle); + _ASSERT(obj != nullptr); + _ASSERT(!this->GetLoaderAllocator()->CanUnload()); + return ObjectToOBJECTREF(obj); + } _ASSERT(this->GetLoaderAllocator()->CanUnload()); } -#endif return NULL; } From 2fd4384a86fb749785e6dd4f2a2d859ece0f4aa2 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Sun, 18 Sep 2022 21:28:16 +0200 Subject: [PATCH 21/39] Address Jan's feedback --- src/coreclr/vm/methodtable.cpp | 79 +++++++++++++++++++--------------- src/coreclr/vm/methodtable.h | 1 + src/coreclr/vm/typedesc.cpp | 46 +++----------------- 3 files changed, 51 insertions(+), 75 deletions(-) diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index 0b534ac2eef84d..31ef2871babc71 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -4220,48 +4220,57 @@ OBJECTREF MethodTable::GetManagedClassObject() { // Make sure that we have been restored CheckRestore(); + AllocateRuntimeTypeObject(GetLoaderAllocator(), (RUNTIMETYPEHANDLE*)&GetWriteableData()->m_hExposedClassObject, TypeHandle(this)); + } + RETURN(GetManagedClassObjectIfExists()); +} + +//====================================================================================== +// Allocates a RuntimeType object with the given TypeHandle. If the LoaderAllocator +// represents a not-unloadable context, it allocates the object on a frozen segment +// so the direct reference will be stored to the pDest argument. In case of unloadable +// context, an index to the pinned table will be saved. +//====================================================================================== +void MethodTable::AllocateRuntimeTypeObject(LoaderAllocator* allocator, RUNTIMETYPEHANDLE* pDest, TypeHandle type) +{ + REFLECTCLASSBASEREF refClass = NULL; - REFLECTCLASSBASEREF refClass = NULL; + if (!allocator->CanUnload()) + { + CrstHolder exposedClassLock(AppDomain::GetMethodTableExposedClassObjectLock()); - LoaderAllocator* pLoaderAllocator = GetLoaderAllocator(); - if (!pLoaderAllocator->CanUnload()) + if (*pDest == NULL) { - CrstHolder exposedClassLock(AppDomain::GetMethodTableExposedClassObjectLock()); + // Allocate RuntimeType on a frozen segment + // Take a lock here since we don't want to allocate redundant objects which won't be collected - if (GetWriteableData()->m_hExposedClassObject == NULL) - { - // Allocate RuntimeType on a frozen segment - // Take a lock here since we don't want to allocate redundant objects which won't be collected - - FrozenObjectHeapManager* foh = SystemDomain::GetFrozenObjectHeapManager(); - size_t objSize = g_pRuntimeTypeClass->GetBaseSize(); - Object* obj = foh->TryAllocateObject(g_pRuntimeTypeClass, objSize); - _ASSERTE(obj != NULL); - _ASSERTE((((SSIZE_T)obj) & 1) == 0); - refClass = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(obj); - refClass->SetType(TypeHandle(this)); - GetWriteableDataForWrite()->m_hExposedClassObject = (RUNTIMETYPEHANDLE)obj; - } + FrozenObjectHeapManager* foh = SystemDomain::GetFrozenObjectHeapManager(); + Object* obj = foh->TryAllocateObject(g_pRuntimeTypeClass, g_pRuntimeTypeClass->GetBaseSize()); + _ASSERTE(obj != NULL); + _ASSERTE((((SSIZE_T)obj) & 1) == 0); + refClass = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(obj); + refClass->SetType(type); + *pDest = (RUNTIMETYPEHANDLE)obj; } - else + } + else + { + GCPROTECT_BEGIN(refClass); + refClass = (REFLECTCLASSBASEREF)AllocateObject(g_pRuntimeTypeClass); + refClass->SetKeepAlive(allocator->GetExposedObject()); + LOADERHANDLE exposedClassObjectHandle = allocator->AllocateHandle(refClass); + // Set the lowest bit, we use it GetPinnedManagedClassObjectIfExists as a fast detection of the unloadable context + exposedClassObjectHandle |= 1; + refClass->SetType(type); + + // Let all threads fight over who wins using InterlockedCompareExchange. + // Only the winner can set m_ExposedClassObject from NULL. + if (InterlockedCompareExchangeT(pDest, exposedClassObjectHandle, static_cast(NULL))) { - GCPROTECT_BEGIN(refClass); - refClass = (REFLECTCLASSBASEREF)AllocateObject(g_pRuntimeTypeClass); - refClass->SetKeepAlive(pLoaderAllocator->GetExposedObject()); - LOADERHANDLE exposedClassObjectHandle = pLoaderAllocator->AllocateHandle(refClass); - // Set the lowest bit, we use it GetPinnedManagedClassObjectIfExists as a fast detection of the unloadable context - exposedClassObjectHandle |= 1; - refClass->SetType(TypeHandle(this)); - - // Let all threads fight over who wins using InterlockedCompareExchange. - // Only the winner can set m_ExposedClassObject from NULL. - if (InterlockedCompareExchangeT(&GetWriteableDataForWrite()->m_hExposedClassObject, exposedClassObjectHandle, static_cast(NULL))) - { - // GC will collect unused instance - pLoaderAllocator->FreeHandle(exposedClassObjectHandle); - } - GCPROTECT_END(); + // GC will collect unused instance + allocator->FreeHandle(exposedClassObjectHandle); } + GCPROTECT_END(); } RETURN(GetManagedClassObjectIfExists()); } diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index c2a4bffe340357..dac2f650e15f1d 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -2716,6 +2716,7 @@ class MethodTable OBJECTREF GetManagedClassObject(); OBJECTREF GetManagedClassObjectIfExists(); OBJECTREF GetPinnedManagedClassObjectIfExists(); + static void AllocateRuntimeTypeObject(LoaderAllocator* allocator, RUNTIMETYPEHANDLE* pDest, TypeHandle type); // ------------------------------------------------------------------ diff --git a/src/coreclr/vm/typedesc.cpp b/src/coreclr/vm/typedesc.cpp index f613addf1418cc..c9787425e87a32 100644 --- a/src/coreclr/vm/typedesc.cpp +++ b/src/coreclr/vm/typedesc.cpp @@ -492,26 +492,9 @@ OBJECTREF ParamTypeDesc::GetManagedClassObject() } CONTRACTL_END; - if (m_hExposedClassObject == NULL) { - REFLECTCLASSBASEREF refClass = NULL; - GCPROTECT_BEGIN(refClass); - refClass = (REFLECTCLASSBASEREF) AllocateObject(g_pRuntimeTypeClass); - - LoaderAllocator *pLoaderAllocator = GetLoaderAllocator(); - TypeHandle th = TypeHandle(this); - ((ReflectClassBaseObject*)OBJECTREFToObject(refClass))->SetType(th); - ((ReflectClassBaseObject*)OBJECTREFToObject(refClass))->SetKeepAlive(pLoaderAllocator->GetExposedObject()); - - // Let all threads fight over who wins using InterlockedCompareExchange. - // Only the winner can set m_hExposedClassObject from NULL. - LOADERHANDLE hExposedClassObject = pLoaderAllocator->AllocateHandle(refClass); - - if (InterlockedCompareExchangeT(&m_hExposedClassObject, hExposedClassObject, static_cast(NULL))) - { - pLoaderAllocator->FreeHandle(hExposedClassObject); - } - - GCPROTECT_END(); + if (m_hExposedClassObject == NULL) + { + MethodTable::AllocateRuntimeTypeObject(GetLoaderAllocator(), &m_hExposedClassObject, TypeHandle(this)); } return GetManagedClassObjectIfExists(); } @@ -1610,26 +1593,9 @@ OBJECTREF TypeVarTypeDesc::GetManagedClassObject() } CONTRACTL_END; - if (m_hExposedClassObject == NULL) { - REFLECTCLASSBASEREF refClass = NULL; - GCPROTECT_BEGIN(refClass); - refClass = (REFLECTCLASSBASEREF) AllocateObject(g_pRuntimeTypeClass); - - LoaderAllocator *pLoaderAllocator = GetLoaderAllocator(); - TypeHandle th = TypeHandle(this); - ((ReflectClassBaseObject*)OBJECTREFToObject(refClass))->SetType(th); - ((ReflectClassBaseObject*)OBJECTREFToObject(refClass))->SetKeepAlive(pLoaderAllocator->GetExposedObject()); - - // Let all threads fight over who wins using InterlockedCompareExchange. - // Only the winner can set m_hExposedClassObject from NULL. - LOADERHANDLE hExposedClassObject = pLoaderAllocator->AllocateHandle(refClass); - - if (InterlockedCompareExchangeT(&m_hExposedClassObject, hExposedClassObject, static_cast(NULL))) - { - pLoaderAllocator->FreeHandle(hExposedClassObject); - } - - GCPROTECT_END(); + if (m_hExposedClassObject == NULL) + { + MethodTable::AllocateRuntimeTypeObject(GetLoaderAllocator(), &m_hExposedClassObject, TypeHandle(this)); } return GetManagedClassObjectIfExists(); } From 8f2a7677a0799014896b70f28450833ecb0fc354 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Sun, 18 Sep 2022 21:33:12 +0200 Subject: [PATCH 22/39] Oops, a typo --- src/coreclr/vm/methodtable.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index 31ef2871babc71..5c2c242a5dfa96 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -4272,7 +4272,6 @@ void MethodTable::AllocateRuntimeTypeObject(LoaderAllocator* allocator, RUNTIMET } GCPROTECT_END(); } - RETURN(GetManagedClassObjectIfExists()); } #endif //!DACCESS_COMPILE From b4b7128b8585da8e4d89ea69c6763dedcc6e45d3 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Sun, 18 Sep 2022 23:01:57 +0200 Subject: [PATCH 23/39] Share logic to extract OBJECTREF from m_hExposedClassObject --- src/coreclr/vm/methodtable.cpp | 38 ++++++++++++++++++++++++++++++++++ src/coreclr/vm/methodtable.h | 9 +++++--- src/coreclr/vm/methodtable.inl | 36 ++------------------------------ src/coreclr/vm/typedesc.h | 38 +++++++++++++++------------------- 4 files changed, 63 insertions(+), 58 deletions(-) diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index 5c2c242a5dfa96..e0e5d944d44633 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -4274,6 +4274,44 @@ void MethodTable::AllocateRuntimeTypeObject(LoaderAllocator* allocator, RUNTIMET } } +OBJECTREF MethodTable::GetRuntimeTypeObjectFromHandleFast(RUNTIMETYPEHANDLE handle) +{ + LIMITED_METHOD_CONTRACT; + + // For a non-unloadable context, handle is expected to be either null (is not cached yet) + // or be a direct pointer to a frozen RuntimeType object + if (handle != NULL) + { + if ((handle & 1) == 0) + { + Object* obj = reinterpret_cast(handle); + _ASSERT(obj != nullptr); + return ObjectToOBJECTREF(obj); + } + } + return NULL; +} + +OBJECTREF MethodTable::GetRuntimeTypeObjectFromHandle(LoaderAllocator* allocator, RUNTIMETYPEHANDLE handle) +{ + LIMITED_METHOD_CONTRACT; + + // First, check if we have a cached reference to an effectively pinned (allocated on FOH) object + OBJECTREF retVal = GetRuntimeTypeObjectFromHandleFast(handle); + if (retVal != NULL) + { + return retVal; + } + + if (!allocator->GetHandleValueFastPhase2(handle, &retVal)) + { + return NULL; + } + + COMPILER_ASSUME(retVal != NULL); + return retVal; +} + #endif //!DACCESS_COMPILE //========================================================================================== diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index dac2f650e15f1d..8b27ddf1181ead 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -299,8 +299,8 @@ struct MethodTableWriteableData }; DWORD m_dwFlags; // Lot of empty bits here. - // Either a direct RuntimeType instance reference or a slot index in LoaderAllocator's table - // a RuntimeType instance for this class. + // Non-unloadable context: internal RuntimeType object handle + // Unloadable context: slot index in LoaderAllocator's pinned table RUNTIMETYPEHANDLE m_hExposedClassObject; #ifdef _DEBUG @@ -2716,8 +2716,11 @@ class MethodTable OBJECTREF GetManagedClassObject(); OBJECTREF GetManagedClassObjectIfExists(); OBJECTREF GetPinnedManagedClassObjectIfExists(); - static void AllocateRuntimeTypeObject(LoaderAllocator* allocator, RUNTIMETYPEHANDLE* pDest, TypeHandle type); + // Shared static helpers to allocate/cache RuntimeType objects + static void AllocateRuntimeTypeObject(LoaderAllocator* allocator, RUNTIMETYPEHANDLE* pDest, TypeHandle type); + static OBJECTREF GetRuntimeTypeObjectFromHandleFast(RUNTIMETYPEHANDLE handle); + static OBJECTREF GetRuntimeTypeObjectFromHandle(LoaderAllocator* allocator, RUNTIMETYPEHANDLE handle); // ------------------------------------------------------------------ // Private part of MethodTable diff --git a/src/coreclr/vm/methodtable.inl b/src/coreclr/vm/methodtable.inl index a84d7b875dd694..d0114bfa25918f 100644 --- a/src/coreclr/vm/methodtable.inl +++ b/src/coreclr/vm/methodtable.inl @@ -1338,46 +1338,14 @@ inline OBJECTHANDLE MethodTable::GetLoaderAllocatorObjectHandle() FORCEINLINE OBJECTREF MethodTable::GetPinnedManagedClassObjectIfExists() { LIMITED_METHOD_CONTRACT; - - const RUNTIMETYPEHANDLE handle = GetWriteableData_NoLogging()->GetExposedClassObjectHandle(); - // For a non-unloadable context, handle is expected to be either null (is not cached yet) - // or be a direct pointer to a frozen RuntimeType object - if (handle != NULL) - { - if ((handle & 1) == 0) - { - Object* obj = reinterpret_cast(handle); - _ASSERT(obj != nullptr); - _ASSERT(!this->GetLoaderAllocator()->CanUnload()); - return ObjectToOBJECTREF(obj); - } - _ASSERT(this->GetLoaderAllocator()->CanUnload()); - } - return NULL; + return GetRuntimeTypeObjectFromHandleFast(GetWriteableData_NoLogging()->GetExposedClassObjectHandle()); } //========================================================================================== FORCEINLINE OBJECTREF MethodTable::GetManagedClassObjectIfExists() { LIMITED_METHOD_CONTRACT; - - // Logging will be done by the slow path - LOADERHANDLE handle = GetWriteableData_NoLogging()->GetExposedClassObjectHandle(); - - // First, check if have a cached reference to an effectively pinned (allocated on FOH) object - OBJECTREF retVal = GetPinnedManagedClassObjectIfExists(); - if (retVal != NULL) - { - return retVal; - } - - if (!GetLoaderAllocator()->GetHandleValueFastPhase2(handle, &retVal)) - { - return NULL; - } - - COMPILER_ASSUME(retVal != NULL); - return retVal; + return GetRuntimeTypeObjectFromHandle(GetLoaderAllocator(), GetWriteableData_NoLogging()->GetExposedClassObjectHandle()); } //========================================================================================== diff --git a/src/coreclr/vm/typedesc.h b/src/coreclr/vm/typedesc.h index 19833eede708bb..e6333fcc6b4b14 100644 --- a/src/coreclr/vm/typedesc.h +++ b/src/coreclr/vm/typedesc.h @@ -251,18 +251,13 @@ class ParamTypeDesc : public TypeDesc { MODE_COOPERATIVE; } CONTRACTL_END; - - OBJECTREF objRet = NULL; - GET_LOADERHANDLE_VALUE_FAST(GetLoaderAllocator(), m_hExposedClassObject, &objRet); - return objRet; + return MethodTable::GetRuntimeTypeObjectFromHandle(GetLoaderAllocator(), m_hExposedClassObject); } + OBJECTREF GetManagedClassObjectFast() { LIMITED_METHOD_CONTRACT; - - OBJECTREF objRet = NULL; - LoaderAllocator::GetHandleValueFast(m_hExposedClassObject, &objRet); - return objRet; + return MethodTable::GetRuntimeTypeObjectFromHandleFast(m_hExposedClassObject); } TypeHandle GetModifiedType() @@ -286,8 +281,13 @@ class ParamTypeDesc : public TypeDesc { protected: // the m_typeAndFlags field in TypeDesc tell what kind of parameterized type we have - TypeHandle m_Arg; // The type that is being modified - LOADERHANDLE m_hExposedClassObject; // handle back to the internal reflection Type object + + // The type that is being modified + TypeHandle m_Arg; + + // Non-unloadable context: internal RuntimeType object handle + // Unloadable context: slot index in LoaderAllocator's pinned table + RUNTIMETYPEHANDLE m_hExposedClassObject; }; /*************************************************************************/ @@ -368,18 +368,13 @@ class TypeVarTypeDesc : public TypeDesc MODE_COOPERATIVE; } CONTRACTL_END; - - OBJECTREF objRet = NULL; - GET_LOADERHANDLE_VALUE_FAST(GetLoaderAllocator(), m_hExposedClassObject, &objRet); - return objRet; + return MethodTable::GetRuntimeTypeObjectFromHandle(GetLoaderAllocator(), m_hExposedClassObject); } + OBJECTREF GetManagedClassObjectFast() { LIMITED_METHOD_CONTRACT; - - OBJECTREF objRet = NULL; - LoaderAllocator::GetHandleValueFast(m_hExposedClassObject, &objRet); - return objRet; + return MethodTable::GetRuntimeTypeObjectFromHandleFast(m_hExposedClassObject); } // Load the owning type. Note that the result is not guaranteed to be full loaded @@ -425,9 +420,10 @@ class TypeVarTypeDesc : public TypeDesc // Constraints, determined on first call to GetConstraints Volatile m_numConstraints; // -1 until number has been determined PTR_TypeHandle m_constraints; - - // slot index back to the internal reflection Type object - LOADERHANDLE m_hExposedClassObject; + + // Non-unloadable context: internal RuntimeType object handle + // Unloadable context: slot index in LoaderAllocator's pinned table + RUNTIMETYPEHANDLE m_hExposedClassObject; // token for GenericParam entry mdGenericParam m_token; From fd099a2eb766b92f5f3bf5a9cddc3a2bc6e3fbb5 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Mon, 19 Sep 2022 15:51:50 +0200 Subject: [PATCH 24/39] Produce better asm code for JIT_GetRuntimeType --- src/coreclr/vm/methodtable.cpp | 16 ++++++---------- src/coreclr/vm/methodtable.inl | 21 ++++++++++++++++++++- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index e0e5d944d44633..7792c5f656fd3e 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -4280,14 +4280,10 @@ OBJECTREF MethodTable::GetRuntimeTypeObjectFromHandleFast(RUNTIMETYPEHANDLE hand // For a non-unloadable context, handle is expected to be either null (is not cached yet) // or be a direct pointer to a frozen RuntimeType object - if (handle != NULL) + + if (handle != NULL && (handle & 1) == 0) { - if ((handle & 1) == 0) - { - Object* obj = reinterpret_cast(handle); - _ASSERT(obj != nullptr); - return ObjectToOBJECTREF(obj); - } + return (OBJECTREF)handle; } return NULL; } @@ -4297,12 +4293,12 @@ OBJECTREF MethodTable::GetRuntimeTypeObjectFromHandle(LoaderAllocator* allocator LIMITED_METHOD_CONTRACT; // First, check if we have a cached reference to an effectively pinned (allocated on FOH) object - OBJECTREF retVal = GetRuntimeTypeObjectFromHandleFast(handle); - if (retVal != NULL) + if (handle != NULL && (handle & 1) == 0) { - return retVal; + return (OBJECTREF)handle; } + OBJECTREF retVal; if (!allocator->GetHandleValueFastPhase2(handle, &retVal)) { return NULL; diff --git a/src/coreclr/vm/methodtable.inl b/src/coreclr/vm/methodtable.inl index d0114bfa25918f..3a2a05dae8458d 100644 --- a/src/coreclr/vm/methodtable.inl +++ b/src/coreclr/vm/methodtable.inl @@ -1345,7 +1345,26 @@ FORCEINLINE OBJECTREF MethodTable::GetPinnedManagedClassObjectIfExists() FORCEINLINE OBJECTREF MethodTable::GetManagedClassObjectIfExists() { LIMITED_METHOD_CONTRACT; - return GetRuntimeTypeObjectFromHandle(GetLoaderAllocator(), GetWriteableData_NoLogging()->GetExposedClassObjectHandle()); + + // GetRuntimeTypeObjectFromHandle was inlined here to produce better code in MSVC + // since this method is hot. + + const RUNTIMETYPEHANDLE handle = GetWriteableData_NoLogging()->m_hExposedClassObject; + + // First, check if we have a cached reference to an effectively pinned (allocated on FOH) object + if (handle != NULL && (handle & 1) == 0) + { + return (OBJECTREF)handle; + } + + OBJECTREF retVal; + if (!GetLoaderAllocator()->GetHandleValueFastPhase2(handle, &retVal)) + { + return NULL; + } + + COMPILER_ASSUME(retVal != NULL); + return retVal; } //========================================================================================== From 7ab7bd19be12eb3bed2818cc04cf30117972906f Mon Sep 17 00:00:00 2001 From: EgorBo Date: Wed, 21 Sep 2022 00:29:30 +0200 Subject: [PATCH 25/39] Address feedback --- .../tools/Common/JitInterface/CorInfoImpl.cs | 4 +- src/coreclr/vm/jitinterface.cpp | 27 ++---- src/coreclr/vm/methodtable.cpp | 86 +----------------- src/coreclr/vm/methodtable.h | 6 -- src/coreclr/vm/methodtable.inl | 9 +- src/coreclr/vm/typedesc.cpp | 4 +- src/coreclr/vm/typedesc.h | 12 ++- src/coreclr/vm/typehandle.cpp | 88 +++++++++++++++++++ src/coreclr/vm/typehandle.h | 12 +++ src/coreclr/vm/typehandle.inl | 2 + 10 files changed, 126 insertions(+), 124 deletions(-) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 9cf66febbf97d3..0806dca6e26561 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -1834,13 +1834,15 @@ private int getStringLiteral(CORINFO_MODULE_STRUCT_* module, uint metaTOK, char* private int objectToString(void* handle, char* buffer, int size) #pragma warning restore CA1822 // Mark members as static { - Debug.Assert(size >= 0); + Debug.Assert(size > 0 && handle != null && buffer != null); // NOTE: this function is used for pinned/frozen handles ReadOnlySpan str = HandleToObject((IntPtr)handle).ToString(); int maxLength = Math.Min(size, str.Length); str.CopyTo(new Span(buffer, maxLength)); + // Null-terminate it (trim if needed) + buffer[maxLength == size ? maxLength - 1 : maxLength] = '\0'; return maxLength; } diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 474c1a4e2b7b81..a3e9a6f51000ec 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -728,6 +728,8 @@ int CEEInfo::objectToString ( int result = -1; + _ASSERT(handle != nullptr && buffer != nullptr && bufferSize > 0); + JIT_TO_EE_TRANSITION(); Object* obj = (Object*)handle; @@ -750,6 +752,8 @@ int CEEInfo::objectToString ( { result = min(bufferSize, (int)stackStr.GetCount()); memcpy((BYTE*)buffer, stackStr.GetUnicode(), result * 2); + // Null-terminate it (trim if needed) + buffer[result == bufferSize ? result - 1 : result] = 0; } EE_TO_JIT_TRANSITION(); @@ -5996,26 +6000,13 @@ void* CEEInfo::getRuntimeTypePointer(CORINFO_CLASS_HANDLE clsHnd) JIT_TO_EE_TRANSITION(); - GCX_COOP(); - TypeHandle typeHnd(clsHnd); - if (!typeHnd.IsNull() && !typeHnd.IsTypeDesc()) - { - MethodTable* pMT = typeHnd.AsMethodTable(); - if (!typeHnd.IsCanonicalSubtype()) - { - // Trigger allocation if it's not allocated yet - if (pMT->GetManagedClassObject() != NULL) - { - // Check if we can rely on object being effectively pinned - OBJECTREF objRef = pMT->GetPinnedManagedClassObjectIfExists(); - if (objRef != NULL) - { - pointer = (void*)OBJECTREFToObject(objRef); - } - } - } + if (!typeHnd.IsCanonicalSubtype() && typeHnd.IsManagedClassObjectPinned()) + { + GCX_COOP(); + pointer = OBJECTREFToObject(typeHnd.GetManagedClassObject()); } + EE_TO_JIT_TRANSITION(); return pointer; diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index 7792c5f656fd3e..fb41c3d956baef 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -58,7 +58,6 @@ #include "array.h" #include "castcache.h" #include "dynamicinterfacecastable.h" -#include "frozenobjectheap.h" #ifdef FEATURE_INTERPRETER #include "interpreter.h" @@ -4220,94 +4219,11 @@ OBJECTREF MethodTable::GetManagedClassObject() { // Make sure that we have been restored CheckRestore(); - AllocateRuntimeTypeObject(GetLoaderAllocator(), (RUNTIMETYPEHANDLE*)&GetWriteableData()->m_hExposedClassObject, TypeHandle(this)); + TypeHandle::AllocateManagedClassObject(GetLoaderAllocator(), (RUNTIMETYPEHANDLE*)&GetWriteableData()->m_hExposedClassObject, TypeHandle(this)); } RETURN(GetManagedClassObjectIfExists()); } -//====================================================================================== -// Allocates a RuntimeType object with the given TypeHandle. If the LoaderAllocator -// represents a not-unloadable context, it allocates the object on a frozen segment -// so the direct reference will be stored to the pDest argument. In case of unloadable -// context, an index to the pinned table will be saved. -//====================================================================================== -void MethodTable::AllocateRuntimeTypeObject(LoaderAllocator* allocator, RUNTIMETYPEHANDLE* pDest, TypeHandle type) -{ - REFLECTCLASSBASEREF refClass = NULL; - - if (!allocator->CanUnload()) - { - CrstHolder exposedClassLock(AppDomain::GetMethodTableExposedClassObjectLock()); - - if (*pDest == NULL) - { - // Allocate RuntimeType on a frozen segment - // Take a lock here since we don't want to allocate redundant objects which won't be collected - - FrozenObjectHeapManager* foh = SystemDomain::GetFrozenObjectHeapManager(); - Object* obj = foh->TryAllocateObject(g_pRuntimeTypeClass, g_pRuntimeTypeClass->GetBaseSize()); - _ASSERTE(obj != NULL); - _ASSERTE((((SSIZE_T)obj) & 1) == 0); - refClass = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(obj); - refClass->SetType(type); - *pDest = (RUNTIMETYPEHANDLE)obj; - } - } - else - { - GCPROTECT_BEGIN(refClass); - refClass = (REFLECTCLASSBASEREF)AllocateObject(g_pRuntimeTypeClass); - refClass->SetKeepAlive(allocator->GetExposedObject()); - LOADERHANDLE exposedClassObjectHandle = allocator->AllocateHandle(refClass); - // Set the lowest bit, we use it GetPinnedManagedClassObjectIfExists as a fast detection of the unloadable context - exposedClassObjectHandle |= 1; - refClass->SetType(type); - - // Let all threads fight over who wins using InterlockedCompareExchange. - // Only the winner can set m_ExposedClassObject from NULL. - if (InterlockedCompareExchangeT(pDest, exposedClassObjectHandle, static_cast(NULL))) - { - // GC will collect unused instance - allocator->FreeHandle(exposedClassObjectHandle); - } - GCPROTECT_END(); - } -} - -OBJECTREF MethodTable::GetRuntimeTypeObjectFromHandleFast(RUNTIMETYPEHANDLE handle) -{ - LIMITED_METHOD_CONTRACT; - - // For a non-unloadable context, handle is expected to be either null (is not cached yet) - // or be a direct pointer to a frozen RuntimeType object - - if (handle != NULL && (handle & 1) == 0) - { - return (OBJECTREF)handle; - } - return NULL; -} - -OBJECTREF MethodTable::GetRuntimeTypeObjectFromHandle(LoaderAllocator* allocator, RUNTIMETYPEHANDLE handle) -{ - LIMITED_METHOD_CONTRACT; - - // First, check if we have a cached reference to an effectively pinned (allocated on FOH) object - if (handle != NULL && (handle & 1) == 0) - { - return (OBJECTREF)handle; - } - - OBJECTREF retVal; - if (!allocator->GetHandleValueFastPhase2(handle, &retVal)) - { - return NULL; - } - - COMPILER_ASSUME(retVal != NULL); - return retVal; -} - #endif //!DACCESS_COMPILE //========================================================================================== diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index 8b27ddf1181ead..d278196cb6474b 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -2715,12 +2715,6 @@ class MethodTable // GetManagedClassObjectIfExists() will return null if the Type object doesn't exist. OBJECTREF GetManagedClassObject(); OBJECTREF GetManagedClassObjectIfExists(); - OBJECTREF GetPinnedManagedClassObjectIfExists(); - - // Shared static helpers to allocate/cache RuntimeType objects - static void AllocateRuntimeTypeObject(LoaderAllocator* allocator, RUNTIMETYPEHANDLE* pDest, TypeHandle type); - static OBJECTREF GetRuntimeTypeObjectFromHandleFast(RUNTIMETYPEHANDLE handle); - static OBJECTREF GetRuntimeTypeObjectFromHandle(LoaderAllocator* allocator, RUNTIMETYPEHANDLE handle); // ------------------------------------------------------------------ // Private part of MethodTable diff --git a/src/coreclr/vm/methodtable.inl b/src/coreclr/vm/methodtable.inl index 3a2a05dae8458d..35575a1b80d182 100644 --- a/src/coreclr/vm/methodtable.inl +++ b/src/coreclr/vm/methodtable.inl @@ -1334,19 +1334,12 @@ inline OBJECTHANDLE MethodTable::GetLoaderAllocatorObjectHandle() return GetLoaderAllocator()->GetLoaderAllocatorObjectHandle(); } -//========================================================================================== -FORCEINLINE OBJECTREF MethodTable::GetPinnedManagedClassObjectIfExists() -{ - LIMITED_METHOD_CONTRACT; - return GetRuntimeTypeObjectFromHandleFast(GetWriteableData_NoLogging()->GetExposedClassObjectHandle()); -} - //========================================================================================== FORCEINLINE OBJECTREF MethodTable::GetManagedClassObjectIfExists() { LIMITED_METHOD_CONTRACT; - // GetRuntimeTypeObjectFromHandle was inlined here to produce better code in MSVC + // GetManagedClassObjectFromHandle was inlined here to produce better code in MSVC // since this method is hot. const RUNTIMETYPEHANDLE handle = GetWriteableData_NoLogging()->m_hExposedClassObject; diff --git a/src/coreclr/vm/typedesc.cpp b/src/coreclr/vm/typedesc.cpp index c9787425e87a32..ededd519877982 100644 --- a/src/coreclr/vm/typedesc.cpp +++ b/src/coreclr/vm/typedesc.cpp @@ -494,7 +494,7 @@ OBJECTREF ParamTypeDesc::GetManagedClassObject() if (m_hExposedClassObject == NULL) { - MethodTable::AllocateRuntimeTypeObject(GetLoaderAllocator(), &m_hExposedClassObject, TypeHandle(this)); + TypeHandle::AllocateManagedClassObject(GetLoaderAllocator(), &m_hExposedClassObject, TypeHandle(this)); } return GetManagedClassObjectIfExists(); } @@ -1595,7 +1595,7 @@ OBJECTREF TypeVarTypeDesc::GetManagedClassObject() if (m_hExposedClassObject == NULL) { - MethodTable::AllocateRuntimeTypeObject(GetLoaderAllocator(), &m_hExposedClassObject, TypeHandle(this)); + TypeHandle::AllocateManagedClassObject(GetLoaderAllocator(), &m_hExposedClassObject, TypeHandle(this)); } return GetManagedClassObjectIfExists(); } diff --git a/src/coreclr/vm/typedesc.h b/src/coreclr/vm/typedesc.h index e6333fcc6b4b14..fd8ceac9ebe778 100644 --- a/src/coreclr/vm/typedesc.h +++ b/src/coreclr/vm/typedesc.h @@ -240,6 +240,7 @@ class ParamTypeDesc : public TypeDesc { INDEBUGIMPL(BOOL Verify();) +#ifndef DACCESS_COMPILE OBJECTREF GetManagedClassObject(); OBJECTREF GetManagedClassObjectIfExists() @@ -251,14 +252,15 @@ class ParamTypeDesc : public TypeDesc { MODE_COOPERATIVE; } CONTRACTL_END; - return MethodTable::GetRuntimeTypeObjectFromHandle(GetLoaderAllocator(), m_hExposedClassObject); + return TypeHandle::GetManagedClassObjectFromHandle(GetLoaderAllocator(), m_hExposedClassObject); } OBJECTREF GetManagedClassObjectFast() { LIMITED_METHOD_CONTRACT; - return MethodTable::GetRuntimeTypeObjectFromHandleFast(m_hExposedClassObject); + return TypeHandle::GetManagedClassObjectFromHandleFast(m_hExposedClassObject); } +#endif TypeHandle GetModifiedType() { @@ -358,6 +360,7 @@ class TypeVarTypeDesc : public TypeDesc return m_typeOrMethodDef; } +#ifndef DACCESS_COMPILE OBJECTREF GetManagedClassObject(); OBJECTREF GetManagedClassObjectIfExists() { @@ -368,14 +371,15 @@ class TypeVarTypeDesc : public TypeDesc MODE_COOPERATIVE; } CONTRACTL_END; - return MethodTable::GetRuntimeTypeObjectFromHandle(GetLoaderAllocator(), m_hExposedClassObject); + return TypeHandle::GetManagedClassObjectFromHandle(GetLoaderAllocator(), m_hExposedClassObject); } OBJECTREF GetManagedClassObjectFast() { LIMITED_METHOD_CONTRACT; - return MethodTable::GetRuntimeTypeObjectFromHandleFast(m_hExposedClassObject); + return TypeHandle::GetManagedClassObjectFromHandleFast(m_hExposedClassObject); } +#endif // Load the owning type. Note that the result is not guaranteed to be full loaded MethodDesc * LoadOwnerMethod(); diff --git a/src/coreclr/vm/typehandle.cpp b/src/coreclr/vm/typehandle.cpp index 115aae31543610..4b636f83748e9a 100644 --- a/src/coreclr/vm/typehandle.cpp +++ b/src/coreclr/vm/typehandle.cpp @@ -15,6 +15,7 @@ #include "classloadlevel.h" #include "array.h" #include "castcache.h" +#include "frozenobjectheap.h" #ifdef _DEBUG_IMPL @@ -343,6 +344,93 @@ BOOL TypeHandle::IsCanonicalSubtype() const return (*this == TypeHandle(g_pCanonMethodTableClass)) || IsSharedByGenericInstantiations(); } +#ifndef DACCESS_COMPILE +bool TypeHandle::IsManagedClassObjectPinned() const +{ + LIMITED_METHOD_DAC_CONTRACT; + + // Function pointers are always mapped to typeof(IntPtr) + return !GetLoaderAllocator()->CanUnload() || IsFnPtrType(); +} + +void TypeHandle::AllocateManagedClassObject(LoaderAllocator* allocator, RUNTIMETYPEHANDLE* pDest, TypeHandle type) +{ + REFLECTCLASSBASEREF refClass = NULL; + + if (!allocator->CanUnload()) + { + CrstHolder exposedClassLock(AppDomain::GetMethodTableExposedClassObjectLock()); + + if (*pDest == NULL) + { + // Allocate RuntimeType on a frozen segment + // Take a lock here since we don't want to allocate redundant objects which won't be collected + + FrozenObjectHeapManager* foh = SystemDomain::GetFrozenObjectHeapManager(); + Object* obj = foh->TryAllocateObject(g_pRuntimeTypeClass, g_pRuntimeTypeClass->GetBaseSize()); + _ASSERTE(obj != NULL); + _ASSERTE((((SSIZE_T)obj) & 1) == 0); + refClass = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(obj); + refClass->SetType(type); + *pDest = (RUNTIMETYPEHANDLE)obj; + } + } + else + { + GCPROTECT_BEGIN(refClass); + refClass = (REFLECTCLASSBASEREF)AllocateObject(g_pRuntimeTypeClass); + refClass->SetKeepAlive(allocator->GetExposedObject()); + LOADERHANDLE exposedClassObjectHandle = allocator->AllocateHandle(refClass); + // Set the lowest bit, we use it GetPinnedManagedClassObjectIfExists as a fast detection of the unloadable context + exposedClassObjectHandle |= 1; + refClass->SetType(type); + + // Let all threads fight over who wins using InterlockedCompareExchange. + // Only the winner can set m_ExposedClassObject from NULL. + if (InterlockedCompareExchangeT(pDest, exposedClassObjectHandle, static_cast(NULL))) + { + // GC will collect unused instance + allocator->FreeHandle(exposedClassObjectHandle); + } + GCPROTECT_END(); + } +} + +OBJECTREF TypeHandle::GetManagedClassObjectFromHandleFast(RUNTIMETYPEHANDLE handle) +{ + LIMITED_METHOD_CONTRACT; + + // For a non-unloadable context, handle is expected to be either null (is not cached yet) + // or be a direct pointer to a frozen RuntimeType object + + if (handle != NULL && (handle & 1) == 0) + { + return (OBJECTREF)handle; + } + return NULL; +} + +OBJECTREF TypeHandle::GetManagedClassObjectFromHandle(LoaderAllocator* allocator, RUNTIMETYPEHANDLE handle) +{ + LIMITED_METHOD_CONTRACT; + + // First, check if we have a cached reference to an effectively pinned (allocated on FOH) object + if (handle != NULL && (handle & 1) == 0) + { + return (OBJECTREF)handle; + } + + OBJECTREF retVal; + if (!allocator->GetHandleValueFastPhase2(handle, &retVal)) + { + return NULL; + } + + COMPILER_ASSUME(retVal != NULL); + return retVal; +} +#endif + /* static */ BOOL TypeHandle::IsCanonicalSubtypeInstantiation(Instantiation inst) { LIMITED_METHOD_DAC_CONTRACT; diff --git a/src/coreclr/vm/typehandle.h b/src/coreclr/vm/typehandle.h index decfa20df4274b..69d35197ac51d3 100644 --- a/src/coreclr/vm/typehandle.h +++ b/src/coreclr/vm/typehandle.h @@ -323,6 +323,18 @@ class TypeHandle // BOOL IsCanonicalSubtype() const; +#ifndef DACCESS_COMPILE + bool IsManagedClassObjectPinned() const; + + // Allocates a RuntimeType object with the given TypeHandle. If the LoaderAllocator + // represents a not-unloadable context, it allocates the object on a frozen segment + // so the direct reference will be stored to the pDest argument. In case of unloadable + // context, an index to the pinned table will be saved. + static void AllocateManagedClassObject(LoaderAllocator* allocator, RUNTIMETYPEHANDLE* pDest, TypeHandle type); + static OBJECTREF GetManagedClassObjectFromHandleFast(RUNTIMETYPEHANDLE handle); + static OBJECTREF GetManagedClassObjectFromHandle(LoaderAllocator* allocator, RUNTIMETYPEHANDLE handle); +#endif + // Similar to IsCanonicalSubtype, but applied to a vector. static BOOL IsCanonicalSubtypeInstantiation(Instantiation inst); diff --git a/src/coreclr/vm/typehandle.inl b/src/coreclr/vm/typehandle.inl index ffe668a901f76c..bd98e25ab0e231 100644 --- a/src/coreclr/vm/typehandle.inl +++ b/src/coreclr/vm/typehandle.inl @@ -232,6 +232,7 @@ inline void TypeHandle::ForEachComponentMethodTable(T &callback) const } } +#ifndef DACCESS_COMPILE FORCEINLINE OBJECTREF TypeHandle::GetManagedClassObjectFast() const { CONTRACTL @@ -276,5 +277,6 @@ FORCEINLINE OBJECTREF TypeHandle::GetManagedClassObjectFast() const return o; } +#endif #endif // _TYPEHANDLE_INL_ From 895e9f5d72eaed28baa45c6e0b68d03bff1c5c50 Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Wed, 21 Sep 2022 01:37:00 +0200 Subject: [PATCH 26/39] Update src/coreclr/vm/jitinterface.cpp Co-authored-by: Jan Kotas --- src/coreclr/vm/jitinterface.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index a3e9a6f51000ec..87f6dbe0a23331 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -5994,7 +5994,11 @@ CorInfoHelpFunc CEEInfo::getUnBoxHelper(CORINFO_CLASS_HANDLE clsHnd) /***********************************************************************/ void* CEEInfo::getRuntimeTypePointer(CORINFO_CLASS_HANDLE clsHnd) { - LIMITED_METHOD_CONTRACT; + CONTRACTL{ + THROWS; + GC_TRIGGERS; + MODE_PREEMPTIVE; + } CONTRACTL_END; void* pointer = nullptr; From bcd47b1d39e923ed2695f9f6cd3be73e13b78928 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Wed, 21 Sep 2022 01:53:28 +0200 Subject: [PATCH 27/39] Address feedback --- src/coreclr/vm/methodtable.cpp | 2 +- src/coreclr/vm/methodtable.inl | 5 +++-- src/coreclr/vm/typedesc.cpp | 5 ++--- src/coreclr/vm/typehandle.cpp | 32 +++++++++++++++++++------------- src/coreclr/vm/typehandle.h | 2 +- 5 files changed, 26 insertions(+), 20 deletions(-) diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index fb41c3d956baef..c50b31137288ff 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -4219,7 +4219,7 @@ OBJECTREF MethodTable::GetManagedClassObject() { // Make sure that we have been restored CheckRestore(); - TypeHandle::AllocateManagedClassObject(GetLoaderAllocator(), (RUNTIMETYPEHANDLE*)&GetWriteableData()->m_hExposedClassObject, TypeHandle(this)); + TypeHandle(this).AllocateManagedClassObject((RUNTIMETYPEHANDLE*)&GetWriteableData()->m_hExposedClassObject); } RETURN(GetManagedClassObjectIfExists()); } diff --git a/src/coreclr/vm/methodtable.inl b/src/coreclr/vm/methodtable.inl index 35575a1b80d182..fe50797268ef56 100644 --- a/src/coreclr/vm/methodtable.inl +++ b/src/coreclr/vm/methodtable.inl @@ -1345,9 +1345,10 @@ FORCEINLINE OBJECTREF MethodTable::GetManagedClassObjectIfExists() const RUNTIMETYPEHANDLE handle = GetWriteableData_NoLogging()->m_hExposedClassObject; // First, check if we have a cached reference to an effectively pinned (allocated on FOH) object - if (handle != NULL && (handle & 1) == 0) + if (handle & 1) { - return (OBJECTREF)handle; + // Clear the "is pinned object" bit from the managed reference + return (OBJECTREF)((handle >> 1) << 1); // C++ compiler is expected to emit "and reg, mask" } OBJECTREF retVal; diff --git a/src/coreclr/vm/typedesc.cpp b/src/coreclr/vm/typedesc.cpp index ededd519877982..1812a0d4bd893a 100644 --- a/src/coreclr/vm/typedesc.cpp +++ b/src/coreclr/vm/typedesc.cpp @@ -494,7 +494,7 @@ OBJECTREF ParamTypeDesc::GetManagedClassObject() if (m_hExposedClassObject == NULL) { - TypeHandle::AllocateManagedClassObject(GetLoaderAllocator(), &m_hExposedClassObject, TypeHandle(this)); + TypeHandle(this).AllocateManagedClassObject(&m_hExposedClassObject); } return GetManagedClassObjectIfExists(); } @@ -1579,7 +1579,6 @@ BOOL TypeVarTypeDesc::SatisfiesConstraints(SigTypeContext *pTypeContextOfConstra return TRUE; } - OBJECTREF TypeVarTypeDesc::GetManagedClassObject() { CONTRACTL { @@ -1595,7 +1594,7 @@ OBJECTREF TypeVarTypeDesc::GetManagedClassObject() if (m_hExposedClassObject == NULL) { - TypeHandle::AllocateManagedClassObject(GetLoaderAllocator(), &m_hExposedClassObject, TypeHandle(this)); + TypeHandle(this).AllocateManagedClassObject(&m_hExposedClassObject); } return GetManagedClassObjectIfExists(); } diff --git a/src/coreclr/vm/typehandle.cpp b/src/coreclr/vm/typehandle.cpp index 4b636f83748e9a..5d13b94fa28e99 100644 --- a/src/coreclr/vm/typehandle.cpp +++ b/src/coreclr/vm/typehandle.cpp @@ -353,26 +353,31 @@ bool TypeHandle::IsManagedClassObjectPinned() const return !GetLoaderAllocator()->CanUnload() || IsFnPtrType(); } -void TypeHandle::AllocateManagedClassObject(LoaderAllocator* allocator, RUNTIMETYPEHANDLE* pDest, TypeHandle type) +void TypeHandle::AllocateManagedClassObject(RUNTIMETYPEHANDLE* pDest) { REFLECTCLASSBASEREF refClass = NULL; + PTR_LoaderAllocator allocator = GetLoaderAllocator(); + if (!allocator->CanUnload()) { + // Allocate RuntimeType on a frozen segment + // Take a lock here since we don't want to allocate redundant objects which won't be collected CrstHolder exposedClassLock(AppDomain::GetMethodTableExposedClassObjectLock()); if (*pDest == NULL) { - // Allocate RuntimeType on a frozen segment - // Take a lock here since we don't want to allocate redundant objects which won't be collected - FrozenObjectHeapManager* foh = SystemDomain::GetFrozenObjectHeapManager(); Object* obj = foh->TryAllocateObject(g_pRuntimeTypeClass, g_pRuntimeTypeClass->GetBaseSize()); _ASSERTE(obj != NULL); + // Since objects are aligned we can use the lowest bit as a storage for "is pinned object" flag _ASSERTE((((SSIZE_T)obj) & 1) == 0); refClass = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(obj); - refClass->SetType(type); - *pDest = (RUNTIMETYPEHANDLE)obj; + refClass->SetType(*this); + RUNTIMETYPEHANDLE handle = (RUNTIMETYPEHANDLE)obj; + // Set the bit to 1 (we'll have to reset it before use) + handle |= 1; + *pDest = handle; } } else @@ -381,9 +386,8 @@ void TypeHandle::AllocateManagedClassObject(LoaderAllocator* allocator, RUNTIMET refClass = (REFLECTCLASSBASEREF)AllocateObject(g_pRuntimeTypeClass); refClass->SetKeepAlive(allocator->GetExposedObject()); LOADERHANDLE exposedClassObjectHandle = allocator->AllocateHandle(refClass); - // Set the lowest bit, we use it GetPinnedManagedClassObjectIfExists as a fast detection of the unloadable context - exposedClassObjectHandle |= 1; - refClass->SetType(type); + _ASSERTE((exposedClassObjectHandle & 1) == 0); + refClass->SetType(*this); // Let all threads fight over who wins using InterlockedCompareExchange. // Only the winner can set m_ExposedClassObject from NULL. @@ -403,9 +407,10 @@ OBJECTREF TypeHandle::GetManagedClassObjectFromHandleFast(RUNTIMETYPEHANDLE hand // For a non-unloadable context, handle is expected to be either null (is not cached yet) // or be a direct pointer to a frozen RuntimeType object - if (handle != NULL && (handle & 1) == 0) + if (handle & 1) { - return (OBJECTREF)handle; + // Clear the "is pinned object" bit from the managed reference + return (OBJECTREF)((handle >> 1) << 1); // C++ compiler is expected to emit "and reg, mask" } return NULL; } @@ -415,9 +420,10 @@ OBJECTREF TypeHandle::GetManagedClassObjectFromHandle(LoaderAllocator* allocator LIMITED_METHOD_CONTRACT; // First, check if we have a cached reference to an effectively pinned (allocated on FOH) object - if (handle != NULL && (handle & 1) == 0) + if (handle & 1) { - return (OBJECTREF)handle; + // Clear the "is pinned object" bit from the managed reference + return (OBJECTREF)((handle >> 1) << 1); // C++ compiler is expected to emit "and reg, mask" } OBJECTREF retVal; diff --git a/src/coreclr/vm/typehandle.h b/src/coreclr/vm/typehandle.h index 69d35197ac51d3..9e4b6fea0a2937 100644 --- a/src/coreclr/vm/typehandle.h +++ b/src/coreclr/vm/typehandle.h @@ -330,7 +330,7 @@ class TypeHandle // represents a not-unloadable context, it allocates the object on a frozen segment // so the direct reference will be stored to the pDest argument. In case of unloadable // context, an index to the pinned table will be saved. - static void AllocateManagedClassObject(LoaderAllocator* allocator, RUNTIMETYPEHANDLE* pDest, TypeHandle type); + void AllocateManagedClassObject(RUNTIMETYPEHANDLE* pDest); static OBJECTREF GetManagedClassObjectFromHandleFast(RUNTIMETYPEHANDLE handle); static OBJECTREF GetManagedClassObjectFromHandle(LoaderAllocator* allocator, RUNTIMETYPEHANDLE handle); #endif From c217579c9b069238213d536795efc2d15454b55f Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Wed, 21 Sep 2022 02:04:25 +0200 Subject: [PATCH 28/39] Update src/coreclr/vm/methodtable.cpp Co-authored-by: Jan Kotas --- src/coreclr/vm/methodtable.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index c50b31137288ff..6872f57c32ff2f 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -4219,7 +4219,7 @@ OBJECTREF MethodTable::GetManagedClassObject() { // Make sure that we have been restored CheckRestore(); - TypeHandle(this).AllocateManagedClassObject((RUNTIMETYPEHANDLE*)&GetWriteableData()->m_hExposedClassObject); + TypeHandle(this).AllocateManagedClassObject(&GetWriteableData()->m_hExposedClassObject); } RETURN(GetManagedClassObjectIfExists()); } From 253747e0394a3cba6a7408574382debfa9d52993 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Wed, 21 Sep 2022 02:14:14 +0200 Subject: [PATCH 29/39] Address feedback: the bit is always there so we can do ` - 1` --- src/coreclr/vm/methodtable.inl | 2 +- src/coreclr/vm/typehandle.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/coreclr/vm/methodtable.inl b/src/coreclr/vm/methodtable.inl index fe50797268ef56..066a49005b240d 100644 --- a/src/coreclr/vm/methodtable.inl +++ b/src/coreclr/vm/methodtable.inl @@ -1348,7 +1348,7 @@ FORCEINLINE OBJECTREF MethodTable::GetManagedClassObjectIfExists() if (handle & 1) { // Clear the "is pinned object" bit from the managed reference - return (OBJECTREF)((handle >> 1) << 1); // C++ compiler is expected to emit "and reg, mask" + return (OBJECTREF)(handle - 1); } OBJECTREF retVal; diff --git a/src/coreclr/vm/typehandle.cpp b/src/coreclr/vm/typehandle.cpp index 5d13b94fa28e99..cb49c9d14d9f10 100644 --- a/src/coreclr/vm/typehandle.cpp +++ b/src/coreclr/vm/typehandle.cpp @@ -410,7 +410,7 @@ OBJECTREF TypeHandle::GetManagedClassObjectFromHandleFast(RUNTIMETYPEHANDLE hand if (handle & 1) { // Clear the "is pinned object" bit from the managed reference - return (OBJECTREF)((handle >> 1) << 1); // C++ compiler is expected to emit "and reg, mask" + return (OBJECTREF)(handle - 1); } return NULL; } @@ -423,7 +423,7 @@ OBJECTREF TypeHandle::GetManagedClassObjectFromHandle(LoaderAllocator* allocator if (handle & 1) { // Clear the "is pinned object" bit from the managed reference - return (OBJECTREF)((handle >> 1) << 1); // C++ compiler is expected to emit "and reg, mask" + return (OBJECTREF)(handle - 1); } OBJECTREF retVal; From ca6c69adae933395e9862d0fa254db7ba74e70e9 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Wed, 21 Sep 2022 02:59:33 +0200 Subject: [PATCH 30/39] Address feedback --- src/coreclr/vm/methodtable.cpp | 2 +- src/coreclr/vm/methodtable.inl | 15 ++++-------- src/coreclr/vm/typedesc.h | 44 ++++++++++++++++++++++++++++++---- src/coreclr/vm/typehandle.cpp | 36 ---------------------------- src/coreclr/vm/typehandle.h | 18 ++++++++++++-- 5 files changed, 61 insertions(+), 54 deletions(-) diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index 6872f57c32ff2f..c50b31137288ff 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -4219,7 +4219,7 @@ OBJECTREF MethodTable::GetManagedClassObject() { // Make sure that we have been restored CheckRestore(); - TypeHandle(this).AllocateManagedClassObject(&GetWriteableData()->m_hExposedClassObject); + TypeHandle(this).AllocateManagedClassObject((RUNTIMETYPEHANDLE*)&GetWriteableData()->m_hExposedClassObject); } RETURN(GetManagedClassObjectIfExists()); } diff --git a/src/coreclr/vm/methodtable.inl b/src/coreclr/vm/methodtable.inl index 066a49005b240d..d7b7d263ff96e8 100644 --- a/src/coreclr/vm/methodtable.inl +++ b/src/coreclr/vm/methodtable.inl @@ -1334,25 +1334,17 @@ inline OBJECTHANDLE MethodTable::GetLoaderAllocatorObjectHandle() return GetLoaderAllocator()->GetLoaderAllocatorObjectHandle(); } +#ifndef DACCESS_COMPILE //========================================================================================== FORCEINLINE OBJECTREF MethodTable::GetManagedClassObjectIfExists() { LIMITED_METHOD_CONTRACT; - // GetManagedClassObjectFromHandle was inlined here to produce better code in MSVC - // since this method is hot. - const RUNTIMETYPEHANDLE handle = GetWriteableData_NoLogging()->m_hExposedClassObject; - // First, check if we have a cached reference to an effectively pinned (allocated on FOH) object - if (handle & 1) - { - // Clear the "is pinned object" bit from the managed reference - return (OBJECTREF)(handle - 1); - } - OBJECTREF retVal; - if (!GetLoaderAllocator()->GetHandleValueFastPhase2(handle, &retVal)) + if (!TypeHandle::GetManagedClassObjectFromHandleFast(handle, &retVal) && + !GetLoaderAllocator()->GetHandleValueFastPhase2(handle, &retVal)) { return NULL; } @@ -1360,6 +1352,7 @@ FORCEINLINE OBJECTREF MethodTable::GetManagedClassObjectIfExists() COMPILER_ASSUME(retVal != NULL); return retVal; } +#endif //========================================================================================== inline void MethodTable::SetIsArray(CorElementType arrayType) diff --git a/src/coreclr/vm/typedesc.h b/src/coreclr/vm/typedesc.h index fd8ceac9ebe778..c4a0a83043e593 100644 --- a/src/coreclr/vm/typedesc.h +++ b/src/coreclr/vm/typedesc.h @@ -252,13 +252,31 @@ class ParamTypeDesc : public TypeDesc { MODE_COOPERATIVE; } CONTRACTL_END; - return TypeHandle::GetManagedClassObjectFromHandle(GetLoaderAllocator(), m_hExposedClassObject); + + const RUNTIMETYPEHANDLE handle = m_hExposedClassObject; + + OBJECTREF retVal; + if (!TypeHandle::GetManagedClassObjectFromHandleFast(handle, &retVal) && + !GetLoaderAllocator()->GetHandleValueFastPhase2(handle, &retVal)) + { + return NULL; + } + + COMPILER_ASSUME(retVal != NULL); + return retVal; } OBJECTREF GetManagedClassObjectFast() { LIMITED_METHOD_CONTRACT; - return TypeHandle::GetManagedClassObjectFromHandleFast(m_hExposedClassObject); + + OBJECTREF objRef; + if (!TypeHandle::GetManagedClassObjectFromHandleFast(m_hExposedClassObject, &objRef)) + { + return FALSE; + } + COMPILER_ASSUME(objRef != NULL); + return objRef; } #endif @@ -371,13 +389,31 @@ class TypeVarTypeDesc : public TypeDesc MODE_COOPERATIVE; } CONTRACTL_END; - return TypeHandle::GetManagedClassObjectFromHandle(GetLoaderAllocator(), m_hExposedClassObject); + + const RUNTIMETYPEHANDLE handle = m_hExposedClassObject; + + OBJECTREF retVal; + if (!TypeHandle::GetManagedClassObjectFromHandleFast(handle, &retVal) && + !GetLoaderAllocator()->GetHandleValueFastPhase2(handle, &retVal)) + { + return NULL; + } + + COMPILER_ASSUME(retVal != NULL); + return retVal; } OBJECTREF GetManagedClassObjectFast() { LIMITED_METHOD_CONTRACT; - return TypeHandle::GetManagedClassObjectFromHandleFast(m_hExposedClassObject); + + OBJECTREF objRef; + if (!TypeHandle::GetManagedClassObjectFromHandleFast(m_hExposedClassObject, &objRef)) + { + return FALSE; + } + COMPILER_ASSUME(objRef != NULL); + return objRef; } #endif diff --git a/src/coreclr/vm/typehandle.cpp b/src/coreclr/vm/typehandle.cpp index cb49c9d14d9f10..88dce11a4fc172 100644 --- a/src/coreclr/vm/typehandle.cpp +++ b/src/coreclr/vm/typehandle.cpp @@ -399,42 +399,6 @@ void TypeHandle::AllocateManagedClassObject(RUNTIMETYPEHANDLE* pDest) GCPROTECT_END(); } } - -OBJECTREF TypeHandle::GetManagedClassObjectFromHandleFast(RUNTIMETYPEHANDLE handle) -{ - LIMITED_METHOD_CONTRACT; - - // For a non-unloadable context, handle is expected to be either null (is not cached yet) - // or be a direct pointer to a frozen RuntimeType object - - if (handle & 1) - { - // Clear the "is pinned object" bit from the managed reference - return (OBJECTREF)(handle - 1); - } - return NULL; -} - -OBJECTREF TypeHandle::GetManagedClassObjectFromHandle(LoaderAllocator* allocator, RUNTIMETYPEHANDLE handle) -{ - LIMITED_METHOD_CONTRACT; - - // First, check if we have a cached reference to an effectively pinned (allocated on FOH) object - if (handle & 1) - { - // Clear the "is pinned object" bit from the managed reference - return (OBJECTREF)(handle - 1); - } - - OBJECTREF retVal; - if (!allocator->GetHandleValueFastPhase2(handle, &retVal)) - { - return NULL; - } - - COMPILER_ASSUME(retVal != NULL); - return retVal; -} #endif /* static */ BOOL TypeHandle::IsCanonicalSubtypeInstantiation(Instantiation inst) diff --git a/src/coreclr/vm/typehandle.h b/src/coreclr/vm/typehandle.h index 9e4b6fea0a2937..037bc10205e17b 100644 --- a/src/coreclr/vm/typehandle.h +++ b/src/coreclr/vm/typehandle.h @@ -331,8 +331,22 @@ class TypeHandle // so the direct reference will be stored to the pDest argument. In case of unloadable // context, an index to the pinned table will be saved. void AllocateManagedClassObject(RUNTIMETYPEHANDLE* pDest); - static OBJECTREF GetManagedClassObjectFromHandleFast(RUNTIMETYPEHANDLE handle); - static OBJECTREF GetManagedClassObjectFromHandle(LoaderAllocator* allocator, RUNTIMETYPEHANDLE handle); + + FORCEINLINE static bool GetManagedClassObjectFromHandleFast(RUNTIMETYPEHANDLE handle, OBJECTREF* pRef) + { + LIMITED_METHOD_CONTRACT; + + // For a non-unloadable context, handle is expected to be either null (is not cached yet) + // or be a direct pointer to a frozen RuntimeType object + + if (handle & 1) + { + // Clear the "is pinned object" bit from the managed reference + *pRef = (OBJECTREF)(handle - 1); + return true; + } + return false; + } #endif // Similar to IsCanonicalSubtype, but applied to a vector. From 93ef5257baf6daa8500eb7789bd8f14178c91a4f Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Tue, 20 Sep 2022 18:30:18 -0700 Subject: [PATCH 31/39] Update src/coreclr/vm/methodtable.cpp --- src/coreclr/vm/methodtable.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index c50b31137288ff..d42d4e3efc1453 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -4219,7 +4219,7 @@ OBJECTREF MethodTable::GetManagedClassObject() { // Make sure that we have been restored CheckRestore(); - TypeHandle(this).AllocateManagedClassObject((RUNTIMETYPEHANDLE*)&GetWriteableData()->m_hExposedClassObject); + TypeHandle(this).AllocateManagedClassObject(&GetWriteableDataForWrite()->m_hExposedClassObject); } RETURN(GetManagedClassObjectIfExists()); } From 7394e1ef617148ce263e5ea9f9bdcc9c39a59246 Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Wed, 21 Sep 2022 14:11:26 +0200 Subject: [PATCH 32/39] Update src/coreclr/jit/ee_il_dll.cpp Co-authored-by: Jakob Botsch Nielsen --- src/coreclr/jit/ee_il_dll.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/ee_il_dll.cpp b/src/coreclr/jit/ee_il_dll.cpp index 343f0f9c99648f..26dd171dc3aa49 100644 --- a/src/coreclr/jit/ee_il_dll.cpp +++ b/src/coreclr/jit/ee_il_dll.cpp @@ -1618,7 +1618,7 @@ const char16_t* Compiler::eeGetShortClassName(CORINFO_CLASS_HANDLE clsHnd) void Compiler::eePrintFrozenObjectDescription(const char* prefix, size_t handle) { const int maxStrSize = 128; - char16_t str[maxStrSize] = {0}; + char16_t str[maxStrSize]; int realLength = this->info.compCompHnd->objectToString((void*)handle, str, maxStrSize); if (realLength >= 0) { From f6055b99d9ff2442f64afdfb8d9da793671e9cc4 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Wed, 21 Sep 2022 15:31:16 +0200 Subject: [PATCH 33/39] remove null-termination from api --- src/coreclr/jit/ee_il_dll.cpp | 25 +++++++++++++++++-- .../tools/Common/JitInterface/CorInfoImpl.cs | 14 +++++------ src/coreclr/vm/jitinterface.cpp | 15 ++++++----- 3 files changed, 37 insertions(+), 17 deletions(-) diff --git a/src/coreclr/jit/ee_il_dll.cpp b/src/coreclr/jit/ee_il_dll.cpp index 26dd171dc3aa49..fdad02bbe7e6a0 100644 --- a/src/coreclr/jit/ee_il_dll.cpp +++ b/src/coreclr/jit/ee_il_dll.cpp @@ -1617,9 +1617,30 @@ const char16_t* Compiler::eeGetShortClassName(CORINFO_CLASS_HANDLE clsHnd) void Compiler::eePrintFrozenObjectDescription(const char* prefix, size_t handle) { - const int maxStrSize = 128; + const int maxStrSize = 64; char16_t str[maxStrSize]; - int realLength = this->info.compCompHnd->objectToString((void*)handle, str, maxStrSize); + int realLength = this->info.compCompHnd->objectToString((void*)handle, str, maxStrSize); + if (realLength >= maxStrSize) + { + str[maxStrSize - 4] = L'.'; + str[maxStrSize - 3] = L'.'; + str[maxStrSize - 2] = L'.'; + str[maxStrSize - 1] = 0; + } + else + { + str[realLength] = 0; + } + + for (size_t i = 0; i < min(maxStrSize, realLength); i++) + { + // Escape \n and \r symbols + if (str[i] == L'\n' || str[i] == L'\r') + { + str[i] = L' '; + } + } + if (realLength >= 0) { printf("%s '%S'\n", prefix, str); diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 0806dca6e26561..a6fc1bb3b8a3de 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -1831,19 +1831,19 @@ private int getStringLiteral(CORINFO_MODULE_STRUCT_* module, uint metaTOK, char* } #pragma warning disable CA1822 // Mark members as static - private int objectToString(void* handle, char* buffer, int size) + private int objectToString(void* handle, char* buffer, int bufferSize) #pragma warning restore CA1822 // Mark members as static { - Debug.Assert(size > 0 && handle != null && buffer != null); + Debug.Assert(bufferSize >= 0 && handle != null); // NOTE: this function is used for pinned/frozen handles ReadOnlySpan str = HandleToObject((IntPtr)handle).ToString(); - int maxLength = Math.Min(size, str.Length); - str.CopyTo(new Span(buffer, maxLength)); - // Null-terminate it (trim if needed) - buffer[maxLength == size ? maxLength - 1 : maxLength] = '\0'; - return maxLength; + if (buffer != null) + { + str.CopyTo(new Span(buffer, Math.Min(bufferSize, str.Length))); + } + return str.Length; } private CorInfoType asCorInfoType(CORINFO_CLASS_STRUCT_* cls) diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 87f6dbe0a23331..609618732603a0 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -726,9 +726,9 @@ int CEEInfo::objectToString ( MODE_PREEMPTIVE; } CONTRACTL_END; - int result = -1; + int charsCount = 0; - _ASSERT(handle != nullptr && buffer != nullptr && bufferSize > 0); + _ASSERT(handle != nullptr && bufferSize >= 0); JIT_TO_EE_TRANSITION(); @@ -748,17 +748,16 @@ int CEEInfo::objectToString ( ((ReflectClassBaseObject*)obj)->GetType().GetName(stackStr); } - if (stackStr.GetCount() > 0) + charsCount = (int)stackStr.GetCount(); + + if (buffer != nullptr) { - result = min(bufferSize, (int)stackStr.GetCount()); - memcpy((BYTE*)buffer, stackStr.GetUnicode(), result * 2); - // Null-terminate it (trim if needed) - buffer[result == bufferSize ? result - 1 : result] = 0; + memcpy((BYTE*)buffer, stackStr.GetUnicode(), min(bufferSize, charsCount) * 2); } EE_TO_JIT_TRANSITION(); - return result; + return charsCount; } /* static */ From 57b1477db6a2210ead2f00b235f7502652b48cfa Mon Sep 17 00:00:00 2001 From: EgorBo Date: Wed, 21 Sep 2022 15:37:45 +0200 Subject: [PATCH 34/39] address feedback --- src/coreclr/jit/ee_il_dll.cpp | 11 +++-------- src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs | 1 + src/coreclr/vm/jitinterface.cpp | 3 +++ 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/coreclr/jit/ee_il_dll.cpp b/src/coreclr/jit/ee_il_dll.cpp index fdad02bbe7e6a0..64ded5ec9830ee 100644 --- a/src/coreclr/jit/ee_il_dll.cpp +++ b/src/coreclr/jit/ee_il_dll.cpp @@ -1622,6 +1622,7 @@ void Compiler::eePrintFrozenObjectDescription(const char* prefix, size_t handle) int realLength = this->info.compCompHnd->objectToString((void*)handle, str, maxStrSize); if (realLength >= maxStrSize) { + // string is too long, trim it and null-terminate str[maxStrSize - 4] = L'.'; str[maxStrSize - 3] = L'.'; str[maxStrSize - 2] = L'.'; @@ -1629,6 +1630,7 @@ void Compiler::eePrintFrozenObjectDescription(const char* prefix, size_t handle) } else { + // objectToString doesn't null-terminate buffer str[realLength] = 0; } @@ -1641,14 +1643,7 @@ void Compiler::eePrintFrozenObjectDescription(const char* prefix, size_t handle) } } - if (realLength >= 0) - { - printf("%s '%S'\n", prefix, str); - } - else - { - printf("%s 'frozen object handle'\n", prefix, str); - } + printf("%s '%S'\n", prefix, str); } #else // DEBUG void jitprintf(const char* fmt, ...) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index a6fc1bb3b8a3de..cde7bf0c6538ce 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -1837,6 +1837,7 @@ private int objectToString(void* handle, char* buffer, int bufferSize) Debug.Assert(bufferSize >= 0 && handle != null); // NOTE: this function is used for pinned/frozen handles + // it doesn't need to null-terminate the string ReadOnlySpan str = HandleToObject((IntPtr)handle).ToString(); if (buffer != null) diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 609618732603a0..ad312b034b1a60 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -728,6 +728,9 @@ int CEEInfo::objectToString ( int charsCount = 0; + // NOTE: this function is used for pinned/frozen handles + // it doesn't need to null-terminate the string + _ASSERT(handle != nullptr && bufferSize >= 0); JIT_TO_EE_TRANSITION(); From e9a396f88b178ab4fc88eb925e0b5e0bb8b8f78b Mon Sep 17 00:00:00 2001 From: EgorBo Date: Wed, 21 Sep 2022 16:21:19 +0200 Subject: [PATCH 35/39] Address feedback --- src/coreclr/jit/ee_il_dll.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/coreclr/jit/ee_il_dll.cpp b/src/coreclr/jit/ee_il_dll.cpp index 64ded5ec9830ee..5fafc5e9392c8f 100644 --- a/src/coreclr/jit/ee_il_dll.cpp +++ b/src/coreclr/jit/ee_il_dll.cpp @@ -1620,7 +1620,12 @@ void Compiler::eePrintFrozenObjectDescription(const char* prefix, size_t handle) const int maxStrSize = 64; char16_t str[maxStrSize]; int realLength = this->info.compCompHnd->objectToString((void*)handle, str, maxStrSize); - if (realLength >= maxStrSize) + if (realLength == -1) + { + printf("%s 'unknown frozen object'", prefix); + return; + } + else if (realLength >= maxStrSize) { // string is too long, trim it and null-terminate str[maxStrSize - 4] = L'.'; @@ -1636,7 +1641,7 @@ void Compiler::eePrintFrozenObjectDescription(const char* prefix, size_t handle) for (size_t i = 0; i < min(maxStrSize, realLength); i++) { - // Escape \n and \r symbols + // Replace \n and \r symbols with whitespaces if (str[i] == L'\n' || str[i] == L'\r') { str[i] = L' '; From 4fbb894ce853a9f943069b60b55beeae521ff25f Mon Sep 17 00:00:00 2001 From: EgorBo Date: Wed, 21 Sep 2022 18:37:37 +0200 Subject: [PATCH 36/39] Pass utf8 string in objectToString --- src/coreclr/inc/corinfo.h | 2 +- src/coreclr/inc/icorjitinfoimpl_generated.h | 2 +- src/coreclr/jit/ICorJitInfo_API_wrapper.hpp | 2 +- src/coreclr/jit/ee_il_dll.cpp | 14 +++++++------- .../tools/Common/JitInterface/CorInfoBase.cs | 4 ++-- .../tools/Common/JitInterface/CorInfoImpl.cs | 15 +++++++-------- .../JitInterface/ThunkGenerator/ThunkInput.txt | 2 +- .../tools/aot/jitinterface/jitinterface.h | 4 ++-- .../superpmi/superpmi-shared/methodcontext.cpp | 8 ++++---- .../superpmi/superpmi-shared/methodcontext.h | 4 ++-- .../superpmi-shim-collector/icorjitinfo.cpp | 6 +++--- .../superpmi-shim-counter/icorjitinfo.cpp | 2 +- .../superpmi-shim-simple/icorjitinfo.cpp | 2 +- .../tools/superpmi/superpmi/icorjitinfo.cpp | 2 +- src/coreclr/vm/jitinterface.cpp | 17 +++++++---------- 15 files changed, 41 insertions(+), 45 deletions(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 87f8c2964ecf38..848e1a53314c83 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -2268,7 +2268,7 @@ class ICorStaticInfo // Calls ToString() for given pinned/frozen object handle virtual int objectToString ( void* handle, /* IN */ - char16_t* buffer, /* OUT */ + char* buffer, /* OUT */ int bufferSize /* IN */ ) = 0; diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h index 8caf56a5237ea9..4e0e1094eb250d 100644 --- a/src/coreclr/inc/icorjitinfoimpl_generated.h +++ b/src/coreclr/inc/icorjitinfoimpl_generated.h @@ -177,7 +177,7 @@ int getStringLiteral( int objectToString( void* handle, - char16_t* buffer, + char* buffer, int bufferSize) override; CorInfoType asCorInfoType( diff --git a/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp b/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp index 0cbdb58c270ab9..4bedcebcf3b0c5 100644 --- a/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp +++ b/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp @@ -376,7 +376,7 @@ int WrapICorJitInfo::getStringLiteral( int WrapICorJitInfo::objectToString( void* handle, - char16_t* buffer, + char* buffer, int bufferSize) { API_ENTER(objectToString); diff --git a/src/coreclr/jit/ee_il_dll.cpp b/src/coreclr/jit/ee_il_dll.cpp index 5fafc5e9392c8f..940fbabe0053af 100644 --- a/src/coreclr/jit/ee_il_dll.cpp +++ b/src/coreclr/jit/ee_il_dll.cpp @@ -1618,7 +1618,7 @@ const char16_t* Compiler::eeGetShortClassName(CORINFO_CLASS_HANDLE clsHnd) void Compiler::eePrintFrozenObjectDescription(const char* prefix, size_t handle) { const int maxStrSize = 64; - char16_t str[maxStrSize]; + char str[maxStrSize]; int realLength = this->info.compCompHnd->objectToString((void*)handle, str, maxStrSize); if (realLength == -1) { @@ -1628,9 +1628,9 @@ void Compiler::eePrintFrozenObjectDescription(const char* prefix, size_t handle) else if (realLength >= maxStrSize) { // string is too long, trim it and null-terminate - str[maxStrSize - 4] = L'.'; - str[maxStrSize - 3] = L'.'; - str[maxStrSize - 2] = L'.'; + str[maxStrSize - 4] = '.'; + str[maxStrSize - 3] = '.'; + str[maxStrSize - 2] = '.'; str[maxStrSize - 1] = 0; } else @@ -1642,13 +1642,13 @@ void Compiler::eePrintFrozenObjectDescription(const char* prefix, size_t handle) for (size_t i = 0; i < min(maxStrSize, realLength); i++) { // Replace \n and \r symbols with whitespaces - if (str[i] == L'\n' || str[i] == L'\r') + if (str[i] == '\n' || str[i] == '\r') { - str[i] = L' '; + str[i] = ' '; } } - printf("%s '%S'\n", prefix, str); + printf("%s '%s'\n", prefix, str); } #else // DEBUG void jitprintf(const char* fmt, ...) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs b/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs index 7b753fb48a20d4..8d8c426a7130d2 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs @@ -554,7 +554,7 @@ private static int _getStringLiteral(IntPtr thisHandle, IntPtr* ppException, COR } [UnmanagedCallersOnly] - private static int _objectToString(IntPtr thisHandle, IntPtr* ppException, void* handle, char* buffer, int bufferSize) + private static int _objectToString(IntPtr thisHandle, IntPtr* ppException, void* handle, byte* buffer, int bufferSize) { var _this = GetThis(thisHandle); try @@ -2664,7 +2664,7 @@ private static IntPtr GetUnmanagedCallbacks() callbacks[34] = (delegate* unmanaged)&_isValidToken; callbacks[35] = (delegate* unmanaged)&_isValidStringRef; callbacks[36] = (delegate* unmanaged)&_getStringLiteral; - callbacks[37] = (delegate* unmanaged)&_objectToString; + callbacks[37] = (delegate* unmanaged)&_objectToString; callbacks[38] = (delegate* unmanaged)&_asCorInfoType; callbacks[39] = (delegate* unmanaged)&_getClassName; callbacks[40] = (delegate* unmanaged)&_getClassNameFromMetadata; diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index cde7bf0c6538ce..cc087e8b31e218 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -9,6 +9,7 @@ using System.Runtime.CompilerServices; using System.Runtime.ExceptionServices; using System.Runtime.InteropServices; +using System.Text.Unicode; #if SUPPORT_JIT using Internal.Runtime.CompilerServices; @@ -1831,20 +1832,18 @@ private int getStringLiteral(CORINFO_MODULE_STRUCT_* module, uint metaTOK, char* } #pragma warning disable CA1822 // Mark members as static - private int objectToString(void* handle, char* buffer, int bufferSize) + private int objectToString(void* handle, byte* buffer, int bufferSize) #pragma warning restore CA1822 // Mark members as static { - Debug.Assert(bufferSize >= 0 && handle != null); + Debug.Assert(bufferSize > 0 && handle != null && buffer != null); // NOTE: this function is used for pinned/frozen handles // it doesn't need to null-terminate the string - ReadOnlySpan str = HandleToObject((IntPtr)handle).ToString(); - if (buffer != null) - { - str.CopyTo(new Span(buffer, Math.Min(bufferSize, str.Length))); - } - return str.Length; + ReadOnlySpan objStr = HandleToObject((IntPtr)handle).ToString(); + var bufferSpan = new Span(buffer, bufferSize); + Utf8.FromUtf16(objStr, bufferSpan, out _, out int written); + return written; } private CorInfoType asCorInfoType(CORINFO_CLASS_STRUCT_* cls) diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt index 216986ef15e224..0294eced60258f 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -192,7 +192,7 @@ FUNCTIONS bool isValidToken(CORINFO_MODULE_HANDLE module, unsigned metaTOK) bool isValidStringRef(CORINFO_MODULE_HANDLE module, unsigned metaTOK) int getStringLiteral(CORINFO_MODULE_HANDLE module, unsigned metaTOK, char16_t* buffer, int bufferSize) - int objectToString(void* handle, char16_t* buffer, int bufferSize) + int objectToString(void* handle, char* buffer, int bufferSize) CorInfoType asCorInfoType(CORINFO_CLASS_HANDLE cls) const char* getClassName(CORINFO_CLASS_HANDLE cls) const char* getClassNameFromMetadata(CORINFO_CLASS_HANDLE cls, const char **namespaceName) diff --git a/src/coreclr/tools/aot/jitinterface/jitinterface.h b/src/coreclr/tools/aot/jitinterface/jitinterface.h index 82056ad4592b8a..f12f60b98cb9c3 100644 --- a/src/coreclr/tools/aot/jitinterface/jitinterface.h +++ b/src/coreclr/tools/aot/jitinterface/jitinterface.h @@ -48,7 +48,7 @@ struct JitInterfaceCallbacks bool (* isValidToken)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_MODULE_HANDLE module, unsigned metaTOK); bool (* isValidStringRef)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_MODULE_HANDLE module, unsigned metaTOK); int (* getStringLiteral)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_MODULE_HANDLE module, unsigned metaTOK, char16_t* buffer, int bufferSize); - int (* objectToString)(void * thisHandle, CorInfoExceptionClass** ppException, void* handle, char16_t* buffer, int bufferSize); + int (* objectToString)(void * thisHandle, CorInfoExceptionClass** ppException, void* handle, char* buffer, int bufferSize); CorInfoType (* asCorInfoType)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls); const char* (* getClassName)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls); const char* (* getClassNameFromMetadata)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls, const char** namespaceName); @@ -567,7 +567,7 @@ class JitInterfaceWrapper : public ICorJitInfo virtual int objectToString( void* handle, - char16_t* buffer, + char* buffer, int bufferSize) { CorInfoExceptionClass* pException = nullptr; diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index 6f7c144d96290b..95c0d7c63c88ba 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -4897,7 +4897,7 @@ int MethodContext::repGetStringLiteral(CORINFO_MODULE_HANDLE module, unsigned me } } -void MethodContext::recObjectToString(void* handle, char16_t* buffer, int bufferSize, int length) +void MethodContext::recObjectToString(void* handle, char* buffer, int bufferSize, int length) { if (ObjectToString == nullptr) ObjectToString = new LightWeightMap(); @@ -4910,7 +4910,7 @@ void MethodContext::recObjectToString(void* handle, char16_t* buffer, int buffer DWORD strBuf = (DWORD)-1; if (buffer != nullptr && length != -1) { - int bufferRealSize = min(length, bufferSize) * sizeof(char16_t); + int bufferRealSize = min(length, bufferSize); strBuf = (DWORD)ObjectToString->AddBuffer((unsigned char*)buffer, (unsigned int)bufferRealSize); } @@ -4926,7 +4926,7 @@ void MethodContext::dmpObjectToString(DLD key, DD value) printf("ObjectToString key hnd-%016llX bufSize-%u, len-%u", key.A, key.B, value.A); ObjectToString->Unlock(); } -int MethodContext::repObjectToString(void* handle, char16_t* buffer, int bufferSize) +int MethodContext::repObjectToString(void* handle, char* buffer, int bufferSize) { if (ObjectToString == nullptr) { @@ -4952,7 +4952,7 @@ int MethodContext::repObjectToString(void* handle, char16_t* buffer, int bufferS { char16_t* srcBuffer = (char16_t*)ObjectToString->GetBuffer(value.B); Assert(srcBuffer != nullptr); - memcpy(buffer, srcBuffer, min(srcBufferLength, bufferSize) * sizeof(char16_t)); + memcpy(buffer, srcBuffer, min(srcBufferLength, bufferSize)); } return srcBufferLength; } diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h index 6b080a45f20ce3..96c19e8664d78a 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h @@ -622,9 +622,9 @@ class MethodContext void dmpGetStringLiteral(DLDD key, DD value); int repGetStringLiteral(CORINFO_MODULE_HANDLE module, unsigned metaTOK, char16_t* buffer, int bufferSize); - void recObjectToString(void* handle, char16_t* buffer, int bufferSize, int length); + void recObjectToString(void* handle, char* buffer, int bufferSize, int length); void dmpObjectToString(DLD key, DD value); - int repObjectToString(void* handle, char16_t* buffer, int bufferSize); + int repObjectToString(void* handle, char* buffer, int bufferSize); void recGetHelperName(CorInfoHelpFunc funcNum, const char* result); void dmpGetHelperName(DWORD key, DWORD value); diff --git a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp index 82eae5a3510611..b19faebf609677 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -453,9 +453,9 @@ int interceptor_ICJI::getStringLiteral(CORINFO_MODULE_HANDLE module, /* IN * return temp; } -int interceptor_ICJI::objectToString(void* handle, /* IN */ - char16_t* buffer, /* OUT */ - int bufferSize /* IN */ +int interceptor_ICJI::objectToString(void* handle, /* IN */ + char* buffer, /* OUT */ + int bufferSize /* IN */ ) { mc->cr->AddCall("objectToString"); diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp index e49b2f81143967..2a12825c899076 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp @@ -316,7 +316,7 @@ int interceptor_ICJI::getStringLiteral( int interceptor_ICJI::objectToString( void* handle, - char16_t* buffer, + char* buffer, int bufferSize) { mcs->AddCall("objectToString"); diff --git a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp index f507034dea16aa..808ccc3ab473dc 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp @@ -279,7 +279,7 @@ int interceptor_ICJI::getStringLiteral( int interceptor_ICJI::objectToString( void* handle, - char16_t* buffer, + char* buffer, int bufferSize) { return original_ICorJitInfo->objectToString(handle, buffer, bufferSize); diff --git a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp index 8421232c2e867a..efdfafffb8d3b4 100644 --- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp @@ -389,7 +389,7 @@ int MyICJI::getStringLiteral(CORINFO_MODULE_HANDLE module, /* IN */ } int MyICJI::objectToString(void* handle, /* IN */ - char16_t* buffer, /* OUT */ + char* buffer, /* OUT */ int bufferSize /* IN */ ) { diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index ad312b034b1a60..2aa473dc6e9d7a 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -716,9 +716,9 @@ int CEEInfo::getStringLiteral ( } int CEEInfo::objectToString ( - void* handle, - char16_t* buffer, - int bufferSize) + void* handle, + char* buffer, + int bufferSize) { CONTRACTL{ THROWS; @@ -731,7 +731,7 @@ int CEEInfo::objectToString ( // NOTE: this function is used for pinned/frozen handles // it doesn't need to null-terminate the string - _ASSERT(handle != nullptr && bufferSize >= 0); + _ASSERT(handle != nullptr && buffer != nullptr && bufferSize > 0); JIT_TO_EE_TRANSITION(); @@ -751,12 +751,9 @@ int CEEInfo::objectToString ( ((ReflectClassBaseObject*)obj)->GetType().GetName(stackStr); } - charsCount = (int)stackStr.GetCount(); - - if (buffer != nullptr) - { - memcpy((BYTE*)buffer, stackStr.GetUnicode(), min(bufferSize, charsCount) * 2); - } + const UTF8* utf8data = stackStr.GetUTF8(); + charsCount = stackStr.GetCount(); + memcpy((BYTE*)buffer, (BYTE*)utf8data, min(bufferSize, charsCount)); EE_TO_JIT_TRANSITION(); From 7476a689389caff47498d15acb8065c4e3332c16 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Wed, 21 Sep 2022 18:39:31 +0200 Subject: [PATCH 37/39] remove char16_t left over --- src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index 95c0d7c63c88ba..5eea6f742ba214 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -4950,7 +4950,7 @@ int MethodContext::repObjectToString(void* handle, char* buffer, int bufferSize) int srcBufferLength = (int)value.A; if (buffer != nullptr && srcBufferLength > 0) { - char16_t* srcBuffer = (char16_t*)ObjectToString->GetBuffer(value.B); + char* srcBuffer = (char*)ObjectToString->GetBuffer(value.B); Assert(srcBuffer != nullptr); memcpy(buffer, srcBuffer, min(srcBufferLength, bufferSize)); } From bc2292bb8a7cf6468432aa379cc84b6f10c89457 Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Thu, 22 Sep 2022 02:37:04 +0200 Subject: [PATCH 38/39] fix compilation warning --- src/coreclr/jit/ee_il_dll.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/ee_il_dll.cpp b/src/coreclr/jit/ee_il_dll.cpp index 940fbabe0053af..71a0dd52630a5d 100644 --- a/src/coreclr/jit/ee_il_dll.cpp +++ b/src/coreclr/jit/ee_il_dll.cpp @@ -1639,7 +1639,7 @@ void Compiler::eePrintFrozenObjectDescription(const char* prefix, size_t handle) str[realLength] = 0; } - for (size_t i = 0; i < min(maxStrSize, realLength); i++) + for (int i = 0; i < min(maxStrSize, realLength); i++) { // Replace \n and \r symbols with whitespaces if (str[i] == '\n' || str[i] == '\r') From 7bf7e0ef8819dfcac8ca6c1fff790b13529eb8d7 Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Thu, 22 Sep 2022 14:09:18 +0200 Subject: [PATCH 39/39] Update gentree.cpp --- src/coreclr/jit/gentree.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index e7e38a0fc827f9..fa11408d6741d8 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -6911,9 +6911,9 @@ GenTree* Compiler::gtNewIndOfIconHandleNode(var_types indType, size_t addr, GenT // This indirection also is invariant. indNode->gtFlags |= GTF_IND_INVARIANT; - if ((iconFlags == GTF_ICON_STR_HDL) || (iconFlags == GTF_ICON_OBJ_HDL)) + if (iconFlags == GTF_ICON_STR_HDL) { - // String literals and frozen type objects are never null + // String literals are never null indNode->gtFlags |= GTF_IND_NONNULL; } }