diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index a34c372d89652..c6135b8ed173a 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -2503,6 +2503,32 @@ class ICorStaticInfo CORINFO_CLASS_HANDLE cls ) = 0; + //------------------------------------------------------------------------------ + // isObjectImmutable: checks whether given object is known to be immutable or not + // + // Arguments: + // objPtr - Direct object handle + // + // Return Value: + // Returns true if object is known to be immutable + // + virtual bool isObjectImmutable( + void* objPtr + ) = 0; + + //------------------------------------------------------------------------------ + // getObjectType: obtains type handle for given object + // + // Arguments: + // objPtr - Direct object handle + // + // Return Value: + // Returns CORINFO_CLASS_HANDLE handle that represents given object's type + // + virtual CORINFO_CLASS_HANDLE getObjectType( + void* objPtr + ) = 0; + virtual bool getReadyToRunHelper( CORINFO_RESOLVED_TOKEN * pResolvedToken, CORINFO_LOOKUP_KIND * pGenericLookupKind, @@ -3167,6 +3193,27 @@ class ICorDynamicInfo : public ICorStaticInfo void **ppIndirection = NULL ) = 0; + //------------------------------------------------------------------------------ + // getReadonlyStaticFieldValue: returns true and the actual field's value if the given + // field represents a statically initialized readonly field of any type, it might be: + // * integer/floating point primitive + // * null + // * frozen object reference (string, array or object) + // + // Arguments: + // field - field handle + // buffer - buffer field's value will be stored to + // bufferSize - size of buffer + // + // Return Value: + // Returns true if field's constant value was available and successfully copied to buffer + // + virtual bool getReadonlyStaticFieldValue( + CORINFO_FIELD_HANDLE field, + uint8_t *buffer, + int bufferSize + ) = 0; + // If pIsSpeculative is NULL, return the class handle for the value of ref-class typed // static readonly fields, if there is a unique location for the static and the class // is already initialized. diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h index 2c132ee74b234..2e421d931df17 100644 --- a/src/coreclr/inc/icorjitinfoimpl_generated.h +++ b/src/coreclr/inc/icorjitinfoimpl_generated.h @@ -289,6 +289,12 @@ CorInfoHelpFunc getUnBoxHelper( void* getRuntimeTypePointer( CORINFO_CLASS_HANDLE cls) override; +bool isObjectImmutable( + void* objPtr) override; + +CORINFO_CLASS_HANDLE getObjectType( + void* objPtr) override; + bool getReadyToRunHelper( CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_LOOKUP_KIND* pGenericLookupKind, @@ -606,6 +612,11 @@ void* getFieldAddress( CORINFO_FIELD_HANDLE field, void** ppIndirection) override; +bool getReadonlyStaticFieldValue( + CORINFO_FIELD_HANDLE field, + uint8_t* buffer, + int bufferSize) override; + CORINFO_CLASS_HANDLE getStaticFieldCurrentClass( CORINFO_FIELD_HANDLE field, bool* pIsSpeculative) override; diff --git a/src/coreclr/inc/jiteeversionguid.h b/src/coreclr/inc/jiteeversionguid.h index 115f0d538a5da..45905ce47d337 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 = { /* 3f5e4630-b29a-4aeb-bab7-07bdff43a156 */ - 0x3f5e4630, - 0xb29a, - 0x4aeb, - {0xba, 0xb7, 0x7, 0xbd, 0xff, 0x43, 0xa1, 0x56} +constexpr GUID JITEEVersionIdentifier = { /* 982ed1fd-7bf3-425b-8b8a-902873151e79 */ + 0x982ed1fd, + 0x7bf3, + 0x425b, + {0x8b, 0x8a, 0x90, 0x28, 0x73, 0x15, 0x1e, 0x79} }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/coreclr/jit/ICorJitInfo_API_names.h b/src/coreclr/jit/ICorJitInfo_API_names.h index c6324f8648638..ed9a2be8c8d72 100644 --- a/src/coreclr/jit/ICorJitInfo_API_names.h +++ b/src/coreclr/jit/ICorJitInfo_API_names.h @@ -72,6 +72,8 @@ DEF_CLR_API(getTypeForBox) DEF_CLR_API(getBoxHelper) DEF_CLR_API(getUnBoxHelper) DEF_CLR_API(getRuntimeTypePointer) +DEF_CLR_API(isObjectImmutable) +DEF_CLR_API(getObjectType) DEF_CLR_API(getReadyToRunHelper) DEF_CLR_API(getReadyToRunDelegateCtorHelper) DEF_CLR_API(getHelperName) @@ -152,6 +154,7 @@ DEF_CLR_API(canAccessFamily) DEF_CLR_API(isRIDClassDomainID) DEF_CLR_API(getClassDomainID) DEF_CLR_API(getFieldAddress) +DEF_CLR_API(getReadonlyStaticFieldValue) DEF_CLR_API(getStaticFieldCurrentClass) DEF_CLR_API(getVarArgsHandle) DEF_CLR_API(canGetVarArgsHandle) diff --git a/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp b/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp index 9f77c6212963e..716a49b628f9f 100644 --- a/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp +++ b/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp @@ -673,6 +673,24 @@ void* WrapICorJitInfo::getRuntimeTypePointer( return temp; } +bool WrapICorJitInfo::isObjectImmutable( + void* objPtr) +{ + API_ENTER(isObjectImmutable); + bool temp = wrapHnd->isObjectImmutable(objPtr); + API_LEAVE(isObjectImmutable); + return temp; +} + +CORINFO_CLASS_HANDLE WrapICorJitInfo::getObjectType( + void* objPtr) +{ + API_ENTER(getObjectType); + CORINFO_CLASS_HANDLE temp = wrapHnd->getObjectType(objPtr); + API_LEAVE(getObjectType); + return temp; +} + bool WrapICorJitInfo::getReadyToRunHelper( CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_LOOKUP_KIND* pGenericLookupKind, @@ -1451,6 +1469,17 @@ void* WrapICorJitInfo::getFieldAddress( return temp; } +bool WrapICorJitInfo::getReadonlyStaticFieldValue( + CORINFO_FIELD_HANDLE field, + uint8_t* buffer, + int bufferSize) +{ + API_ENTER(getReadonlyStaticFieldValue); + bool temp = wrapHnd->getReadonlyStaticFieldValue(field, buffer, bufferSize); + API_LEAVE(getReadonlyStaticFieldValue); + return temp; +} + CORINFO_CLASS_HANDLE WrapICorJitInfo::getStaticFieldCurrentClass( CORINFO_FIELD_HANDLE field, bool* pIsSpeculative) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 236766082a1c0..1f17c5664afd2 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -3631,7 +3631,7 @@ class Compiler GenTree* impInitClass(CORINFO_RESOLVED_TOKEN* pResolvedToken); - GenTree* impImportStaticReadOnlyField(void* fldAddr, var_types lclTyp); + GenTree* impImportStaticReadOnlyField(uint8_t* buffer, int bufferSize, var_types valueType); GenTree* impImportStaticFieldAccess(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_ACCESS_FLAGS access, diff --git a/src/coreclr/jit/gcinfo.cpp b/src/coreclr/jit/gcinfo.cpp index ae7303435a68c..6ee757a7238bc 100644 --- a/src/coreclr/jit/gcinfo.cpp +++ b/src/coreclr/jit/gcinfo.cpp @@ -252,6 +252,7 @@ GCInfo::WriteBarrierForm GCInfo::gcIsWriteBarrierCandidate(GenTreeStoreInd* stor return WBF_NoBarrier; } + // Write-barriers are no-op for frozen objects (as values) if (store->Data()->IsIconHandle(GTF_ICON_OBJ_HDL)) { // Ignore frozen objects diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index c49c2bc40659a..2321a624fc74a 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -17502,6 +17502,20 @@ CORINFO_CLASS_HANDLE Compiler::gtGetClassHandle(GenTree* tree, bool* pIsExact, b break; } + case GT_CNS_INT: + { + if (tree->IsIconHandle(GTF_ICON_OBJ_HDL)) + { + objClass = info.compCompHnd->getObjectType((void*)tree->AsIntCon()->IconValue()); + if (objClass != NO_CLASS_HANDLE) + { + // if we managed to get a class handle it's definitely not null + *pIsNonNull = true; + } + } + break; + } + case GT_RET_EXPR: { // If we see a RET_EXPR, recurse through to examine the diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 33f25ed04d1f3..e1ef371bd5f34 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -8116,133 +8116,92 @@ GenTree* Compiler::impInitClass(CORINFO_RESOLVED_TOKEN* pResolvedToken) return node; } -GenTree* Compiler::impImportStaticReadOnlyField(void* fldAddr, var_types lclTyp) +GenTree* Compiler::impImportStaticReadOnlyField(uint8_t* buffer, int bufferSize, var_types valueType) { - GenTree* op1 = nullptr; - -#if defined(DEBUG) - // If we're replaying under SuperPMI, we're going to read the data stored by SuperPMI and use it - // for optimization. Unfortunately, SuperPMI doesn't implement a guarantee on the alignment of - // this data, so for some platforms which don't allow unaligned access (e.g., Linux arm32), - // this can fault. We should fix SuperPMI to guarantee alignment, but that is a big change. - // Instead, simply fix up the data here for future use. - - // This variable should be the largest size element, with the largest alignment requirement, - // and the native C++ compiler should guarantee sufficient alignment. - double aligned_data = 0.0; - void* p_aligned_data = &aligned_data; - if (info.compMethodSuperPMIIndex != -1) - { - switch (lclTyp) - { - case TYP_BOOL: - case TYP_BYTE: - case TYP_UBYTE: - static_assert_no_msg(sizeof(unsigned __int8) == sizeof(bool)); - static_assert_no_msg(sizeof(unsigned __int8) == sizeof(signed char)); - static_assert_no_msg(sizeof(unsigned __int8) == sizeof(unsigned char)); - // No alignment necessary for byte. - break; - - case TYP_SHORT: - case TYP_USHORT: - static_assert_no_msg(sizeof(unsigned __int16) == sizeof(short)); - static_assert_no_msg(sizeof(unsigned __int16) == sizeof(unsigned short)); - if ((size_t)fldAddr % sizeof(unsigned __int16) != 0) - { - *(unsigned __int16*)p_aligned_data = GET_UNALIGNED_16(fldAddr); - fldAddr = p_aligned_data; - } - break; - - case TYP_INT: - case TYP_UINT: - case TYP_FLOAT: - static_assert_no_msg(sizeof(unsigned __int32) == sizeof(int)); - static_assert_no_msg(sizeof(unsigned __int32) == sizeof(unsigned int)); - static_assert_no_msg(sizeof(unsigned __int32) == sizeof(float)); - if ((size_t)fldAddr % sizeof(unsigned __int32) != 0) - { - *(unsigned __int32*)p_aligned_data = GET_UNALIGNED_32(fldAddr); - fldAddr = p_aligned_data; - } - break; - - case TYP_LONG: - case TYP_ULONG: - case TYP_DOUBLE: - static_assert_no_msg(sizeof(unsigned __int64) == sizeof(__int64)); - static_assert_no_msg(sizeof(unsigned __int64) == sizeof(double)); - if ((size_t)fldAddr % sizeof(unsigned __int64) != 0) - { - *(unsigned __int64*)p_aligned_data = GET_UNALIGNED_64(fldAddr); - fldAddr = p_aligned_data; - } - break; - - default: - assert(!"Unexpected lclTyp"); - break; - } - } -#endif // DEBUG + // We plan to support larger values (for structs), for now let's keep it 64 bit + assert(bufferSize == sizeof(INT64)); - switch (lclTyp) + GenTree* tree = nullptr; + switch (valueType) { - int ival; - __int64 lval; - double dval; +// Use memcpy to read from the buffer and create an Icon/Dcon tree +#define CreateTreeFromBuffer(type, treeFactory) \ + type v##type; \ + memcpy(&v##type, buffer, sizeof(type)); \ + tree = treeFactory(v##type); case TYP_BOOL: - ival = *((bool*)fldAddr); - goto IVAL_COMMON; - + { + CreateTreeFromBuffer(bool, gtNewIconNode); + break; + } case TYP_BYTE: - ival = *((signed char*)fldAddr); - goto IVAL_COMMON; - + { + CreateTreeFromBuffer(int8_t, gtNewIconNode); + break; + } case TYP_UBYTE: - ival = *((unsigned char*)fldAddr); - goto IVAL_COMMON; - + { + CreateTreeFromBuffer(uint8_t, gtNewIconNode); + break; + } case TYP_SHORT: - ival = *((short*)fldAddr); - goto IVAL_COMMON; - + { + CreateTreeFromBuffer(int16_t, gtNewIconNode); + break; + } case TYP_USHORT: - ival = *((unsigned short*)fldAddr); - goto IVAL_COMMON; - + { + CreateTreeFromBuffer(uint16_t, gtNewIconNode); + break; + } case TYP_UINT: case TYP_INT: - ival = *((int*)fldAddr); - IVAL_COMMON: - op1 = gtNewIconNode(ival); + { + CreateTreeFromBuffer(int32_t, gtNewIconNode); break; - + } case TYP_LONG: case TYP_ULONG: - lval = *((__int64*)fldAddr); - op1 = gtNewLconNode(lval); + { + CreateTreeFromBuffer(int64_t, gtNewLconNode); break; - + } case TYP_FLOAT: - dval = *((float*)fldAddr); - op1 = gtNewDconNode(dval); - op1->gtType = TYP_FLOAT; + { + CreateTreeFromBuffer(float, gtNewDconNode); break; - + } case TYP_DOUBLE: - dval = *((double*)fldAddr); - op1 = gtNewDconNode(dval); + { + CreateTreeFromBuffer(double, gtNewDconNode); break; + } + case TYP_REF: + { + void* ptr; + memcpy(&ptr, buffer, sizeof(ssize_t)); - default: - assert(!"Unexpected lclTyp"); + if (ptr == 0) + { + tree = gtNewNull(); + } + else + { + setMethodHasFrozenObjects(); + tree = gtNewIconEmbHndNode(ptr, nullptr, GTF_ICON_OBJ_HDL, nullptr); + tree->gtType = TYP_REF; + INDEBUG(tree->AsIntCon()->gtTargetHandle = (size_t)ptr); + } break; + } + default: + return nullptr; } - return op1; + assert(tree != nullptr); + tree->gtType = genActualType(valueType); + return tree; } GenTree* Compiler::impImportStaticFieldAccess(CORINFO_RESOLVED_TOKEN* pResolvedToken, @@ -15230,41 +15189,31 @@ void Compiler::impImportBlockCode(BasicBlock* block) usesHelper = true; break; + case CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER: case CORINFO_FIELD_STATIC_ADDRESS: // Replace static read-only fields with constant if possible - if ((aflags & CORINFO_ACCESS_GET) && (fieldInfo.fieldFlags & CORINFO_FLG_FIELD_FINAL) && - !(fieldInfo.fieldFlags & CORINFO_FLG_FIELD_STATIC_IN_HEAP) && - (varTypeIsIntegral(lclTyp) || varTypeIsFloating(lclTyp))) + if ((aflags & CORINFO_ACCESS_GET) && (fieldInfo.fieldFlags & CORINFO_FLG_FIELD_FINAL)) { - CorInfoInitClassResult initClassResult = - info.compCompHnd->initClass(resolvedToken.hField, info.compMethodHnd, - impTokenLookupContextHandle); - - if (initClassResult & CORINFO_INITCLASS_INITIALIZED) + const int bufferSize = sizeof(uint64_t); + uint8_t buffer[bufferSize] = {0}; + if (varTypeIsIntegral(lclTyp) || varTypeIsFloating(lclTyp) || (lclTyp == TYP_REF)) { - void** pFldAddr = nullptr; - void* fldAddr = - info.compCompHnd->getFieldAddress(resolvedToken.hField, (void**)&pFldAddr); - - // We should always be able to access this static's address directly - // - assert(pFldAddr == nullptr); - - op1 = impImportStaticReadOnlyField(fldAddr, lclTyp); - - // Widen small types since we're propagating the value - // instead of producing an indir. - // - op1->gtType = genActualType(lclTyp); - - goto FIELD_DONE; + assert(bufferSize >= genTypeSize(lclTyp)); + if (info.compCompHnd->getReadonlyStaticFieldValue(resolvedToken.hField, buffer, + genTypeSize(lclTyp))) + { + GenTree* cnsValue = impImportStaticReadOnlyField(buffer, bufferSize, lclTyp); + if (cnsValue != nullptr) + { + op1 = cnsValue; + goto FIELD_DONE; + } + } } } - FALLTHROUGH; case CORINFO_FIELD_STATIC_RVA_ADDRESS: - case CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER: case CORINFO_FIELD_STATIC_GENERICS_STATIC_HELPER: case CORINFO_FIELD_STATIC_READYTORUN_HELPER: op1 = impImportStaticFieldAccess(&resolvedToken, (CORINFO_ACCESS_FLAGS)aflags, &fieldInfo, diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index bb8d617104e7a..baa2b13670fd9 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -7101,6 +7101,23 @@ void Lowering::LowerStoreIndirCommon(GenTreeStoreInd* ind) if (!comp->codeGen->gcInfo.gcIsWriteBarrierStoreIndNode(ind)) { +#ifndef TARGET_XARCH + if (ind->Data()->IsIconHandle(GTF_ICON_OBJ_HDL)) + { + const ssize_t handle = ind->Data()->AsIntCon()->IconValue(); + if (!comp->info.compCompHnd->isObjectImmutable(reinterpret_cast(handle))) + { + // On platforms with weaker memory model we need to make sure we use a store with the release semantic + // when we publish a potentially mutable object + // See relevant discussions https://github.com/dotnet/runtime/pull/76135#issuecomment-1257258310 and + // https://github.com/dotnet/runtime/pull/76112#discussion_r980639782 + + // This can be relaxed to "just make sure to use stlr/memory barrier" if needed + ind->gtFlags |= GTF_IND_VOLATILE; + } + } +#endif + if (varTypeIsFloating(ind) && ind->Data()->IsCnsFltOrDbl()) { // Optimize *x = DCON to *x = ICON which can be slightly faster and/or smaller. diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs b/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs index deae2ff107764..227ea1336ca70 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs @@ -1017,6 +1017,36 @@ private static CorInfoHelpFunc _getUnBoxHelper(IntPtr thisHandle, IntPtr* ppExce } } + [UnmanagedCallersOnly] + private static byte _isObjectImmutable(IntPtr thisHandle, IntPtr* ppException, void* objPtr) + { + var _this = GetThis(thisHandle); + try + { + return _this.isObjectImmutable(objPtr) ? (byte)1 : (byte)0; + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default; + } + } + + [UnmanagedCallersOnly] + private static CORINFO_CLASS_STRUCT_* _getObjectType(IntPtr thisHandle, IntPtr* ppException, void* objPtr) + { + var _this = GetThis(thisHandle); + try + { + return _this.getObjectType(objPtr); + } + 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) { @@ -2198,6 +2228,21 @@ private static uint _getClassDomainID(IntPtr thisHandle, IntPtr* ppException, CO } } + [UnmanagedCallersOnly] + private static byte _getReadonlyStaticFieldValue(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field, byte* buffer, int bufferSize) + { + var _this = GetThis(thisHandle); + try + { + return _this.getReadonlyStaticFieldValue(field, buffer, bufferSize) ? (byte)1 : (byte)0; + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default; + } + } + [UnmanagedCallersOnly] private static CORINFO_CLASS_STRUCT_* _getStaticFieldCurrentClass(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field, byte* pIsSpeculative) { @@ -2625,7 +2670,7 @@ private static uint _getJitFlags(IntPtr thisHandle, IntPtr* ppException, CORJIT_ private static IntPtr GetUnmanagedCallbacks() { - void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 177); + void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 180); callbacks[0] = (delegate* unmanaged)&_isIntrinsic; callbacks[1] = (delegate* unmanaged)&_getMethodAttribs; @@ -2695,115 +2740,118 @@ private static IntPtr GetUnmanagedCallbacks() 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; + callbacks[68] = (delegate* unmanaged)&_isObjectImmutable; + callbacks[69] = (delegate* unmanaged)&_getObjectType; + callbacks[70] = (delegate* unmanaged)&_getReadyToRunHelper; + callbacks[71] = (delegate* unmanaged)&_getReadyToRunDelegateCtorHelper; + callbacks[72] = (delegate* unmanaged)&_getHelperName; + callbacks[73] = (delegate* unmanaged)&_initClass; + callbacks[74] = (delegate* unmanaged)&_classMustBeLoadedBeforeCodeIsRun; + callbacks[75] = (delegate* unmanaged)&_getBuiltinClass; + callbacks[76] = (delegate* unmanaged)&_getTypeForPrimitiveValueClass; + callbacks[77] = (delegate* unmanaged)&_getTypeForPrimitiveNumericClass; + callbacks[78] = (delegate* unmanaged)&_canCast; + callbacks[79] = (delegate* unmanaged)&_areTypesEquivalent; + callbacks[80] = (delegate* unmanaged)&_compareTypesForCast; + callbacks[81] = (delegate* unmanaged)&_compareTypesForEquality; + callbacks[82] = (delegate* unmanaged)&_mergeClasses; + callbacks[83] = (delegate* unmanaged)&_isMoreSpecificType; + callbacks[84] = (delegate* unmanaged)&_getParentType; + callbacks[85] = (delegate* unmanaged)&_getChildType; + callbacks[86] = (delegate* unmanaged)&_satisfiesClassConstraints; + callbacks[87] = (delegate* unmanaged)&_isSDArray; + callbacks[88] = (delegate* unmanaged)&_getArrayRank; + callbacks[89] = (delegate* unmanaged)&_getArrayIntrinsicID; + callbacks[90] = (delegate* unmanaged)&_getArrayInitializationData; + callbacks[91] = (delegate* unmanaged)&_canAccessClass; + callbacks[92] = (delegate* unmanaged)&_getFieldName; + callbacks[93] = (delegate* unmanaged)&_getFieldClass; + callbacks[94] = (delegate* unmanaged)&_getFieldType; + callbacks[95] = (delegate* unmanaged)&_getFieldOffset; + callbacks[96] = (delegate* unmanaged)&_getFieldInfo; + callbacks[97] = (delegate* unmanaged)&_isFieldStatic; + callbacks[98] = (delegate* unmanaged)&_getBoundaries; + callbacks[99] = (delegate* unmanaged)&_setBoundaries; + callbacks[100] = (delegate* unmanaged)&_getVars; + callbacks[101] = (delegate* unmanaged)&_setVars; + callbacks[102] = (delegate* unmanaged)&_reportRichMappings; + callbacks[103] = (delegate* unmanaged)&_allocateArray; + callbacks[104] = (delegate* unmanaged)&_freeArray; + callbacks[105] = (delegate* unmanaged)&_getArgNext; + callbacks[106] = (delegate* unmanaged)&_getArgType; + callbacks[107] = (delegate* unmanaged)&_getExactClasses; + callbacks[108] = (delegate* unmanaged)&_getArgClass; + callbacks[109] = (delegate* unmanaged)&_getHFAType; + callbacks[110] = (delegate* unmanaged)&_GetErrorHRESULT; + callbacks[111] = (delegate* unmanaged)&_GetErrorMessage; + callbacks[112] = (delegate* unmanaged)&_FilterException; + callbacks[113] = (delegate* unmanaged)&_ThrowExceptionForJitResult; + callbacks[114] = (delegate* unmanaged)&_ThrowExceptionForHelper; + callbacks[115] = (delegate* unmanaged)&_runWithErrorTrap; + callbacks[116] = (delegate* unmanaged)&_runWithSPMIErrorTrap; + callbacks[117] = (delegate* unmanaged)&_getEEInfo; + callbacks[118] = (delegate* unmanaged)&_getJitTimeLogFilename; + callbacks[119] = (delegate* unmanaged)&_getMethodDefFromMethod; + callbacks[120] = (delegate* unmanaged)&_getMethodName; + callbacks[121] = (delegate* unmanaged)&_getMethodNameFromMetadata; + callbacks[122] = (delegate* unmanaged)&_getMethodHash; + callbacks[123] = (delegate* unmanaged)&_findNameOfToken; + callbacks[124] = (delegate* unmanaged)&_getSystemVAmd64PassStructInRegisterDescriptor; + callbacks[125] = (delegate* unmanaged)&_getLoongArch64PassStructInRegisterFlags; + callbacks[126] = (delegate* unmanaged)&_getThreadTLSIndex; + callbacks[127] = (delegate* unmanaged)&_getInlinedCallFrameVptr; + callbacks[128] = (delegate* unmanaged)&_getAddrOfCaptureThreadGlobal; + callbacks[129] = (delegate* unmanaged)&_getHelperFtn; + callbacks[130] = (delegate* unmanaged)&_getFunctionEntryPoint; + callbacks[131] = (delegate* unmanaged)&_getFunctionFixedEntryPoint; + callbacks[132] = (delegate* unmanaged)&_getMethodSync; + callbacks[133] = (delegate* unmanaged)&_getLazyStringLiteralHelper; + callbacks[134] = (delegate* unmanaged)&_embedModuleHandle; + callbacks[135] = (delegate* unmanaged)&_embedClassHandle; + callbacks[136] = (delegate* unmanaged)&_embedMethodHandle; + callbacks[137] = (delegate* unmanaged)&_embedFieldHandle; + callbacks[138] = (delegate* unmanaged)&_embedGenericHandle; + callbacks[139] = (delegate* unmanaged)&_getLocationOfThisType; + callbacks[140] = (delegate* unmanaged)&_getAddressOfPInvokeTarget; + callbacks[141] = (delegate* unmanaged)&_GetCookieForPInvokeCalliSig; + callbacks[142] = (delegate* unmanaged)&_canGetCookieForPInvokeCalliSig; + callbacks[143] = (delegate* unmanaged)&_getJustMyCodeHandle; + callbacks[144] = (delegate* unmanaged)&_GetProfilingHandle; + callbacks[145] = (delegate* unmanaged)&_getCallInfo; + callbacks[146] = (delegate* unmanaged)&_canAccessFamily; + callbacks[147] = (delegate* unmanaged)&_isRIDClassDomainID; + callbacks[148] = (delegate* unmanaged)&_getClassDomainID; + callbacks[149] = (delegate* unmanaged)&_getFieldAddress; + callbacks[150] = (delegate* unmanaged)&_getReadonlyStaticFieldValue; + callbacks[151] = (delegate* unmanaged)&_getStaticFieldCurrentClass; + callbacks[152] = (delegate* unmanaged)&_getVarArgsHandle; + callbacks[153] = (delegate* unmanaged)&_canGetVarArgsHandle; + callbacks[154] = (delegate* unmanaged)&_constructStringLiteral; + callbacks[155] = (delegate* unmanaged)&_emptyStringLiteral; + callbacks[156] = (delegate* unmanaged)&_getFieldThreadLocalStoreID; + callbacks[157] = (delegate* unmanaged)&_addActiveDependency; + callbacks[158] = (delegate* unmanaged)&_GetDelegateCtor; + callbacks[159] = (delegate* unmanaged)&_MethodCompileComplete; + callbacks[160] = (delegate* unmanaged)&_getTailCallHelpers; + callbacks[161] = (delegate* unmanaged)&_convertPInvokeCalliToCall; + callbacks[162] = (delegate* unmanaged)&_notifyInstructionSetUsage; + callbacks[163] = (delegate* unmanaged)&_updateEntryPointForTailCall; + callbacks[164] = (delegate* unmanaged)&_allocMem; + callbacks[165] = (delegate* unmanaged)&_reserveUnwindInfo; + callbacks[166] = (delegate* unmanaged)&_allocUnwindInfo; + callbacks[167] = (delegate* unmanaged)&_allocGCInfo; + callbacks[168] = (delegate* unmanaged)&_setEHcount; + callbacks[169] = (delegate* unmanaged)&_setEHinfo; + callbacks[170] = (delegate* unmanaged)&_logMsg; + callbacks[171] = (delegate* unmanaged)&_doAssert; + callbacks[172] = (delegate* unmanaged)&_reportFatalError; + callbacks[173] = (delegate* unmanaged)&_getPgoInstrumentationResults; + callbacks[174] = (delegate* unmanaged)&_allocPgoInstrumentationBySchema; + callbacks[175] = (delegate* unmanaged)&_recordCallSite; + callbacks[176] = (delegate* unmanaged)&_recordRelocation; + callbacks[177] = (delegate* unmanaged)&_getRelocTypeHint; + callbacks[178] = (delegate* unmanaged)&_getExpectedTargetArchitecture; + callbacks[179] = (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 5364f8c42d1a9..950266e9645bf 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -2349,13 +2349,6 @@ 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 fa24d8765374e..3b32d819eed71 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -223,6 +223,8 @@ FUNCTIONS CorInfoHelpFunc getBoxHelper(CORINFO_CLASS_HANDLE cls) CorInfoHelpFunc getUnBoxHelper(CORINFO_CLASS_HANDLE cls) void* getRuntimeTypePointer(CORINFO_CLASS_HANDLE cls) + bool isObjectImmutable(void* objPtr) + CORINFO_CLASS_HANDLE getObjectType(void* objPtr) 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) @@ -303,6 +305,7 @@ FUNCTIONS bool isRIDClassDomainID(CORINFO_CLASS_HANDLE cls); unsigned getClassDomainID (CORINFO_CLASS_HANDLE cls, void **ppIndirection); void* getFieldAddress(CORINFO_FIELD_HANDLE field, VOIDSTARSTAR ppIndirection); + bool getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint8_t *buffer, int bufferSize); CORINFO_CLASS_HANDLE getStaticFieldCurrentClass(CORINFO_FIELD_HANDLE field, BoolStar pIsSpeculative); CORINFO_VARARGS_HANDLE getVarArgsHandle(CORINFO_SIG_INFO *pSig, void **ppIndirection); bool canGetVarArgsHandle(CORINFO_SIG_INFO *pSig); diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/FrozenObjectNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/FrozenObjectNode.cs index 7a1cf593a6ab3..bc863631e8818 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/FrozenObjectNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/FrozenObjectNode.cs @@ -35,6 +35,10 @@ public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) public override bool StaticDependenciesAreComputed => true; + public TypeDesc ObjectType => _data.Type; + + public bool IsKnownImmutable => _data.IsKnownImmutable; + int ISymbolNode.Offset => 0; int ISymbolDefinitionNode.Offset @@ -101,5 +105,7 @@ public override int CompareToImpl(ISortableNode other, CompilerComparer comparer return _allocationSiteId.CompareTo(otherFrozenObjectNode._allocationSiteId); } + + public override string ToString() => $"Frozen {_data.Type.GetDisplayNameWithoutNamespace()} object"; } } diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs index 5d292226fbd72..24cfdac46c01a 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs @@ -1704,6 +1704,8 @@ private enum StackValueKind public interface ISerializableValue { void WriteFieldData(ref ObjectDataBuilder builder, NodeFactory factory); + + bool GetRawData(NodeFactory factory, out object data); } /// @@ -1713,6 +1715,7 @@ public interface ISerializableReference : ISerializableValue { TypeDesc Type { get; } void WriteContent(ref ObjectDataBuilder builder, ISymbolNode thisNode, NodeFactory factory); + bool IsKnownImmutable { get; } } /// @@ -1767,6 +1770,8 @@ public virtual bool TryCreateByRef(out Value value) public abstract void WriteFieldData(ref ObjectDataBuilder builder, NodeFactory factory); + public abstract bool GetRawData(NodeFactory factory, out object data); + private static T ThrowInvalidProgram() { ThrowHelper.ThrowInvalidProgramException(); @@ -1855,6 +1860,12 @@ public override void WriteFieldData(ref ObjectDataBuilder builder, NodeFactory f builder.EmitBytes(InstanceBytes); } + public override bool GetRawData(NodeFactory factory, out object data) + { + data = InstanceBytes; + return true; + } + private byte[] AsExactByteCount(int size) { if (InstanceBytes.Length != size) @@ -1903,6 +1914,12 @@ public override void WriteFieldData(ref ObjectDataBuilder builder, NodeFactory f { throw new NotSupportedException(); } + + public override bool GetRawData(NodeFactory factory, out object data) + { + data = null; + return false; + } } private sealed class MethodPointerValue : BaseValueTypeValue, IInternalModelingOnlyValue @@ -1930,6 +1947,12 @@ public override void WriteFieldData(ref ObjectDataBuilder builder, NodeFactory f { throw new NotSupportedException(); } + + public override bool GetRawData(NodeFactory factory, out object data) + { + data = null; + return false; + } } private sealed class ByRefValue : Value, IHasInstanceFields @@ -1976,6 +1999,12 @@ public override void WriteFieldData(ref ObjectDataBuilder builder, NodeFactory f // This would imply we have a byref-typed static field. The layout algorithm should have blocked this. throw new NotImplementedException(); } + + public override bool GetRawData(NodeFactory factory, out object data) + { + data = null; + return false; + } } private abstract class ReferenceTypeValue : Value @@ -2022,6 +2051,17 @@ public override ReferenceTypeValue ToForeignInstance(int baseInstructionCounter) Type, new AllocationSite(AllocationSite.OwningType, AllocationSite.InstructionCounter - baseInstructionCounter), this); + + public override bool GetRawData(NodeFactory factory, out object data) + { + if (this is ISerializableReference serializableRef) + { + data = factory.SerializedFrozenObject(AllocationSite.OwningType, AllocationSite.InstructionCounter, serializableRef); + return true; + } + data = null; + return false; + } } #pragma warning disable CA1852 @@ -2095,6 +2135,8 @@ public override void WriteFieldData(ref ObjectDataBuilder builder, NodeFactory f { builder.EmitPointerReloc(factory.SerializedFrozenObject(AllocationSite.OwningType, AllocationSite.InstructionCounter, this)); } + + public bool IsKnownImmutable => _methodPointed.Signature.IsStatic; } #pragma warning disable CA1852 @@ -2183,6 +2225,8 @@ public virtual void WriteContent(ref ObjectDataBuilder builder, ISymbolNode this builder.EmitBytes(_data); } + + public bool IsKnownImmutable => _elementCount == 0; } private sealed class ForeignTypeInstance : AllocatedReferenceTypeValue @@ -2225,6 +2269,12 @@ public override void WriteFieldData(ref ObjectDataBuilder builder, NodeFactory f builder.EmitPointerReloc(factory.SerializedStringObject(_value)); } + public override bool GetRawData(NodeFactory factory, out object data) + { + data = factory.SerializedStringObject(_value); + return true; + } + public override ReferenceTypeValue ToForeignInstance(int baseInstructionCounter) => this; } @@ -2296,6 +2346,8 @@ public virtual void WriteContent(ref ObjectDataBuilder builder, ISymbolNode this int pointerSize = factory.Target.PointerSize; builder.EmitBytes(_data, pointerSize, _data.Length - pointerSize); } + + public bool IsKnownImmutable => !Type.GetFields().GetEnumerator().MoveNext(); } private struct FieldAccessor diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs index 4a4e9027c2890..c366a6e4f0835 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs @@ -2992,5 +2992,25 @@ private int getExactClasses(CORINFO_CLASS_STRUCT_* baseType, int maxExactClasses // Not implemented for R2R yet return 0; } + + private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byte* buffer, int bufferSize) + { + return false; + } + + private CORINFO_CLASS_STRUCT_* getObjectType(void* objPtr) + { + throw new NotSupportedException(); + } + + private bool isObjectImmutable(void* objPtr) + { + throw new NotSupportedException(); + } + + private void* getRuntimeTypePointer(CORINFO_CLASS_STRUCT_* cls) + { + return null; + } } } diff --git a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs index 8a0e974b0f937..72ee00ccd76da 100644 --- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs +++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs @@ -2203,5 +2203,88 @@ private int getExactClasses(CORINFO_CLASS_STRUCT_* baseType, int maxExactClasses Debug.Assert(index <= maxExactClasses); return index; } + + private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byte* buffer, int bufferSize) + { + Debug.Assert(fieldHandle != null); + Debug.Assert(buffer != null); + Debug.Assert(bufferSize > 0); + + FieldDesc field = HandleToObject(fieldHandle); + Debug.Assert(field.IsStatic); + + if (!field.IsThreadStatic && field.IsInitOnly && field.OwningType is MetadataType owningType) + { + PreinitializationManager preinitManager = _compilation.NodeFactory.PreinitializationManager; + if (preinitManager.IsPreinitialized(owningType)) + { + TypePreinit.ISerializableValue value = preinitManager + .GetPreinitializationInfo(owningType).GetFieldValue(field); + + int targetPtrSize = _compilation.TypeSystemContext.Target.PointerSize; + + if (value == null) + { + Debug.Assert(bufferSize == targetPtrSize); + + // Write "null" to buffer + new Span(buffer, targetPtrSize).Clear(); + return true; + } + + if (value.GetRawData(_compilation.NodeFactory, out object data)) + { + switch (data) + { + case byte[] bytes: + Debug.Assert(bufferSize == bytes.Length); + + // Ensure we have enough room in the buffer, it can be a large struct + bytes.AsSpan().CopyTo(new Span(buffer, bufferSize)); + return true; + + case FrozenObjectNode or FrozenStringNode: + Debug.Assert(bufferSize == targetPtrSize); + + // save handle's value to buffer + nint handle = ObjectToHandle(data); + new Span(&handle, targetPtrSize).CopyTo(new Span(buffer, targetPtrSize)); + return true; + } + } + } + } + return false; + } + + private CORINFO_CLASS_STRUCT_* getObjectType(void* objPtr) + { + object obj = HandleToObject(objPtr); + return obj switch + { + FrozenStringNode => ObjectToHandle(_compilation.TypeSystemContext.GetWellKnownType(WellKnownType.String)), + FrozenObjectNode frozenObj => ObjectToHandle(frozenObj.ObjectType), + _ => throw new NotImplementedException($"Unexpected object in getObjectType: {obj}") + }; + } + +#pragma warning disable CA1822 // Mark members as static + private void* getRuntimeTypePointer(CORINFO_CLASS_STRUCT_* cls) +#pragma warning restore CA1822 // Mark members as static + { + // TODO: https://github.com/dotnet/runtime/pull/75573#issuecomment-1250824543 + return null; + } + + private bool isObjectImmutable(void* objPtr) + { + object obj = HandleToObject(objPtr); + return obj switch + { + FrozenStringNode => true, + FrozenObjectNode frozenObj => frozenObj.IsKnownImmutable, + _ => throw new NotImplementedException($"Unexpected object in isObjectImmutable: {obj}") + }; + } } } diff --git a/src/coreclr/tools/aot/jitinterface/jitinterface.h b/src/coreclr/tools/aot/jitinterface/jitinterface.h index 1afde939023b5..3f574cd062ec7 100644 --- a/src/coreclr/tools/aot/jitinterface/jitinterface.h +++ b/src/coreclr/tools/aot/jitinterface/jitinterface.h @@ -79,6 +79,8 @@ struct JitInterfaceCallbacks 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 (* isObjectImmutable)(void * thisHandle, CorInfoExceptionClass** ppException, void* objPtr); + CORINFO_CLASS_HANDLE (* getObjectType)(void * thisHandle, CorInfoExceptionClass** ppException, void* objPtr); 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); @@ -159,6 +161,7 @@ struct JitInterfaceCallbacks bool (* isRIDClassDomainID)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls); unsigned (* getClassDomainID)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls, void** ppIndirection); void* (* getFieldAddress)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_FIELD_HANDLE field, void** ppIndirection); + bool (* getReadonlyStaticFieldValue)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize); CORINFO_CLASS_HANDLE (* getStaticFieldCurrentClass)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_FIELD_HANDLE field, bool* pIsSpeculative); CORINFO_VARARGS_HANDLE (* getVarArgsHandle)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_SIG_INFO* pSig, void** ppIndirection); bool (* canGetVarArgsHandle)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_SIG_INFO* pSig); @@ -864,6 +867,24 @@ class JitInterfaceWrapper : public ICorJitInfo return temp; } + virtual bool isObjectImmutable( + void* objPtr) +{ + CorInfoExceptionClass* pException = nullptr; + bool temp = _callbacks->isObjectImmutable(_thisHandle, &pException, objPtr); + if (pException != nullptr) throw pException; + return temp; +} + + virtual CORINFO_CLASS_HANDLE getObjectType( + void* objPtr) +{ + CorInfoExceptionClass* pException = nullptr; + CORINFO_CLASS_HANDLE temp = _callbacks->getObjectType(_thisHandle, &pException, objPtr); + if (pException != nullptr) throw pException; + return temp; +} + virtual bool getReadyToRunHelper( CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_LOOKUP_KIND* pGenericLookupKind, @@ -1624,6 +1645,17 @@ class JitInterfaceWrapper : public ICorJitInfo return temp; } + virtual bool getReadonlyStaticFieldValue( + CORINFO_FIELD_HANDLE field, + uint8_t* buffer, + int bufferSize) +{ + CorInfoExceptionClass* pException = nullptr; + bool temp = _callbacks->getReadonlyStaticFieldValue(_thisHandle, &pException, field, buffer, bufferSize); + if (pException != nullptr) throw pException; + return temp; +} + virtual CORINFO_CLASS_HANDLE getStaticFieldCurrentClass( CORINFO_FIELD_HANDLE field, bool* pIsSpeculative) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h index 6bb3adc7f540b..55f857917df49 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h @@ -194,7 +194,6 @@ struct Agnostic_GetFieldAddress { DWORDLONG ppIndirection; DWORDLONG fieldAddress; - DWORD fieldValue; }; struct Agnostic_GetStaticFieldCurrentClass diff --git a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h index 696730baa40bf..8918c9b59a6e8 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h @@ -80,6 +80,7 @@ LWM(GetDelegateCtor, Agnostic_GetDelegateCtorIn, Agnostic_GetDelegateCtorOut) LWM(GetEEInfo, DWORD, Agnostic_CORINFO_EE_INFO) LWM(GetEHinfo, DLD, Agnostic_CORINFO_EH_CLAUSE) LWM(GetFieldAddress, DWORDLONG, Agnostic_GetFieldAddress) +LWM(GetReadonlyStaticFieldValue, DLD, DD) LWM(GetStaticFieldCurrentClass, DWORDLONG, Agnostic_GetStaticFieldCurrentClass) LWM(GetFieldClass, DWORDLONG, DWORDLONG) LWM(GetFieldInClass, DLD, DWORDLONG) @@ -139,6 +140,8 @@ LWM(GetTypeForPrimitiveNumericClass, DWORDLONG, DWORD) LWM(GetUnboxedEntry, DWORDLONG, DLD); LWM(GetUnBoxHelper, DWORDLONG, DWORD) LWM(GetRuntimeTypePointer, DWORDLONG, DWORDLONG) +LWM(IsObjectImmutable, DWORDLONG, DWORD) +LWM(GetObjectType, 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 50dfcb7141975..5534c4617769d 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -31,7 +31,6 @@ MethodContext::MethodContext() cr = new CompileResult(); index = -1; ignoreStoredConfig = false; - isReadyToRunCompilation = ReadyToRunCompilation::Uninitialized; } MethodContext::~MethodContext() @@ -1237,7 +1236,6 @@ void MethodContext::recGetJitFlags(CORJIT_FLAGS* jitFlags, DWORD sizeInBytes, DW // zero. GetJitFlags->Add(0, value); DEBUG_REC(dmpGetJitFlags(0, value)); - InitReadyToRunFlag(jitFlags); } void MethodContext::dmpGetJitFlags(DWORD key, DD value) { @@ -1262,7 +1260,6 @@ DWORD MethodContext::repGetJitFlags(CORJIT_FLAGS* jitFlags, DWORD sizeInBytes) CORJIT_FLAGS* resultFlags = (CORJIT_FLAGS*)GetJitFlags->GetBuffer(value.A); Assert(sizeInBytes >= value.B); memcpy(jitFlags, resultFlags, value.B); - InitReadyToRunFlag(resultFlags); return value.B; } @@ -2211,6 +2208,52 @@ void* MethodContext::repGetRuntimeTypePointer(CORINFO_CLASS_HANDLE cls) return (void*)value; } +void MethodContext::recIsObjectImmutable(void* objPtr, bool result) +{ + if (IsObjectImmutable == nullptr) + IsObjectImmutable = new LightWeightMap(); + + DWORDLONG key = (DWORDLONG)objPtr; + DWORD value = (DWORD)result; + IsObjectImmutable->Add(key, value); + DEBUG_REC(dmpIsObjectImmutable(key, value)); +} +void MethodContext::dmpIsObjectImmutable(DWORDLONG key, DWORD value) +{ + printf("IsObjectImmutable key obj-%016llX, value res-%u", key, value); +} +bool MethodContext::repIsObjectImmutable(void* objPtr) +{ + DWORDLONG key = (DWORDLONG)objPtr; + AssertMapAndKeyExist(IsObjectImmutable, key, ": key %016llX", key); + DWORD value = IsObjectImmutable->Get(key); + DEBUG_REP(dmpIsObjectImmutable(key, value)); + return (bool)value; +} + +void MethodContext::recGetObjectType(void* objPtr, CORINFO_CLASS_HANDLE result) +{ + if (GetObjectType == nullptr) + GetObjectType = new LightWeightMap(); + + DWORDLONG key = (DWORDLONG)objPtr; + DWORDLONG value = (DWORDLONG)result; + GetObjectType->Add(key, value); + DEBUG_REC(dmpGetObjectType(key, value)); +} +void MethodContext::dmpGetObjectType(DWORDLONG key, DWORDLONG value) +{ + printf("GetObjectType key obj-%016llX, value res-%016llX", key, value); +} +CORINFO_CLASS_HANDLE MethodContext::repGetObjectType(void* objPtr) +{ + DWORDLONG key = (DWORDLONG)objPtr; + AssertMapAndKeyExist(GetObjectType, key, ": key %016llX", key); + DWORDLONG value = GetObjectType->Get(key); + DEBUG_REP(dmpGetObjectType(key, value)); + return (CORINFO_CLASS_HANDLE)value; +} + void MethodContext::recGetReadyToRunHelper(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_LOOKUP_KIND* pGenericLookupKind, CorInfoHelpFunc id, @@ -3559,70 +3602,13 @@ void MethodContext::recGetFieldAddress(CORINFO_FIELD_HANDLE field, void** ppIndi value.ppIndirection = CastPointer(*ppIndirection); value.fieldAddress = CastPointer(result); - value.fieldValue = (DWORD)-1; - - AssertCodeMsg(isReadyToRunCompilation != ReadyToRunCompilation::Uninitialized, EXCEPTIONCODE_MC, - "ReadyToRun flag should be initialized"); - - // Make an attempt at stashing a copy of the value, Jit can try to access - // a static readonly field value. - if (isReadyToRunCompilation == ReadyToRunCompilation::NotReadyToRun && - result > (void*)0xffff) - { - DWORDLONG scratch = 0x4242424242424242; - switch (cit) - { - case CORINFO_TYPE_BOOL: - case CORINFO_TYPE_BYTE: - case CORINFO_TYPE_UBYTE: - value.fieldValue = - (DWORD)GetFieldAddress->AddBuffer((unsigned char*)result, sizeof(BYTE), - true); // important to not merge two fields into one address - break; - case CORINFO_TYPE_CHAR: - case CORINFO_TYPE_SHORT: - case CORINFO_TYPE_USHORT: - value.fieldValue = - (DWORD)GetFieldAddress->AddBuffer((unsigned char*)result, sizeof(WORD), - true); // important to not merge two fields into one address - break; - case CORINFO_TYPE_INT: - case CORINFO_TYPE_UINT: - case CORINFO_TYPE_FLOAT: - value.fieldValue = - (DWORD)GetFieldAddress->AddBuffer((unsigned char*)result, sizeof(DWORD), - true); // important to not merge two fields into one address - break; - case CORINFO_TYPE_LONG: - case CORINFO_TYPE_ULONG: - case CORINFO_TYPE_DOUBLE: - value.fieldValue = - (DWORD)GetFieldAddress->AddBuffer((unsigned char*)result, sizeof(DWORDLONG), - true); // important to not merge two fields into one address - break; - case CORINFO_TYPE_NATIVEINT: - case CORINFO_TYPE_NATIVEUINT: - case CORINFO_TYPE_PTR: - value.fieldValue = - (DWORD)GetFieldAddress->AddBuffer((unsigned char*)result, sizeof(size_t), - true); // important to not merge two fields into one address - GetFieldAddress->AddBuffer((unsigned char*)&scratch, sizeof(DWORD)); // Padding out the data so we - // can read it back "safetly" - // on x64 - break; - default: - break; - } - } - DWORDLONG key = CastHandle(field); GetFieldAddress->Add(key, value); DEBUG_REC(dmpGetFieldAddress(key, value)); } void MethodContext::dmpGetFieldAddress(DWORDLONG key, const Agnostic_GetFieldAddress& value) { - printf("GetFieldAddress key fld-%016llX, value ppi-%016llX addr-%016llX val-%u", key, value.ppIndirection, - value.fieldAddress, value.fieldValue); + printf("GetFieldAddress key fld-%016llX, value ppi-%016llX addr-%016llX", key, value.ppIndirection, value.fieldAddress); } void* MethodContext::repGetFieldAddress(CORINFO_FIELD_HANDLE field, void** ppIndirection) { @@ -3632,26 +3618,57 @@ void* MethodContext::repGetFieldAddress(CORINFO_FIELD_HANDLE field, void** ppInd Agnostic_GetFieldAddress value = GetFieldAddress->Get(key); DEBUG_REP(dmpGetFieldAddress(key, value)); - AssertCodeMsg(isReadyToRunCompilation != ReadyToRunCompilation::Uninitialized, - EXCEPTIONCODE_MC, "isReadyToRunCompilation should be initialized"); - if (ppIndirection != nullptr) { *ppIndirection = (void*)value.ppIndirection; } - void* temp; + return (void*)value.fieldAddress; +} - if (value.fieldValue != (DWORD)-1) - { - temp = (void*)GetFieldAddress->GetBuffer(value.fieldValue); - cr->recAddressMap((void*)value.fieldAddress, temp, toCorInfoSize(repGetFieldType(field, nullptr, nullptr))); - } - else +void MethodContext::recGetReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, bool result) +{ + if (GetReadonlyStaticFieldValue == nullptr) + GetReadonlyStaticFieldValue = new LightWeightMap(); + + DLD key; + ZeroMemory(&key, sizeof(key)); + key.A = CastHandle(field); + key.B = (DWORD)bufferSize; + + DWORD tmpBuf = (DWORD)-1; + if (buffer != nullptr && result) + tmpBuf = (DWORD)GetReadonlyStaticFieldValue->AddBuffer((uint8_t*)buffer, (uint32_t)bufferSize); + + DD value; + value.A = (DWORD)result; + value.B = (DWORD)tmpBuf; + + GetReadonlyStaticFieldValue->Add(key, value); + DEBUG_REC(dmpGetReadonlyStaticFieldValue(key, value)); +} +void MethodContext::dmpGetReadonlyStaticFieldValue(DLD key, DD value) +{ + printf("GetReadonlyStaticFieldValue key fld-%016llX bufSize-%u, result-%u", key.A, key.B, value.A); + GetReadonlyStaticFieldValue->Unlock(); +} +bool MethodContext::repGetReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize) +{ + DLD key; + ZeroMemory(&key, sizeof(key)); + key.A = CastHandle(field); + key.B = (DWORD)bufferSize; + + AssertMapAndKeyExist(GetReadonlyStaticFieldValue, key, ": key %016llX", key.A); + + DD value = GetReadonlyStaticFieldValue->Get(key); + DEBUG_REP(dmpGetReadonlyStaticFieldValue(key, value)); + if (buffer != nullptr && (bool)value.A) { - temp = (void*)value.fieldAddress; + uint8_t* srcBuffer = (uint8_t*)GetReadonlyStaticFieldValue->GetBuffer(value.B); + Assert(srcBuffer != nullptr); + memcpy(buffer, srcBuffer, bufferSize); } - - return temp; + return (bool)value.A; } void MethodContext::recGetStaticFieldCurrentClass(CORINFO_FIELD_HANDLE field, @@ -7441,20 +7458,6 @@ bool MethodContext::IsStringContentEqual(LightWeightMap* prev, Lig } } -void MethodContext::InitReadyToRunFlag(const CORJIT_FLAGS* jitFlags) -{ - if (jitFlags->IsSet(CORJIT_FLAGS::CORJIT_FLAG_READYTORUN)) - { - isReadyToRunCompilation = ReadyToRunCompilation::ReadyToRun; - } - else - { - isReadyToRunCompilation = ReadyToRunCompilation::NotReadyToRun; - } - -} - - bool g_debugRec = false; bool g_debugRep = false; diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h index fae88359e1a90..df89458a05f98 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h @@ -314,6 +314,14 @@ class MethodContext void dmpGetRuntimeTypePointer(DWORDLONG key, DWORDLONG value); void* repGetRuntimeTypePointer(CORINFO_CLASS_HANDLE cls); + void recIsObjectImmutable(void* objPtr, bool result); + void dmpIsObjectImmutable(DWORDLONG key, DWORD value); + bool repIsObjectImmutable(void* objPtr); + + void recGetObjectType(void* objPtr, CORINFO_CLASS_HANDLE result); + void dmpGetObjectType(DWORDLONG key, DWORDLONG value); + CORINFO_CLASS_HANDLE repGetObjectType(void* objPtr); + void recGetReadyToRunHelper(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_LOOKUP_KIND* pGenericLookupKind, CorInfoHelpFunc id, @@ -480,6 +488,10 @@ class MethodContext void dmpGetFieldAddress(DWORDLONG key, const Agnostic_GetFieldAddress& value); void* repGetFieldAddress(CORINFO_FIELD_HANDLE field, void** ppIndirection); + void recGetReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, bool result); + void dmpGetReadonlyStaticFieldValue(DLD key, DD value); + bool repGetReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize); + void recGetStaticFieldCurrentClass(CORINFO_FIELD_HANDLE field, bool isSpeculative, CORINFO_CLASS_HANDLE result); void dmpGetStaticFieldCurrentClass(DWORDLONG key, const Agnostic_GetStaticFieldCurrentClass& value); CORINFO_CLASS_HANDLE repGetStaticFieldCurrentClass(CORINFO_FIELD_HANDLE field, bool* pIsSpeculative); @@ -893,17 +905,6 @@ class MethodContext bool IsEnvironmentHeaderEqual(const Environment& prevEnv); bool IsEnvironmentContentEqual(const Environment& prevEnv); - enum class ReadyToRunCompilation - { - Uninitialized, - ReadyToRun, - NotReadyToRun - }; - - ReadyToRunCompilation isReadyToRunCompilation; - - void InitReadyToRunFlag(const CORJIT_FLAGS* jitFlags); - template static bool AreLWMHeadersEqual(LightWeightMap* prev, LightWeightMap* curr); static bool IsIntConfigContentEqual(LightWeightMap* prev, @@ -1140,6 +1141,9 @@ enum mcPackets Packet_GetExactClasses = 195, Packet_GetRuntimeTypePointer = 196, Packet_PrintObjectDescription = 197, + Packet_GetReadonlyStaticFieldValue = 198, + Packet_GetObjectType = 199, + Packet_IsObjectImmutable = 200, }; 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 282c692060aa1..3bcad317d1950 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -799,6 +799,22 @@ void* interceptor_ICJI::getRuntimeTypePointer(CORINFO_CLASS_HANDLE cls) return temp; } +bool interceptor_ICJI::isObjectImmutable(void* typeObj) +{ + mc->cr->AddCall("isObjectImmutable"); + bool temp = original_ICorJitInfo->isObjectImmutable(typeObj); + mc->recIsObjectImmutable(typeObj, temp); + return temp; +} + +CORINFO_CLASS_HANDLE interceptor_ICJI::getObjectType(void* typeObj) +{ + mc->cr->AddCall("getObjectType"); + CORINFO_CLASS_HANDLE temp = original_ICorJitInfo->getObjectType(typeObj); + mc->recGetObjectType(typeObj, temp); + return temp; +} + bool interceptor_ICJI::getReadyToRunHelper(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_LOOKUP_KIND* pGenericLookupKind, CorInfoHelpFunc id, @@ -1724,6 +1740,14 @@ void* interceptor_ICJI::getFieldAddress(CORINFO_FIELD_HANDLE field, void** ppInd return temp; } +bool interceptor_ICJI::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize) +{ + mc->cr->AddCall("getReadonlyStaticFieldValue"); + bool result = original_ICorJitInfo->getReadonlyStaticFieldValue(field, buffer, bufferSize); + mc->recGetReadonlyStaticFieldValue(field, buffer, bufferSize, result); + return result; +} + // return the class handle for the current value of a static field CORINFO_CLASS_HANDLE interceptor_ICJI::getStaticFieldCurrentClass(CORINFO_FIELD_HANDLE field, bool* pIsSpeculative) { diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp index d685447c59f81..400f3d08e130f 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp @@ -552,6 +552,20 @@ void* interceptor_ICJI::getRuntimeTypePointer( return original_ICorJitInfo->getRuntimeTypePointer(cls); } +bool interceptor_ICJI::isObjectImmutable( + void* objPtr) +{ + mcs->AddCall("isObjectImmutable"); + return original_ICorJitInfo->isObjectImmutable(objPtr); +} + +CORINFO_CLASS_HANDLE interceptor_ICJI::getObjectType( + void* objPtr) +{ + mcs->AddCall("getObjectType"); + return original_ICorJitInfo->getObjectType(objPtr); +} + bool interceptor_ICJI::getReadyToRunHelper( CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_LOOKUP_KIND* pGenericLookupKind, @@ -1189,6 +1203,15 @@ void* interceptor_ICJI::getFieldAddress( return original_ICorJitInfo->getFieldAddress(field, ppIndirection); } +bool interceptor_ICJI::getReadonlyStaticFieldValue( + CORINFO_FIELD_HANDLE field, + uint8_t* buffer, + int bufferSize) +{ + mcs->AddCall("getReadonlyStaticFieldValue"); + return original_ICorJitInfo->getReadonlyStaticFieldValue(field, buffer, bufferSize); +} + CORINFO_CLASS_HANDLE interceptor_ICJI::getStaticFieldCurrentClass( CORINFO_FIELD_HANDLE field, bool* pIsSpeculative) diff --git a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp index 3369c1c776101..0f1ba82825e0b 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp @@ -484,6 +484,18 @@ void* interceptor_ICJI::getRuntimeTypePointer( return original_ICorJitInfo->getRuntimeTypePointer(cls); } +bool interceptor_ICJI::isObjectImmutable( + void* objPtr) +{ + return original_ICorJitInfo->isObjectImmutable(objPtr); +} + +CORINFO_CLASS_HANDLE interceptor_ICJI::getObjectType( + void* objPtr) +{ + return original_ICorJitInfo->getObjectType(objPtr); +} + bool interceptor_ICJI::getReadyToRunHelper( CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_LOOKUP_KIND* pGenericLookupKind, @@ -1041,6 +1053,14 @@ void* interceptor_ICJI::getFieldAddress( return original_ICorJitInfo->getFieldAddress(field, ppIndirection); } +bool interceptor_ICJI::getReadonlyStaticFieldValue( + CORINFO_FIELD_HANDLE field, + uint8_t* buffer, + int bufferSize) +{ + return original_ICorJitInfo->getReadonlyStaticFieldValue(field, buffer, bufferSize); +} + CORINFO_CLASS_HANDLE interceptor_ICJI::getStaticFieldCurrentClass( CORINFO_FIELD_HANDLE field, bool* pIsSpeculative) diff --git a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp index e2917c8ac8f80..191854b2c0c55 100644 --- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp @@ -680,6 +680,20 @@ void* MyICJI::getRuntimeTypePointer(CORINFO_CLASS_HANDLE cls) return result; } +bool MyICJI::isObjectImmutable(void* objPtr) +{ + jitInstance->mc->cr->AddCall("isObjectImmutable"); + bool result = jitInstance->mc->repIsObjectImmutable(objPtr); + return result; +} + +CORINFO_CLASS_HANDLE MyICJI::getObjectType(void* objPtr) +{ + jitInstance->mc->cr->AddCall("getObjectType"); + CORINFO_CLASS_HANDLE result = jitInstance->mc->repGetObjectType(objPtr); + return result; +} + bool MyICJI::getReadyToRunHelper(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_LOOKUP_KIND* pGenericLookupKind, CorInfoHelpFunc id, @@ -1504,6 +1518,12 @@ void* MyICJI::getFieldAddress(CORINFO_FIELD_HANDLE field, void** ppIndirection) return jitInstance->mc->repGetFieldAddress(field, ppIndirection); } +bool MyICJI::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize) +{ + jitInstance->mc->cr->AddCall("getReadonlyStaticFieldValue"); + return jitInstance->mc->repGetReadonlyStaticFieldValue(field, buffer, bufferSize); +} + // return the class handle for the current value of a static field CORINFO_CLASS_HANDLE MyICJI::getStaticFieldCurrentClass(CORINFO_FIELD_HANDLE field, bool* pIsSpeculative) { diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 470c755ca1594..7f9eb04892604 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -6028,6 +6028,57 @@ void* CEEInfo::getRuntimeTypePointer(CORINFO_CLASS_HANDLE clsHnd) return pointer; } + +/***********************************************************************/ +bool CEEInfo::isObjectImmutable(void* objPtr) +{ + CONTRACTL{ + THROWS; + GC_TRIGGERS; + MODE_PREEMPTIVE; + } CONTRACTL_END; + +#ifdef DEBUG + JIT_TO_EE_TRANSITION(); + + GCX_COOP(); + Object* obj = (Object*)objPtr; + MethodTable* type = obj->GetMethodTable(); + + _ASSERTE(type->IsString() || type == g_pRuntimeTypeClass); + + EE_TO_JIT_TRANSITION(); +#endif + + // All currently allocated frozen objects can be treated as immutable + return true; +} + +/***********************************************************************/ +CORINFO_CLASS_HANDLE CEEInfo::getObjectType(void* objPtr) +{ + CONTRACTL{ + THROWS; + GC_TRIGGERS; + MODE_PREEMPTIVE; + } CONTRACTL_END; + + _ASSERT(objPtr != nullptr); + + CORINFO_CLASS_HANDLE handle = NULL; + + JIT_TO_EE_TRANSITION(); + + GCX_COOP(); + Object* obj = (Object*)objPtr; + VALIDATEOBJECT(obj); + handle = (CORINFO_CLASS_HANDLE)obj->GetMethodTable(); + + EE_TO_JIT_TRANSITION(); + + return handle; +} + /***********************************************************************/ bool CEEInfo::getReadyToRunHelper( CORINFO_RESOLVED_TOKEN * pResolvedToken, @@ -11822,6 +11873,71 @@ void* CEEJitInfo::getFieldAddress(CORINFO_FIELD_HANDLE fieldHnd, return result; } +bool CEEInfo::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE fieldHnd, uint8_t* buffer, int bufferSize) +{ + CONTRACTL { + THROWS; + GC_TRIGGERS; + MODE_PREEMPTIVE; + } CONTRACTL_END; + + _ASSERT(fieldHnd != NULL); + _ASSERT(buffer != NULL); + _ASSERT(bufferSize > 0); + + bool result = false; + + JIT_TO_EE_TRANSITION(); + + FieldDesc* field = (FieldDesc*)fieldHnd; + _ASSERTE(field->IsStatic()); + _ASSERTE((unsigned)bufferSize == field->GetSize()); + + MethodTable* pEnclosingMT = field->GetEnclosingMethodTable(); + _ASSERTE(!pEnclosingMT->IsSharedByGenericInstantiations()); + _ASSERTE(!pEnclosingMT->ContainsGenericVariables()); + + // Allocate space for the local class if necessary, but don't trigger + // class construction. + DomainLocalModule* pLocalModule = pEnclosingMT->GetDomainLocalModule(); + pLocalModule->PopulateClass(pEnclosingMT); + + if (!field->IsThreadStatic() && pEnclosingMT->IsClassInited() && IsFdInitOnly(field->GetAttributes())) + { + GCX_COOP(); + if (field->IsObjRef()) + { + OBJECTREF fieldObj = field->GetStaticOBJECTREF(); + if (fieldObj != NULL) + { + Object* obj = OBJECTREFToObject(fieldObj); + if (GCHeapUtilities::GetGCHeap()->IsInFrozenSegment(obj)) + { + intptr_t ptr = (intptr_t)obj; + memcpy(buffer, &ptr, sizeof(intptr_t)); + result = true; + } + } + else + { + memset(buffer, 0, sizeof(intptr_t)); + result = true; + } + } + else + { + void* fldAddr = field->GetCurrentStaticAddress(); + _ASSERTE(fldAddr != nullptr); + memcpy(buffer, fldAddr, bufferSize); + result = true; + } + } + + EE_TO_JIT_TRANSITION(); + + return result; +} + /*********************************************************************/ CORINFO_CLASS_HANDLE CEEJitInfo::getStaticFieldCurrentClass(CORINFO_FIELD_HANDLE fieldHnd, bool* pIsSpeculative)