diff options
39 files changed, 293 insertions, 515 deletions
diff --git a/src/coreclr/inc/CrstTypes.def b/src/coreclr/inc/CrstTypes.def index 2179a45cadf..7ea873e18a3 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 b4faaf34861..e42d8a64f9d 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 - * <NONE> This is a normal static field. Its address in memory is determined by getFieldAddress. (see + * <NONE> 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 @@ public: 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 366e60cf9d2..93cd272894b 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 dc05dced40a..9b1cd429542 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 601ba406d83..b24885dcbeb 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 ed00cc19112..2971c082849 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 8cedeccd487..9b5c73589b6 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 9a4be3c6e4e..a3797e0f51a 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<simd32_t>(vnCns); - + simd32_t value = vnStore->ConstantValue<simd32_t>(vnCns); GenTreeVecCon* vecCon = gtNewVconNode(tree->TypeGet()); vecCon->gtSimd32Val = value; diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 34a0b475d09..154cb199b75 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -5733,7 +5733,6 @@ private: 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 a546d5aaab9..741d2d50dfb 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 5dacf783fa5..635ef39fcf1 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 9922e2cec43..dcd6a8b3bdd 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 24081df5c38..506d5fb0f89 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 b78096914eb..b349a813286 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -2209,6 +2209,12 @@ public: return (gtOper == GT_CNS_INT) && ((gtFlags & GTF_ICON_HDL_MASK) == handleType); } + template <typename... T> + 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 19e2c842393..062181d15ea 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<ssize_t>(info.compCompHnd->getFieldAddress(pResolvedToken->hField)); - assert(offset != 0); + assert(pFieldInfo->fieldLookup.accessType == IAT_VALUE); + offset = reinterpret_cast<ssize_t>(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<size_t>(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<size_t>(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<size_t>(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 2ea9f1225e3..c86087a6778 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<size_t>(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<size_t>(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 7b1ce731f25..ce51202d1ae 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -3346,25 +3346,6 @@ namespace Internal.JitInterface 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 40218af44e7..ddc81d77eb7 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs @@ -2244,21 +2244,6 @@ namespace Internal.JitInterface } [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) { var _this = GetThis(thisHandle); @@ -2700,7 +2685,7 @@ namespace Internal.JitInterface private static IntPtr GetUnmanagedCallbacks() { - void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 182); + void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 181); callbacks[0] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, byte>)&_isIntrinsic; callbacks[1] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint>)&_getMethodAttribs; @@ -2853,37 +2838,36 @@ namespace Internal.JitInterface callbacks[148] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_CLASS_STRUCT_*, byte>)&_canAccessFamily; callbacks[149] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, byte>)&_isRIDClassDomainID; callbacks[150] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, void**, uint>)&_getClassDomainID; - callbacks[151] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, void**, void*>)&_getFieldAddress; - callbacks[152] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, byte*, int, byte, byte>)&_getReadonlyStaticFieldValue; - callbacks[153] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, byte*, CORINFO_CLASS_STRUCT_*>)&_getStaticFieldCurrentClass; - callbacks[154] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, void**, IntPtr>)&_getVarArgsHandle; - callbacks[155] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, byte>)&_canGetVarArgsHandle; - callbacks[156] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_MODULE_STRUCT_*, mdToken, void**, InfoAccessType>)&_constructStringLiteral; - callbacks[157] = (delegate* unmanaged<IntPtr, IntPtr*, void**, InfoAccessType>)&_emptyStringLiteral; - callbacks[158] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, void**, uint>)&_getFieldThreadLocalStoreID; - callbacks[159] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_MODULE_STRUCT_*, CORINFO_MODULE_STRUCT_*, void>)&_addActiveDependency; - callbacks[160] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_CLASS_STRUCT_*, CORINFO_METHOD_STRUCT_*, DelegateCtorArgs*, CORINFO_METHOD_STRUCT_*>)&_GetDelegateCtor; - callbacks[161] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, void>)&_MethodCompileComplete; - callbacks[162] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, CORINFO_SIG_INFO*, CORINFO_GET_TAILCALL_HELPERS_FLAGS, CORINFO_TAILCALL_HELPERS*, byte>)&_getTailCallHelpers; - callbacks[163] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, byte, byte>)&_convertPInvokeCalliToCall; - callbacks[164] = (delegate* unmanaged<IntPtr, IntPtr*, InstructionSet, byte, byte>)&_notifyInstructionSetUsage; - callbacks[165] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CONST_LOOKUP*, void>)&_updateEntryPointForTailCall; - callbacks[166] = (delegate* unmanaged<IntPtr, IntPtr*, AllocMemArgs*, void>)&_allocMem; - callbacks[167] = (delegate* unmanaged<IntPtr, IntPtr*, byte, byte, uint, void>)&_reserveUnwindInfo; - callbacks[168] = (delegate* unmanaged<IntPtr, IntPtr*, byte*, byte*, uint, uint, uint, byte*, CorJitFuncKind, void>)&_allocUnwindInfo; - callbacks[169] = (delegate* unmanaged<IntPtr, IntPtr*, UIntPtr, void*>)&_allocGCInfo; - callbacks[170] = (delegate* unmanaged<IntPtr, IntPtr*, uint, void>)&_setEHcount; - callbacks[171] = (delegate* unmanaged<IntPtr, IntPtr*, uint, CORINFO_EH_CLAUSE*, void>)&_setEHinfo; - callbacks[172] = (delegate* unmanaged<IntPtr, IntPtr*, uint, byte*, IntPtr, byte>)&_logMsg; - callbacks[173] = (delegate* unmanaged<IntPtr, IntPtr*, byte*, int, byte*, int>)&_doAssert; - callbacks[174] = (delegate* unmanaged<IntPtr, IntPtr*, CorJitResult, void>)&_reportFatalError; - callbacks[175] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, PgoInstrumentationSchema**, uint*, byte**, PgoSource*, HRESULT>)&_getPgoInstrumentationResults; - callbacks[176] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, PgoInstrumentationSchema*, uint, byte**, HRESULT>)&_allocPgoInstrumentationBySchema; - callbacks[177] = (delegate* unmanaged<IntPtr, IntPtr*, uint, CORINFO_SIG_INFO*, CORINFO_METHOD_STRUCT_*, void>)&_recordCallSite; - callbacks[178] = (delegate* unmanaged<IntPtr, IntPtr*, void*, void*, void*, ushort, ushort, int, void>)&_recordRelocation; - callbacks[179] = (delegate* unmanaged<IntPtr, IntPtr*, void*, ushort>)&_getRelocTypeHint; - callbacks[180] = (delegate* unmanaged<IntPtr, IntPtr*, uint>)&_getExpectedTargetArchitecture; - callbacks[181] = (delegate* unmanaged<IntPtr, IntPtr*, CORJIT_FLAGS*, uint, uint>)&_getJitFlags; + callbacks[151] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, byte*, int, byte, byte>)&_getReadonlyStaticFieldValue; + callbacks[152] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, byte*, CORINFO_CLASS_STRUCT_*>)&_getStaticFieldCurrentClass; + callbacks[153] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, void**, IntPtr>)&_getVarArgsHandle; + callbacks[154] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, byte>)&_canGetVarArgsHandle; + callbacks[155] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_MODULE_STRUCT_*, mdToken, void**, InfoAccessType>)&_constructStringLiteral; + callbacks[156] = (delegate* unmanaged<IntPtr, IntPtr*, void**, InfoAccessType>)&_emptyStringLiteral; + callbacks[157] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, void**, uint>)&_getFieldThreadLocalStoreID; + callbacks[158] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_MODULE_STRUCT_*, CORINFO_MODULE_STRUCT_*, void>)&_addActiveDependency; + callbacks[159] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_CLASS_STRUCT_*, CORINFO_METHOD_STRUCT_*, DelegateCtorArgs*, CORINFO_METHOD_STRUCT_*>)&_GetDelegateCtor; + callbacks[160] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, void>)&_MethodCompileComplete; + callbacks[161] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, CORINFO_SIG_INFO*, CORINFO_GET_TAILCALL_HELPERS_FLAGS, CORINFO_TAILCALL_HELPERS*, byte>)&_getTailCallHelpers; + callbacks[162] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, byte, byte>)&_convertPInvokeCalliToCall; + callbacks[163] = (delegate* unmanaged<IntPtr, IntPtr*, InstructionSet, byte, byte>)&_notifyInstructionSetUsage; + callbacks[164] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CONST_LOOKUP*, void>)&_updateEntryPointForTailCall; + callbacks[165] = (delegate* unmanaged<IntPtr, IntPtr*, AllocMemArgs*, void>)&_allocMem; + callbacks[166] = (delegate* unmanaged<IntPtr, IntPtr*, byte, byte, uint, void>)&_reserveUnwindInfo; + callbacks[167] = (delegate* unmanaged<IntPtr, IntPtr*, byte*, byte*, uint, uint, uint, byte*, CorJitFuncKind, void>)&_allocUnwindInfo; + callbacks[168] = (delegate* unmanaged<IntPtr, IntPtr*, UIntPtr, void*>)&_allocGCInfo; + callbacks[169] = (delegate* unmanaged<IntPtr, IntPtr*, uint, void>)&_setEHcount; + callbacks[170] = (delegate* unmanaged<IntPtr, IntPtr*, uint, CORINFO_EH_CLAUSE*, void>)&_setEHinfo; + callbacks[171] = (delegate* unmanaged<IntPtr, IntPtr*, uint, byte*, IntPtr, byte>)&_logMsg; + callbacks[172] = (delegate* unmanaged<IntPtr, IntPtr*, byte*, int, byte*, int>)&_doAssert; + callbacks[173] = (delegate* unmanaged<IntPtr, IntPtr*, CorJitResult, void>)&_reportFatalError; + callbacks[174] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, PgoInstrumentationSchema**, uint*, byte**, PgoSource*, HRESULT>)&_getPgoInstrumentationResults; + callbacks[175] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, PgoInstrumentationSchema*, uint, byte**, HRESULT>)&_allocPgoInstrumentationBySchema; + callbacks[176] = (delegate* unmanaged<IntPtr, IntPtr*, uint, CORINFO_SIG_INFO*, CORINFO_METHOD_STRUCT_*, void>)&_recordCallSite; + callbacks[177] = (delegate* unmanaged<IntPtr, IntPtr*, void*, void*, void*, ushort, ushort, int, void>)&_recordRelocation; + callbacks[178] = (delegate* unmanaged<IntPtr, IntPtr*, void*, ushort>)&_getRelocTypeHint; + callbacks[179] = (delegate* unmanaged<IntPtr, IntPtr*, uint>)&_getExpectedTargetArchitecture; + callbacks[180] = (delegate* unmanaged<IntPtr, IntPtr*, CORJIT_FLAGS*, uint, uint>)&_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 d33bea88a4c..6b94ca32742 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 974590abe9e..773e4df50c2 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 @@ namespace Internal.JitInterface // 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 d4641674406..76725e2fc1e 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 @@ namespace Internal.JitInterface // 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 4f2f5944d2d..2326246a090 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 @@ public: 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 b4e16e87703..6c9da5cb6b3 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 327435391fc..e0cb6a6020e 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 588d96884df..66c6b910f45 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 cb6db7560e2..91b6daf5250 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<DWORDLONG, Agnostic_GetFieldAddress>(); - - 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 184102f757d..95272063455 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h @@ -488,10 +488,6 @@ public: 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 9e91b15de69..377a302dd8f 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 2ecdf378351..dd75ac3001d 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 1e0593ec325..31c507acf85 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 a86f7d27184..7fab36946f4 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 74c74041a49..1397c1673d0 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 18b4d4fd3f5..1296adbed0d 100644 --- a/src/coreclr/vm/appdomain.hpp +++ b/src/coreclr/vm/appdomain.hpp @@ -1088,6 +1088,12 @@ public: return &m_crstLoaderAllocatorReferences; } + CrstExplicitInit* GetStaticBoxInitLock() + { + LIMITED_METHOD_CONTRACT; + return &m_crstStaticBoxInitLock; + } + static CrstStatic* GetMethodTableExposedClassObjectLock() { LIMITED_METHOD_CONTRACT; @@ -1112,6 +1118,7 @@ protected: 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 a1ed1c8b46d..8fe40c3cc37 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 9c8d9cbe59c..e39d70e9910 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()) - { - // <REVISIT_TODO>@todo: assert that the current method being compiled is unshared</REVISIT_TODO> - // 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 c0fcb0a92fb..4460c413b76 100644 --- a/src/coreclr/vm/jitinterface.h +++ b/src/coreclr/vm/jitinterface.h @@ -944,7 +944,6 @@ public: 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 d42d4e3efc1..121774a513e 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<Object**>(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 a378ec69ad5..e7e24c8d8ae 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -831,7 +831,8 @@ public: // instantiations of the superclass or interfaces e.g. System.Int32 : IComparable<System.Int32> 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 a8a61132b19..56667c70cd2 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; + } } |