From 0fdefe26bf33ee6050f4e1a8ce465b3fe64678ab Mon Sep 17 00:00:00 2001
From: EgorBo <egorbo@gmail.com>
Date: Sat, 24 Sep 2022 04:38:07 +0200
Subject: [PATCH 01/61] handle static readonly for frozen objects in jit

---
 src/coreclr/inc/corinfo.h                     |  5 ++
 src/coreclr/inc/icorjitinfoimpl_generated.h   |  3 +
 src/coreclr/inc/jiteeversionguid.h            | 10 +--
 src/coreclr/jit/ICorJitInfo_API_names.h       |  1 +
 src/coreclr/jit/ICorJitInfo_API_wrapper.hpp   |  9 +++
 src/coreclr/jit/importer.cpp                  | 43 +++++++----
 .../tools/Common/JitInterface/CorInfoBase.cs  | 76 +++++++++++--------
 .../tools/Common/JitInterface/CorInfoImpl.cs  |  7 ++
 .../ThunkGenerator/ThunkInput.txt             |  1 +
 .../tools/aot/jitinterface/jitinterface.h     | 10 +++
 .../tools/superpmi/superpmi-shared/lwmlist.h  |  1 +
 .../superpmi-shared/methodcontext.cpp         | 24 ++++++
 .../superpmi/superpmi-shared/methodcontext.h  |  5 ++
 .../superpmi-shim-collector/icorjitinfo.cpp   |  8 ++
 .../superpmi-shim-counter/icorjitinfo.cpp     |  7 ++
 .../superpmi-shim-simple/icorjitinfo.cpp      |  6 ++
 .../tools/superpmi/superpmi/icorjitinfo.cpp   |  6 ++
 src/coreclr/vm/jitinterface.cpp               | 42 ++++++++++
 src/coreclr/vm/jitinterface.h                 |  1 +
 19 files changed, 217 insertions(+), 48 deletions(-)

diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h
index 848e1a53314c83..f715dee3c3d402 100644
--- a/src/coreclr/inc/corinfo.h
+++ b/src/coreclr/inc/corinfo.h
@@ -3150,6 +3150,11 @@ class ICorDynamicInfo : public ICorStaticInfo
                     void                  **ppIndirection = NULL
                     ) = 0;
 
+    // Returns frozen object handle if field is a static readonly field of an initialized type
+    virtual void* getFrozenHandleFromInitedStaticField(
+                    CORINFO_FIELD_HANDLE field
+                    ) = 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 4e0e1094eb250d..9cf06b691da2ac 100644
--- a/src/coreclr/inc/icorjitinfoimpl_generated.h
+++ b/src/coreclr/inc/icorjitinfoimpl_generated.h
@@ -605,6 +605,9 @@ void* getFieldAddress(
           CORINFO_FIELD_HANDLE field,
           void** ppIndirection) override;
 
+void* getFrozenHandleFromInitedStaticField(
+          CORINFO_FIELD_HANDLE field) 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 8ec7e89f0ef06c..0ebe0c417ef489 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 = { /* 11b4ea58-c400-4c3d-995e-4e2f0676f6e8 */
-    0x11b4ea58,
-    0xc400,
-    0x4c3d,
-    {0x99, 0x5e, 0x4e, 0x2f, 0x6, 0x76, 0xf6, 0xe8}
+constexpr GUID JITEEVersionIdentifier = { /* ebc78c0f-f765-41ea-9cf3-519e36dc6ce2 */
+    0xebc78c0f,
+    0xf765,
+    0x41ea,
+    {0x9c, 0xf3, 0x51, 0x9e, 0x36, 0xdc, 0x6c, 0xe2}
   };
 
 //////////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/coreclr/jit/ICorJitInfo_API_names.h b/src/coreclr/jit/ICorJitInfo_API_names.h
index 9ebd42f381af65..f0ce623bf568b9 100644
--- a/src/coreclr/jit/ICorJitInfo_API_names.h
+++ b/src/coreclr/jit/ICorJitInfo_API_names.h
@@ -152,6 +152,7 @@ DEF_CLR_API(canAccessFamily)
 DEF_CLR_API(isRIDClassDomainID)
 DEF_CLR_API(getClassDomainID)
 DEF_CLR_API(getFieldAddress)
+DEF_CLR_API(getFrozenHandleFromInitedStaticField)
 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 4bedcebcf3b0c5..11be587704bbfb 100644
--- a/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp
+++ b/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp
@@ -1450,6 +1450,15 @@ void* WrapICorJitInfo::getFieldAddress(
     return temp;
 }
 
+void* WrapICorJitInfo::getFrozenHandleFromInitedStaticField(
+          CORINFO_FIELD_HANDLE field)
+{
+    API_ENTER(getFrozenHandleFromInitedStaticField);
+    void* temp = wrapHnd->getFrozenHandleFromInitedStaticField(field);
+    API_LEAVE(getFrozenHandleFromInitedStaticField);
+    return temp;
+}
+
 CORINFO_CLASS_HANDLE WrapICorJitInfo::getStaticFieldCurrentClass(
           CORINFO_FIELD_HANDLE field,
           bool* pIsSpeculative)
diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp
index a42812060d38b4..512c88d178167d 100644
--- a/src/coreclr/jit/importer.cpp
+++ b/src/coreclr/jit/importer.cpp
@@ -15287,7 +15287,7 @@ void Compiler::impImportBlockCode(BasicBlock* block)
                         // 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)))
+                            (varTypeIsIntegral(lclTyp) || varTypeIsFloating(lclTyp) || (lclTyp == TYP_REF)))
                         {
                             CorInfoInitClassResult initClassResult =
                                 info.compCompHnd->initClass(resolvedToken.hField, info.compMethodHnd,
@@ -15295,22 +15295,39 @@ void Compiler::impImportBlockCode(BasicBlock* block)
 
                             if (initClassResult & CORINFO_INITCLASS_INITIALIZED)
                             {
-                                void** pFldAddr = nullptr;
-                                void*  fldAddr =
-                                    info.compCompHnd->getFieldAddress(resolvedToken.hField, (void**)&pFldAddr);
+                                if (varTypeIsIntegral(lclTyp) || varTypeIsFloating(lclTyp))
+                                {
+                                    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);
+                                    // We should always be able to access this static's address directly
+                                    //
+                                    assert(pFldAddr == nullptr);
 
-                                op1 = impImportStaticReadOnlyField(fldAddr, lclTyp);
+                                    op1 = impImportStaticReadOnlyField(fldAddr, lclTyp);
 
-                                // Widen small types since we're propagating the value
-                                // instead of producing an indir.
-                                //
-                                op1->gtType = genActualType(lclTyp);
+                                    // Widen small types since we're propagating the value
+                                    // instead of producing an indir.
+                                    //
+                                    op1->gtType = genActualType(lclTyp);
 
-                                goto FIELD_DONE;
+                                    goto FIELD_DONE;
+                                }
+                                else
+                                {
+                                    assert(lclTyp == TYP_REF);
+                                    void* frozenHandle =
+                                        info.compCompHnd->getFrozenHandleFromInitedStaticField(resolvedToken.hField);
+                                    if (frozenHandle != nullptr)
+                                    {
+                                        setMethodHasFrozenObjects();
+                                        op1 = gtNewIconEmbHndNode(frozenHandle, nullptr, GTF_ICON_OBJ_HDL, nullptr);
+                                        op1->gtType = TYP_REF;
+                                        INDEBUG(op1->AsIntCon()->gtTargetHandle = (size_t)frozenHandle);
+                                        goto FIELD_DONE;
+                                    }
+                                }
                             }
                         }
 
diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs b/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs
index 8d8c426a7130d2..d69aa43576f6b6 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs
@@ -2198,6 +2198,21 @@ private static uint _getClassDomainID(IntPtr thisHandle, IntPtr* ppException, CO
             }
         }
 
+        [UnmanagedCallersOnly]
+        private static void* _getFrozenHandleFromInitedStaticField(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field)
+        {
+            var _this = GetThis(thisHandle);
+            try
+            {
+                return _this.getFrozenHandleFromInitedStaticField(field);
+            }
+            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 +2640,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) * 178);
 
             callbacks[0] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, byte>)&_isIntrinsic;
             callbacks[1] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint>)&_getMethodAttribs;
@@ -2775,35 +2790,36 @@ private static IntPtr GetUnmanagedCallbacks()
             callbacks[145] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, byte>)&_isRIDClassDomainID;
             callbacks[146] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, void**, uint>)&_getClassDomainID;
             callbacks[147] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, void**, void*>)&_getFieldAddress;
-            callbacks[148] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, byte*, CORINFO_CLASS_STRUCT_*>)&_getStaticFieldCurrentClass;
-            callbacks[149] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, void**, IntPtr>)&_getVarArgsHandle;
-            callbacks[150] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, byte>)&_canGetVarArgsHandle;
-            callbacks[151] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_MODULE_STRUCT_*, mdToken, void**, InfoAccessType>)&_constructStringLiteral;
-            callbacks[152] = (delegate* unmanaged<IntPtr, IntPtr*, void**, InfoAccessType>)&_emptyStringLiteral;
-            callbacks[153] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, void**, uint>)&_getFieldThreadLocalStoreID;
-            callbacks[154] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_MODULE_STRUCT_*, CORINFO_MODULE_STRUCT_*, void>)&_addActiveDependency;
-            callbacks[155] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_CLASS_STRUCT_*, CORINFO_METHOD_STRUCT_*, DelegateCtorArgs*, CORINFO_METHOD_STRUCT_*>)&_GetDelegateCtor;
-            callbacks[156] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, void>)&_MethodCompileComplete;
-            callbacks[157] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, CORINFO_SIG_INFO*, CORINFO_GET_TAILCALL_HELPERS_FLAGS, CORINFO_TAILCALL_HELPERS*, byte>)&_getTailCallHelpers;
-            callbacks[158] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, byte, byte>)&_convertPInvokeCalliToCall;
-            callbacks[159] = (delegate* unmanaged<IntPtr, IntPtr*, InstructionSet, byte, byte>)&_notifyInstructionSetUsage;
-            callbacks[160] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CONST_LOOKUP*, void>)&_updateEntryPointForTailCall;
-            callbacks[161] = (delegate* unmanaged<IntPtr, IntPtr*, AllocMemArgs*, void>)&_allocMem;
-            callbacks[162] = (delegate* unmanaged<IntPtr, IntPtr*, byte, byte, uint, void>)&_reserveUnwindInfo;
-            callbacks[163] = (delegate* unmanaged<IntPtr, IntPtr*, byte*, byte*, uint, uint, uint, byte*, CorJitFuncKind, void>)&_allocUnwindInfo;
-            callbacks[164] = (delegate* unmanaged<IntPtr, IntPtr*, UIntPtr, void*>)&_allocGCInfo;
-            callbacks[165] = (delegate* unmanaged<IntPtr, IntPtr*, uint, void>)&_setEHcount;
-            callbacks[166] = (delegate* unmanaged<IntPtr, IntPtr*, uint, CORINFO_EH_CLAUSE*, void>)&_setEHinfo;
-            callbacks[167] = (delegate* unmanaged<IntPtr, IntPtr*, uint, byte*, IntPtr, byte>)&_logMsg;
-            callbacks[168] = (delegate* unmanaged<IntPtr, IntPtr*, byte*, int, byte*, int>)&_doAssert;
-            callbacks[169] = (delegate* unmanaged<IntPtr, IntPtr*, CorJitResult, void>)&_reportFatalError;
-            callbacks[170] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, PgoInstrumentationSchema**, uint*, byte**, PgoSource*, HRESULT>)&_getPgoInstrumentationResults;
-            callbacks[171] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, PgoInstrumentationSchema*, uint, byte**, HRESULT>)&_allocPgoInstrumentationBySchema;
-            callbacks[172] = (delegate* unmanaged<IntPtr, IntPtr*, uint, CORINFO_SIG_INFO*, CORINFO_METHOD_STRUCT_*, void>)&_recordCallSite;
-            callbacks[173] = (delegate* unmanaged<IntPtr, IntPtr*, void*, void*, void*, ushort, ushort, int, void>)&_recordRelocation;
-            callbacks[174] = (delegate* unmanaged<IntPtr, IntPtr*, void*, ushort>)&_getRelocTypeHint;
-            callbacks[175] = (delegate* unmanaged<IntPtr, IntPtr*, uint>)&_getExpectedTargetArchitecture;
-            callbacks[176] = (delegate* unmanaged<IntPtr, IntPtr*, CORJIT_FLAGS*, uint, uint>)&_getJitFlags;
+            callbacks[148] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, void*>)&_getFrozenHandleFromInitedStaticField;
+            callbacks[149] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, byte*, CORINFO_CLASS_STRUCT_*>)&_getStaticFieldCurrentClass;
+            callbacks[150] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, void**, IntPtr>)&_getVarArgsHandle;
+            callbacks[151] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, byte>)&_canGetVarArgsHandle;
+            callbacks[152] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_MODULE_STRUCT_*, mdToken, void**, InfoAccessType>)&_constructStringLiteral;
+            callbacks[153] = (delegate* unmanaged<IntPtr, IntPtr*, void**, InfoAccessType>)&_emptyStringLiteral;
+            callbacks[154] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, void**, uint>)&_getFieldThreadLocalStoreID;
+            callbacks[155] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_MODULE_STRUCT_*, CORINFO_MODULE_STRUCT_*, void>)&_addActiveDependency;
+            callbacks[156] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_CLASS_STRUCT_*, CORINFO_METHOD_STRUCT_*, DelegateCtorArgs*, CORINFO_METHOD_STRUCT_*>)&_GetDelegateCtor;
+            callbacks[157] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, void>)&_MethodCompileComplete;
+            callbacks[158] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, CORINFO_SIG_INFO*, CORINFO_GET_TAILCALL_HELPERS_FLAGS, CORINFO_TAILCALL_HELPERS*, byte>)&_getTailCallHelpers;
+            callbacks[159] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, byte, byte>)&_convertPInvokeCalliToCall;
+            callbacks[160] = (delegate* unmanaged<IntPtr, IntPtr*, InstructionSet, byte, byte>)&_notifyInstructionSetUsage;
+            callbacks[161] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CONST_LOOKUP*, void>)&_updateEntryPointForTailCall;
+            callbacks[162] = (delegate* unmanaged<IntPtr, IntPtr*, AllocMemArgs*, void>)&_allocMem;
+            callbacks[163] = (delegate* unmanaged<IntPtr, IntPtr*, byte, byte, uint, void>)&_reserveUnwindInfo;
+            callbacks[164] = (delegate* unmanaged<IntPtr, IntPtr*, byte*, byte*, uint, uint, uint, byte*, CorJitFuncKind, void>)&_allocUnwindInfo;
+            callbacks[165] = (delegate* unmanaged<IntPtr, IntPtr*, UIntPtr, void*>)&_allocGCInfo;
+            callbacks[166] = (delegate* unmanaged<IntPtr, IntPtr*, uint, void>)&_setEHcount;
+            callbacks[167] = (delegate* unmanaged<IntPtr, IntPtr*, uint, CORINFO_EH_CLAUSE*, void>)&_setEHinfo;
+            callbacks[168] = (delegate* unmanaged<IntPtr, IntPtr*, uint, byte*, IntPtr, byte>)&_logMsg;
+            callbacks[169] = (delegate* unmanaged<IntPtr, IntPtr*, byte*, int, byte*, int>)&_doAssert;
+            callbacks[170] = (delegate* unmanaged<IntPtr, IntPtr*, CorJitResult, void>)&_reportFatalError;
+            callbacks[171] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, PgoInstrumentationSchema**, uint*, byte**, PgoSource*, HRESULT>)&_getPgoInstrumentationResults;
+            callbacks[172] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, PgoInstrumentationSchema*, uint, byte**, HRESULT>)&_allocPgoInstrumentationBySchema;
+            callbacks[173] = (delegate* unmanaged<IntPtr, IntPtr*, uint, CORINFO_SIG_INFO*, CORINFO_METHOD_STRUCT_*, void>)&_recordCallSite;
+            callbacks[174] = (delegate* unmanaged<IntPtr, IntPtr*, void*, void*, void*, ushort, ushort, int, void>)&_recordRelocation;
+            callbacks[175] = (delegate* unmanaged<IntPtr, IntPtr*, void*, ushort>)&_getRelocTypeHint;
+            callbacks[176] = (delegate* unmanaged<IntPtr, IntPtr*, uint>)&_getExpectedTargetArchitecture;
+            callbacks[177] = (delegate* unmanaged<IntPtr, IntPtr*, CORJIT_FLAGS*, uint, uint>)&_getJitFlags;
 
             return (IntPtr)callbacks;
         }
diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
index cc087e8b31e218..56235666b4781b 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
@@ -3306,6 +3306,13 @@ private uint getClassDomainID(CORINFO_CLASS_STRUCT_* cls, ref void* ppIndirectio
             }
         }
 
+#pragma warning disable CA1822 // Mark members as static
+        private void* getFrozenHandleFromInitedStaticField(CORINFO_FIELD_STRUCT_* field)
+#pragma warning restore CA1822 // Mark members as static
+        {
+            return null;
+        }
+
         private CORINFO_CLASS_STRUCT_* getStaticFieldCurrentClass(CORINFO_FIELD_STRUCT_* field, byte* pIsSpeculative)
         {
             if (pIsSpeculative != null)
diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt
index 0294eced60258f..89629af04fb786 100644
--- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt
+++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt
@@ -303,6 +303,7 @@ FUNCTIONS
     bool isRIDClassDomainID(CORINFO_CLASS_HANDLE cls);
     unsigned getClassDomainID (CORINFO_CLASS_HANDLE    cls, void                  **ppIndirection);
     void* getFieldAddress(CORINFO_FIELD_HANDLE    field, VOIDSTARSTAR ppIndirection);
+    void* getFrozenHandleFromInitedStaticField(CORINFO_FIELD_HANDLE field);
     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/jitinterface/jitinterface.h b/src/coreclr/tools/aot/jitinterface/jitinterface.h
index f12f60b98cb9c3..6c870466a29b57 100644
--- a/src/coreclr/tools/aot/jitinterface/jitinterface.h
+++ b/src/coreclr/tools/aot/jitinterface/jitinterface.h
@@ -159,6 +159,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);
+    void* (* getFrozenHandleFromInitedStaticField)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_FIELD_HANDLE field);
     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);
@@ -1623,6 +1624,15 @@ class JitInterfaceWrapper : public ICorJitInfo
     return temp;
 }
 
+    virtual void* getFrozenHandleFromInitedStaticField(
+          CORINFO_FIELD_HANDLE field)
+{
+    CorInfoExceptionClass* pException = nullptr;
+    void* temp = _callbacks->getFrozenHandleFromInitedStaticField(_thisHandle, &pException, field);
+    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/lwmlist.h b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h
index a40f741eea317e..4a4b924fbad2c4 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(GetFrozenHandleFromInitedStaticField, DWORDLONG, DWORDLONG)
 LWM(GetStaticFieldCurrentClass, DWORDLONG, 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 5eea6f742ba214..f375111d6ff9d6 100644
--- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp
+++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp
@@ -3653,6 +3653,30 @@ void* MethodContext::repGetFieldAddress(CORINFO_FIELD_HANDLE field, void** ppInd
     return temp;
 }
 
+void MethodContext::recGetFrozenHandleFromInitedStaticField(CORINFO_FIELD_HANDLE field, void* result)
+{
+    if (GetFrozenHandleFromInitedStaticField == nullptr)
+        GetFrozenHandleFromInitedStaticField = new LightWeightMap<DWORDLONG, DWORDLONG>();
+
+    DWORDLONG key = CastHandle(field);
+    DWORDLONG value = DWORDLONG(result);
+    GetFrozenHandleFromInitedStaticField->Add(key, value);
+    DEBUG_REC(dmpGetFrozenHandleFromInitedStaticField(key, value));
+}
+void MethodContext::dmpGetFrozenHandleFromInitedStaticField(DWORDLONG key, DWORDLONG value)
+{
+    printf("GetFrozenHandleFromInitedStaticField key field-%016llX, value field-%016llX", key, value);
+}
+void* MethodContext::repGetFrozenHandleFromInitedStaticField(CORINFO_FIELD_HANDLE field)
+{
+    DWORDLONG key = CastHandle(field);
+    AssertMapAndKeyExist(GetFrozenHandleFromInitedStaticField, key, ": key %016llX", key);
+    DWORDLONG value = GetFrozenHandleFromInitedStaticField->Get(key);
+    DEBUG_REP(dmpGetFrozenHandleFromInitedStaticField(key, value));
+    void* result = (void*)value;
+    return result;
+}
+
 void MethodContext::recGetStaticFieldCurrentClass(CORINFO_FIELD_HANDLE field,
                                                   bool                 isSpeculative,
                                                   CORINFO_CLASS_HANDLE result)
diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h
index 96c19e8664d78a..9afa759671bd5b 100644
--- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h
+++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h
@@ -480,6 +480,10 @@ class MethodContext
     void dmpGetFieldAddress(DWORDLONG key, const Agnostic_GetFieldAddress& value);
     void* repGetFieldAddress(CORINFO_FIELD_HANDLE field, void** ppIndirection);
 
+    void recGetFrozenHandleFromInitedStaticField(CORINFO_FIELD_HANDLE field, void* result);
+    void dmpGetFrozenHandleFromInitedStaticField(DWORDLONG key, DWORDLONG value);
+    void* repGetFrozenHandleFromInitedStaticField(CORINFO_FIELD_HANDLE field);
+
     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);
@@ -1139,6 +1143,7 @@ enum mcPackets
     Packet_GetExactClasses = 195,
     Packet_GetRuntimeTypePointer = 196,
     Packet_ObjectToString = 197,
+    Packet_GetFrozenHandleFromInitedStaticField = 198,
 };
 
 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 b19faebf609677..eaca5917bffa07 100644
--- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp
+++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp
@@ -1723,6 +1723,14 @@ void* interceptor_ICJI::getFieldAddress(CORINFO_FIELD_HANDLE field, void** ppInd
     return temp;
 }
 
+void* interceptor_ICJI::getFrozenHandleFromInitedStaticField(CORINFO_FIELD_HANDLE field)
+{
+    mc->cr->AddCall("getFrozenHandleFromInitedStaticField");
+    void* result = original_ICorJitInfo->getFrozenHandleFromInitedStaticField(field);
+    mc->recGetFrozenHandleFromInitedStaticField(field, 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 2a12825c899076..0ab289b5be48fc 100644
--- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp
+++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp
@@ -1188,6 +1188,13 @@ void* interceptor_ICJI::getFieldAddress(
     return original_ICorJitInfo->getFieldAddress(field, ppIndirection);
 }
 
+void* interceptor_ICJI::getFrozenHandleFromInitedStaticField(
+          CORINFO_FIELD_HANDLE field)
+{
+    mcs->AddCall("getFrozenHandleFromInitedStaticField");
+    return original_ICorJitInfo->getFrozenHandleFromInitedStaticField(field);
+}
+
 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 808ccc3ab473dc..a44a5de5ec4843 100644
--- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp
+++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp
@@ -1040,6 +1040,12 @@ void* interceptor_ICJI::getFieldAddress(
     return original_ICorJitInfo->getFieldAddress(field, ppIndirection);
 }
 
+void* interceptor_ICJI::getFrozenHandleFromInitedStaticField(
+          CORINFO_FIELD_HANDLE field)
+{
+    return original_ICorJitInfo->getFrozenHandleFromInitedStaticField(field);
+}
+
 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 efdfafffb8d3b4..0005a7367cb215 100644
--- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp
+++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp
@@ -1503,6 +1503,12 @@ void* MyICJI::getFieldAddress(CORINFO_FIELD_HANDLE field, void** ppIndirection)
     return jitInstance->mc->repGetFieldAddress(field, ppIndirection);
 }
 
+void* MyICJI::getFrozenHandleFromInitedStaticField(CORINFO_FIELD_HANDLE field)
+{
+    jitInstance->mc->cr->AddCall("getFrozenHandleFromInitedStaticField");
+    return jitInstance->mc->repGetFrozenHandleFromInitedStaticField(field);
+}
+
 // 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 2aa473dc6e9d7a..391fb5562d73a1 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -11788,6 +11788,42 @@ void* CEEJitInfo::getFieldAddress(CORINFO_FIELD_HANDLE fieldHnd,
     return result;
 }
 
+void* CEEJitInfo::getFrozenHandleFromInitedStaticField(CORINFO_FIELD_HANDLE fieldHnd)
+{
+    CONTRACTL {
+        THROWS;
+        GC_TRIGGERS;
+        MODE_PREEMPTIVE;
+    } CONTRACTL_END;
+
+    void* ptr = nullptr;
+
+    JIT_TO_EE_TRANSITION();
+
+    bool isSpeculative;
+    if (getStaticFieldCurrentClass(fieldHnd, &isSpeculative) != NULL && !isSpeculative)
+    {
+        GCX_COOP();
+
+        FieldDesc* field = (FieldDesc*)fieldHnd;
+        _ASSERT(field->IsStatic() && field->IsObjRef());
+        OBJECTREF fieldObj = field->GetStaticOBJECTREF();
+        if (fieldObj != NULL)
+        {
+            Object* obj = OBJECTREFToObject(fieldObj);
+            if (!obj->GetMethodTable()->GetLoaderAllocator()->CanUnload() &&
+                GCHeapUtilities::GetGCHeap()->IsInFrozenSegment(obj))
+            {
+                ptr = (void*)obj;
+            }
+        }
+    }
+
+    EE_TO_JIT_TRANSITION();
+
+    return ptr;
+}
+
 /*********************************************************************/
 CORINFO_CLASS_HANDLE CEEJitInfo::getStaticFieldCurrentClass(CORINFO_FIELD_HANDLE fieldHnd,
                                                             bool* pIsSpeculative)
@@ -14328,6 +14364,12 @@ void* CEEInfo::getFieldAddress(CORINFO_FIELD_HANDLE fieldHnd,
     return result;
 }
 
+void* CEEInfo::getFrozenHandleFromInitedStaticField(CORINFO_FIELD_HANDLE CORINFO_FIELD_HANDLE)
+{
+    LIMITED_METHOD_CONTRACT;
+    UNREACHABLE();      // only called on derived class.
+}
+
 CORINFO_CLASS_HANDLE CEEInfo::getStaticFieldCurrentClass(CORINFO_FIELD_HANDLE fieldHnd,
                                                          bool* pIsSpeculative)
 {
diff --git a/src/coreclr/vm/jitinterface.h b/src/coreclr/vm/jitinterface.h
index 9b517406ce4f14..be86632d80576e 100644
--- a/src/coreclr/vm/jitinterface.h
+++ b/src/coreclr/vm/jitinterface.h
@@ -925,6 +925,7 @@ class CEEJitInfo : public CEEInfo
     InfoAccessType constructStringLiteral(CORINFO_MODULE_HANDLE scopeHnd, mdToken metaTok, void **ppValue) override final;
     InfoAccessType emptyStringLiteral(void ** ppValue) override final;
     void* getFieldAddress(CORINFO_FIELD_HANDLE field, void **ppIndirection) override final;
+    void* getFrozenHandleFromInitedStaticField(CORINFO_FIELD_HANDLE field) override final;
     CORINFO_CLASS_HANDLE getStaticFieldCurrentClass(CORINFO_FIELD_HANDLE field, bool* pIsSpeculative) override final;
     void* getMethodSync(CORINFO_METHOD_HANDLE ftnHnd, void **ppIndirection) override final;
 

From 07fdafc9a9583674763f94b728f7f8e533b695d1 Mon Sep 17 00:00:00 2001
From: EgorBo <egorbo@gmail.com>
Date: Sat, 24 Sep 2022 05:28:53 +0200
Subject: [PATCH 02/61] Address Jan's feedback

---
 src/coreclr/vm/jitinterface.cpp | 29 +++++++++++++++++------------
 1 file changed, 17 insertions(+), 12 deletions(-)

diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp
index 391fb5562d73a1..e73bbf143cfbd0 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -11800,21 +11800,26 @@ void* CEEJitInfo::getFrozenHandleFromInitedStaticField(CORINFO_FIELD_HANDLE fiel
 
     JIT_TO_EE_TRANSITION();
 
-    bool isSpeculative;
-    if (getStaticFieldCurrentClass(fieldHnd, &isSpeculative) != NULL && !isSpeculative)
+    FieldDesc* field = (FieldDesc*)fieldHnd;
+    if (field->IsStatic() && field->IsObjRef() && !field->IsThreadStatic())
     {
-        GCX_COOP();
-
-        FieldDesc* field = (FieldDesc*)fieldHnd;
-        _ASSERT(field->IsStatic() && field->IsObjRef());
-        OBJECTREF fieldObj = field->GetStaticOBJECTREF();
-        if (fieldObj != NULL)
+        MethodTable* pEnclosingMT = field->GetEnclosingMethodTable();
+        if (!pEnclosingMT->IsSharedByGenericInstantiations())
         {
-            Object* obj = OBJECTREFToObject(fieldObj);
-            if (!obj->GetMethodTable()->GetLoaderAllocator()->CanUnload() &&
-                GCHeapUtilities::GetGCHeap()->IsInFrozenSegment(obj))
+            // Allocate space for the local class if necessary, but don't trigger
+            // class construction.
+            DomainLocalModule* pLocalModule = pEnclosingMT->GetDomainLocalModule();
+            pLocalModule->PopulateClass(pEnclosingMT);
+
+            GCX_COOP();
+            OBJECTREF fieldObj = field->GetStaticOBJECTREF();
+            if (fieldObj != NULL && pEnclosingMT->IsClassInited() && IsFdInitOnly(field->GetAttributes()))
             {
-                ptr = (void*)obj;
+                Object* obj = OBJECTREFToObject(fieldObj);
+                if (GCHeapUtilities::GetGCHeap()->IsInFrozenSegment(obj))
+                {
+                    ptr = (void*)obj;
+                }
             }
         }
     }

From ad6914595caf42667338649ee9b3fca3e2692886 Mon Sep 17 00:00:00 2001
From: EgorBo <egorbo@gmail.com>
Date: Sat, 24 Sep 2022 08:20:38 +0200
Subject: [PATCH 03/61] Address feedback

---
 src/coreclr/inc/corinfo.h                     |  11 +-
 src/coreclr/inc/icorjitinfoimpl_generated.h   |   5 +-
 src/coreclr/jit/ICorJitInfo_API_names.h       |   2 +-
 src/coreclr/jit/ICorJitInfo_API_wrapper.hpp   |  11 +-
 src/coreclr/jit/compiler.h                    |   2 +-
 src/coreclr/jit/importer.cpp                  | 173 ++++--------------
 .../tools/Common/JitInterface/CorInfoBase.cs  |   6 +-
 .../tools/Common/JitInterface/CorInfoImpl.cs  |   4 +-
 .../ThunkGenerator/ThunkInput.txt             |   4 +-
 .../tools/aot/jitinterface/jitinterface.h     |   9 +-
 .../tools/superpmi/superpmi-shared/lwmlist.h  |   2 +-
 .../superpmi-shared/methodcontext.cpp         |  53 ++++--
 .../superpmi/superpmi-shared/methodcontext.h  |   8 +-
 .../superpmi-shim-collector/icorjitinfo.cpp   |   8 +-
 .../superpmi-shim-counter/icorjitinfo.cpp     |   9 +-
 .../superpmi-shim-simple/icorjitinfo.cpp      |   7 +-
 .../tools/superpmi/superpmi/icorjitinfo.cpp   |   6 +-
 src/coreclr/vm/jitinterface.cpp               |  92 +++++++++-
 src/coreclr/vm/jitinterface.h                 |   2 +-
 19 files changed, 209 insertions(+), 205 deletions(-)

diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h
index f715dee3c3d402..f812e70881055f 100644
--- a/src/coreclr/inc/corinfo.h
+++ b/src/coreclr/inc/corinfo.h
@@ -3150,9 +3150,14 @@ class ICorDynamicInfo : public ICorStaticInfo
                     void                  **ppIndirection = NULL
                     ) = 0;
 
-    // Returns frozen object handle if field is a static readonly field of an initialized type
-    virtual void* getFrozenHandleFromInitedStaticField(
-                    CORINFO_FIELD_HANDLE field
+    // Returns true if the given field is "static readonly" and its value will never change
+    // also, returns its actual value via pValue argument. For now, it's either:
+    //  * integer/floating point primitive
+    //  * null
+    //  * frozen object
+    virtual bool getReadonlyStaticFieldValue(
+                    CORINFO_FIELD_HANDLE    field,
+                    uint64_t               *pValue
                     ) = 0;
 
     // If pIsSpeculative is NULL, return the class handle for the value of ref-class typed
diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h
index 9cf06b691da2ac..70a8ff6d468fd0 100644
--- a/src/coreclr/inc/icorjitinfoimpl_generated.h
+++ b/src/coreclr/inc/icorjitinfoimpl_generated.h
@@ -605,8 +605,9 @@ void* getFieldAddress(
           CORINFO_FIELD_HANDLE field,
           void** ppIndirection) override;
 
-void* getFrozenHandleFromInitedStaticField(
-          CORINFO_FIELD_HANDLE field) override;
+bool getReadonlyStaticFieldValue(
+          CORINFO_FIELD_HANDLE field,
+          uint64_t* pValue) override;
 
 CORINFO_CLASS_HANDLE getStaticFieldCurrentClass(
           CORINFO_FIELD_HANDLE field,
diff --git a/src/coreclr/jit/ICorJitInfo_API_names.h b/src/coreclr/jit/ICorJitInfo_API_names.h
index f0ce623bf568b9..dc817238d9ab00 100644
--- a/src/coreclr/jit/ICorJitInfo_API_names.h
+++ b/src/coreclr/jit/ICorJitInfo_API_names.h
@@ -152,7 +152,7 @@ DEF_CLR_API(canAccessFamily)
 DEF_CLR_API(isRIDClassDomainID)
 DEF_CLR_API(getClassDomainID)
 DEF_CLR_API(getFieldAddress)
-DEF_CLR_API(getFrozenHandleFromInitedStaticField)
+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 11be587704bbfb..6abbe84472fc3f 100644
--- a/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp
+++ b/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp
@@ -1450,12 +1450,13 @@ void* WrapICorJitInfo::getFieldAddress(
     return temp;
 }
 
-void* WrapICorJitInfo::getFrozenHandleFromInitedStaticField(
-          CORINFO_FIELD_HANDLE field)
+bool WrapICorJitInfo::getReadonlyStaticFieldValue(
+          CORINFO_FIELD_HANDLE field,
+          uint64_t* pValue)
 {
-    API_ENTER(getFrozenHandleFromInitedStaticField);
-    void* temp = wrapHnd->getFrozenHandleFromInitedStaticField(field);
-    API_LEAVE(getFrozenHandleFromInitedStaticField);
+    API_ENTER(getReadonlyStaticFieldValue);
+    bool temp = wrapHnd->getReadonlyStaticFieldValue(field, pValue);
+    API_LEAVE(getReadonlyStaticFieldValue);
     return temp;
 }
 
diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h
index 8504476d2cdf6d..3e41a941296458 100644
--- a/src/coreclr/jit/compiler.h
+++ b/src/coreclr/jit/compiler.h
@@ -3639,7 +3639,7 @@ class Compiler
 
     GenTree* impInitClass(CORINFO_RESOLVED_TOKEN* pResolvedToken);
 
-    GenTree* impImportStaticReadOnlyField(void* fldAddr, var_types lclTyp);
+    GenTree* impImportStaticReadOnlyField(UINT64 value, var_types valueType);
 
     GenTree* impImportStaticFieldAccess(CORINFO_RESOLVED_TOKEN* pResolvedToken,
                                         CORINFO_ACCESS_FLAGS    access,
diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp
index 512c88d178167d..bb9475f740d595 100644
--- a/src/coreclr/jit/importer.cpp
+++ b/src/coreclr/jit/importer.cpp
@@ -8083,133 +8083,56 @@ GenTree* Compiler::impInitClass(CORINFO_RESOLVED_TOKEN* pResolvedToken)
     return node;
 }
 
-GenTree* Compiler::impImportStaticReadOnlyField(void* fldAddr, var_types lclTyp)
+GenTree* Compiler::impImportStaticReadOnlyField(UINT64 value, 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
-
-    switch (lclTyp)
+    GenTree* tree = nullptr;
+    switch (valueType)
     {
-        int     ival;
-        __int64 lval;
-        double  dval;
-
         case TYP_BOOL:
-            ival = *((bool*)fldAddr);
-            goto IVAL_COMMON;
-
         case TYP_BYTE:
-            ival = *((signed char*)fldAddr);
-            goto IVAL_COMMON;
-
         case TYP_UBYTE:
-            ival = *((unsigned char*)fldAddr);
-            goto IVAL_COMMON;
-
         case TYP_SHORT:
-            ival = *((short*)fldAddr);
-            goto IVAL_COMMON;
-
         case TYP_USHORT:
-            ival = *((unsigned short*)fldAddr);
-            goto IVAL_COMMON;
-
         case TYP_UINT:
         case TYP_INT:
-            ival = *((int*)fldAddr);
-        IVAL_COMMON:
-            op1 = gtNewIconNode(ival);
+            tree = gtNewIconNode((ssize_t)value);
             break;
 
         case TYP_LONG:
         case TYP_ULONG:
-            lval = *((__int64*)fldAddr);
-            op1  = gtNewLconNode(lval);
+            tree = gtNewLconNode((INT64)value);
             break;
 
         case TYP_FLOAT:
-            dval        = *((float*)fldAddr);
-            op1         = gtNewDconNode(dval);
-            op1->gtType = TYP_FLOAT;
+            tree = gtNewDconNode(*((float*)&value));
             break;
 
         case TYP_DOUBLE:
-            dval = *((double*)fldAddr);
-            op1  = gtNewDconNode(dval);
+            tree = gtNewDconNode(*((double*)&value));
             break;
 
-        default:
-            assert(!"Unexpected lclTyp");
+        case TYP_REF:
+        {
+            if (value == 0)
+            {
+                tree = gtNewNull();
+            }
+            else
+            {
+                setMethodHasFrozenObjects();
+                tree         = gtNewIconEmbHndNode((void*)value, nullptr, GTF_ICON_OBJ_HDL, nullptr);
+                tree->gtType = TYP_REF;
+                INDEBUG(tree->AsIntCon()->gtTargetHandle = (size_t)value);
+            }
             break;
+        }
+        default:
+            return nullptr;
     }
 
-    return op1;
+    assert(tree != nullptr);
+    tree->gtType = genActualType(valueType);
+    return tree;
 }
 
 GenTree* Compiler::impImportStaticFieldAccess(CORINFO_RESOLVED_TOKEN* pResolvedToken,
@@ -15286,51 +15209,19 @@ void Compiler::impImportBlockCode(BasicBlock* block)
                     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) || (lclTyp == TYP_REF)))
+                            !(fieldInfo.fieldFlags & CORINFO_FLG_FIELD_STATIC_IN_HEAP))
                         {
-                            CorInfoInitClassResult initClassResult =
-                                info.compCompHnd->initClass(resolvedToken.hField, info.compMethodHnd,
-                                                            impTokenLookupContextHandle);
-
-                            if (initClassResult & CORINFO_INITCLASS_INITIALIZED)
+                            UINT64 value;
+                            if (info.compCompHnd->getReadonlyStaticFieldValue(resolvedToken.hField, &value))
                             {
-                                if (varTypeIsIntegral(lclTyp) || varTypeIsFloating(lclTyp))
+                                GenTree* cnsValue = impImportStaticReadOnlyField(value, lclTyp);
+                                if (cnsValue != nullptr)
                                 {
-                                    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);
-
+                                    op1 = cnsValue;
                                     goto FIELD_DONE;
                                 }
-                                else
-                                {
-                                    assert(lclTyp == TYP_REF);
-                                    void* frozenHandle =
-                                        info.compCompHnd->getFrozenHandleFromInitedStaticField(resolvedToken.hField);
-                                    if (frozenHandle != nullptr)
-                                    {
-                                        setMethodHasFrozenObjects();
-                                        op1 = gtNewIconEmbHndNode(frozenHandle, nullptr, GTF_ICON_OBJ_HDL, nullptr);
-                                        op1->gtType = TYP_REF;
-                                        INDEBUG(op1->AsIntCon()->gtTargetHandle = (size_t)frozenHandle);
-                                        goto FIELD_DONE;
-                                    }
-                                }
                             }
                         }
-
                         FALLTHROUGH;
 
                     case CORINFO_FIELD_STATIC_RVA_ADDRESS:
diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs b/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs
index d69aa43576f6b6..c8eac9a44247d2 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs
@@ -2199,12 +2199,12 @@ private static uint _getClassDomainID(IntPtr thisHandle, IntPtr* ppException, CO
         }
 
         [UnmanagedCallersOnly]
-        private static void* _getFrozenHandleFromInitedStaticField(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field)
+        private static byte _getReadonlyStaticFieldValue(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field, ulong* pValue)
         {
             var _this = GetThis(thisHandle);
             try
             {
-                return _this.getFrozenHandleFromInitedStaticField(field);
+                return _this.getReadonlyStaticFieldValue(field, ref *pValue) ? (byte)1 : (byte)0;
             }
             catch (Exception ex)
             {
@@ -2790,7 +2790,7 @@ private static IntPtr GetUnmanagedCallbacks()
             callbacks[145] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, byte>)&_isRIDClassDomainID;
             callbacks[146] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, void**, uint>)&_getClassDomainID;
             callbacks[147] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, void**, void*>)&_getFieldAddress;
-            callbacks[148] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, void*>)&_getFrozenHandleFromInitedStaticField;
+            callbacks[148] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, ulong*, byte>)&_getReadonlyStaticFieldValue;
             callbacks[149] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, byte*, CORINFO_CLASS_STRUCT_*>)&_getStaticFieldCurrentClass;
             callbacks[150] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, void**, IntPtr>)&_getVarArgsHandle;
             callbacks[151] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, byte>)&_canGetVarArgsHandle;
diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
index 56235666b4781b..fe798522b7116b 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
@@ -3307,10 +3307,10 @@ private uint getClassDomainID(CORINFO_CLASS_STRUCT_* cls, ref void* ppIndirectio
         }
 
 #pragma warning disable CA1822 // Mark members as static
-        private void* getFrozenHandleFromInitedStaticField(CORINFO_FIELD_STRUCT_* field)
+        private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* field, ref ulong pHandle)
 #pragma warning restore CA1822 // Mark members as static
         {
-            return null;
+            return false;
         }
 
         private CORINFO_CLASS_STRUCT_* getStaticFieldCurrentClass(CORINFO_FIELD_STRUCT_* field, byte* pIsSpeculative)
diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt
index 89629af04fb786..0b39f744e5a60b 100644
--- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt
+++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt
@@ -58,6 +58,7 @@ GSCookie**,IntPtr**
 bool*,ref bool
 BoolStar,byte*,bool*,bool*
 uint32_t*,ref uint
+uint64_t*,ref ulong
 void **,ref void*
 VOIDSTARSTAR,void **,void **,void **
 int32_t*,int*
@@ -70,6 +71,7 @@ wchar_t*,char*
 const wchar_t*,String
 
 uint32_t**,ref uint*
+uint64_t**,ref ulong*
 unsigned*,ref uint
 CORJIT_FLAGS*,ref CORJIT_FLAGS
 CORINFO_CONST_LOOKUP*,ref CORINFO_CONST_LOOKUP
@@ -303,7 +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);
-    void* getFrozenHandleFromInitedStaticField(CORINFO_FIELD_HANDLE field);
+    bool getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint64_t *pValue);
     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/jitinterface/jitinterface.h b/src/coreclr/tools/aot/jitinterface/jitinterface.h
index 6c870466a29b57..5aea3a0e440574 100644
--- a/src/coreclr/tools/aot/jitinterface/jitinterface.h
+++ b/src/coreclr/tools/aot/jitinterface/jitinterface.h
@@ -159,7 +159,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);
-    void* (* getFrozenHandleFromInitedStaticField)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_FIELD_HANDLE field);
+    bool (* getReadonlyStaticFieldValue)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_FIELD_HANDLE field, uint64_t* pValue);
     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);
@@ -1624,11 +1624,12 @@ class JitInterfaceWrapper : public ICorJitInfo
     return temp;
 }
 
-    virtual void* getFrozenHandleFromInitedStaticField(
-          CORINFO_FIELD_HANDLE field)
+    virtual bool getReadonlyStaticFieldValue(
+          CORINFO_FIELD_HANDLE field,
+          uint64_t* pValue)
 {
     CorInfoExceptionClass* pException = nullptr;
-    void* temp = _callbacks->getFrozenHandleFromInitedStaticField(_thisHandle, &pException, field);
+    bool temp = _callbacks->getReadonlyStaticFieldValue(_thisHandle, &pException, field, pValue);
     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 4a4b924fbad2c4..dde3813f23e62b 100644
--- a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h
+++ b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h
@@ -80,7 +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(GetFrozenHandleFromInitedStaticField, DWORDLONG, DWORDLONG)
+LWM(GetReadonlyStaticFieldValue, DWORDLONG, DLD)
 LWM(GetStaticFieldCurrentClass, DWORDLONG, 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 f375111d6ff9d6..215beb5bdb38d6 100644
--- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp
+++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp
@@ -3653,29 +3653,58 @@ void* MethodContext::repGetFieldAddress(CORINFO_FIELD_HANDLE field, void** ppInd
     return temp;
 }
 
-void MethodContext::recGetFrozenHandleFromInitedStaticField(CORINFO_FIELD_HANDLE field, void* result)
+void MethodContext::recGetReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint64_t value, bool result)
 {
-    if (GetFrozenHandleFromInitedStaticField == nullptr)
-        GetFrozenHandleFromInitedStaticField = new LightWeightMap<DWORDLONG, DWORDLONG>();
+    if (GetReadonlyStaticFieldValue == nullptr)
+        GetReadonlyStaticFieldValue = new LightWeightMap<DWORDLONG, DLD>();
+
+    DWORDLONG key = CastHandle(field);
+    DLD       val;
+    val.A = (DWORDLONG)value;
+    val.B = (DWORD)result;
+    GetReadonlyStaticFieldValue->Add(key, val);
+    DEBUG_REC(dmpGetReadonlyStaticFieldValue(key, val));
+}
+void MethodContext::dmpGetReadonlyStaticFieldValue(DWORDLONG key, DLD value)
+{
+    printf("GetReadonlyStaticFieldValue key field-%016llX, value-%016llX result-%08X", key, value.A, value.B);
+}
+bool MethodContext::repGetReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint64_t* value)
+{
+    DWORDLONG key = CastHandle(field);
+    AssertMapAndKeyExist(GetReadonlyStaticFieldValue, key, ": key %016llX", key);
+
+    DLD val = GetReadonlyStaticFieldValue->Get(key);
+    DEBUG_REP(dmpGetReadonlyStaticFieldValue(key, val));
+
+    *value = (uint64_t)val.A;
+    return (bool)val.B;
+}
+
+/*
+void MethodContext::recGetReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, void* result)
+{
+    if (GetReadonlyStaticFieldValue == nullptr)
+        GetReadonlyStaticFieldValue = new LightWeightMap<DWORDLONG, DWORDLONG>();
 
     DWORDLONG key = CastHandle(field);
     DWORDLONG value = DWORDLONG(result);
-    GetFrozenHandleFromInitedStaticField->Add(key, value);
-    DEBUG_REC(dmpGetFrozenHandleFromInitedStaticField(key, value));
+    GetReadonlyStaticFieldValue->Add(key, value);
+    DEBUG_REC(dmpGetReadonlyStaticFieldValue(key, value));
 }
-void MethodContext::dmpGetFrozenHandleFromInitedStaticField(DWORDLONG key, DWORDLONG value)
+void MethodContext::dmpGetReadonlyStaticFieldValue(DWORDLONG key, DWORDLONG value)
 {
-    printf("GetFrozenHandleFromInitedStaticField key field-%016llX, value field-%016llX", key, value);
+    printf("GetReadonlyStaticFieldValue key field-%016llX, value field-%016llX", key, value);
 }
-void* MethodContext::repGetFrozenHandleFromInitedStaticField(CORINFO_FIELD_HANDLE field)
+void* MethodContext::repGetReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field)
 {
     DWORDLONG key = CastHandle(field);
-    AssertMapAndKeyExist(GetFrozenHandleFromInitedStaticField, key, ": key %016llX", key);
-    DWORDLONG value = GetFrozenHandleFromInitedStaticField->Get(key);
-    DEBUG_REP(dmpGetFrozenHandleFromInitedStaticField(key, value));
+    AssertMapAndKeyExist(GetReadonlyStaticFieldValue, key, ": key %016llX", key);
+    DWORDLONG value = GetReadonlyStaticFieldValue->Get(key);
+    DEBUG_REP(dmpGetReadonlyStaticFieldValue(key, value));
     void* result = (void*)value;
     return result;
-}
+}*/
 
 void MethodContext::recGetStaticFieldCurrentClass(CORINFO_FIELD_HANDLE field,
                                                   bool                 isSpeculative,
diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h
index 9afa759671bd5b..8bb34b96403303 100644
--- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h
+++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h
@@ -480,9 +480,9 @@ class MethodContext
     void dmpGetFieldAddress(DWORDLONG key, const Agnostic_GetFieldAddress& value);
     void* repGetFieldAddress(CORINFO_FIELD_HANDLE field, void** ppIndirection);
 
-    void recGetFrozenHandleFromInitedStaticField(CORINFO_FIELD_HANDLE field, void* result);
-    void dmpGetFrozenHandleFromInitedStaticField(DWORDLONG key, DWORDLONG value);
-    void* repGetFrozenHandleFromInitedStaticField(CORINFO_FIELD_HANDLE field);
+    void recGetReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint64_t value, bool result);
+    void dmpGetReadonlyStaticFieldValue(DWORDLONG key, DLD value);
+    bool repGetReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint64_t* pValue);
 
     void recGetStaticFieldCurrentClass(CORINFO_FIELD_HANDLE field, bool isSpeculative, CORINFO_CLASS_HANDLE result);
     void dmpGetStaticFieldCurrentClass(DWORDLONG key, const Agnostic_GetStaticFieldCurrentClass& value);
@@ -1143,7 +1143,7 @@ enum mcPackets
     Packet_GetExactClasses = 195,
     Packet_GetRuntimeTypePointer = 196,
     Packet_ObjectToString = 197,
-    Packet_GetFrozenHandleFromInitedStaticField = 198,
+    Packet_GetReadonlyStaticFieldValue = 198,
 };
 
 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 eaca5917bffa07..e1bf9ffcb56c49 100644
--- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp
+++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp
@@ -1723,11 +1723,11 @@ void* interceptor_ICJI::getFieldAddress(CORINFO_FIELD_HANDLE field, void** ppInd
     return temp;
 }
 
-void* interceptor_ICJI::getFrozenHandleFromInitedStaticField(CORINFO_FIELD_HANDLE field)
+bool interceptor_ICJI::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint64_t* pValue)
 {
-    mc->cr->AddCall("getFrozenHandleFromInitedStaticField");
-    void* result = original_ICorJitInfo->getFrozenHandleFromInitedStaticField(field);
-    mc->recGetFrozenHandleFromInitedStaticField(field, result);
+    mc->cr->AddCall("getReadonlyStaticFieldValue");
+    bool result = original_ICorJitInfo->getReadonlyStaticFieldValue(field, pValue);
+    mc->recGetReadonlyStaticFieldValue(field, *pValue, result);
     return result;
 }
 
diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp
index 0ab289b5be48fc..a82bef0d7e452c 100644
--- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp
+++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp
@@ -1188,11 +1188,12 @@ void* interceptor_ICJI::getFieldAddress(
     return original_ICorJitInfo->getFieldAddress(field, ppIndirection);
 }
 
-void* interceptor_ICJI::getFrozenHandleFromInitedStaticField(
-          CORINFO_FIELD_HANDLE field)
+bool interceptor_ICJI::getReadonlyStaticFieldValue(
+          CORINFO_FIELD_HANDLE field,
+          uint64_t* pValue)
 {
-    mcs->AddCall("getFrozenHandleFromInitedStaticField");
-    return original_ICorJitInfo->getFrozenHandleFromInitedStaticField(field);
+    mcs->AddCall("getReadonlyStaticFieldValue");
+    return original_ICorJitInfo->getReadonlyStaticFieldValue(field, pValue);
 }
 
 CORINFO_CLASS_HANDLE interceptor_ICJI::getStaticFieldCurrentClass(
diff --git a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp
index a44a5de5ec4843..2afc4f6301dd87 100644
--- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp
+++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp
@@ -1040,10 +1040,11 @@ void* interceptor_ICJI::getFieldAddress(
     return original_ICorJitInfo->getFieldAddress(field, ppIndirection);
 }
 
-void* interceptor_ICJI::getFrozenHandleFromInitedStaticField(
-          CORINFO_FIELD_HANDLE field)
+bool interceptor_ICJI::getReadonlyStaticFieldValue(
+          CORINFO_FIELD_HANDLE field,
+          uint64_t* pValue)
 {
-    return original_ICorJitInfo->getFrozenHandleFromInitedStaticField(field);
+    return original_ICorJitInfo->getReadonlyStaticFieldValue(field, pValue);
 }
 
 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 0005a7367cb215..0afd8ae9a21292 100644
--- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp
+++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp
@@ -1503,10 +1503,10 @@ void* MyICJI::getFieldAddress(CORINFO_FIELD_HANDLE field, void** ppIndirection)
     return jitInstance->mc->repGetFieldAddress(field, ppIndirection);
 }
 
-void* MyICJI::getFrozenHandleFromInitedStaticField(CORINFO_FIELD_HANDLE field)
+bool MyICJI::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint64_t* pValue)
 {
-    jitInstance->mc->cr->AddCall("getFrozenHandleFromInitedStaticField");
-    return jitInstance->mc->repGetFrozenHandleFromInitedStaticField(field);
+    jitInstance->mc->cr->AddCall("getReadonlyStaticFieldValue");
+    return jitInstance->mc->repGetReadonlyStaticFieldValue(field, pValue);
 }
 
 // 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 e73bbf143cfbd0..ac182c198681e0 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -11788,7 +11788,7 @@ void* CEEJitInfo::getFieldAddress(CORINFO_FIELD_HANDLE fieldHnd,
     return result;
 }
 
-void* CEEJitInfo::getFrozenHandleFromInitedStaticField(CORINFO_FIELD_HANDLE fieldHnd)
+bool CEEJitInfo::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE fieldHnd, uint64_t* pValue)
 {
     CONTRACTL {
         THROWS;
@@ -11796,12 +11796,15 @@ void* CEEJitInfo::getFrozenHandleFromInitedStaticField(CORINFO_FIELD_HANDLE fiel
         MODE_PREEMPTIVE;
     } CONTRACTL_END;
 
-    void* ptr = nullptr;
+    _ASSERT(fieldHnd != NULL);
+    _ASSERT(pValue != NULL);
+
+    bool result = false;
 
     JIT_TO_EE_TRANSITION();
 
     FieldDesc* field = (FieldDesc*)fieldHnd;
-    if (field->IsStatic() && field->IsObjRef() && !field->IsThreadStatic())
+    if (field->IsStatic() && !field->IsThreadStatic())
     {
         MethodTable* pEnclosingMT = field->GetEnclosingMethodTable();
         if (!pEnclosingMT->IsSharedByGenericInstantiations())
@@ -11812,13 +11815,82 @@ void* CEEJitInfo::getFrozenHandleFromInitedStaticField(CORINFO_FIELD_HANDLE fiel
             pLocalModule->PopulateClass(pEnclosingMT);
 
             GCX_COOP();
-            OBJECTREF fieldObj = field->GetStaticOBJECTREF();
-            if (fieldObj != NULL && pEnclosingMT->IsClassInited() && IsFdInitOnly(field->GetAttributes()))
+            if (pEnclosingMT->IsClassInited() && IsFdInitOnly(field->GetAttributes()))
             {
-                Object* obj = OBJECTREFToObject(fieldObj);
-                if (GCHeapUtilities::GetGCHeap()->IsInFrozenSegment(obj))
+                if (field->IsObjRef())
+                {
+                    OBJECTREF fieldObj = field->GetStaticOBJECTREF();
+                    if (fieldObj != NULL)
+                    {
+                        Object* obj = OBJECTREFToObject(fieldObj);
+                        if (GCHeapUtilities::GetGCHeap()->IsInFrozenSegment(obj))
+                        {
+                            *pValue = (uint64_t)obj;
+                            result = true;
+                        }
+                    }
+                    else
+                    {
+                        *pValue = 0;
+                        result = true;
+                    }
+                }
+                else
                 {
-                    ptr = (void*)obj;
+                    void* fldAddr = field->GetStaticAddressHandle(field->IsRVA() ? nullptr : (void*)field->GetBase());
+                    if (fldAddr != nullptr)
+                    {
+                        _ASSERTE(!pEnclosingMT->ContainsGenericVariables());
+                        result = true;
+                        switch (field->GetFieldType())
+                        {
+                            case ELEMENT_TYPE_BOOLEAN:
+                                *pValue = (uint64_t)*((uint8_t*)fldAddr);
+                                break;
+                            case ELEMENT_TYPE_CHAR:
+                                *pValue = (uint64_t)*((uint16_t*)fldAddr);
+                                break;
+                            case ELEMENT_TYPE_I1:
+                                *pValue = (uint64_t)*((int8_t*)fldAddr);
+                                break;
+                            case ELEMENT_TYPE_U1:
+                                *pValue = (uint64_t)*((uint8_t*)fldAddr);
+                                break;
+                            case ELEMENT_TYPE_I2:
+                                *pValue = (uint64_t)*((int16_t*)fldAddr);
+                                break;
+                            case ELEMENT_TYPE_U2:
+                                *pValue = (uint64_t)*((uint16_t*)fldAddr);
+                                break;
+                            case ELEMENT_TYPE_I4:
+                                *pValue = (uint64_t)*((int32_t*)fldAddr);
+                                break;
+                            case ELEMENT_TYPE_U4:
+                                *pValue = (uint64_t)*((uint32_t*)fldAddr);
+                                break;
+                            case ELEMENT_TYPE_I8:
+                                *pValue = (uint64_t)*((int32_t*)fldAddr);
+                                break;
+                            case ELEMENT_TYPE_U8:
+                                *pValue = (uint64_t)*((uint64_t*)fldAddr);
+                                break;
+                            case ELEMENT_TYPE_R4:
+                                *pValue = (uint64_t)*((float*)fldAddr);
+                                break;
+                            case ELEMENT_TYPE_R8:
+                                *pValue = (uint64_t)*((double*)fldAddr);
+                                break;
+                            case ELEMENT_TYPE_I:
+                                *pValue = (uint64_t)*((intptr_t*)fldAddr);
+                                break;
+                            case ELEMENT_TYPE_U:
+                                *pValue = (uint64_t)*((uintptr_t*)fldAddr);
+                                break;
+                            default:
+                                result = false;
+                                break;
+                        }
+                    }
                 }
             }
         }
@@ -11826,7 +11898,7 @@ void* CEEJitInfo::getFrozenHandleFromInitedStaticField(CORINFO_FIELD_HANDLE fiel
 
     EE_TO_JIT_TRANSITION();
 
-    return ptr;
+    return result;
 }
 
 /*********************************************************************/
@@ -14369,7 +14441,7 @@ void* CEEInfo::getFieldAddress(CORINFO_FIELD_HANDLE fieldHnd,
     return result;
 }
 
-void* CEEInfo::getFrozenHandleFromInitedStaticField(CORINFO_FIELD_HANDLE CORINFO_FIELD_HANDLE)
+bool CEEInfo::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE fieldHnd, uint64_t* pValue)
 {
     LIMITED_METHOD_CONTRACT;
     UNREACHABLE();      // only called on derived class.
diff --git a/src/coreclr/vm/jitinterface.h b/src/coreclr/vm/jitinterface.h
index be86632d80576e..3ffc6d774c5866 100644
--- a/src/coreclr/vm/jitinterface.h
+++ b/src/coreclr/vm/jitinterface.h
@@ -925,7 +925,7 @@ class CEEJitInfo : public CEEInfo
     InfoAccessType constructStringLiteral(CORINFO_MODULE_HANDLE scopeHnd, mdToken metaTok, void **ppValue) override final;
     InfoAccessType emptyStringLiteral(void ** ppValue) override final;
     void* getFieldAddress(CORINFO_FIELD_HANDLE field, void **ppIndirection) override final;
-    void* getFrozenHandleFromInitedStaticField(CORINFO_FIELD_HANDLE field) override final;
+    bool getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint64_t *pValue) override final;
     CORINFO_CLASS_HANDLE getStaticFieldCurrentClass(CORINFO_FIELD_HANDLE field, bool* pIsSpeculative) override final;
     void* getMethodSync(CORINFO_METHOD_HANDLE ftnHnd, void **ppIndirection) override final;
 

From f10b886549a2751c0ff510e1e3f92ea748dbf3dd Mon Sep 17 00:00:00 2001
From: EgorBo <egorbo@gmail.com>
Date: Sat, 24 Sep 2022 09:36:19 +0200
Subject: [PATCH 04/61] Mitigate regressions via getObjectType

---
 src/coreclr/inc/corinfo.h                     |   4 +
 src/coreclr/inc/icorjitinfoimpl_generated.h   |   3 +
 src/coreclr/jit/ICorJitInfo_API_names.h       |   1 +
 src/coreclr/jit/ICorJitInfo_API_wrapper.hpp   |   9 +
 src/coreclr/jit/gentree.cpp                   |  14 ++
 .../tools/Common/JitInterface/CorInfoBase.cs  | 238 ++++++++++--------
 .../tools/Common/JitInterface/CorInfoImpl.cs  |   7 +
 .../ThunkGenerator/ThunkInput.txt             |   1 +
 .../tools/aot/jitinterface/jitinterface.h     |  10 +
 .../tools/superpmi/superpmi-shared/lwmlist.h  |   1 +
 .../superpmi-shared/methodcontext.cpp         |  23 ++
 .../superpmi/superpmi-shared/methodcontext.h  |   5 +
 .../superpmi-shim-collector/icorjitinfo.cpp   |   8 +
 .../superpmi-shim-counter/icorjitinfo.cpp     |   7 +
 .../superpmi-shim-simple/icorjitinfo.cpp      |   6 +
 .../tools/superpmi/superpmi/icorjitinfo.cpp   |   7 +
 src/coreclr/vm/jitinterface.cpp               |  26 ++
 17 files changed, 259 insertions(+), 111 deletions(-)

diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h
index f812e70881055f..b08d5c26e6ea31 100644
--- a/src/coreclr/inc/corinfo.h
+++ b/src/coreclr/inc/corinfo.h
@@ -2486,6 +2486,10 @@ class ICorStaticInfo
             CORINFO_CLASS_HANDLE        cls
             ) = 0;
 
+    virtual CORINFO_CLASS_HANDLE getObjectType(
+            void*                       typeObj
+            ) = 0;
+
     virtual bool getReadyToRunHelper(
             CORINFO_RESOLVED_TOKEN *        pResolvedToken,
             CORINFO_LOOKUP_KIND *           pGenericLookupKind,
diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h
index 70a8ff6d468fd0..0acbe25d4fef82 100644
--- a/src/coreclr/inc/icorjitinfoimpl_generated.h
+++ b/src/coreclr/inc/icorjitinfoimpl_generated.h
@@ -288,6 +288,9 @@ CorInfoHelpFunc getUnBoxHelper(
 void* getRuntimeTypePointer(
           CORINFO_CLASS_HANDLE cls) override;
 
+CORINFO_CLASS_HANDLE getObjectType(
+          void* typeObj) override;
+
 bool getReadyToRunHelper(
           CORINFO_RESOLVED_TOKEN* pResolvedToken,
           CORINFO_LOOKUP_KIND* pGenericLookupKind,
diff --git a/src/coreclr/jit/ICorJitInfo_API_names.h b/src/coreclr/jit/ICorJitInfo_API_names.h
index dc817238d9ab00..6e306d6b1e9e7d 100644
--- a/src/coreclr/jit/ICorJitInfo_API_names.h
+++ b/src/coreclr/jit/ICorJitInfo_API_names.h
@@ -72,6 +72,7 @@ DEF_CLR_API(getTypeForBox)
 DEF_CLR_API(getBoxHelper)
 DEF_CLR_API(getUnBoxHelper)
 DEF_CLR_API(getRuntimeTypePointer)
+DEF_CLR_API(getObjectType)
 DEF_CLR_API(getReadyToRunHelper)
 DEF_CLR_API(getReadyToRunDelegateCtorHelper)
 DEF_CLR_API(getHelperName)
diff --git a/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp b/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp
index 6abbe84472fc3f..49cc32abdc4eac 100644
--- a/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp
+++ b/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp
@@ -672,6 +672,15 @@ void* WrapICorJitInfo::getRuntimeTypePointer(
     return temp;
 }
 
+CORINFO_CLASS_HANDLE WrapICorJitInfo::getObjectType(
+          void* typeObj)
+{
+    API_ENTER(getObjectType);
+    CORINFO_CLASS_HANDLE temp = wrapHnd->getObjectType(typeObj);
+    API_LEAVE(getObjectType);
+    return temp;
+}
+
 bool WrapICorJitInfo::getReadyToRunHelper(
           CORINFO_RESOLVED_TOKEN* pResolvedToken,
           CORINFO_LOOKUP_KIND* pGenericLookupKind,
diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp
index 1e97a840a32635..baa099d055c017 100644
--- a/src/coreclr/jit/gentree.cpp
+++ b/src/coreclr/jit/gentree.cpp
@@ -17574,6 +17574,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 manage to get the 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/tools/Common/JitInterface/CorInfoBase.cs b/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs
index c8eac9a44247d2..a8e12f59ee85f2 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs
@@ -1017,6 +1017,21 @@ private static CorInfoHelpFunc _getUnBoxHelper(IntPtr thisHandle, IntPtr* ppExce
             }
         }
 
+        [UnmanagedCallersOnly]
+        private static CORINFO_CLASS_STRUCT_* _getObjectType(IntPtr thisHandle, IntPtr* ppException, void* typeObj)
+        {
+            var _this = GetThis(thisHandle);
+            try
+            {
+                return _this.getObjectType(typeObj);
+            }
+            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)
         {
@@ -2640,7 +2655,7 @@ private static uint _getJitFlags(IntPtr thisHandle, IntPtr* ppException, CORJIT_
 
         private static IntPtr GetUnmanagedCallbacks()
         {
-            void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 178);
+            void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 179);
 
             callbacks[0] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, byte>)&_isIntrinsic;
             callbacks[1] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint>)&_getMethodAttribs;
@@ -2710,116 +2725,117 @@ private static IntPtr GetUnmanagedCallbacks()
             callbacks[65] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CorInfoHelpFunc>)&_getBoxHelper;
             callbacks[66] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CorInfoHelpFunc>)&_getUnBoxHelper;
             callbacks[67] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, void*>)&_getRuntimeTypePointer;
-            callbacks[68] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, CORINFO_LOOKUP_KIND*, CorInfoHelpFunc, CORINFO_CONST_LOOKUP*, byte>)&_getReadyToRunHelper;
-            callbacks[69] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, mdToken, CORINFO_CLASS_STRUCT_*, CORINFO_LOOKUP*, void>)&_getReadyToRunDelegateCtorHelper;
-            callbacks[70] = (delegate* unmanaged<IntPtr, IntPtr*, CorInfoHelpFunc, byte*>)&_getHelperName;
-            callbacks[71] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, CORINFO_METHOD_STRUCT_*, CORINFO_CONTEXT_STRUCT*, CorInfoInitClassResult>)&_initClass;
-            callbacks[72] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, void>)&_classMustBeLoadedBeforeCodeIsRun;
-            callbacks[73] = (delegate* unmanaged<IntPtr, IntPtr*, CorInfoClassId, CORINFO_CLASS_STRUCT_*>)&_getBuiltinClass;
-            callbacks[74] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CorInfoType>)&_getTypeForPrimitiveValueClass;
-            callbacks[75] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CorInfoType>)&_getTypeForPrimitiveNumericClass;
-            callbacks[76] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*, byte>)&_canCast;
-            callbacks[77] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*, byte>)&_areTypesEquivalent;
-            callbacks[78] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*, TypeCompareState>)&_compareTypesForCast;
-            callbacks[79] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*, TypeCompareState>)&_compareTypesForEquality;
-            callbacks[80] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*>)&_mergeClasses;
-            callbacks[81] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*, byte>)&_isMoreSpecificType;
-            callbacks[82] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*>)&_getParentType;
-            callbacks[83] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_**, CorInfoType>)&_getChildType;
-            callbacks[84] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, byte>)&_satisfiesClassConstraints;
-            callbacks[85] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, byte>)&_isSDArray;
-            callbacks[86] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, uint>)&_getArrayRank;
-            callbacks[87] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CorInfoArrayIntrinsic>)&_getArrayIntrinsicID;
-            callbacks[88] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, uint, void*>)&_getArrayInitializationData;
-            callbacks[89] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, CORINFO_METHOD_STRUCT_*, CORINFO_HELPER_DESC*, CorInfoIsAccessAllowedResult>)&_canAccessClass;
-            callbacks[90] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, byte**, byte*>)&_getFieldName;
-            callbacks[91] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, CORINFO_CLASS_STRUCT_*>)&_getFieldClass;
-            callbacks[92] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, CORINFO_CLASS_STRUCT_**, CORINFO_CLASS_STRUCT_*, CorInfoType>)&_getFieldType;
-            callbacks[93] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, uint>)&_getFieldOffset;
-            callbacks[94] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, CORINFO_METHOD_STRUCT_*, CORINFO_ACCESS_FLAGS, CORINFO_FIELD_INFO*, void>)&_getFieldInfo;
-            callbacks[95] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, byte>)&_isFieldStatic;
-            callbacks[96] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint*, uint**, BoundaryTypes*, void>)&_getBoundaries;
-            callbacks[97] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint, OffsetMapping*, void>)&_setBoundaries;
-            callbacks[98] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint*, ILVarInfo**, bool*, void>)&_getVars;
-            callbacks[99] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint, NativeVarInfo*, void>)&_setVars;
-            callbacks[100] = (delegate* unmanaged<IntPtr, IntPtr*, InlineTreeNode*, uint, RichOffsetMapping*, uint, void>)&_reportRichMappings;
-            callbacks[101] = (delegate* unmanaged<IntPtr, IntPtr*, UIntPtr, void*>)&_allocateArray;
-            callbacks[102] = (delegate* unmanaged<IntPtr, IntPtr*, void*, void>)&_freeArray;
-            callbacks[103] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_ARG_LIST_STRUCT_*, CORINFO_ARG_LIST_STRUCT_*>)&_getArgNext;
-            callbacks[104] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, CORINFO_ARG_LIST_STRUCT_*, CORINFO_CLASS_STRUCT_**, CorInfoTypeWithMod>)&_getArgType;
-            callbacks[105] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, int, CORINFO_CLASS_STRUCT_**, int>)&_getExactClasses;
-            callbacks[106] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, CORINFO_ARG_LIST_STRUCT_*, CORINFO_CLASS_STRUCT_*>)&_getArgClass;
-            callbacks[107] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CorInfoHFAElemType>)&_getHFAType;
-            callbacks[108] = (delegate* unmanaged<IntPtr, IntPtr*, _EXCEPTION_POINTERS*, HRESULT>)&_GetErrorHRESULT;
-            callbacks[109] = (delegate* unmanaged<IntPtr, IntPtr*, char*, uint, uint>)&_GetErrorMessage;
-            callbacks[110] = (delegate* unmanaged<IntPtr, IntPtr*, _EXCEPTION_POINTERS*, int>)&_FilterException;
-            callbacks[111] = (delegate* unmanaged<IntPtr, IntPtr*, HRESULT, void>)&_ThrowExceptionForJitResult;
-            callbacks[112] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_HELPER_DESC*, void>)&_ThrowExceptionForHelper;
-            callbacks[113] = (delegate* unmanaged<IntPtr, IntPtr*, void*, void*, byte>)&_runWithErrorTrap;
-            callbacks[114] = (delegate* unmanaged<IntPtr, IntPtr*, void*, void*, byte>)&_runWithSPMIErrorTrap;
-            callbacks[115] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_EE_INFO*, void>)&_getEEInfo;
-            callbacks[116] = (delegate* unmanaged<IntPtr, IntPtr*, char*>)&_getJitTimeLogFilename;
-            callbacks[117] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, mdToken>)&_getMethodDefFromMethod;
-            callbacks[118] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, byte**, byte*>)&_getMethodName;
-            callbacks[119] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, byte**, byte**, byte**, byte*>)&_getMethodNameFromMetadata;
-            callbacks[120] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint>)&_getMethodHash;
-            callbacks[121] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_MODULE_STRUCT_*, mdToken, byte*, UIntPtr, UIntPtr>)&_findNameOfToken;
-            callbacks[122] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR*, byte>)&_getSystemVAmd64PassStructInRegisterDescriptor;
-            callbacks[123] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, uint>)&_getLoongArch64PassStructInRegisterFlags;
-            callbacks[124] = (delegate* unmanaged<IntPtr, IntPtr*, void**, uint>)&_getThreadTLSIndex;
-            callbacks[125] = (delegate* unmanaged<IntPtr, IntPtr*, void**, void*>)&_getInlinedCallFrameVptr;
-            callbacks[126] = (delegate* unmanaged<IntPtr, IntPtr*, void**, int*>)&_getAddrOfCaptureThreadGlobal;
-            callbacks[127] = (delegate* unmanaged<IntPtr, IntPtr*, CorInfoHelpFunc, void**, void*>)&_getHelperFtn;
-            callbacks[128] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_CONST_LOOKUP*, CORINFO_ACCESS_FLAGS, void>)&_getFunctionEntryPoint;
-            callbacks[129] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, byte, CORINFO_CONST_LOOKUP*, void>)&_getFunctionFixedEntryPoint;
-            callbacks[130] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, void**, void*>)&_getMethodSync;
-            callbacks[131] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_MODULE_STRUCT_*, CorInfoHelpFunc>)&_getLazyStringLiteralHelper;
-            callbacks[132] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_MODULE_STRUCT_*, void**, CORINFO_MODULE_STRUCT_*>)&_embedModuleHandle;
-            callbacks[133] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, void**, CORINFO_CLASS_STRUCT_*>)&_embedClassHandle;
-            callbacks[134] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, void**, CORINFO_METHOD_STRUCT_*>)&_embedMethodHandle;
-            callbacks[135] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, void**, CORINFO_FIELD_STRUCT_*>)&_embedFieldHandle;
-            callbacks[136] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, byte, CORINFO_GENERICHANDLE_RESULT*, void>)&_embedGenericHandle;
-            callbacks[137] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_LOOKUP_KIND*, void>)&_getLocationOfThisType;
-            callbacks[138] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_CONST_LOOKUP*, void>)&_getAddressOfPInvokeTarget;
-            callbacks[139] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, void**, void*>)&_GetCookieForPInvokeCalliSig;
-            callbacks[140] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, byte>)&_canGetCookieForPInvokeCalliSig;
-            callbacks[141] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_JUST_MY_CODE_HANDLE_**, CORINFO_JUST_MY_CODE_HANDLE_*>)&_getJustMyCodeHandle;
-            callbacks[142] = (delegate* unmanaged<IntPtr, IntPtr*, bool*, void**, bool*, void>)&_GetProfilingHandle;
-            callbacks[143] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, CORINFO_RESOLVED_TOKEN*, CORINFO_METHOD_STRUCT_*, CORINFO_CALLINFO_FLAGS, CORINFO_CALL_INFO*, void>)&_getCallInfo;
-            callbacks[144] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_CLASS_STRUCT_*, byte>)&_canAccessFamily;
-            callbacks[145] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, byte>)&_isRIDClassDomainID;
-            callbacks[146] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, void**, uint>)&_getClassDomainID;
-            callbacks[147] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, void**, void*>)&_getFieldAddress;
-            callbacks[148] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, ulong*, byte>)&_getReadonlyStaticFieldValue;
-            callbacks[149] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, byte*, CORINFO_CLASS_STRUCT_*>)&_getStaticFieldCurrentClass;
-            callbacks[150] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, void**, IntPtr>)&_getVarArgsHandle;
-            callbacks[151] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, byte>)&_canGetVarArgsHandle;
-            callbacks[152] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_MODULE_STRUCT_*, mdToken, void**, InfoAccessType>)&_constructStringLiteral;
-            callbacks[153] = (delegate* unmanaged<IntPtr, IntPtr*, void**, InfoAccessType>)&_emptyStringLiteral;
-            callbacks[154] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, void**, uint>)&_getFieldThreadLocalStoreID;
-            callbacks[155] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_MODULE_STRUCT_*, CORINFO_MODULE_STRUCT_*, void>)&_addActiveDependency;
-            callbacks[156] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_CLASS_STRUCT_*, CORINFO_METHOD_STRUCT_*, DelegateCtorArgs*, CORINFO_METHOD_STRUCT_*>)&_GetDelegateCtor;
-            callbacks[157] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, void>)&_MethodCompileComplete;
-            callbacks[158] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, CORINFO_SIG_INFO*, CORINFO_GET_TAILCALL_HELPERS_FLAGS, CORINFO_TAILCALL_HELPERS*, byte>)&_getTailCallHelpers;
-            callbacks[159] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, byte, byte>)&_convertPInvokeCalliToCall;
-            callbacks[160] = (delegate* unmanaged<IntPtr, IntPtr*, InstructionSet, byte, byte>)&_notifyInstructionSetUsage;
-            callbacks[161] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CONST_LOOKUP*, void>)&_updateEntryPointForTailCall;
-            callbacks[162] = (delegate* unmanaged<IntPtr, IntPtr*, AllocMemArgs*, void>)&_allocMem;
-            callbacks[163] = (delegate* unmanaged<IntPtr, IntPtr*, byte, byte, uint, void>)&_reserveUnwindInfo;
-            callbacks[164] = (delegate* unmanaged<IntPtr, IntPtr*, byte*, byte*, uint, uint, uint, byte*, CorJitFuncKind, void>)&_allocUnwindInfo;
-            callbacks[165] = (delegate* unmanaged<IntPtr, IntPtr*, UIntPtr, void*>)&_allocGCInfo;
-            callbacks[166] = (delegate* unmanaged<IntPtr, IntPtr*, uint, void>)&_setEHcount;
-            callbacks[167] = (delegate* unmanaged<IntPtr, IntPtr*, uint, CORINFO_EH_CLAUSE*, void>)&_setEHinfo;
-            callbacks[168] = (delegate* unmanaged<IntPtr, IntPtr*, uint, byte*, IntPtr, byte>)&_logMsg;
-            callbacks[169] = (delegate* unmanaged<IntPtr, IntPtr*, byte*, int, byte*, int>)&_doAssert;
-            callbacks[170] = (delegate* unmanaged<IntPtr, IntPtr*, CorJitResult, void>)&_reportFatalError;
-            callbacks[171] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, PgoInstrumentationSchema**, uint*, byte**, PgoSource*, HRESULT>)&_getPgoInstrumentationResults;
-            callbacks[172] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, PgoInstrumentationSchema*, uint, byte**, HRESULT>)&_allocPgoInstrumentationBySchema;
-            callbacks[173] = (delegate* unmanaged<IntPtr, IntPtr*, uint, CORINFO_SIG_INFO*, CORINFO_METHOD_STRUCT_*, void>)&_recordCallSite;
-            callbacks[174] = (delegate* unmanaged<IntPtr, IntPtr*, void*, void*, void*, ushort, ushort, int, void>)&_recordRelocation;
-            callbacks[175] = (delegate* unmanaged<IntPtr, IntPtr*, void*, ushort>)&_getRelocTypeHint;
-            callbacks[176] = (delegate* unmanaged<IntPtr, IntPtr*, uint>)&_getExpectedTargetArchitecture;
-            callbacks[177] = (delegate* unmanaged<IntPtr, IntPtr*, CORJIT_FLAGS*, uint, uint>)&_getJitFlags;
+            callbacks[68] = (delegate* unmanaged<IntPtr, IntPtr*, void*, CORINFO_CLASS_STRUCT_*>)&_getObjectType;
+            callbacks[69] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, CORINFO_LOOKUP_KIND*, CorInfoHelpFunc, CORINFO_CONST_LOOKUP*, byte>)&_getReadyToRunHelper;
+            callbacks[70] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, mdToken, CORINFO_CLASS_STRUCT_*, CORINFO_LOOKUP*, void>)&_getReadyToRunDelegateCtorHelper;
+            callbacks[71] = (delegate* unmanaged<IntPtr, IntPtr*, CorInfoHelpFunc, byte*>)&_getHelperName;
+            callbacks[72] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, CORINFO_METHOD_STRUCT_*, CORINFO_CONTEXT_STRUCT*, CorInfoInitClassResult>)&_initClass;
+            callbacks[73] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, void>)&_classMustBeLoadedBeforeCodeIsRun;
+            callbacks[74] = (delegate* unmanaged<IntPtr, IntPtr*, CorInfoClassId, CORINFO_CLASS_STRUCT_*>)&_getBuiltinClass;
+            callbacks[75] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CorInfoType>)&_getTypeForPrimitiveValueClass;
+            callbacks[76] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CorInfoType>)&_getTypeForPrimitiveNumericClass;
+            callbacks[77] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*, byte>)&_canCast;
+            callbacks[78] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*, byte>)&_areTypesEquivalent;
+            callbacks[79] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*, TypeCompareState>)&_compareTypesForCast;
+            callbacks[80] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*, TypeCompareState>)&_compareTypesForEquality;
+            callbacks[81] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*>)&_mergeClasses;
+            callbacks[82] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*, byte>)&_isMoreSpecificType;
+            callbacks[83] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*>)&_getParentType;
+            callbacks[84] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_**, CorInfoType>)&_getChildType;
+            callbacks[85] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, byte>)&_satisfiesClassConstraints;
+            callbacks[86] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, byte>)&_isSDArray;
+            callbacks[87] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, uint>)&_getArrayRank;
+            callbacks[88] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CorInfoArrayIntrinsic>)&_getArrayIntrinsicID;
+            callbacks[89] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, uint, void*>)&_getArrayInitializationData;
+            callbacks[90] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, CORINFO_METHOD_STRUCT_*, CORINFO_HELPER_DESC*, CorInfoIsAccessAllowedResult>)&_canAccessClass;
+            callbacks[91] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, byte**, byte*>)&_getFieldName;
+            callbacks[92] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, CORINFO_CLASS_STRUCT_*>)&_getFieldClass;
+            callbacks[93] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, CORINFO_CLASS_STRUCT_**, CORINFO_CLASS_STRUCT_*, CorInfoType>)&_getFieldType;
+            callbacks[94] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, uint>)&_getFieldOffset;
+            callbacks[95] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, CORINFO_METHOD_STRUCT_*, CORINFO_ACCESS_FLAGS, CORINFO_FIELD_INFO*, void>)&_getFieldInfo;
+            callbacks[96] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, byte>)&_isFieldStatic;
+            callbacks[97] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint*, uint**, BoundaryTypes*, void>)&_getBoundaries;
+            callbacks[98] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint, OffsetMapping*, void>)&_setBoundaries;
+            callbacks[99] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint*, ILVarInfo**, bool*, void>)&_getVars;
+            callbacks[100] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint, NativeVarInfo*, void>)&_setVars;
+            callbacks[101] = (delegate* unmanaged<IntPtr, IntPtr*, InlineTreeNode*, uint, RichOffsetMapping*, uint, void>)&_reportRichMappings;
+            callbacks[102] = (delegate* unmanaged<IntPtr, IntPtr*, UIntPtr, void*>)&_allocateArray;
+            callbacks[103] = (delegate* unmanaged<IntPtr, IntPtr*, void*, void>)&_freeArray;
+            callbacks[104] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_ARG_LIST_STRUCT_*, CORINFO_ARG_LIST_STRUCT_*>)&_getArgNext;
+            callbacks[105] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, CORINFO_ARG_LIST_STRUCT_*, CORINFO_CLASS_STRUCT_**, CorInfoTypeWithMod>)&_getArgType;
+            callbacks[106] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, int, CORINFO_CLASS_STRUCT_**, int>)&_getExactClasses;
+            callbacks[107] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, CORINFO_ARG_LIST_STRUCT_*, CORINFO_CLASS_STRUCT_*>)&_getArgClass;
+            callbacks[108] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CorInfoHFAElemType>)&_getHFAType;
+            callbacks[109] = (delegate* unmanaged<IntPtr, IntPtr*, _EXCEPTION_POINTERS*, HRESULT>)&_GetErrorHRESULT;
+            callbacks[110] = (delegate* unmanaged<IntPtr, IntPtr*, char*, uint, uint>)&_GetErrorMessage;
+            callbacks[111] = (delegate* unmanaged<IntPtr, IntPtr*, _EXCEPTION_POINTERS*, int>)&_FilterException;
+            callbacks[112] = (delegate* unmanaged<IntPtr, IntPtr*, HRESULT, void>)&_ThrowExceptionForJitResult;
+            callbacks[113] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_HELPER_DESC*, void>)&_ThrowExceptionForHelper;
+            callbacks[114] = (delegate* unmanaged<IntPtr, IntPtr*, void*, void*, byte>)&_runWithErrorTrap;
+            callbacks[115] = (delegate* unmanaged<IntPtr, IntPtr*, void*, void*, byte>)&_runWithSPMIErrorTrap;
+            callbacks[116] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_EE_INFO*, void>)&_getEEInfo;
+            callbacks[117] = (delegate* unmanaged<IntPtr, IntPtr*, char*>)&_getJitTimeLogFilename;
+            callbacks[118] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, mdToken>)&_getMethodDefFromMethod;
+            callbacks[119] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, byte**, byte*>)&_getMethodName;
+            callbacks[120] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, byte**, byte**, byte**, byte*>)&_getMethodNameFromMetadata;
+            callbacks[121] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint>)&_getMethodHash;
+            callbacks[122] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_MODULE_STRUCT_*, mdToken, byte*, UIntPtr, UIntPtr>)&_findNameOfToken;
+            callbacks[123] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR*, byte>)&_getSystemVAmd64PassStructInRegisterDescriptor;
+            callbacks[124] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, uint>)&_getLoongArch64PassStructInRegisterFlags;
+            callbacks[125] = (delegate* unmanaged<IntPtr, IntPtr*, void**, uint>)&_getThreadTLSIndex;
+            callbacks[126] = (delegate* unmanaged<IntPtr, IntPtr*, void**, void*>)&_getInlinedCallFrameVptr;
+            callbacks[127] = (delegate* unmanaged<IntPtr, IntPtr*, void**, int*>)&_getAddrOfCaptureThreadGlobal;
+            callbacks[128] = (delegate* unmanaged<IntPtr, IntPtr*, CorInfoHelpFunc, void**, void*>)&_getHelperFtn;
+            callbacks[129] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_CONST_LOOKUP*, CORINFO_ACCESS_FLAGS, void>)&_getFunctionEntryPoint;
+            callbacks[130] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, byte, CORINFO_CONST_LOOKUP*, void>)&_getFunctionFixedEntryPoint;
+            callbacks[131] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, void**, void*>)&_getMethodSync;
+            callbacks[132] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_MODULE_STRUCT_*, CorInfoHelpFunc>)&_getLazyStringLiteralHelper;
+            callbacks[133] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_MODULE_STRUCT_*, void**, CORINFO_MODULE_STRUCT_*>)&_embedModuleHandle;
+            callbacks[134] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, void**, CORINFO_CLASS_STRUCT_*>)&_embedClassHandle;
+            callbacks[135] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, void**, CORINFO_METHOD_STRUCT_*>)&_embedMethodHandle;
+            callbacks[136] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, void**, CORINFO_FIELD_STRUCT_*>)&_embedFieldHandle;
+            callbacks[137] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, byte, CORINFO_GENERICHANDLE_RESULT*, void>)&_embedGenericHandle;
+            callbacks[138] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_LOOKUP_KIND*, void>)&_getLocationOfThisType;
+            callbacks[139] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_CONST_LOOKUP*, void>)&_getAddressOfPInvokeTarget;
+            callbacks[140] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, void**, void*>)&_GetCookieForPInvokeCalliSig;
+            callbacks[141] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, byte>)&_canGetCookieForPInvokeCalliSig;
+            callbacks[142] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_JUST_MY_CODE_HANDLE_**, CORINFO_JUST_MY_CODE_HANDLE_*>)&_getJustMyCodeHandle;
+            callbacks[143] = (delegate* unmanaged<IntPtr, IntPtr*, bool*, void**, bool*, void>)&_GetProfilingHandle;
+            callbacks[144] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, CORINFO_RESOLVED_TOKEN*, CORINFO_METHOD_STRUCT_*, CORINFO_CALLINFO_FLAGS, CORINFO_CALL_INFO*, void>)&_getCallInfo;
+            callbacks[145] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_CLASS_STRUCT_*, byte>)&_canAccessFamily;
+            callbacks[146] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, byte>)&_isRIDClassDomainID;
+            callbacks[147] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, void**, uint>)&_getClassDomainID;
+            callbacks[148] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, void**, void*>)&_getFieldAddress;
+            callbacks[149] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, ulong*, byte>)&_getReadonlyStaticFieldValue;
+            callbacks[150] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, byte*, CORINFO_CLASS_STRUCT_*>)&_getStaticFieldCurrentClass;
+            callbacks[151] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, void**, IntPtr>)&_getVarArgsHandle;
+            callbacks[152] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, byte>)&_canGetVarArgsHandle;
+            callbacks[153] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_MODULE_STRUCT_*, mdToken, void**, InfoAccessType>)&_constructStringLiteral;
+            callbacks[154] = (delegate* unmanaged<IntPtr, IntPtr*, void**, InfoAccessType>)&_emptyStringLiteral;
+            callbacks[155] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, void**, uint>)&_getFieldThreadLocalStoreID;
+            callbacks[156] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_MODULE_STRUCT_*, CORINFO_MODULE_STRUCT_*, void>)&_addActiveDependency;
+            callbacks[157] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_CLASS_STRUCT_*, CORINFO_METHOD_STRUCT_*, DelegateCtorArgs*, CORINFO_METHOD_STRUCT_*>)&_GetDelegateCtor;
+            callbacks[158] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, void>)&_MethodCompileComplete;
+            callbacks[159] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, CORINFO_SIG_INFO*, CORINFO_GET_TAILCALL_HELPERS_FLAGS, CORINFO_TAILCALL_HELPERS*, byte>)&_getTailCallHelpers;
+            callbacks[160] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, byte, byte>)&_convertPInvokeCalliToCall;
+            callbacks[161] = (delegate* unmanaged<IntPtr, IntPtr*, InstructionSet, byte, byte>)&_notifyInstructionSetUsage;
+            callbacks[162] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CONST_LOOKUP*, void>)&_updateEntryPointForTailCall;
+            callbacks[163] = (delegate* unmanaged<IntPtr, IntPtr*, AllocMemArgs*, void>)&_allocMem;
+            callbacks[164] = (delegate* unmanaged<IntPtr, IntPtr*, byte, byte, uint, void>)&_reserveUnwindInfo;
+            callbacks[165] = (delegate* unmanaged<IntPtr, IntPtr*, byte*, byte*, uint, uint, uint, byte*, CorJitFuncKind, void>)&_allocUnwindInfo;
+            callbacks[166] = (delegate* unmanaged<IntPtr, IntPtr*, UIntPtr, void*>)&_allocGCInfo;
+            callbacks[167] = (delegate* unmanaged<IntPtr, IntPtr*, uint, void>)&_setEHcount;
+            callbacks[168] = (delegate* unmanaged<IntPtr, IntPtr*, uint, CORINFO_EH_CLAUSE*, void>)&_setEHinfo;
+            callbacks[169] = (delegate* unmanaged<IntPtr, IntPtr*, uint, byte*, IntPtr, byte>)&_logMsg;
+            callbacks[170] = (delegate* unmanaged<IntPtr, IntPtr*, byte*, int, byte*, int>)&_doAssert;
+            callbacks[171] = (delegate* unmanaged<IntPtr, IntPtr*, CorJitResult, void>)&_reportFatalError;
+            callbacks[172] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, PgoInstrumentationSchema**, uint*, byte**, PgoSource*, HRESULT>)&_getPgoInstrumentationResults;
+            callbacks[173] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, PgoInstrumentationSchema*, uint, byte**, HRESULT>)&_allocPgoInstrumentationBySchema;
+            callbacks[174] = (delegate* unmanaged<IntPtr, IntPtr*, uint, CORINFO_SIG_INFO*, CORINFO_METHOD_STRUCT_*, void>)&_recordCallSite;
+            callbacks[175] = (delegate* unmanaged<IntPtr, IntPtr*, void*, void*, void*, ushort, ushort, int, void>)&_recordRelocation;
+            callbacks[176] = (delegate* unmanaged<IntPtr, IntPtr*, void*, ushort>)&_getRelocTypeHint;
+            callbacks[177] = (delegate* unmanaged<IntPtr, IntPtr*, uint>)&_getExpectedTargetArchitecture;
+            callbacks[178] = (delegate* unmanaged<IntPtr, IntPtr*, CORJIT_FLAGS*, uint, uint>)&_getJitFlags;
 
             return (IntPtr)callbacks;
         }
diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
index fe798522b7116b..6646c1629b2dea 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
@@ -2350,6 +2350,13 @@ private CorInfoHelpFunc getUnBoxHelper(CORINFO_CLASS_STRUCT_* cls)
             return (void*)IntPtr.Zero;
         }
 
+#pragma warning disable CA1822 // Mark members as static
+        private CORINFO_CLASS_STRUCT_* getObjectType(void* typeObj)
+#pragma warning restore CA1822 // Mark members as static
+        {
+            return (CORINFO_CLASS_STRUCT_*)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 0b39f744e5a60b..e83f4a78934fc3 100644
--- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt
+++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt
@@ -225,6 +225,7 @@ FUNCTIONS
     CorInfoHelpFunc getBoxHelper(CORINFO_CLASS_HANDLE cls)
     CorInfoHelpFunc getUnBoxHelper(CORINFO_CLASS_HANDLE cls)
     void* getRuntimeTypePointer(CORINFO_CLASS_HANDLE cls)
+    CORINFO_CLASS_HANDLE getObjectType(void* typeObj)
     bool getReadyToRunHelper(CORINFO_RESOLVED_TOKEN * pResolvedToken, CORINFO_LOOKUP_KIND * pGenericLookupKind, CorInfoHelpFunc id, CORINFO_CONST_LOOKUP *pLookup)
     void getReadyToRunDelegateCtorHelper(CORINFO_RESOLVED_TOKEN * pTargetMethod, mdToken targetConstraint, CORINFO_CLASS_HANDLE delegateType, CORINFO_LOOKUP *pLookup)
     const char* getHelperName(CorInfoHelpFunc helpFunc)
diff --git a/src/coreclr/tools/aot/jitinterface/jitinterface.h b/src/coreclr/tools/aot/jitinterface/jitinterface.h
index 5aea3a0e440574..99f4359d3c655c 100644
--- a/src/coreclr/tools/aot/jitinterface/jitinterface.h
+++ b/src/coreclr/tools/aot/jitinterface/jitinterface.h
@@ -79,6 +79,7 @@ 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);
+    CORINFO_CLASS_HANDLE (* getObjectType)(void * thisHandle, CorInfoExceptionClass** ppException, void* typeObj);
     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);
@@ -864,6 +865,15 @@ class JitInterfaceWrapper : public ICorJitInfo
     return temp;
 }
 
+    virtual CORINFO_CLASS_HANDLE getObjectType(
+          void* typeObj)
+{
+    CorInfoExceptionClass* pException = nullptr;
+    CORINFO_CLASS_HANDLE temp = _callbacks->getObjectType(_thisHandle, &pException, typeObj);
+    if (pException != nullptr) throw pException;
+    return temp;
+}
+
     virtual bool getReadyToRunHelper(
           CORINFO_RESOLVED_TOKEN* pResolvedToken,
           CORINFO_LOOKUP_KIND* pGenericLookupKind,
diff --git a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h
index dde3813f23e62b..7dec7d97fcb0d9 100644
--- a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h
+++ b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h
@@ -140,6 +140,7 @@ LWM(GetTypeForPrimitiveNumericClass, DWORDLONG, DWORD)
 LWM(GetUnboxedEntry, DWORDLONG, DLD);
 LWM(GetUnBoxHelper, DWORDLONG, DWORD)
 LWM(GetRuntimeTypePointer, DWORDLONG, DWORDLONG)
+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 215beb5bdb38d6..01837d744aa0af 100644
--- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp
+++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp
@@ -2210,6 +2210,29 @@ void* MethodContext::repGetRuntimeTypePointer(CORINFO_CLASS_HANDLE cls)
     return (void*)value;
 }
 
+void MethodContext::recGetObjectType(void* typeObj, CORINFO_CLASS_HANDLE result)
+{
+    if (GetObjectType == nullptr)
+        GetObjectType = new LightWeightMap<DWORDLONG, DWORDLONG>();
+
+    DWORDLONG key = (DWORDLONG)typeObj;
+    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* typeObj)
+{
+    DWORDLONG key = (DWORDLONG)typeObj;
+    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,
diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h
index 8bb34b96403303..eb7c716b91f6df 100644
--- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h
+++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h
@@ -314,6 +314,10 @@ class MethodContext
     void dmpGetRuntimeTypePointer(DWORDLONG key, DWORDLONG value);
     void* repGetRuntimeTypePointer(CORINFO_CLASS_HANDLE cls);
 
+    void recGetObjectType(void* typeObj, CORINFO_CLASS_HANDLE result);
+    void dmpGetObjectType(DWORDLONG key, DWORDLONG value);
+    CORINFO_CLASS_HANDLE repGetObjectType(void* typeObj);
+
     void recGetReadyToRunHelper(CORINFO_RESOLVED_TOKEN* pResolvedToken,
                                 CORINFO_LOOKUP_KIND*    pGenericLookupKind,
                                 CorInfoHelpFunc         id,
@@ -1144,6 +1148,7 @@ enum mcPackets
     Packet_GetRuntimeTypePointer = 196,
     Packet_ObjectToString = 197,
     Packet_GetReadonlyStaticFieldValue = 198,
+    Packet_GetObjectType = 199,
 };
 
 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 e1bf9ffcb56c49..d55f13b2a30126 100644
--- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp
+++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp
@@ -798,6 +798,14 @@ void* interceptor_ICJI::getRuntimeTypePointer(CORINFO_CLASS_HANDLE cls)
     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,
diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp
index a82bef0d7e452c..6e2f9f007b41b0 100644
--- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp
+++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp
@@ -551,6 +551,13 @@ void* interceptor_ICJI::getRuntimeTypePointer(
     return original_ICorJitInfo->getRuntimeTypePointer(cls);
 }
 
+CORINFO_CLASS_HANDLE interceptor_ICJI::getObjectType(
+          void* typeObj)
+{
+    mcs->AddCall("getObjectType");
+    return original_ICorJitInfo->getObjectType(typeObj);
+}
+
 bool interceptor_ICJI::getReadyToRunHelper(
           CORINFO_RESOLVED_TOKEN* pResolvedToken,
           CORINFO_LOOKUP_KIND* pGenericLookupKind,
diff --git a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp
index 2afc4f6301dd87..3a6ccd6cc71646 100644
--- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp
+++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp
@@ -483,6 +483,12 @@ void* interceptor_ICJI::getRuntimeTypePointer(
     return original_ICorJitInfo->getRuntimeTypePointer(cls);
 }
 
+CORINFO_CLASS_HANDLE interceptor_ICJI::getObjectType(
+          void* typeObj)
+{
+    return original_ICorJitInfo->getObjectType(typeObj);
+}
+
 bool interceptor_ICJI::getReadyToRunHelper(
           CORINFO_RESOLVED_TOKEN* pResolvedToken,
           CORINFO_LOOKUP_KIND* pGenericLookupKind,
diff --git a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp
index 0afd8ae9a21292..e4d76580076763 100644
--- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp
+++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp
@@ -679,6 +679,13 @@ void* MyICJI::getRuntimeTypePointer(CORINFO_CLASS_HANDLE cls)
     return result;
 }
 
+CORINFO_CLASS_HANDLE MyICJI::getObjectType(void* typeObj)
+{
+    jitInstance->mc->cr->AddCall("getObjectType");
+    CORINFO_CLASS_HANDLE result = jitInstance->mc->repGetObjectType(typeObj);
+    return result;
+}
+
 bool MyICJI::getReadyToRunHelper(CORINFO_RESOLVED_TOKEN* pResolvedToken,
                                  CORINFO_LOOKUP_KIND*    pGenericLookupKind,
                                  CorInfoHelpFunc         id,
diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp
index ac182c198681e0..ce0d5d05f16ad2 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -6015,6 +6015,32 @@ void* CEEInfo::getRuntimeTypePointer(CORINFO_CLASS_HANDLE clsHnd)
     return pointer;
 }
 
+/***********************************************************************/
+CORINFO_CLASS_HANDLE CEEInfo::getObjectType(void* typeObj)
+{
+    CONTRACTL{
+        THROWS;
+        GC_TRIGGERS;
+        MODE_PREEMPTIVE;
+    } CONTRACTL_END;
+
+    CORINFO_CLASS_HANDLE handle = NULL;
+
+    JIT_TO_EE_TRANSITION();
+
+    if (typeObj != nullptr)
+    {
+        GCX_COOP();
+        Object* obj = (Object*)typeObj;
+        VALIDATEOBJECT(obj);
+        handle = (CORINFO_CLASS_HANDLE)obj->GetMethodTable();
+    }
+
+    EE_TO_JIT_TRANSITION();
+
+    return handle;
+}
+
 /***********************************************************************/
 bool CEEInfo::getReadyToRunHelper(
         CORINFO_RESOLVED_TOKEN *        pResolvedToken,

From 97c3cdf16da000d7d2f8d4fc3433de708b047249 Mon Sep 17 00:00:00 2001
From: EgorBo <egorbo@gmail.com>
Date: Sat, 24 Sep 2022 12:21:40 +0200
Subject: [PATCH 05/61] use memcpy

---
 src/coreclr/inc/corinfo.h                     |  3 +-
 src/coreclr/inc/icorjitinfoimpl_generated.h   |  3 +-
 src/coreclr/jit/ICorJitInfo_API_wrapper.hpp   |  5 +-
 src/coreclr/jit/compiler.h                    |  2 +-
 src/coreclr/jit/importer.cpp                  | 45 +++++++---
 .../tools/Common/JitInterface/CorInfoBase.cs  |  6 +-
 .../tools/Common/JitInterface/CorInfoImpl.cs  |  2 +-
 .../ThunkGenerator/ThunkInput.txt             |  4 +-
 .../tools/aot/jitinterface/jitinterface.h     |  7 +-
 .../tools/superpmi/superpmi-shared/lwmlist.h  |  2 +-
 .../superpmi-shared/methodcontext.cpp         | 82 ++++++++++---------
 .../superpmi/superpmi-shared/methodcontext.h  |  6 +-
 .../superpmi-shim-collector/icorjitinfo.cpp   |  6 +-
 .../superpmi-shim-counter/icorjitinfo.cpp     |  5 +-
 .../superpmi-shim-simple/icorjitinfo.cpp      |  5 +-
 .../tools/superpmi/superpmi/icorjitinfo.cpp   |  4 +-
 src/coreclr/vm/jitinterface.cpp               | 48 +++--------
 src/coreclr/vm/jitinterface.h                 |  1 -
 18 files changed, 121 insertions(+), 115 deletions(-)

diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h
index b08d5c26e6ea31..1b4befc32de34e 100644
--- a/src/coreclr/inc/corinfo.h
+++ b/src/coreclr/inc/corinfo.h
@@ -3161,7 +3161,8 @@ class ICorDynamicInfo : public ICorStaticInfo
     //  * frozen object
     virtual bool getReadonlyStaticFieldValue(
                     CORINFO_FIELD_HANDLE    field,
-                    uint64_t               *pValue
+                    uint8_t                *buffer,
+                    int                     bufferSize
                     ) = 0;
 
     // If pIsSpeculative is NULL, return the class handle for the value of ref-class typed
diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h
index 0acbe25d4fef82..6a54465d383dcb 100644
--- a/src/coreclr/inc/icorjitinfoimpl_generated.h
+++ b/src/coreclr/inc/icorjitinfoimpl_generated.h
@@ -610,7 +610,8 @@ void* getFieldAddress(
 
 bool getReadonlyStaticFieldValue(
           CORINFO_FIELD_HANDLE field,
-          uint64_t* pValue) override;
+          uint8_t* buffer,
+          int bufferSize) override;
 
 CORINFO_CLASS_HANDLE getStaticFieldCurrentClass(
           CORINFO_FIELD_HANDLE field,
diff --git a/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp b/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp
index 49cc32abdc4eac..4c2e2b95ef40f0 100644
--- a/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp
+++ b/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp
@@ -1461,10 +1461,11 @@ void* WrapICorJitInfo::getFieldAddress(
 
 bool WrapICorJitInfo::getReadonlyStaticFieldValue(
           CORINFO_FIELD_HANDLE field,
-          uint64_t* pValue)
+          uint8_t* buffer,
+          int bufferSize)
 {
     API_ENTER(getReadonlyStaticFieldValue);
-    bool temp = wrapHnd->getReadonlyStaticFieldValue(field, pValue);
+    bool temp = wrapHnd->getReadonlyStaticFieldValue(field, buffer, bufferSize);
     API_LEAVE(getReadonlyStaticFieldValue);
     return temp;
 }
diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h
index 3e41a941296458..3a72605a8eee6a 100644
--- a/src/coreclr/jit/compiler.h
+++ b/src/coreclr/jit/compiler.h
@@ -3639,7 +3639,7 @@ class Compiler
 
     GenTree* impInitClass(CORINFO_RESOLVED_TOKEN* pResolvedToken);
 
-    GenTree* impImportStaticReadOnlyField(UINT64 value, var_types valueType);
+    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/importer.cpp b/src/coreclr/jit/importer.cpp
index 63de90e3d10130..baeed615943f57 100644
--- a/src/coreclr/jit/importer.cpp
+++ b/src/coreclr/jit/importer.cpp
@@ -8116,8 +8116,11 @@ GenTree* Compiler::impInitClass(CORINFO_RESOLVED_TOKEN* pResolvedToken)
     return node;
 }
 
-GenTree* Compiler::impImportStaticReadOnlyField(UINT64 value, var_types valueType)
+GenTree* Compiler::impImportStaticReadOnlyField(uint8_t* buffer, int bufferSize, var_types valueType)
 {
+    // We plan to support bigger values for structs, but for now it's always 64bit
+    assert(bufferSize == sizeof(INT64));
+
     GenTree* tree = nullptr;
     switch (valueType)
     {
@@ -8128,34 +8131,53 @@ GenTree* Compiler::impImportStaticReadOnlyField(UINT64 value, var_types valueTyp
         case TYP_USHORT:
         case TYP_UINT:
         case TYP_INT:
-            tree = gtNewIconNode((ssize_t)value);
+        {
+            ssize_t i32;
+            memcpy(&i32, buffer, sizeof(ssize_t));
+            tree = gtNewIconNode(i32);
             break;
+        }
 
         case TYP_LONG:
         case TYP_ULONG:
-            tree = gtNewLconNode((INT64)value);
+        {
+            INT64 i64;
+            memcpy(&i64, buffer, sizeof(INT64));
+            tree = gtNewLconNode(i64);
             break;
+        }
 
         case TYP_FLOAT:
-            tree = gtNewDconNode(*((float*)&value));
+        {
+            float f32;
+            memcpy(&f32, buffer, sizeof(float));
+            tree = gtNewDconNode(f32);
             break;
+        }
 
         case TYP_DOUBLE:
-            tree = gtNewDconNode(*((double*)&value));
+        {
+            float f64;
+            memcpy(&f64, buffer, sizeof(double));
+            tree = gtNewDconNode(f64);
             break;
+        }
 
         case TYP_REF:
         {
-            if (value == 0)
+            ssize_t ptr;
+            memcpy(&ptr, buffer, sizeof(ssize_t));
+            
+            if (ptr == 0)
             {
                 tree = gtNewNull();
             }
             else
             {
                 setMethodHasFrozenObjects();
-                tree         = gtNewIconEmbHndNode((void*)value, nullptr, GTF_ICON_OBJ_HDL, nullptr);
+                tree         = gtNewIconEmbHndNode((void*)ptr, nullptr, GTF_ICON_OBJ_HDL, nullptr);
                 tree->gtType = TYP_REF;
-                INDEBUG(tree->AsIntCon()->gtTargetHandle = (size_t)value);
+                INDEBUG(tree->AsIntCon()->gtTargetHandle = (size_t)ptr);
             }
             break;
         }
@@ -15247,10 +15269,11 @@ void Compiler::impImportBlockCode(BasicBlock* block)
                         if ((aflags & CORINFO_ACCESS_GET) && (fieldInfo.fieldFlags & CORINFO_FLG_FIELD_FINAL) &&
                             !(fieldInfo.fieldFlags & CORINFO_FLG_FIELD_STATIC_IN_HEAP))
                         {
-                            UINT64 value;
-                            if (info.compCompHnd->getReadonlyStaticFieldValue(resolvedToken.hField, &value))
+                            const int bufferSize = sizeof(uint64_t);
+                            uint8_t buffer[bufferSize] = {0};
+                            if (info.compCompHnd->getReadonlyStaticFieldValue(resolvedToken.hField, buffer, bufferSize))
                             {
-                                GenTree* cnsValue = impImportStaticReadOnlyField(value, lclTyp);
+                                GenTree* cnsValue = impImportStaticReadOnlyField(buffer, bufferSize, lclTyp);
                                 if (cnsValue != nullptr)
                                 {
                                     op1 = cnsValue;
diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs b/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs
index a8e12f59ee85f2..47805909574f71 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs
@@ -2214,12 +2214,12 @@ private static uint _getClassDomainID(IntPtr thisHandle, IntPtr* ppException, CO
         }
 
         [UnmanagedCallersOnly]
-        private static byte _getReadonlyStaticFieldValue(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field, ulong* pValue)
+        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, ref *pValue) ? (byte)1 : (byte)0;
+                return _this.getReadonlyStaticFieldValue(field, buffer, bufferSize) ? (byte)1 : (byte)0;
             }
             catch (Exception ex)
             {
@@ -2806,7 +2806,7 @@ private static IntPtr GetUnmanagedCallbacks()
             callbacks[146] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, byte>)&_isRIDClassDomainID;
             callbacks[147] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, void**, uint>)&_getClassDomainID;
             callbacks[148] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, void**, void*>)&_getFieldAddress;
-            callbacks[149] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, ulong*, byte>)&_getReadonlyStaticFieldValue;
+            callbacks[149] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, byte*, int, byte>)&_getReadonlyStaticFieldValue;
             callbacks[150] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, byte*, CORINFO_CLASS_STRUCT_*>)&_getStaticFieldCurrentClass;
             callbacks[151] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, void**, IntPtr>)&_getVarArgsHandle;
             callbacks[152] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, byte>)&_canGetVarArgsHandle;
diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
index 6646c1629b2dea..6ef615b5ca1ab0 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
@@ -3314,7 +3314,7 @@ private uint getClassDomainID(CORINFO_CLASS_STRUCT_* cls, ref void* ppIndirectio
         }
 
 #pragma warning disable CA1822 // Mark members as static
-        private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* field, ref ulong pHandle)
+        private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* field, byte* buffer, int bufferSize)
 #pragma warning restore CA1822 // Mark members as static
         {
             return false;
diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt
index e83f4a78934fc3..7ae8475d1506a9 100644
--- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt
+++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt
@@ -58,7 +58,6 @@ GSCookie**,IntPtr**
 bool*,ref bool
 BoolStar,byte*,bool*,bool*
 uint32_t*,ref uint
-uint64_t*,ref ulong
 void **,ref void*
 VOIDSTARSTAR,void **,void **,void **
 int32_t*,int*
@@ -71,7 +70,6 @@ wchar_t*,char*
 const wchar_t*,String
 
 uint32_t**,ref uint*
-uint64_t**,ref ulong*
 unsigned*,ref uint
 CORJIT_FLAGS*,ref CORJIT_FLAGS
 CORINFO_CONST_LOOKUP*,ref CORINFO_CONST_LOOKUP
@@ -306,7 +304,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, uint64_t *pValue);
+    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/jitinterface/jitinterface.h b/src/coreclr/tools/aot/jitinterface/jitinterface.h
index 99f4359d3c655c..b00339b2b4e95a 100644
--- a/src/coreclr/tools/aot/jitinterface/jitinterface.h
+++ b/src/coreclr/tools/aot/jitinterface/jitinterface.h
@@ -160,7 +160,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, uint64_t* pValue);
+    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);
@@ -1636,10 +1636,11 @@ class JitInterfaceWrapper : public ICorJitInfo
 
     virtual bool getReadonlyStaticFieldValue(
           CORINFO_FIELD_HANDLE field,
-          uint64_t* pValue)
+          uint8_t* buffer,
+          int bufferSize)
 {
     CorInfoExceptionClass* pException = nullptr;
-    bool temp = _callbacks->getReadonlyStaticFieldValue(_thisHandle, &pException, field, pValue);
+    bool temp = _callbacks->getReadonlyStaticFieldValue(_thisHandle, &pException, field, buffer, bufferSize);
     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 7dec7d97fcb0d9..b0af2f1e3f2500 100644
--- a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h
+++ b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h
@@ -80,7 +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, DWORDLONG, DLD)
+LWM(GetReadonlyStaticFieldValue, DLD, DD)
 LWM(GetStaticFieldCurrentClass, DWORDLONG, 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 01837d744aa0af..294fab25b45b05 100644
--- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp
+++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp
@@ -3676,58 +3676,60 @@ void* MethodContext::repGetFieldAddress(CORINFO_FIELD_HANDLE field, void** ppInd
     return temp;
 }
 
-void MethodContext::recGetReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint64_t value, bool result)
+void MethodContext::recGetReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, bool result)
 {
     if (GetReadonlyStaticFieldValue == nullptr)
-        GetReadonlyStaticFieldValue = new LightWeightMap<DWORDLONG, DLD>();
+        GetReadonlyStaticFieldValue = new LightWeightMap<DLD, DD>();
 
-    DWORDLONG key = CastHandle(field);
-    DLD       val;
-    val.A = (DWORDLONG)value;
-    val.B = (DWORD)result;
-    GetReadonlyStaticFieldValue->Add(key, val);
-    DEBUG_REC(dmpGetReadonlyStaticFieldValue(key, val));
-}
-void MethodContext::dmpGetReadonlyStaticFieldValue(DWORDLONG key, DLD value)
-{
-    printf("GetReadonlyStaticFieldValue key field-%016llX, value-%016llX result-%08X", key, value.A, value.B);
-}
-bool MethodContext::repGetReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint64_t* value)
-{
-    DWORDLONG key = CastHandle(field);
-    AssertMapAndKeyExist(GetReadonlyStaticFieldValue, key, ": key %016llX", key);
-
-    DLD val = GetReadonlyStaticFieldValue->Get(key);
-    DEBUG_REP(dmpGetReadonlyStaticFieldValue(key, val));
+    DLD key;
+    ZeroMemory(&key, sizeof(key));
+    key.A = CastHandle(field);
+    key.B = (DWORD)bufferSize;
 
-    *value = (uint64_t)val.A;
-    return (bool)val.B;
-}
+    DWORD tmpBuf = (DWORD)-1;
+    if (buffer != nullptr && result)
+        tmpBuf = (DWORD)GetReadonlyStaticFieldValue->AddBuffer((uint8_t*)buffer, (uint32_t)bufferSize);
 
-/*
-void MethodContext::recGetReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, void* result)
-{
-    if (GetReadonlyStaticFieldValue == nullptr)
-        GetReadonlyStaticFieldValue = new LightWeightMap<DWORDLONG, DWORDLONG>();
+    DD value;
+    value.A = (DWORD)result;
+    value.B = (DWORD)tmpBuf;
 
-    DWORDLONG key = CastHandle(field);
-    DWORDLONG value = DWORDLONG(result);
     GetReadonlyStaticFieldValue->Add(key, value);
     DEBUG_REC(dmpGetReadonlyStaticFieldValue(key, value));
 }
-void MethodContext::dmpGetReadonlyStaticFieldValue(DWORDLONG key, DWORDLONG value)
+void MethodContext::dmpGetReadonlyStaticFieldValue(DLD key, DD value)
 {
-    printf("GetReadonlyStaticFieldValue key field-%016llX, value field-%016llX", key, value);
+    printf("GetReadonlyStaticFieldValue key fld-%016llX bufSize-%u, result-%u", key.A, key.B, value.A);
+    GetReadonlyStaticFieldValue->Unlock();
 }
-void* MethodContext::repGetReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field)
+bool MethodContext::repGetReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize)
 {
-    DWORDLONG key = CastHandle(field);
-    AssertMapAndKeyExist(GetReadonlyStaticFieldValue, key, ": key %016llX", key);
-    DWORDLONG value = GetReadonlyStaticFieldValue->Get(key);
-    DEBUG_REP(dmpGetReadonlyStaticFieldValue(key, value));
-    void* result = (void*)value;
-    return result;
-}*/
+    if (GetReadonlyStaticFieldValue == nullptr)
+        return false;
+
+    DLD key;
+    ZeroMemory(&key, sizeof(key));
+    key.A = CastHandle(field);
+    key.B = (DWORD)bufferSize;
+
+    int itemIndex = GetReadonlyStaticFieldValue->GetIndex(key);
+    if (itemIndex < 0)
+    {
+        return false;
+    }
+    else
+    {
+        DD value = GetReadonlyStaticFieldValue->Get(key);
+        DEBUG_REP(dmpGetReadonlyStaticFieldValue(key, value));
+        if (buffer != nullptr && (bool)value.A)
+        {
+            uint8_t* srcBuffer = (uint8_t*)GetReadonlyStaticFieldValue->GetBuffer(value.B);
+            Assert(srcBuffer != nullptr);
+            memcpy(buffer, srcBuffer, bufferSize);
+        }
+        return (bool)value.A;
+    }
+}
 
 void MethodContext::recGetStaticFieldCurrentClass(CORINFO_FIELD_HANDLE field,
                                                   bool                 isSpeculative,
diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h
index eb7c716b91f6df..219b5573cd0e14 100644
--- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h
+++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h
@@ -484,9 +484,9 @@ class MethodContext
     void dmpGetFieldAddress(DWORDLONG key, const Agnostic_GetFieldAddress& value);
     void* repGetFieldAddress(CORINFO_FIELD_HANDLE field, void** ppIndirection);
 
-    void recGetReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint64_t value, bool result);
-    void dmpGetReadonlyStaticFieldValue(DWORDLONG key, DLD value);
-    bool repGetReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint64_t* pValue);
+    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);
diff --git a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp
index d55f13b2a30126..b90a955fa53ff3 100644
--- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp
+++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp
@@ -1731,11 +1731,11 @@ void* interceptor_ICJI::getFieldAddress(CORINFO_FIELD_HANDLE field, void** ppInd
     return temp;
 }
 
-bool interceptor_ICJI::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint64_t* pValue)
+bool interceptor_ICJI::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize)
 {
     mc->cr->AddCall("getReadonlyStaticFieldValue");
-    bool result = original_ICorJitInfo->getReadonlyStaticFieldValue(field, pValue);
-    mc->recGetReadonlyStaticFieldValue(field, *pValue, result);
+    bool result = original_ICorJitInfo->getReadonlyStaticFieldValue(field, buffer, bufferSize);
+    mc->recGetReadonlyStaticFieldValue(field, buffer, bufferSize, result);
     return result;
 }
 
diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp
index 6e2f9f007b41b0..1e86378f5155b1 100644
--- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp
+++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp
@@ -1197,10 +1197,11 @@ void* interceptor_ICJI::getFieldAddress(
 
 bool interceptor_ICJI::getReadonlyStaticFieldValue(
           CORINFO_FIELD_HANDLE field,
-          uint64_t* pValue)
+          uint8_t* buffer,
+          int bufferSize)
 {
     mcs->AddCall("getReadonlyStaticFieldValue");
-    return original_ICorJitInfo->getReadonlyStaticFieldValue(field, pValue);
+    return original_ICorJitInfo->getReadonlyStaticFieldValue(field, buffer, bufferSize);
 }
 
 CORINFO_CLASS_HANDLE interceptor_ICJI::getStaticFieldCurrentClass(
diff --git a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp
index 3a6ccd6cc71646..1058681597f712 100644
--- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp
+++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp
@@ -1048,9 +1048,10 @@ void* interceptor_ICJI::getFieldAddress(
 
 bool interceptor_ICJI::getReadonlyStaticFieldValue(
           CORINFO_FIELD_HANDLE field,
-          uint64_t* pValue)
+          uint8_t* buffer,
+          int bufferSize)
 {
-    return original_ICorJitInfo->getReadonlyStaticFieldValue(field, pValue);
+    return original_ICorJitInfo->getReadonlyStaticFieldValue(field, buffer, bufferSize);
 }
 
 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 e4d76580076763..fe6e7a4c7bc36f 100644
--- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp
+++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp
@@ -1510,10 +1510,10 @@ void* MyICJI::getFieldAddress(CORINFO_FIELD_HANDLE field, void** ppIndirection)
     return jitInstance->mc->repGetFieldAddress(field, ppIndirection);
 }
 
-bool MyICJI::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint64_t* pValue)
+bool MyICJI::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize)
 {
     jitInstance->mc->cr->AddCall("getReadonlyStaticFieldValue");
-    return jitInstance->mc->repGetReadonlyStaticFieldValue(field, pValue);
+    return jitInstance->mc->repGetReadonlyStaticFieldValue(field, buffer, bufferSize);
 }
 
 // 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 ce0d5d05f16ad2..b158de4f5e3b07 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -11814,7 +11814,7 @@ void* CEEJitInfo::getFieldAddress(CORINFO_FIELD_HANDLE fieldHnd,
     return result;
 }
 
-bool CEEJitInfo::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE fieldHnd, uint64_t* pValue)
+bool CEEInfo::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE fieldHnd, uint8_t* buffer, int bufferSize)
 {
     CONTRACTL {
         THROWS;
@@ -11823,7 +11823,8 @@ bool CEEJitInfo::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE fieldHnd, uint
     } CONTRACTL_END;
 
     _ASSERT(fieldHnd != NULL);
-    _ASSERT(pValue != NULL);
+    _ASSERT(buffer != NULL);
+    _ASSERT(bufferSize == sizeof(uint64_t));
 
     bool result = false;
 
@@ -11851,13 +11852,14 @@ bool CEEJitInfo::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE fieldHnd, uint
                         Object* obj = OBJECTREFToObject(fieldObj);
                         if (GCHeapUtilities::GetGCHeap()->IsInFrozenSegment(obj))
                         {
-                            *pValue = (uint64_t)obj;
+                            intptr_t ptr = (intptr_t)obj;
+                            memcpy(buffer, &ptr, sizeof(intptr_t));
                             result = true;
                         }
                     }
                     else
                     {
-                        *pValue = 0;
+                        memset(buffer, 0, sizeof(intptr_t));
                         result = true;
                     }
                 }
@@ -11871,46 +11873,28 @@ bool CEEJitInfo::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE fieldHnd, uint
                         switch (field->GetFieldType())
                         {
                             case ELEMENT_TYPE_BOOLEAN:
-                                *pValue = (uint64_t)*((uint8_t*)fldAddr);
-                                break;
-                            case ELEMENT_TYPE_CHAR:
-                                *pValue = (uint64_t)*((uint16_t*)fldAddr);
-                                break;
                             case ELEMENT_TYPE_I1:
-                                *pValue = (uint64_t)*((int8_t*)fldAddr);
-                                break;
                             case ELEMENT_TYPE_U1:
-                                *pValue = (uint64_t)*((uint8_t*)fldAddr);
+                                memcpy(buffer, fldAddr, sizeof(uint8_t));
                                 break;
+                            case ELEMENT_TYPE_CHAR:
                             case ELEMENT_TYPE_I2:
-                                *pValue = (uint64_t)*((int16_t*)fldAddr);
-                                break;
                             case ELEMENT_TYPE_U2:
-                                *pValue = (uint64_t)*((uint16_t*)fldAddr);
+                                memcpy(buffer, fldAddr, sizeof(uint16_t));
                                 break;
                             case ELEMENT_TYPE_I4:
-                                *pValue = (uint64_t)*((int32_t*)fldAddr);
-                                break;
                             case ELEMENT_TYPE_U4:
-                                *pValue = (uint64_t)*((uint32_t*)fldAddr);
+                            case ELEMENT_TYPE_R4:
+                                memcpy(buffer, fldAddr, sizeof(uint32_t));
                                 break;
                             case ELEMENT_TYPE_I8:
-                                *pValue = (uint64_t)*((int32_t*)fldAddr);
-                                break;
                             case ELEMENT_TYPE_U8:
-                                *pValue = (uint64_t)*((uint64_t*)fldAddr);
-                                break;
-                            case ELEMENT_TYPE_R4:
-                                *pValue = (uint64_t)*((float*)fldAddr);
-                                break;
                             case ELEMENT_TYPE_R8:
-                                *pValue = (uint64_t)*((double*)fldAddr);
+                                memcpy(buffer, fldAddr, sizeof(uint64_t));
                                 break;
                             case ELEMENT_TYPE_I:
-                                *pValue = (uint64_t)*((intptr_t*)fldAddr);
-                                break;
                             case ELEMENT_TYPE_U:
-                                *pValue = (uint64_t)*((uintptr_t*)fldAddr);
+                                memcpy(buffer, fldAddr, sizeof(intptr_t));
                                 break;
                             default:
                                 result = false;
@@ -14467,12 +14451,6 @@ void* CEEInfo::getFieldAddress(CORINFO_FIELD_HANDLE fieldHnd,
     return result;
 }
 
-bool CEEInfo::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE fieldHnd, uint64_t* pValue)
-{
-    LIMITED_METHOD_CONTRACT;
-    UNREACHABLE();      // only called on derived class.
-}
-
 CORINFO_CLASS_HANDLE CEEInfo::getStaticFieldCurrentClass(CORINFO_FIELD_HANDLE fieldHnd,
                                                          bool* pIsSpeculative)
 {
diff --git a/src/coreclr/vm/jitinterface.h b/src/coreclr/vm/jitinterface.h
index 3ffc6d774c5866..9b517406ce4f14 100644
--- a/src/coreclr/vm/jitinterface.h
+++ b/src/coreclr/vm/jitinterface.h
@@ -925,7 +925,6 @@ class CEEJitInfo : public CEEInfo
     InfoAccessType constructStringLiteral(CORINFO_MODULE_HANDLE scopeHnd, mdToken metaTok, void **ppValue) override final;
     InfoAccessType emptyStringLiteral(void ** ppValue) override final;
     void* getFieldAddress(CORINFO_FIELD_HANDLE field, void **ppIndirection) override final;
-    bool getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint64_t *pValue) override final;
     CORINFO_CLASS_HANDLE getStaticFieldCurrentClass(CORINFO_FIELD_HANDLE field, bool* pIsSpeculative) override final;
     void* getMethodSync(CORINFO_METHOD_HANDLE ftnHnd, void **ppIndirection) override final;
 

From fd7e74211a6004b52170254070e785d57236d69b Mon Sep 17 00:00:00 2001
From: EgorBo <egorbo@gmail.com>
Date: Sat, 24 Sep 2022 12:37:51 +0200
Subject: [PATCH 06/61] Address feedback

---
 src/coreclr/jit/importer.cpp                  |  2 +-
 .../tools/superpmi/superpmi-shared/agnostic.h |  1 -
 .../superpmi-shared/methodcontext.cpp         | 76 +------------------
 3 files changed, 3 insertions(+), 76 deletions(-)

diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp
index baeed615943f57..cc1ea8435f36e5 100644
--- a/src/coreclr/jit/importer.cpp
+++ b/src/coreclr/jit/importer.cpp
@@ -8157,7 +8157,7 @@ GenTree* Compiler::impImportStaticReadOnlyField(uint8_t* buffer, int bufferSize,
 
         case TYP_DOUBLE:
         {
-            float f64;
+            double f64;
             memcpy(&f64, buffer, sizeof(double));
             tree = gtNewDconNode(f64);
             break;
diff --git a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h
index c9b67a1da85253..d2e9e8a3f40497 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/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp
index 294fab25b45b05..29cfc0e9693bef 100644
--- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp
+++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp
@@ -3581,70 +3581,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)
 {
@@ -3654,26 +3597,11 @@ 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;
-
-    if (value.fieldValue != (DWORD)-1)
-    {
-        temp = (void*)GetFieldAddress->GetBuffer(value.fieldValue);
-        cr->recAddressMap((void*)value.fieldAddress, temp, toCorInfoSize(repGetFieldType(field, nullptr, nullptr)));
-    }
-    else
-    {
-        temp = (void*)value.fieldAddress;
-    }
-
-    return temp;
+    return (void*)value.fieldAddress;
 }
 
 void MethodContext::recGetReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, bool result)

From 75c40ae7d91a35cbb891ccc836c09f0e654e3c2c Mon Sep 17 00:00:00 2001
From: EgorBo <egorbo@gmail.com>
Date: Sat, 24 Sep 2022 13:09:14 +0200
Subject: [PATCH 07/61] make jit-format happy

---
 src/coreclr/jit/importer.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp
index cc1ea8435f36e5..1c2620f072ca4b 100644
--- a/src/coreclr/jit/importer.cpp
+++ b/src/coreclr/jit/importer.cpp
@@ -8167,7 +8167,7 @@ GenTree* Compiler::impImportStaticReadOnlyField(uint8_t* buffer, int bufferSize,
         {
             ssize_t ptr;
             memcpy(&ptr, buffer, sizeof(ssize_t));
-            
+
             if (ptr == 0)
             {
                 tree = gtNewNull();
@@ -15269,8 +15269,8 @@ void Compiler::impImportBlockCode(BasicBlock* block)
                         if ((aflags & CORINFO_ACCESS_GET) && (fieldInfo.fieldFlags & CORINFO_FLG_FIELD_FINAL) &&
                             !(fieldInfo.fieldFlags & CORINFO_FLG_FIELD_STATIC_IN_HEAP))
                         {
-                            const int bufferSize = sizeof(uint64_t);
-                            uint8_t buffer[bufferSize] = {0};
+                            const int bufferSize         = sizeof(uint64_t);
+                            uint8_t   buffer[bufferSize] = {0};
                             if (info.compCompHnd->getReadonlyStaticFieldValue(resolvedToken.hField, buffer, bufferSize))
                             {
                                 GenTree* cnsValue = impImportStaticReadOnlyField(buffer, bufferSize, lclTyp);

From 283b833f2ba72fcfc00321a980e8e4cfffd4c94d Mon Sep 17 00:00:00 2001
From: EgorBo <egorbo@gmail.com>
Date: Sat, 24 Sep 2022 17:56:20 +0200
Subject: [PATCH 08/61] Fix FitsI32 assert

---
 src/coreclr/jit/gentree.cpp  |  2 +-
 src/coreclr/jit/importer.cpp | 48 +++++++++++++++++++++++-------------
 2 files changed, 32 insertions(+), 18 deletions(-)

diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp
index baa099d055c017..e278a3e288a3ae 100644
--- a/src/coreclr/jit/gentree.cpp
+++ b/src/coreclr/jit/gentree.cpp
@@ -17581,7 +17581,7 @@ CORINFO_CLASS_HANDLE Compiler::gtGetClassHandle(GenTree* tree, bool* pIsExact, b
                 objClass = info.compCompHnd->getObjectType((void*)tree->AsIntCon()->IconValue());
                 if (objClass != NO_CLASS_HANDLE)
                 {
-                    // if we manage to get the class handle it's definitely not null
+                    // if we managed to get a class handle it's definitely not null
                     *pIsNonNull = true;
                 }
             }
diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp
index 1c2620f072ca4b..9a78431cc58daf 100644
--- a/src/coreclr/jit/importer.cpp
+++ b/src/coreclr/jit/importer.cpp
@@ -8118,51 +8118,65 @@ GenTree* Compiler::impInitClass(CORINFO_RESOLVED_TOKEN* pResolvedToken)
 
 GenTree* Compiler::impImportStaticReadOnlyField(uint8_t* buffer, int bufferSize, var_types valueType)
 {
-    // We plan to support bigger values for structs, but for now it's always 64bit
+    // We plan to support larger values (for structs), for now let's keep it 64 bit
     assert(bufferSize == sizeof(INT64));
 
     GenTree* tree = nullptr;
     switch (valueType)
     {
+// 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:
+        {
+            CreateTreeFromBuffer(bool, gtNewIconNode);
+            break;
+        }
         case TYP_BYTE:
+        {
+            CreateTreeFromBuffer(int8_t, gtNewIconNode);
+            break;
+        }
         case TYP_UBYTE:
+        {
+            CreateTreeFromBuffer(uint8_t, gtNewIconNode);
+            break;
+        }
         case TYP_SHORT:
+        {
+            CreateTreeFromBuffer(int16_t, gtNewIconNode);
+            break;
+        }
         case TYP_USHORT:
+        {
+            CreateTreeFromBuffer(uint16_t, gtNewIconNode);
+            break;
+        }
         case TYP_UINT:
         case TYP_INT:
         {
-            ssize_t i32;
-            memcpy(&i32, buffer, sizeof(ssize_t));
-            tree = gtNewIconNode(i32);
+            CreateTreeFromBuffer(int32_t, gtNewIconNode);
             break;
         }
-
         case TYP_LONG:
         case TYP_ULONG:
         {
-            INT64 i64;
-            memcpy(&i64, buffer, sizeof(INT64));
-            tree = gtNewLconNode(i64);
+            CreateTreeFromBuffer(int64_t, gtNewIconNode);
             break;
         }
-
         case TYP_FLOAT:
         {
-            float f32;
-            memcpy(&f32, buffer, sizeof(float));
-            tree = gtNewDconNode(f32);
+            CreateTreeFromBuffer(float, gtNewDconNode);
             break;
         }
-
         case TYP_DOUBLE:
         {
-            double f64;
-            memcpy(&f64, buffer, sizeof(double));
-            tree = gtNewDconNode(f64);
+            CreateTreeFromBuffer(double, gtNewDconNode);
             break;
         }
-
         case TYP_REF:
         {
             ssize_t ptr;

From 00e3e691bd7994411a400af2b9a4cb09e1ca5641 Mon Sep 17 00:00:00 2001
From: EgorBo <egorbo@gmail.com>
Date: Sat, 24 Sep 2022 18:17:59 +0200
Subject: [PATCH 09/61] clean up in methodcontext

---
 .../superpmi/superpmi-shared/methodcontext.cpp  | 17 -----------------
 .../superpmi/superpmi-shared/methodcontext.h    | 11 -----------
 2 files changed, 28 deletions(-)

diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp
index 29cfc0e9693bef..b46094963bb95e 100644
--- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp
+++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp
@@ -30,7 +30,6 @@ MethodContext::MethodContext()
 
     cr    = new CompileResult();
     index = -1;
-    isReadyToRunCompilation = ReadyToRunCompilation::Uninitialized;
 }
 
 MethodContext::~MethodContext()
@@ -1236,7 +1235,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)
 {
@@ -1261,7 +1259,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;
 }
 
@@ -7430,20 +7427,6 @@ bool MethodContext::IsStringContentEqual(LightWeightMap<DWORD, DWORD>* 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 219b5573cd0e14..79f7b14365f87d 100644
--- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h
+++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h
@@ -900,17 +900,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 <typename key, typename value>
     static bool AreLWMHeadersEqual(LightWeightMap<key, value>* prev, LightWeightMap<key, value>* curr);
     static bool IsIntConfigContentEqual(LightWeightMap<Agnostic_ConfigIntInfo, DWORD>* prev,

From f7902d2e1a0e6e5e24ed634046f88485821b1fe9 Mon Sep 17 00:00:00 2001
From: Egor Bogatov <egorbo@gmail.com>
Date: Sat, 24 Sep 2022 18:33:58 +0200
Subject: [PATCH 10/61] Update importer.cpp

---
 src/coreclr/jit/importer.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp
index 9a78431cc58daf..ade399a4ef26d8 100644
--- a/src/coreclr/jit/importer.cpp
+++ b/src/coreclr/jit/importer.cpp
@@ -8164,7 +8164,7 @@ GenTree* Compiler::impImportStaticReadOnlyField(uint8_t* buffer, int bufferSize,
         case TYP_LONG:
         case TYP_ULONG:
         {
-            CreateTreeFromBuffer(int64_t, gtNewIconNode);
+            CreateTreeFromBuffer(int64_t, gtNewLconNode);
             break;
         }
         case TYP_FLOAT:

From bf7947f95f27e04d742066bdb176177fc9b105c6 Mon Sep 17 00:00:00 2001
From: EgorBo <egorbo@gmail.com>
Date: Sat, 24 Sep 2022 18:49:26 +0200
Subject: [PATCH 11/61] Implement getObjectType for ILC

---
 .../tools/Common/JitInterface/CorInfoImpl.cs        |  8 +-------
 .../JitInterface/CorInfoImpl.ReadyToRun.cs          |  5 +++++
 .../JitInterface/CorInfoImpl.RyuJit.cs              | 13 +++++++++++++
 3 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
index 6ef615b5ca1ab0..d33d3256908c6c 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
@@ -2347,16 +2347,10 @@ private CorInfoHelpFunc getUnBoxHelper(CORINFO_CLASS_STRUCT_* cls)
         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 (void*)IntPtr.Zero;
         }
 
-#pragma warning disable CA1822 // Mark members as static
-        private CORINFO_CLASS_STRUCT_* getObjectType(void* typeObj)
-#pragma warning restore CA1822 // Mark members as static
-        {
-            return (CORINFO_CLASS_STRUCT_*)IntPtr.Zero;
-        }
-
         private byte* getHelperName(CorInfoHelpFunc helpFunc)
         {
             return (byte*)GetPin(StringToUTF8(helpFunc.ToString()));
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 7b89e36006e8f9..f52e1d592e806e 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,10 @@ private int getExactClasses(CORINFO_CLASS_STRUCT_* baseType, int maxExactClasses
             // Not implemented for R2R yet
             return 0;
         }
+
+        private CORINFO_CLASS_STRUCT_* getObjectType(void* objPtr)
+        {
+            return (CORINFO_CLASS_STRUCT_*)IntPtr.Zero;
+        }
     }
 }
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 efc9c60ac8cc09..35451576cc6358 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,18 @@ private int getExactClasses(CORINFO_CLASS_STRUCT_* baseType, int maxExactClasses
             Debug.Assert(index <= maxExactClasses);
             return index;
         }
+
+#pragma warning disable CA1822 // Mark members as static
+        private CORINFO_CLASS_STRUCT_* getObjectType(void* objPtr)
+#pragma warning restore CA1822 // Mark members as static
+        {
+            // only strings are passed here for now
+            object obj = HandleToObject((IntPtr)objPtr);
+            if (obj is string)
+            {
+                return ObjectToHandle(_compilation.TypeSystemContext.GetWellKnownType(WellKnownType.String));
+            }
+            return (CORINFO_CLASS_STRUCT_*)IntPtr.Zero;
+        }
     }
 }

From 5374beafac4ad53bba9472bdcd9883bbbd11f1a7 Mon Sep 17 00:00:00 2001
From: Egor Bogatov <egorbo@gmail.com>
Date: Sat, 24 Sep 2022 19:09:50 +0200
Subject: [PATCH 12/61] fix clang/gcc

---
 src/coreclr/jit/importer.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp
index ade399a4ef26d8..4460576476419c 100644
--- a/src/coreclr/jit/importer.cpp
+++ b/src/coreclr/jit/importer.cpp
@@ -8126,9 +8126,9 @@ GenTree* Compiler::impImportStaticReadOnlyField(uint8_t* buffer, int bufferSize,
     {
 // 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##);
+    type v##type;                                                                                                      \
+    memcpy(&v##type, buffer, sizeof(type));                                                                            \
+    tree = treeFactory(v##type);
 
         case TYP_BOOL:
         {

From 548dc9c931ca5a4d71c6f5fa335463892f73e12f Mon Sep 17 00:00:00 2001
From: Egor Bogatov <egorbo@gmail.com>
Date: Sat, 24 Sep 2022 21:08:38 +0200
Subject: [PATCH 13/61] Update src/coreclr/vm/jitinterface.cpp

Co-authored-by: Jan Kotas <jkotas@microsoft.com>
---
 src/coreclr/vm/jitinterface.cpp | 2 --
 1 file changed, 2 deletions(-)

diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp
index b158de4f5e3b07..013cb77c16cda0 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -6028,8 +6028,6 @@ CORINFO_CLASS_HANDLE CEEInfo::getObjectType(void* typeObj)
 
     JIT_TO_EE_TRANSITION();
 
-    if (typeObj != nullptr)
-    {
         GCX_COOP();
         Object* obj = (Object*)typeObj;
         VALIDATEOBJECT(obj);

From 1234e97bc17412aee96d228c2fad1348192253bc Mon Sep 17 00:00:00 2001
From: EgorBo <egorbo@gmail.com>
Date: Sat, 24 Sep 2022 21:23:29 +0200
Subject: [PATCH 14/61] Address feedback

---
 .../JitInterface/CorInfoImpl.RyuJit.cs              |  9 ++++-----
 src/coreclr/vm/jitinterface.cpp                     | 13 +++++++------
 2 files changed, 11 insertions(+), 11 deletions(-)

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 35451576cc6358..7b058040790035 100644
--- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
+++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
@@ -2204,17 +2204,16 @@ private int getExactClasses(CORINFO_CLASS_STRUCT_* baseType, int maxExactClasses
             return index;
         }
 
-#pragma warning disable CA1822 // Mark members as static
         private CORINFO_CLASS_STRUCT_* getObjectType(void* objPtr)
-#pragma warning restore CA1822 // Mark members as static
         {
-            // only strings are passed here for now
             object obj = HandleToObject((IntPtr)objPtr);
-            if (obj is string)
+            if (obj is FrozenStringNode)
             {
                 return ObjectToHandle(_compilation.TypeSystemContext.GetWellKnownType(WellKnownType.String));
             }
-            return (CORINFO_CLASS_STRUCT_*)IntPtr.Zero;
+
+            // For now only frozen strings can come here
+            throw new NotImplementedException($"Unexpected object in getObjectType: {obj}");
         }
     }
 }
diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp
index 013cb77c16cda0..91abd581c08f28 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -6016,7 +6016,7 @@ void* CEEInfo::getRuntimeTypePointer(CORINFO_CLASS_HANDLE clsHnd)
 }
 
 /***********************************************************************/
-CORINFO_CLASS_HANDLE CEEInfo::getObjectType(void* typeObj)
+CORINFO_CLASS_HANDLE CEEInfo::getObjectType(void* objPtr)
 {
     CONTRACTL{
         THROWS;
@@ -6024,15 +6024,16 @@ CORINFO_CLASS_HANDLE CEEInfo::getObjectType(void* typeObj)
         MODE_PREEMPTIVE;
     } CONTRACTL_END;
 
+    _ASSERT(objPtr != nullptr);
+
     CORINFO_CLASS_HANDLE handle = NULL;
 
     JIT_TO_EE_TRANSITION();
 
-        GCX_COOP();
-        Object* obj = (Object*)typeObj;
-        VALIDATEOBJECT(obj);
-        handle = (CORINFO_CLASS_HANDLE)obj->GetMethodTable();
-    }
+    GCX_COOP();
+    Object* obj = (Object*)objPtr;
+    VALIDATEOBJECT(obj);
+    handle = (CORINFO_CLASS_HANDLE)obj->GetMethodTable();
 
     EE_TO_JIT_TRANSITION();
 

From 1c584a19e1b63a17d88db22e5f714931de719e04 Mon Sep 17 00:00:00 2001
From: EgorBo <egorbo@gmail.com>
Date: Sun, 25 Sep 2022 22:29:47 +0200
Subject: [PATCH 15/61] Initial impl for NativeAOT

---
 src/coreclr/jit/importer.cpp                  |  2 +-
 .../tools/Common/JitInterface/CorInfoImpl.cs  | 19 ++++++++++++++++++-
 2 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp
index 4460576476419c..d328b437d6f68d 100644
--- a/src/coreclr/jit/importer.cpp
+++ b/src/coreclr/jit/importer.cpp
@@ -15278,6 +15278,7 @@ 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) &&
@@ -15298,7 +15299,6 @@ void Compiler::impImportBlockCode(BasicBlock* block)
                         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/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
index d33d3256908c6c..0dca88957392a3 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
@@ -3308,9 +3308,26 @@ private uint getClassDomainID(CORINFO_CLASS_STRUCT_* cls, ref void* ppIndirectio
         }
 
 #pragma warning disable CA1822 // Mark members as static
-        private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* field, byte* buffer, int bufferSize)
+        private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byte* buffer, int bufferSize)
 #pragma warning restore CA1822 // Mark members as static
         {
+            /*
+            FieldDesc field = HandleToObject(fieldHandle);
+            if (field.IsStatic && !field.IsThreadStatic && field.IsInitOnly && !field.IsIntrinsic && !field.HasGCStaticBase &&
+                !_compilation.HasLazyStaticConstructor(field.OwningType))
+            {
+                switch (field.FieldType.Category)
+                {
+                    case TypeFlags.Int32:
+                        {
+                            var baseAddress = _compilation.NodeFactory.TypeGCStaticsSymbol((MetadataType)field.OwningType);
+                            *((int*)buffer) = 42;
+                            return true;
+                        }
+                        break;
+                }
+            }
+            */
             return false;
         }
 

From 1fc50c72a577f51dcfbd372bc8f22f5574faff5c Mon Sep 17 00:00:00 2001
From: EgorBo <egorbo@gmail.com>
Date: Sun, 25 Sep 2022 23:56:47 +0200
Subject: [PATCH 16/61] Use PreinitializationInfo

---
 .../tools/Common/JitInterface/CorInfoImpl.cs  | 28 +++++++++++++++----
 .../Compiler/TypePreinit.cs                   | 18 ++++++++++++
 2 files changed, 40 insertions(+), 6 deletions(-)

diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
index 0dca88957392a3..7adb17dd6c8904 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
@@ -3311,23 +3311,39 @@ private uint getClassDomainID(CORINFO_CLASS_STRUCT_* cls, ref void* ppIndirectio
         private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byte* buffer, int bufferSize)
 #pragma warning restore CA1822 // Mark members as static
         {
-            /*
             FieldDesc field = HandleToObject(fieldHandle);
             if (field.IsStatic && !field.IsThreadStatic && field.IsInitOnly && !field.IsIntrinsic && !field.HasGCStaticBase &&
-                !_compilation.HasLazyStaticConstructor(field.OwningType))
+                !_compilation.HasLazyStaticConstructor(field.OwningType) && field.OwningType is MetadataType owningType)
             {
                 switch (field.FieldType.Category)
                 {
+                    case TypeFlags.Boolean:
+                    case TypeFlags.Byte:
+                    case TypeFlags.SByte:
+                    case TypeFlags.Int16:
+                    case TypeFlags.UInt16:
+                    case TypeFlags.Char:
                     case TypeFlags.Int32:
+                    case TypeFlags.UInt32:
+                    case TypeFlags.Int64:
+                    case TypeFlags.UInt64:
+                    case TypeFlags.Single:
+                    case TypeFlags.Double:
                         {
-                            var baseAddress = _compilation.NodeFactory.TypeGCStaticsSymbol((MetadataType)field.OwningType);
-                            *((int*)buffer) = 42;
-                            return true;
+                            PreinitializationManager preinitManager = _compilation.NodeFactory.PreinitializationManager;
+                            if (preinitManager.IsPreinitialized(owningType))
+                            {
+                                TypePreinit.ISerializableValue value = preinitManager
+                                    .GetPreinitializationInfo(owningType).GetFieldValue(field);
+                                if (value.WriteFieldData(new Span<byte>(buffer, bufferSize)))
+                                {
+                                    return true;
+                                }
+                            }
                         }
                         break;
                 }
             }
-            */
             return false;
         }
 
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs
index 5d292226fbd720..600746ff3c6e04 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 WriteFieldData(Span<byte> dest);
         }
 
         /// <summary>
@@ -1767,6 +1769,11 @@ public virtual bool TryCreateByRef(out Value value)
 
             public abstract void WriteFieldData(ref ObjectDataBuilder builder, NodeFactory factory);
 
+            public virtual bool WriteFieldData(Span<byte> dest)
+            {
+                return false;
+            }
+
             private static T ThrowInvalidProgram<T>()
             {
                 ThrowHelper.ThrowInvalidProgramException();
@@ -1855,6 +1862,17 @@ public override void WriteFieldData(ref ObjectDataBuilder builder, NodeFactory f
                 builder.EmitBytes(InstanceBytes);
             }
 
+            public override bool WriteFieldData(Span<byte> dest)
+            {
+                byte[] data = InstanceBytes;
+                if (dest.Length < data.Length)
+                {
+                    return false;
+                }
+                data.AsSpan().CopyTo(dest);
+                return true;
+            }
+
             private byte[] AsExactByteCount(int size)
             {
                 if (InstanceBytes.Length != size)

From 600209fb2a90b971066a26cc80763b7c935010f9 Mon Sep 17 00:00:00 2001
From: EgorBo <egorbo@gmail.com>
Date: Mon, 26 Sep 2022 00:36:20 +0200
Subject: [PATCH 17/61] Handle strings

---
 .../tools/Common/JitInterface/CorInfoImpl.cs  | 31 +++++++++++++++++--
 .../Compiler/TypePreinit.cs                   | 20 ++++++------
 2 files changed, 39 insertions(+), 12 deletions(-)

diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
index 7adb17dd6c8904..a8240f5df0251a 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
@@ -3312,7 +3312,7 @@ private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byt
 #pragma warning restore CA1822 // Mark members as static
         {
             FieldDesc field = HandleToObject(fieldHandle);
-            if (field.IsStatic && !field.IsThreadStatic && field.IsInitOnly && !field.IsIntrinsic && !field.HasGCStaticBase &&
+            if (field.IsStatic && !field.IsThreadStatic && field.IsInitOnly && !field.IsIntrinsic &&
                 !_compilation.HasLazyStaticConstructor(field.OwningType) && field.OwningType is MetadataType owningType)
             {
                 switch (field.FieldType.Category)
@@ -3329,15 +3329,40 @@ private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byt
                     case TypeFlags.UInt64:
                     case TypeFlags.Single:
                     case TypeFlags.Double:
+                    case TypeFlags.Class:
                         {
                             PreinitializationManager preinitManager = _compilation.NodeFactory.PreinitializationManager;
                             if (preinitManager.IsPreinitialized(owningType))
                             {
                                 TypePreinit.ISerializableValue value = preinitManager
                                     .GetPreinitializationInfo(owningType).GetFieldValue(field);
-                                if (value.WriteFieldData(new Span<byte>(buffer, bufferSize)))
+
+                                object data;
+                                if (value.GetRawData(out data))
                                 {
-                                    return true;
+                                    if (data is byte[] bytes && bytes.Length <= bufferSize)
+                                    {
+                                        Debug.Assert(!field.HasGCStaticBase);
+                                        bytes.AsSpan().CopyTo(new Span<byte>(buffer, bufferSize));
+                                        return true;
+                                    }
+
+                                    if (data is null)
+                                    {
+                                        Debug.Assert(field.FieldType.Category == TypeFlags.Class && field.HasGCStaticBase);
+
+                                        *((nint*)buffer) = 0;
+                                        return true;
+                                    }
+
+                                    if (data is string str)
+                                    {
+                                        Debug.Assert(field.FieldType.Category == TypeFlags.Class && field.HasGCStaticBase);
+
+                                        FrozenStringNode stringObject = _compilation.NodeFactory.SerializedStringObject(str);
+                                        *((nint*)buffer) = ObjectToHandle(stringObject);
+                                        return true;
+                                    }
                                 }
                             }
                         }
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs
index 600746ff3c6e04..1758a6cf07973d 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs
@@ -1705,7 +1705,7 @@ public interface ISerializableValue
         {
             void WriteFieldData(ref ObjectDataBuilder builder, NodeFactory factory);
 
-            bool WriteFieldData(Span<byte> dest);
+            bool GetRawData(out object data);
         }
 
         /// <summary>
@@ -1769,8 +1769,9 @@ public virtual bool TryCreateByRef(out Value value)
 
             public abstract void WriteFieldData(ref ObjectDataBuilder builder, NodeFactory factory);
 
-            public virtual bool WriteFieldData(Span<byte> dest)
+            public virtual bool GetRawData(out object data)
             {
+                data = null;
                 return false;
             }
 
@@ -1862,14 +1863,9 @@ public override void WriteFieldData(ref ObjectDataBuilder builder, NodeFactory f
                 builder.EmitBytes(InstanceBytes);
             }
 
-            public override bool WriteFieldData(Span<byte> dest)
+            public override bool GetRawData(out object data)
             {
-                byte[] data = InstanceBytes;
-                if (dest.Length < data.Length)
-                {
-                    return false;
-                }
-                data.AsSpan().CopyTo(dest);
+                data = InstanceBytes;
                 return true;
             }
 
@@ -2243,6 +2239,12 @@ public override void WriteFieldData(ref ObjectDataBuilder builder, NodeFactory f
                 builder.EmitPointerReloc(factory.SerializedStringObject(_value));
             }
 
+            public override bool GetRawData(out object data)
+            {
+                data = _value;
+                return true;
+            }
+
             public override ReferenceTypeValue ToForeignInstance(int baseInstructionCounter) => this;
         }
 

From 4cad20ac7901fbbc78949d18012ab93fac90f835 Mon Sep 17 00:00:00 2001
From: Egor Bogatov <egorbo@gmail.com>
Date: Mon, 26 Sep 2022 00:36:45 +0200
Subject: [PATCH 18/61] Update
 src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs

Co-authored-by: Jan Kotas <jkotas@microsoft.com>
---
 src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
index 7adb17dd6c8904..83ec2392635625 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
@@ -3307,7 +3307,6 @@ private uint getClassDomainID(CORINFO_CLASS_STRUCT_* cls, ref void* ppIndirectio
             }
         }
 
-#pragma warning disable CA1822 // Mark members as static
         private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byte* buffer, int bufferSize)
 #pragma warning restore CA1822 // Mark members as static
         {

From 28f2749acd5f4521cb86fb38356e41d261bd21cf Mon Sep 17 00:00:00 2001
From: Egor Bogatov <egorbo@gmail.com>
Date: Mon, 26 Sep 2022 00:37:08 +0200
Subject: [PATCH 19/61] Apply suggestions from code review

Co-authored-by: Jan Kotas <jkotas@microsoft.com>
---
 src/coreclr/jit/importer.cpp                         | 1 -
 src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs | 5 ++---
 2 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp
index d328b437d6f68d..8b508e9d9ee2a4 100644
--- a/src/coreclr/jit/importer.cpp
+++ b/src/coreclr/jit/importer.cpp
@@ -15282,7 +15282,6 @@ void Compiler::impImportBlockCode(BasicBlock* block)
                     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))
                         {
                             const int bufferSize         = sizeof(uint64_t);
                             uint8_t   buffer[bufferSize] = {0};
diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
index 83ec2392635625..7e0872a433796f 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
@@ -3308,11 +3308,10 @@ private uint getClassDomainID(CORINFO_CLASS_STRUCT_* cls, ref void* ppIndirectio
         }
 
         private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byte* buffer, int bufferSize)
-#pragma warning restore CA1822 // Mark members as static
         {
             FieldDesc field = HandleToObject(fieldHandle);
-            if (field.IsStatic && !field.IsThreadStatic && field.IsInitOnly && !field.IsIntrinsic && !field.HasGCStaticBase &&
-                !_compilation.HasLazyStaticConstructor(field.OwningType) && field.OwningType is MetadataType owningType)
+            if (field.IsStatic && !field.IsThreadStatic && field.IsInitOnly) 
+                 field.OwningType is MetadataType owningType)
             {
                 switch (field.FieldType.Category)
                 {

From a07232dc30a68800701ab4e606fe04f41430d7ea Mon Sep 17 00:00:00 2001
From: EgorBo <egorbo@gmail.com>
Date: Mon, 26 Sep 2022 00:48:44 +0200
Subject: [PATCH 20/61] clean up

---
 src/coreclr/jit/importer.cpp                  |  2 +-
 .../tools/Common/JitInterface/CorInfoImpl.cs  | 21 +++++++++----------
 2 files changed, 11 insertions(+), 12 deletions(-)

diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp
index 8b508e9d9ee2a4..df4c032b8f6fac 100644
--- a/src/coreclr/jit/importer.cpp
+++ b/src/coreclr/jit/importer.cpp
@@ -15281,7 +15281,7 @@ void Compiler::impImportBlockCode(BasicBlock* block)
                     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) &&
+                        if ((aflags & CORINFO_ACCESS_GET) && (fieldInfo.fieldFlags & CORINFO_FLG_FIELD_FINAL))
                         {
                             const int bufferSize         = sizeof(uint64_t);
                             uint8_t   buffer[bufferSize] = {0};
diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
index 0e626ffc79d9fd..13a75860ed5b89 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
@@ -3308,11 +3308,9 @@ private uint getClassDomainID(CORINFO_CLASS_STRUCT_* cls, ref void* ppIndirectio
         }
 
         private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byte* buffer, int bufferSize)
-#pragma warning restore CA1822 // Mark members as static
         {
             FieldDesc field = HandleToObject(fieldHandle);
-            if (field.IsStatic && !field.IsThreadStatic && field.IsInitOnly && !field.IsIntrinsic &&
-                !_compilation.HasLazyStaticConstructor(field.OwningType) && field.OwningType is MetadataType owningType)
+            if (field.IsStatic && !field.IsThreadStatic && field.IsInitOnly && field.OwningType is MetadataType owningType)
             {
                 switch (field.FieldType.Category)
                 {
@@ -3336,21 +3334,22 @@ private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byt
                                 TypePreinit.ISerializableValue value = preinitManager
                                     .GetPreinitializationInfo(owningType).GetFieldValue(field);
 
+                                if (value == null)
+                                {
+                                    Debug.Assert(field.FieldType.Category == TypeFlags.Class && field.HasGCStaticBase);
+
+                                    *((nint*)buffer) = 0;
+                                    return true;
+                                }
+
                                 object data;
                                 if (value.GetRawData(out data))
                                 {
                                     if (data is byte[] bytes && bytes.Length <= bufferSize)
                                     {
                                         Debug.Assert(!field.HasGCStaticBase);
-                                        bytes.AsSpan().CopyTo(new Span<byte>(buffer, bufferSize));
-                                        return true;
-                                    }
-
-                                    if (data is null)
-                                    {
-                                        Debug.Assert(field.FieldType.Category == TypeFlags.Class && field.HasGCStaticBase);
 
-                                        *((nint*)buffer) = 0;
+                                        bytes.AsSpan().CopyTo(new Span<byte>(buffer, bufferSize));
                                         return true;
                                     }
 

From 0c6fe27d6df1b45623aa1ee8fa8fd07ed868db56 Mon Sep 17 00:00:00 2001
From: EgorBo <egorbo@gmail.com>
Date: Mon, 26 Sep 2022 01:05:56 +0200
Subject: [PATCH 21/61] Add a comment

---
 src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
index 13a75860ed5b89..d91bd23cd7b975 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
@@ -3312,6 +3312,13 @@ private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byt
             FieldDesc field = HandleToObject(fieldHandle);
             if (field.IsStatic && !field.IsThreadStatic && field.IsInitOnly && field.OwningType is MetadataType owningType)
             {
+                // Currently, jit is able to handle only these types of objects:
+                // * primitives
+                // * frozen strings
+                // * null
+                //
+                // To add support for mutable objects see https://github.com/dotnet/runtime/pull/76135#issuecomment-1257263126
+
                 switch (field.FieldType.Category)
                 {
                     case TypeFlags.Boolean:

From 271f44287ba68584a970437ce2b0f839ad554b02 Mon Sep 17 00:00:00 2001
From: EgorBo <egorbo@gmail.com>
Date: Mon, 26 Sep 2022 01:11:50 +0200
Subject: [PATCH 22/61] Fix build

---
 .../JitInterface/CorInfoImpl.ReadyToRun.cs    |  5 ++
 .../JitInterface/CorInfoImpl.RyuJit.cs        | 70 +++++++++++++++++++
 2 files changed, 75 insertions(+)

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 f52e1d592e806e..80e8359d2ffaec 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs
@@ -2993,6 +2993,11 @@ private int getExactClasses(CORINFO_CLASS_STRUCT_* baseType, int maxExactClasses
             return 0;
         }
 
+        private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byte* buffer, int bufferSize)
+        {
+            return false;
+        }
+
         private CORINFO_CLASS_STRUCT_* getObjectType(void* objPtr)
         {
             return (CORINFO_CLASS_STRUCT_*)IntPtr.Zero;
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 7b058040790035..42df80b8daec6e 100644
--- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
+++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
@@ -2204,6 +2204,76 @@ private int getExactClasses(CORINFO_CLASS_STRUCT_* baseType, int maxExactClasses
             return index;
         }
 
+        private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byte* buffer, int bufferSize)
+        {
+            FieldDesc field = HandleToObject(fieldHandle);
+            if (field.IsStatic && !field.IsThreadStatic && field.IsInitOnly && field.OwningType is MetadataType owningType)
+            {
+                // Currently, jit is able to handle only these types of objects:
+                // * primitives
+                // * frozen strings
+                // * null
+                //
+                // To add support for mutable objects see https://github.com/dotnet/runtime/pull/76135#issuecomment-1257263126
+
+                switch (field.FieldType.Category)
+                {
+                    case TypeFlags.Boolean:
+                    case TypeFlags.Byte:
+                    case TypeFlags.SByte:
+                    case TypeFlags.Int16:
+                    case TypeFlags.UInt16:
+                    case TypeFlags.Char:
+                    case TypeFlags.Int32:
+                    case TypeFlags.UInt32:
+                    case TypeFlags.Int64:
+                    case TypeFlags.UInt64:
+                    case TypeFlags.Single:
+                    case TypeFlags.Double:
+                    case TypeFlags.Class:
+                        {
+                            PreinitializationManager preinitManager = _compilation.NodeFactory.PreinitializationManager;
+                            if (preinitManager.IsPreinitialized(owningType))
+                            {
+                                TypePreinit.ISerializableValue value = preinitManager
+                                    .GetPreinitializationInfo(owningType).GetFieldValue(field);
+
+                                if (value == null)
+                                {
+                                    Debug.Assert(field.FieldType.Category == TypeFlags.Class && field.HasGCStaticBase);
+
+                                    *((nint*)buffer) = 0;
+                                    return true;
+                                }
+
+                                object data;
+                                if (value.GetRawData(out data))
+                                {
+                                    if (data is byte[] bytes && bytes.Length <= bufferSize)
+                                    {
+                                        Debug.Assert(!field.HasGCStaticBase);
+
+                                        bytes.AsSpan().CopyTo(new Span<byte>(buffer, bufferSize));
+                                        return true;
+                                    }
+
+                                    if (data is string str)
+                                    {
+                                        Debug.Assert(field.FieldType.Category == TypeFlags.Class && field.HasGCStaticBase);
+
+                                        FrozenStringNode stringObject = _compilation.NodeFactory.SerializedStringObject(str);
+                                        *((nint*)buffer) = ObjectToHandle(stringObject);
+                                        return true;
+                                    }
+                                }
+                            }
+                        }
+                        break;
+                }
+            }
+            return false;
+        }
+
         private CORINFO_CLASS_STRUCT_* getObjectType(void* objPtr)
         {
             object obj = HandleToObject((IntPtr)objPtr);

From 76f6cdc812b5fef66fa633a9e45bff70957f9941 Mon Sep 17 00:00:00 2001
From: EgorBo <egorbo@gmail.com>
Date: Mon, 26 Sep 2022 01:13:58 +0200
Subject: [PATCH 23/61] Fix build

---
 .../tools/Common/JitInterface/CorInfoImpl.cs  | 70 -------------------
 1 file changed, 70 deletions(-)

diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
index d91bd23cd7b975..06a29f75d91d00 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
@@ -3307,76 +3307,6 @@ private uint getClassDomainID(CORINFO_CLASS_STRUCT_* cls, ref void* ppIndirectio
             }
         }
 
-        private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byte* buffer, int bufferSize)
-        {
-            FieldDesc field = HandleToObject(fieldHandle);
-            if (field.IsStatic && !field.IsThreadStatic && field.IsInitOnly && field.OwningType is MetadataType owningType)
-            {
-                // Currently, jit is able to handle only these types of objects:
-                // * primitives
-                // * frozen strings
-                // * null
-                //
-                // To add support for mutable objects see https://github.com/dotnet/runtime/pull/76135#issuecomment-1257263126
-
-                switch (field.FieldType.Category)
-                {
-                    case TypeFlags.Boolean:
-                    case TypeFlags.Byte:
-                    case TypeFlags.SByte:
-                    case TypeFlags.Int16:
-                    case TypeFlags.UInt16:
-                    case TypeFlags.Char:
-                    case TypeFlags.Int32:
-                    case TypeFlags.UInt32:
-                    case TypeFlags.Int64:
-                    case TypeFlags.UInt64:
-                    case TypeFlags.Single:
-                    case TypeFlags.Double:
-                    case TypeFlags.Class:
-                        {
-                            PreinitializationManager preinitManager = _compilation.NodeFactory.PreinitializationManager;
-                            if (preinitManager.IsPreinitialized(owningType))
-                            {
-                                TypePreinit.ISerializableValue value = preinitManager
-                                    .GetPreinitializationInfo(owningType).GetFieldValue(field);
-
-                                if (value == null)
-                                {
-                                    Debug.Assert(field.FieldType.Category == TypeFlags.Class && field.HasGCStaticBase);
-
-                                    *((nint*)buffer) = 0;
-                                    return true;
-                                }
-
-                                object data;
-                                if (value.GetRawData(out data))
-                                {
-                                    if (data is byte[] bytes && bytes.Length <= bufferSize)
-                                    {
-                                        Debug.Assert(!field.HasGCStaticBase);
-
-                                        bytes.AsSpan().CopyTo(new Span<byte>(buffer, bufferSize));
-                                        return true;
-                                    }
-
-                                    if (data is string str)
-                                    {
-                                        Debug.Assert(field.FieldType.Category == TypeFlags.Class && field.HasGCStaticBase);
-
-                                        FrozenStringNode stringObject = _compilation.NodeFactory.SerializedStringObject(str);
-                                        *((nint*)buffer) = ObjectToHandle(stringObject);
-                                        return true;
-                                    }
-                                }
-                            }
-                        }
-                        break;
-                }
-            }
-            return false;
-        }
-
         private CORINFO_CLASS_STRUCT_* getStaticFieldCurrentClass(CORINFO_FIELD_STRUCT_* field, byte* pIsSpeculative)
         {
             if (pIsSpeculative != null)

From 133c2681ba3d7db04a9edf3f858ebebb62dcb046 Mon Sep 17 00:00:00 2001
From: EgorBo <egorbo@gmail.com>
Date: Mon, 26 Sep 2022 12:38:18 +0200
Subject: [PATCH 24/61] Address Michal's feedback

---
 .../Compiler/TypePreinit.cs                   | 16 ++--
 .../JitInterface/CorInfoImpl.RyuJit.cs        | 76 +++++--------------
 2 files changed, 32 insertions(+), 60 deletions(-)

diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs
index 1758a6cf07973d..8834f0be65718a 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs
@@ -1705,7 +1705,7 @@ public interface ISerializableValue
         {
             void WriteFieldData(ref ObjectDataBuilder builder, NodeFactory factory);
 
-            bool GetRawData(out object data);
+            bool GetRawData(NodeFactory factory, out object data);
         }
 
         /// <summary>
@@ -1769,7 +1769,7 @@ public virtual bool TryCreateByRef(out Value value)
 
             public abstract void WriteFieldData(ref ObjectDataBuilder builder, NodeFactory factory);
 
-            public virtual bool GetRawData(out object data)
+            public virtual bool GetRawData(NodeFactory factory, out object data)
             {
                 data = null;
                 return false;
@@ -1863,7 +1863,7 @@ public override void WriteFieldData(ref ObjectDataBuilder builder, NodeFactory f
                 builder.EmitBytes(InstanceBytes);
             }
 
-            public override bool GetRawData(out object data)
+            public override bool GetRawData(NodeFactory factory, out object data)
             {
                 data = InstanceBytes;
                 return true;
@@ -2127,6 +2127,12 @@ public ArrayInstance(ArrayType type, int elementCount, AllocationSite allocation
                 _data = new byte[elementCount * _elementSize];
             }
 
+            public override bool GetRawData(NodeFactory factory, out object data)
+            {
+                data = null;
+                return false;
+            }
+
             public bool TryInitialize(byte[] bytes)
             {
                 if (bytes.Length != _data.Length)
@@ -2239,9 +2245,9 @@ public override void WriteFieldData(ref ObjectDataBuilder builder, NodeFactory f
                 builder.EmitPointerReloc(factory.SerializedStringObject(_value));
             }
 
-            public override bool GetRawData(out object data)
+            public override bool GetRawData(NodeFactory factory, out object data)
             {
-                data = _value;
+                data = factory.SerializedStringObject(_value);
                 return true;
             }
 
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 42df80b8daec6e..10db57a7048e66 100644
--- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
+++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
@@ -2209,66 +2209,32 @@ private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byt
             FieldDesc field = HandleToObject(fieldHandle);
             if (field.IsStatic && !field.IsThreadStatic && field.IsInitOnly && field.OwningType is MetadataType owningType)
             {
-                // Currently, jit is able to handle only these types of objects:
-                // * primitives
-                // * frozen strings
-                // * null
-                //
-                // To add support for mutable objects see https://github.com/dotnet/runtime/pull/76135#issuecomment-1257263126
-
-                switch (field.FieldType.Category)
+                PreinitializationManager preinitManager = _compilation.NodeFactory.PreinitializationManager;
+                if (preinitManager.IsPreinitialized(owningType))
                 {
-                    case TypeFlags.Boolean:
-                    case TypeFlags.Byte:
-                    case TypeFlags.SByte:
-                    case TypeFlags.Int16:
-                    case TypeFlags.UInt16:
-                    case TypeFlags.Char:
-                    case TypeFlags.Int32:
-                    case TypeFlags.UInt32:
-                    case TypeFlags.Int64:
-                    case TypeFlags.UInt64:
-                    case TypeFlags.Single:
-                    case TypeFlags.Double:
-                    case TypeFlags.Class:
-                        {
-                            PreinitializationManager preinitManager = _compilation.NodeFactory.PreinitializationManager;
-                            if (preinitManager.IsPreinitialized(owningType))
-                            {
-                                TypePreinit.ISerializableValue value = preinitManager
-                                    .GetPreinitializationInfo(owningType).GetFieldValue(field);
+                    TypePreinit.ISerializableValue value = preinitManager
+                        .GetPreinitializationInfo(owningType).GetFieldValue(field);
 
-                                if (value == null)
-                                {
-                                    Debug.Assert(field.FieldType.Category == TypeFlags.Class && field.HasGCStaticBase);
+                    if (value == null)
+                    {
+                        *((nint*)buffer) = 0;
+                        return true;
+                    }
 
-                                    *((nint*)buffer) = 0;
-                                    return true;
-                                }
+                    object data;
+                    if (value.GetRawData(_compilation.NodeFactory, out data))
+                    {
+                        switch (data)
+                        {
+                            case byte[] bytes when bytes.Length <= bufferSize:
+                                bytes.AsSpan().CopyTo(new Span<byte>(buffer, bufferSize));
+                                return true;
 
-                                object data;
-                                if (value.GetRawData(out data))
-                                {
-                                    if (data is byte[] bytes && bytes.Length <= bufferSize)
-                                    {
-                                        Debug.Assert(!field.HasGCStaticBase);
-
-                                        bytes.AsSpan().CopyTo(new Span<byte>(buffer, bufferSize));
-                                        return true;
-                                    }
-
-                                    if (data is string str)
-                                    {
-                                        Debug.Assert(field.FieldType.Category == TypeFlags.Class && field.HasGCStaticBase);
-
-                                        FrozenStringNode stringObject = _compilation.NodeFactory.SerializedStringObject(str);
-                                        *((nint*)buffer) = ObjectToHandle(stringObject);
-                                        return true;
-                                    }
-                                }
-                            }
+                            case FrozenStringNode str:
+                                *((nint*)buffer) = ObjectToHandle(str);
+                                return true;
                         }
-                        break;
+                    }
                 }
             }
             return false;

From 88809549d6445963801ca3946027c5eec504f28e Mon Sep 17 00:00:00 2001
From: EgorBo <egorbo@gmail.com>
Date: Mon, 26 Sep 2022 12:48:08 +0200
Subject: [PATCH 25/61] Address Michal's feedback

---
 .../ILCompiler.Compiler/Compiler/TypePreinit.cs | 17 +++++++++++------
 .../JitInterface/CorInfoImpl.RyuJit.cs          | 10 ++++++++--
 2 files changed, 19 insertions(+), 8 deletions(-)

diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs
index 8834f0be65718a..d063ffb541c05c 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs
@@ -2036,6 +2036,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
@@ -2127,12 +2138,6 @@ public ArrayInstance(ArrayType type, int elementCount, AllocationSite allocation
                 _data = new byte[elementCount * _elementSize];
             }
 
-            public override bool GetRawData(NodeFactory factory, out object data)
-            {
-                data = null;
-                return false;
-            }
-
             public bool TryInitialize(byte[] bytes)
             {
                 if (bytes.Length != _data.Length)
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 10db57a7048e66..b59aeee9bc127d 100644
--- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
+++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
@@ -2233,6 +2233,10 @@ private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byt
                             case FrozenStringNode str:
                                 *((nint*)buffer) = ObjectToHandle(str);
                                 return true;
+
+                            case FrozenObjectNode node:
+                                *((nint*)buffer) = ObjectToHandle(node);
+                                return true;
                         }
                     }
                 }
@@ -2247,8 +2251,10 @@ private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byt
             {
                 return ObjectToHandle(_compilation.TypeSystemContext.GetWellKnownType(WellKnownType.String));
             }
-
-            // For now only frozen strings can come here
+            else if (obj is FrozenObjectNode)
+            {
+                return null; // TODO: how to implement properly?
+            }
             throw new NotImplementedException($"Unexpected object in getObjectType: {obj}");
         }
     }

From 63cd7cc22dd48c37f32a1a69ae557e7cde0253cf Mon Sep 17 00:00:00 2001
From: EgorBo <egorbo@gmail.com>
Date: Mon, 26 Sep 2022 12:53:23 +0200
Subject: [PATCH 26/61] Simplify PM switch

---
 .../ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs  | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

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 b59aeee9bc127d..63f5c3d6728944 100644
--- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
+++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
@@ -2230,12 +2230,8 @@ private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byt
                                 bytes.AsSpan().CopyTo(new Span<byte>(buffer, bufferSize));
                                 return true;
 
-                            case FrozenStringNode str:
-                                *((nint*)buffer) = ObjectToHandle(str);
-                                return true;
-
-                            case FrozenObjectNode node:
-                                *((nint*)buffer) = ObjectToHandle(node);
+                            case FrozenObjectNode or FrozenStringNode:
+                                *(nint*)buffer = ObjectToHandle(data);
                                 return true;
                         }
                     }

From 26567198faccd2b5148687fa0a995618df04be63 Mon Sep 17 00:00:00 2001
From: EgorBo <egorbo@gmail.com>
Date: Mon, 26 Sep 2022 14:46:00 +0200
Subject: [PATCH 27/61] Implement getObjectType for FrozenObjectNode

---
 .../DependencyAnalysis/FrozenObjectNode.cs    |  2 ++
 .../JitInterface/CorInfoImpl.RyuJit.cs        | 20 +++++++++----------
 2 files changed, 12 insertions(+), 10 deletions(-)

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 7a1cf593a6ab3f..a56c134e57abdf 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,8 @@ public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
 
         public override bool StaticDependenciesAreComputed => true;
 
+        public MetadataType OwningType => _owningType;
+
         int ISymbolNode.Offset => 0;
 
         int ISymbolDefinitionNode.Offset
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 63f5c3d6728944..53b71cdaaa25a4 100644
--- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
+++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
@@ -2221,8 +2221,7 @@ private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byt
                         return true;
                     }
 
-                    object data;
-                    if (value.GetRawData(_compilation.NodeFactory, out data))
+                    if (value.GetRawData(_compilation.NodeFactory, out object data))
                     {
                         switch (data)
                         {
@@ -2243,15 +2242,16 @@ private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byt
         private CORINFO_CLASS_STRUCT_* getObjectType(void* objPtr)
         {
             object obj = HandleToObject((IntPtr)objPtr);
-            if (obj is FrozenStringNode)
+            return obj switch
             {
-                return ObjectToHandle(_compilation.TypeSystemContext.GetWellKnownType(WellKnownType.String));
-            }
-            else if (obj is FrozenObjectNode)
-            {
-                return null; // TODO: how to implement properly?
-            }
-            throw new NotImplementedException($"Unexpected object in getObjectType: {obj}");
+                // For now we only support frozen strings
+                FrozenStringNode => ObjectToHandle(_compilation.TypeSystemContext.GetWellKnownType(WellKnownType.String)),
+
+                // and frozen objects like arrays
+                FrozenObjectNode frozenObj => ObjectToHandle(frozenObj.OwningType),
+
+                _ => throw new NotImplementedException($"Unexpected object in getObjectType: {obj}")
+            };
         }
     }
 }

From 10065722c34279302f428f628775aaf07b39ffbd Mon Sep 17 00:00:00 2001
From: EgorBo <egorbo@gmail.com>
Date: Mon, 26 Sep 2022 14:54:24 +0200
Subject: [PATCH 28/61] Address feedback

---
 .../Compiler/DependencyAnalysis/FrozenObjectNode.cs             | 2 +-
 .../aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs    | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

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 a56c134e57abdf..ee3279e89c9365 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/FrozenObjectNode.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/FrozenObjectNode.cs
@@ -35,7 +35,7 @@ public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
 
         public override bool StaticDependenciesAreComputed => true;
 
-        public MetadataType OwningType => _owningType;
+        public TypeDesc ObjectType => _data.Type;
 
         int ISymbolNode.Offset => 0;
 
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 53b71cdaaa25a4..b9f47420f0b346 100644
--- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
+++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
@@ -2248,7 +2248,7 @@ private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byt
                 FrozenStringNode => ObjectToHandle(_compilation.TypeSystemContext.GetWellKnownType(WellKnownType.String)),
 
                 // and frozen objects like arrays
-                FrozenObjectNode frozenObj => ObjectToHandle(frozenObj.OwningType),
+                FrozenObjectNode frozenObj => ObjectToHandle(frozenObj.ObjectType),
 
                 _ => throw new NotImplementedException($"Unexpected object in getObjectType: {obj}")
             };

From 0d27470d0e9862388936d22af5cec5d699f1d2ae Mon Sep 17 00:00:00 2001
From: EgorBo <egorbo@gmail.com>
Date: Mon, 26 Sep 2022 16:59:52 +0200
Subject: [PATCH 29/61] Add isObjectImmutable

---
 src/coreclr/inc/corinfo.h                     |   6 +-
 src/coreclr/inc/icorjitinfoimpl_generated.h   |   5 +-
 src/coreclr/jit/ICorJitInfo_API_names.h       |   1 +
 src/coreclr/jit/ICorJitInfo_API_wrapper.hpp   |  13 +-
 src/coreclr/jit/gcinfo.cpp                    |   9 +
 .../tools/Common/JitInterface/CorInfoBase.cs  | 244 ++++++++++--------
 .../tools/Common/JitInterface/CorInfoImpl.cs  |   8 -
 .../ThunkGenerator/ThunkInput.txt             |   3 +-
 .../JitInterface/CorInfoImpl.ReadyToRun.cs    |  12 +-
 .../JitInterface/CorInfoImpl.RyuJit.cs        |  17 ++
 .../tools/aot/jitinterface/jitinterface.h     |  16 +-
 .../tools/superpmi/superpmi-shared/lwmlist.h  |   1 +
 .../superpmi-shared/methodcontext.cpp         |  31 ++-
 .../superpmi/superpmi-shared/methodcontext.h  |   9 +-
 .../superpmi-shim-collector/icorjitinfo.cpp   |   8 +
 .../superpmi-shim-counter/icorjitinfo.cpp     |  11 +-
 .../superpmi-shim-simple/icorjitinfo.cpp      |  10 +-
 .../tools/superpmi/superpmi/icorjitinfo.cpp   |  11 +-
 src/coreclr/vm/jitinterface.cpp               |  33 +++
 19 files changed, 305 insertions(+), 143 deletions(-)

diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h
index 1b4befc32de34e..c9ed71954e2a87 100644
--- a/src/coreclr/inc/corinfo.h
+++ b/src/coreclr/inc/corinfo.h
@@ -2486,8 +2486,12 @@ class ICorStaticInfo
             CORINFO_CLASS_HANDLE        cls
             ) = 0;
 
+    virtual bool isObjectImmutable(
+            void*                       objPtr
+            ) = 0;
+
     virtual CORINFO_CLASS_HANDLE getObjectType(
-            void*                       typeObj
+            void*                       objPtr
             ) = 0;
 
     virtual bool getReadyToRunHelper(
diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h
index 6a54465d383dcb..b9d3378c4550cd 100644
--- a/src/coreclr/inc/icorjitinfoimpl_generated.h
+++ b/src/coreclr/inc/icorjitinfoimpl_generated.h
@@ -288,8 +288,11 @@ CorInfoHelpFunc getUnBoxHelper(
 void* getRuntimeTypePointer(
           CORINFO_CLASS_HANDLE cls) override;
 
+bool isObjectImmutable(
+          void* objPtr) override;
+
 CORINFO_CLASS_HANDLE getObjectType(
-          void* typeObj) override;
+          void* objPtr) override;
 
 bool getReadyToRunHelper(
           CORINFO_RESOLVED_TOKEN* pResolvedToken,
diff --git a/src/coreclr/jit/ICorJitInfo_API_names.h b/src/coreclr/jit/ICorJitInfo_API_names.h
index 6e306d6b1e9e7d..4ba98bdff84cd5 100644
--- a/src/coreclr/jit/ICorJitInfo_API_names.h
+++ b/src/coreclr/jit/ICorJitInfo_API_names.h
@@ -72,6 +72,7 @@ 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)
diff --git a/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp b/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp
index 4c2e2b95ef40f0..431190d6bbf846 100644
--- a/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp
+++ b/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp
@@ -672,11 +672,20 @@ 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* typeObj)
+          void* objPtr)
 {
     API_ENTER(getObjectType);
-    CORINFO_CLASS_HANDLE temp = wrapHnd->getObjectType(typeObj);
+    CORINFO_CLASS_HANDLE temp = wrapHnd->getObjectType(objPtr);
     API_LEAVE(getObjectType);
     return temp;
 }
diff --git a/src/coreclr/jit/gcinfo.cpp b/src/coreclr/jit/gcinfo.cpp
index ae7303435a68c9..43f2acb5a03707 100644
--- a/src/coreclr/jit/gcinfo.cpp
+++ b/src/coreclr/jit/gcinfo.cpp
@@ -254,6 +254,15 @@ GCInfo::WriteBarrierForm GCInfo::gcIsWriteBarrierCandidate(GenTreeStoreInd* stor
 
     if (store->Data()->IsIconHandle(GTF_ICON_OBJ_HDL))
     {
+#ifdef TARGET_ARMARCH
+        const ssize_t handle = store->Data()->AsIntCon()->IconValue();
+        if (!compiler->info.compCompHnd->isObjectImmutable(reinterpret_cast<void*>(handle)))
+        {
+            // See https://github.com/dotnet/runtime/pull/76135#issuecomment-1257258310
+            store->gtFlags |= GTF_IND_VOLATILE;
+        }
+#endif
+
         // Ignore frozen objects
         return WBF_NoBarrier;
     }
diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs b/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs
index 47805909574f71..5c06bf7580f42c 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs
@@ -1018,12 +1018,27 @@ private static CorInfoHelpFunc _getUnBoxHelper(IntPtr thisHandle, IntPtr* ppExce
         }
 
         [UnmanagedCallersOnly]
-        private static CORINFO_CLASS_STRUCT_* _getObjectType(IntPtr thisHandle, IntPtr* ppException, void* typeObj)
+        private static byte _isObjectImmutable(IntPtr thisHandle, IntPtr* ppException, void* objPtr)
         {
             var _this = GetThis(thisHandle);
             try
             {
-                return _this.getObjectType(typeObj);
+                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)
             {
@@ -2655,7 +2670,7 @@ private static uint _getJitFlags(IntPtr thisHandle, IntPtr* ppException, CORJIT_
 
         private static IntPtr GetUnmanagedCallbacks()
         {
-            void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 179);
+            void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 180);
 
             callbacks[0] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, byte>)&_isIntrinsic;
             callbacks[1] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint>)&_getMethodAttribs;
@@ -2725,117 +2740,118 @@ private static IntPtr GetUnmanagedCallbacks()
             callbacks[65] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CorInfoHelpFunc>)&_getBoxHelper;
             callbacks[66] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CorInfoHelpFunc>)&_getUnBoxHelper;
             callbacks[67] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, void*>)&_getRuntimeTypePointer;
-            callbacks[68] = (delegate* unmanaged<IntPtr, IntPtr*, void*, CORINFO_CLASS_STRUCT_*>)&_getObjectType;
-            callbacks[69] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, CORINFO_LOOKUP_KIND*, CorInfoHelpFunc, CORINFO_CONST_LOOKUP*, byte>)&_getReadyToRunHelper;
-            callbacks[70] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, mdToken, CORINFO_CLASS_STRUCT_*, CORINFO_LOOKUP*, void>)&_getReadyToRunDelegateCtorHelper;
-            callbacks[71] = (delegate* unmanaged<IntPtr, IntPtr*, CorInfoHelpFunc, byte*>)&_getHelperName;
-            callbacks[72] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, CORINFO_METHOD_STRUCT_*, CORINFO_CONTEXT_STRUCT*, CorInfoInitClassResult>)&_initClass;
-            callbacks[73] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, void>)&_classMustBeLoadedBeforeCodeIsRun;
-            callbacks[74] = (delegate* unmanaged<IntPtr, IntPtr*, CorInfoClassId, CORINFO_CLASS_STRUCT_*>)&_getBuiltinClass;
-            callbacks[75] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CorInfoType>)&_getTypeForPrimitiveValueClass;
-            callbacks[76] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CorInfoType>)&_getTypeForPrimitiveNumericClass;
-            callbacks[77] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*, byte>)&_canCast;
-            callbacks[78] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*, byte>)&_areTypesEquivalent;
-            callbacks[79] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*, TypeCompareState>)&_compareTypesForCast;
-            callbacks[80] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*, TypeCompareState>)&_compareTypesForEquality;
-            callbacks[81] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*>)&_mergeClasses;
-            callbacks[82] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*, byte>)&_isMoreSpecificType;
-            callbacks[83] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*>)&_getParentType;
-            callbacks[84] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_**, CorInfoType>)&_getChildType;
-            callbacks[85] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, byte>)&_satisfiesClassConstraints;
-            callbacks[86] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, byte>)&_isSDArray;
-            callbacks[87] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, uint>)&_getArrayRank;
-            callbacks[88] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CorInfoArrayIntrinsic>)&_getArrayIntrinsicID;
-            callbacks[89] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, uint, void*>)&_getArrayInitializationData;
-            callbacks[90] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, CORINFO_METHOD_STRUCT_*, CORINFO_HELPER_DESC*, CorInfoIsAccessAllowedResult>)&_canAccessClass;
-            callbacks[91] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, byte**, byte*>)&_getFieldName;
-            callbacks[92] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, CORINFO_CLASS_STRUCT_*>)&_getFieldClass;
-            callbacks[93] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, CORINFO_CLASS_STRUCT_**, CORINFO_CLASS_STRUCT_*, CorInfoType>)&_getFieldType;
-            callbacks[94] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, uint>)&_getFieldOffset;
-            callbacks[95] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, CORINFO_METHOD_STRUCT_*, CORINFO_ACCESS_FLAGS, CORINFO_FIELD_INFO*, void>)&_getFieldInfo;
-            callbacks[96] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, byte>)&_isFieldStatic;
-            callbacks[97] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint*, uint**, BoundaryTypes*, void>)&_getBoundaries;
-            callbacks[98] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint, OffsetMapping*, void>)&_setBoundaries;
-            callbacks[99] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint*, ILVarInfo**, bool*, void>)&_getVars;
-            callbacks[100] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint, NativeVarInfo*, void>)&_setVars;
-            callbacks[101] = (delegate* unmanaged<IntPtr, IntPtr*, InlineTreeNode*, uint, RichOffsetMapping*, uint, void>)&_reportRichMappings;
-            callbacks[102] = (delegate* unmanaged<IntPtr, IntPtr*, UIntPtr, void*>)&_allocateArray;
-            callbacks[103] = (delegate* unmanaged<IntPtr, IntPtr*, void*, void>)&_freeArray;
-            callbacks[104] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_ARG_LIST_STRUCT_*, CORINFO_ARG_LIST_STRUCT_*>)&_getArgNext;
-            callbacks[105] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, CORINFO_ARG_LIST_STRUCT_*, CORINFO_CLASS_STRUCT_**, CorInfoTypeWithMod>)&_getArgType;
-            callbacks[106] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, int, CORINFO_CLASS_STRUCT_**, int>)&_getExactClasses;
-            callbacks[107] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, CORINFO_ARG_LIST_STRUCT_*, CORINFO_CLASS_STRUCT_*>)&_getArgClass;
-            callbacks[108] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CorInfoHFAElemType>)&_getHFAType;
-            callbacks[109] = (delegate* unmanaged<IntPtr, IntPtr*, _EXCEPTION_POINTERS*, HRESULT>)&_GetErrorHRESULT;
-            callbacks[110] = (delegate* unmanaged<IntPtr, IntPtr*, char*, uint, uint>)&_GetErrorMessage;
-            callbacks[111] = (delegate* unmanaged<IntPtr, IntPtr*, _EXCEPTION_POINTERS*, int>)&_FilterException;
-            callbacks[112] = (delegate* unmanaged<IntPtr, IntPtr*, HRESULT, void>)&_ThrowExceptionForJitResult;
-            callbacks[113] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_HELPER_DESC*, void>)&_ThrowExceptionForHelper;
-            callbacks[114] = (delegate* unmanaged<IntPtr, IntPtr*, void*, void*, byte>)&_runWithErrorTrap;
-            callbacks[115] = (delegate* unmanaged<IntPtr, IntPtr*, void*, void*, byte>)&_runWithSPMIErrorTrap;
-            callbacks[116] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_EE_INFO*, void>)&_getEEInfo;
-            callbacks[117] = (delegate* unmanaged<IntPtr, IntPtr*, char*>)&_getJitTimeLogFilename;
-            callbacks[118] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, mdToken>)&_getMethodDefFromMethod;
-            callbacks[119] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, byte**, byte*>)&_getMethodName;
-            callbacks[120] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, byte**, byte**, byte**, byte*>)&_getMethodNameFromMetadata;
-            callbacks[121] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint>)&_getMethodHash;
-            callbacks[122] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_MODULE_STRUCT_*, mdToken, byte*, UIntPtr, UIntPtr>)&_findNameOfToken;
-            callbacks[123] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR*, byte>)&_getSystemVAmd64PassStructInRegisterDescriptor;
-            callbacks[124] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, uint>)&_getLoongArch64PassStructInRegisterFlags;
-            callbacks[125] = (delegate* unmanaged<IntPtr, IntPtr*, void**, uint>)&_getThreadTLSIndex;
-            callbacks[126] = (delegate* unmanaged<IntPtr, IntPtr*, void**, void*>)&_getInlinedCallFrameVptr;
-            callbacks[127] = (delegate* unmanaged<IntPtr, IntPtr*, void**, int*>)&_getAddrOfCaptureThreadGlobal;
-            callbacks[128] = (delegate* unmanaged<IntPtr, IntPtr*, CorInfoHelpFunc, void**, void*>)&_getHelperFtn;
-            callbacks[129] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_CONST_LOOKUP*, CORINFO_ACCESS_FLAGS, void>)&_getFunctionEntryPoint;
-            callbacks[130] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, byte, CORINFO_CONST_LOOKUP*, void>)&_getFunctionFixedEntryPoint;
-            callbacks[131] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, void**, void*>)&_getMethodSync;
-            callbacks[132] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_MODULE_STRUCT_*, CorInfoHelpFunc>)&_getLazyStringLiteralHelper;
-            callbacks[133] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_MODULE_STRUCT_*, void**, CORINFO_MODULE_STRUCT_*>)&_embedModuleHandle;
-            callbacks[134] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, void**, CORINFO_CLASS_STRUCT_*>)&_embedClassHandle;
-            callbacks[135] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, void**, CORINFO_METHOD_STRUCT_*>)&_embedMethodHandle;
-            callbacks[136] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, void**, CORINFO_FIELD_STRUCT_*>)&_embedFieldHandle;
-            callbacks[137] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, byte, CORINFO_GENERICHANDLE_RESULT*, void>)&_embedGenericHandle;
-            callbacks[138] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_LOOKUP_KIND*, void>)&_getLocationOfThisType;
-            callbacks[139] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_CONST_LOOKUP*, void>)&_getAddressOfPInvokeTarget;
-            callbacks[140] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, void**, void*>)&_GetCookieForPInvokeCalliSig;
-            callbacks[141] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, byte>)&_canGetCookieForPInvokeCalliSig;
-            callbacks[142] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_JUST_MY_CODE_HANDLE_**, CORINFO_JUST_MY_CODE_HANDLE_*>)&_getJustMyCodeHandle;
-            callbacks[143] = (delegate* unmanaged<IntPtr, IntPtr*, bool*, void**, bool*, void>)&_GetProfilingHandle;
-            callbacks[144] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, CORINFO_RESOLVED_TOKEN*, CORINFO_METHOD_STRUCT_*, CORINFO_CALLINFO_FLAGS, CORINFO_CALL_INFO*, void>)&_getCallInfo;
-            callbacks[145] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_CLASS_STRUCT_*, byte>)&_canAccessFamily;
-            callbacks[146] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, byte>)&_isRIDClassDomainID;
-            callbacks[147] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, void**, uint>)&_getClassDomainID;
-            callbacks[148] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, void**, void*>)&_getFieldAddress;
-            callbacks[149] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, byte*, int, byte>)&_getReadonlyStaticFieldValue;
-            callbacks[150] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, byte*, CORINFO_CLASS_STRUCT_*>)&_getStaticFieldCurrentClass;
-            callbacks[151] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, void**, IntPtr>)&_getVarArgsHandle;
-            callbacks[152] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, byte>)&_canGetVarArgsHandle;
-            callbacks[153] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_MODULE_STRUCT_*, mdToken, void**, InfoAccessType>)&_constructStringLiteral;
-            callbacks[154] = (delegate* unmanaged<IntPtr, IntPtr*, void**, InfoAccessType>)&_emptyStringLiteral;
-            callbacks[155] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, void**, uint>)&_getFieldThreadLocalStoreID;
-            callbacks[156] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_MODULE_STRUCT_*, CORINFO_MODULE_STRUCT_*, void>)&_addActiveDependency;
-            callbacks[157] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_CLASS_STRUCT_*, CORINFO_METHOD_STRUCT_*, DelegateCtorArgs*, CORINFO_METHOD_STRUCT_*>)&_GetDelegateCtor;
-            callbacks[158] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, void>)&_MethodCompileComplete;
-            callbacks[159] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, CORINFO_SIG_INFO*, CORINFO_GET_TAILCALL_HELPERS_FLAGS, CORINFO_TAILCALL_HELPERS*, byte>)&_getTailCallHelpers;
-            callbacks[160] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, byte, byte>)&_convertPInvokeCalliToCall;
-            callbacks[161] = (delegate* unmanaged<IntPtr, IntPtr*, InstructionSet, byte, byte>)&_notifyInstructionSetUsage;
-            callbacks[162] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CONST_LOOKUP*, void>)&_updateEntryPointForTailCall;
-            callbacks[163] = (delegate* unmanaged<IntPtr, IntPtr*, AllocMemArgs*, void>)&_allocMem;
-            callbacks[164] = (delegate* unmanaged<IntPtr, IntPtr*, byte, byte, uint, void>)&_reserveUnwindInfo;
-            callbacks[165] = (delegate* unmanaged<IntPtr, IntPtr*, byte*, byte*, uint, uint, uint, byte*, CorJitFuncKind, void>)&_allocUnwindInfo;
-            callbacks[166] = (delegate* unmanaged<IntPtr, IntPtr*, UIntPtr, void*>)&_allocGCInfo;
-            callbacks[167] = (delegate* unmanaged<IntPtr, IntPtr*, uint, void>)&_setEHcount;
-            callbacks[168] = (delegate* unmanaged<IntPtr, IntPtr*, uint, CORINFO_EH_CLAUSE*, void>)&_setEHinfo;
-            callbacks[169] = (delegate* unmanaged<IntPtr, IntPtr*, uint, byte*, IntPtr, byte>)&_logMsg;
-            callbacks[170] = (delegate* unmanaged<IntPtr, IntPtr*, byte*, int, byte*, int>)&_doAssert;
-            callbacks[171] = (delegate* unmanaged<IntPtr, IntPtr*, CorJitResult, void>)&_reportFatalError;
-            callbacks[172] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, PgoInstrumentationSchema**, uint*, byte**, PgoSource*, HRESULT>)&_getPgoInstrumentationResults;
-            callbacks[173] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, PgoInstrumentationSchema*, uint, byte**, HRESULT>)&_allocPgoInstrumentationBySchema;
-            callbacks[174] = (delegate* unmanaged<IntPtr, IntPtr*, uint, CORINFO_SIG_INFO*, CORINFO_METHOD_STRUCT_*, void>)&_recordCallSite;
-            callbacks[175] = (delegate* unmanaged<IntPtr, IntPtr*, void*, void*, void*, ushort, ushort, int, void>)&_recordRelocation;
-            callbacks[176] = (delegate* unmanaged<IntPtr, IntPtr*, void*, ushort>)&_getRelocTypeHint;
-            callbacks[177] = (delegate* unmanaged<IntPtr, IntPtr*, uint>)&_getExpectedTargetArchitecture;
-            callbacks[178] = (delegate* unmanaged<IntPtr, IntPtr*, CORJIT_FLAGS*, uint, uint>)&_getJitFlags;
+            callbacks[68] = (delegate* unmanaged<IntPtr, IntPtr*, void*, byte>)&_isObjectImmutable;
+            callbacks[69] = (delegate* unmanaged<IntPtr, IntPtr*, void*, CORINFO_CLASS_STRUCT_*>)&_getObjectType;
+            callbacks[70] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, CORINFO_LOOKUP_KIND*, CorInfoHelpFunc, CORINFO_CONST_LOOKUP*, byte>)&_getReadyToRunHelper;
+            callbacks[71] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, mdToken, CORINFO_CLASS_STRUCT_*, CORINFO_LOOKUP*, void>)&_getReadyToRunDelegateCtorHelper;
+            callbacks[72] = (delegate* unmanaged<IntPtr, IntPtr*, CorInfoHelpFunc, byte*>)&_getHelperName;
+            callbacks[73] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, CORINFO_METHOD_STRUCT_*, CORINFO_CONTEXT_STRUCT*, CorInfoInitClassResult>)&_initClass;
+            callbacks[74] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, void>)&_classMustBeLoadedBeforeCodeIsRun;
+            callbacks[75] = (delegate* unmanaged<IntPtr, IntPtr*, CorInfoClassId, CORINFO_CLASS_STRUCT_*>)&_getBuiltinClass;
+            callbacks[76] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CorInfoType>)&_getTypeForPrimitiveValueClass;
+            callbacks[77] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CorInfoType>)&_getTypeForPrimitiveNumericClass;
+            callbacks[78] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*, byte>)&_canCast;
+            callbacks[79] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*, byte>)&_areTypesEquivalent;
+            callbacks[80] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*, TypeCompareState>)&_compareTypesForCast;
+            callbacks[81] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*, TypeCompareState>)&_compareTypesForEquality;
+            callbacks[82] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*>)&_mergeClasses;
+            callbacks[83] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*, byte>)&_isMoreSpecificType;
+            callbacks[84] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*>)&_getParentType;
+            callbacks[85] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_**, CorInfoType>)&_getChildType;
+            callbacks[86] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, byte>)&_satisfiesClassConstraints;
+            callbacks[87] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, byte>)&_isSDArray;
+            callbacks[88] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, uint>)&_getArrayRank;
+            callbacks[89] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CorInfoArrayIntrinsic>)&_getArrayIntrinsicID;
+            callbacks[90] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, uint, void*>)&_getArrayInitializationData;
+            callbacks[91] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, CORINFO_METHOD_STRUCT_*, CORINFO_HELPER_DESC*, CorInfoIsAccessAllowedResult>)&_canAccessClass;
+            callbacks[92] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, byte**, byte*>)&_getFieldName;
+            callbacks[93] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, CORINFO_CLASS_STRUCT_*>)&_getFieldClass;
+            callbacks[94] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, CORINFO_CLASS_STRUCT_**, CORINFO_CLASS_STRUCT_*, CorInfoType>)&_getFieldType;
+            callbacks[95] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, uint>)&_getFieldOffset;
+            callbacks[96] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, CORINFO_METHOD_STRUCT_*, CORINFO_ACCESS_FLAGS, CORINFO_FIELD_INFO*, void>)&_getFieldInfo;
+            callbacks[97] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, byte>)&_isFieldStatic;
+            callbacks[98] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint*, uint**, BoundaryTypes*, void>)&_getBoundaries;
+            callbacks[99] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint, OffsetMapping*, void>)&_setBoundaries;
+            callbacks[100] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint*, ILVarInfo**, bool*, void>)&_getVars;
+            callbacks[101] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint, NativeVarInfo*, void>)&_setVars;
+            callbacks[102] = (delegate* unmanaged<IntPtr, IntPtr*, InlineTreeNode*, uint, RichOffsetMapping*, uint, void>)&_reportRichMappings;
+            callbacks[103] = (delegate* unmanaged<IntPtr, IntPtr*, UIntPtr, void*>)&_allocateArray;
+            callbacks[104] = (delegate* unmanaged<IntPtr, IntPtr*, void*, void>)&_freeArray;
+            callbacks[105] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_ARG_LIST_STRUCT_*, CORINFO_ARG_LIST_STRUCT_*>)&_getArgNext;
+            callbacks[106] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, CORINFO_ARG_LIST_STRUCT_*, CORINFO_CLASS_STRUCT_**, CorInfoTypeWithMod>)&_getArgType;
+            callbacks[107] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, int, CORINFO_CLASS_STRUCT_**, int>)&_getExactClasses;
+            callbacks[108] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, CORINFO_ARG_LIST_STRUCT_*, CORINFO_CLASS_STRUCT_*>)&_getArgClass;
+            callbacks[109] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CorInfoHFAElemType>)&_getHFAType;
+            callbacks[110] = (delegate* unmanaged<IntPtr, IntPtr*, _EXCEPTION_POINTERS*, HRESULT>)&_GetErrorHRESULT;
+            callbacks[111] = (delegate* unmanaged<IntPtr, IntPtr*, char*, uint, uint>)&_GetErrorMessage;
+            callbacks[112] = (delegate* unmanaged<IntPtr, IntPtr*, _EXCEPTION_POINTERS*, int>)&_FilterException;
+            callbacks[113] = (delegate* unmanaged<IntPtr, IntPtr*, HRESULT, void>)&_ThrowExceptionForJitResult;
+            callbacks[114] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_HELPER_DESC*, void>)&_ThrowExceptionForHelper;
+            callbacks[115] = (delegate* unmanaged<IntPtr, IntPtr*, void*, void*, byte>)&_runWithErrorTrap;
+            callbacks[116] = (delegate* unmanaged<IntPtr, IntPtr*, void*, void*, byte>)&_runWithSPMIErrorTrap;
+            callbacks[117] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_EE_INFO*, void>)&_getEEInfo;
+            callbacks[118] = (delegate* unmanaged<IntPtr, IntPtr*, char*>)&_getJitTimeLogFilename;
+            callbacks[119] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, mdToken>)&_getMethodDefFromMethod;
+            callbacks[120] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, byte**, byte*>)&_getMethodName;
+            callbacks[121] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, byte**, byte**, byte**, byte*>)&_getMethodNameFromMetadata;
+            callbacks[122] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint>)&_getMethodHash;
+            callbacks[123] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_MODULE_STRUCT_*, mdToken, byte*, UIntPtr, UIntPtr>)&_findNameOfToken;
+            callbacks[124] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR*, byte>)&_getSystemVAmd64PassStructInRegisterDescriptor;
+            callbacks[125] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, uint>)&_getLoongArch64PassStructInRegisterFlags;
+            callbacks[126] = (delegate* unmanaged<IntPtr, IntPtr*, void**, uint>)&_getThreadTLSIndex;
+            callbacks[127] = (delegate* unmanaged<IntPtr, IntPtr*, void**, void*>)&_getInlinedCallFrameVptr;
+            callbacks[128] = (delegate* unmanaged<IntPtr, IntPtr*, void**, int*>)&_getAddrOfCaptureThreadGlobal;
+            callbacks[129] = (delegate* unmanaged<IntPtr, IntPtr*, CorInfoHelpFunc, void**, void*>)&_getHelperFtn;
+            callbacks[130] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_CONST_LOOKUP*, CORINFO_ACCESS_FLAGS, void>)&_getFunctionEntryPoint;
+            callbacks[131] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, byte, CORINFO_CONST_LOOKUP*, void>)&_getFunctionFixedEntryPoint;
+            callbacks[132] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, void**, void*>)&_getMethodSync;
+            callbacks[133] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_MODULE_STRUCT_*, CorInfoHelpFunc>)&_getLazyStringLiteralHelper;
+            callbacks[134] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_MODULE_STRUCT_*, void**, CORINFO_MODULE_STRUCT_*>)&_embedModuleHandle;
+            callbacks[135] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, void**, CORINFO_CLASS_STRUCT_*>)&_embedClassHandle;
+            callbacks[136] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, void**, CORINFO_METHOD_STRUCT_*>)&_embedMethodHandle;
+            callbacks[137] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, void**, CORINFO_FIELD_STRUCT_*>)&_embedFieldHandle;
+            callbacks[138] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, byte, CORINFO_GENERICHANDLE_RESULT*, void>)&_embedGenericHandle;
+            callbacks[139] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_LOOKUP_KIND*, void>)&_getLocationOfThisType;
+            callbacks[140] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_CONST_LOOKUP*, void>)&_getAddressOfPInvokeTarget;
+            callbacks[141] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, void**, void*>)&_GetCookieForPInvokeCalliSig;
+            callbacks[142] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, byte>)&_canGetCookieForPInvokeCalliSig;
+            callbacks[143] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_JUST_MY_CODE_HANDLE_**, CORINFO_JUST_MY_CODE_HANDLE_*>)&_getJustMyCodeHandle;
+            callbacks[144] = (delegate* unmanaged<IntPtr, IntPtr*, bool*, void**, bool*, void>)&_GetProfilingHandle;
+            callbacks[145] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, CORINFO_RESOLVED_TOKEN*, CORINFO_METHOD_STRUCT_*, CORINFO_CALLINFO_FLAGS, CORINFO_CALL_INFO*, void>)&_getCallInfo;
+            callbacks[146] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_CLASS_STRUCT_*, byte>)&_canAccessFamily;
+            callbacks[147] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, byte>)&_isRIDClassDomainID;
+            callbacks[148] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, void**, uint>)&_getClassDomainID;
+            callbacks[149] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, void**, void*>)&_getFieldAddress;
+            callbacks[150] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, byte*, int, byte>)&_getReadonlyStaticFieldValue;
+            callbacks[151] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, byte*, CORINFO_CLASS_STRUCT_*>)&_getStaticFieldCurrentClass;
+            callbacks[152] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, void**, IntPtr>)&_getVarArgsHandle;
+            callbacks[153] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, byte>)&_canGetVarArgsHandle;
+            callbacks[154] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_MODULE_STRUCT_*, mdToken, void**, InfoAccessType>)&_constructStringLiteral;
+            callbacks[155] = (delegate* unmanaged<IntPtr, IntPtr*, void**, InfoAccessType>)&_emptyStringLiteral;
+            callbacks[156] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, void**, uint>)&_getFieldThreadLocalStoreID;
+            callbacks[157] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_MODULE_STRUCT_*, CORINFO_MODULE_STRUCT_*, void>)&_addActiveDependency;
+            callbacks[158] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_CLASS_STRUCT_*, CORINFO_METHOD_STRUCT_*, DelegateCtorArgs*, CORINFO_METHOD_STRUCT_*>)&_GetDelegateCtor;
+            callbacks[159] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, void>)&_MethodCompileComplete;
+            callbacks[160] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, CORINFO_SIG_INFO*, CORINFO_GET_TAILCALL_HELPERS_FLAGS, CORINFO_TAILCALL_HELPERS*, byte>)&_getTailCallHelpers;
+            callbacks[161] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, byte, byte>)&_convertPInvokeCalliToCall;
+            callbacks[162] = (delegate* unmanaged<IntPtr, IntPtr*, InstructionSet, byte, byte>)&_notifyInstructionSetUsage;
+            callbacks[163] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CONST_LOOKUP*, void>)&_updateEntryPointForTailCall;
+            callbacks[164] = (delegate* unmanaged<IntPtr, IntPtr*, AllocMemArgs*, void>)&_allocMem;
+            callbacks[165] = (delegate* unmanaged<IntPtr, IntPtr*, byte, byte, uint, void>)&_reserveUnwindInfo;
+            callbacks[166] = (delegate* unmanaged<IntPtr, IntPtr*, byte*, byte*, uint, uint, uint, byte*, CorJitFuncKind, void>)&_allocUnwindInfo;
+            callbacks[167] = (delegate* unmanaged<IntPtr, IntPtr*, UIntPtr, void*>)&_allocGCInfo;
+            callbacks[168] = (delegate* unmanaged<IntPtr, IntPtr*, uint, void>)&_setEHcount;
+            callbacks[169] = (delegate* unmanaged<IntPtr, IntPtr*, uint, CORINFO_EH_CLAUSE*, void>)&_setEHinfo;
+            callbacks[170] = (delegate* unmanaged<IntPtr, IntPtr*, uint, byte*, IntPtr, byte>)&_logMsg;
+            callbacks[171] = (delegate* unmanaged<IntPtr, IntPtr*, byte*, int, byte*, int>)&_doAssert;
+            callbacks[172] = (delegate* unmanaged<IntPtr, IntPtr*, CorJitResult, void>)&_reportFatalError;
+            callbacks[173] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, PgoInstrumentationSchema**, uint*, byte**, PgoSource*, HRESULT>)&_getPgoInstrumentationResults;
+            callbacks[174] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, PgoInstrumentationSchema*, uint, byte**, HRESULT>)&_allocPgoInstrumentationBySchema;
+            callbacks[175] = (delegate* unmanaged<IntPtr, IntPtr*, uint, CORINFO_SIG_INFO*, CORINFO_METHOD_STRUCT_*, void>)&_recordCallSite;
+            callbacks[176] = (delegate* unmanaged<IntPtr, IntPtr*, void*, void*, void*, ushort, ushort, int, void>)&_recordRelocation;
+            callbacks[177] = (delegate* unmanaged<IntPtr, IntPtr*, void*, ushort>)&_getRelocTypeHint;
+            callbacks[178] = (delegate* unmanaged<IntPtr, IntPtr*, uint>)&_getExpectedTargetArchitecture;
+            callbacks[179] = (delegate* unmanaged<IntPtr, IntPtr*, CORJIT_FLAGS*, uint, uint>)&_getJitFlags;
 
             return (IntPtr)callbacks;
         }
diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
index 06a29f75d91d00..433537b2072b77 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
@@ -2343,14 +2343,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
-        {
-            // TODO: https://github.com/dotnet/runtime/pull/75573#issuecomment-1250824543
-            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 7ae8475d1506a9..96b0e73b4dc06d 100644
--- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt
+++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt
@@ -223,7 +223,8 @@ FUNCTIONS
     CorInfoHelpFunc getBoxHelper(CORINFO_CLASS_HANDLE cls)
     CorInfoHelpFunc getUnBoxHelper(CORINFO_CLASS_HANDLE cls)
     void* getRuntimeTypePointer(CORINFO_CLASS_HANDLE cls)
-    CORINFO_CLASS_HANDLE getObjectType(void* typeObj)
+    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)
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 80e8359d2ffaec..aa95d302834a9f 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs
@@ -3000,7 +3000,17 @@ private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byt
 
         private CORINFO_CLASS_STRUCT_* getObjectType(void* objPtr)
         {
-            return (CORINFO_CLASS_STRUCT_*)IntPtr.Zero;
+            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 b9f47420f0b346..f5526393b43233 100644
--- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
+++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
@@ -2253,5 +2253,22 @@ private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byt
                 _ => throw new NotImplementedException($"Unexpected object in getObjectType: {obj}")
             };
         }
+
+        private void* getRuntimeTypePointer(CORINFO_CLASS_STRUCT_* cls)
+        {
+            // TODO: https://github.com/dotnet/runtime/pull/75573#issuecomment-1250824543
+            throw new NotImplementedException();
+        }
+
+        private bool isObjectImmutable(void* objPtr)
+        {
+            object obj = HandleToObject((IntPtr)objPtr);
+            return obj switch
+            {
+                FrozenStringNode => true,
+                FrozenObjectNode => false,
+                _ => 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 b00339b2b4e95a..f3e5b3445982a1 100644
--- a/src/coreclr/tools/aot/jitinterface/jitinterface.h
+++ b/src/coreclr/tools/aot/jitinterface/jitinterface.h
@@ -79,7 +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);
-    CORINFO_CLASS_HANDLE (* getObjectType)(void * thisHandle, CorInfoExceptionClass** ppException, void* typeObj);
+    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);
@@ -865,11 +866,20 @@ 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* typeObj)
+          void* objPtr)
 {
     CorInfoExceptionClass* pException = nullptr;
-    CORINFO_CLASS_HANDLE temp = _callbacks->getObjectType(_thisHandle, &pException, typeObj);
+    CORINFO_CLASS_HANDLE temp = _callbacks->getObjectType(_thisHandle, &pException, objPtr);
     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 b0af2f1e3f2500..a4ed23c57024c1 100644
--- a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h
+++ b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h
@@ -140,6 +140,7 @@ 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)
diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp
index b46094963bb95e..c2da94ac6f2aab 100644
--- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp
+++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp
@@ -2207,12 +2207,35 @@ void* MethodContext::repGetRuntimeTypePointer(CORINFO_CLASS_HANDLE cls)
     return (void*)value;
 }
 
-void MethodContext::recGetObjectType(void* typeObj, CORINFO_CLASS_HANDLE result)
+void MethodContext::recIsObjectImmutable(void* objPtr, bool result)
+{
+    if (IsObjectImmutable == nullptr)
+        IsObjectImmutable = new LightWeightMap<DWORDLONG, DWORD>();
+
+    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, DWORDLONG>();
 
-    DWORDLONG key = (DWORDLONG)typeObj;
+    DWORDLONG key = (DWORDLONG)objPtr;
     DWORDLONG value = (DWORDLONG)result;
     GetObjectType->Add(key, value);
     DEBUG_REC(dmpGetObjectType(key, value));
@@ -2221,9 +2244,9 @@ void MethodContext::dmpGetObjectType(DWORDLONG key, DWORDLONG value)
 {
     printf("GetObjectType key obj-%016llX, value res-%016llX", key, value);
 }
-CORINFO_CLASS_HANDLE MethodContext::repGetObjectType(void* typeObj)
+CORINFO_CLASS_HANDLE MethodContext::repGetObjectType(void* objPtr)
 {
-    DWORDLONG key = (DWORDLONG)typeObj;
+    DWORDLONG key = (DWORDLONG)objPtr;
     AssertMapAndKeyExist(GetObjectType, key, ": key %016llX", key);
     DWORDLONG value = GetObjectType->Get(key);
     DEBUG_REP(dmpGetObjectType(key, value));
diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h
index 79f7b14365f87d..e6aa9111a394a0 100644
--- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h
+++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h
@@ -314,9 +314,13 @@ class MethodContext
     void dmpGetRuntimeTypePointer(DWORDLONG key, DWORDLONG value);
     void* repGetRuntimeTypePointer(CORINFO_CLASS_HANDLE cls);
 
-    void recGetObjectType(void* typeObj, CORINFO_CLASS_HANDLE result);
+    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* typeObj);
+    CORINFO_CLASS_HANDLE repGetObjectType(void* objPtr);
 
     void recGetReadyToRunHelper(CORINFO_RESOLVED_TOKEN* pResolvedToken,
                                 CORINFO_LOOKUP_KIND*    pGenericLookupKind,
@@ -1138,6 +1142,7 @@ enum mcPackets
     Packet_ObjectToString = 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 b90a955fa53ff3..de0cefe9cf4279 100644
--- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp
+++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp
@@ -798,6 +798,14 @@ 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");
diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp
index 1e86378f5155b1..ebc3162218b85b 100644
--- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp
+++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp
@@ -551,11 +551,18 @@ 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* typeObj)
+          void* objPtr)
 {
     mcs->AddCall("getObjectType");
-    return original_ICorJitInfo->getObjectType(typeObj);
+    return original_ICorJitInfo->getObjectType(objPtr);
 }
 
 bool interceptor_ICJI::getReadyToRunHelper(
diff --git a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp
index 1058681597f712..fb9bb5f7063b3b 100644
--- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp
+++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp
@@ -483,10 +483,16 @@ 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* typeObj)
+          void* objPtr)
 {
-    return original_ICorJitInfo->getObjectType(typeObj);
+    return original_ICorJitInfo->getObjectType(objPtr);
 }
 
 bool interceptor_ICJI::getReadyToRunHelper(
diff --git a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp
index fe6e7a4c7bc36f..b815f2b27bd892 100644
--- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp
+++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp
@@ -679,10 +679,17 @@ void* MyICJI::getRuntimeTypePointer(CORINFO_CLASS_HANDLE cls)
     return result;
 }
 
-CORINFO_CLASS_HANDLE MyICJI::getObjectType(void* typeObj)
+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(typeObj);
+    CORINFO_CLASS_HANDLE result = jitInstance->mc->repGetObjectType(objPtr);
     return result;
 }
 
diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp
index 91abd581c08f28..287455a0d5aeb0 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -6015,6 +6015,39 @@ void* CEEInfo::getRuntimeTypePointer(CORINFO_CLASS_HANDLE clsHnd)
     return pointer;
 }
 
+
+/***********************************************************************/
+bool CEEInfo::isObjectImmutable(void* objPtr)
+{
+    CONTRACTL{
+        THROWS;
+        GC_TRIGGERS;
+        MODE_PREEMPTIVE;
+    } CONTRACTL_END;
+
+    bool isImmutable = false;
+
+    JIT_TO_EE_TRANSITION();
+
+    GCX_COOP();
+    Object* obj = (Object*)objPtr;
+    MethodTable* type = obj->GetMethodTable();
+
+    if (type->IsString() || type == g_pRuntimeTypeClass)
+    {
+        isImmutable = true;
+    }
+    else
+    {
+        // Unexpected type of object
+        UNREACHABLE();
+    }
+
+    EE_TO_JIT_TRANSITION();
+
+    return isImmutable;
+}
+
 /***********************************************************************/
 CORINFO_CLASS_HANDLE CEEInfo::getObjectType(void* objPtr)
 {

From 48343eed2d351562fdaceb38d6c2b7151fa9de36 Mon Sep 17 00:00:00 2001
From: Egor Bogatov <egorbo@gmail.com>
Date: Mon, 26 Sep 2022 17:10:00 +0200
Subject: [PATCH 30/61] Update gcinfo.cpp

---
 src/coreclr/jit/gcinfo.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/coreclr/jit/gcinfo.cpp b/src/coreclr/jit/gcinfo.cpp
index 43f2acb5a03707..7b3cecc9b4f2b6 100644
--- a/src/coreclr/jit/gcinfo.cpp
+++ b/src/coreclr/jit/gcinfo.cpp
@@ -254,7 +254,7 @@ GCInfo::WriteBarrierForm GCInfo::gcIsWriteBarrierCandidate(GenTreeStoreInd* stor
 
     if (store->Data()->IsIconHandle(GTF_ICON_OBJ_HDL))
     {
-#ifdef TARGET_ARMARCH
+#ifndef TARGET_XARCH
         const ssize_t handle = store->Data()->AsIntCon()->IconValue();
         if (!compiler->info.compCompHnd->isObjectImmutable(reinterpret_cast<void*>(handle)))
         {

From 7264f67a1fe39a919764c4618163c88766b8a0e7 Mon Sep 17 00:00:00 2001
From: EgorBo <egorbo@gmail.com>
Date: Mon, 26 Sep 2022 18:05:20 +0200
Subject: [PATCH 31/61] fix getRuntimeTypePointer on NativeAOT

---
 .../aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs    | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

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 f5526393b43233..61ba6ecc307fa5 100644
--- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
+++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
@@ -2257,7 +2257,7 @@ private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byt
         private void* getRuntimeTypePointer(CORINFO_CLASS_STRUCT_* cls)
         {
             // TODO: https://github.com/dotnet/runtime/pull/75573#issuecomment-1250824543
-            throw new NotImplementedException();
+            return null;
         }
 
         private bool isObjectImmutable(void* objPtr)

From 8d4048a083c0082d1926ebf2da4074a3d7d2afed Mon Sep 17 00:00:00 2001
From: EgorBo <egorbo@gmail.com>
Date: Mon, 26 Sep 2022 18:39:08 +0200
Subject: [PATCH 32/61] fix getRuntimeTypePointer on NativeAOT

---
 .../aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs    | 2 ++
 1 file changed, 2 insertions(+)

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 61ba6ecc307fa5..9f87941d5cbe59 100644
--- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
+++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
@@ -2254,7 +2254,9 @@ private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byt
             };
         }
 
+#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;

From 44a8fc612477b63fceb48b9e25360c7c3832a206 Mon Sep 17 00:00:00 2001
From: EgorBo <egorbo@gmail.com>
Date: Thu, 6 Oct 2022 19:17:06 +0200
Subject: [PATCH 33/61] Fix compilation

---
 .../aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs  | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

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 08183c876fbbe1..e3ab92272c9249 100644
--- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
+++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
@@ -2241,7 +2241,7 @@ private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byt
 
         private CORINFO_CLASS_STRUCT_* getObjectType(void* objPtr)
         {
-            object obj = HandleToObject((IntPtr)objPtr);
+            object obj = HandleToObject(objPtr);
             return obj switch
             {
                 // For now we only support frozen strings
@@ -2264,7 +2264,7 @@ private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byt
 
         private bool isObjectImmutable(void* objPtr)
         {
-            object obj = HandleToObject((IntPtr)objPtr);
+            object obj = HandleToObject(objPtr);
             return obj switch
             {
                 FrozenStringNode => true,

From 256bbd4179d9b9d85046c63911a84ba8a12223fa Mon Sep 17 00:00:00 2001
From: Egor Bogatov <egorbo@gmail.com>
Date: Thu, 6 Oct 2022 19:21:30 +0200
Subject: [PATCH 34/61] Apply suggestions from code review

Co-authored-by: Jan Kotas <jkotas@microsoft.com>
---
 .../JitInterface/CorInfoImpl.RyuJit.cs          |  2 --
 src/coreclr/vm/jitinterface.cpp                 | 17 +++++------------
 2 files changed, 5 insertions(+), 14 deletions(-)

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 e3ab92272c9249..e9319e2d9866bb 100644
--- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
+++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
@@ -2244,10 +2244,8 @@ private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byt
             object obj = HandleToObject(objPtr);
             return obj switch
             {
-                // For now we only support frozen strings
                 FrozenStringNode => ObjectToHandle(_compilation.TypeSystemContext.GetWellKnownType(WellKnownType.String)),
 
-                // and frozen objects like arrays
                 FrozenObjectNode frozenObj => ObjectToHandle(frozenObj.ObjectType),
 
                 _ => throw new NotImplementedException($"Unexpected object in getObjectType: {obj}")
diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp
index a80f1daeb88730..78f6ab4cbbb851 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -6038,27 +6038,20 @@ bool CEEInfo::isObjectImmutable(void* objPtr)
         MODE_PREEMPTIVE;
     } CONTRACTL_END;
 
-    bool isImmutable = false;
-
+#ifdef DEBUG
     JIT_TO_EE_TRANSITION();
 
     GCX_COOP();
     Object* obj = (Object*)objPtr;
     MethodTable* type = obj->GetMethodTable();
 
-    if (type->IsString() || type == g_pRuntimeTypeClass)
-    {
-        isImmutable = true;
-    }
-    else
-    {
-        // Unexpected type of object
-        UNREACHABLE();
-    }
+    _ASSERTE(type->IsString() || type == g_pRuntimeTypeClass);
 
     EE_TO_JIT_TRANSITION();
+#endif
 
-    return isImmutable;
+     // All currently allocated frozen objects can be treated as immutable
+    return true;
 }
 
 /***********************************************************************/

From fefbbe1a026c3ab64e68babd2ac2200ede9429db Mon Sep 17 00:00:00 2001
From: EgorBo <egorbo@gmail.com>
Date: Thu, 6 Oct 2022 19:48:02 +0200
Subject: [PATCH 35/61] ILC: use correct TargetPtrSize

---
 .../JitInterface/CorInfoImpl.RyuJit.cs                | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

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 e9319e2d9866bb..6074392cee47c2 100644
--- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
+++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
@@ -2215,9 +2215,13 @@ private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byt
                     TypePreinit.ISerializableValue value = preinitManager
                         .GetPreinitializationInfo(owningType).GetFieldValue(field);
 
+                    int targetPtrSize = _compilation.TypeSystemContext.Target.PointerSize;
+
                     if (value == null)
                     {
-                        *((nint*)buffer) = 0;
+                        // Write "null" to buffer
+                        Debug.Assert(bufferSize >= targetPtrSize);
+                        new Span<byte>(buffer, targetPtrSize).Clear();
                         return true;
                     }
 
@@ -2230,7 +2234,10 @@ private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byt
                                 return true;
 
                             case FrozenObjectNode or FrozenStringNode:
-                                *(nint*)buffer = ObjectToHandle(data);
+                                // save handle's value to buffer
+                                nint handle = ObjectToHandle(data);
+                                Debug.Assert(bufferSize >= targetPtrSize);
+                                new Span<byte>(&handle, targetPtrSize).CopyTo(new Span<byte>(buffer, targetPtrSize));
                                 return true;
                         }
                     }

From 3d06a33a76eea10fa90884df37c43a831cb09b0d Mon Sep 17 00:00:00 2001
From: EgorBo <egorbo@gmail.com>
Date: Thu, 6 Oct 2022 21:05:44 +0200
Subject: [PATCH 36/61] Address feedback

---
 .../Compiler/TypePreinit.cs                   | 24 +++++++++++++++----
 .../JitInterface/CorInfoImpl.RyuJit.cs        | 10 +++++---
 2 files changed, 26 insertions(+), 8 deletions(-)

diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs
index d063ffb541c05c..3f6339e91e9829 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs
@@ -1769,11 +1769,7 @@ public virtual bool TryCreateByRef(out Value value)
 
             public abstract void WriteFieldData(ref ObjectDataBuilder builder, NodeFactory factory);
 
-            public virtual bool GetRawData(NodeFactory factory, out object data)
-            {
-                data = null;
-                return false;
-            }
+            public abstract bool GetRawData(NodeFactory factory, out object data);
 
             private static T ThrowInvalidProgram<T>()
             {
@@ -1917,6 +1913,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
@@ -1944,6 +1946,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
@@ -1990,6 +1998,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
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 6074392cee47c2..8edce45f28e63a 100644
--- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
+++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
@@ -2219,8 +2219,9 @@ private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byt
 
                     if (value == null)
                     {
-                        // Write "null" to buffer
                         Debug.Assert(bufferSize >= targetPtrSize);
+
+                        // Write "null" to buffer
                         new Span<byte>(buffer, targetPtrSize).Clear();
                         return true;
                     }
@@ -2229,14 +2230,17 @@ private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byt
                     {
                         switch (data)
                         {
-                            case byte[] bytes when bytes.Length <= bufferSize:
+                            case byte[] bytes:
+                                Debug.Assert(bufferSize >= bytes.Length);
+
                                 bytes.AsSpan().CopyTo(new Span<byte>(buffer, bufferSize));
                                 return true;
 
                             case FrozenObjectNode or FrozenStringNode:
+                                Debug.Assert(bufferSize >= targetPtrSize);
+
                                 // save handle's value to buffer
                                 nint handle = ObjectToHandle(data);
-                                Debug.Assert(bufferSize >= targetPtrSize);
                                 new Span<byte>(&handle, targetPtrSize).CopyTo(new Span<byte>(buffer, targetPtrSize));
                                 return true;
                         }

From afefe442872705e6a413c391bec28541d82b8928 Mon Sep 17 00:00:00 2001
From: EgorBo <egorbo@gmail.com>
Date: Thu, 6 Oct 2022 21:35:03 +0200
Subject: [PATCH 37/61] Add support for delegates, empty arrays and objects
 without fields

---
 .../Compiler/DependencyAnalysis/FrozenObjectNode.cs        | 2 ++
 .../tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs  | 7 +++++++
 .../ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs   | 4 +---
 3 files changed, 10 insertions(+), 3 deletions(-)

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 ee3279e89c9365..18ff65d55f37ea 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/FrozenObjectNode.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/FrozenObjectNode.cs
@@ -37,6 +37,8 @@ public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
 
         public TypeDesc ObjectType => _data.Type;
 
+        public bool IsKnownImmutable => _data.IsKnownImmutable;
+
         int ISymbolNode.Offset => 0;
 
         int ISymbolDefinitionNode.Offset
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs
index 3f6339e91e9829..6ba34016e78520 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs
@@ -1715,6 +1715,7 @@ public interface ISerializableReference : ISerializableValue
         {
             TypeDesc Type { get; }
             void WriteContent(ref ObjectDataBuilder builder, ISymbolNode thisNode, NodeFactory factory);
+            bool IsKnownImmutable { get; }
         }
 
         /// <summary>
@@ -2134,6 +2135,8 @@ public override void WriteFieldData(ref ObjectDataBuilder builder, NodeFactory f
             {
                 builder.EmitPointerReloc(factory.SerializedFrozenObject(AllocationSite.OwningType, AllocationSite.InstructionCounter, this));
             }
+
+            public bool IsKnownImmutable => true;
         }
 
 #pragma warning disable CA1852
@@ -2222,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
@@ -2341,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.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
index 8edce45f28e63a..9f48f080b5b2f3 100644
--- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
+++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
@@ -2256,9 +2256,7 @@ private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byt
             return obj switch
             {
                 FrozenStringNode => ObjectToHandle(_compilation.TypeSystemContext.GetWellKnownType(WellKnownType.String)),
-
                 FrozenObjectNode frozenObj => ObjectToHandle(frozenObj.ObjectType),
-
                 _ => throw new NotImplementedException($"Unexpected object in getObjectType: {obj}")
             };
         }
@@ -2277,7 +2275,7 @@ private bool isObjectImmutable(void* objPtr)
             return obj switch
             {
                 FrozenStringNode => true,
-                FrozenObjectNode => false,
+                FrozenObjectNode frozenObj => frozenObj.IsKnownImmutable,
                 _ => throw new NotImplementedException($"Unexpected object in isObjectImmutable: {obj}")
             };
         }

From eece561f856a8e650cc915f901522b100e5c61c3 Mon Sep 17 00:00:00 2001
From: EgorBo <egorbo@gmail.com>
Date: Thu, 6 Oct 2022 21:50:18 +0200
Subject: [PATCH 38/61] Add some comments

---
 src/coreclr/inc/corinfo.h | 43 ++++++++++++++++++++++++++++++++++-----
 1 file changed, 38 insertions(+), 5 deletions(-)

diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h
index 509acbd00a077f..dede4ad2f8858c 100644
--- a/src/coreclr/inc/corinfo.h
+++ b/src/coreclr/inc/corinfo.h
@@ -2503,10 +2503,28 @@ 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;
@@ -3175,11 +3193,26 @@ class ICorDynamicInfo : public ICorStaticInfo
                     void                  **ppIndirection = NULL
                     ) = 0;
 
-    // Returns true if the given field is "static readonly" and its value will never change
-    // also, returns its actual value via pValue argument. For now, it's either:
-    //  * integer/floating point primitive
-    //  * null
-    //  * frozen object
+    //------------------------------------------------------------------------------
+    // 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 which in turn can be:
+    //       * string
+    //       * RuntimeType (CoreCLR only)
+    //       * Array (NativeAOT only)
+    //       * Delegate (NativeAOT only)
+    //       * Object wihtout fields (NativeAOT only)
+    //
+    // 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 succesfully copied to buffer
+    //
     virtual bool getReadonlyStaticFieldValue(
                     CORINFO_FIELD_HANDLE    field,
                     uint8_t                *buffer,

From e2ae1178b7354654148a07be3c874424e087e2eb Mon Sep 17 00:00:00 2001
From: Egor Bogatov <egorbo@gmail.com>
Date: Thu, 6 Oct 2022 21:55:45 +0200
Subject: [PATCH 39/61] Update
 src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs

Co-authored-by: Jan Kotas <jkotas@microsoft.com>
---
 .../tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs       | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs
index 6ba34016e78520..24cfdac46c01a7 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs
@@ -2136,7 +2136,7 @@ public override void WriteFieldData(ref ObjectDataBuilder builder, NodeFactory f
                 builder.EmitPointerReloc(factory.SerializedFrozenObject(AllocationSite.OwningType, AllocationSite.InstructionCounter, this));
             }
 
-            public bool IsKnownImmutable => true;
+            public bool IsKnownImmutable => _methodPointed.Signature.IsStatic;
         }
 
 #pragma warning disable CA1852

From 34b39cb7ecd4e0e6b88c0e02898e862a9633a0c8 Mon Sep 17 00:00:00 2001
From: Egor Bogatov <egorbo@gmail.com>
Date: Thu, 6 Oct 2022 22:02:27 +0200
Subject: [PATCH 40/61] Apply suggestions from code review

Co-authored-by: Jan Kotas <jkotas@microsoft.com>
---
 src/coreclr/inc/corinfo.h | 9 ++-------
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h
index dede4ad2f8858c..c6135b8ed173a1 100644
--- a/src/coreclr/inc/corinfo.h
+++ b/src/coreclr/inc/corinfo.h
@@ -3198,12 +3198,7 @@ class ICorDynamicInfo : public ICorStaticInfo
     //    field represents a statically initialized readonly field of any type, it might be:
     //    * integer/floating point primitive
     //    * null
-    //    * frozen object which in turn can be:
-    //       * string
-    //       * RuntimeType (CoreCLR only)
-    //       * Array (NativeAOT only)
-    //       * Delegate (NativeAOT only)
-    //       * Object wihtout fields (NativeAOT only)
+    //    * frozen object reference (string, array or object)
     //
     // Arguments:
     //    field      - field handle
@@ -3211,7 +3206,7 @@ class ICorDynamicInfo : public ICorStaticInfo
     //    bufferSize - size of buffer
     //
     // Return Value:
-    //    Returns true if field's constant value was succesfully copied to buffer
+    //    Returns true if field's constant value was available and successfully copied to buffer
     //
     virtual bool getReadonlyStaticFieldValue(
                     CORINFO_FIELD_HANDLE    field,

From 22baa4325e5147dbcf27b048ecb4f8478ba3a201 Mon Sep 17 00:00:00 2001
From: EgorBo <egorbo@gmail.com>
Date: Thu, 6 Oct 2022 22:53:25 +0200
Subject: [PATCH 41/61] Ah, actually we need that condition, it can be a struct

---
 .../aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

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 9f48f080b5b2f3..86b0a5d59da4bb 100644
--- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
+++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
@@ -2230,9 +2230,8 @@ private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byt
                     {
                         switch (data)
                         {
-                            case byte[] bytes:
-                                Debug.Assert(bufferSize >= bytes.Length);
-
+                            case byte[] bytes when bufferSize >= bytes.Length:
+                                // Ensure we have enough room in the buffer, it can be a large struct
                                 bytes.AsSpan().CopyTo(new Span<byte>(buffer, bufferSize));
                                 return true;
 

From 47523545d3965c90b5e08c4773a100ed4253e912 Mon Sep 17 00:00:00 2001
From: EgorBo <egorbo@gmail.com>
Date: Fri, 7 Oct 2022 14:46:40 +0200
Subject: [PATCH 42/61] Address Jakob's feedback

---
 src/coreclr/jit/gcinfo.cpp                    |  8 ++++-
 .../superpmi-shared/methodcontext.cpp         |  2 +-
 src/coreclr/vm/jitinterface.cpp               | 31 +++++++++++++------
 3 files changed, 29 insertions(+), 12 deletions(-)

diff --git a/src/coreclr/jit/gcinfo.cpp b/src/coreclr/jit/gcinfo.cpp
index 7b3cecc9b4f2b6..732075b876a505 100644
--- a/src/coreclr/jit/gcinfo.cpp
+++ b/src/coreclr/jit/gcinfo.cpp
@@ -252,13 +252,19 @@ 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))
     {
 #ifndef TARGET_XARCH
         const ssize_t handle = store->Data()->AsIntCon()->IconValue();
         if (!compiler->info.compCompHnd->isObjectImmutable(reinterpret_cast<void*>(handle)))
         {
-            // See https://github.com/dotnet/runtime/pull/76135#issuecomment-1257258310
+            // 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
             store->gtFlags |= GTF_IND_VOLATILE;
         }
 #endif
diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp
index dd8062b8bed174..ae9cc6da3ec2df 100644
--- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp
+++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp
@@ -3664,7 +3664,7 @@ bool MethodContext::repGetReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, u
     int itemIndex = GetReadonlyStaticFieldValue->GetIndex(key);
     if (itemIndex < 0)
     {
-        return false;
+        LogException(EXCEPTIONCODE_MC, "repGetReadonlyStaticFieldValue: didn't find buffer for {fld-%016llX, %d}", field, bufferSize);
     }
     else
     {
diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp
index 78f6ab4cbbb851..db8cd5542d4b2b 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -11889,6 +11889,19 @@ bool CEEInfo::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE fieldHnd, uint8_t
 
     JIT_TO_EE_TRANSITION();
 
+    auto setResult = [&](void* data, int size)
+    {
+        if (size > bufferSize)
+        {
+            result = false;
+        }
+        else
+        {
+            memcpy(buffer, data, size);
+            result = true;
+        }
+    };
+
     FieldDesc* field = (FieldDesc*)fieldHnd;
     if (field->IsStatic() && !field->IsThreadStatic())
     {
@@ -11911,15 +11924,13 @@ bool CEEInfo::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE fieldHnd, uint8_t
                         Object* obj = OBJECTREFToObject(fieldObj);
                         if (GCHeapUtilities::GetGCHeap()->IsInFrozenSegment(obj))
                         {
-                            intptr_t ptr = (intptr_t)obj;
-                            memcpy(buffer, &ptr, sizeof(intptr_t));
-                            result = true;
+                            setResult(&obj, sizeof(intptr_t));
                         }
                     }
                     else
                     {
-                        memset(buffer, 0, sizeof(intptr_t));
-                        result = true;
+                        intptr_t zero = 0;
+                        setResult(&zero, sizeof(intptr_t));
                     }
                 }
                 else
@@ -11934,26 +11945,26 @@ bool CEEInfo::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE fieldHnd, uint8_t
                             case ELEMENT_TYPE_BOOLEAN:
                             case ELEMENT_TYPE_I1:
                             case ELEMENT_TYPE_U1:
-                                memcpy(buffer, fldAddr, sizeof(uint8_t));
+                                setResult(fldAddr, sizeof(uint8_t));
                                 break;
                             case ELEMENT_TYPE_CHAR:
                             case ELEMENT_TYPE_I2:
                             case ELEMENT_TYPE_U2:
-                                memcpy(buffer, fldAddr, sizeof(uint16_t));
+                                setResult(fldAddr, sizeof(uint16_t));
                                 break;
                             case ELEMENT_TYPE_I4:
                             case ELEMENT_TYPE_U4:
                             case ELEMENT_TYPE_R4:
-                                memcpy(buffer, fldAddr, sizeof(uint32_t));
+                                setResult(fldAddr, sizeof(uint32_t));
                                 break;
                             case ELEMENT_TYPE_I8:
                             case ELEMENT_TYPE_U8:
                             case ELEMENT_TYPE_R8:
-                                memcpy(buffer, fldAddr, sizeof(uint64_t));
+                                setResult(fldAddr, sizeof(uint64_t));
                                 break;
                             case ELEMENT_TYPE_I:
                             case ELEMENT_TYPE_U:
-                                memcpy(buffer, fldAddr, sizeof(intptr_t));
+                                setResult(fldAddr, sizeof(intptr_t));
                                 break;
                             default:
                                 result = false;

From 49ab02390695d2d6bf86ddc313d985410ef79143 Mon Sep 17 00:00:00 2001
From: EgorBo <egorbo@gmail.com>
Date: Fri, 7 Oct 2022 15:07:17 +0200
Subject: [PATCH 43/61] fix compilation

---
 .../Compiler/DependencyAnalysis/FrozenObjectNode.cs             | 2 ++
 src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp    | 1 +
 2 files changed, 3 insertions(+)

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 18ff65d55f37ea..bc863631e88183 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/FrozenObjectNode.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/FrozenObjectNode.cs
@@ -105,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/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp
index ae9cc6da3ec2df..e50a507cf54234 100644
--- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp
+++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp
@@ -3665,6 +3665,7 @@ bool MethodContext::repGetReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, u
     if (itemIndex < 0)
     {
         LogException(EXCEPTIONCODE_MC, "repGetReadonlyStaticFieldValue: didn't find buffer for {fld-%016llX, %d}", field, bufferSize);
+        return false;
     }
     else
     {

From 08d59f5123ecc7638f405ac927462171fe43e987 Mon Sep 17 00:00:00 2001
From: EgorBo <egorbo@gmail.com>
Date: Fri, 7 Oct 2022 15:14:26 +0200
Subject: [PATCH 44/61] Use AssertMapExistsNoMessage

---
 .../superpmi-shared/methodcontext.cpp         | 28 ++++++-------------
 1 file changed, 9 insertions(+), 19 deletions(-)

diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp
index e50a507cf54234..6d814571511904 100644
--- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp
+++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp
@@ -3653,32 +3653,22 @@ void MethodContext::dmpGetReadonlyStaticFieldValue(DLD key, DD value)
 }
 bool MethodContext::repGetReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize)
 {
-    if (GetReadonlyStaticFieldValue == nullptr)
-        return false;
-
     DLD key;
     ZeroMemory(&key, sizeof(key));
     key.A = CastHandle(field);
     key.B = (DWORD)bufferSize;
 
-    int itemIndex = GetReadonlyStaticFieldValue->GetIndex(key);
-    if (itemIndex < 0)
-    {
-        LogException(EXCEPTIONCODE_MC, "repGetReadonlyStaticFieldValue: didn't find buffer for {fld-%016llX, %d}", field, bufferSize);
-        return false;
-    }
-    else
+    AssertMapExistsNoMessage(GetReadonlyStaticFieldValue, key);
+
+    DD value = GetReadonlyStaticFieldValue->Get(key);
+    DEBUG_REP(dmpGetReadonlyStaticFieldValue(key, value));
+    if (buffer != nullptr && (bool)value.A)
     {
-        DD value = GetReadonlyStaticFieldValue->Get(key);
-        DEBUG_REP(dmpGetReadonlyStaticFieldValue(key, value));
-        if (buffer != nullptr && (bool)value.A)
-        {
-            uint8_t* srcBuffer = (uint8_t*)GetReadonlyStaticFieldValue->GetBuffer(value.B);
-            Assert(srcBuffer != nullptr);
-            memcpy(buffer, srcBuffer, bufferSize);
-        }
-        return (bool)value.A;
+        uint8_t* srcBuffer = (uint8_t*)GetReadonlyStaticFieldValue->GetBuffer(value.B);
+        Assert(srcBuffer != nullptr);
+        memcpy(buffer, srcBuffer, bufferSize);
     }
+    return (bool)value.A;
 }
 
 void MethodContext::recGetStaticFieldCurrentClass(CORINFO_FIELD_HANDLE field,

From 45cd02b2262f1443db9aef6ae552eef6a4e77689 Mon Sep 17 00:00:00 2001
From: EgorBo <egorbo@gmail.com>
Date: Fri, 7 Oct 2022 16:14:22 +0200
Subject: [PATCH 45/61] Address feedback

---
 src/coreclr/jit/gcinfo.cpp                    | 14 -----
 src/coreclr/jit/importer.cpp                  | 15 +++--
 src/coreclr/jit/lower.cpp                     | 17 ++++++
 .../JitInterface/CorInfoImpl.RyuJit.cs        |  8 ++-
 .../superpmi-shared/methodcontext.cpp         |  2 +-
 src/coreclr/vm/jitinterface.cpp               | 57 ++++---------------
 6 files changed, 45 insertions(+), 68 deletions(-)

diff --git a/src/coreclr/jit/gcinfo.cpp b/src/coreclr/jit/gcinfo.cpp
index 732075b876a505..6ee757a7238bc8 100644
--- a/src/coreclr/jit/gcinfo.cpp
+++ b/src/coreclr/jit/gcinfo.cpp
@@ -255,20 +255,6 @@ GCInfo::WriteBarrierForm GCInfo::gcIsWriteBarrierCandidate(GenTreeStoreInd* stor
     // Write-barriers are no-op for frozen objects (as values)
     if (store->Data()->IsIconHandle(GTF_ICON_OBJ_HDL))
     {
-#ifndef TARGET_XARCH
-        const ssize_t handle = store->Data()->AsIntCon()->IconValue();
-        if (!compiler->info.compCompHnd->isObjectImmutable(reinterpret_cast<void*>(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
-            store->gtFlags |= GTF_IND_VOLATILE;
-        }
-#endif
-
         // Ignore frozen objects
         return WBF_NoBarrier;
     }
diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp
index 7d490c5a88fe23..586d6dc34ae397 100644
--- a/src/coreclr/jit/importer.cpp
+++ b/src/coreclr/jit/importer.cpp
@@ -15291,13 +15291,18 @@ void Compiler::impImportBlockCode(BasicBlock* block)
                         {
                             const int bufferSize         = sizeof(uint64_t);
                             uint8_t   buffer[bufferSize] = {0};
-                            if (info.compCompHnd->getReadonlyStaticFieldValue(resolvedToken.hField, buffer, bufferSize))
+                            if (varTypeIsIntegral(lclTyp) || varTypeIsFloating(lclTyp) || (lclTyp == TYP_REF))
                             {
-                                GenTree* cnsValue = impImportStaticReadOnlyField(buffer, bufferSize, lclTyp);
-                                if (cnsValue != nullptr)
+                                assert(bufferSize >= genTypeSize(lclTyp));
+                                if (info.compCompHnd->getReadonlyStaticFieldValue(resolvedToken.hField, buffer,
+                                                                                  genTypeSize(lclTyp)))
                                 {
-                                    op1 = cnsValue;
-                                    goto FIELD_DONE;
+                                    GenTree* cnsValue = impImportStaticReadOnlyField(buffer, bufferSize, lclTyp);
+                                    if (cnsValue != nullptr)
+                                    {
+                                        op1 = cnsValue;
+                                        goto FIELD_DONE;
+                                    }
                                 }
                             }
                         }
diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp
index 5611761daababc..c9b047438ac568 100644
--- a/src/coreclr/jit/lower.cpp
+++ b/src/coreclr/jit/lower.cpp
@@ -7108,6 +7108,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<void*>(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/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
index 86b0a5d59da4bb..4d82e7b0e35368 100644
--- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
+++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
@@ -2206,6 +2206,10 @@ private int getExactClasses(CORINFO_CLASS_STRUCT_* baseType, int maxExactClasses
 
         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);
             if (field.IsStatic && !field.IsThreadStatic && field.IsInitOnly && field.OwningType is MetadataType owningType)
             {
@@ -2230,7 +2234,9 @@ private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byt
                     {
                         switch (data)
                         {
-                            case byte[] bytes when bufferSize >= bytes.Length:
+                            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<byte>(buffer, bufferSize));
                                 return true;
diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp
index 6d814571511904..8863efa420b4e9 100644
--- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp
+++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp
@@ -3658,7 +3658,7 @@ bool MethodContext::repGetReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, u
     key.A = CastHandle(field);
     key.B = (DWORD)bufferSize;
 
-    AssertMapExistsNoMessage(GetReadonlyStaticFieldValue, key);
+    AssertMapExistsNoMessage(GetReadonlyStaticFieldValue);
 
     DD value = GetReadonlyStaticFieldValue->Get(key);
     DEBUG_REP(dmpGetReadonlyStaticFieldValue(key, value));
diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp
index db8cd5542d4b2b..8ea37d517a04ba 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -11883,25 +11883,12 @@ bool CEEInfo::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE fieldHnd, uint8_t
 
     _ASSERT(fieldHnd != NULL);
     _ASSERT(buffer != NULL);
-    _ASSERT(bufferSize == sizeof(uint64_t));
+    _ASSERT(bufferSize > 0);
 
     bool result = false;
 
     JIT_TO_EE_TRANSITION();
 
-    auto setResult = [&](void* data, int size)
-    {
-        if (size > bufferSize)
-        {
-            result = false;
-        }
-        else
-        {
-            memcpy(buffer, data, size);
-            result = true;
-        }
-    };
-
     FieldDesc* field = (FieldDesc*)fieldHnd;
     if (field->IsStatic() && !field->IsThreadStatic())
     {
@@ -11918,19 +11905,23 @@ bool CEEInfo::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE fieldHnd, uint8_t
             {
                 if (field->IsObjRef())
                 {
+                    _ASSERT(bufferSize >= sizeof(intptr_t));
+
                     OBJECTREF fieldObj = field->GetStaticOBJECTREF();
                     if (fieldObj != NULL)
                     {
                         Object* obj = OBJECTREFToObject(fieldObj);
                         if (GCHeapUtilities::GetGCHeap()->IsInFrozenSegment(obj))
                         {
-                            setResult(&obj, sizeof(intptr_t));
+                            intptr_t ptr = (intptr_t)obj;
+                            memcpy(buffer, &ptr, sizeof(intptr_t));
+                            result = true;
                         }
                     }
                     else
                     {
-                        intptr_t zero = 0;
-                        setResult(&zero, sizeof(intptr_t));
+                        memset(buffer, 0, sizeof(intptr_t));
+                        result = true;
                     }
                 }
                 else
@@ -11938,38 +11929,10 @@ bool CEEInfo::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE fieldHnd, uint8_t
                     void* fldAddr = field->GetStaticAddressHandle(field->IsRVA() ? nullptr : (void*)field->GetBase());
                     if (fldAddr != nullptr)
                     {
+                        _ASSERT((unsigned)bufferSize >= field->GetSize());
                         _ASSERTE(!pEnclosingMT->ContainsGenericVariables());
+                        memcpy(fldAddr, fldAddr, field->GetSize());
                         result = true;
-                        switch (field->GetFieldType())
-                        {
-                            case ELEMENT_TYPE_BOOLEAN:
-                            case ELEMENT_TYPE_I1:
-                            case ELEMENT_TYPE_U1:
-                                setResult(fldAddr, sizeof(uint8_t));
-                                break;
-                            case ELEMENT_TYPE_CHAR:
-                            case ELEMENT_TYPE_I2:
-                            case ELEMENT_TYPE_U2:
-                                setResult(fldAddr, sizeof(uint16_t));
-                                break;
-                            case ELEMENT_TYPE_I4:
-                            case ELEMENT_TYPE_U4:
-                            case ELEMENT_TYPE_R4:
-                                setResult(fldAddr, sizeof(uint32_t));
-                                break;
-                            case ELEMENT_TYPE_I8:
-                            case ELEMENT_TYPE_U8:
-                            case ELEMENT_TYPE_R8:
-                                setResult(fldAddr, sizeof(uint64_t));
-                                break;
-                            case ELEMENT_TYPE_I:
-                            case ELEMENT_TYPE_U:
-                                setResult(fldAddr, sizeof(intptr_t));
-                                break;
-                            default:
-                                result = false;
-                                break;
-                        }
                     }
                 }
             }

From b578780fc3e5f1580d30045de5762351c8e2eaec Mon Sep 17 00:00:00 2001
From: Egor Bogatov <egorbo@gmail.com>
Date: Fri, 7 Oct 2022 16:57:51 +0200
Subject: [PATCH 46/61] Update src/coreclr/vm/jitinterface.cpp

Co-authored-by: Jakob Botsch Nielsen <Jakob.botsch.nielsen@gmail.com>
---
 src/coreclr/vm/jitinterface.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp
index 8ea37d517a04ba..995e88f58ff9dd 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -11890,7 +11890,7 @@ bool CEEInfo::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE fieldHnd, uint8_t
     JIT_TO_EE_TRANSITION();
 
     FieldDesc* field = (FieldDesc*)fieldHnd;
-    if (field->IsStatic() && !field->IsThreadStatic())
+    if (field->IsStatic() && !field->IsThreadStatic() && (bufferSize == field->GetSize()))
     {
         MethodTable* pEnclosingMT = field->GetEnclosingMethodTable();
         if (!pEnclosingMT->IsSharedByGenericInstantiations())

From 84de4d2ce5f7aa5dabd05a2a1a84e967059cc4c3 Mon Sep 17 00:00:00 2001
From: EgorBo <egorbo@gmail.com>
Date: Fri, 7 Oct 2022 17:01:57 +0200
Subject: [PATCH 47/61] Address feedback

---
 src/coreclr/jit/importer.cpp                                 | 4 ++--
 src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp | 2 +-
 src/coreclr/vm/jitinterface.cpp                              | 3 ---
 3 files changed, 3 insertions(+), 6 deletions(-)

diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp
index 586d6dc34ae397..f4e92d2163324d 100644
--- a/src/coreclr/jit/importer.cpp
+++ b/src/coreclr/jit/importer.cpp
@@ -8179,7 +8179,7 @@ GenTree* Compiler::impImportStaticReadOnlyField(uint8_t* buffer, int bufferSize,
         }
         case TYP_REF:
         {
-            ssize_t ptr;
+            void* ptr;
             memcpy(&ptr, buffer, sizeof(ssize_t));
 
             if (ptr == 0)
@@ -8189,7 +8189,7 @@ GenTree* Compiler::impImportStaticReadOnlyField(uint8_t* buffer, int bufferSize,
             else
             {
                 setMethodHasFrozenObjects();
-                tree         = gtNewIconEmbHndNode((void*)ptr, nullptr, GTF_ICON_OBJ_HDL, nullptr);
+                tree         = gtNewIconEmbHndNode(ptr, nullptr, GTF_ICON_OBJ_HDL, nullptr);
                 tree->gtType = TYP_REF;
                 INDEBUG(tree->AsIntCon()->gtTargetHandle = (size_t)ptr);
             }
diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp
index 8863efa420b4e9..5534c4617769d3 100644
--- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp
+++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp
@@ -3658,7 +3658,7 @@ bool MethodContext::repGetReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, u
     key.A = CastHandle(field);
     key.B = (DWORD)bufferSize;
 
-    AssertMapExistsNoMessage(GetReadonlyStaticFieldValue);
+    AssertMapAndKeyExist(GetReadonlyStaticFieldValue, key, ": key %016llX", key.A);
 
     DD value = GetReadonlyStaticFieldValue->Get(key);
     DEBUG_REP(dmpGetReadonlyStaticFieldValue(key, value));
diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp
index 995e88f58ff9dd..c22e195c994ff0 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -11905,8 +11905,6 @@ bool CEEInfo::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE fieldHnd, uint8_t
             {
                 if (field->IsObjRef())
                 {
-                    _ASSERT(bufferSize >= sizeof(intptr_t));
-
                     OBJECTREF fieldObj = field->GetStaticOBJECTREF();
                     if (fieldObj != NULL)
                     {
@@ -11929,7 +11927,6 @@ bool CEEInfo::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE fieldHnd, uint8_t
                     void* fldAddr = field->GetStaticAddressHandle(field->IsRVA() ? nullptr : (void*)field->GetBase());
                     if (fldAddr != nullptr)
                     {
-                        _ASSERT((unsigned)bufferSize >= field->GetSize());
                         _ASSERTE(!pEnclosingMT->ContainsGenericVariables());
                         memcpy(fldAddr, fldAddr, field->GetSize());
                         result = true;

From 05e263972ca5a5f5a32485d537d286b89ce0bd50 Mon Sep 17 00:00:00 2001
From: EgorBo <egorbo@gmail.com>
Date: Fri, 7 Oct 2022 17:07:43 +0200
Subject: [PATCH 48/61] fix compilation

---
 src/coreclr/vm/jitinterface.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp
index c22e195c994ff0..8b04d234be866d 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -11890,7 +11890,7 @@ bool CEEInfo::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE fieldHnd, uint8_t
     JIT_TO_EE_TRANSITION();
 
     FieldDesc* field = (FieldDesc*)fieldHnd;
-    if (field->IsStatic() && !field->IsThreadStatic() && (bufferSize == field->GetSize()))
+    if (field->IsStatic() && !field->IsThreadStatic() && ((unsigned)bufferSize == field->GetSize()))
     {
         MethodTable* pEnclosingMT = field->GetEnclosingMethodTable();
         if (!pEnclosingMT->IsSharedByGenericInstantiations())

From 771fd6adcb63c087263a681873feec09d3ea9b05 Mon Sep 17 00:00:00 2001
From: Egor Bogatov <egorbo@gmail.com>
Date: Fri, 7 Oct 2022 18:25:57 +0200
Subject: [PATCH 49/61] Update src/coreclr/vm/jitinterface.cpp

Co-authored-by: Jan Kotas <jkotas@microsoft.com>
---
 src/coreclr/vm/jitinterface.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp
index 8b04d234be866d..9c1ee178c7ca4b 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -11928,7 +11928,7 @@ bool CEEInfo::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE fieldHnd, uint8_t
                     if (fldAddr != nullptr)
                     {
                         _ASSERTE(!pEnclosingMT->ContainsGenericVariables());
-                        memcpy(fldAddr, fldAddr, field->GetSize());
+                        memcpy(buffer, fldAddr, bufferSize);
                         result = true;
                     }
                 }

From 1acf664ba4261edcb8d5528c2255af87dffb22cd Mon Sep 17 00:00:00 2001
From: Egor Bogatov <egorbo@gmail.com>
Date: Fri, 7 Oct 2022 18:26:15 +0200
Subject: [PATCH 50/61] Update src/coreclr/vm/jitinterface.cpp

Co-authored-by: Jan Kotas <jkotas@microsoft.com>
---
 src/coreclr/vm/jitinterface.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp
index 9c1ee178c7ca4b..268137a4641c69 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -11925,8 +11925,7 @@ bool CEEInfo::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE fieldHnd, uint8_t
                 else
                 {
                     void* fldAddr = field->GetStaticAddressHandle(field->IsRVA() ? nullptr : (void*)field->GetBase());
-                    if (fldAddr != nullptr)
-                    {
+                    _ASSERTE(fldAddr != nullptr);
                         _ASSERTE(!pEnclosingMT->ContainsGenericVariables());
                         memcpy(buffer, fldAddr, bufferSize);
                         result = true;

From 806e985b664ed27e9086cea6ae3d5170c599ee77 Mon Sep 17 00:00:00 2001
From: EgorBo <egorbo@gmail.com>
Date: Fri, 7 Oct 2022 18:31:40 +0200
Subject: [PATCH 51/61] Address feedback

---
 src/coreclr/vm/jitinterface.cpp | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp
index 268137a4641c69..e161c44d3ed018 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -11926,10 +11926,9 @@ bool CEEInfo::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE fieldHnd, uint8_t
                 {
                     void* fldAddr = field->GetStaticAddressHandle(field->IsRVA() ? nullptr : (void*)field->GetBase());
                     _ASSERTE(fldAddr != nullptr);
-                        _ASSERTE(!pEnclosingMT->ContainsGenericVariables());
-                        memcpy(buffer, fldAddr, bufferSize);
-                        result = true;
-                    }
+                    _ASSERTE(!pEnclosingMT->ContainsGenericVariables());
+                    memcpy(buffer, fldAddr, bufferSize);
+                    result = true;
                 }
             }
         }

From 2a0fc8840acee10cedde12b5f55735198a49932b Mon Sep 17 00:00:00 2001
From: EgorBo <egorbo@gmail.com>
Date: Fri, 7 Oct 2022 18:39:19 +0200
Subject: [PATCH 52/61] add assert

---
 src/coreclr/vm/jitinterface.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp
index e161c44d3ed018..9f8f5b641763ab 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -11924,6 +11924,8 @@ bool CEEInfo::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE fieldHnd, uint8_t
                 }
                 else
                 {
+                    // GetStaticAddressHandle doesn't work for structs
+                    _ASSERT(field->GetFieldType() != ELEMENT_TYPE_VALUETYPE);
                     void* fldAddr = field->GetStaticAddressHandle(field->IsRVA() ? nullptr : (void*)field->GetBase());
                     _ASSERTE(fldAddr != nullptr);
                     _ASSERTE(!pEnclosingMT->ContainsGenericVariables());

From fe169c679205338744cd84e8a0f3f24cb17653e9 Mon Sep 17 00:00:00 2001
From: EgorBo <egorbo@gmail.com>
Date: Fri, 7 Oct 2022 18:45:00 +0200
Subject: [PATCH 53/61] limit to primitives and objects on llc side

---
 .../aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs   | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

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 4d82e7b0e35368..c34d2655c17057 100644
--- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
+++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
@@ -2211,7 +2211,8 @@ private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byt
             Debug.Assert(bufferSize > 0);
 
             FieldDesc field = HandleToObject(fieldHandle);
-            if (field.IsStatic && !field.IsThreadStatic && field.IsInitOnly && field.OwningType is MetadataType owningType)
+            if (field.IsStatic && !field.IsThreadStatic && field.IsInitOnly && field.OwningType is MetadataType owningType &&
+                ((field.FieldType.IsPrimitive) || field.FieldType.IsObject))
             {
                 PreinitializationManager preinitManager = _compilation.NodeFactory.PreinitializationManager;
                 if (preinitManager.IsPreinitialized(owningType))

From 30fbd2170fb9d85126e170d874443352f8dc1f94 Mon Sep 17 00:00:00 2001
From: EgorBo <egorbo@gmail.com>
Date: Fri, 7 Oct 2022 18:56:56 +0200
Subject: [PATCH 54/61] fix check

---
 .../JitInterface/CorInfoImpl.RyuJit.cs         | 18 +++++++++++++++---
 1 file changed, 15 insertions(+), 3 deletions(-)

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 c34d2655c17057..23d02734779b32 100644
--- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
+++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
@@ -2211,11 +2211,23 @@ private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byt
             Debug.Assert(bufferSize > 0);
 
             FieldDesc field = HandleToObject(fieldHandle);
-            if (field.IsStatic && !field.IsThreadStatic && field.IsInitOnly && field.OwningType is MetadataType owningType &&
-                ((field.FieldType.IsPrimitive) || field.FieldType.IsObject))
+            if (field.IsStatic && !field.IsThreadStatic && field.IsInitOnly && field.OwningType is MetadataType owningType)
             {
+                bool supportedType = field.FieldType.Category switch
+                {
+                    TypeFlags.Enum or
+                    TypeFlags.Class or
+                    TypeFlags.Interface or
+                    TypeFlags.Array or
+                    TypeFlags.SzArray or
+                    TypeFlags.Pointer or
+                    TypeFlags.FunctionPointer => true,
+
+                    _ => field.FieldType.IsPrimitive
+                };
+
                 PreinitializationManager preinitManager = _compilation.NodeFactory.PreinitializationManager;
-                if (preinitManager.IsPreinitialized(owningType))
+                if (supportedType && preinitManager.IsPreinitialized(owningType))
                 {
                     TypePreinit.ISerializableValue value = preinitManager
                         .GetPreinitializationInfo(owningType).GetFieldValue(field);

From 7c2d8dc02c23124b1e3ebce5281e4589c9a0014c Mon Sep 17 00:00:00 2001
From: Egor Bogatov <egorbo@gmail.com>
Date: Sat, 8 Oct 2022 04:55:36 +0200
Subject: [PATCH 55/61] Apply suggestions from code review

Co-authored-by: Jan Kotas <jkotas@microsoft.com>
---
 src/coreclr/vm/jitinterface.cpp | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp
index 9f8f5b641763ab..d77228bad1350d 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -11890,7 +11890,8 @@ bool CEEInfo::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE fieldHnd, uint8_t
     JIT_TO_EE_TRANSITION();
 
     FieldDesc* field = (FieldDesc*)fieldHnd;
-    if (field->IsStatic() && !field->IsThreadStatic() && ((unsigned)bufferSize == field->GetSize()))
+    _ASSERTE(field->IsStatic() && !field->IsThreadStatic());
+    _ASSERTE((unsigned)bufferSize == field->GetSize());
     {
         MethodTable* pEnclosingMT = field->GetEnclosingMethodTable();
         if (!pEnclosingMT->IsSharedByGenericInstantiations())
@@ -11924,9 +11925,7 @@ bool CEEInfo::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE fieldHnd, uint8_t
                 }
                 else
                 {
-                    // GetStaticAddressHandle doesn't work for structs
-                    _ASSERT(field->GetFieldType() != ELEMENT_TYPE_VALUETYPE);
-                    void* fldAddr = field->GetStaticAddressHandle(field->IsRVA() ? nullptr : (void*)field->GetBase());
+                    void* fldAddr = field->GetCurrentStaticAddress();
                     _ASSERTE(fldAddr != nullptr);
                     _ASSERTE(!pEnclosingMT->ContainsGenericVariables());
                     memcpy(buffer, fldAddr, bufferSize);

From be7c16f68a550e6b29e06a3208b1199a6fc5d10f Mon Sep 17 00:00:00 2001
From: EgorBo <egorbo@gmail.com>
Date: Sat, 8 Oct 2022 04:58:39 +0200
Subject: [PATCH 56/61] Fix indention since "if" was removed

---
 src/coreclr/vm/jitinterface.cpp | 53 ++++++++++++++++-----------------
 1 file changed, 26 insertions(+), 27 deletions(-)

diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp
index d77228bad1350d..951109777d13e4 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -11892,46 +11892,45 @@ bool CEEInfo::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE fieldHnd, uint8_t
     FieldDesc* field = (FieldDesc*)fieldHnd;
     _ASSERTE(field->IsStatic() && !field->IsThreadStatic());
     _ASSERTE((unsigned)bufferSize == field->GetSize());
+
+    MethodTable* pEnclosingMT = field->GetEnclosingMethodTable();
+    if (!pEnclosingMT->IsSharedByGenericInstantiations())
     {
-        MethodTable* pEnclosingMT = field->GetEnclosingMethodTable();
-        if (!pEnclosingMT->IsSharedByGenericInstantiations())
-        {
-            // Allocate space for the local class if necessary, but don't trigger
-            // class construction.
-            DomainLocalModule* pLocalModule = pEnclosingMT->GetDomainLocalModule();
-            pLocalModule->PopulateClass(pEnclosingMT);
+        // Allocate space for the local class if necessary, but don't trigger
+        // class construction.
+        DomainLocalModule* pLocalModule = pEnclosingMT->GetDomainLocalModule();
+        pLocalModule->PopulateClass(pEnclosingMT);
 
-            GCX_COOP();
-            if (pEnclosingMT->IsClassInited() && IsFdInitOnly(field->GetAttributes()))
+        GCX_COOP();
+        if (pEnclosingMT->IsClassInited() && IsFdInitOnly(field->GetAttributes()))
+        {
+            if (field->IsObjRef())
             {
-                if (field->IsObjRef())
+                OBJECTREF fieldObj = field->GetStaticOBJECTREF();
+                if (fieldObj != NULL)
                 {
-                    OBJECTREF fieldObj = field->GetStaticOBJECTREF();
-                    if (fieldObj != NULL)
+                    Object* obj = OBJECTREFToObject(fieldObj);
+                    if (GCHeapUtilities::GetGCHeap()->IsInFrozenSegment(obj))
                     {
-                        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));
+                        intptr_t ptr = (intptr_t)obj;
+                        memcpy(buffer, &ptr, sizeof(intptr_t));
                         result = true;
                     }
                 }
                 else
                 {
-                    void* fldAddr = field->GetCurrentStaticAddress();
-                    _ASSERTE(fldAddr != nullptr);
-                    _ASSERTE(!pEnclosingMT->ContainsGenericVariables());
-                    memcpy(buffer, fldAddr, bufferSize);
+                    memset(buffer, 0, sizeof(intptr_t));
                     result = true;
                 }
             }
+            else
+            {
+                void* fldAddr = field->GetCurrentStaticAddress();
+                _ASSERTE(fldAddr != nullptr);
+                _ASSERTE(!pEnclosingMT->ContainsGenericVariables());
+                memcpy(buffer, fldAddr, bufferSize);
+                result = true;
+            }
         }
     }
 

From 5fbe665e50a9a50782a9801a1028138f378fd2a6 Mon Sep 17 00:00:00 2001
From: Egor Bogatov <egorbo@gmail.com>
Date: Sat, 8 Oct 2022 05:11:20 +0200
Subject: [PATCH 57/61] Apply suggestions from code review

Co-authored-by: Jan Kotas <jkotas@microsoft.com>
---
 .../aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs  | 4 ++--
 src/coreclr/vm/jitinterface.cpp                               | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

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 23d02734779b32..f7b4d3fd9c9368 100644
--- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
+++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
@@ -2248,14 +2248,14 @@ TypeFlags.Pointer or
                         switch (data)
                         {
                             case byte[] bytes:
-                                Debug.Assert(bufferSize >= bytes.Length);
+                                Debug.Assert(bufferSize == bytes.Length);
 
                                 // Ensure we have enough room in the buffer, it can be a large struct
                                 bytes.AsSpan().CopyTo(new Span<byte>(buffer, bufferSize));
                                 return true;
 
                             case FrozenObjectNode or FrozenStringNode:
-                                Debug.Assert(bufferSize >= targetPtrSize);
+                                Debug.Assert(bufferSize == targetPtrSize);
 
                                 // save handle's value to buffer
                                 nint handle = ObjectToHandle(data);
diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp
index 951109777d13e4..a40f87537da14d 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -11894,7 +11894,8 @@ bool CEEInfo::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE fieldHnd, uint8_t
     _ASSERTE((unsigned)bufferSize == field->GetSize());
 
     MethodTable* pEnclosingMT = field->GetEnclosingMethodTable();
-    if (!pEnclosingMT->IsSharedByGenericInstantiations())
+    _ASSERTE(!pEnclosingMT->IsSharedByGenericInstantiations());
+    _ASSERTE(!pEnclosingMT->ContainsGenericVariables());
     {
         // Allocate space for the local class if necessary, but don't trigger
         // class construction.
@@ -11927,7 +11928,6 @@ bool CEEInfo::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE fieldHnd, uint8_t
             {
                 void* fldAddr = field->GetCurrentStaticAddress();
                 _ASSERTE(fldAddr != nullptr);
-                _ASSERTE(!pEnclosingMT->ContainsGenericVariables());
                 memcpy(buffer, fldAddr, bufferSize);
                 result = true;
             }

From 56908b08f97c5cd4fdd1bb2e503b93274d7220e5 Mon Sep 17 00:00:00 2001
From: EgorBo <egorbo@gmail.com>
Date: Sat, 8 Oct 2022 05:16:58 +0200
Subject: [PATCH 58/61] Address feedback, align NativeAOT logic with CoreCLR

---
 .../JitInterface/CorInfoImpl.RyuJit.cs        | 22 +++------
 src/coreclr/vm/jitinterface.cpp               | 47 +++++++++----------
 2 files changed, 29 insertions(+), 40 deletions(-)

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 f7b4d3fd9c9368..34ece05ba5afad 100644
--- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
+++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
@@ -2211,23 +2211,13 @@ private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byt
             Debug.Assert(bufferSize > 0);
 
             FieldDesc field = HandleToObject(fieldHandle);
-            if (field.IsStatic && !field.IsThreadStatic && field.IsInitOnly && field.OwningType is MetadataType owningType)
-            {
-                bool supportedType = field.FieldType.Category switch
-                {
-                    TypeFlags.Enum or
-                    TypeFlags.Class or
-                    TypeFlags.Interface or
-                    TypeFlags.Array or
-                    TypeFlags.SzArray or
-                    TypeFlags.Pointer or
-                    TypeFlags.FunctionPointer => true,
-
-                    _ => field.FieldType.IsPrimitive
-                };
+            Debug.Assert(field.IsStatic && !field.IsThreadStatic);
+            Debug.Assert(field.FieldType.GetElementSize().AsInt == bufferSize);
 
+            if (field.IsInitOnly && field.OwningType is MetadataType owningType)
+            {
                 PreinitializationManager preinitManager = _compilation.NodeFactory.PreinitializationManager;
-                if (supportedType && preinitManager.IsPreinitialized(owningType))
+                if (preinitManager.IsPreinitialized(owningType))
                 {
                     TypePreinit.ISerializableValue value = preinitManager
                         .GetPreinitializationInfo(owningType).GetFieldValue(field);
@@ -2236,7 +2226,7 @@ TypeFlags.Pointer or
 
                     if (value == null)
                     {
-                        Debug.Assert(bufferSize >= targetPtrSize);
+                        Debug.Assert(bufferSize == targetPtrSize);
 
                         // Write "null" to buffer
                         new Span<byte>(buffer, targetPtrSize).Clear();
diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp
index a40f87537da14d..1dd60201f4198c 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -11896,42 +11896,41 @@ bool CEEInfo::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE fieldHnd, uint8_t
     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);
 
-        GCX_COOP();
-        if (pEnclosingMT->IsClassInited() && IsFdInitOnly(field->GetAttributes()))
+    // Allocate space for the local class if necessary, but don't trigger
+    // class construction.
+    DomainLocalModule* pLocalModule = pEnclosingMT->GetDomainLocalModule();
+    pLocalModule->PopulateClass(pEnclosingMT);
+
+    GCX_COOP();
+    if (pEnclosingMT->IsClassInited() && IsFdInitOnly(field->GetAttributes()))
+    {
+        if (field->IsObjRef())
         {
-            if (field->IsObjRef())
+            OBJECTREF fieldObj = field->GetStaticOBJECTREF();
+            if (fieldObj != NULL)
             {
-                OBJECTREF fieldObj = field->GetStaticOBJECTREF();
-                if (fieldObj != NULL)
+                Object* obj = OBJECTREFToObject(fieldObj);
+                if (GCHeapUtilities::GetGCHeap()->IsInFrozenSegment(obj))
                 {
-                    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));
+                    intptr_t ptr = (intptr_t)obj;
+                    memcpy(buffer, &ptr, sizeof(intptr_t));
                     result = true;
                 }
             }
             else
             {
-                void* fldAddr = field->GetCurrentStaticAddress();
-                _ASSERTE(fldAddr != nullptr);
-                memcpy(buffer, fldAddr, bufferSize);
+                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();

From cbe5cd0238087191dc47ad78bc5d5b0e0cd9e7a5 Mon Sep 17 00:00:00 2001
From: Egor Bogatov <egorbo@gmail.com>
Date: Sat, 8 Oct 2022 05:21:10 +0200
Subject: [PATCH 59/61] Update
 src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs

Co-authored-by: Jan Kotas <jkotas@microsoft.com>
---
 .../aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs     | 1 -
 1 file changed, 1 deletion(-)

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 34ece05ba5afad..e287f660705243 100644
--- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
+++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
@@ -2212,7 +2212,6 @@ private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byt
 
             FieldDesc field = HandleToObject(fieldHandle);
             Debug.Assert(field.IsStatic && !field.IsThreadStatic);
-            Debug.Assert(field.FieldType.GetElementSize().AsInt == bufferSize);
 
             if (field.IsInitOnly && field.OwningType is MetadataType owningType)
             {

From 76a72d845c8fd607be2298ad15a25032807d2208 Mon Sep 17 00:00:00 2001
From: Jan Kotas <jkotas@microsoft.com>
Date: Fri, 7 Oct 2022 20:24:54 -0700
Subject: [PATCH 60/61] Update src/coreclr/vm/jitinterface.cpp

---
 src/coreclr/vm/jitinterface.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp
index 1dd60201f4198c..70ffd2cb832d5a 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -11902,9 +11902,9 @@ bool CEEInfo::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE fieldHnd, uint8_t
     DomainLocalModule* pLocalModule = pEnclosingMT->GetDomainLocalModule();
     pLocalModule->PopulateClass(pEnclosingMT);
 
-    GCX_COOP();
     if (pEnclosingMT->IsClassInited() && IsFdInitOnly(field->GetAttributes()))
     {
+        GCX_COOP();
         if (field->IsObjRef())
         {
             OBJECTREF fieldObj = field->GetStaticOBJECTREF();

From aa5be5107517545d53efd6c7190f82c133514bbf Mon Sep 17 00:00:00 2001
From: EgorBo <egorbo@gmail.com>
Date: Sat, 8 Oct 2022 05:36:01 +0200
Subject: [PATCH 61/61] Keep IsThreadStatic on vm side

---
 .../aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs  | 4 ++--
 src/coreclr/vm/jitinterface.cpp                               | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

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 e287f660705243..72ee00ccd76dab 100644
--- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
+++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
@@ -2211,9 +2211,9 @@ private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byt
             Debug.Assert(bufferSize > 0);
 
             FieldDesc field = HandleToObject(fieldHandle);
-            Debug.Assert(field.IsStatic && !field.IsThreadStatic);
+            Debug.Assert(field.IsStatic);
 
-            if (field.IsInitOnly && field.OwningType is MetadataType owningType)
+            if (!field.IsThreadStatic && field.IsInitOnly && field.OwningType is MetadataType owningType)
             {
                 PreinitializationManager preinitManager = _compilation.NodeFactory.PreinitializationManager;
                 if (preinitManager.IsPreinitialized(owningType))
diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp
index 70ffd2cb832d5a..7f9eb048926049 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -11890,7 +11890,7 @@ bool CEEInfo::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE fieldHnd, uint8_t
     JIT_TO_EE_TRANSITION();
 
     FieldDesc* field = (FieldDesc*)fieldHnd;
-    _ASSERTE(field->IsStatic() && !field->IsThreadStatic());
+    _ASSERTE(field->IsStatic());
     _ASSERTE((unsigned)bufferSize == field->GetSize());
 
     MethodTable* pEnclosingMT = field->GetEnclosingMethodTable();
@@ -11902,7 +11902,7 @@ bool CEEInfo::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE fieldHnd, uint8_t
     DomainLocalModule* pLocalModule = pEnclosingMT->GetDomainLocalModule();
     pLocalModule->PopulateClass(pEnclosingMT);
 
-    if (pEnclosingMT->IsClassInited() && IsFdInitOnly(field->GetAttributes()))
+    if (!field->IsThreadStatic() && pEnclosingMT->IsClassInited() && IsFdInitOnly(field->GetAttributes()))
     {
         GCX_COOP();
         if (field->IsObjRef())
