diff --git a/src/coreclr/inc/CrstTypes.def b/src/coreclr/inc/CrstTypes.def index 7ea873e18a374..2179a45cadf62 100644 --- a/src/coreclr/inc/CrstTypes.def +++ b/src/coreclr/inc/CrstTypes.def @@ -577,7 +577,3 @@ End Crst PgoData AcquiredBefore LoaderHeap End - -Crst StaticBoxInit - AcquiredBefore LoaderHeap FrozenObjectHeap -End diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index e42d8a64f9d71..b4faaf34861d1 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -141,7 +141,7 @@ The first 4 options are mutually exclusive have managed thread local statics, which work through the HELPER. Support for this is considered legacy, and going forward, the EE should - * This is a normal static field. Its address in memory is determined by getFieldInfo. (see + * This is a normal static field. Its address in memory is determined by getFieldAddress. (see also CORINFO_FLG_STATIC_IN_HEAP). @@ -1719,7 +1719,7 @@ struct CORINFO_FIELD_INFO CorInfoIsAccessAllowedResult accessAllowed; CORINFO_HELPER_DESC accessCalloutHelper; - CORINFO_CONST_LOOKUP fieldLookup; + CORINFO_CONST_LOOKUP fieldLookup; // Used by Ready-to-Run }; //---------------------------------------------------------------------------- @@ -3200,6 +3200,13 @@ class ICorDynamicInfo : public ICorStaticInfo void **ppIndirection = NULL ) = 0; + + // return the data's address (for static fields only) + virtual void* getFieldAddress( + CORINFO_FIELD_HANDLE field, + void **ppIndirection = NULL + ) = 0; + //------------------------------------------------------------------------------ // getReadonlyStaticFieldValue: returns true and the actual field's value if the given // field represents a statically initialized readonly field of any type. diff --git a/src/coreclr/inc/crsttypes_generated.h b/src/coreclr/inc/crsttypes_generated.h index 93cd272894ba0..366e60cf9d29f 100644 --- a/src/coreclr/inc/crsttypes_generated.h +++ b/src/coreclr/inc/crsttypes_generated.h @@ -112,29 +112,28 @@ enum CrstType CrstSingleUseLock = 94, CrstSpecialStatics = 95, CrstStackSampler = 96, - CrstStaticBoxInit = 97, - CrstStressLog = 98, - CrstStubCache = 99, - CrstStubDispatchCache = 100, - CrstStubUnwindInfoHeapSegments = 101, - CrstSyncBlockCache = 102, - CrstSyncHashLock = 103, - CrstSystemBaseDomain = 104, - CrstSystemDomain = 105, - CrstSystemDomainDelayedUnloadList = 106, - CrstThreadIdDispenser = 107, - CrstThreadStore = 108, - CrstTieredCompilation = 109, - CrstTypeEquivalenceMap = 110, - CrstTypeIDMap = 111, - CrstUMEntryThunkCache = 112, - CrstUMEntryThunkFreeListLock = 113, - CrstUniqueStack = 114, - CrstUnresolvedClassLock = 115, - CrstUnwindInfoTableLock = 116, - CrstVSDIndirectionCellLock = 117, - CrstWrapperTemplate = 118, - kNumberOfCrstTypes = 119 + CrstStressLog = 97, + CrstStubCache = 98, + CrstStubDispatchCache = 99, + CrstStubUnwindInfoHeapSegments = 100, + CrstSyncBlockCache = 101, + CrstSyncHashLock = 102, + CrstSystemBaseDomain = 103, + CrstSystemDomain = 104, + CrstSystemDomainDelayedUnloadList = 105, + CrstThreadIdDispenser = 106, + CrstThreadStore = 107, + CrstTieredCompilation = 108, + CrstTypeEquivalenceMap = 109, + CrstTypeIDMap = 110, + CrstUMEntryThunkCache = 111, + CrstUMEntryThunkFreeListLock = 112, + CrstUniqueStack = 113, + CrstUnresolvedClassLock = 114, + CrstUnwindInfoTableLock = 115, + CrstVSDIndirectionCellLock = 116, + CrstWrapperTemplate = 117, + kNumberOfCrstTypes = 118 }; #endif // __CRST_TYPES_INCLUDED @@ -242,7 +241,6 @@ int g_rgCrstLevelMap[] = 5, // CrstSingleUseLock 0, // CrstSpecialStatics 0, // CrstStackSampler - -1, // CrstStaticBoxInit -1, // CrstStressLog 5, // CrstStubCache 0, // CrstStubDispatchCache @@ -366,7 +364,6 @@ LPCSTR g_rgCrstNameMap[] = "CrstSingleUseLock", "CrstSpecialStatics", "CrstStackSampler", - "CrstStaticBoxInit", "CrstStressLog", "CrstStubCache", "CrstStubDispatchCache", diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h index 9b1cd429542ff..dc05dced40a16 100644 --- a/src/coreclr/inc/icorjitinfoimpl_generated.h +++ b/src/coreclr/inc/icorjitinfoimpl_generated.h @@ -616,6 +616,10 @@ unsigned getClassDomainID( CORINFO_CLASS_HANDLE cls, void** ppIndirection) override; +void* getFieldAddress( + CORINFO_FIELD_HANDLE field, + void** ppIndirection) override; + bool getReadonlyStaticFieldValue( CORINFO_FIELD_HANDLE field, uint8_t* buffer, diff --git a/src/coreclr/inc/jiteeversionguid.h b/src/coreclr/inc/jiteeversionguid.h index b24885dcbeb37..a9c88b0a7c54d 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 = { /* c0c94f6c-5358-4a3d-be83-b2a9d1b2545e */ - 0xc0c94f6c, - 0x5358, - 0x4a3d, - {0xbe, 0x83, 0xb2, 0xa9, 0xd1, 0xb2, 0x54, 0x5e} +constexpr GUID JITEEVersionIdentifier = { /* e3c98d96-6e67-459a-9750-ebe799cfb788 */ + 0xe3c98d96, + 0x6e67, + 0x459a, + {0x97, 0x50, 0xeb, 0xe7, 0x99, 0xcf, 0xb7, 0x88} }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/coreclr/jit/ICorJitInfo_names_generated.h b/src/coreclr/jit/ICorJitInfo_names_generated.h index 2971c08284981..ed00cc191122b 100644 --- a/src/coreclr/jit/ICorJitInfo_names_generated.h +++ b/src/coreclr/jit/ICorJitInfo_names_generated.h @@ -155,6 +155,7 @@ DEF_CLR_API(getCallInfo) DEF_CLR_API(canAccessFamily) DEF_CLR_API(isRIDClassDomainID) DEF_CLR_API(getClassDomainID) +DEF_CLR_API(getFieldAddress) DEF_CLR_API(getReadonlyStaticFieldValue) DEF_CLR_API(getStaticFieldCurrentClass) DEF_CLR_API(getVarArgsHandle) diff --git a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp index 9b5c73589b6cc..8cedeccd48769 100644 --- a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp +++ b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp @@ -1479,6 +1479,16 @@ unsigned WrapICorJitInfo::getClassDomainID( return temp; } +void* WrapICorJitInfo::getFieldAddress( + CORINFO_FIELD_HANDLE field, + void** ppIndirection) +{ + API_ENTER(getFieldAddress); + void* temp = wrapHnd->getFieldAddress(field, ppIndirection); + API_LEAVE(getFieldAddress); + return temp; +} + bool WrapICorJitInfo::getReadonlyStaticFieldValue( CORINFO_FIELD_HANDLE field, uint8_t* buffer, diff --git a/src/coreclr/jit/assertionprop.cpp b/src/coreclr/jit/assertionprop.cpp index a3797e0f51ac0..9a4be3c6e4e9e 100644 --- a/src/coreclr/jit/assertionprop.cpp +++ b/src/coreclr/jit/assertionprop.cpp @@ -3197,7 +3197,8 @@ GenTree* Compiler::optVNConstantPropOnTree(BasicBlock* block, GenTree* tree) case TYP_SIMD32: { - simd32_t value = vnStore->ConstantValue(vnCns); + simd32_t value = vnStore->ConstantValue(vnCns); + GenTreeVecCon* vecCon = gtNewVconNode(tree->TypeGet()); vecCon->gtSimd32Val = value; diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 154cb199b756f..34a0b475d09ab 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -5733,6 +5733,7 @@ class Compiler GenTree* fgMorphField(GenTree* tree, MorphAddrContext* mac); GenTree* fgMorphExpandInstanceField(GenTree* tree, MorphAddrContext* mac); GenTree* fgMorphExpandTlsFieldAddr(GenTree* tree); + GenTree* fgMorphExpandStaticField(GenTree* tree); bool fgCanFastTailCall(GenTreeCall* call, const char** failReason); #if FEATURE_FASTTAILCALL bool fgCallHasMustCopyByrefParameter(GenTreeCall* callee); diff --git a/src/coreclr/jit/emitarm.cpp b/src/coreclr/jit/emitarm.cpp index 741d2d50dfbac..a546d5aaab940 100644 --- a/src/coreclr/jit/emitarm.cpp +++ b/src/coreclr/jit/emitarm.cpp @@ -4012,7 +4012,10 @@ void emitter::emitIns_R_C(instruction ins, emitAttr attr, regNumber reg, CORINFO } else { - assert(!"Normal statics are expected to be handled in the importer"); + assert(!jitStaticFldIsGlobAddr(fldHnd)); + addr = (ssize_t)emitComp->info.compCompHnd->getFieldAddress(fldHnd, NULL); + if (addr == NULL) + NO_WAY("could not obtain address of static field"); } // We can use reg to load the constant address, diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index 635ef39fcf117..5dacf783fa5df 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -12977,8 +12977,18 @@ BYTE* emitter::emitOutputCV(BYTE* dst, instrDesc* id, code_t code, CnsVal* addc) else { // Special case: mov reg, fs:[ddd] or mov reg, [ddd] - assert(jitStaticFldIsGlobAddr(fldh)); - addr = nullptr; + if (jitStaticFldIsGlobAddr(fldh)) + { + addr = nullptr; + } + else + { + addr = (BYTE*)emitComp->info.compCompHnd->getFieldAddress(fldh, nullptr); + if (addr == nullptr) + { + NO_WAY("could not obtain address of static field"); + } + } } BYTE* target = (addr + offs); diff --git a/src/coreclr/jit/fginline.cpp b/src/coreclr/jit/fginline.cpp index dcd6a8b3bdd12..9922e2cec437c 100644 --- a/src/coreclr/jit/fginline.cpp +++ b/src/coreclr/jit/fginline.cpp @@ -1608,8 +1608,7 @@ Statement* Compiler::fgInlinePrependStatements(InlineInfo* inlineInfo) GenTree* op2 = argNode->AsOp()->gtOp2; if (op1->IsCall() && ((op1->AsCall()->gtCallMoreFlags & GTF_CALL_M_HELPER_SPECIAL_DCE) != 0) && - op2->OperIs(GT_IND) && op2->gtGetOp1()->IsIconHandle() && - ((op2->gtFlags & GTF_EXCEPT) == 0)) + (op2->gtOper == GT_FIELD) && ((op2->gtFlags & GTF_EXCEPT) == 0)) { JITDUMP("\nPerforming special dce on unused arg [%06u]:" " actual arg [%06u] helper call [%06u]\n", diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 506d5fb0f8964..24081df5c38ae 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -18079,16 +18079,6 @@ CORINFO_CLASS_HANDLE Compiler::gtGetClassHandle(GenTree* tree, bool* pIsExact, b } } } - else if (base->IsIconHandle(GTF_ICON_CONST_PTR, GTF_ICON_STATIC_HDL)) - { - // Check if we have IND(ICON_HANDLE) that represents a static field - FieldSeq* fldSeq = base->AsIntCon()->gtFieldSeq; - if ((fldSeq != nullptr) && (fldSeq->GetOffset() == base->AsIntCon()->IconValue())) - { - CORINFO_FIELD_HANDLE fldHandle = base->AsIntCon()->gtFieldSeq->GetFieldHandle(); - objClass = gtGetFieldClassHandle(fldHandle, pIsExact, pIsNonNull); - } - } } break; diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index b349a813286fd..b78096914ebab 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -2209,12 +2209,6 @@ struct GenTree return (gtOper == GT_CNS_INT) && ((gtFlags & GTF_ICON_HDL_MASK) == handleType); } - template - bool IsIconHandle(GenTreeFlags handleType, T... rest) const - { - return IsIconHandle(handleType) || IsIconHandle(rest...); - } - // Return just the part of the flags corresponding to the GTF_ICON_*_HDL flag. // For non-icon handle trees, returns GTF_EMPTY. GenTreeFlags GetIconHandleFlag() const diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 062181d15ea25..19e2c842393b5 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -1615,9 +1615,9 @@ GenTree* Compiler::impNormStructVal(GenTree* structVal, CORINFO_CLASS_HANDLE str // In case of a chained GT_COMMA case, we sink the last // GT_COMMA below the blockNode addr. GenTree* blockNodeAddr = blockNode->AsOp()->gtOp1; - assert(blockNodeAddr->TypeIs(TYP_BYREF, TYP_I_IMPL)); + assert(blockNodeAddr->gtType == TYP_BYREF); GenTree* commaNode = parent; - commaNode->gtType = blockNodeAddr->gtType; + commaNode->gtType = TYP_BYREF; commaNode->AsOp()->gtOp2 = blockNodeAddr; blockNode->AsOp()->gtOp1 = commaNode; if (parent == structVal) @@ -4374,9 +4374,6 @@ GenTree* Compiler::impImportStaticFieldAccess(CORINFO_RESOLVED_TOKEN* pResolvedT FieldSeq::FieldKind fieldKind = isSharedStatic ? FieldSeq::FieldKind::SharedStatic : FieldSeq::FieldKind::SimpleStatic; - bool hasConstAddr = (pFieldInfo->fieldAccessor == CORINFO_FIELD_STATIC_ADDRESS) || - (pFieldInfo->fieldAccessor == CORINFO_FIELD_STATIC_RVA_ADDRESS); - FieldSeq* innerFldSeq; FieldSeq* outerFldSeq; if (isBoxedStatic) @@ -4386,11 +4383,14 @@ GenTree* Compiler::impImportStaticFieldAccess(CORINFO_RESOLVED_TOKEN* pResolvedT } else { + bool hasConstAddr = (pFieldInfo->fieldAccessor == CORINFO_FIELD_STATIC_ADDRESS) || + (pFieldInfo->fieldAccessor == CORINFO_FIELD_STATIC_RVA_ADDRESS); + ssize_t offset; if (hasConstAddr) { - assert(pFieldInfo->fieldLookup.accessType == IAT_VALUE); - offset = reinterpret_cast(pFieldInfo->fieldLookup.addr); + offset = reinterpret_cast(info.compCompHnd->getFieldAddress(pResolvedToken->hField)); + assert(offset != 0); } else { @@ -4401,7 +4401,6 @@ GenTree* Compiler::impImportStaticFieldAccess(CORINFO_RESOLVED_TOKEN* pResolvedT outerFldSeq = nullptr; } - bool isStaticReadOnlyInitedRef = false; GenTree* op1; switch (pFieldInfo->fieldAccessor) { @@ -4494,41 +4493,53 @@ GenTree* Compiler::impImportStaticFieldAccess(CORINFO_RESOLVED_TOKEN* pResolvedT default: { -// TODO-CQ: enable this optimization for 32 bit targets. -#ifdef TARGET_64BIT - if (!isBoxedStatic && (lclTyp == TYP_REF) && ((access & CORINFO_ACCESS_ADDRESS) == 0)) + // Do we need the address of a static field? + // + if (access & CORINFO_ACCESS_ADDRESS) { - bool isSpeculative = true; - if ((info.compCompHnd->getStaticFieldCurrentClass(pResolvedToken->hField, &isSpeculative) != - NO_CLASS_HANDLE)) + void** pFldAddr = nullptr; + void* fldAddr = info.compCompHnd->getFieldAddress(pResolvedToken->hField, (void**)&pFldAddr); + + // We should always be able to access this static's address directly. + assert(pFldAddr == nullptr); + + // Create the address node. + GenTreeFlags handleKind = isBoxedStatic ? GTF_ICON_STATIC_BOX_PTR : GTF_ICON_STATIC_HDL; + op1 = gtNewIconHandleNode((size_t)fldAddr, handleKind, innerFldSeq); + INDEBUG(op1->AsIntCon()->gtTargetHandle = reinterpret_cast(pResolvedToken->hField)); + + if (pFieldInfo->fieldFlags & CORINFO_FLG_FIELD_INITCLASS) { - isStaticReadOnlyInitedRef = !isSpeculative; + op1->gtFlags |= GTF_ICON_INITCLASS; } } -#endif // TARGET_64BIT - - assert(hasConstAddr); - assert(pFieldInfo->fieldLookup.addr != nullptr); - assert(pFieldInfo->fieldLookup.accessType == IAT_VALUE); - size_t fldAddr = reinterpret_cast(pFieldInfo->fieldLookup.addr); - GenTreeFlags handleKind; - if (isBoxedStatic) - { - handleKind = GTF_ICON_STATIC_BOX_PTR; - } - else if (isStaticReadOnlyInitedRef) - { - handleKind = GTF_ICON_CONST_PTR; - } - else - { - handleKind = GTF_ICON_STATIC_HDL; - } - op1 = gtNewIconHandleNode(fldAddr, handleKind, innerFldSeq); - INDEBUG(op1->AsIntCon()->gtTargetHandle = reinterpret_cast(pResolvedToken->hField)); - if (pFieldInfo->fieldFlags & CORINFO_FLG_FIELD_INITCLASS) + else // We need the value of a static field { - op1->gtFlags |= GTF_ICON_INITCLASS; + op1 = gtNewFieldRef(lclTyp, pResolvedToken->hField); + + if (pFieldInfo->fieldFlags & CORINFO_FLG_FIELD_INITCLASS) + { + op1->gtFlags |= GTF_FLD_INITCLASS; + } + + if (isBoxedStatic) + { + op1->ChangeType(TYP_REF); // points at boxed object + op1 = gtNewOperNode(GT_ADD, TYP_BYREF, op1, gtNewIconNode(TARGET_POINTER_SIZE, outerFldSeq)); + + if (varTypeIsStruct(lclTyp)) + { + // Constructor adds GTF_GLOB_REF. Note that this is *not* GTF_EXCEPT. + op1 = gtNewObjNode(pFieldInfo->structType, op1); + } + else + { + op1 = gtNewOperNode(GT_IND, lclTyp, op1); + op1->gtFlags |= (GTF_GLOB_REF | GTF_IND_NONFAULTING); + } + } + + return op1; } break; } @@ -4552,10 +4563,6 @@ GenTree* Compiler::impImportStaticFieldAccess(CORINFO_RESOLVED_TOKEN* pResolvedT op1 = gtNewOperNode(GT_IND, lclTyp, op1); op1->gtFlags |= GTF_GLOB_REF; } - if (isStaticReadOnlyInitedRef) - { - op1->gtFlags |= (GTF_IND_INVARIANT | GTF_IND_NONFAULTING | GTF_IND_NONNULL); - } } return op1; diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index c86087a6778ce..2ea9f1225e341 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -5033,7 +5033,7 @@ GenTree* Compiler::fgMorphField(GenTree* tree, MorphAddrContext* mac) } else { - assert(!"Normal statics are expected to be handled in the importer"); + tree = fgMorphExpandStaticField(tree); } // Pass down the current mac; if non null we are computing an address @@ -5371,6 +5371,102 @@ GenTree* Compiler::fgMorphExpandTlsFieldAddr(GenTree* tree) return tree; } +//------------------------------------------------------------------------ +// fgMorphExpandStaticField: Expand a simple static field load. +// +// Transforms the field into an explicit indirection off of a constant +// address. +// +// Arguments: +// tree - The GT_FIELD tree +// +// Return Value: +// The expanded tree - a GT_IND. +// +GenTree* Compiler::fgMorphExpandStaticField(GenTree* tree) +{ + // Note we do not support "FIELD_ADDR"s for simple statics. + assert(tree->OperIs(GT_FIELD) && tree->AsField()->IsStatic()); + + // If we can we access the static's address directly + // then pFldAddr will be NULL and + // fldAddr will be the actual address of the static field + // + CORINFO_FIELD_HANDLE fieldHandle = tree->AsField()->gtFldHnd; + void** pFldAddr = nullptr; + void* fldAddr = info.compCompHnd->getFieldAddress(fieldHandle, (void**)&pFldAddr); + + // We should always be able to access this static field address directly + // + assert(pFldAddr == nullptr); + + // For boxed statics, this direct address will be for the box. We have already added + // the indirection for the field itself and attached the sequence, in importation. + FieldSeq* fieldSeq = nullptr; + bool isBoxedStatic = gtIsStaticFieldPtrToBoxedStruct(tree->TypeGet(), fieldHandle); + if (!isBoxedStatic) + { + // Only simple statics get importred as GT_FIELDs. + fieldSeq = GetFieldSeqStore()->Create(fieldHandle, reinterpret_cast(fldAddr), + FieldSeq::FieldKind::SimpleStatic); + } + + // TODO-CQ: enable this optimization for 32 bit targets. + bool isStaticReadOnlyInited = false; +#ifdef TARGET_64BIT + if (tree->TypeIs(TYP_REF) && !isBoxedStatic) + { + bool pIsSpeculative = true; + if (info.compCompHnd->getStaticFieldCurrentClass(fieldHandle, &pIsSpeculative) != NO_CLASS_HANDLE) + { + isStaticReadOnlyInited = !pIsSpeculative; + } + } +#endif // TARGET_64BIT + + GenTreeFlags handleKind = GTF_EMPTY; + if (isBoxedStatic) + { + handleKind = GTF_ICON_STATIC_BOX_PTR; + } + else if (isStaticReadOnlyInited) + { + handleKind = GTF_ICON_CONST_PTR; + } + else + { + handleKind = GTF_ICON_STATIC_HDL; + } + GenTreeIntCon* addr = gtNewIconHandleNode((size_t)fldAddr, handleKind, fieldSeq); + INDEBUG(addr->gtTargetHandle = reinterpret_cast(fieldHandle)); + + // Translate GTF_FLD_INITCLASS to GTF_ICON_INITCLASS, if we need to. + if (((tree->gtFlags & GTF_FLD_INITCLASS) != 0) && !isStaticReadOnlyInited) + { + tree->gtFlags &= ~GTF_FLD_INITCLASS; + addr->gtFlags |= GTF_ICON_INITCLASS; + } + + tree->SetOper(GT_IND); + tree->AsOp()->gtOp1 = addr; + + if (isBoxedStatic) + { + // The box for the static cannot be null, and is logically invariant, since it + // represents (a base for) the static's address. + tree->gtFlags |= (GTF_IND_INVARIANT | GTF_IND_NONFAULTING | GTF_IND_NONNULL); + } + else if (isStaticReadOnlyInited) + { + JITDUMP("Marking initialized static read-only field '%s' as invariant.\n", eeGetFieldName(fieldHandle)); + + // Static readonly field is not null at this point (see getStaticFieldCurrentClass impl). + tree->gtFlags |= (GTF_IND_INVARIANT | GTF_IND_NONFAULTING | GTF_IND_NONNULL); + } + + return tree; +} + //------------------------------------------------------------------------------ // fgMorphCallInline: attempt to inline a call // diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index ce51202d1aeed..7b1ce731f2563 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -3346,6 +3346,25 @@ private bool isRIDClassDomainID(CORINFO_CLASS_STRUCT_* cls) private uint getClassDomainID(CORINFO_CLASS_STRUCT_* cls, ref void* ppIndirection) { throw new NotImplementedException("getClassDomainID"); } + private void* getFieldAddress(CORINFO_FIELD_STRUCT_* field, void** ppIndirection) + { + FieldDesc fieldDesc = HandleToObject(field); + Debug.Assert(fieldDesc.HasRva); + ISymbolNode node = _compilation.GetFieldRvaData(fieldDesc); + void *handle = (void *)ObjectToHandle(node); + if (node.RepresentsIndirectionCell) + { + *ppIndirection = handle; + return null; + } + else + { + if (ppIndirection != null) + *ppIndirection = null; + return handle; + } + } + private CORINFO_CLASS_STRUCT_* getStaticFieldCurrentClass(CORINFO_FIELD_STRUCT_* field, byte* pIsSpeculative) { if (pIsSpeculative != null) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs index ddc81d77eb7d0..40218af44e79a 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs @@ -2243,6 +2243,21 @@ private static uint _getClassDomainID(IntPtr thisHandle, IntPtr* ppException, CO } } + [UnmanagedCallersOnly] + private static void* _getFieldAddress(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field, void** ppIndirection) + { + var _this = GetThis(thisHandle); + try + { + return _this.getFieldAddress(field, ppIndirection); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default; + } + } + [UnmanagedCallersOnly] private static byte _getReadonlyStaticFieldValue(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field, byte* buffer, int bufferSize, byte ignoreMovableObjects) { @@ -2685,7 +2700,7 @@ private static uint _getJitFlags(IntPtr thisHandle, IntPtr* ppException, CORJIT_ private static IntPtr GetUnmanagedCallbacks() { - void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 181); + void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 182); callbacks[0] = (delegate* unmanaged)&_isIntrinsic; callbacks[1] = (delegate* unmanaged)&_getMethodAttribs; @@ -2838,36 +2853,37 @@ private static IntPtr GetUnmanagedCallbacks() callbacks[148] = (delegate* unmanaged)&_canAccessFamily; callbacks[149] = (delegate* unmanaged)&_isRIDClassDomainID; callbacks[150] = (delegate* unmanaged)&_getClassDomainID; - callbacks[151] = (delegate* unmanaged)&_getReadonlyStaticFieldValue; - callbacks[152] = (delegate* unmanaged)&_getStaticFieldCurrentClass; - callbacks[153] = (delegate* unmanaged)&_getVarArgsHandle; - callbacks[154] = (delegate* unmanaged)&_canGetVarArgsHandle; - callbacks[155] = (delegate* unmanaged)&_constructStringLiteral; - callbacks[156] = (delegate* unmanaged)&_emptyStringLiteral; - callbacks[157] = (delegate* unmanaged)&_getFieldThreadLocalStoreID; - callbacks[158] = (delegate* unmanaged)&_addActiveDependency; - callbacks[159] = (delegate* unmanaged)&_GetDelegateCtor; - callbacks[160] = (delegate* unmanaged)&_MethodCompileComplete; - callbacks[161] = (delegate* unmanaged)&_getTailCallHelpers; - callbacks[162] = (delegate* unmanaged)&_convertPInvokeCalliToCall; - callbacks[163] = (delegate* unmanaged)&_notifyInstructionSetUsage; - callbacks[164] = (delegate* unmanaged)&_updateEntryPointForTailCall; - callbacks[165] = (delegate* unmanaged)&_allocMem; - callbacks[166] = (delegate* unmanaged)&_reserveUnwindInfo; - callbacks[167] = (delegate* unmanaged)&_allocUnwindInfo; - callbacks[168] = (delegate* unmanaged)&_allocGCInfo; - callbacks[169] = (delegate* unmanaged)&_setEHcount; - callbacks[170] = (delegate* unmanaged)&_setEHinfo; - callbacks[171] = (delegate* unmanaged)&_logMsg; - callbacks[172] = (delegate* unmanaged)&_doAssert; - callbacks[173] = (delegate* unmanaged)&_reportFatalError; - callbacks[174] = (delegate* unmanaged)&_getPgoInstrumentationResults; - callbacks[175] = (delegate* unmanaged)&_allocPgoInstrumentationBySchema; - callbacks[176] = (delegate* unmanaged)&_recordCallSite; - callbacks[177] = (delegate* unmanaged)&_recordRelocation; - callbacks[178] = (delegate* unmanaged)&_getRelocTypeHint; - callbacks[179] = (delegate* unmanaged)&_getExpectedTargetArchitecture; - callbacks[180] = (delegate* unmanaged)&_getJitFlags; + callbacks[151] = (delegate* unmanaged)&_getFieldAddress; + callbacks[152] = (delegate* unmanaged)&_getReadonlyStaticFieldValue; + callbacks[153] = (delegate* unmanaged)&_getStaticFieldCurrentClass; + callbacks[154] = (delegate* unmanaged)&_getVarArgsHandle; + callbacks[155] = (delegate* unmanaged)&_canGetVarArgsHandle; + callbacks[156] = (delegate* unmanaged)&_constructStringLiteral; + callbacks[157] = (delegate* unmanaged)&_emptyStringLiteral; + callbacks[158] = (delegate* unmanaged)&_getFieldThreadLocalStoreID; + callbacks[159] = (delegate* unmanaged)&_addActiveDependency; + callbacks[160] = (delegate* unmanaged)&_GetDelegateCtor; + callbacks[161] = (delegate* unmanaged)&_MethodCompileComplete; + callbacks[162] = (delegate* unmanaged)&_getTailCallHelpers; + callbacks[163] = (delegate* unmanaged)&_convertPInvokeCalliToCall; + callbacks[164] = (delegate* unmanaged)&_notifyInstructionSetUsage; + callbacks[165] = (delegate* unmanaged)&_updateEntryPointForTailCall; + callbacks[166] = (delegate* unmanaged)&_allocMem; + callbacks[167] = (delegate* unmanaged)&_reserveUnwindInfo; + callbacks[168] = (delegate* unmanaged)&_allocUnwindInfo; + callbacks[169] = (delegate* unmanaged)&_allocGCInfo; + callbacks[170] = (delegate* unmanaged)&_setEHcount; + callbacks[171] = (delegate* unmanaged)&_setEHinfo; + callbacks[172] = (delegate* unmanaged)&_logMsg; + callbacks[173] = (delegate* unmanaged)&_doAssert; + callbacks[174] = (delegate* unmanaged)&_reportFatalError; + callbacks[175] = (delegate* unmanaged)&_getPgoInstrumentationResults; + callbacks[176] = (delegate* unmanaged)&_allocPgoInstrumentationBySchema; + callbacks[177] = (delegate* unmanaged)&_recordCallSite; + callbacks[178] = (delegate* unmanaged)&_recordRelocation; + callbacks[179] = (delegate* unmanaged)&_getRelocTypeHint; + callbacks[180] = (delegate* unmanaged)&_getExpectedTargetArchitecture; + callbacks[181] = (delegate* unmanaged)&_getJitFlags; return (IntPtr)callbacks; } diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt index 6b94ca327421a..d33bea88a4c5d 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -307,6 +307,7 @@ FUNCTIONS bool canAccessFamily(CORINFO_METHOD_HANDLE hCaller, CORINFO_CLASS_HANDLE hInstanceType); bool isRIDClassDomainID(CORINFO_CLASS_HANDLE cls); unsigned getClassDomainID (CORINFO_CLASS_HANDLE cls, void **ppIndirection); + void* getFieldAddress(CORINFO_FIELD_HANDLE field, VOIDSTARSTAR ppIndirection); bool getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint8_t *buffer, int bufferSize, bool ignoreMovableObjects); CORINFO_CLASS_HANDLE getStaticFieldCurrentClass(CORINFO_FIELD_HANDLE field, BoolStar pIsSpeculative); CORINFO_VARARGS_HANDLE getVarArgsHandle(CORINFO_SIG_INFO *pSig, void **ppIndirection); 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 773e4df50c234..974590abe9eba 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs @@ -1499,10 +1499,6 @@ private void getFieldInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_MET // TODO: Handle the case when the RVA is in the TLS range fieldAccessor = CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_STATIC_RVA_ADDRESS; - ISymbolNode node = _compilation.GetFieldRvaData(field); - pResult->fieldLookup.addr = (void*)ObjectToHandle(node); - pResult->fieldLookup.accessType = node.RepresentsIndirectionCell ? InfoAccessType.IAT_PVALUE : InfoAccessType.IAT_VALUE; - // We are not going through a helper. The constructor has to be triggered explicitly. if (!IsClassPreInited(field.OwningType)) { 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 76725e2fc1e57..d46416744066f 100644 --- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs +++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs @@ -2063,10 +2063,6 @@ private void getFieldInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_MET // TODO: Handle the case when the RVA is in the TLS range fieldAccessor = CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_STATIC_RVA_ADDRESS; - ISymbolNode node = _compilation.GetFieldRvaData(field); - pResult->fieldLookup.addr = (void*)ObjectToHandle(node); - pResult->fieldLookup.accessType = node.RepresentsIndirectionCell ? InfoAccessType.IAT_PVALUE : InfoAccessType.IAT_VALUE; - // We are not going through a helper. The constructor has to be triggered explicitly. if (_compilation.HasLazyStaticConstructor(field.OwningType)) { diff --git a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h index 2326246a09047..4f2f5944d2d6d 100644 --- a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h +++ b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h @@ -162,6 +162,7 @@ struct JitInterfaceCallbacks bool (* canAccessFamily)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE hCaller, CORINFO_CLASS_HANDLE hInstanceType); bool (* isRIDClassDomainID)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls); unsigned (* getClassDomainID)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls, void** ppIndirection); + void* (* getFieldAddress)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_FIELD_HANDLE field, void** ppIndirection); bool (* getReadonlyStaticFieldValue)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, bool ignoreMovableObjects); 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); @@ -1656,6 +1657,16 @@ class JitInterfaceWrapper : public ICorJitInfo return temp; } + virtual void* getFieldAddress( + CORINFO_FIELD_HANDLE field, + void** ppIndirection) +{ + CorInfoExceptionClass* pException = nullptr; + void* temp = _callbacks->getFieldAddress(_thisHandle, &pException, field, ppIndirection); + if (pException != nullptr) throw pException; + return temp; +} + virtual bool getReadonlyStaticFieldValue( CORINFO_FIELD_HANDLE field, uint8_t* buffer, diff --git a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h index 6c9da5cb6b3d0..b4e16e8770393 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h @@ -198,6 +198,12 @@ struct Agnostic_GetOSRInfo unsigned ilOffset; }; +struct Agnostic_GetFieldAddress +{ + DWORDLONG ppIndirection; + DWORDLONG fieldAddress; +}; + struct Agnostic_GetStaticFieldCurrentClass { DWORDLONG classHandle; diff --git a/src/coreclr/tools/superpmi/superpmi-shared/compileresult.cpp b/src/coreclr/tools/superpmi/superpmi-shared/compileresult.cpp index e0cb6a6020e3a..327435391fc95 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/compileresult.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/compileresult.cpp @@ -926,7 +926,7 @@ void CompileResult::applyRelocs(RelocContext* rc, unsigned char* block1, ULONG b if (index == -1) { // See if the original address is in the replay address map. This happens for - // relocations on static field addresses found via getFieldInfo(). + // relocations on static field addresses found via getFieldAddress(). void* origAddr = repAddressMap((void*)tmp.target); if ((origAddr != (void*)-1) && (origAddr != nullptr)) { diff --git a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h index 66c6b910f4590..588d96884df20 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h @@ -79,6 +79,7 @@ LWM(GetDefaultEqualityComparerClass, DWORDLONG, DWORDLONG) LWM(GetDelegateCtor, Agnostic_GetDelegateCtorIn, Agnostic_GetDelegateCtorOut) LWM(GetEEInfo, DWORD, Agnostic_CORINFO_EE_INFO) LWM(GetEHinfo, DLD, Agnostic_CORINFO_EH_CLAUSE) +LWM(GetFieldAddress, DWORDLONG, Agnostic_GetFieldAddress) LWM(GetReadonlyStaticFieldValue, DLDD, DD) LWM(GetStaticFieldCurrentClass, DWORDLONG, Agnostic_GetStaticFieldCurrentClass) LWM(GetFieldClass, DWORDLONG, DWORDLONG) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index 91b6daf52507c..cb6db7560e21f 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -3628,6 +3628,41 @@ CORINFO_METHOD_HANDLE MethodContext::repEmbedMethodHandle(CORINFO_METHOD_HANDLE return (CORINFO_METHOD_HANDLE)value.B; } +void MethodContext::recGetFieldAddress(CORINFO_FIELD_HANDLE field, void** ppIndirection, void* result, CorInfoType cit) +{ + if (GetFieldAddress == nullptr) + GetFieldAddress = new LightWeightMap(); + + Agnostic_GetFieldAddress value; + if (ppIndirection == nullptr) + value.ppIndirection = 0; + else + value.ppIndirection = CastPointer(*ppIndirection); + value.fieldAddress = CastPointer(result); + + 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", key, value.ppIndirection, value.fieldAddress); +} +void* MethodContext::repGetFieldAddress(CORINFO_FIELD_HANDLE field, void** ppIndirection) +{ + DWORDLONG key = CastHandle(field); + AssertMapAndKeyExist(GetFieldAddress, key, ": key %016llX", key); + + Agnostic_GetFieldAddress value = GetFieldAddress->Get(key); + DEBUG_REP(dmpGetFieldAddress(key, value)); + + if (ppIndirection != nullptr) + { + *ppIndirection = (void*)value.ppIndirection; + } + return (void*)value.fieldAddress; +} + void MethodContext::recGetReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, bool ignoreMovableObjects, bool result) { if (GetReadonlyStaticFieldValue == nullptr) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h index 95272063455d9..184102f757d8c 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h @@ -488,6 +488,10 @@ class MethodContext void dmpEmbedMethodHandle(DWORDLONG key, DLDL value); CORINFO_METHOD_HANDLE repEmbedMethodHandle(CORINFO_METHOD_HANDLE handle, void** ppIndirection); + void recGetFieldAddress(CORINFO_FIELD_HANDLE field, void** ppIndirection, void* result, CorInfoType cit); + void dmpGetFieldAddress(DWORDLONG key, const Agnostic_GetFieldAddress& value); + void* repGetFieldAddress(CORINFO_FIELD_HANDLE field, void** ppIndirection); + void recGetReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, bool ignoreMovableObjects, bool result); void dmpGetReadonlyStaticFieldValue(DLDD key, DD value); bool repGetReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, bool ignoreMovableObjects); @@ -1004,7 +1008,7 @@ enum mcPackets Packet_GetDelegateCtor = 49, Packet_GetEEInfo = 50, Packet_GetEHinfo = 51, - //Packet_GetFieldAddress = 52, + Packet_GetFieldAddress = 52, Packet_GetFieldClass = 53, Packet_GetFieldInClass = 54, Packet_GetFieldInfo = 55, diff --git a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp index 377a302dd8fbb..9e91b15de69fe 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -1755,6 +1755,19 @@ unsigned interceptor_ICJI::getClassDomainID(CORINFO_CLASS_HANDLE cls, void** ppI return temp; } +// return the data's address (for static fields only) +void* interceptor_ICJI::getFieldAddress(CORINFO_FIELD_HANDLE field, void** ppIndirection) +{ + mc->cr->AddCall("getFieldAddress"); + void* temp = original_ICorJitInfo->getFieldAddress(field, ppIndirection); + + // Figure out the element type so we know how much we can load + CORINFO_CLASS_HANDLE cch; + CorInfoType cit = getFieldType(field, &cch, NULL); + mc->recGetFieldAddress(field, ppIndirection, temp, cit); + return temp; +} + bool interceptor_ICJI::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, bool ignoreMovableObjects) { mc->cr->AddCall("getReadonlyStaticFieldValue"); diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp index dd75ac3001dba..2ecdf378351f5 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp @@ -1211,6 +1211,14 @@ unsigned interceptor_ICJI::getClassDomainID( return original_ICorJitInfo->getClassDomainID(cls, ppIndirection); } +void* interceptor_ICJI::getFieldAddress( + CORINFO_FIELD_HANDLE field, + void** ppIndirection) +{ + mcs->AddCall("getFieldAddress"); + return original_ICorJitInfo->getFieldAddress(field, ppIndirection); +} + bool interceptor_ICJI::getReadonlyStaticFieldValue( CORINFO_FIELD_HANDLE field, uint8_t* buffer, diff --git a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp index 31c507acf85cb..1e0593ec3258a 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp @@ -1060,6 +1060,13 @@ unsigned interceptor_ICJI::getClassDomainID( return original_ICorJitInfo->getClassDomainID(cls, ppIndirection); } +void* interceptor_ICJI::getFieldAddress( + CORINFO_FIELD_HANDLE field, + void** ppIndirection) +{ + return original_ICorJitInfo->getFieldAddress(field, ppIndirection); +} + bool interceptor_ICJI::getReadonlyStaticFieldValue( CORINFO_FIELD_HANDLE field, uint8_t* buffer, diff --git a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp index 7fab36946f470..a86f7d2718424 100644 --- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp @@ -1530,6 +1530,13 @@ unsigned MyICJI::getClassDomainID(CORINFO_CLASS_HANDLE cls, void** ppIndirection return jitInstance->mc->repGetClassDomainID(cls, ppIndirection); } +// return the data's address (for static fields only) +void* MyICJI::getFieldAddress(CORINFO_FIELD_HANDLE field, void** ppIndirection) +{ + jitInstance->mc->cr->AddCall("getFieldAddress"); + return jitInstance->mc->repGetFieldAddress(field, ppIndirection); +} + bool MyICJI::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, bool ignoreMovableObjects) { jitInstance->mc->cr->AddCall("getReadonlyStaticFieldValue"); diff --git a/src/coreclr/vm/appdomain.cpp b/src/coreclr/vm/appdomain.cpp index 1397c1673d0ba..74c74041a49d6 100644 --- a/src/coreclr/vm/appdomain.cpp +++ b/src/coreclr/vm/appdomain.cpp @@ -637,7 +637,6 @@ void BaseDomain::Init() m_NativeTypeLoadLock.Init(CrstInteropData, CrstFlags(CRST_REENTRANCY), TRUE); m_crstLoaderAllocatorReferences.Init(CrstLoaderAllocatorReferences); - m_crstStaticBoxInitLock.Init(CrstStaticBoxInit); // Has to switch thread to GC_NOTRIGGER while being held (see code:BaseDomain#AssemblyListLock) m_crstAssemblyList.Init(CrstAssemblyList, CrstFlags( CRST_GC_NOTRIGGER_WHEN_TAKEN | CRST_DEBUGGER_THREAD | CRST_TAKEN_DURING_SHUTDOWN)); diff --git a/src/coreclr/vm/appdomain.hpp b/src/coreclr/vm/appdomain.hpp index 1296adbed0d59..18b4d4fd3f562 100644 --- a/src/coreclr/vm/appdomain.hpp +++ b/src/coreclr/vm/appdomain.hpp @@ -1088,12 +1088,6 @@ class BaseDomain return &m_crstLoaderAllocatorReferences; } - CrstExplicitInit* GetStaticBoxInitLock() - { - LIMITED_METHOD_CONTRACT; - return &m_crstStaticBoxInitLock; - } - static CrstStatic* GetMethodTableExposedClassObjectLock() { LIMITED_METHOD_CONTRACT; @@ -1118,7 +1112,6 @@ class BaseDomain CrstExplicitInit m_DomainLocalBlockCrst; // Used to protect the reference lists in the collectible loader allocators attached to this appdomain CrstExplicitInit m_crstLoaderAllocatorReferences; - CrstExplicitInit m_crstStaticBoxInitLock; //#AssemblyListLock // Used to protect the assembly list. Taken also by GC or debugger thread, therefore we have to avoid diff --git a/src/coreclr/vm/frozenobjectheap.cpp b/src/coreclr/vm/frozenobjectheap.cpp index 8fe40c3cc37b6..a1ed1c8b46dc4 100644 --- a/src/coreclr/vm/frozenobjectheap.cpp +++ b/src/coreclr/vm/frozenobjectheap.cpp @@ -37,10 +37,6 @@ Object* FrozenObjectHeapManager::TryAllocateObject(PTR_MethodTable type, size_t _ASSERT(type != nullptr); _ASSERT(FOH_COMMIT_SIZE >= MIN_OBJECT_SIZE); -#ifdef FEATURE_64BIT_ALIGNMENT - _ASSERT(!type->RequiresAlign8()); -#endif - // NOTE: objectSize is expected be the full size including header _ASSERT(objectSize >= MIN_OBJECT_SIZE); diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index e39d70e9910db..9c8d9cbe59c0b 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -1480,8 +1480,6 @@ void CEEInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken, DWORD fieldFlags = 0; pResult->offset = pField->GetOffset(); - pResult->fieldLookup.addr = nullptr; - if (pField->IsStatic()) { fieldFlags |= CORINFO_FLG_FIELD_STATIC; @@ -1498,17 +1496,16 @@ void CEEInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken, // Provide helper to use if the JIT is not able to emit the TLS access // as intrinsic pResult->helper = CORINFO_HELP_GETSTATICFIELDADDR_TLS; + pResult->offset = module->GetFieldTlsOffset(pResult->offset); } else { fieldAccessor = CORINFO_FIELD_STATIC_RVA_ADDRESS; - pResult->fieldLookup.addr = pField->GetStaticAddressHandle(NULL); - pResult->fieldLookup.accessType = IAT_VALUE; } // We are not going through a helper. The constructor has to be triggered explicitly. - if (!pFieldMT->IsClassInited()) + if (!pFieldMT->IsClassPreInited()) fieldFlags |= CORINFO_FLG_FIELD_INITCLASS; } else @@ -1548,41 +1545,9 @@ void CEEInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken, { fieldAccessor = CORINFO_FIELD_STATIC_ADDRESS; - // Allocate space for the local class if necessary, but don't trigger - // class construction. - DomainLocalModule* pLocalModule = pFieldMT->GetDomainLocalModule(); - pLocalModule->PopulateClass(pFieldMT); - // We are not going through a helper. The constructor has to be triggered explicitly. - if (!pFieldMT->IsClassInited()) + if (!pFieldMT->IsClassPreInited()) fieldFlags |= CORINFO_FLG_FIELD_INITCLASS; - - GCX_COOP(); - - pResult->fieldLookup.addr = pField->GetStaticAddressHandle((void*)pField->GetBase()); - if (fieldFlags & CORINFO_FLG_FIELD_STATIC_IN_HEAP) - { - Object* frozenObj = VolatileLoad((Object**)pResult->fieldLookup.addr); - - if (frozenObj == nullptr) - { - // Boxed static is not yet set, allocate it - pFieldMT->AllocateRegularStaticBox(pField, (BYTE*)pResult->fieldLookup.addr); - frozenObj = VolatileLoad((Object**)pResult->fieldLookup.addr); - } - - _ASSERT(frozenObj != nullptr); - - // ContainsPointers here is unnecessary but it's cheaper than IsInFrozenSegment - // for structs containing gc handles - if (!frozenObj->GetMethodTable()->ContainsPointers() && - GCHeapUtilities::GetGCHeap()->IsInFrozenSegment(frozenObj)) - { - pResult->fieldLookup.addr = frozenObj->GetData(); - fieldFlags &= ~CORINFO_FLG_FIELD_STATIC_IN_HEAP; - } - } - pResult->fieldLookup.accessType = IAT_VALUE; } } @@ -11998,6 +11963,54 @@ InfoAccessType CEEJitInfo::emptyStringLiteral(void ** ppValue) return result; } +/*********************************************************************/ +void* CEEJitInfo::getFieldAddress(CORINFO_FIELD_HANDLE fieldHnd, + void **ppIndirection) +{ + CONTRACTL { + THROWS; + GC_TRIGGERS; + MODE_PREEMPTIVE; + } CONTRACTL_END; + + void *result = NULL; + + if (ppIndirection != NULL) + *ppIndirection = NULL; + + JIT_TO_EE_TRANSITION(); + + FieldDesc* field = (FieldDesc*) fieldHnd; + + MethodTable* pMT = field->GetEnclosingMethodTable(); + + _ASSERTE(!pMT->ContainsGenericVariables()); + + void *base = NULL; + + if (!field->IsRVA()) + { + // @todo: assert that the current method being compiled is unshared + // We must not call here for statics of collectible types. + _ASSERTE(!pMT->Collectible()); + + // Allocate space for the local class if necessary, but don't trigger + // class construction. + DomainLocalModule *pLocalModule = pMT->GetDomainLocalModule(); + pLocalModule->PopulateClass(pMT); + + GCX_COOP(); + + base = (void *) field->GetBase(); + } + + result = field->GetStaticAddressHandle(base); + + EE_TO_JIT_TRANSITION(); + + return result; +} + bool CEEInfo::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE fieldHnd, uint8_t* buffer, int bufferSize, bool ignoreMovableObjects) { CONTRACTL { @@ -14549,6 +14562,33 @@ InfoAccessType CEEInfo::emptyStringLiteral(void ** ppValue) UNREACHABLE(); // only called on derived class. } +void* CEEInfo::getFieldAddress(CORINFO_FIELD_HANDLE fieldHnd, + void **ppIndirection) +{ + CONTRACTL{ + THROWS; + GC_TRIGGERS; + MODE_PREEMPTIVE; + } CONTRACTL_END; + + void *result = NULL; + + if (ppIndirection != NULL) + *ppIndirection = NULL; + + JIT_TO_EE_TRANSITION(); + + FieldDesc* field = (FieldDesc*)fieldHnd; + + _ASSERTE(field->IsRVA()); + + result = field->GetStaticAddressHandle(NULL); + + EE_TO_JIT_TRANSITION(); + + return result; +} + 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 4460c413b76e6..c0fcb0a92fb72 100644 --- a/src/coreclr/vm/jitinterface.h +++ b/src/coreclr/vm/jitinterface.h @@ -944,6 +944,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; CORINFO_CLASS_HANDLE getStaticFieldCurrentClass(CORINFO_FIELD_HANDLE field, bool* pIsSpeculative) override final; void* getMethodSync(CORINFO_METHOD_HANDLE ftnHnd, void **ppIndirection) override final; diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index 121774a513e68..d42d4e3efc145 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -58,7 +58,6 @@ #include "array.h" #include "castcache.h" #include "dynamicinterfacecastable.h" -#include "frozenobjectheap.h" #ifdef FEATURE_INTERPRETER #include "interpreter.h" @@ -3484,6 +3483,7 @@ void MethodTable::AllocateRegularStaticBoxes() PTR_BYTE pStaticBase = GetGCStaticsBasePointer(); GCPROTECT_BEGININTERIOR(pStaticBase); + { FieldDesc *pField = HasGenericsStaticsInfo() ? GetGenericsStaticFieldDescs() : (GetApproxFieldDescListRaw() + GetNumIntroducedInstanceFields()); @@ -3491,70 +3491,33 @@ void MethodTable::AllocateRegularStaticBoxes() while (pField < pFieldEnd) { + _ASSERTE(pField->IsStatic()); + if (!pField->IsSpecialStatic() && pField->IsByValue()) { - AllocateRegularStaticBox(pField, pStaticBase + pField->GetOffset()); + TypeHandle th = pField->GetFieldTypeHandleThrowing(); + MethodTable* pFieldMT = th.GetMethodTable(); + + LOG((LF_CLASSLOADER, LL_INFO10000, "\tInstantiating static of type %s\n", pFieldMT->GetDebugClassName())); + OBJECTREF obj = AllocateStaticBox(pFieldMT, HasFixedAddressVTStatics()); + + SetObjectReference( (OBJECTREF*)(pStaticBase + pField->GetOffset()), obj); } + pField++; } } GCPROTECT_END(); } -void MethodTable::AllocateRegularStaticBox(FieldDesc* pField, BYTE* fieldAddress) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - CONTRACTL_END; - } - _ASSERT(pField->IsStatic() && !pField->IsSpecialStatic() && pField->IsByValue()); - - Object** boxedStaticHandle = reinterpret_cast(fieldAddress); - - if (VolatileLoad(boxedStaticHandle) != nullptr) - { - // Boxed static is already initialized - return; - } - - // Grab field's type handle before we enter lock - TypeHandle th = pField->GetFieldTypeHandleThrowing(); - - // Taking a lock since we might come here from multiple threads/places - CrstHolder crst(GetAppDomain()->GetStaticBoxInitLock()); - - // double-checked locking - if (VolatileLoad(boxedStaticHandle) != nullptr) - { - // Boxed static is already initialized - return; - } - - MethodTable* pFieldMT = th.GetMethodTable(); - LOG((LF_CLASSLOADER, LL_INFO10000, "\tInstantiating static of type %s\n", pFieldMT->GetDebugClassName())); - bool canBeFrozen = !pFieldMT->ContainsPointers() && !Collectible(); -#ifdef FEATURE_64BIT_ALIGNMENT - if (pFieldMT->RequiresAlign8()) - { - // 64bit alignment is not yet supported in FOH for 32bit targets - canBeFrozen = false; - } -#endif - OBJECTREF obj = AllocateStaticBox(pFieldMT, HasFixedAddressVTStatics(), NULL, canBeFrozen); - SetObjectReference((OBJECTREF*)boxedStaticHandle, obj); -} - //========================================================================================== -OBJECTREF MethodTable::AllocateStaticBox(MethodTable* pFieldMT, BOOL fPinned, OBJECTHANDLE* pHandle, bool canBeFrozen) +OBJECTREF MethodTable::AllocateStaticBox(MethodTable* pFieldMT, BOOL fPinned, OBJECTHANDLE* pHandle) { CONTRACTL { THROWS; GC_TRIGGERS; - MODE_COOPERATIVE; + MODE_ANY; CONTRACTL_END; } @@ -3563,21 +3526,7 @@ OBJECTREF MethodTable::AllocateStaticBox(MethodTable* pFieldMT, BOOL fPinned, OB // Activate any dependent modules if necessary pFieldMT->EnsureInstanceActive(); - OBJECTREF obj = NULL; - if (canBeFrozen) - { - // In case if we don't plan to collect this handle we may try to allocate it on FOH - _ASSERT(!pFieldMT->ContainsPointers()); - FrozenObjectHeapManager* foh = SystemDomain::GetFrozenObjectHeapManager(); - obj = ObjectToOBJECTREF(foh->TryAllocateObject(pFieldMT, pFieldMT->GetBaseSize())); - // obj can be null in case if struct is huge (>64kb) - if (obj != NULL) - { - return obj; - } - } - - obj = AllocateObject(pFieldMT); + OBJECTREF obj = AllocateObject(pFieldMT); // Pin the object if necessary if (fPinned) diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index e7e24c8d8ae6a..a378ec69ad5d0 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -831,8 +831,7 @@ class MethodTable // instantiations of the superclass or interfaces e.g. System.Int32 : IComparable void AllocateRegularStaticBoxes(); - void AllocateRegularStaticBox(FieldDesc* pField, BYTE* fieldAddress); - static OBJECTREF AllocateStaticBox(MethodTable* pFieldMT, BOOL fPinned, OBJECTHANDLE* pHandle = 0, bool canBeFrozen = false); + static OBJECTREF AllocateStaticBox(MethodTable* pFieldMT, BOOL fPinned, OBJECTHANDLE* pHandle = 0); void CheckRestore(); diff --git a/src/tests/baseservices/compilerservices/FixedAddressValueType/FixedAddressValueType.cs b/src/tests/baseservices/compilerservices/FixedAddressValueType/FixedAddressValueType.cs index 56667c70cd292..a8a61132b1972 100644 --- a/src/tests/baseservices/compilerservices/FixedAddressValueType/FixedAddressValueType.cs +++ b/src/tests/baseservices/compilerservices/FixedAddressValueType/FixedAddressValueType.cs @@ -1,50 +1,59 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // - using System; using System.Runtime.CompilerServices; -public struct Age +public struct Age { + public int years; + public int months; +} + +public class FreeClass { - public int years; - public int months; + public static Age FreeAge; + + public static unsafe IntPtr AddressOfFreeAge() + { + fixed (Age* pointer = &FreeAge) + { return (IntPtr) pointer; } + } } public class FixedClass { - [FixedAddressValueType] - public static Age FixedAge; - - public static unsafe IntPtr AddressOfFixedAge() - { - fixed (Age* pointer = &FixedAge) - { - return (IntPtr)pointer; - } - } + [FixedAddressValueType] + public static Age FixedAge; + + public static unsafe IntPtr AddressOfFixedAge() + { + fixed (Age* pointer = &FixedAge) + { return (IntPtr) pointer; } + } } public class Example { - public static int Main() - { - for (int i = 0; i < 1000; i++) - { - IntPtr fixedPtr1 = FixedClass.AddressOfFixedAge(); - - // Garbage collection. - GC.Collect(3, GCCollectionMode.Forced, true, true); - GC.WaitForPendingFinalizers(); - - // Get addresses of static Age fields after garbage collection. - IntPtr fixedPtr2 = FixedClass.AddressOfFixedAge(); - - if (fixedPtr1 != fixedPtr2) - { - return -1; - } - } - return 100; - } + public static int Main() + { + // Get addresses of static Age fields. + IntPtr freePtr1 = FreeClass.AddressOfFreeAge(); + + IntPtr fixedPtr1 = FixedClass.AddressOfFixedAge(); + + // Garbage collection. + GC.Collect(3, GCCollectionMode.Forced, true, true); + GC.WaitForPendingFinalizers(); + + // Get addresses of static Age fields after garbage collection. + IntPtr freePtr2 = FreeClass.AddressOfFreeAge(); + IntPtr fixedPtr2 = FixedClass.AddressOfFixedAge(); + + if(freePtr1 != freePtr2 && fixedPtr1 == fixedPtr2) + { + return 100; + } + + return -1; + } }