diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 66a4e46063fab..7b830a1e306e7 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -3224,7 +3224,7 @@ class ICorDynamicInfo : public ICorStaticInfo ) = 0; //------------------------------------------------------------------------------ - // getReadonlyStaticFieldValue: returns true and the actual field's value if the given + // getStaticFieldContent: returns true and the actual field's value if the given // field represents a statically initialized readonly field of any type. // // Arguments: @@ -3236,7 +3236,7 @@ class ICorDynamicInfo : public ICorStaticInfo // Return Value: // Returns true if field's constant value was available and successfully copied to buffer // - virtual bool getReadonlyStaticFieldValue( + virtual bool getStaticFieldContent( CORINFO_FIELD_HANDLE field, uint8_t *buffer, int bufferSize, @@ -3244,6 +3244,13 @@ class ICorDynamicInfo : public ICorStaticInfo bool ignoreMovableObjects = true ) = 0; + virtual bool getObjectContent( + CORINFO_OBJECT_HANDLE obj, + uint8_t* buffer, + int bufferSize, + int valueOffset + ) = 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 e053b3d2f816f..18ea19b28df17 100644 --- a/src/coreclr/inc/icorjitinfoimpl_generated.h +++ b/src/coreclr/inc/icorjitinfoimpl_generated.h @@ -636,13 +636,19 @@ unsigned getClassDomainID( CORINFO_CLASS_HANDLE cls, void** ppIndirection) override; -bool getReadonlyStaticFieldValue( +bool getStaticFieldContent( CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects) override; +bool getObjectContent( + CORINFO_OBJECT_HANDLE obj, + uint8_t* buffer, + int bufferSize, + int valueOffset) 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 69d98159f440e..be6cc1e7f4f8d 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 = { /* 7925c4a8-129f-48ef-b48a-262d60ef84b0 */ - 0x7925c4a8, - 0x129f, - 0x48ef, - { 0xb4, 0x8a, 0x26, 0x2d, 0x60, 0xef, 0x84, 0xb0 } +constexpr GUID JITEEVersionIdentifier = { /* 387bcec3-9a71-4422-a11c-e7ce3b73c592 */ + 0x387bcec3, + 0x9a71, + 0x4422, + {0xa1, 0x1c, 0xe7, 0xce, 0x3b, 0x73, 0xc5, 0x92} }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/coreclr/jit/ICorJitInfo_names_generated.h b/src/coreclr/jit/ICorJitInfo_names_generated.h index 6a9f0408fb82a..e554312dedb64 100644 --- a/src/coreclr/jit/ICorJitInfo_names_generated.h +++ b/src/coreclr/jit/ICorJitInfo_names_generated.h @@ -159,7 +159,8 @@ DEF_CLR_API(getCallInfo) DEF_CLR_API(canAccessFamily) DEF_CLR_API(isRIDClassDomainID) DEF_CLR_API(getClassDomainID) -DEF_CLR_API(getReadonlyStaticFieldValue) +DEF_CLR_API(getStaticFieldContent) +DEF_CLR_API(getObjectContent) DEF_CLR_API(getStaticFieldCurrentClass) DEF_CLR_API(getVarArgsHandle) DEF_CLR_API(canGetVarArgsHandle) diff --git a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp index 1b3aa470acf33..26aa42f752260 100644 --- a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp +++ b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp @@ -1522,16 +1522,28 @@ unsigned WrapICorJitInfo::getClassDomainID( return temp; } -bool WrapICorJitInfo::getReadonlyStaticFieldValue( +bool WrapICorJitInfo::getStaticFieldContent( CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects) { - API_ENTER(getReadonlyStaticFieldValue); - bool temp = wrapHnd->getReadonlyStaticFieldValue(field, buffer, bufferSize, valueOffset, ignoreMovableObjects); - API_LEAVE(getReadonlyStaticFieldValue); + API_ENTER(getStaticFieldContent); + bool temp = wrapHnd->getStaticFieldContent(field, buffer, bufferSize, valueOffset, ignoreMovableObjects); + API_LEAVE(getStaticFieldContent); + return temp; +} + +bool WrapICorJitInfo::getObjectContent( + CORINFO_OBJECT_HANDLE obj, + uint8_t* buffer, + int bufferSize, + int valueOffset) +{ + API_ENTER(getObjectContent); + bool temp = wrapHnd->getObjectContent(obj, buffer, bufferSize, valueOffset); + API_LEAVE(getObjectContent); return temp; } diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 5a82719562fed..ad16d27762867 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -3869,7 +3869,7 @@ GenTree* Compiler::impImportStaticReadOnlyField(CORINFO_FIELD_HANDLE field, CORI if (varTypeIsIntegral(fieldType) || varTypeIsFloating(fieldType) || (fieldType == TYP_REF)) { assert(bufferSize >= genTypeSize(fieldType)); - if (info.compCompHnd->getReadonlyStaticFieldValue(field, buffer, genTypeSize(fieldType))) + if (info.compCompHnd->getStaticFieldContent(field, buffer, genTypeSize(fieldType))) { GenTree* cnsValue = impImportCnsTreeFromBuffer(buffer, fieldType); if (cnsValue != nullptr) @@ -3899,7 +3899,7 @@ GenTree* Compiler::impImportStaticReadOnlyField(CORINFO_FIELD_HANDLE field, CORI } uint8_t buffer[MaxStructSize] = {0}; - if (info.compCompHnd->getReadonlyStaticFieldValue(field, buffer, totalSize)) + if (info.compCompHnd->getStaticFieldContent(field, buffer, totalSize)) { #ifdef FEATURE_SIMD // First, let's check whether field is a SIMD vector and import it as GT_CNS_VEC @@ -3949,7 +3949,7 @@ GenTree* Compiler::impImportStaticReadOnlyField(CORINFO_FIELD_HANDLE field, CORI return gtNewLclvNode(structTempNum, realType); } - JITDUMP("getReadonlyStaticFieldValue returned false - bail out."); + JITDUMP("getStaticFieldContent returned false - bail out."); return nullptr; } @@ -3980,7 +3980,7 @@ GenTree* Compiler::impImportStaticReadOnlyField(CORINFO_FIELD_HANDLE field, CORI const int bufferSize = TARGET_POINTER_SIZE; uint8_t buffer[bufferSize] = {0}; - if ((totalSize > bufferSize) || !info.compCompHnd->getReadonlyStaticFieldValue(field, buffer, totalSize)) + if ((totalSize > bufferSize) || !info.compCompHnd->getStaticFieldContent(field, buffer, totalSize)) { return nullptr; } diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index 9b580f69c672a..3d258bdb8263e 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -1876,6 +1876,113 @@ ValueNum ValueNumStore::VNForSimd64Con(simd64_t cnsVal) #endif // TARGET_XARCH #endif // FEATURE_SIMD +ValueNum ValueNumStore::VNForGenericCon(var_types typ, uint8_t* cnsVal) +{ + // For now we only support these primitives, we can extend this list to FP, SIMD and structs in future. + switch (typ) + { +#define READ_VALUE(typ) \ + typ val = {}; \ + memcpy(&val, cnsVal, sizeof(typ)); + + case TYP_BOOL: + case TYP_UBYTE: + { + READ_VALUE(uint8_t); + return VNForIntCon(val); + } + case TYP_BYTE: + { + READ_VALUE(int8_t); + return VNForIntCon(val); + } + case TYP_SHORT: + { + READ_VALUE(int16_t); + return VNForIntCon(val); + } + case TYP_USHORT: + { + READ_VALUE(uint16_t); + return VNForIntCon(val); + } + case TYP_INT: + { + READ_VALUE(int32_t); + return VNForIntCon(val); + } + case TYP_UINT: + { + READ_VALUE(uint32_t); + return VNForIntCon(val); + } + case TYP_LONG: + { + READ_VALUE(int64_t); + return VNForLongCon(val); + } + case TYP_ULONG: + { + READ_VALUE(uint64_t); + return VNForLongCon(val); + } + case TYP_FLOAT: + { + READ_VALUE(float); + return VNForFloatCon(val); + } + case TYP_DOUBLE: + { + READ_VALUE(double); + return VNForDoubleCon(val); + } + case TYP_REF: + { + READ_VALUE(ssize_t); + if (val == 0) + { + return VNForNull(); + } + else + { + return VNForHandle(val, GTF_ICON_OBJ_HDL); + } + } +#if defined(FEATURE_SIMD) + case TYP_SIMD8: + { + READ_VALUE(simd8_t); + return VNForSimd8Con(val); + } + case TYP_SIMD12: + { + READ_VALUE(simd12_t); + return VNForSimd12Con(val); + } + case TYP_SIMD16: + { + READ_VALUE(simd16_t); + return VNForSimd16Con(val); + } +#if defined(TARGET_XARCH) + case TYP_SIMD32: + { + READ_VALUE(simd32_t); + return VNForSimd32Con(val); + } + case TYP_SIMD64: + { + READ_VALUE(simd64_t); + return VNForSimd64Con(val); + } +#endif // TARGET_XARCH +#endif // FEATURE_SIMD + default: + unreached(); + break; + } +} + ValueNum ValueNumStore::VNForCastOper(var_types castToType, bool srcIsUnsigned) { assert(castToType != TYP_STRUCT); @@ -2284,7 +2391,7 @@ ValueNum ValueNumStore::VNForFunc(var_types typ, VNFunc func, ValueNum arg0VN) { // Case 1: ARR_LENGTH(FROZEN_OBJ) ValueNum addressVN = VNNormalValue(arg0VN); - if (IsVNHandle(addressVN) && (GetHandleFlags(addressVN) == GTF_ICON_OBJ_HDL)) + if (IsVNObjHandle(addressVN)) { size_t handle = CoercedConstantValue(addressVN); int len = m_pComp->info.compCompHnd->getArrayOrStringLength((CORINFO_OBJECT_HANDLE)handle); @@ -2308,8 +2415,8 @@ ValueNum ValueNumStore::VNForFunc(var_types typ, VNFunc func, ValueNum arg0VN) if (field != NULL) { uint8_t buffer[TARGET_POINTER_SIZE] = {0}; - if (m_pComp->info.compCompHnd->getReadonlyStaticFieldValue(field, buffer, - TARGET_POINTER_SIZE, 0, false)) + if (m_pComp->info.compCompHnd->getStaticFieldContent(field, buffer, TARGET_POINTER_SIZE, 0, + false)) { // In case of 64bit jit emitting 32bit codegen this handle will be 64bit // value holding 32bit handle with upper half zeroed (hence, "= NULL"). @@ -5810,6 +5917,11 @@ bool ValueNumStore::IsVNHandle(ValueNum vn) return c->m_attribs == CEA_Handle; } +bool ValueNumStore::IsVNObjHandle(ValueNum vn) +{ + return IsVNHandle(vn) && GetHandleFlags(vn) == GTF_ICON_OBJ_HDL; +} + //------------------------------------------------------------------------ // SwapRelop: return VNFunc for swapped relop // @@ -10165,12 +10277,14 @@ static bool GetStaticFieldSeqAndAddress(ValueNumStore* vnStore, GenTree* tree, s } ssize_t val = 0; - // Special case for NativeAOT: ADD(ICON_STATIC, CNS_INT) where CNS_INT has field sequence corresponding to field's - // offset - if (tree->OperIs(GT_ADD) && tree->gtGetOp1()->IsIconHandle(GTF_ICON_STATIC_HDL) && tree->gtGetOp2()->IsCnsIntOrI()) + // Special cases for NativeAOT: + // ADD(ICON_STATIC, CNS_INT) // nonGC-static base + // ADD(IND(ICON_STATIC_ADDR_PTR), CNS_INT) // GC-static base + // where CNS_INT has field sequence corresponding to field's offset + if (tree->OperIs(GT_ADD) && tree->gtGetOp2()->IsCnsIntOrI() && !tree->gtGetOp2()->IsIconHandle()) { GenTreeIntCon* cns2 = tree->gtGetOp2()->AsIntCon(); - if (cns2->gtFieldSeq != nullptr) + if ((cns2->gtFieldSeq != nullptr) && (cns2->gtFieldSeq->GetKind() == FieldSeq::FieldKind::SimpleStatic)) { *byteOffset = cns2->IconValue() - cns2->gtFieldSeq->GetOffset(); *pFseq = cns2->gtFieldSeq; @@ -10221,6 +10335,61 @@ static bool GetStaticFieldSeqAndAddress(ValueNumStore* vnStore, GenTree* tree, s return false; } +//---------------------------------------------------------------------------------- +// GetObjectHandleAndOffset: Try to obtain a constant object handle with an offset from +// the given tree. +// +// Arguments: +// vnStore - ValueNumStore object +// tree - tree node to inspect +// byteOffset - [Out] resulting byte offset +// pObj - [Out] constant object handle +// +// Return Value: +// true if the given tree is a ObjHandle + CNS +// +static bool GetObjectHandleAndOffset(ValueNumStore* vnStore, + GenTree* tree, + ssize_t* byteOffset, + CORINFO_OBJECT_HANDLE* pObj) +{ + + if (!tree->gtVNPair.BothEqual()) + { + return false; + } + + ValueNum treeVN = tree->gtVNPair.GetLiberal(); + VNFuncApp funcApp; + if (vnStore->GetVNFunc(treeVN, &funcApp) && (funcApp.m_func == (VNFunc)GT_ADD)) + { + // [objHandle + offset] + if (vnStore->IsVNObjHandle(funcApp.m_args[0]) && vnStore->IsVNConstant(funcApp.m_args[1])) + { + *pObj = vnStore->ConstantObjHandle(funcApp.m_args[0]); + *byteOffset = vnStore->ConstantValue(funcApp.m_args[1]); + return true; + } + + // [offset + objHandle] + // TODO: Introduce a general helper to accumulate offsets for + // shapes such as (((X + CNS1) + CNS2) + CNS3) etc. + if (vnStore->IsVNObjHandle(funcApp.m_args[1]) && vnStore->IsVNConstant(funcApp.m_args[0])) + { + *pObj = vnStore->ConstantObjHandle(funcApp.m_args[1]); + *byteOffset = vnStore->ConstantValue(funcApp.m_args[0]); + return true; + } + } + else if (vnStore->IsVNObjHandle(treeVN)) + { + *pObj = vnStore->ConstantObjHandle(treeVN); + *byteOffset = 0; + return true; + } + return false; +} + //---------------------------------------------------------------------------------- // fgValueNumberConstLoad: Try to detect const_immutable_array[cns_index] tree // and apply a constant VN representing given element at cns_index in that array. @@ -10244,139 +10413,45 @@ bool Compiler::fgValueNumberConstLoad(GenTreeIndir* tree) // // sbyte GetVal() => RVA[1]; // fold to '100' // - ssize_t byteOffset = 0; - FieldSeq* fieldSeq = nullptr; + ssize_t byteOffset = 0; + FieldSeq* fieldSeq = nullptr; + CORINFO_OBJECT_HANDLE obj = nullptr; + int size = (int)genTypeSize(tree->TypeGet()); + const int maxElementSize = sizeof(simd_t); + if ((varTypeIsSIMD(tree) || varTypeIsIntegral(tree) || varTypeIsFloating(tree) || tree->TypeIs(TYP_REF)) && GetStaticFieldSeqAndAddress(vnStore, tree->gtGetOp1(), &byteOffset, &fieldSeq)) { - CORINFO_FIELD_HANDLE fieldHandle = fieldSeq->GetFieldHandle(); - int size = (int)genTypeSize(tree->TypeGet()); - const int maxElementSize = sizeof(simd_t); + CORINFO_FIELD_HANDLE fieldHandle = fieldSeq->GetFieldHandle(); if ((fieldHandle != nullptr) && (size > 0) && (size <= maxElementSize) && ((size_t)byteOffset < INT_MAX)) { uint8_t buffer[maxElementSize] = {0}; - if (info.compCompHnd->getReadonlyStaticFieldValue(fieldHandle, (uint8_t*)&buffer, size, (int)byteOffset)) + if (info.compCompHnd->getStaticFieldContent(fieldHandle, buffer, size, (int)byteOffset)) { - // For now we only support these primitives, we can extend this list to FP, SIMD and structs in future. - switch (tree->TypeGet()) + ValueNum vn = vnStore->VNForGenericCon(tree->TypeGet(), buffer); + if (vnStore->IsVNObjHandle(vn)) { -#define READ_VALUE(typ) \ - typ val = {}; \ - memcpy(&val, buffer, sizeof(typ)); - - case TYP_BOOL: - case TYP_UBYTE: - { - READ_VALUE(uint8_t); - tree->gtVNPair.SetBoth(vnStore->VNForIntCon(val)); - return true; - } - case TYP_BYTE: - { - READ_VALUE(int8_t); - tree->gtVNPair.SetBoth(vnStore->VNForIntCon(val)); - return true; - } - case TYP_SHORT: - { - READ_VALUE(int16_t); - tree->gtVNPair.SetBoth(vnStore->VNForIntCon(val)); - return true; - } - case TYP_USHORT: - { - READ_VALUE(uint16_t); - tree->gtVNPair.SetBoth(vnStore->VNForIntCon(val)); - return true; - } - case TYP_INT: - { - READ_VALUE(int32_t); - tree->gtVNPair.SetBoth(vnStore->VNForIntCon(val)); - return true; - } - case TYP_UINT: - { - READ_VALUE(uint32_t); - tree->gtVNPair.SetBoth(vnStore->VNForIntCon(val)); - return true; - } - case TYP_LONG: - { - READ_VALUE(int64_t); - tree->gtVNPair.SetBoth(vnStore->VNForLongCon(val)); - return true; - } - case TYP_ULONG: - { - READ_VALUE(uint64_t); - tree->gtVNPair.SetBoth(vnStore->VNForLongCon(val)); - return true; - } - case TYP_FLOAT: - { - READ_VALUE(float); - tree->gtVNPair.SetBoth(vnStore->VNForFloatCon(val)); - return true; - } - case TYP_DOUBLE: - { - READ_VALUE(double); - tree->gtVNPair.SetBoth(vnStore->VNForDoubleCon(val)); - return true; - } - case TYP_REF: - { - READ_VALUE(ssize_t); - if (val == 0) - { - tree->gtVNPair.SetBoth(vnStore->VNForNull()); - } - else - { - tree->gtVNPair.SetBoth(vnStore->VNForHandle(val, GTF_ICON_OBJ_HDL)); - setMethodHasFrozenObjects(); - } - return true; - } -#if defined(FEATURE_SIMD) - case TYP_SIMD8: - { - READ_VALUE(simd8_t); - tree->gtVNPair.SetBoth(vnStore->VNForSimd8Con(val)); - return true; - } - case TYP_SIMD12: - { - READ_VALUE(simd12_t); - tree->gtVNPair.SetBoth(vnStore->VNForSimd12Con(val)); - return true; - } - case TYP_SIMD16: - { - READ_VALUE(simd16_t); - tree->gtVNPair.SetBoth(vnStore->VNForSimd16Con(val)); - return true; - } -#if defined(TARGET_XARCH) - case TYP_SIMD32: - { - READ_VALUE(simd32_t); - tree->gtVNPair.SetBoth(vnStore->VNForSimd32Con(val)); - return true; - } - case TYP_SIMD64: - { - READ_VALUE(simd64_t); - tree->gtVNPair.SetBoth(vnStore->VNForSimd64Con(val)); - return true; - } -#endif // TARGET_XARCH -#endif // FEATURE_SIMD - default: - assert(!varTypeIsSIMD(tree)); - break; + setMethodHasFrozenObjects(); } + tree->gtVNPair.SetBoth(vn); + return true; + } + } + } + else if ((varTypeIsSIMD(tree) || varTypeIsIntegral(tree) || varTypeIsFloating(tree)) && + GetObjectHandleAndOffset(vnStore, tree->gtGetOp1(), &byteOffset, &obj)) + { + // See if we can fold IND(ADD(FrozenObj, CNS)) to a constant + assert(obj != nullptr); + if ((size > 0) && (size <= maxElementSize) && ((size_t)byteOffset < INT_MAX)) + { + uint8_t buffer[maxElementSize] = {0}; + if (info.compCompHnd->getObjectContent(obj, buffer, size, (int)byteOffset)) + { + ValueNum vn = vnStore->VNForGenericCon(tree->TypeGet(), buffer); + assert(!vnStore->IsVNObjHandle(vn)); + tree->gtVNPair.SetBoth(vn); + return true; } } } @@ -10396,10 +10471,9 @@ bool Compiler::fgValueNumberConstLoad(GenTreeIndir* tree) // Is given VN representing a frozen object handle auto isCnsObjHandle = [](ValueNumStore* vnStore, ValueNum vn, CORINFO_OBJECT_HANDLE* handle) -> bool { - if (vnStore->IsVNHandle(vn) && (vnStore->GetHandleFlags(vn) == GTF_ICON_OBJ_HDL)) + if (vnStore->IsVNObjHandle(vn)) { - const size_t obj = vnStore->CoercedConstantValue(vn); - *handle = reinterpret_cast(obj); + *handle = vnStore->ConstantObjHandle(vn); return true; } return false; diff --git a/src/coreclr/jit/valuenum.h b/src/coreclr/jit/valuenum.h index 31ebe77ed9a18..c4f9a2918c0a3 100644 --- a/src/coreclr/jit/valuenum.h +++ b/src/coreclr/jit/valuenum.h @@ -442,6 +442,7 @@ class ValueNumStore ValueNum VNForSimd64Con(simd64_t cnsVal); #endif // TARGET_XARCH #endif // FEATURE_SIMD + ValueNum VNForGenericCon(var_types typ, uint8_t* cnsVal); #ifdef TARGET_64BIT ValueNum VNForPtrSizeIntCon(INT64 cnsVal) @@ -990,6 +991,9 @@ class ValueNumStore // Returns true iff the VN represents a handle constant. bool IsVNHandle(ValueNum vn); + // Returns true iff the VN represents an object handle constant. + bool IsVNObjHandle(ValueNum vn); + // Returns true iff the VN represents a relop bool IsVNRelop(ValueNum vn); @@ -1120,6 +1124,12 @@ class ValueNumStore return ConstantValueInternal(vn DEBUGARG(true)); } + CORINFO_OBJECT_HANDLE ConstantObjHandle(ValueNum vn) + { + assert(IsVNObjHandle(vn)); + return reinterpret_cast(CoercedConstantValue(vn)); + } + // Requires "mthFunc" to be an intrinsic math function (one of the allowable values for the "gtMath" field // of a GenTreeMath node). For unary ops, return the value number for the application of this function to // "arg0VN". For binary ops, return the value number for the application of this function to "arg0VN" and diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs index 26b637ef6357d..55c7d70b6618a 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs @@ -2303,12 +2303,27 @@ 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, int valueOffset, byte ignoreMovableObjects) + private static byte _getStaticFieldContent(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field, byte* buffer, int bufferSize, int valueOffset, byte ignoreMovableObjects) { var _this = GetThis(thisHandle); try { - return _this.getReadonlyStaticFieldValue(field, buffer, bufferSize, valueOffset, ignoreMovableObjects != 0) ? (byte)1 : (byte)0; + return _this.getStaticFieldContent(field, buffer, bufferSize, valueOffset, ignoreMovableObjects != 0) ? (byte)1 : (byte)0; + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default; + } + } + + [UnmanagedCallersOnly] + private static byte _getObjectContent(IntPtr thisHandle, IntPtr* ppException, CORINFO_OBJECT_STRUCT_* obj, byte* buffer, int bufferSize, int valueOffset) + { + var _this = GetThis(thisHandle); + try + { + return _this.getObjectContent(obj, buffer, bufferSize, valueOffset) ? (byte)1 : (byte)0; } catch (Exception ex) { @@ -2730,7 +2745,7 @@ private static uint _getJitFlags(IntPtr thisHandle, IntPtr* ppException, CORJIT_ private static IntPtr GetUnmanagedCallbacks() { - void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 184); + void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 185); callbacks[0] = (delegate* unmanaged)&_isIntrinsic; callbacks[1] = (delegate* unmanaged)&_getMethodAttribs; @@ -2887,35 +2902,36 @@ private static IntPtr GetUnmanagedCallbacks() callbacks[152] = (delegate* unmanaged)&_canAccessFamily; callbacks[153] = (delegate* unmanaged)&_isRIDClassDomainID; callbacks[154] = (delegate* unmanaged)&_getClassDomainID; - callbacks[155] = (delegate* unmanaged)&_getReadonlyStaticFieldValue; - callbacks[156] = (delegate* unmanaged)&_getStaticFieldCurrentClass; - callbacks[157] = (delegate* unmanaged)&_getVarArgsHandle; - callbacks[158] = (delegate* unmanaged)&_canGetVarArgsHandle; - callbacks[159] = (delegate* unmanaged)&_constructStringLiteral; - callbacks[160] = (delegate* unmanaged)&_emptyStringLiteral; - callbacks[161] = (delegate* unmanaged)&_getFieldThreadLocalStoreID; - callbacks[162] = (delegate* unmanaged)&_GetDelegateCtor; - callbacks[163] = (delegate* unmanaged)&_MethodCompileComplete; - callbacks[164] = (delegate* unmanaged)&_getTailCallHelpers; - callbacks[165] = (delegate* unmanaged)&_convertPInvokeCalliToCall; - callbacks[166] = (delegate* unmanaged)&_notifyInstructionSetUsage; - callbacks[167] = (delegate* unmanaged)&_updateEntryPointForTailCall; - callbacks[168] = (delegate* unmanaged)&_allocMem; - callbacks[169] = (delegate* unmanaged)&_reserveUnwindInfo; - callbacks[170] = (delegate* unmanaged)&_allocUnwindInfo; - callbacks[171] = (delegate* unmanaged)&_allocGCInfo; - callbacks[172] = (delegate* unmanaged)&_setEHcount; - callbacks[173] = (delegate* unmanaged)&_setEHinfo; - callbacks[174] = (delegate* unmanaged)&_logMsg; - callbacks[175] = (delegate* unmanaged)&_doAssert; - callbacks[176] = (delegate* unmanaged)&_reportFatalError; - callbacks[177] = (delegate* unmanaged)&_getPgoInstrumentationResults; - callbacks[178] = (delegate* unmanaged)&_allocPgoInstrumentationBySchema; - callbacks[179] = (delegate* unmanaged)&_recordCallSite; - callbacks[180] = (delegate* unmanaged)&_recordRelocation; - callbacks[181] = (delegate* unmanaged)&_getRelocTypeHint; - callbacks[182] = (delegate* unmanaged)&_getExpectedTargetArchitecture; - callbacks[183] = (delegate* unmanaged)&_getJitFlags; + callbacks[155] = (delegate* unmanaged)&_getStaticFieldContent; + callbacks[156] = (delegate* unmanaged)&_getObjectContent; + callbacks[157] = (delegate* unmanaged)&_getStaticFieldCurrentClass; + callbacks[158] = (delegate* unmanaged)&_getVarArgsHandle; + callbacks[159] = (delegate* unmanaged)&_canGetVarArgsHandle; + callbacks[160] = (delegate* unmanaged)&_constructStringLiteral; + callbacks[161] = (delegate* unmanaged)&_emptyStringLiteral; + callbacks[162] = (delegate* unmanaged)&_getFieldThreadLocalStoreID; + callbacks[163] = (delegate* unmanaged)&_GetDelegateCtor; + callbacks[164] = (delegate* unmanaged)&_MethodCompileComplete; + callbacks[165] = (delegate* unmanaged)&_getTailCallHelpers; + callbacks[166] = (delegate* unmanaged)&_convertPInvokeCalliToCall; + callbacks[167] = (delegate* unmanaged)&_notifyInstructionSetUsage; + callbacks[168] = (delegate* unmanaged)&_updateEntryPointForTailCall; + callbacks[169] = (delegate* unmanaged)&_allocMem; + callbacks[170] = (delegate* unmanaged)&_reserveUnwindInfo; + callbacks[171] = (delegate* unmanaged)&_allocUnwindInfo; + callbacks[172] = (delegate* unmanaged)&_allocGCInfo; + callbacks[173] = (delegate* unmanaged)&_setEHcount; + callbacks[174] = (delegate* unmanaged)&_setEHinfo; + callbacks[175] = (delegate* unmanaged)&_logMsg; + callbacks[176] = (delegate* unmanaged)&_doAssert; + callbacks[177] = (delegate* unmanaged)&_reportFatalError; + callbacks[178] = (delegate* unmanaged)&_getPgoInstrumentationResults; + callbacks[179] = (delegate* unmanaged)&_allocPgoInstrumentationBySchema; + callbacks[180] = (delegate* unmanaged)&_recordCallSite; + callbacks[181] = (delegate* unmanaged)&_recordRelocation; + callbacks[182] = (delegate* unmanaged)&_getRelocTypeHint; + callbacks[183] = (delegate* unmanaged)&_getExpectedTargetArchitecture; + callbacks[184] = (delegate* unmanaged)&_getJitFlags; return (IntPtr)callbacks; } diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt index 5c4d8ad0b94b1..870d86df9136d 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -314,7 +314,8 @@ FUNCTIONS bool canAccessFamily(CORINFO_METHOD_HANDLE hCaller, CORINFO_CLASS_HANDLE hInstanceType); bool isRIDClassDomainID(CORINFO_CLASS_HANDLE cls); unsigned getClassDomainID (CORINFO_CLASS_HANDLE cls, void **ppIndirection); - bool getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint8_t *buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects); + bool getStaticFieldContent(CORINFO_FIELD_HANDLE field, uint8_t *buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects); + bool getObjectContent(CORINFO_OBJECT_HANDLE obj, uint8_t *buffer, int bufferSize, int valueOffset); 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.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs index c40ee03d8fb05..e0617683dce46 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs @@ -3015,7 +3015,7 @@ private int getExactClasses(CORINFO_CLASS_STRUCT_* baseType, int maxExactClasses return 0; } - private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byte* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects) + private bool getStaticFieldContent(CORINFO_FIELD_STRUCT_* fieldHandle, byte* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects) { Debug.Assert(fieldHandle != null); FieldDesc field = HandleToObject(fieldHandle); @@ -3028,6 +3028,11 @@ private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byt return false; } + private bool getObjectContent(CORINFO_OBJECT_STRUCT_* obj, byte* buffer, int bufferSize, int valueOffset) + { + throw new NotSupportedException(); + } + private CORINFO_CLASS_STRUCT_* getObjectType(CORINFO_OBJECT_STRUCT_* objPtr) { throw new NotSupportedException(); 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 b336eb9665e61..8d0b4de86d843 100644 --- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs +++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs @@ -2240,7 +2240,7 @@ private int getExactClasses(CORINFO_CLASS_STRUCT_* baseType, int maxExactClasses return index; } - private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byte* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects) + private bool getStaticFieldContent(CORINFO_FIELD_STRUCT_* fieldHandle, byte* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects) { Debug.Assert(fieldHandle != null); Debug.Assert(buffer != null); @@ -2303,6 +2303,33 @@ private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byt return false; } + private bool getObjectContent(CORINFO_OBJECT_STRUCT_* objPtr, byte* buffer, int bufferSize, int valueOffset) + { + Debug.Assert(objPtr != null); + Debug.Assert(buffer != null); + Debug.Assert(bufferSize >= 0); + Debug.Assert(valueOffset >= 0); + + object obj = HandleToObject(objPtr); + if (obj is FrozenStringNode frozenStr) + { + // Only support reading the string data + int strDataOffset = _compilation.TypeSystemContext.Target.PointerSize + sizeof(int); // 12 on 64bit + if (valueOffset >= strDataOffset && (long)frozenStr.Data.Length * 2 >= (valueOffset - strDataOffset) + bufferSize) + { + int offset = valueOffset - strDataOffset; + fixed (char* pStr = frozenStr.Data) + { + new Span((byte*)pStr + offset, bufferSize).CopyTo( + new Span(buffer, bufferSize)); + return true; + } + } + } + // TODO: handle FrozenObjectNode + return false; + } + private CORINFO_CLASS_STRUCT_* getObjectType(CORINFO_OBJECT_STRUCT_* objPtr) { object obj = HandleToObject(objPtr); diff --git a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h index bc1f1383c2966..038abebbeceac 100644 --- a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h +++ b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h @@ -166,7 +166,8 @@ struct JitInterfaceCallbacks bool (* canAccessFamily)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE hCaller, CORINFO_CLASS_HANDLE hInstanceType); bool (* isRIDClassDomainID)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls); unsigned (* getClassDomainID)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls, void** ppIndirection); - bool (* getReadonlyStaticFieldValue)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects); + bool (* getStaticFieldContent)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects); + bool (* getObjectContent)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_OBJECT_HANDLE obj, uint8_t* buffer, int bufferSize, int valueOffset); 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); @@ -1702,7 +1703,7 @@ class JitInterfaceWrapper : public ICorJitInfo return temp; } - virtual bool getReadonlyStaticFieldValue( + virtual bool getStaticFieldContent( CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, @@ -1710,7 +1711,19 @@ class JitInterfaceWrapper : public ICorJitInfo bool ignoreMovableObjects) { CorInfoExceptionClass* pException = nullptr; - bool temp = _callbacks->getReadonlyStaticFieldValue(_thisHandle, &pException, field, buffer, bufferSize, valueOffset, ignoreMovableObjects); + bool temp = _callbacks->getStaticFieldContent(_thisHandle, &pException, field, buffer, bufferSize, valueOffset, ignoreMovableObjects); + if (pException != nullptr) throw pException; + return temp; +} + + virtual bool getObjectContent( + CORINFO_OBJECT_HANDLE obj, + uint8_t* buffer, + int bufferSize, + int valueOffset) +{ + CorInfoExceptionClass* pException = nullptr; + bool temp = _callbacks->getObjectContent(_thisHandle, &pException, obj, buffer, bufferSize, valueOffset); if (pException != nullptr) throw pException; return temp; } diff --git a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h index f079877342882..0a26a5d05774f 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h @@ -81,7 +81,8 @@ LWM(GetDefaultEqualityComparerClass, DWORDLONG, DWORDLONG) LWM(GetDelegateCtor, Agnostic_GetDelegateCtorIn, Agnostic_GetDelegateCtorOut) LWM(GetEEInfo, DWORD, Agnostic_CORINFO_EE_INFO) LWM(GetEHinfo, DLD, Agnostic_CORINFO_EH_CLAUSE) -LWM(GetReadonlyStaticFieldValue, DLDDD, DD) +LWM(GetStaticFieldContent, DLDDD, DD) +LWM(GetObjectContent, DLDD, DD) LWM(GetStaticFieldCurrentClass, DLD, Agnostic_GetStaticFieldCurrentClass) LWM(GetFieldClass, DWORDLONG, DWORDLONG) LWM(GetFieldInClass, DLD, DWORDLONG) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index 7680c8685fe8f..43032b7616103 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -3727,10 +3727,10 @@ CORINFO_METHOD_HANDLE MethodContext::repEmbedMethodHandle(CORINFO_METHOD_HANDLE return (CORINFO_METHOD_HANDLE)value.B; } -void MethodContext::recGetReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects, bool result) +void MethodContext::recGetStaticFieldContent(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects, bool result) { - if (GetReadonlyStaticFieldValue == nullptr) - GetReadonlyStaticFieldValue = new LightWeightMap(); + if (GetStaticFieldContent == nullptr) + GetStaticFieldContent = new LightWeightMap(); DLDDD key; ZeroMemory(&key, sizeof(key)); @@ -3741,21 +3741,21 @@ void MethodContext::recGetReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, u DWORD tmpBuf = (DWORD)-1; if (buffer != nullptr && result) - tmpBuf = (DWORD)GetReadonlyStaticFieldValue->AddBuffer((uint8_t*)buffer, (uint32_t)bufferSize); + tmpBuf = (DWORD)GetStaticFieldContent->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)); + GetStaticFieldContent->Add(key, value); + DEBUG_REC(dmpGetStaticFieldContent(key, value)); } -void MethodContext::dmpGetReadonlyStaticFieldValue(DLDDD key, DD value) +void MethodContext::dmpGetStaticFieldContent(DLDDD key, DD value) { - printf("GetReadonlyStaticFieldValue key fld-%016" PRIX64 " bufSize-%u, ignoremovable-%u, valOffset-%u result-%u", key.A, key.B, key.C, key.D, value.A); - GetReadonlyStaticFieldValue->Unlock(); + printf("GetStaticFieldContent key fld-%016" PRIX64 " bufSize-%u, ignoremovable-%u, valOffset-%u result-%u", key.A, key.B, key.C, key.D, value.A); + GetStaticFieldContent->Unlock(); } -bool MethodContext::repGetReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects) +bool MethodContext::repGetStaticFieldContent(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects) { DLDDD key; ZeroMemory(&key, sizeof(key)); @@ -3764,12 +3764,59 @@ bool MethodContext::repGetReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, u key.C = (DWORD)ignoreMovableObjects; key.D = (DWORD)valueOffset; - DD value = LookupByKeyOrMiss(GetReadonlyStaticFieldValue, key, ": key %016" PRIX64 "", key.A); + DD value = LookupByKeyOrMiss(GetStaticFieldContent, key, ": key %016" PRIX64 "", key.A); - DEBUG_REP(dmpGetReadonlyStaticFieldValue(key, value)); + DEBUG_REP(dmpGetStaticFieldContent(key, value)); if (buffer != nullptr && (bool)value.A) { - uint8_t* srcBuffer = (uint8_t*)GetReadonlyStaticFieldValue->GetBuffer(value.B); + uint8_t* srcBuffer = (uint8_t*)GetStaticFieldContent->GetBuffer(value.B); + Assert(srcBuffer != nullptr); + memcpy(buffer, srcBuffer, bufferSize); + } + return (bool)value.A; +} + +void MethodContext::recGetObjectContent(CORINFO_OBJECT_HANDLE obj, uint8_t* buffer, int bufferSize, int valueOffset, bool result) +{ + if (GetObjectContent == nullptr) + GetObjectContent = new LightWeightMap(); + + DLDD key; + ZeroMemory(&key, sizeof(key)); + key.A = CastHandle(obj); + key.B = (DWORD)bufferSize; + key.C = (DWORD)valueOffset; + + DWORD tmpBuf = (DWORD)-1; + if (buffer != nullptr && result) + tmpBuf = (DWORD)GetObjectContent->AddBuffer((uint8_t*)buffer, (uint32_t)bufferSize); + + DD value; + value.A = (DWORD)result; + value.B = (DWORD)tmpBuf; + + GetObjectContent->Add(key, value); + DEBUG_REC(dmpGetObjectContent(key, value)); +} +void MethodContext::dmpGetObjectContent(DLDD key, DD value) +{ + printf("GetObjectContent key fld-%016" PRIX64 " bufSize-%u, valOffset-%u result-%u", key.A, key.B, key.C, value.A); + GetObjectContent->Unlock(); +} +bool MethodContext::repGetObjectContent(CORINFO_OBJECT_HANDLE obj, uint8_t* buffer, int bufferSize, int valueOffset) +{ + DLDD key; + ZeroMemory(&key, sizeof(key)); + key.A = CastHandle(obj); + key.B = (DWORD)bufferSize; + key.C = (DWORD)valueOffset; + + DD value = LookupByKeyOrMiss(GetObjectContent, key, ": key %016" PRIX64 "", key.A); + + DEBUG_REP(dmpGetObjectContent(key, value)); + if (buffer != nullptr && (bool)value.A) + { + uint8_t* srcBuffer = (uint8_t*)GetObjectContent->GetBuffer(value.B); Assert(srcBuffer != nullptr); memcpy(buffer, srcBuffer, bufferSize); } diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h index 949d780b09089..d8935bb4f806b 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h @@ -497,9 +497,13 @@ class MethodContext void dmpEmbedMethodHandle(DWORDLONG key, DLDL value); CORINFO_METHOD_HANDLE repEmbedMethodHandle(CORINFO_METHOD_HANDLE handle, void** ppIndirection); - void recGetReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects, bool result); - void dmpGetReadonlyStaticFieldValue(DLDDD key, DD value); - bool repGetReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects); + void recGetStaticFieldContent(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects, bool result); + void dmpGetStaticFieldContent(DLDDD key, DD value); + bool repGetStaticFieldContent(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects); + + void recGetObjectContent(CORINFO_OBJECT_HANDLE obj, uint8_t* buffer, int bufferSize, int valueOffset, bool result); + void dmpGetObjectContent(DLDD key, DD value); + bool repGetObjectContent(CORINFO_OBJECT_HANDLE obj, uint8_t* buffer, int bufferSize, int valueOffset); void recGetStaticFieldCurrentClass(CORINFO_FIELD_HANDLE field, bool* pIsSpeculative, CORINFO_CLASS_HANDLE result); void dmpGetStaticFieldCurrentClass(DLD key, const Agnostic_GetStaticFieldCurrentClass& value); @@ -1175,7 +1179,7 @@ enum mcPackets Packet_GetExactClasses = 195, Packet_GetRuntimeTypePointer = 196, Packet_PrintObjectDescription = 197, - Packet_GetReadonlyStaticFieldValue = 198, + Packet_GetStaticFieldContent = 198, Packet_GetObjectType = 199, Packet_IsObjectImmutable = 200, Packet_ExpandRawHandleIntrinsic = 201, @@ -1187,6 +1191,7 @@ enum mcPackets Packet_GetThreadLocalFieldInfo = 207, Packet_GetThreadLocalStaticBlocksInfo = 208, Packet_GetRISCV64PassStructInRegisterFlags = 209, + Packet_GetObjectContent = 210, }; 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 c318a1a6481a4..6adbb6ac6f624 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -1743,11 +1743,19 @@ unsigned interceptor_ICJI::getClassDomainID(CORINFO_CLASS_HANDLE cls, void** ppI return temp; } -bool interceptor_ICJI::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects) +bool interceptor_ICJI::getStaticFieldContent(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects) { - mc->cr->AddCall("getReadonlyStaticFieldValue"); - bool result = original_ICorJitInfo->getReadonlyStaticFieldValue(field, buffer, bufferSize, valueOffset, ignoreMovableObjects); - mc->recGetReadonlyStaticFieldValue(field, buffer, bufferSize, valueOffset, ignoreMovableObjects, result); + mc->cr->AddCall("getStaticFieldContent"); + bool result = original_ICorJitInfo->getStaticFieldContent(field, buffer, bufferSize, valueOffset, ignoreMovableObjects); + mc->recGetStaticFieldContent(field, buffer, bufferSize, valueOffset, ignoreMovableObjects, result); + return result; +} + +bool interceptor_ICJI::getObjectContent(CORINFO_OBJECT_HANDLE obj, uint8_t* buffer, int bufferSize, int valueOffset) +{ + mc->cr->AddCall("getObjectContent"); + bool result = original_ICorJitInfo->getObjectContent(obj, buffer, bufferSize, valueOffset); + mc->recGetObjectContent(obj, buffer, bufferSize, valueOffset, result); return result; } diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp index ab0c006b8c3ce..e4aa9e7e69af8 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp @@ -1247,15 +1247,25 @@ unsigned interceptor_ICJI::getClassDomainID( return original_ICorJitInfo->getClassDomainID(cls, ppIndirection); } -bool interceptor_ICJI::getReadonlyStaticFieldValue( +bool interceptor_ICJI::getStaticFieldContent( CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects) { - mcs->AddCall("getReadonlyStaticFieldValue"); - return original_ICorJitInfo->getReadonlyStaticFieldValue(field, buffer, bufferSize, valueOffset, ignoreMovableObjects); + mcs->AddCall("getStaticFieldContent"); + return original_ICorJitInfo->getStaticFieldContent(field, buffer, bufferSize, valueOffset, ignoreMovableObjects); +} + +bool interceptor_ICJI::getObjectContent( + CORINFO_OBJECT_HANDLE obj, + uint8_t* buffer, + int bufferSize, + int valueOffset) +{ + mcs->AddCall("getObjectContent"); + return original_ICorJitInfo->getObjectContent(obj, buffer, bufferSize, valueOffset); } CORINFO_CLASS_HANDLE interceptor_ICJI::getStaticFieldCurrentClass( diff --git a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp index d8e33021f6286..d832d82b4f3b5 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp @@ -1092,14 +1092,23 @@ unsigned interceptor_ICJI::getClassDomainID( return original_ICorJitInfo->getClassDomainID(cls, ppIndirection); } -bool interceptor_ICJI::getReadonlyStaticFieldValue( +bool interceptor_ICJI::getStaticFieldContent( CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects) { - return original_ICorJitInfo->getReadonlyStaticFieldValue(field, buffer, bufferSize, valueOffset, ignoreMovableObjects); + return original_ICorJitInfo->getStaticFieldContent(field, buffer, bufferSize, valueOffset, ignoreMovableObjects); +} + +bool interceptor_ICJI::getObjectContent( + CORINFO_OBJECT_HANDLE obj, + uint8_t* buffer, + int bufferSize, + int valueOffset) +{ + return original_ICorJitInfo->getObjectContent(obj, buffer, bufferSize, valueOffset); } CORINFO_CLASS_HANDLE interceptor_ICJI::getStaticFieldCurrentClass( diff --git a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp index 693ea2fe00673..3b25e9ad9f076 100644 --- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp @@ -1515,10 +1515,16 @@ unsigned MyICJI::getClassDomainID(CORINFO_CLASS_HANDLE cls, void** ppIndirection return jitInstance->mc->repGetClassDomainID(cls, ppIndirection); } -bool MyICJI::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects) +bool MyICJI::getStaticFieldContent(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects) { - jitInstance->mc->cr->AddCall("getReadonlyStaticFieldValue"); - return jitInstance->mc->repGetReadonlyStaticFieldValue(field, buffer, bufferSize, valueOffset, ignoreMovableObjects); + jitInstance->mc->cr->AddCall("getStaticFieldContent"); + return jitInstance->mc->repGetStaticFieldContent(field, buffer, bufferSize, valueOffset, ignoreMovableObjects); +} + +bool MyICJI::getObjectContent(CORINFO_OBJECT_HANDLE obj, uint8_t* buffer, int bufferSize, int valueOffset) +{ + jitInstance->mc->cr->AddCall("getObjectContent"); + return jitInstance->mc->repGetObjectContent(obj, buffer, bufferSize, valueOffset); } // return the class handle for the current value of a static field diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index c7130d80419ba..30ba16e9770ea 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -11851,7 +11851,7 @@ InfoAccessType CEEJitInfo::emptyStringLiteral(void ** ppValue) return result; } -bool CEEInfo::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE fieldHnd, uint8_t* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects) +bool CEEInfo::getStaticFieldContent(CORINFO_FIELD_HANDLE fieldHnd, uint8_t* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects) { CONTRACTL { THROWS; @@ -11989,6 +11989,40 @@ bool CEEInfo::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE fieldHnd, uint8_t return result; } +bool CEEInfo::getObjectContent(CORINFO_OBJECT_HANDLE handle, uint8_t* buffer, int bufferSize, int valueOffset) +{ + CONTRACTL { + THROWS; + GC_TRIGGERS; + MODE_PREEMPTIVE; + } CONTRACTL_END; + + _ASSERT(handle != NULL); + _ASSERT(buffer != NULL); + _ASSERT(bufferSize > 0); + _ASSERT(valueOffset >= 0); + + bool result = false; + + JIT_TO_EE_TRANSITION(); + + GCX_COOP(); + OBJECTREF objRef = getObjectFromJitHandle(handle); + _ASSERTE(objRef != NULL); + + // TODO: support types containing GC pointers + if (!objRef->GetMethodTable()->ContainsPointers() && bufferSize + valueOffset <= (int)objRef->GetSize()) + { + Object* obj = OBJECTREFToObject(objRef); + memcpy(buffer, (uint8_t*)obj + valueOffset, bufferSize); + result = true; + } + + EE_TO_JIT_TRANSITION(); + + return result; +} + /*********************************************************************/ CORINFO_CLASS_HANDLE CEEJitInfo::getStaticFieldCurrentClass(CORINFO_FIELD_HANDLE fieldHnd, bool* pIsSpeculative) diff --git a/src/coreclr/vm/jitinterface.h b/src/coreclr/vm/jitinterface.h index 5f2fd20abda2a..73778a1ca6bab 100644 --- a/src/coreclr/vm/jitinterface.h +++ b/src/coreclr/vm/jitinterface.h @@ -422,6 +422,7 @@ class CEEInfo : public ICorJitInfo public: #include "icorjitinfoimpl_generated.h" uint32_t getClassAttribsInternal (CORINFO_CLASS_HANDLE cls); + bool isObjectImmutableInteral(OBJECTREF obj); static unsigned getClassAlignmentRequirementStatic(TypeHandle clsHnd); diff --git a/src/libraries/System.Memory/tests/MemoryMarshal/GetReference.cs b/src/libraries/System.Memory/tests/MemoryMarshal/GetReference.cs index f65ae5ba47550..d0e83a069d0b4 100644 --- a/src/libraries/System.Memory/tests/MemoryMarshal/GetReference.cs +++ b/src/libraries/System.Memory/tests/MemoryMarshal/GetReference.cs @@ -100,5 +100,17 @@ public static void ReadOnlySpanGetReferenceEmpty() Assert.True(Unsafe.AreSame(ref Unsafe.AsRef(null), ref pinnableReference)); } } + + [Fact] + public static void ReadOnlySpanGetReferenceAndReadInteger() + { + Assert.Equal(6619240, + Unsafe.As(ref Unsafe.Add(ref Unsafe.As( + ref MemoryMarshal.GetReference("hello world 1".AsSpan())), 0))); + + Assert.Equal(7998511687277765888, + Unsafe.As(ref Unsafe.Add(ref Unsafe.As( + ref MemoryMarshal.GetReference("hello world 2".AsSpan())), 1))); + } } }