From cabb8b089fd3d84fc46446c2079ddc1981b55fd9 Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Sun, 13 Nov 2022 21:48:33 +0100 Subject: [PATCH] Allocate boxed static structs on Frozen Object Heap and remove getFieldAddress (#77737) Co-authored-by: Jan Kotas --- src/coreclr/inc/CrstTypes.def | 4 + src/coreclr/inc/corinfo.h | 11 +- src/coreclr/inc/crsttypes_generated.h | 47 +++---- src/coreclr/inc/icorjitinfoimpl_generated.h | 4 - src/coreclr/inc/jiteeversionguid.h | 10 +- src/coreclr/jit/ICorJitInfo_names_generated.h | 1 - .../jit/ICorJitInfo_wrapper_generated.hpp | 10 -- src/coreclr/jit/assertionprop.cpp | 3 +- src/coreclr/jit/compiler.h | 1 - src/coreclr/jit/emitarm.cpp | 5 +- src/coreclr/jit/emitxarch.cpp | 14 +-- src/coreclr/jit/fginline.cpp | 3 +- src/coreclr/jit/gentree.cpp | 10 ++ src/coreclr/jit/gentree.h | 6 + src/coreclr/jit/importer.cpp | 91 +++++++------- src/coreclr/jit/morph.cpp | 98 +-------------- .../tools/Common/JitInterface/CorInfoImpl.cs | 19 --- .../JitInterface/CorInfoImpl_generated.cs | 78 +++++------- .../ThunkGenerator/ThunkInput.txt | 1 - .../JitInterface/CorInfoImpl.ReadyToRun.cs | 4 + .../JitInterface/CorInfoImpl.RyuJit.cs | 4 + .../aot/jitinterface/jitinterface_generated.h | 11 -- .../tools/superpmi/superpmi-shared/agnostic.h | 6 - .../superpmi-shared/compileresult.cpp | 2 +- .../tools/superpmi/superpmi-shared/lwmlist.h | 1 - .../superpmi-shared/methodcontext.cpp | 35 ------ .../superpmi/superpmi-shared/methodcontext.h | 6 +- .../superpmi-shim-collector/icorjitinfo.cpp | 13 -- .../icorjitinfo_generated.cpp | 8 -- .../icorjitinfo_generated.cpp | 7 -- .../tools/superpmi/superpmi/icorjitinfo.cpp | 7 -- src/coreclr/vm/appdomain.cpp | 1 + src/coreclr/vm/appdomain.hpp | 7 ++ src/coreclr/vm/frozenobjectheap.cpp | 4 + src/coreclr/vm/jitinterface.cpp | 116 ++++++------------ src/coreclr/vm/jitinterface.h | 1 - src/coreclr/vm/methodtable.cpp | 79 +++++++++--- src/coreclr/vm/methodtable.h | 3 +- .../FixedAddressValueType.cs | 77 +++++------- 39 files changed, 293 insertions(+), 515 deletions(-) diff --git a/src/coreclr/inc/CrstTypes.def b/src/coreclr/inc/CrstTypes.def index 2179a45cadf62..7ea873e18a374 100644 --- a/src/coreclr/inc/CrstTypes.def +++ b/src/coreclr/inc/CrstTypes.def @@ -577,3 +577,7 @@ 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 b4faaf34861d1..e42d8a64f9d71 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 getFieldAddress. (see + * This is a normal static field. Its address in memory is determined by getFieldInfo. (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; // Used by Ready-to-Run + CORINFO_CONST_LOOKUP fieldLookup; }; //---------------------------------------------------------------------------- @@ -3200,13 +3200,6 @@ 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 366e60cf9d29f..93cd272894ba0 100644 --- a/src/coreclr/inc/crsttypes_generated.h +++ b/src/coreclr/inc/crsttypes_generated.h @@ -112,28 +112,29 @@ enum CrstType CrstSingleUseLock = 94, CrstSpecialStatics = 95, CrstStackSampler = 96, - 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 + 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 }; #endif // __CRST_TYPES_INCLUDED @@ -241,6 +242,7 @@ int g_rgCrstLevelMap[] = 5, // CrstSingleUseLock 0, // CrstSpecialStatics 0, // CrstStackSampler + -1, // CrstStaticBoxInit -1, // CrstStressLog 5, // CrstStubCache 0, // CrstStubDispatchCache @@ -364,6 +366,7 @@ 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 dc05dced40a16..9b1cd429542ff 100644 --- a/src/coreclr/inc/icorjitinfoimpl_generated.h +++ b/src/coreclr/inc/icorjitinfoimpl_generated.h @@ -616,10 +616,6 @@ 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 601ba406d8334..b24885dcbeb37 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 = { /* e452af1d-0a1a-44a8-a5b3-ef6074b8ab4a */ - 0xe452af1d, - 0x0a1a, - 0x44a8, - {0xa5, 0xb3, 0xef, 0x60, 0x74, 0xb8, 0xab, 0x4a} +constexpr GUID JITEEVersionIdentifier = { /* c0c94f6c-5358-4a3d-be83-b2a9d1b2545e */ + 0xc0c94f6c, + 0x5358, + 0x4a3d, + {0xbe, 0x83, 0xb2, 0xa9, 0xd1, 0xb2, 0x54, 0x5e} }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/coreclr/jit/ICorJitInfo_names_generated.h b/src/coreclr/jit/ICorJitInfo_names_generated.h index ed00cc191122b..2971c08284981 100644 --- a/src/coreclr/jit/ICorJitInfo_names_generated.h +++ b/src/coreclr/jit/ICorJitInfo_names_generated.h @@ -155,7 +155,6 @@ 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 8cedeccd48769..9b5c73589b6cc 100644 --- a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp +++ b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp @@ -1479,16 +1479,6 @@ 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 9a4be3c6e4e9e..a3797e0f51ac0 100644 --- a/src/coreclr/jit/assertionprop.cpp +++ b/src/coreclr/jit/assertionprop.cpp @@ -3197,8 +3197,7 @@ 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 34a0b475d09ab..154cb199b756f 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -5733,7 +5733,6 @@ 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 a546d5aaab940..741d2d50dfbac 100644 --- a/src/coreclr/jit/emitarm.cpp +++ b/src/coreclr/jit/emitarm.cpp @@ -4012,10 +4012,7 @@ void emitter::emitIns_R_C(instruction ins, emitAttr attr, regNumber reg, CORINFO } else { - assert(!jitStaticFldIsGlobAddr(fldHnd)); - addr = (ssize_t)emitComp->info.compCompHnd->getFieldAddress(fldHnd, NULL); - if (addr == NULL) - NO_WAY("could not obtain address of static field"); + assert(!"Normal statics are expected to be handled in the importer"); } // We can use reg to load the constant address, diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index 5dacf783fa5df..635ef39fcf117 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -12977,18 +12977,8 @@ BYTE* emitter::emitOutputCV(BYTE* dst, instrDesc* id, code_t code, CnsVal* addc) else { // Special case: mov reg, fs:[ddd] or mov reg, [ddd] - 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"); - } - } + assert(jitStaticFldIsGlobAddr(fldh)); + addr = nullptr; } BYTE* target = (addr + offs); diff --git a/src/coreclr/jit/fginline.cpp b/src/coreclr/jit/fginline.cpp index 9922e2cec437c..dcd6a8b3bdd12 100644 --- a/src/coreclr/jit/fginline.cpp +++ b/src/coreclr/jit/fginline.cpp @@ -1608,7 +1608,8 @@ Statement* Compiler::fgInlinePrependStatements(InlineInfo* inlineInfo) GenTree* op2 = argNode->AsOp()->gtOp2; if (op1->IsCall() && ((op1->AsCall()->gtCallMoreFlags & GTF_CALL_M_HELPER_SPECIAL_DCE) != 0) && - (op2->gtOper == GT_FIELD) && ((op2->gtFlags & GTF_EXCEPT) == 0)) + op2->OperIs(GT_IND) && op2->gtGetOp1()->IsIconHandle() && + ((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 24081df5c38ae..506d5fb0f8964 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -18079,6 +18079,16 @@ 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 b78096914ebab..b349a813286fd 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -2209,6 +2209,12 @@ 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 19e2c842393b5..062181d15ea25 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->gtType == TYP_BYREF); + assert(blockNodeAddr->TypeIs(TYP_BYREF, TYP_I_IMPL)); GenTree* commaNode = parent; - commaNode->gtType = TYP_BYREF; + commaNode->gtType = blockNodeAddr->gtType; commaNode->AsOp()->gtOp2 = blockNodeAddr; blockNode->AsOp()->gtOp1 = commaNode; if (parent == structVal) @@ -4374,6 +4374,9 @@ 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) @@ -4383,14 +4386,11 @@ 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) { - offset = reinterpret_cast(info.compCompHnd->getFieldAddress(pResolvedToken->hField)); - assert(offset != 0); + assert(pFieldInfo->fieldLookup.accessType == IAT_VALUE); + offset = reinterpret_cast(pFieldInfo->fieldLookup.addr); } else { @@ -4401,6 +4401,7 @@ GenTree* Compiler::impImportStaticFieldAccess(CORINFO_RESOLVED_TOKEN* pResolvedT outerFldSeq = nullptr; } + bool isStaticReadOnlyInitedRef = false; GenTree* op1; switch (pFieldInfo->fieldAccessor) { @@ -4493,53 +4494,41 @@ GenTree* Compiler::impImportStaticFieldAccess(CORINFO_RESOLVED_TOKEN* pResolvedT default: { - // Do we need the address of a static field? - // - if (access & CORINFO_ACCESS_ADDRESS) +// TODO-CQ: enable this optimization for 32 bit targets. +#ifdef TARGET_64BIT + if (!isBoxedStatic && (lclTyp == TYP_REF) && ((access & CORINFO_ACCESS_ADDRESS) == 0)) { - 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) + bool isSpeculative = true; + if ((info.compCompHnd->getStaticFieldCurrentClass(pResolvedToken->hField, &isSpeculative) != + NO_CLASS_HANDLE)) { - op1->gtFlags |= GTF_ICON_INITCLASS; + isStaticReadOnlyInitedRef = !isSpeculative; } } - else // We need the value of a static field - { - 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); - } - } +#endif // TARGET_64BIT - return op1; + 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) + { + op1->gtFlags |= GTF_ICON_INITCLASS; } break; } @@ -4563,6 +4552,10 @@ 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 2ea9f1225e341..c86087a6778ce 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 { - tree = fgMorphExpandStaticField(tree); + assert(!"Normal statics are expected to be handled in the importer"); } // Pass down the current mac; if non null we are computing an address @@ -5371,102 +5371,6 @@ 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 7b1ce731f2563..ce51202d1aeed 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -3346,25 +3346,6 @@ 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 40218af44e79a..ddc81d77eb7d0 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs @@ -2243,21 +2243,6 @@ 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) { @@ -2700,7 +2685,7 @@ private static uint _getJitFlags(IntPtr thisHandle, IntPtr* ppException, CORJIT_ private static IntPtr GetUnmanagedCallbacks() { - void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 182); + void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 181); callbacks[0] = (delegate* unmanaged)&_isIntrinsic; callbacks[1] = (delegate* unmanaged)&_getMethodAttribs; @@ -2853,37 +2838,36 @@ private static IntPtr GetUnmanagedCallbacks() callbacks[148] = (delegate* unmanaged)&_canAccessFamily; callbacks[149] = (delegate* unmanaged)&_isRIDClassDomainID; callbacks[150] = (delegate* unmanaged)&_getClassDomainID; - 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; + 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; return (IntPtr)callbacks; } diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt index d33bea88a4c5d..6b94ca327421a 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -307,7 +307,6 @@ 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 974590abe9eba..773e4df50c234 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs @@ -1499,6 +1499,10 @@ 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 d46416744066f..76725e2fc1e57 100644 --- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs +++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs @@ -2063,6 +2063,10 @@ 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 4f2f5944d2d6d..2326246a09047 100644 --- a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h +++ b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h @@ -162,7 +162,6 @@ 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); @@ -1657,16 +1656,6 @@ 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 b4e16e8770393..6c9da5cb6b3d0 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h @@ -198,12 +198,6 @@ 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 327435391fc95..e0cb6a6020e3a 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 getFieldAddress(). + // relocations on static field addresses found via getFieldInfo(). 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 588d96884df20..66c6b910f4590 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h @@ -79,7 +79,6 @@ 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 cb6db7560e21f..91b6daf52507c 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -3628,41 +3628,6 @@ 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 184102f757d8c..95272063455d9 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h @@ -488,10 +488,6 @@ 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); @@ -1008,7 +1004,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 9e91b15de69fe..377a302dd8fbb 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -1755,19 +1755,6 @@ 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 2ecdf378351f5..dd75ac3001dba 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp @@ -1211,14 +1211,6 @@ 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 1e0593ec3258a..31c507acf85cb 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp @@ -1060,13 +1060,6 @@ 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 a86f7d2718424..7fab36946f470 100644 --- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp @@ -1530,13 +1530,6 @@ 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 74c74041a49d6..1397c1673d0ba 100644 --- a/src/coreclr/vm/appdomain.cpp +++ b/src/coreclr/vm/appdomain.cpp @@ -637,6 +637,7 @@ 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 18b4d4fd3f562..1296adbed0d59 100644 --- a/src/coreclr/vm/appdomain.hpp +++ b/src/coreclr/vm/appdomain.hpp @@ -1088,6 +1088,12 @@ class BaseDomain return &m_crstLoaderAllocatorReferences; } + CrstExplicitInit* GetStaticBoxInitLock() + { + LIMITED_METHOD_CONTRACT; + return &m_crstStaticBoxInitLock; + } + static CrstStatic* GetMethodTableExposedClassObjectLock() { LIMITED_METHOD_CONTRACT; @@ -1112,6 +1118,7 @@ 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 a1ed1c8b46dc4..8fe40c3cc37b6 100644 --- a/src/coreclr/vm/frozenobjectheap.cpp +++ b/src/coreclr/vm/frozenobjectheap.cpp @@ -37,6 +37,10 @@ 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 9c8d9cbe59c0b..e39d70e9910db 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -1480,6 +1480,8 @@ 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; @@ -1496,16 +1498,17 @@ 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->IsClassPreInited()) + if (!pFieldMT->IsClassInited()) fieldFlags |= CORINFO_FLG_FIELD_INITCLASS; } else @@ -1545,9 +1548,41 @@ 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->IsClassPreInited()) + if (!pFieldMT->IsClassInited()) 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; } } @@ -11963,54 +11998,6 @@ 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 { @@ -14562,33 +14549,6 @@ 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 c0fcb0a92fb72..4460c413b76e6 100644 --- a/src/coreclr/vm/jitinterface.h +++ b/src/coreclr/vm/jitinterface.h @@ -944,7 +944,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; 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 d42d4e3efc145..121774a513e68 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -58,6 +58,7 @@ #include "array.h" #include "castcache.h" #include "dynamicinterfacecastable.h" +#include "frozenobjectheap.h" #ifdef FEATURE_INTERPRETER #include "interpreter.h" @@ -3483,7 +3484,6 @@ void MethodTable::AllocateRegularStaticBoxes() PTR_BYTE pStaticBase = GetGCStaticsBasePointer(); GCPROTECT_BEGININTERIOR(pStaticBase); - { FieldDesc *pField = HasGenericsStaticsInfo() ? GetGenericsStaticFieldDescs() : (GetApproxFieldDescListRaw() + GetNumIntroducedInstanceFields()); @@ -3491,33 +3491,70 @@ void MethodTable::AllocateRegularStaticBoxes() while (pField < pFieldEnd) { - _ASSERTE(pField->IsStatic()); - if (!pField->IsSpecialStatic() && pField->IsByValue()) { - 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); + AllocateRegularStaticBox(pField, pStaticBase + pField->GetOffset()); } - 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) +OBJECTREF MethodTable::AllocateStaticBox(MethodTable* pFieldMT, BOOL fPinned, OBJECTHANDLE* pHandle, bool canBeFrozen) { CONTRACTL { THROWS; GC_TRIGGERS; - MODE_ANY; + MODE_COOPERATIVE; CONTRACTL_END; } @@ -3526,7 +3563,21 @@ OBJECTREF MethodTable::AllocateStaticBox(MethodTable* pFieldMT, BOOL fPinned, OB // Activate any dependent modules if necessary pFieldMT->EnsureInstanceActive(); - OBJECTREF obj = AllocateObject(pFieldMT); + 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); // Pin the object if necessary if (fPinned) diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index a378ec69ad5d0..e7e24c8d8ae6a 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -831,7 +831,8 @@ class MethodTable // instantiations of the superclass or interfaces e.g. System.Int32 : IComparable void AllocateRegularStaticBoxes(); - static OBJECTREF AllocateStaticBox(MethodTable* pFieldMT, BOOL fPinned, OBJECTHANDLE* pHandle = 0); + void AllocateRegularStaticBox(FieldDesc* pField, BYTE* fieldAddress); + static OBJECTREF AllocateStaticBox(MethodTable* pFieldMT, BOOL fPinned, OBJECTHANDLE* pHandle = 0, bool canBeFrozen = false); void CheckRestore(); diff --git a/src/tests/baseservices/compilerservices/FixedAddressValueType/FixedAddressValueType.cs b/src/tests/baseservices/compilerservices/FixedAddressValueType/FixedAddressValueType.cs index a8a61132b1972..56667c70cd292 100644 --- a/src/tests/baseservices/compilerservices/FixedAddressValueType/FixedAddressValueType.cs +++ b/src/tests/baseservices/compilerservices/FixedAddressValueType/FixedAddressValueType.cs @@ -1,59 +1,50 @@ // 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 int years; - public int months; -} - -public class FreeClass +public struct Age { - public static Age FreeAge; - - public static unsafe IntPtr AddressOfFreeAge() - { - fixed (Age* pointer = &FreeAge) - { return (IntPtr) pointer; } - } + public int years; + public int months; } 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() - { - // 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; - } + 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; + } }