From 9c571e6ae1b4003bdb0be875939f1e8da1bc6055 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Mon, 15 Jan 2024 12:59:43 +0100 Subject: [PATCH 1/8] Implement getStaticFieldCurrentClass for NAOT --- src/coreclr/jit/importer.cpp | 17 ++++++----------- .../tools/Common/JitInterface/CorInfoImpl.cs | 17 +++++++++++++++++ 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 2ba0643887987d..addbe9bda11758 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -3935,18 +3935,17 @@ GenTree* Compiler::impImportStaticFieldAddress(CORINFO_RESOLVED_TOKEN* pResolved default: { - bool isStaticReadOnlyInitedRef = false; + bool isStaticReadOnlyInited = false; #ifdef TARGET_64BIT // TODO-CQ: enable this optimization for 32 bit targets. - if (!isBoxedStatic && (lclTyp == TYP_REF) && ((access & CORINFO_ACCESS_GET) != 0) && - ((*pIndirFlags & GTF_IND_VOLATILE) == 0)) + if (!isBoxedStatic && ((access & CORINFO_ACCESS_GET) != 0) && ((*pIndirFlags & GTF_IND_VOLATILE) == 0)) { bool isSpeculative = true; if ((info.compCompHnd->getStaticFieldCurrentClass(pResolvedToken->hField, &isSpeculative) != NO_CLASS_HANDLE)) { - isStaticReadOnlyInitedRef = !isSpeculative; + isStaticReadOnlyInited = !isSpeculative; } } #endif // TARGET_64BIT @@ -3958,7 +3957,7 @@ GenTree* Compiler::impImportStaticFieldAddress(CORINFO_RESOLVED_TOKEN* pResolved { handleKind = GTF_ICON_STATIC_BOX_PTR; } - else if (isStaticReadOnlyInitedRef) + else if (isStaticReadOnlyInited) { handleKind = GTF_ICON_CONST_PTR; } @@ -3970,13 +3969,9 @@ GenTree* Compiler::impImportStaticFieldAddress(CORINFO_RESOLVED_TOKEN* pResolved op1 = gtNewIconHandleNode(fldAddr, handleKind, innerFldSeq); INDEBUG(op1->AsIntCon()->gtTargetHandle = reinterpret_cast(pResolvedToken->hField)); - if (pFieldInfo->fieldFlags & CORINFO_FLG_FIELD_INITCLASS) + if (isStaticReadOnlyInited) { - indirFlags |= GTF_IND_INITCLASS; - } - if (isStaticReadOnlyInitedRef) - { - indirFlags |= (GTF_IND_INVARIANT | GTF_IND_NONNULL); + indirFlags |= GTF_IND_INVARIANT; } break; } diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 19faf31a208674..8aade910a574b1 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -3532,6 +3532,23 @@ private uint getClassDomainID(CORINFO_CLASS_STRUCT_* cls, ref void* ppIndirectio if (pIsSpeculative != null) *pIsSpeculative = 1; + FieldDesc fieldDesc = HandleToObject(field); + + if (fieldDesc.IsStatic && !fieldDesc.IsThreadStatic && fieldDesc.OwningType is MetadataType owningType && + !fieldDesc.FieldType.IsCanonicalSubtype(CanonicalFormKind.Any)) + { + if (pIsSpeculative != null && _compilation.IsInitOnly(fieldDesc)) + { + // RVA -> initialized + // No cctor -> initialized (to its default value) + // Preinitialized cctor -> initialized + if (fieldDesc.HasRva || !owningType.HasStaticConstructor || _compilation.NodeFactory.PreinitializationManager.IsPreinitialized(owningType)) + { + *pIsSpeculative = 0; + } + } + return ObjectToHandle(owningType); + } return null; } From 1c3a0a90b30603ee4fa76f0e086ca719a268b29c Mon Sep 17 00:00:00 2001 From: EgorBo Date: Mon, 15 Jan 2024 13:18:12 +0100 Subject: [PATCH 2/8] Fix compilation --- .../tools/Common/JitInterface/CorInfoImpl.cs | 26 ------------------- .../JitInterface/CorInfoImpl.ReadyToRun.cs | 7 +++++ .../JitInterface/CorInfoImpl.RyuJit.cs | 25 ++++++++++++++++++ 3 files changed, 32 insertions(+), 26 deletions(-) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 8aade910a574b1..f857d99df509ac 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -3526,32 +3526,6 @@ private CORINFO_CONST_LOOKUP CreateConstLookupToSymbol(ISymbolNode symbol) private uint getClassDomainID(CORINFO_CLASS_STRUCT_* cls, ref void* ppIndirection) { throw new NotImplementedException("getClassDomainID"); } - - private CORINFO_CLASS_STRUCT_* getStaticFieldCurrentClass(CORINFO_FIELD_STRUCT_* field, byte* pIsSpeculative) - { - if (pIsSpeculative != null) - *pIsSpeculative = 1; - - FieldDesc fieldDesc = HandleToObject(field); - - if (fieldDesc.IsStatic && !fieldDesc.IsThreadStatic && fieldDesc.OwningType is MetadataType owningType && - !fieldDesc.FieldType.IsCanonicalSubtype(CanonicalFormKind.Any)) - { - if (pIsSpeculative != null && _compilation.IsInitOnly(fieldDesc)) - { - // RVA -> initialized - // No cctor -> initialized (to its default value) - // Preinitialized cctor -> initialized - if (fieldDesc.HasRva || !owningType.HasStaticConstructor || _compilation.NodeFactory.PreinitializationManager.IsPreinitialized(owningType)) - { - *pIsSpeculative = 0; - } - } - return ObjectToHandle(owningType); - } - return null; - } - private IntPtr getVarArgsHandle(CORINFO_SIG_INFO* pSig, ref void* ppIndirection) { throw new NotImplementedException("getVarArgsHandle"); } private bool canGetVarArgsHandle(CORINFO_SIG_INFO* pSig) diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs index d0b5413f985e0a..d94dd98ad6e340 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs @@ -3366,5 +3366,12 @@ private bool notifyMethodInfoUsage(CORINFO_METHOD_STRUCT_* ftn) // stable e.g. mark calls as no-return if their IL has no rets. return _compilation.NodeFactory.CompilationModuleGroup.VersionsWithMethodBody(method); } + + private CORINFO_CLASS_STRUCT_* getStaticFieldCurrentClass(CORINFO_FIELD_STRUCT_* field, byte* pIsSpeculative) + { + if (pIsSpeculative != null) + *pIsSpeculative = 1; + 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 f4b46156369c94..562e427b135216 100644 --- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs +++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs @@ -2395,5 +2395,30 @@ private bool notifyMethodInfoUsage(CORINFO_METHOD_STRUCT_* ftn) { return true; } + + private CORINFO_CLASS_STRUCT_* getStaticFieldCurrentClass(CORINFO_FIELD_STRUCT_* field, byte* pIsSpeculative) + { + if (pIsSpeculative != null) + *pIsSpeculative = 1; + + FieldDesc fieldDesc = HandleToObject(field); + + if (fieldDesc.IsStatic && !fieldDesc.IsThreadStatic && fieldDesc.OwningType is MetadataType owningType && + !fieldDesc.FieldType.IsCanonicalSubtype(CanonicalFormKind.Any)) + { + if (pIsSpeculative != null && _compilation.IsInitOnly(fieldDesc)) + { + // RVA -> initialized + // No cctor -> initialized (to its default value) + // Preinitialized cctor -> initialized + if (fieldDesc.HasRva || !owningType.HasStaticConstructor || _compilation.NodeFactory.PreinitializationManager.IsPreinitialized(owningType)) + { + *pIsSpeculative = 0; + } + } + return ObjectToHandle(owningType); + } + return null; + } } } From 4b255f55cb90600c54760cffe4c3cf9f37c0eae1 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Mon, 15 Jan 2024 16:49:24 +0100 Subject: [PATCH 3/8] better impl --- src/coreclr/inc/corinfo.h | 15 ++-------- src/coreclr/jit/gentree.cpp | 9 +----- src/coreclr/jit/importer.cpp | 17 ++++++----- .../JitInterface/CorInfoImpl.RyuJit.cs | 28 +++++++++++-------- src/coreclr/vm/jitinterface.cpp | 21 ++++---------- 5 files changed, 35 insertions(+), 55 deletions(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 45b520935b0435..761d64491a78e5 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -3268,20 +3268,11 @@ class ICorDynamicInfo : public ICorStaticInfo int valueOffset ) = 0; - // If pIsSpeculative is NULL, return the class handle for the value of ref-class typed - // static readonly fields, if there is a unique location for the static and the class - // is already initialized. - // - // If pIsSpeculative is not NULL, fetch the class handle for the value of all ref-class - // typed static fields, if there is a unique location for the static and the field is - // not null. - // - // Set *pIsSpeculative true if this type may change over time (field is not readonly or - // is readonly but class has not yet finished initialization). Set *pIsSpeculative false - // if this type will not change. + // Return field's exact type if its value is known to be never changed and is not null. + // E.g. static readonly in an initialized class. Returns nullptr otherwise. virtual CORINFO_CLASS_HANDLE getStaticFieldCurrentClass( CORINFO_FIELD_HANDLE field, - bool *pIsSpeculative = NULL + bool *pIsSpeculative = NULL // unused, to be deleted ) = 0; // registers a vararg sig & returns a VM cookie for it (which can contain other stuff) diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 86caf8654cd9e5..476ad1917e06fe 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -18809,27 +18809,20 @@ CORINFO_CLASS_HANDLE Compiler::gtGetFieldClassHandle(CORINFO_FIELD_HANDLE fieldH #endif // DEBUG // Is this a fully initialized init-only static field? - // - // Note we're not asking for speculative results here, yet. CORINFO_CLASS_HANDLE currentClass = info.compCompHnd->getStaticFieldCurrentClass(fieldHnd); - if (currentClass != NO_CLASS_HANDLE) { // Yes! We know the class exactly and can rely on this to always be true. fieldClass = currentClass; *pIsExact = true; *pIsNonNull = true; -#ifdef DEBUG - char buffer[128]; JITDUMP("Runtime reports field is init-only and initialized and has class %s\n", - eeGetClassName(fieldClass, buffer, sizeof(buffer))); -#endif + eeGetClassName(fieldClass)); } else { JITDUMP("Field's current class not available\n"); } - return fieldClass; } } diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index addbe9bda11758..2c475ec6f45841 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -3936,17 +3936,16 @@ GenTree* Compiler::impImportStaticFieldAddress(CORINFO_RESOLVED_TOKEN* pResolved default: { bool isStaticReadOnlyInited = false; + bool isStaticReadNotNull = false; #ifdef TARGET_64BIT // TODO-CQ: enable this optimization for 32 bit targets. - if (!isBoxedStatic && ((access & CORINFO_ACCESS_GET) != 0) && ((*pIndirFlags & GTF_IND_VOLATILE) == 0)) + if (!isBoxedStatic && ((access & CORINFO_ACCESS_GET) != 0) && ((*pIndirFlags & GTF_IND_VOLATILE) == 0) && + (info.compCompHnd->getStaticFieldCurrentClass(pResolvedToken->hField) != NO_CLASS_HANDLE)) { - bool isSpeculative = true; - if ((info.compCompHnd->getStaticFieldCurrentClass(pResolvedToken->hField, &isSpeculative) != - NO_CLASS_HANDLE)) - { - isStaticReadOnlyInited = !isSpeculative; - } + isStaticReadOnlyInited = true; + isStaticReadNotNull = lclTyp == TYP_REF; + // if it's not TYP_REF then its value could be 0 so don't append GTF_IND_NONNULL flag. } #endif // TARGET_64BIT @@ -3972,6 +3971,10 @@ GenTree* Compiler::impImportStaticFieldAddress(CORINFO_RESOLVED_TOKEN* pResolved if (isStaticReadOnlyInited) { indirFlags |= GTF_IND_INVARIANT; + if (isStaticReadNotNull) + { + indirFlags |= GTF_IND_NONNULL; + } } break; } 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 562e427b135216..c55cece656767f 100644 --- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs +++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs @@ -2398,25 +2398,29 @@ private bool notifyMethodInfoUsage(CORINFO_METHOD_STRUCT_* ftn) private CORINFO_CLASS_STRUCT_* getStaticFieldCurrentClass(CORINFO_FIELD_STRUCT_* field, byte* pIsSpeculative) { - if (pIsSpeculative != null) - *pIsSpeculative = 1; + Debug.Assert(pIsSpeculative == null); // To be deleted FieldDesc fieldDesc = HandleToObject(field); if (fieldDesc.IsStatic && !fieldDesc.IsThreadStatic && fieldDesc.OwningType is MetadataType owningType && - !fieldDesc.FieldType.IsCanonicalSubtype(CanonicalFormKind.Any)) + !owningType.IsCanonicalSubtype(CanonicalFormKind.Any)) { - if (pIsSpeculative != null && _compilation.IsInitOnly(fieldDesc)) + // Generally, this API is only used for reference types to provide better information to the JIT + // for possible devirtualizations. Value types are usually handled separately and folded to constants + // via getStaticFieldContent. However, some artificial RVA fields aren't foldable (e.g. cpuFeatures) + // so let's tell the JIT it can rely on them being invariant too. + if (fieldDesc.HasRva) { - // RVA -> initialized - // No cctor -> initialized (to its default value) - // Preinitialized cctor -> initialized - if (fieldDesc.HasRva || !owningType.HasStaticConstructor || _compilation.NodeFactory.PreinitializationManager.IsPreinitialized(owningType)) - { - *pIsSpeculative = 0; - } + Debug.Assert(fieldDesc.FieldType.IsValueType); + return ObjectToHandle(fieldDesc.FieldType); + } + + PreinitializationManager preinitManager = _compilation.NodeFactory.PreinitializationManager; + if (!fieldDesc.FieldType.IsValueType && preinitManager.IsPreinitialized(owningType) && + preinitManager.GetPreinitializationInfo(owningType).GetFieldValue(fieldDesc) != null) + { + return ObjectToHandle(fieldDesc.FieldType); } - return ObjectToHandle(owningType); } return null; } diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index ca1dd982e1cbb0..366cdaaae1bd83 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -11806,10 +11806,8 @@ CORINFO_CLASS_HANDLE CEEJitInfo::getStaticFieldCurrentClass(CORINFO_FIELD_HANDLE CORINFO_CLASS_HANDLE result = NULL; - if (pIsSpeculative != NULL) - { - *pIsSpeculative = true; - } + // TODO: delete + _ASSERT(pIsSpeculative == NULL); JIT_TO_EE_TRANSITION(); @@ -11853,19 +11851,10 @@ CORINFO_CLASS_HANDLE CEEJitInfo::getStaticFieldCurrentClass(CORINFO_FIELD_HANDLE { // Figure out what to report back. bool isResultImmutable = isClassInitialized && IsFdInitOnly(field->GetAttributes()); - - if (pIsSpeculative != NULL) - { - // Caller is ok with potentially mutable results. - *pIsSpeculative = !isResultImmutable; - } - else + // Caller only wants to see immutable results. + if (!isResultImmutable) { - // Caller only wants to see immutable results. - if (!isResultImmutable) - { - result = NULL; - } + result = NULL; } } From 75ab3e4e8586a94c5ac85dc10094ff8c80b03877 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Mon, 15 Jan 2024 19:06:33 +0100 Subject: [PATCH 4/8] Clean up --- src/coreclr/inc/corinfo.h | 4 +- src/coreclr/jit/gentree.cpp | 45 ++++++------------- src/coreclr/jit/jitconfigvalues.h | 1 - .../JitInterface/CorInfoImpl.RyuJit.cs | 10 +++-- src/coreclr/vm/jitinterface.cpp | 28 ++---------- 5 files changed, 25 insertions(+), 63 deletions(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 761d64491a78e5..2651846c96badf 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -3268,8 +3268,8 @@ class ICorDynamicInfo : public ICorStaticInfo int valueOffset ) = 0; - // Return field's exact type if its value is known to be never changed and is not null. - // E.g. static readonly in an initialized class. Returns nullptr otherwise. + // Return field's exact type if its value is known to be never changed and + // is not null (for reference types). Returns nullptr otherwise. virtual CORINFO_CLASS_HANDLE getStaticFieldCurrentClass( CORINFO_FIELD_HANDLE field, bool *pIsSpeculative = NULL // unused, to be deleted diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 476ad1917e06fe..a0d07a977e31c4 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -18789,42 +18789,25 @@ CORINFO_CLASS_HANDLE Compiler::gtGetArrayElementClassHandle(GenTree* array) CORINFO_CLASS_HANDLE Compiler::gtGetFieldClassHandle(CORINFO_FIELD_HANDLE fieldHnd, bool* pIsExact, bool* pIsNonNull) { - CORINFO_CLASS_HANDLE fieldClass = nullptr; - CorInfoType fieldCorType = info.compCompHnd->getFieldType(fieldHnd, &fieldClass); - - if (fieldCorType == CORINFO_TYPE_CLASS) + CORINFO_CLASS_HANDLE fieldClass = nullptr; + if (info.compCompHnd->getFieldType(fieldHnd, &fieldClass) == CORINFO_TYPE_CLASS) { - // Optionally, look at the actual type of the field's value - bool queryForCurrentClass = true; - INDEBUG(queryForCurrentClass = (JitConfig.JitQueryCurrentStaticFieldClass() > 0);); + JITDUMP("Querying runtime about current class of field %s (declared as %s)\n", eeGetFieldName(fieldHnd, true), + eeGetClassName(fieldClass)); - if (queryForCurrentClass) + // Is this a fully initialized init-only static field? + CORINFO_CLASS_HANDLE currentClass = info.compCompHnd->getStaticFieldCurrentClass(fieldHnd); + if (currentClass != NO_CLASS_HANDLE) { -#if DEBUG - char fieldNameBuffer[128]; - char classNameBuffer[128]; - JITDUMP("Querying runtime about current class of field %s (declared as %s)\n", - eeGetFieldName(fieldHnd, true, fieldNameBuffer, sizeof(fieldNameBuffer)), - eeGetClassName(fieldClass, classNameBuffer, sizeof(classNameBuffer))); -#endif // DEBUG + assert(!eeIsValueClass(currentClass)); - // Is this a fully initialized init-only static field? - CORINFO_CLASS_HANDLE currentClass = info.compCompHnd->getStaticFieldCurrentClass(fieldHnd); - if (currentClass != NO_CLASS_HANDLE) - { - // Yes! We know the class exactly and can rely on this to always be true. - fieldClass = currentClass; - *pIsExact = true; - *pIsNonNull = true; - JITDUMP("Runtime reports field is init-only and initialized and has class %s\n", - eeGetClassName(fieldClass)); - } - else - { - JITDUMP("Field's current class not available\n"); - } - return fieldClass; + *pIsExact = true; + *pIsNonNull = true; + JITDUMP("Runtime reports field is init-only and initialized and has class %s\n", + eeGetClassName(currentClass)); + return currentClass; } + JITDUMP("Field's current class not available\n"); } return NO_CLASS_HANDLE; diff --git a/src/coreclr/jit/jitconfigvalues.h b/src/coreclr/jit/jitconfigvalues.h index 753b7451b875c4..264fa81feb4037 100644 --- a/src/coreclr/jit/jitconfigvalues.h +++ b/src/coreclr/jit/jitconfigvalues.h @@ -132,7 +132,6 @@ CONFIG_INTEGER(JitNoStructPromotion, W("JitNoStructPromotion"), 0) // Disables s // params. CONFIG_INTEGER(JitNoUnroll, W("JitNoUnroll"), 0) CONFIG_INTEGER(JitOrder, W("JitOrder"), 0) -CONFIG_INTEGER(JitQueryCurrentStaticFieldClass, W("JitQueryCurrentStaticFieldClass"), 1) CONFIG_INTEGER(JitReportFastTailCallDecisions, W("JitReportFastTailCallDecisions"), 0) CONFIG_INTEGER(JitPInvokeCheckEnabled, W("JITPInvokeCheckEnabled"), 0) CONFIG_INTEGER(JitPInvokeEnabled, W("JITPInvokeEnabled"), 1) 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 c55cece656767f..12d3e5735fe943 100644 --- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs +++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs @@ -2405,12 +2405,14 @@ private bool notifyMethodInfoUsage(CORINFO_METHOD_STRUCT_* ftn) if (fieldDesc.IsStatic && !fieldDesc.IsThreadStatic && fieldDesc.OwningType is MetadataType owningType && !owningType.IsCanonicalSubtype(CanonicalFormKind.Any)) { - // Generally, this API is only used for reference types to provide better information to the JIT - // for possible devirtualizations. Value types are usually handled separately and folded to constants - // via getStaticFieldContent. However, some artificial RVA fields aren't foldable (e.g. cpuFeatures) - // so let's tell the JIT it can rely on them being invariant too. + // Generally, this API is only used for reference types to provide better information + // to the JIT for possible devirtualizations. Value types are typically handled + // separately and folded to constants via getStaticFieldContent. However, some + // fields aren't foldable (e.g. ExternSymbolMappedField), so let's tell the JIT + // it can rely on them being invariant too. if (fieldDesc.HasRva) { + // Read-only RVA fields need no "is class initialized" check. Debug.Assert(fieldDesc.FieldType.IsValueType); return ObjectToHandle(fieldDesc.FieldType); } diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 366cdaaae1bd83..5e15d180ad4c4b 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -11806,20 +11806,17 @@ CORINFO_CLASS_HANDLE CEEJitInfo::getStaticFieldCurrentClass(CORINFO_FIELD_HANDLE CORINFO_CLASS_HANDLE result = NULL; - // TODO: delete - _ASSERT(pIsSpeculative == NULL); + _ASSERT(pIsSpeculative == nullptr); // to be deleted JIT_TO_EE_TRANSITION(); FieldDesc* field = (FieldDesc*) fieldHnd; - bool isClassInitialized = false; // We're only interested in ref class typed static fields // where the field handle specifies a unique location. if (field->IsStatic() && field->IsObjRef() && !field->IsThreadStatic()) { MethodTable* pEnclosingMT = field->GetEnclosingMethodTable(); - if (!pEnclosingMT->IsSharedByGenericInstantiations()) { // Allocate space for the local class if necessary, but don't trigger @@ -11832,32 +11829,13 @@ CORINFO_CLASS_HANDLE CEEJitInfo::getStaticFieldCurrentClass(CORINFO_FIELD_HANDLE OBJECTREF fieldObj = field->GetStaticOBJECTREF(); VALIDATEOBJECTREF(fieldObj); - // Check for initialization before looking at the value - isClassInitialized = !!pEnclosingMT->IsClassInited(); - - if (fieldObj != NULL) + if (fieldObj != NULL && pEnclosingMT->IsClassInited() && IsFdInitOnly(field->GetAttributes())) { - MethodTable *pObjMT = fieldObj->GetMethodTable(); - - // TODO: Check if the jit is allowed to embed this handle in jitted code. - // Note for the initonly cases it probably won't embed. - result = (CORINFO_CLASS_HANDLE) pObjMT; + result = (CORINFO_CLASS_HANDLE)fieldObj->GetMethodTable(); } } } - // Did we find a class? - if (result != NULL) - { - // Figure out what to report back. - bool isResultImmutable = isClassInitialized && IsFdInitOnly(field->GetAttributes()); - // Caller only wants to see immutable results. - if (!isResultImmutable) - { - result = NULL; - } - } - EE_TO_JIT_TRANSITION(); return result; From efb46d8fac3d900972049dce669cc5761a0b6dd9 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Mon, 15 Jan 2024 19:08:07 +0100 Subject: [PATCH 5/8] clean up --- .../JitInterface/CorInfoImpl.ReadyToRun.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 d94dd98ad6e340..8b4dca7a0c260f 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs @@ -3369,8 +3369,7 @@ private bool notifyMethodInfoUsage(CORINFO_METHOD_STRUCT_* ftn) private CORINFO_CLASS_STRUCT_* getStaticFieldCurrentClass(CORINFO_FIELD_STRUCT_* field, byte* pIsSpeculative) { - if (pIsSpeculative != null) - *pIsSpeculative = 1; + Debug.Assert(pIsSpeculative == null); // to be deleted return null; } } From fe94fa5cd7f04d93c0b3db8a41e3bd975aca81d4 Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Mon, 15 Jan 2024 20:03:50 +0100 Subject: [PATCH 6/8] Update gentree.cpp --- src/coreclr/jit/gentree.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index a0d07a977e31c4..e7f3778e4959f4 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -18799,8 +18799,6 @@ CORINFO_CLASS_HANDLE Compiler::gtGetFieldClassHandle(CORINFO_FIELD_HANDLE fieldH CORINFO_CLASS_HANDLE currentClass = info.compCompHnd->getStaticFieldCurrentClass(fieldHnd); if (currentClass != NO_CLASS_HANDLE) { - assert(!eeIsValueClass(currentClass)); - *pIsExact = true; *pIsNonNull = true; JITDUMP("Runtime reports field is init-only and initialized and has class %s\n", From 87f2383383c5cc89151e0e86acf1604fdc8775f4 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Mon, 15 Jan 2024 23:44:25 +0100 Subject: [PATCH 7/8] Fix unexpected diffs --- src/coreclr/jit/gentree.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index e7f3778e4959f4..fbcff2f9ba0537 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -18799,13 +18799,14 @@ CORINFO_CLASS_HANDLE Compiler::gtGetFieldClassHandle(CORINFO_FIELD_HANDLE fieldH CORINFO_CLASS_HANDLE currentClass = info.compCompHnd->getStaticFieldCurrentClass(fieldHnd); if (currentClass != NO_CLASS_HANDLE) { + fieldClass = currentClass; *pIsExact = true; *pIsNonNull = true; JITDUMP("Runtime reports field is init-only and initialized and has class %s\n", - eeGetClassName(currentClass)); - return currentClass; + eeGetClassName(fieldClass)); } - JITDUMP("Field's current class not available\n"); + JITDUMP("Field's current class is not available\n"); + return fieldClass; } return NO_CLASS_HANDLE; From d3420422c0eb7951d318aef9b9cd675a0b47b363 Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Tue, 16 Jan 2024 14:24:18 +0100 Subject: [PATCH 8/8] Update src/coreclr/jit/gentree.cpp Co-authored-by: Jan Kotas --- src/coreclr/jit/gentree.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index fbcff2f9ba0537..a4dd11e6907291 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -18805,7 +18805,10 @@ CORINFO_CLASS_HANDLE Compiler::gtGetFieldClassHandle(CORINFO_FIELD_HANDLE fieldH JITDUMP("Runtime reports field is init-only and initialized and has class %s\n", eeGetClassName(fieldClass)); } - JITDUMP("Field's current class is not available\n"); + else + { + JITDUMP("Field's current class is not available\n"); + } return fieldClass; }