diff --git a/Build.proj b/Build.proj index 6dcc3b9542037b..44da6d66f9942c 100644 --- a/Build.proj +++ b/Build.proj @@ -18,7 +18,7 @@ - + diff --git a/Directory.Build.props b/Directory.Build.props index 4ee7e1db360f89..3917b5b3f7b51e 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -200,7 +200,7 @@ - true + true true diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/lwmlist.h b/src/coreclr/ToolBox/superpmi/superpmi-shared/lwmlist.h index 7826a25ae00d48..71f9eca564a34d 100644 --- a/src/coreclr/ToolBox/superpmi/superpmi-shared/lwmlist.h +++ b/src/coreclr/ToolBox/superpmi/superpmi-shared/lwmlist.h @@ -101,6 +101,7 @@ LWM(GetJustMyCodeHandle, DWORDLONG, DLDL) LWM(GetLazyStringLiteralHelper, DWORDLONG, DWORD) LWM(GetLikelyClass, Agnostic_GetLikelyClass, Agnostic_GetLikelyClassResult) LWM(GetLocationOfThisType, DWORDLONG, Agnostic_CORINFO_LOOKUP_KIND) +LWM(IsJitIntrinsic, DWORDLONG, DWORD) LWM(GetMethodAttribs, DWORDLONG, DWORD) LWM(GetClassModule, DWORDLONG, DWORDLONG) LWM(GetModuleAssembly, DWORDLONG, DWORDLONG) diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontext.cpp index 7c7296b803634c..0654207f2817be 100644 --- a/src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontext.cpp @@ -771,6 +771,28 @@ DWORD MethodContext::repGetClassAttribs(CORINFO_CLASS_HANDLE classHandle) return value; } +void MethodContext::recIsJitIntrinsic(CORINFO_METHOD_HANDLE ftn, bool result) +{ + if (IsJitIntrinsic == nullptr) + IsJitIntrinsic = new LightWeightMap(); + + IsJitIntrinsic->Add(CastHandle(ftn), (DWORD)result); + DEBUG_REC(dmpIsJitIntrinsic(CastHandle(ftn), (DWORD)result)); +} +void MethodContext::dmpIsJitIntrinsic(DWORDLONG key, DWORD value) +{ + printf("IsJitIntrinsic key ftn-%016llX, value res-%u", key, value); +} +bool MethodContext::repIsJitIntrinsic(CORINFO_METHOD_HANDLE ftn) +{ + AssertCodeMsg((IsJitIntrinsic != nullptr) && (IsJitIntrinsic->GetIndex(CastHandle(ftn)) != -1), EXCEPTIONCODE_MC, + "Didn't find %016llX", CastHandle(ftn)); + + bool result = (BOOL)IsJitIntrinsic->Get(CastHandle(ftn)); + DEBUG_REP(dmpIsJitIntrinsic(CastHandle(ftn), (DWORD)result)); + return result; +} + void MethodContext::recGetMethodAttribs(CORINFO_METHOD_HANDLE methodHandle, DWORD attribs) { if (GetMethodAttribs == nullptr) diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontext.h index d71f8d35f3b332..69837068f23f2f 100644 --- a/src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontext.h @@ -119,6 +119,10 @@ class MethodContext void dmpGetClassAttribs(DWORDLONG key, DWORD value); DWORD repGetClassAttribs(CORINFO_CLASS_HANDLE classHandle); + void recIsJitIntrinsic(CORINFO_METHOD_HANDLE ftn, bool result); + void dmpIsJitIntrinsic(DWORDLONG key, DWORD value); + bool repIsJitIntrinsic(CORINFO_METHOD_HANDLE ftn); + void recGetMethodAttribs(CORINFO_METHOD_HANDLE methodHandle, DWORD attribs); void dmpGetMethodAttribs(DWORDLONG key, DWORD value); DWORD repGetMethodAttribs(CORINFO_METHOD_HANDLE methodHandle); @@ -898,7 +902,7 @@ class MethodContext }; // ********************* Please keep this up-to-date to ease adding more *************** -// Highest packet number: 191 +// Highest packet number: 192 // ************************************************************************************* enum mcPackets { @@ -1000,6 +1004,7 @@ enum mcPackets Packet_GetJustMyCodeHandle = 68, Packet_GetLikelyClass = 182, // Added 9/27/2020 Packet_GetLocationOfThisType = 69, + Packet_IsJitIntrinsic = 192, Packet_GetMethodAttribs = 70, Packet_GetMethodClass = 71, Packet_GetMethodModule = 181, // Added 11/20/2020 diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/coreclr/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp index 85cca8a129d774..281533e4affec7 100644 --- a/src/coreclr/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -17,6 +17,17 @@ // ICorMethodInfo // /**********************************************************************************/ + +// Quick check whether the method is a jit intrinsic. Returns the same value as getMethodAttribs(ftn) & +// CORINFO_FLG_JIT_INTRINSIC, except faster. +bool interceptor_ICJI::isJitIntrinsic(CORINFO_METHOD_HANDLE ftn) +{ + mc->cr->AddCall("isJitIntrinsic"); + bool temp = original_ICorJitInfo->isJitIntrinsic(ftn); + mc->recIsJitIntrinsic(ftn, temp); + return temp; +} + // return flags (defined above, CORINFO_FLG_PUBLIC ...) uint32_t interceptor_ICJI::getMethodAttribs(CORINFO_METHOD_HANDLE ftn /* IN */) { diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp b/src/coreclr/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp index 674d9f4e1fd102..d5ee05be454813 100644 --- a/src/coreclr/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp +++ b/src/coreclr/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp @@ -12,6 +12,13 @@ #include "spmiutil.h" +bool interceptor_ICJI::isJitIntrinsic( + CORINFO_METHOD_HANDLE ftn) +{ + mcs->AddCall("isJitIntrinsic"); + return original_ICorJitInfo->isJitIntrinsic(ftn); +} + uint32_t interceptor_ICJI::getMethodAttribs( CORINFO_METHOD_HANDLE ftn) { diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp b/src/coreclr/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp index a276453ba69c99..3aed50b5b51a3c 100644 --- a/src/coreclr/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp +++ b/src/coreclr/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp @@ -12,6 +12,12 @@ #include "spmiutil.h" +bool interceptor_ICJI::isJitIntrinsic( + CORINFO_METHOD_HANDLE ftn) +{ + return original_ICorJitInfo->isJitIntrinsic(ftn); +} + uint32_t interceptor_ICJI::getMethodAttribs( CORINFO_METHOD_HANDLE ftn) { diff --git a/src/coreclr/ToolBox/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/ToolBox/superpmi/superpmi/icorjitinfo.cpp index 9d59f4449be613..4f86025dfc8192 100644 --- a/src/coreclr/ToolBox/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/ToolBox/superpmi/superpmi/icorjitinfo.cpp @@ -23,6 +23,14 @@ ICorJitInfo* InitICorJitInfo(JitInstance* jitInstance) // /**********************************************************************************/ +// Quick check whether the method is a jit intrinsic. Returns the same value as getMethodAttribs(ftn) & +// CORINFO_FLG_JIT_INTRINSIC, except faster. +bool MyICJI::isJitIntrinsic(CORINFO_METHOD_HANDLE ftn) +{ + jitInstance->mc->cr->AddCall("isJitIntrinsic"); + return jitInstance->mc->repIsJitIntrinsic(ftn); +} + // return flags (defined above, CORINFO_FLG_PUBLIC ...) uint32_t MyICJI::getMethodAttribs(CORINFO_METHOD_HANDLE ftn /* IN */) { diff --git a/src/coreclr/crossgen-corelib.proj b/src/coreclr/crossgen-corelib.proj index 2399255b78d0f2..53c4e57c72eb58 100644 --- a/src/coreclr/crossgen-corelib.proj +++ b/src/coreclr/crossgen-corelib.proj @@ -45,6 +45,10 @@ + + + + System.Private.CoreLib $([MSBuild]::NormalizePath('$(BinDir)', 'IL', '$(CoreLibAssemblyName).dll')) @@ -53,12 +57,28 @@ $([MSBuild]::NormalizePath('$(BinDir)', 'PDB', '$(CoreLibAssemblyName).ni.pdb')) $([MSBuild]::NormalizePath('$(BinDir)', '$(CoreLibAssemblyName).perf.map')) + $([MSBuild]::NormalizePath('$(BinDir)', 'StandardOptimizationData.mibc')) - + + + $(DotNetCli) $([MSBuild]::NormalizePath('$(BinDir)', 'dotnet-pgo', 'dotnet-pgo.dll')) merge + $(DotNetPgoCmd) -o:$(MergedMibcPath) + $(DotNetPgoCmd) @(OptimizationMibcFiles->'-i:%(Identity)', ' ') + + + + + + + @@ -75,17 +95,12 @@ - - - - $(DotNetCli) $([MSBuild]::NormalizePath('$(BinDir)', '$(CrossDir)', 'crossgen2', 'crossgen2.dll')) $(CrossGenDllCmd) -o:$(CoreLibOutputPath) $(CrossGenDllCmd) -r:$([MSBuild]::NormalizePath('$(BinDir)', 'IL', '*.dll')) $(CrossGenDllCmd) --targetarch:$(TargetArchitecture) - @(OptimizationMibcFiles->'-m:%(Identity)', ' ') - $(CrossGenDllCmd) $(MibcArgs) --embed-pgo-data + $(CrossGenDllCmd) -m:$(MergedMibcPath) --embed-pgo-data $(CrossGenDllCmd) -O $(CrossGenDllCmd) $(CoreLibInputPath) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index c971d807a800b8..f62759467de10d 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -1953,6 +1953,9 @@ class ICorStaticInfo // /**********************************************************************************/ + // Quick check whether the method is a jit intrinsic. Returns the same value as getMethodAttribs(ftn) & CORINFO_FLG_JIT_INTRINSIC, except faster. + virtual bool isJitIntrinsic(CORINFO_METHOD_HANDLE ftn) = 0; + // return flags (a bitfield of CorInfoFlags values) virtual uint32_t getMethodAttribs ( CORINFO_METHOD_HANDLE ftn /* IN */ diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h index beb71ca0d3fa70..922a854795ec6a 100644 --- a/src/coreclr/inc/icorjitinfoimpl_generated.h +++ b/src/coreclr/inc/icorjitinfoimpl_generated.h @@ -21,6 +21,9 @@ public: +bool isJitIntrinsic( + CORINFO_METHOD_HANDLE ftn) override; + uint32_t getMethodAttribs( CORINFO_METHOD_HANDLE ftn) override; diff --git a/src/coreclr/inc/jiteeversionguid.h b/src/coreclr/inc/jiteeversionguid.h index 5e6a2ef98993e2..f76ceb70b11fcb 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 = { /* 1776ab48-edfa-49be-a11f-ec216b28174c */ - 0x1776ab48, - 0xedfa, - 0x49be, - {0xa1, 0x1f, 0xec, 0x21, 0x6b, 0x28, 0x17, 0x4c} +constexpr GUID JITEEVersionIdentifier = { /* a33f2f79-dd8d-49dd-b4c3-ac86f34f6a87 */ + 0xa33f2f79, + 0xdd8d, + 0x49dd, + {0xb4, 0xc3, 0xac, 0x86, 0xf3, 0x4f, 0x6a, 0x87} }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/coreclr/jit/ICorJitInfo_API_names.h b/src/coreclr/jit/ICorJitInfo_API_names.h index 2e1e67cc24a773..dd0063573a3e14 100644 --- a/src/coreclr/jit/ICorJitInfo_API_names.h +++ b/src/coreclr/jit/ICorJitInfo_API_names.h @@ -4,6 +4,7 @@ // DO NOT EDIT THIS FILE! IT IS AUTOGENERATED // To regenerate run the gen script in src/coreclr/tools/Common/JitInterface/ThunkGenerator // and follow the instructions in docs/project/updating-jitinterface.md +DEF_CLR_API(isJitIntrinsic) DEF_CLR_API(getMethodAttribs) DEF_CLR_API(setMethodAttribs) DEF_CLR_API(getMethodSig) diff --git a/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp b/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp index d80bb83ef059a7..e06bdb51279f52 100644 --- a/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp +++ b/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp @@ -12,6 +12,15 @@ // clang-format off /**********************************************************************************/ +bool WrapICorJitInfo::isJitIntrinsic( + CORINFO_METHOD_HANDLE ftn) +{ + API_ENTER(isJitIntrinsic); + bool temp = wrapHnd->isJitIntrinsic(ftn); + API_LEAVE(isJitIntrinsic); + return temp; +} + uint32_t WrapICorJitInfo::getMethodAttribs( CORINFO_METHOD_HANDLE ftn) { diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 584e3568f7f51a..5c4ab9c8e22cad 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -7542,6 +7542,7 @@ class Compiler // Get the flags bool eeIsValueClass(CORINFO_CLASS_HANDLE clsHnd); + bool eeIsJitIntrinsic(CORINFO_METHOD_HANDLE ftn); #if defined(DEBUG) || defined(FEATURE_JIT_METHOD_PERF) || defined(FEATURE_SIMD) || defined(TRACK_LSRA_STATS) diff --git a/src/coreclr/jit/ee_il_dll.hpp b/src/coreclr/jit/ee_il_dll.hpp index b0626489f6a97d..5a45f22bce6d2d 100644 --- a/src/coreclr/jit/ee_il_dll.hpp +++ b/src/coreclr/jit/ee_il_dll.hpp @@ -53,6 +53,12 @@ bool Compiler::eeIsValueClass(CORINFO_CLASS_HANDLE clsHnd) return info.compCompHnd->isValueClass(clsHnd); } +FORCEINLINE +bool Compiler::eeIsJitIntrinsic(CORINFO_METHOD_HANDLE ftn) +{ + return info.compCompHnd->isJitIntrinsic(ftn); +} + FORCEINLINE void Compiler::eeGetSig(unsigned sigTok, CORINFO_MODULE_HANDLE scope, diff --git a/src/coreclr/jit/fgbasic.cpp b/src/coreclr/jit/fgbasic.cpp index 024c32c22427c7..052ab147f78667 100644 --- a/src/coreclr/jit/fgbasic.cpp +++ b/src/coreclr/jit/fgbasic.cpp @@ -893,8 +893,6 @@ void Compiler::fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, Fixed } CORINFO_RESOLVED_TOKEN resolvedToken; - CORINFO_RESOLVED_TOKEN constrainedResolvedToken; - CORINFO_CALL_INFO callInfo; while (codeAddr < codeEndp) { @@ -958,54 +956,35 @@ void Compiler::fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, Fixed break; } - CORINFO_METHOD_HANDLE methodHnd = nullptr; - unsigned methodFlags = 0; - bool mustExpand = false; - CorInfoIntrinsics intrinsicID = CORINFO_INTRINSIC_Illegal; - NamedIntrinsic ni = NI_Illegal; + CORINFO_METHOD_HANDLE methodHnd = nullptr; + bool isJitIntrinsic = false; + bool mustExpand = false; + NamedIntrinsic ni = NI_Illegal; if (resolveTokens) { impResolveToken(codeAddr, &resolvedToken, CORINFO_TOKENKIND_Method); - eeGetCallInfo(&resolvedToken, - (prefixFlags & PREFIX_CONSTRAINED) ? &constrainedResolvedToken : nullptr, - combine(combine(CORINFO_CALLINFO_KINDONLY, CORINFO_CALLINFO_ALLOWINSTPARAM), - (opcode == CEE_CALLVIRT) ? CORINFO_CALLINFO_CALLVIRT : CORINFO_CALLINFO_NONE), - &callInfo); - - methodHnd = callInfo.hMethod; - methodFlags = callInfo.methodFlags; + methodHnd = resolvedToken.hMethod; + isJitIntrinsic = eeIsJitIntrinsic(methodHnd); } - if ((methodFlags & (CORINFO_FLG_INTRINSIC | CORINFO_FLG_JIT_INTRINSIC)) != 0) + if (isJitIntrinsic) { intrinsicCalls++; + ni = lookupNamedIntrinsic(methodHnd); - if ((methodFlags & CORINFO_FLG_INTRINSIC) != 0) + switch (ni) { - intrinsicID = info.compCompHnd->getIntrinsicID(methodHnd, &mustExpand); - } + case NI_IsSupported_True: + case NI_IsSupported_False: + { + pushedStack.PushConstant(); + break; + } - if ((methodFlags & CORINFO_FLG_JIT_INTRINSIC) != 0) - { - if (intrinsicID == CORINFO_INTRINSIC_Illegal) + default: { - ni = lookupNamedIntrinsic(methodHnd); - - switch (ni) - { - case NI_IsSupported_True: - case NI_IsSupported_False: - { - pushedStack.PushConstant(); - break; - } - - default: - { - break; - } - } + break; } } } @@ -1162,10 +1141,6 @@ void Compiler::fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, Fixed noway_assert(sz == sizeof(unsigned)); prefixFlags |= PREFIX_CONSTRAINED; - if (resolveTokens) - { - impResolveToken(codeAddr, &constrainedResolvedToken, CORINFO_TOKENKIND_Constrained); - } codeAddr += sizeof(unsigned); { diff --git a/src/coreclr/jit/fgopt.cpp b/src/coreclr/jit/fgopt.cpp index 9b0eafce39cef9..3fb3c37b8e68bd 100644 --- a/src/coreclr/jit/fgopt.cpp +++ b/src/coreclr/jit/fgopt.cpp @@ -1996,6 +1996,20 @@ void Compiler::fgUpdateLoopsAfterCompacting(BasicBlock* block, BasicBlock* bNext { optLoopTable[loopNum].lpEntry = block; } + + /* Check the loop's first block */ + + if (optLoopTable[loopNum].lpFirst == bNext) + { + optLoopTable[loopNum].lpFirst = block; + } + + /* Check the loop top */ + + if (optLoopTable[loopNum].lpTop == bNext) + { + optLoopTable[loopNum].lpTop = block; + } } } diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs b/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs index 80fc5e6ea34a65..e7224e1d73af0c 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs @@ -12,6 +12,21 @@ namespace Internal.JitInterface { unsafe partial class CorInfoImpl { + [UnmanagedCallersOnly] + static byte _isJitIntrinsic(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn) + { + var _this = GetThis(thisHandle); + try + { + return _this.isJitIntrinsic(ftn) ? (byte)1 : (byte)0; + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default; + } + } + [UnmanagedCallersOnly] static uint _getMethodAttribs(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn) { @@ -2551,180 +2566,181 @@ static uint _getJitFlags(IntPtr thisHandle, IntPtr* ppException, CORJIT_FLAGS* f static IntPtr GetUnmanagedCallbacks() { - void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 172); - - callbacks[0] = (delegate* unmanaged)&_getMethodAttribs; - callbacks[1] = (delegate* unmanaged)&_setMethodAttribs; - callbacks[2] = (delegate* unmanaged)&_getMethodSig; - callbacks[3] = (delegate* unmanaged)&_getMethodInfo; - callbacks[4] = (delegate* unmanaged)&_canInline; - callbacks[5] = (delegate* unmanaged)&_reportInliningDecision; - callbacks[6] = (delegate* unmanaged)&_canTailCall; - callbacks[7] = (delegate* unmanaged)&_reportTailCallDecision; - callbacks[8] = (delegate* unmanaged)&_getEHinfo; - callbacks[9] = (delegate* unmanaged)&_getMethodClass; - callbacks[10] = (delegate* unmanaged)&_getMethodModule; - callbacks[11] = (delegate* unmanaged)&_getMethodVTableOffset; - callbacks[12] = (delegate* unmanaged)&_resolveVirtualMethod; - callbacks[13] = (delegate* unmanaged)&_getUnboxedEntry; - callbacks[14] = (delegate* unmanaged)&_getDefaultComparerClass; - callbacks[15] = (delegate* unmanaged)&_getDefaultEqualityComparerClass; - callbacks[16] = (delegate* unmanaged)&_expandRawHandleIntrinsic; - callbacks[17] = (delegate* unmanaged)&_getIntrinsicID; - callbacks[18] = (delegate* unmanaged)&_isIntrinsicType; - callbacks[19] = (delegate* unmanaged)&_getUnmanagedCallConv; - callbacks[20] = (delegate* unmanaged)&_pInvokeMarshalingRequired; - callbacks[21] = (delegate* unmanaged)&_satisfiesMethodConstraints; - callbacks[22] = (delegate* unmanaged)&_isCompatibleDelegate; - callbacks[23] = (delegate* unmanaged)&_methodMustBeLoadedBeforeCodeIsRun; - callbacks[24] = (delegate* unmanaged)&_mapMethodDeclToMethodImpl; - callbacks[25] = (delegate* unmanaged)&_getGSCookie; - callbacks[26] = (delegate* unmanaged)&_setPatchpointInfo; - callbacks[27] = (delegate* unmanaged)&_getOSRInfo; - callbacks[28] = (delegate* unmanaged)&_resolveToken; - callbacks[29] = (delegate* unmanaged)&_tryResolveToken; - callbacks[30] = (delegate* unmanaged)&_findSig; - callbacks[31] = (delegate* unmanaged)&_findCallSiteSig; - callbacks[32] = (delegate* unmanaged)&_getTokenTypeAsHandle; - callbacks[33] = (delegate* unmanaged)&_isValidToken; - callbacks[34] = (delegate* unmanaged)&_isValidStringRef; - callbacks[35] = (delegate* unmanaged)&_getStringLiteral; - callbacks[36] = (delegate* unmanaged)&_asCorInfoType; - callbacks[37] = (delegate* unmanaged)&_getClassName; - callbacks[38] = (delegate* unmanaged)&_getClassNameFromMetadata; - callbacks[39] = (delegate* unmanaged)&_getTypeInstantiationArgument; - callbacks[40] = (delegate* unmanaged)&_appendClassName; - callbacks[41] = (delegate* unmanaged)&_isValueClass; - callbacks[42] = (delegate* unmanaged)&_canInlineTypeCheck; - callbacks[43] = (delegate* unmanaged)&_getClassAttribs; - callbacks[44] = (delegate* unmanaged)&_isStructRequiringStackAllocRetBuf; - callbacks[45] = (delegate* unmanaged)&_getClassModule; - callbacks[46] = (delegate* unmanaged)&_getModuleAssembly; - callbacks[47] = (delegate* unmanaged)&_getAssemblyName; - callbacks[48] = (delegate* unmanaged)&_LongLifetimeMalloc; - callbacks[49] = (delegate* unmanaged)&_LongLifetimeFree; - callbacks[50] = (delegate* unmanaged)&_getClassModuleIdForStatics; - callbacks[51] = (delegate* unmanaged)&_getClassSize; - callbacks[52] = (delegate* unmanaged)&_getHeapClassSize; - callbacks[53] = (delegate* unmanaged)&_canAllocateOnStack; - callbacks[54] = (delegate* unmanaged)&_getClassAlignmentRequirement; - callbacks[55] = (delegate* unmanaged)&_getClassGClayout; - callbacks[56] = (delegate* unmanaged)&_getClassNumInstanceFields; - callbacks[57] = (delegate* unmanaged)&_getFieldInClass; - callbacks[58] = (delegate* unmanaged)&_checkMethodModifier; - callbacks[59] = (delegate* unmanaged)&_getNewHelper; - callbacks[60] = (delegate* unmanaged)&_getNewArrHelper; - callbacks[61] = (delegate* unmanaged)&_getCastingHelper; - callbacks[62] = (delegate* unmanaged)&_getSharedCCtorHelper; - callbacks[63] = (delegate* unmanaged)&_getTypeForBox; - callbacks[64] = (delegate* unmanaged)&_getBoxHelper; - callbacks[65] = (delegate* unmanaged)&_getUnBoxHelper; - callbacks[66] = (delegate* unmanaged)&_getReadyToRunHelper; - callbacks[67] = (delegate* unmanaged)&_getReadyToRunDelegateCtorHelper; - callbacks[68] = (delegate* unmanaged)&_getHelperName; - callbacks[69] = (delegate* unmanaged)&_initClass; - callbacks[70] = (delegate* unmanaged)&_classMustBeLoadedBeforeCodeIsRun; - callbacks[71] = (delegate* unmanaged)&_getBuiltinClass; - callbacks[72] = (delegate* unmanaged)&_getTypeForPrimitiveValueClass; - callbacks[73] = (delegate* unmanaged)&_getTypeForPrimitiveNumericClass; - callbacks[74] = (delegate* unmanaged)&_canCast; - callbacks[75] = (delegate* unmanaged)&_areTypesEquivalent; - callbacks[76] = (delegate* unmanaged)&_compareTypesForCast; - callbacks[77] = (delegate* unmanaged)&_compareTypesForEquality; - callbacks[78] = (delegate* unmanaged)&_mergeClasses; - callbacks[79] = (delegate* unmanaged)&_isMoreSpecificType; - callbacks[80] = (delegate* unmanaged)&_getParentType; - callbacks[81] = (delegate* unmanaged)&_getChildType; - callbacks[82] = (delegate* unmanaged)&_satisfiesClassConstraints; - callbacks[83] = (delegate* unmanaged)&_isSDArray; - callbacks[84] = (delegate* unmanaged)&_getArrayRank; - callbacks[85] = (delegate* unmanaged)&_getArrayInitializationData; - callbacks[86] = (delegate* unmanaged)&_canAccessClass; - callbacks[87] = (delegate* unmanaged)&_getFieldName; - callbacks[88] = (delegate* unmanaged)&_getFieldClass; - callbacks[89] = (delegate* unmanaged)&_getFieldType; - callbacks[90] = (delegate* unmanaged)&_getFieldOffset; - callbacks[91] = (delegate* unmanaged)&_getFieldInfo; - callbacks[92] = (delegate* unmanaged)&_isFieldStatic; - callbacks[93] = (delegate* unmanaged)&_getBoundaries; - callbacks[94] = (delegate* unmanaged)&_setBoundaries; - callbacks[95] = (delegate* unmanaged)&_getVars; - callbacks[96] = (delegate* unmanaged)&_setVars; - callbacks[97] = (delegate* unmanaged)&_allocateArray; - callbacks[98] = (delegate* unmanaged)&_freeArray; - callbacks[99] = (delegate* unmanaged)&_getArgNext; - callbacks[100] = (delegate* unmanaged)&_getArgType; - callbacks[101] = (delegate* unmanaged)&_getArgClass; - callbacks[102] = (delegate* unmanaged)&_getHFAType; - callbacks[103] = (delegate* unmanaged)&_GetErrorHRESULT; - callbacks[104] = (delegate* unmanaged)&_GetErrorMessage; - callbacks[105] = (delegate* unmanaged)&_FilterException; - callbacks[106] = (delegate* unmanaged)&_HandleException; - callbacks[107] = (delegate* unmanaged)&_ThrowExceptionForJitResult; - callbacks[108] = (delegate* unmanaged)&_ThrowExceptionForHelper; - callbacks[109] = (delegate* unmanaged)&_runWithErrorTrap; - callbacks[110] = (delegate* unmanaged)&_getEEInfo; - callbacks[111] = (delegate* unmanaged)&_getJitTimeLogFilename; - callbacks[112] = (delegate* unmanaged)&_getMethodDefFromMethod; - callbacks[113] = (delegate* unmanaged)&_getMethodName; - callbacks[114] = (delegate* unmanaged)&_getMethodNameFromMetadata; - callbacks[115] = (delegate* unmanaged)&_getMethodHash; - callbacks[116] = (delegate* unmanaged)&_findNameOfToken; - callbacks[117] = (delegate* unmanaged)&_getSystemVAmd64PassStructInRegisterDescriptor; - callbacks[118] = (delegate* unmanaged)&_getThreadTLSIndex; - callbacks[119] = (delegate* unmanaged)&_getInlinedCallFrameVptr; - callbacks[120] = (delegate* unmanaged)&_getAddrOfCaptureThreadGlobal; - callbacks[121] = (delegate* unmanaged)&_getHelperFtn; - callbacks[122] = (delegate* unmanaged)&_getFunctionEntryPoint; - callbacks[123] = (delegate* unmanaged)&_getFunctionFixedEntryPoint; - callbacks[124] = (delegate* unmanaged)&_getMethodSync; - callbacks[125] = (delegate* unmanaged)&_getLazyStringLiteralHelper; - callbacks[126] = (delegate* unmanaged)&_embedModuleHandle; - callbacks[127] = (delegate* unmanaged)&_embedClassHandle; - callbacks[128] = (delegate* unmanaged)&_embedMethodHandle; - callbacks[129] = (delegate* unmanaged)&_embedFieldHandle; - callbacks[130] = (delegate* unmanaged)&_embedGenericHandle; - callbacks[131] = (delegate* unmanaged)&_getLocationOfThisType; - callbacks[132] = (delegate* unmanaged)&_getAddressOfPInvokeTarget; - callbacks[133] = (delegate* unmanaged)&_GetCookieForPInvokeCalliSig; - callbacks[134] = (delegate* unmanaged)&_canGetCookieForPInvokeCalliSig; - callbacks[135] = (delegate* unmanaged)&_getJustMyCodeHandle; - callbacks[136] = (delegate* unmanaged)&_GetProfilingHandle; - callbacks[137] = (delegate* unmanaged)&_getCallInfo; - callbacks[138] = (delegate* unmanaged)&_canAccessFamily; - callbacks[139] = (delegate* unmanaged)&_isRIDClassDomainID; - callbacks[140] = (delegate* unmanaged)&_getClassDomainID; - callbacks[141] = (delegate* unmanaged)&_getFieldAddress; - callbacks[142] = (delegate* unmanaged)&_getStaticFieldCurrentClass; - callbacks[143] = (delegate* unmanaged)&_getVarArgsHandle; - callbacks[144] = (delegate* unmanaged)&_canGetVarArgsHandle; - callbacks[145] = (delegate* unmanaged)&_constructStringLiteral; - callbacks[146] = (delegate* unmanaged)&_emptyStringLiteral; - callbacks[147] = (delegate* unmanaged)&_getFieldThreadLocalStoreID; - callbacks[148] = (delegate* unmanaged)&_setOverride; - callbacks[149] = (delegate* unmanaged)&_addActiveDependency; - callbacks[150] = (delegate* unmanaged)&_GetDelegateCtor; - callbacks[151] = (delegate* unmanaged)&_MethodCompileComplete; - callbacks[152] = (delegate* unmanaged)&_getTailCallHelpers; - callbacks[153] = (delegate* unmanaged)&_convertPInvokeCalliToCall; - callbacks[154] = (delegate* unmanaged)&_notifyInstructionSetUsage; - callbacks[155] = (delegate* unmanaged)&_allocMem; - callbacks[156] = (delegate* unmanaged)&_reserveUnwindInfo; - callbacks[157] = (delegate* unmanaged)&_allocUnwindInfo; - callbacks[158] = (delegate* unmanaged)&_allocGCInfo; - callbacks[159] = (delegate* unmanaged)&_setEHcount; - callbacks[160] = (delegate* unmanaged)&_setEHinfo; - callbacks[161] = (delegate* unmanaged)&_logMsg; - callbacks[162] = (delegate* unmanaged)&_doAssert; - callbacks[163] = (delegate* unmanaged)&_reportFatalError; - callbacks[164] = (delegate* unmanaged)&_getPgoInstrumentationResults; - callbacks[165] = (delegate* unmanaged)&_allocPgoInstrumentationBySchema; - callbacks[166] = (delegate* unmanaged)&_getLikelyClass; - callbacks[167] = (delegate* unmanaged)&_recordCallSite; - callbacks[168] = (delegate* unmanaged)&_recordRelocation; - callbacks[169] = (delegate* unmanaged)&_getRelocTypeHint; - callbacks[170] = (delegate* unmanaged)&_getExpectedTargetArchitecture; - callbacks[171] = (delegate* unmanaged)&_getJitFlags; + void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 173); + + callbacks[0] = (delegate* unmanaged)&_isJitIntrinsic; + callbacks[1] = (delegate* unmanaged)&_getMethodAttribs; + callbacks[2] = (delegate* unmanaged)&_setMethodAttribs; + callbacks[3] = (delegate* unmanaged)&_getMethodSig; + callbacks[4] = (delegate* unmanaged)&_getMethodInfo; + callbacks[5] = (delegate* unmanaged)&_canInline; + callbacks[6] = (delegate* unmanaged)&_reportInliningDecision; + callbacks[7] = (delegate* unmanaged)&_canTailCall; + callbacks[8] = (delegate* unmanaged)&_reportTailCallDecision; + callbacks[9] = (delegate* unmanaged)&_getEHinfo; + callbacks[10] = (delegate* unmanaged)&_getMethodClass; + callbacks[11] = (delegate* unmanaged)&_getMethodModule; + callbacks[12] = (delegate* unmanaged)&_getMethodVTableOffset; + callbacks[13] = (delegate* unmanaged)&_resolveVirtualMethod; + callbacks[14] = (delegate* unmanaged)&_getUnboxedEntry; + callbacks[15] = (delegate* unmanaged)&_getDefaultComparerClass; + callbacks[16] = (delegate* unmanaged)&_getDefaultEqualityComparerClass; + callbacks[17] = (delegate* unmanaged)&_expandRawHandleIntrinsic; + callbacks[18] = (delegate* unmanaged)&_getIntrinsicID; + callbacks[19] = (delegate* unmanaged)&_isIntrinsicType; + callbacks[20] = (delegate* unmanaged)&_getUnmanagedCallConv; + callbacks[21] = (delegate* unmanaged)&_pInvokeMarshalingRequired; + callbacks[22] = (delegate* unmanaged)&_satisfiesMethodConstraints; + callbacks[23] = (delegate* unmanaged)&_isCompatibleDelegate; + callbacks[24] = (delegate* unmanaged)&_methodMustBeLoadedBeforeCodeIsRun; + callbacks[25] = (delegate* unmanaged)&_mapMethodDeclToMethodImpl; + callbacks[26] = (delegate* unmanaged)&_getGSCookie; + callbacks[27] = (delegate* unmanaged)&_setPatchpointInfo; + callbacks[28] = (delegate* unmanaged)&_getOSRInfo; + callbacks[29] = (delegate* unmanaged)&_resolveToken; + callbacks[30] = (delegate* unmanaged)&_tryResolveToken; + callbacks[31] = (delegate* unmanaged)&_findSig; + callbacks[32] = (delegate* unmanaged)&_findCallSiteSig; + callbacks[33] = (delegate* unmanaged)&_getTokenTypeAsHandle; + callbacks[34] = (delegate* unmanaged)&_isValidToken; + callbacks[35] = (delegate* unmanaged)&_isValidStringRef; + callbacks[36] = (delegate* unmanaged)&_getStringLiteral; + callbacks[37] = (delegate* unmanaged)&_asCorInfoType; + callbacks[38] = (delegate* unmanaged)&_getClassName; + callbacks[39] = (delegate* unmanaged)&_getClassNameFromMetadata; + callbacks[40] = (delegate* unmanaged)&_getTypeInstantiationArgument; + callbacks[41] = (delegate* unmanaged)&_appendClassName; + callbacks[42] = (delegate* unmanaged)&_isValueClass; + callbacks[43] = (delegate* unmanaged)&_canInlineTypeCheck; + callbacks[44] = (delegate* unmanaged)&_getClassAttribs; + callbacks[45] = (delegate* unmanaged)&_isStructRequiringStackAllocRetBuf; + callbacks[46] = (delegate* unmanaged)&_getClassModule; + callbacks[47] = (delegate* unmanaged)&_getModuleAssembly; + callbacks[48] = (delegate* unmanaged)&_getAssemblyName; + callbacks[49] = (delegate* unmanaged)&_LongLifetimeMalloc; + callbacks[50] = (delegate* unmanaged)&_LongLifetimeFree; + callbacks[51] = (delegate* unmanaged)&_getClassModuleIdForStatics; + callbacks[52] = (delegate* unmanaged)&_getClassSize; + callbacks[53] = (delegate* unmanaged)&_getHeapClassSize; + callbacks[54] = (delegate* unmanaged)&_canAllocateOnStack; + callbacks[55] = (delegate* unmanaged)&_getClassAlignmentRequirement; + callbacks[56] = (delegate* unmanaged)&_getClassGClayout; + callbacks[57] = (delegate* unmanaged)&_getClassNumInstanceFields; + callbacks[58] = (delegate* unmanaged)&_getFieldInClass; + callbacks[59] = (delegate* unmanaged)&_checkMethodModifier; + callbacks[60] = (delegate* unmanaged)&_getNewHelper; + callbacks[61] = (delegate* unmanaged)&_getNewArrHelper; + callbacks[62] = (delegate* unmanaged)&_getCastingHelper; + callbacks[63] = (delegate* unmanaged)&_getSharedCCtorHelper; + callbacks[64] = (delegate* unmanaged)&_getTypeForBox; + callbacks[65] = (delegate* unmanaged)&_getBoxHelper; + callbacks[66] = (delegate* unmanaged)&_getUnBoxHelper; + callbacks[67] = (delegate* unmanaged)&_getReadyToRunHelper; + callbacks[68] = (delegate* unmanaged)&_getReadyToRunDelegateCtorHelper; + callbacks[69] = (delegate* unmanaged)&_getHelperName; + callbacks[70] = (delegate* unmanaged)&_initClass; + callbacks[71] = (delegate* unmanaged)&_classMustBeLoadedBeforeCodeIsRun; + callbacks[72] = (delegate* unmanaged)&_getBuiltinClass; + callbacks[73] = (delegate* unmanaged)&_getTypeForPrimitiveValueClass; + callbacks[74] = (delegate* unmanaged)&_getTypeForPrimitiveNumericClass; + callbacks[75] = (delegate* unmanaged)&_canCast; + callbacks[76] = (delegate* unmanaged)&_areTypesEquivalent; + callbacks[77] = (delegate* unmanaged)&_compareTypesForCast; + callbacks[78] = (delegate* unmanaged)&_compareTypesForEquality; + callbacks[79] = (delegate* unmanaged)&_mergeClasses; + callbacks[80] = (delegate* unmanaged)&_isMoreSpecificType; + callbacks[81] = (delegate* unmanaged)&_getParentType; + callbacks[82] = (delegate* unmanaged)&_getChildType; + callbacks[83] = (delegate* unmanaged)&_satisfiesClassConstraints; + callbacks[84] = (delegate* unmanaged)&_isSDArray; + callbacks[85] = (delegate* unmanaged)&_getArrayRank; + callbacks[86] = (delegate* unmanaged)&_getArrayInitializationData; + callbacks[87] = (delegate* unmanaged)&_canAccessClass; + callbacks[88] = (delegate* unmanaged)&_getFieldName; + callbacks[89] = (delegate* unmanaged)&_getFieldClass; + callbacks[90] = (delegate* unmanaged)&_getFieldType; + callbacks[91] = (delegate* unmanaged)&_getFieldOffset; + callbacks[92] = (delegate* unmanaged)&_getFieldInfo; + callbacks[93] = (delegate* unmanaged)&_isFieldStatic; + callbacks[94] = (delegate* unmanaged)&_getBoundaries; + callbacks[95] = (delegate* unmanaged)&_setBoundaries; + callbacks[96] = (delegate* unmanaged)&_getVars; + callbacks[97] = (delegate* unmanaged)&_setVars; + callbacks[98] = (delegate* unmanaged)&_allocateArray; + callbacks[99] = (delegate* unmanaged)&_freeArray; + callbacks[100] = (delegate* unmanaged)&_getArgNext; + callbacks[101] = (delegate* unmanaged)&_getArgType; + callbacks[102] = (delegate* unmanaged)&_getArgClass; + callbacks[103] = (delegate* unmanaged)&_getHFAType; + callbacks[104] = (delegate* unmanaged)&_GetErrorHRESULT; + callbacks[105] = (delegate* unmanaged)&_GetErrorMessage; + callbacks[106] = (delegate* unmanaged)&_FilterException; + callbacks[107] = (delegate* unmanaged)&_HandleException; + callbacks[108] = (delegate* unmanaged)&_ThrowExceptionForJitResult; + callbacks[109] = (delegate* unmanaged)&_ThrowExceptionForHelper; + callbacks[110] = (delegate* unmanaged)&_runWithErrorTrap; + callbacks[111] = (delegate* unmanaged)&_getEEInfo; + callbacks[112] = (delegate* unmanaged)&_getJitTimeLogFilename; + callbacks[113] = (delegate* unmanaged)&_getMethodDefFromMethod; + callbacks[114] = (delegate* unmanaged)&_getMethodName; + callbacks[115] = (delegate* unmanaged)&_getMethodNameFromMetadata; + callbacks[116] = (delegate* unmanaged)&_getMethodHash; + callbacks[117] = (delegate* unmanaged)&_findNameOfToken; + callbacks[118] = (delegate* unmanaged)&_getSystemVAmd64PassStructInRegisterDescriptor; + callbacks[119] = (delegate* unmanaged)&_getThreadTLSIndex; + callbacks[120] = (delegate* unmanaged)&_getInlinedCallFrameVptr; + callbacks[121] = (delegate* unmanaged)&_getAddrOfCaptureThreadGlobal; + callbacks[122] = (delegate* unmanaged)&_getHelperFtn; + callbacks[123] = (delegate* unmanaged)&_getFunctionEntryPoint; + callbacks[124] = (delegate* unmanaged)&_getFunctionFixedEntryPoint; + callbacks[125] = (delegate* unmanaged)&_getMethodSync; + callbacks[126] = (delegate* unmanaged)&_getLazyStringLiteralHelper; + callbacks[127] = (delegate* unmanaged)&_embedModuleHandle; + callbacks[128] = (delegate* unmanaged)&_embedClassHandle; + callbacks[129] = (delegate* unmanaged)&_embedMethodHandle; + callbacks[130] = (delegate* unmanaged)&_embedFieldHandle; + callbacks[131] = (delegate* unmanaged)&_embedGenericHandle; + callbacks[132] = (delegate* unmanaged)&_getLocationOfThisType; + callbacks[133] = (delegate* unmanaged)&_getAddressOfPInvokeTarget; + callbacks[134] = (delegate* unmanaged)&_GetCookieForPInvokeCalliSig; + callbacks[135] = (delegate* unmanaged)&_canGetCookieForPInvokeCalliSig; + callbacks[136] = (delegate* unmanaged)&_getJustMyCodeHandle; + callbacks[137] = (delegate* unmanaged)&_GetProfilingHandle; + callbacks[138] = (delegate* unmanaged)&_getCallInfo; + callbacks[139] = (delegate* unmanaged)&_canAccessFamily; + callbacks[140] = (delegate* unmanaged)&_isRIDClassDomainID; + callbacks[141] = (delegate* unmanaged)&_getClassDomainID; + callbacks[142] = (delegate* unmanaged)&_getFieldAddress; + callbacks[143] = (delegate* unmanaged)&_getStaticFieldCurrentClass; + callbacks[144] = (delegate* unmanaged)&_getVarArgsHandle; + callbacks[145] = (delegate* unmanaged)&_canGetVarArgsHandle; + callbacks[146] = (delegate* unmanaged)&_constructStringLiteral; + callbacks[147] = (delegate* unmanaged)&_emptyStringLiteral; + callbacks[148] = (delegate* unmanaged)&_getFieldThreadLocalStoreID; + callbacks[149] = (delegate* unmanaged)&_setOverride; + callbacks[150] = (delegate* unmanaged)&_addActiveDependency; + callbacks[151] = (delegate* unmanaged)&_GetDelegateCtor; + callbacks[152] = (delegate* unmanaged)&_MethodCompileComplete; + callbacks[153] = (delegate* unmanaged)&_getTailCallHelpers; + callbacks[154] = (delegate* unmanaged)&_convertPInvokeCalliToCall; + callbacks[155] = (delegate* unmanaged)&_notifyInstructionSetUsage; + callbacks[156] = (delegate* unmanaged)&_allocMem; + callbacks[157] = (delegate* unmanaged)&_reserveUnwindInfo; + callbacks[158] = (delegate* unmanaged)&_allocUnwindInfo; + callbacks[159] = (delegate* unmanaged)&_allocGCInfo; + callbacks[160] = (delegate* unmanaged)&_setEHcount; + callbacks[161] = (delegate* unmanaged)&_setEHinfo; + callbacks[162] = (delegate* unmanaged)&_logMsg; + callbacks[163] = (delegate* unmanaged)&_doAssert; + callbacks[164] = (delegate* unmanaged)&_reportFatalError; + callbacks[165] = (delegate* unmanaged)&_getPgoInstrumentationResults; + callbacks[166] = (delegate* unmanaged)&_allocPgoInstrumentationBySchema; + callbacks[167] = (delegate* unmanaged)&_getLikelyClass; + callbacks[168] = (delegate* unmanaged)&_recordCallSite; + callbacks[169] = (delegate* unmanaged)&_recordRelocation; + callbacks[170] = (delegate* unmanaged)&_getRelocTypeHint; + callbacks[171] = (delegate* unmanaged)&_getExpectedTargetArchitecture; + callbacks[172] = (delegate* unmanaged)&_getJitFlags; return (IntPtr)callbacks; } diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index c138b9500c8822..fa5b01adc89a37 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -858,6 +858,12 @@ private TypeSystemEntity entityFromContext(CORINFO_CONTEXT_STRUCT* contextStruct return (TypeSystemEntity)HandleToObject((IntPtr)((ulong)contextStruct & ~(ulong)CorInfoContextFlags.CORINFO_CONTEXTFLAGS_MASK)); } + private bool isJitIntrinsic(CORINFO_METHOD_STRUCT_* ftn) + { + MethodDesc method = HandleToObject(ftn); + return method.IsIntrinsic; + } + private uint getMethodAttribsInternal(MethodDesc method) { CorInfoFlag result = 0; diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt index d4640311e8818a..03ddae062ba693 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -150,6 +150,7 @@ struct _EXCEPTION_POINTERS*,_EXCEPTION_POINTERS* ICorJitInfo::errorTrapFunction,void* FUNCTIONS + bool isJitIntrinsic( CORINFO_METHOD_HANDLE ftn ); uint32_t getMethodAttribs( CORINFO_METHOD_HANDLE ftn ); void setMethodAttribs( CORINFO_METHOD_HANDLE ftn, CorInfoMethodRuntimeFlags attribs ); void getMethodSig( CORINFO_METHOD_HANDLE ftn, CORINFO_SIG_INFO *sig, CORINFO_CLASS_HANDLE memberParent ); 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 56a3cce130244e..60fe8683e22d1b 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs @@ -221,8 +221,9 @@ public override int GetHashCode() public bool Equals(MethodWithToken methodWithToken) { - bool equals = Method == methodWithToken.Method && Token.Equals(methodWithToken.Token) && ConstrainedType == methodWithToken.ConstrainedType && - Unboxing == methodWithToken.Unboxing; + bool equals = Method == methodWithToken.Method && Token.Equals(methodWithToken.Token) + && OwningType == methodWithToken.OwningType && ConstrainedType == methodWithToken.ConstrainedType + && Unboxing == methodWithToken.Unboxing; if (equals) { Debug.Assert(OwningTypeNotDerivedFromToken == methodWithToken.OwningTypeNotDerivedFromToken); diff --git a/src/coreclr/tools/aot/jitinterface/jitinterface.h b/src/coreclr/tools/aot/jitinterface/jitinterface.h index 3e61333832c257..b39c924f718495 100644 --- a/src/coreclr/tools/aot/jitinterface/jitinterface.h +++ b/src/coreclr/tools/aot/jitinterface/jitinterface.h @@ -11,6 +11,7 @@ struct JitInterfaceCallbacks { + bool (* isJitIntrinsic)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE ftn); uint32_t (* getMethodAttribs)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE ftn); void (* setMethodAttribs)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE ftn, CorInfoMethodRuntimeFlags attribs); void (* getMethodSig)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE ftn, CORINFO_SIG_INFO* sig, CORINFO_CLASS_HANDLE memberParent); @@ -198,6 +199,15 @@ class JitInterfaceWrapper : public ICorJitInfo } + virtual bool isJitIntrinsic( + CORINFO_METHOD_HANDLE ftn) +{ + CorInfoExceptionClass* pException = nullptr; + bool temp = _callbacks->isJitIntrinsic(_thisHandle, &pException, ftn); + if (pException != nullptr) throw pException; + return temp; +} + virtual uint32_t getMethodAttribs( CORINFO_METHOD_HANDLE ftn) { diff --git a/src/coreclr/tools/r2rtest/BuildOptions.cs b/src/coreclr/tools/r2rtest/BuildOptions.cs index 0a2a8fe0eb7f3d..3465aa18598d7b 100644 --- a/src/coreclr/tools/r2rtest/BuildOptions.cs +++ b/src/coreclr/tools/r2rtest/BuildOptions.cs @@ -49,6 +49,7 @@ public class BuildOptions public string InputFileSearchString { get; set; } public string ConfigurationSuffix => (Release ? "-ret.out" : "-chk.out"); public string GCStress { get; set; } + public FileInfo[] MibcPath { get; set; } public string DotNetCli { get diff --git a/src/coreclr/tools/r2rtest/CommandLineOptions.cs b/src/coreclr/tools/r2rtest/CommandLineOptions.cs index ebadfd8fcdb450..d99e5af1c0c0a9 100644 --- a/src/coreclr/tools/r2rtest/CommandLineOptions.cs +++ b/src/coreclr/tools/r2rtest/CommandLineOptions.cs @@ -70,6 +70,7 @@ Command CompileFolder() => R2RDumpPath(), MeasurePerf(), InputFileSearchString(), + MibcPath(), }, CompileDirectoryCommand.CompileDirectory); @@ -107,6 +108,7 @@ Command CompileSubtree() => ExecutionTimeoutMinutes(), R2RDumpPath(), GCStress(), + MibcPath(), }, CompileSubtreeCommand.CompileSubtree); @@ -137,6 +139,7 @@ Command CompileFramework() => MeasurePerf(), InputFileSearchString(), OutputDirectory(), + MibcPath(), }, CompileFrameworkCommand.CompileFramework); @@ -155,6 +158,7 @@ Command CompileNugetPackages() => DegreeOfParallelism(), CompilationTimeoutMinutes(), ExecutionTimeoutMinutes(), + MibcPath(), }, CompileNugetCommand.CompileNuget); @@ -170,6 +174,7 @@ Command CompileSerp() => Pdb(), CompilationTimeoutMinutes(), Crossgen2Path(), + MibcPath(), }, options => { @@ -195,6 +200,10 @@ Option ReferencePath() => new Option(new[] { "--reference-path", "-r" }, "Folder containing assemblies to reference during compilation") { Argument = new Argument() { Arity = ArgumentArity.ZeroOrMore }.ExistingOnly() }; + Option MibcPath() => + new Option(new[] { "--mibc-path", "-m" }, "Mibc files to use in compilation") + { Argument = new Argument() { Arity = ArgumentArity.ZeroOrMore }.ExistingOnly() }; + Option Crossgen() => new Option(new[] { "--crossgen" }, "Compile the apps using Crossgen in the CORE_ROOT folder"); diff --git a/src/coreclr/tools/r2rtest/Crossgen2Runner.cs b/src/coreclr/tools/r2rtest/Crossgen2Runner.cs index 19d13dc2fc6073..2aa1dee6b6f6d0 100644 --- a/src/coreclr/tools/r2rtest/Crossgen2Runner.cs +++ b/src/coreclr/tools/r2rtest/Crossgen2Runner.cs @@ -122,6 +122,15 @@ protected override IEnumerable BuildCommandLineArguments(IEnumerable 0) + { + yield return "--embed-pgo-data"; + foreach (FileInfo mibc in _options.MibcPath) + { + yield return $"-m:{mibc.FullName}"; + } + } + if (!string.IsNullOrEmpty(Crossgen2RunnerOptions.CompositeRoot)) { yield return $"--compositerootpath={Crossgen2RunnerOptions.CompositeRoot}"; diff --git a/src/coreclr/vm/CMakeLists.txt b/src/coreclr/vm/CMakeLists.txt index 0e1c2513fbca03..c93cbd79dc0f1a 100644 --- a/src/coreclr/vm/CMakeLists.txt +++ b/src/coreclr/vm/CMakeLists.txt @@ -67,7 +67,6 @@ set(VM_SOURCES_DAC_AND_WKS_COMMON debuginfostore.cpp decodemd.cpp disassembler.cpp - dllimport.cpp domainfile.cpp dynamicmethod.cpp ecall.cpp @@ -323,6 +322,7 @@ set(VM_SOURCES_WKS customattribute.cpp custommarshalerinfo.cpp autotrace.cpp + dllimport.cpp dllimportcallback.cpp dynamicinterfacecastable.cpp eeconfig.cpp @@ -358,6 +358,7 @@ set(VM_SOURCES_WKS multicorejitplayer.cpp # Condition="'$(FeatureMulticoreJIT)' == 'true' nativeeventsource.cpp nativeoverlapped.cpp + nativelibrary.cpp nativelibrarynative.cpp objectlist.cpp olevariant.cpp diff --git a/src/coreclr/vm/dllimport.cpp b/src/coreclr/vm/dllimport.cpp index 76bccc36ed5551..7324dfd8feb7f1 100644 --- a/src/coreclr/vm/dllimport.cpp +++ b/src/coreclr/vm/dllimport.cpp @@ -31,10 +31,10 @@ #include "typestring.h" #include "sigbuilder.h" #include "sigformat.h" -#include "strongnameholders.h" #include "ecall.h" #include "fieldmarshaler.h" #include "pinvokeoverride.h" +#include "nativelibrary.h" #include #include "../md/compiler/custattr.h" @@ -49,57 +49,46 @@ #endif // FEATURE_PREJIT #include "eventtrace.h" -#include "clr/fs/path.h" -using namespace clr::fs; -// Specifies whether coreclr is embedded or standalone -extern bool g_coreclr_embedded; - -// Specifies whether hostpolicy is embedded in executable or standalone -extern bool g_hostpolicy_embedded; - -// remove when we get an updated SDK -#define LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR 0x00000100 -#define LOAD_LIBRARY_SEARCH_DEFAULT_DIRS 0x00001000 - -#ifndef DACCESS_COMPILE -void AppendEHClause(int nClauses, COR_ILMETHOD_SECT_EH * pEHSect, ILStubEHClause * pClause, int * pCurIdx) +namespace { - LIMITED_METHOD_CONTRACT; - if (pClause->kind == ILStubEHClause::kNone) - return; + void AppendEHClause(int nClauses, COR_ILMETHOD_SECT_EH * pEHSect, ILStubEHClause * pClause, int * pCurIdx) + { + LIMITED_METHOD_CONTRACT; + if (pClause->kind == ILStubEHClause::kNone) + return; - int idx = *pCurIdx; - *pCurIdx = idx + 1; + int idx = *pCurIdx; + *pCurIdx = idx + 1; - CorExceptionFlag flags; - switch (pClause->kind) - { - case ILStubEHClause::kFinally: flags = COR_ILEXCEPTION_CLAUSE_FINALLY; break; - case ILStubEHClause::kTypedCatch: flags = COR_ILEXCEPTION_CLAUSE_NONE; break; - default: - UNREACHABLE_MSG("unexpected ILStubEHClause kind"); + CorExceptionFlag flags; + switch (pClause->kind) + { + case ILStubEHClause::kFinally: flags = COR_ILEXCEPTION_CLAUSE_FINALLY; break; + case ILStubEHClause::kTypedCatch: flags = COR_ILEXCEPTION_CLAUSE_NONE; break; + default: + UNREACHABLE_MSG("unexpected ILStubEHClause kind"); + } + _ASSERTE(idx < nClauses); + pEHSect->Fat.Clauses[idx].Flags = flags; + pEHSect->Fat.Clauses[idx].TryOffset = pClause->dwTryBeginOffset; + pEHSect->Fat.Clauses[idx].TryLength = pClause->cbTryLength; + pEHSect->Fat.Clauses[idx].HandlerOffset = pClause->dwHandlerBeginOffset; + pEHSect->Fat.Clauses[idx].HandlerLength = pClause->cbHandlerLength; + pEHSect->Fat.Clauses[idx].ClassToken = pClause->dwTypeToken; } - _ASSERTE(idx < nClauses); - pEHSect->Fat.Clauses[idx].Flags = flags; - pEHSect->Fat.Clauses[idx].TryOffset = pClause->dwTryBeginOffset; - pEHSect->Fat.Clauses[idx].TryLength = pClause->cbTryLength; - pEHSect->Fat.Clauses[idx].HandlerOffset = pClause->dwHandlerBeginOffset; - pEHSect->Fat.Clauses[idx].HandlerLength = pClause->cbHandlerLength; - pEHSect->Fat.Clauses[idx].ClassToken = pClause->dwTypeToken; -} -VOID PopulateEHSect(COR_ILMETHOD_SECT_EH * pEHSect, int nClauses, ILStubEHClause * pOne, ILStubEHClause * pTwo) -{ - LIMITED_METHOD_CONTRACT; - pEHSect->Fat.Kind = (CorILMethod_Sect_EHTable | CorILMethod_Sect_FatFormat); - pEHSect->Fat.DataSize = COR_ILMETHOD_SECT_EH_FAT::Size(nClauses); + VOID PopulateEHSect(COR_ILMETHOD_SECT_EH * pEHSect, int nClauses, ILStubEHClause * pOne, ILStubEHClause * pTwo) + { + LIMITED_METHOD_CONTRACT; + pEHSect->Fat.Kind = (CorILMethod_Sect_EHTable | CorILMethod_Sect_FatFormat); + pEHSect->Fat.DataSize = COR_ILMETHOD_SECT_EH_FAT::Size(nClauses); - int curIdx = 0; - AppendEHClause(nClauses, pEHSect, pOne, &curIdx); - AppendEHClause(nClauses, pEHSect, pTwo, &curIdx); + int curIdx = 0; + AppendEHClause(nClauses, pEHSect, pOne, &curIdx); + AppendEHClause(nClauses, pEHSect, pTwo, &curIdx); + } } -#endif StubSigDesc::StubSigDesc(MethodDesc *pMD, PInvokeStaticSigInfo* pSigInfo /*= NULL*/) { @@ -936,6 +925,21 @@ class ILStubState : public StubState } + // + // Truncates a SString by first converting it to unicode and truncate it + // if it is larger than size. "..." will be appended if it is truncated. + // + void TruncateUnicodeString(SString &string, COUNT_T bufSize) + { + string.Normalize(); + if ((string.GetCount() + 1) * sizeof(WCHAR) > bufSize) + { + _ASSERTE(bufSize / sizeof(WCHAR) > 4); + string.Truncate(string.Begin() + bufSize / sizeof(WCHAR) - 4); + string.Append(W("...")); + } + } + //--------------------------------------------------------------------------------------- // void @@ -3660,6 +3664,8 @@ static void CreateNDirectStubWorker(StubState* pss, } #endif // TARGET_X86 + nativeStackSize = ALIGN_UP(nativeStackSize, TARGET_POINTER_SIZE); + if (!FitsInU2(nativeStackSize)) COMPlusThrow(kMarshalDirectiveException, IDS_EE_SIGTOOCOMPLEX); @@ -3764,255 +3770,300 @@ static void CreateStructStub(ILStubState* pss, pss->FinishEmit(pMD); } -class NDirectStubHashBlob : public ILStubHashBlobBase +namespace { -public: - Module* m_pModule; - MethodTable* m_pMT; + class NDirectStubParameters + { + public: + + NDirectStubParameters(Signature sig, + SigTypeContext* pTypeContext, + Module* pModule, + Module* pLoaderModule, + CorNativeLinkType nlType, + CorNativeLinkFlags nlFlags, + CorInfoCallConvExtension unmgdCallConv, + DWORD dwStubFlags, // NDirectStubFlags + int nParamTokens, + mdParamDef* pParamTokenArray, + int iLCIDArg, + MethodTable* pMT + ) : + m_sig(sig), + m_pTypeContext(pTypeContext), + m_pModule(pModule), + m_pLoaderModule(pLoaderModule), + m_pParamTokenArray(pParamTokenArray), + m_unmgdCallConv(unmgdCallConv), + m_nlType(nlType), + m_nlFlags(nlFlags), + m_dwStubFlags(dwStubFlags), + m_iLCIDArg(iLCIDArg), + m_nParamTokens(nParamTokens), + m_pMT(pMT) + { + LIMITED_METHOD_CONTRACT; + } + + Signature m_sig; + SigTypeContext* m_pTypeContext; + Module* m_pModule; + Module* m_pLoaderModule; + mdParamDef* m_pParamTokenArray; + CorInfoCallConvExtension m_unmgdCallConv; + CorNativeLinkType m_nlType; + CorNativeLinkFlags m_nlFlags; + DWORD m_dwStubFlags; + int m_iLCIDArg; + int m_nParamTokens; + MethodTable* m_pMT; + }; - WORD m_unmgdCallConv; - BYTE m_nlType; // C_ASSERTS are in NDirect::CreateHashBlob - BYTE m_nlFlags; + class NDirectStubHashBlob : public ILStubHashBlobBase + { + public: + Module* m_pModule; + MethodTable* m_pMT; - DWORD m_StubFlags; + WORD m_unmgdCallConv; + BYTE m_nlType; // C_ASSERTS are in NDirect::CreateHashBlob + BYTE m_nlFlags; - INT32 m_iLCIDArg; - INT32 m_nParams; - BYTE m_rgbSigAndParamData[1]; - // (dwParamAttr, cbNativeType) // length: number of parameters - // NativeTypeBlob // length: number of parameters - // BYTE m_rgbSigData[]; // length: determined by sig walk -}; + DWORD m_StubFlags; -// For better performance and less memory fragmentation, -// I'm using structure here to avoid allocating 3 different arrays. -struct ParamInfo -{ - DWORD dwParamAttr; - ULONG cbNativeType; - PCCOR_SIGNATURE pvNativeType; -}; + INT32 m_iLCIDArg; + INT32 m_nParams; + BYTE m_rgbSigAndParamData[1]; + // (dwParamAttr, cbNativeType) // length: number of parameters + // NativeTypeBlob // length: number of parameters + // BYTE m_rgbSigData[]; // length: determined by sig walk + }; -ILStubHashBlob* NDirect::CreateHashBlob(NDirectStubParameters* pParams) -{ - STANDARD_VM_CONTRACT; + // For better performance and less memory fragmentation, + // I'm using structure here to avoid allocating 3 different arrays. + struct ParamInfo + { + DWORD dwParamAttr; + ULONG cbNativeType; + PCCOR_SIGNATURE pvNativeType; + }; - NDirectStubHashBlob* pBlob; + ILStubHashBlob* CreateHashBlob(NDirectStubParameters* pParams) + { + STANDARD_VM_CONTRACT; - IMDInternalImport* pInternalImport = pParams->m_pModule->GetMDImport(); + NDirectStubHashBlob* pBlob; - CQuickBytes paramInfoBytes; - paramInfoBytes.AllocThrows(sizeof(ParamInfo)*pParams->m_nParamTokens); - ParamInfo *paramInfos = (ParamInfo *)paramInfoBytes.Ptr(); - ::ZeroMemory(paramInfos, sizeof(ParamInfo) * pParams->m_nParamTokens); + IMDInternalImport* pInternalImport = pParams->m_pModule->GetMDImport(); - size_t cbNativeTypeTotal = 0; + CQuickBytes paramInfoBytes; + paramInfoBytes.AllocThrows(sizeof(ParamInfo)*pParams->m_nParamTokens); + ParamInfo *paramInfos = (ParamInfo *)paramInfoBytes.Ptr(); + ::ZeroMemory(paramInfos, sizeof(ParamInfo) * pParams->m_nParamTokens); - // - // Collect information for function parameters - // - for (int idx = 0; idx < pParams->m_nParamTokens; idx++) - { - mdParamDef token = pParams->m_pParamTokenArray[idx]; - if (TypeFromToken(token) == mdtParamDef && mdParamDefNil != token) - { - USHORT usSequence_Ignore; // We don't need usSequence in the hash as the param array is already sorted - LPCSTR szParamName_Ignore; - IfFailThrow(pInternalImport->GetParamDefProps(token, &usSequence_Ignore, ¶mInfos[idx].dwParamAttr, &szParamName_Ignore)); + size_t cbNativeTypeTotal = 0; - if (paramInfos[idx].dwParamAttr & pdHasFieldMarshal) + // + // Collect information for function parameters + // + for (int idx = 0; idx < pParams->m_nParamTokens; idx++) + { + mdParamDef token = pParams->m_pParamTokenArray[idx]; + if (TypeFromToken(token) == mdtParamDef && mdParamDefNil != token) { - IfFailThrow(pInternalImport->GetFieldMarshal(token, ¶mInfos[idx].pvNativeType, ¶mInfos[idx].cbNativeType)); - cbNativeTypeTotal += paramInfos[idx].cbNativeType; + USHORT usSequence_Ignore; // We don't need usSequence in the hash as the param array is already sorted + LPCSTR szParamName_Ignore; + IfFailThrow(pInternalImport->GetParamDefProps(token, &usSequence_Ignore, ¶mInfos[idx].dwParamAttr, &szParamName_Ignore)); + + if (paramInfos[idx].dwParamAttr & pdHasFieldMarshal) + { + IfFailThrow(pInternalImport->GetFieldMarshal(token, ¶mInfos[idx].pvNativeType, ¶mInfos[idx].cbNativeType)); + cbNativeTypeTotal += paramInfos[idx].cbNativeType; + } } } - } - SigPointer sigPtr = pParams->m_sig.CreateSigPointer(); - - // note that ConvertToInternalSignature also resolves generics so different instantiations will get different - // hash blobs for methods that have generic parameters in their signature - SigBuilder sigBuilder; - sigPtr.ConvertToInternalSignature(pParams->m_pModule, pParams->m_pTypeContext, &sigBuilder, /* bSkipCustomModifier = */ FALSE); + SigPointer sigPtr = pParams->m_sig.CreateSigPointer(); - DWORD cbSig; - PVOID pSig = sigBuilder.GetSignature(&cbSig); + // note that ConvertToInternalSignature also resolves generics so different instantiations will get different + // hash blobs for methods that have generic parameters in their signature + SigBuilder sigBuilder; + sigPtr.ConvertToInternalSignature(pParams->m_pModule, pParams->m_pTypeContext, &sigBuilder, /* bSkipCustomModifier = */ FALSE); - // - // Build hash blob for IL stub sharing - // - S_SIZE_T cbSizeOfBlob = S_SIZE_T(offsetof(NDirectStubHashBlob, m_rgbSigAndParamData)) + - S_SIZE_T(sizeof(ULONG)) * S_SIZE_T(pParams->m_nParamTokens) + // Parameter attributes - S_SIZE_T(sizeof(DWORD)) * S_SIZE_T(pParams->m_nParamTokens) + // Native type blob size - S_SIZE_T(cbNativeTypeTotal) + // Native type blob data - S_SIZE_T(cbSig); // Signature + DWORD cbSig; + PVOID pSig = sigBuilder.GetSignature(&cbSig); - if (cbSizeOfBlob.IsOverflow()) - COMPlusThrowHR(COR_E_OVERFLOW); + // + // Build hash blob for IL stub sharing + // + S_SIZE_T cbSizeOfBlob = S_SIZE_T(offsetof(NDirectStubHashBlob, m_rgbSigAndParamData)) + + S_SIZE_T(sizeof(ULONG)) * S_SIZE_T(pParams->m_nParamTokens) + // Parameter attributes + S_SIZE_T(sizeof(DWORD)) * S_SIZE_T(pParams->m_nParamTokens) + // Native type blob size + S_SIZE_T(cbNativeTypeTotal) + // Native type blob data + S_SIZE_T(cbSig); // Signature - static_assert_no_msg(nltMaxValue <= 0xFF); - static_assert_no_msg(nlfMaxValue <= 0xFF); - static_assert_no_msg(pmMaxValue <= 0xFFFF); + if (cbSizeOfBlob.IsOverflow()) + COMPlusThrowHR(COR_E_OVERFLOW); - NewArrayHolder pBytes = new BYTE[cbSizeOfBlob.Value()]; - // zero out the hash bytes to ensure all bit fields are deterministically set - ZeroMemory(pBytes, cbSizeOfBlob.Value()); - pBlob = (NDirectStubHashBlob*)(BYTE*)pBytes; + static_assert_no_msg(nltMaxValue <= 0xFF); + static_assert_no_msg(nlfMaxValue <= 0xFF); + static_assert_no_msg(pmMaxValue <= 0xFFFF); - pBlob->m_pModule = NULL; + NewArrayHolder pBytes = new BYTE[cbSizeOfBlob.Value()]; + // zero out the hash bytes to ensure all bit fields are deterministically set + ZeroMemory(pBytes, cbSizeOfBlob.Value()); + pBlob = (NDirectStubHashBlob*)(BYTE*)pBytes; - if (SF_IsNGENedStub(pParams->m_dwStubFlags)) - { - // don't share across modules if we are ngening the stub - pBlob->m_pModule = pParams->m_pModule; - } + pBlob->m_pModule = NULL; - pBlob->m_pMT = pParams->m_pMT; - pBlob->m_cbSizeOfBlob = cbSizeOfBlob.Value(); - pBlob->m_unmgdCallConv = static_cast(pParams->m_unmgdCallConv); - pBlob->m_nlType = static_cast(pParams->m_nlType); - pBlob->m_nlFlags = static_cast(pParams->m_nlFlags & ~nlfNoMangle); // this flag does not affect the stub - pBlob->m_iLCIDArg = pParams->m_iLCIDArg; + if (SF_IsNGENedStub(pParams->m_dwStubFlags)) + { + // don't share across modules if we are ngening the stub + pBlob->m_pModule = pParams->m_pModule; + } - pBlob->m_StubFlags = pParams->m_dwStubFlags; - pBlob->m_nParams = pParams->m_nParamTokens; + pBlob->m_pMT = pParams->m_pMT; + pBlob->m_cbSizeOfBlob = cbSizeOfBlob.Value(); + pBlob->m_unmgdCallConv = static_cast(pParams->m_unmgdCallConv); + pBlob->m_nlType = static_cast(pParams->m_nlType); + pBlob->m_nlFlags = static_cast(pParams->m_nlFlags & ~nlfNoMangle); // this flag does not affect the stub + pBlob->m_iLCIDArg = pParams->m_iLCIDArg; - BYTE* pBlobParams = &pBlob->m_rgbSigAndParamData[0]; + pBlob->m_StubFlags = pParams->m_dwStubFlags; + pBlob->m_nParams = pParams->m_nParamTokens; - // - // Write (dwParamAttr, cbNativeType) for parameters - // - // Note that these need to be aligned and it is why they are written before the byte blobs - // I'm putting asserts here so that it will assert even in non-IA64 platforms to catch bugs - // - _ASSERTE((DWORD_PTR)pBlobParams % sizeof(DWORD) == 0); - _ASSERTE(sizeof(DWORD) == sizeof(ULONG)); + BYTE* pBlobParams = &pBlob->m_rgbSigAndParamData[0]; - for (int i = 0; i < pParams->m_nParamTokens; ++i) - { - // We only care about In/Out/HasFieldMarshal - // Other attr are about optional/default values which are not used in marshalling, - // but only used in compilers - *((DWORD *)pBlobParams) = paramInfos[i].dwParamAttr & (pdIn | pdOut | pdHasFieldMarshal); - pBlobParams += sizeof(DWORD); + // + // Write (dwParamAttr, cbNativeType) for parameters + // + // Note that these need to be aligned and it is why they are written before the byte blobs + // I'm putting asserts here so that it will assert even in non-IA64 platforms to catch bugs + // + _ASSERTE((DWORD_PTR)pBlobParams % sizeof(DWORD) == 0); + _ASSERTE(sizeof(DWORD) == sizeof(ULONG)); - *((ULONG *)pBlobParams) = paramInfos[i].cbNativeType; - pBlobParams += sizeof(ULONG); - } + for (int i = 0; i < pParams->m_nParamTokens; ++i) + { + // We only care about In/Out/HasFieldMarshal + // Other attr are about optional/default values which are not used in marshalling, + // but only used in compilers + *((DWORD *)pBlobParams) = paramInfos[i].dwParamAttr & (pdIn | pdOut | pdHasFieldMarshal); + pBlobParams += sizeof(DWORD); - // - // Write native type blob for parameters - // - for (int i = 0; i < pParams->m_nParamTokens; ++i) - { - memcpy(pBlobParams, paramInfos[i].pvNativeType, paramInfos[i].cbNativeType); - pBlobParams += paramInfos[i].cbNativeType; - } + *((ULONG *)pBlobParams) = paramInfos[i].cbNativeType; + pBlobParams += sizeof(ULONG); + } - // - // Copy signature - // - memcpy(pBlobParams, pSig, cbSig); + // + // Write native type blob for parameters + // + for (int i = 0; i < pParams->m_nParamTokens; ++i) + { + memcpy(pBlobParams, paramInfos[i].pvNativeType, paramInfos[i].cbNativeType); + pBlobParams += paramInfos[i].cbNativeType; + } - // Verify that we indeed have reached the end - _ASSERTE(pBlobParams + cbSig == (BYTE *)pBlob + cbSizeOfBlob.Value()); + // + // Copy signature + // + memcpy(pBlobParams, pSig, cbSig); - pBytes.SuppressRelease(); - return (ILStubHashBlob*)pBlob; -} + // Verify that we indeed have reached the end + _ASSERTE(pBlobParams + cbSig == (BYTE *)pBlob + cbSizeOfBlob.Value()); -// static inline -ILStubCache* NDirect::GetILStubCache(NDirectStubParameters* pParams) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; + pBytes.SuppressRelease(); + return (ILStubHashBlob*)pBlob; } - CONTRACTL_END; - // Use the m_pLoaderModule instead of m_pModule - // They could be different for methods on generic types. - return pParams->m_pLoaderModule->GetILStubCache(); -} - -// static -MethodDesc* NDirect::GetStubMethodDesc( - MethodDesc *pTargetMD, - NDirectStubParameters* pParams, - ILStubHashBlob* pHashParams, - AllocMemTracker* pamTracker, - bool& bILStubCreator, - MethodDesc* pLastMD) -{ - CONTRACT(MethodDesc*) + ILStubCache* GetILStubCache(NDirectStubParameters* pParams) { - STANDARD_VM_CHECK; + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; - PRECONDITION(CheckPointer(pParams)); - PRECONDITION(!pParams->m_sig.IsEmpty()); - PRECONDITION(CheckPointer(pParams->m_pModule)); - PRECONDITION(CheckPointer(pTargetMD, NULL_OK)); - POSTCONDITION(CheckPointer(RETVAL)); + // Use the m_pLoaderModule instead of m_pModule + // They could be different for methods on generic types. + return pParams->m_pLoaderModule->GetILStubCache(); } - CONTRACT_END; - MethodDesc* pMD; + MethodDesc* GetStubMethodDesc( + MethodDesc *pTargetMD, + NDirectStubParameters* pParams, + ILStubHashBlob* pHashParams, + AllocMemTracker* pamTracker, + bool& bILStubCreator, + MethodDesc* pLastMD) + { + CONTRACT(MethodDesc*) + { + STANDARD_VM_CHECK; + + PRECONDITION(CheckPointer(pParams)); + PRECONDITION(!pParams->m_sig.IsEmpty()); + PRECONDITION(CheckPointer(pParams->m_pModule)); + PRECONDITION(CheckPointer(pTargetMD, NULL_OK)); + POSTCONDITION(CheckPointer(RETVAL)); + } + CONTRACT_END; - ILStubCache* pCache = NDirect::GetILStubCache(pParams); + MethodDesc* pMD; - pMD = pCache->GetStubMethodDesc(pTargetMD, - pHashParams, - pParams->m_dwStubFlags, - pParams->m_pModule, - pParams->m_sig.GetRawSig(), - pParams->m_sig.GetRawSigLen(), - pamTracker, - bILStubCreator, - pLastMD); + ILStubCache* pCache = GetILStubCache(pParams); - RETURN pMD; -} + pMD = pCache->GetStubMethodDesc(pTargetMD, + pHashParams, + pParams->m_dwStubFlags, + pParams->m_pModule, + pParams->m_sig.GetRawSig(), + pParams->m_sig.GetRawSigLen(), + pamTracker, + bILStubCreator, + pLastMD); + RETURN pMD; + } -// static -void NDirect::RemoveILStubCacheEntry(NDirectStubParameters* pParams, ILStubHashBlob* pHashParams) -{ - CONTRACTL + void RemoveILStubCacheEntry(NDirectStubParameters* pParams, ILStubHashBlob* pHashParams) { - STANDARD_VM_CHECK; + CONTRACTL + { + STANDARD_VM_CHECK; - PRECONDITION(CheckPointer(pParams)); - PRECONDITION(CheckPointer(pHashParams)); - PRECONDITION(!pParams->m_sig.IsEmpty()); - PRECONDITION(CheckPointer(pParams->m_pModule)); - } - CONTRACTL_END; + PRECONDITION(CheckPointer(pParams)); + PRECONDITION(CheckPointer(pHashParams)); + PRECONDITION(!pParams->m_sig.IsEmpty()); + PRECONDITION(CheckPointer(pParams->m_pModule)); + } + CONTRACTL_END; - LOG((LF_STUBS, LL_INFO1000, "Exception happened when generating IL of stub clr!CreateInteropILStub StubMD: %p, HashBlob: %p \n", pParams, pHashParams)); + LOG((LF_STUBS, LL_INFO1000, "Exception happened when generating IL of stub clr!CreateInteropILStub StubMD: %p, HashBlob: %p \n", pParams, pHashParams)); - ILStubCache* pCache = NDirect::GetILStubCache(pParams); + ILStubCache* pCache = GetILStubCache(pParams); - pCache->DeleteEntry(pHashParams); -} + pCache->DeleteEntry(pHashParams); + } -// static -void NDirect::AddMethodDescChunkWithLockTaken(NDirectStubParameters* pParams, MethodDesc *pMD) -{ - CONTRACTL + void AddMethodDescChunkWithLockTaken(NDirectStubParameters* pParams, MethodDesc *pMD) { - STANDARD_VM_CHECK; + CONTRACTL + { + STANDARD_VM_CHECK; - PRECONDITION(CheckPointer(pParams)); - PRECONDITION(!pParams->m_sig.IsEmpty()); - PRECONDITION(CheckPointer(pParams->m_pModule)); - } - CONTRACTL_END; + PRECONDITION(CheckPointer(pParams)); + PRECONDITION(!pParams->m_sig.IsEmpty()); + PRECONDITION(CheckPointer(pParams->m_pModule)); + } + CONTRACTL_END; - ILStubCache* pCache = NDirect::GetILStubCache(pParams); + ILStubCache* pCache = GetILStubCache(pParams); - pCache->AddMethodDescChunkWithLockTaken(pMD); + pCache->AddMethodDescChunkWithLockTaken(pMD); + } } // @@ -4441,326 +4492,420 @@ HRESULT FindPredefinedILStubMethod(MethodDesc *pTargetMD, DWORD dwStubFlags, Met } #endif // FEATURE_COMINTEROP -MethodDesc* CreateInteropILStub( - ILStubState* pss, - StubSigDesc* pSigDesc, - CorNativeLinkType nlType, - CorNativeLinkFlags nlFlags, - CorInfoCallConvExtension unmgdCallConv, - int nParamTokens, - mdParamDef* pParamTokenArray, - int iLCIDArg, - bool* pGeneratedNewStub = nullptr - ) +namespace { - CONTRACT(MethodDesc*) + //======================================================================= + // ILStubCreatorHelper + // The class is used as a helper class in CreateInteropILStub. It mainly + // puts two methods NDirect::GetStubMethodDesc and NDirect::RemoveILStubCacheEntry + // into a holder. See CreateInteropILStub for more information + //======================================================================= + class ILStubCreatorHelper + { + public: + ILStubCreatorHelper(MethodDesc *pTargetMD, + NDirectStubParameters* pParams + ) : + m_pTargetMD(pTargetMD), + m_pParams(pParams), + m_pStubMD(NULL), + m_bILStubCreator(false) + { + STANDARD_VM_CONTRACT; + m_pHashParams = CreateHashBlob(m_pParams); + } + + ~ILStubCreatorHelper() + { + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + } + CONTRACTL_END; + + RemoveILStubCacheEntry(); + } + + inline void GetStubMethodDesc() + { + WRAPPER_NO_CONTRACT; + + m_pStubMD = ::GetStubMethodDesc(m_pTargetMD, m_pParams, m_pHashParams, &m_amTracker, m_bILStubCreator, m_pStubMD); + } + + inline void RemoveILStubCacheEntry() + { + WRAPPER_NO_CONTRACT; + + if (m_bILStubCreator) + { + ::RemoveILStubCacheEntry(m_pParams, m_pHashParams); + m_bILStubCreator = false; + } + } + + inline MethodDesc* GetStubMD() + { + LIMITED_METHOD_CONTRACT; + return m_pStubMD; + } + + inline void SuppressRelease() + { + WRAPPER_NO_CONTRACT; + m_bILStubCreator = false; + m_amTracker.SuppressRelease(); + } + + DEBUG_NOINLINE static void HolderEnter(ILStubCreatorHelper *pThis) + { + WRAPPER_NO_CONTRACT; + ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT; + pThis->GetStubMethodDesc(); + } + + DEBUG_NOINLINE static void HolderLeave(ILStubCreatorHelper *pThis) + { + WRAPPER_NO_CONTRACT; + ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT; + pThis->RemoveILStubCacheEntry(); + } + + private: + MethodDesc* m_pTargetMD; + NDirectStubParameters* m_pParams; + NewArrayHolder m_pHashParams; + AllocMemTracker* m_pAmTracker; + MethodDesc* m_pStubMD; + AllocMemTracker m_amTracker; + bool m_bILStubCreator; // Only the creator can remove the ILStub from the Cache + }; //ILStubCreatorHelper + + typedef Wrapper ILStubCreatorHelperHolder; + + MethodDesc* CreateInteropILStub( + ILStubState* pss, + StubSigDesc* pSigDesc, + CorNativeLinkType nlType, + CorNativeLinkFlags nlFlags, + CorInfoCallConvExtension unmgdCallConv, + int nParamTokens, + mdParamDef* pParamTokenArray, + int iLCIDArg, + bool* pGeneratedNewStub = nullptr + ) { - STANDARD_VM_CHECK; + CONTRACT(MethodDesc*) + { + STANDARD_VM_CHECK; - PRECONDITION(CheckPointer(pSigDesc)); - POSTCONDITION(CheckPointer(RETVAL)); - } - CONTRACT_END; + PRECONDITION(CheckPointer(pSigDesc)); + POSTCONDITION(CheckPointer(RETVAL)); + } + CONTRACT_END; - /////////////////////////////// - // - // MethodDesc creation - // - /////////////////////////////// + /////////////////////////////// + // + // MethodDesc creation + // + /////////////////////////////// - MethodDesc* pStubMD = NULL; + MethodDesc* pStubMD = NULL; - Module* pModule = pSigDesc->m_pModule; - Module* pLoaderModule = pSigDesc->m_pLoaderModule; - MethodDesc* pTargetMD = pSigDesc->m_pMD; - MethodTable* pTargetMT = pSigDesc->m_pMT; - // - // pTargetMD may be null in the case of calli pinvoke - // and vararg pinvoke. - // + Module* pModule = pSigDesc->m_pModule; + Module* pLoaderModule = pSigDesc->m_pLoaderModule; + MethodDesc* pTargetMD = pSigDesc->m_pMD; + MethodTable* pTargetMT = pSigDesc->m_pMT; + // + // pTargetMD may be null in the case of calli pinvoke + // and vararg pinvoke. + // - DWORD dwStubFlags = pss->GetFlags(); + DWORD dwStubFlags = pss->GetFlags(); #ifdef FEATURE_COMINTEROP - // - // Try to locate predefined IL stub either defined in user code or hardcoded in CLR - // If there is one, use the pointed method as the stub. - // Skip pTargetMD == NULL case for reverse interop calls - // - if (pTargetMD && SUCCEEDED(FindPredefinedILStubMethod(pTargetMD, dwStubFlags, &pStubMD))) - { + // + // Try to locate predefined IL stub either defined in user code or hardcoded in CLR + // If there is one, use the pointed method as the stub. + // Skip pTargetMD == NULL case for reverse interop calls + // + if (pTargetMD && SUCCEEDED(FindPredefinedILStubMethod(pTargetMD, dwStubFlags, &pStubMD))) + { #ifndef CROSSGEN_COMPILE - // We are about to execute method in pStubMD which could be in another module. - // Call EnsureActive before make the call - // This cannot be done during NGEN/PEVerify (in PASSIVE_DOMAIN) so I've moved it here - pStubMD->EnsureActive(); + // We are about to execute method in pStubMD which could be in another module. + // Call EnsureActive before make the call + // This cannot be done during NGEN/PEVerify (in PASSIVE_DOMAIN) so I've moved it here + pStubMD->EnsureActive(); - if (pStubMD->IsPreImplemented()) - RestoreNGENedStub(pStubMD); + if (pStubMD->IsPreImplemented()) + RestoreNGENedStub(pStubMD); #endif - RETURN pStubMD; - } + RETURN pStubMD; + } #endif // FEATURE_COMINTEROP - // Otherwise, fall back to generating IL stub on-the-fly - NDirectStubParameters params(pSigDesc->m_sig, - &pSigDesc->m_typeContext, - pModule, - pLoaderModule, - nlType, - nlFlags, - unmgdCallConv, - dwStubFlags, - nParamTokens, - pParamTokenArray, - iLCIDArg, - pSigDesc->m_pMT - ); - - // The following two ILStubCreatorHelperHolder are to recover the status when an - // exception happen during the generation of the IL stubs. We need to free the - // memory allocated and restore the ILStubCache. - // - // The following block is logically divided into two phases. The first phase is - // CreateOrGet IL Stub phase which we take a domain level lock. The second phase - // is IL generation phase which we take a MethodDesc level lock. Taking two locks - // is mainly designed for performance. - // - // ilStubCreatorHelper contains an instance of AllocMemTracker which tracks the - // allocated memory during the creation of MethodDesc so that we are able to remove - // them when releasing the ILStubCreatorHelperHolder or destructing ILStubCreatorHelper - - // When removing IL Stub from Cache, we have a constraint that only the thread which - // creates the stub can remove it. Otherwise, any thread hits cache and gets the stub will - // remove it from cache if OOM occurs + // Otherwise, fall back to generating IL stub on-the-fly + NDirectStubParameters params(pSigDesc->m_sig, + &pSigDesc->m_typeContext, + pModule, + pLoaderModule, + nlType, + nlFlags, + unmgdCallConv, + dwStubFlags, + nParamTokens, + pParamTokenArray, + iLCIDArg, + pSigDesc->m_pMT + ); - { - ILStubCreatorHelper ilStubCreatorHelper(pTargetMD, ¶ms); + // The following two ILStubCreatorHelperHolder are to recover the status when an + // exception happen during the generation of the IL stubs. We need to free the + // memory allocated and restore the ILStubCache. + // + // The following block is logically divided into two phases. The first phase is + // CreateOrGet IL Stub phase which we take a domain level lock. The second phase + // is IL generation phase which we take a MethodDesc level lock. Taking two locks + // is mainly designed for performance. + // + // ilStubCreatorHelper contains an instance of AllocMemTracker which tracks the + // allocated memory during the creation of MethodDesc so that we are able to remove + // them when releasing the ILStubCreatorHelperHolder or destructing ILStubCreatorHelper - // take the domain level lock - ListLockHolder pILStubLock(pLoaderModule->GetDomain()->GetILStubGenLock()); + // When removing IL Stub from Cache, we have a constraint that only the thread which + // creates the stub can remove it. Otherwise, any thread hits cache and gets the stub will + // remove it from cache if OOM occurs { - // The holder will free the allocated MethodDesc and restore the ILStubCache - // if exception happen. - ILStubCreatorHelperHolder pCreateOrGetStubHolder(&ilStubCreatorHelper); - pStubMD = pCreateOrGetStubHolder->GetStubMD(); + ILStubCreatorHelper ilStubCreatorHelper(pTargetMD, ¶ms); - /////////////////////////////// - // - // IL generation - // - /////////////////////////////// + // take the domain level lock + ListLockHolder pILStubLock(pLoaderModule->GetDomain()->GetILStubGenLock()); { - // take the MethodDesc level locker - ListLockEntryHolder pEntry(ListLockEntry::Find(pILStubLock, pStubMD, "il stub gen lock")); + // The holder will free the allocated MethodDesc and restore the ILStubCache + // if exception happen. + ILStubCreatorHelperHolder pCreateOrGetStubHolder(&ilStubCreatorHelper); + pStubMD = pCreateOrGetStubHolder->GetStubMD(); - ListLockEntryLockHolder pEntryLock(pEntry, FALSE); + /////////////////////////////// + // + // IL generation + // + /////////////////////////////// - // We can release the holder for the first phase now - pCreateOrGetStubHolder.SuppressRelease(); + { + // take the MethodDesc level locker + ListLockEntryHolder pEntry(ListLockEntry::Find(pILStubLock, pStubMD, "il stub gen lock")); - // We have the entry lock we need to use, so we can release the global lock. - pILStubLock.Release(); + ListLockEntryLockHolder pEntryLock(pEntry, FALSE); - { - // The holder will free the allocated MethodDesc and restore the ILStubCache - // if exception happen. The reason to get the holder again is to - ILStubCreatorHelperHolder pGenILHolder(&ilStubCreatorHelper); + // We can release the holder for the first phase now + pCreateOrGetStubHolder.SuppressRelease(); - if (!pEntryLock.DeadlockAwareAcquire()) - { - // the IL generation is not recursive. - // However, we can encounter a recursive situation when attempting to - // marshal a struct containing a layout class containing another struct. - // Throw an exception here instead of asserting. - if (SF_IsStructMarshalStub(dwStubFlags)) - { - _ASSERTE(pSigDesc->m_pMT != nullptr); - StackSString strTypeName; - TypeString::AppendType(strTypeName, TypeHandle(pSigDesc->m_pMT)); - COMPlusThrow(kTypeLoadException, IDS_CANNOT_MARSHAL_RECURSIVE_DEF, strTypeName.GetUnicode()); - } - UNREACHABLE_MSG("unexpected deadlock in IL stub generation!"); - } + // We have the entry lock we need to use, so we can release the global lock. + pILStubLock.Release(); - if (SF_IsSharedStub(params.m_dwStubFlags)) { - // We need to re-acquire the lock in case we need to get a new pStubMD - // in the case that the owner of the shared stub was destroyed. - pILStubLock.Acquire(); + // The holder will free the allocated MethodDesc and restore the ILStubCache + // if exception happen. The reason to get the holder again is to + ILStubCreatorHelperHolder pGenILHolder(&ilStubCreatorHelper); - // Assure that pStubMD we have now has not been destroyed by other threads - pGenILHolder->GetStubMethodDesc(); - - while (pStubMD != pGenILHolder->GetStubMD()) + if (!pEntryLock.DeadlockAwareAcquire()) { - pStubMD = pGenILHolder->GetStubMD(); - - pEntry.Assign(ListLockEntry::Find(pILStubLock, pStubMD, "il stub gen lock")); - pEntryLock.Assign(pEntry, FALSE); - - // We have the entry lock we need to use, so we can release the global lock. - pILStubLock.Release(); - - if (!pEntryLock.DeadlockAwareAcquire()) + // the IL generation is not recursive. + // However, we can encounter a recursive situation when attempting to + // marshal a struct containing a layout class containing another struct. + // Throw an exception here instead of asserting. + if (SF_IsStructMarshalStub(dwStubFlags)) { - // the IL generation is not recursive. - // However, we can encounter a recursive situation when attempting to - // marshal a struct containing a layout class containing another struct. - // Throw an exception here instead of asserting. - if (SF_IsStructMarshalStub(dwStubFlags)) - { - _ASSERTE(pSigDesc->m_pMT != nullptr); - StackSString strTypeName; - TypeString::AppendType(strTypeName, TypeHandle(pSigDesc->m_pMT)); - COMPlusThrow(kTypeLoadException, IDS_CANNOT_MARSHAL_RECURSIVE_DEF, strTypeName.GetUnicode()); - } - UNREACHABLE_MSG("unexpected deadlock in IL stub generation!"); + _ASSERTE(pSigDesc->m_pMT != nullptr); + StackSString strTypeName; + TypeString::AppendType(strTypeName, TypeHandle(pSigDesc->m_pMT)); + COMPlusThrow(kTypeLoadException, IDS_CANNOT_MARSHAL_RECURSIVE_DEF, strTypeName.GetUnicode()); } + UNREACHABLE_MSG("unexpected deadlock in IL stub generation!"); + } + if (SF_IsSharedStub(params.m_dwStubFlags)) + { + // We need to re-acquire the lock in case we need to get a new pStubMD + // in the case that the owner of the shared stub was destroyed. pILStubLock.Acquire(); + // Assure that pStubMD we have now has not been destroyed by other threads pGenILHolder->GetStubMethodDesc(); - } - } - for (;;) - { - // We have the entry lock now, we can release the global lock - pILStubLock.Release(); + while (pStubMD != pGenILHolder->GetStubMD()) + { + pStubMD = pGenILHolder->GetStubMD(); - _ASSERTE(pEntryLock.GetValue()->HasLock()); + pEntry.Assign(ListLockEntry::Find(pILStubLock, pStubMD, "il stub gen lock")); + pEntryLock.Assign(pEntry, FALSE); - if (pEntry->m_hrResultCode != S_FALSE) - { - // We came in to generate the IL but someone - // beat us so there's nothing to do - break; - } + // We have the entry lock we need to use, so we can release the global lock. + pILStubLock.Release(); - ILStubResolver* pResolver = pStubMD->AsDynamicMethodDesc()->GetILStubResolver(); + if (!pEntryLock.DeadlockAwareAcquire()) + { + // the IL generation is not recursive. + // However, we can encounter a recursive situation when attempting to + // marshal a struct containing a layout class containing another struct. + // Throw an exception here instead of asserting. + if (SF_IsStructMarshalStub(dwStubFlags)) + { + _ASSERTE(pSigDesc->m_pMT != nullptr); + StackSString strTypeName; + TypeString::AppendType(strTypeName, TypeHandle(pSigDesc->m_pMT)); + COMPlusThrow(kTypeLoadException, IDS_CANNOT_MARSHAL_RECURSIVE_DEF, strTypeName.GetUnicode()); + } + UNREACHABLE_MSG("unexpected deadlock in IL stub generation!"); + } - CONSISTENCY_CHECK((NULL == pResolver->GetStubMethodDesc()) || (pStubMD == pResolver->GetStubMethodDesc())); + pILStubLock.Acquire(); - if (pResolver->IsILGenerated()) - { - // this stub already has its IL generated - break; + pGenILHolder->GetStubMethodDesc(); + } } - // - // Check that the stub signature and MethodDesc are compatible. The JIT - // interface functions depend on this. - // - + for (;;) { - SigPointer ptr = pSigDesc->m_sig.CreateSigPointer(); - - uint32_t callConvInfo; - IfFailThrow(ptr.GetCallingConvInfo(&callConvInfo)); - - BOOL fSigIsStatic = !(callConvInfo & IMAGE_CEE_CS_CALLCONV_HASTHIS); + // We have the entry lock now, we can release the global lock + pILStubLock.Release(); - // CreateNDirectStubWorker will throw an exception for these cases. - BOOL fCanHaveThis = SF_IsDelegateStub(dwStubFlags) || SF_IsCOMStub(dwStubFlags); + _ASSERTE(pEntryLock.GetValue()->HasLock()); - if (fSigIsStatic || fCanHaveThis) + if (pEntry->m_hrResultCode != S_FALSE) { - CONSISTENCY_CHECK(pStubMD->IsStatic() == (DWORD)fSigIsStatic); + // We came in to generate the IL but someone + // beat us so there's nothing to do + break; } - } - { - ILStubGenHolder sgh(pResolver); + ILStubResolver* pResolver = pStubMD->AsDynamicMethodDesc()->GetILStubResolver(); - pResolver->SetStubMethodDesc(pStubMD); - pResolver->SetStubTargetMethodDesc(pTargetMD); + CONSISTENCY_CHECK((NULL == pResolver->GetStubMethodDesc()) || (pStubMD == pResolver->GetStubMethodDesc())); - if (SF_IsStructMarshalStub(dwStubFlags)) + if (pResolver->IsILGenerated()) { - CreateStructStub(pss, pSigDesc, pTargetMT, dwStubFlags, pStubMD); - } - else - { - CreateNDirectStubWorker(pss, - pSigDesc, - nlType, - nlFlags, - unmgdCallConv, - dwStubFlags, - pStubMD, - pParamTokenArray, - iLCIDArg); + // this stub already has its IL generated + break; } + // + // Check that the stub signature and MethodDesc are compatible. The JIT + // interface functions depend on this. + // - pResolver->SetTokenLookupMap(pss->GetTokenLookupMap()); + { + SigPointer ptr = pSigDesc->m_sig.CreateSigPointer(); - pResolver->SetStubTargetMethodSig( - pss->GetStubTargetMethodSig(), - pss->GetStubTargetMethodSigLength()); + uint32_t callConvInfo; + IfFailThrow(ptr.GetCallingConvInfo(&callConvInfo)); - // we successfully generated the IL stub - sgh.SuppressRelease(); - } + BOOL fSigIsStatic = !(callConvInfo & IMAGE_CEE_CS_CALLCONV_HASTHIS); - if (pGeneratedNewStub) - { - *pGeneratedNewStub = true; - } + // CreateNDirectStubWorker will throw an exception for these cases. + BOOL fCanHaveThis = SF_IsDelegateStub(dwStubFlags) || SF_IsCOMStub(dwStubFlags); - pEntry->m_hrResultCode = S_OK; - break; - } + if (fSigIsStatic || fCanHaveThis) + { + CONSISTENCY_CHECK(pStubMD->IsStatic() == (DWORD)fSigIsStatic); + } + } - // Link the MethodDesc onto the method table with the lock taken - NDirect::AddMethodDescChunkWithLockTaken(¶ms, pStubMD); + { + ILStubGenHolder sgh(pResolver); - pGenILHolder.SuppressRelease(); - } + pResolver->SetStubMethodDesc(pStubMD); + pResolver->SetStubTargetMethodDesc(pTargetMD); + + if (SF_IsStructMarshalStub(dwStubFlags)) + { + CreateStructStub(pss, pSigDesc, pTargetMT, dwStubFlags, pStubMD); + } + else + { + CreateNDirectStubWorker(pss, + pSigDesc, + nlType, + nlFlags, + unmgdCallConv, + dwStubFlags, + pStubMD, + pParamTokenArray, + iLCIDArg); + } + + + pResolver->SetTokenLookupMap(pss->GetTokenLookupMap()); + + pResolver->SetStubTargetMethodSig( + pss->GetStubTargetMethodSig(), + pss->GetStubTargetMethodSigLength()); + + // we successfully generated the IL stub + sgh.SuppressRelease(); + } + + if (pGeneratedNewStub) + { + *pGeneratedNewStub = true; + } + + pEntry->m_hrResultCode = S_OK; + break; + } + + // Link the MethodDesc onto the method table with the lock taken + AddMethodDescChunkWithLockTaken(¶ms, pStubMD); + + pGenILHolder.SuppressRelease(); + } + } } + ilStubCreatorHelper.SuppressRelease(); } - ilStubCreatorHelper.SuppressRelease(); - } #if defined(TARGET_X86) - if (SF_IsForwardStub(dwStubFlags) && pTargetMD != NULL && !pTargetMD->IsVarArg()) - { - // copy the stack arg byte count from the stub MD to the target MD - this number is computed - // during stub generation and is copied to all target MDs that share the stub - // (we don't set it for varargs - the number is call site specific) - // also copy the "takes parameters with copy constructors" flag which is needed to generate - // appropriate intercept stub - - WORD cbStackArgSize = pStubMD->AsDynamicMethodDesc()->GetNativeStackArgSize(); - if (pTargetMD->IsNDirect()) + if (SF_IsForwardStub(dwStubFlags) && pTargetMD != NULL && !pTargetMD->IsVarArg()) { - NDirectMethodDesc *pTargetNMD = (NDirectMethodDesc *)pTargetMD; + // copy the stack arg byte count from the stub MD to the target MD - this number is computed + // during stub generation and is copied to all target MDs that share the stub + // (we don't set it for varargs - the number is call site specific) + // also copy the "takes parameters with copy constructors" flag which is needed to generate + // appropriate intercept stub - pTargetNMD->SetStackArgumentSize(cbStackArgSize, MetaSig::GetDefaultUnmanagedCallingConvention()); - } -#ifdef FEATURE_COMINTEROP - else - { - if (SF_IsCOMStub(dwStubFlags)) + WORD cbStackArgSize = pStubMD->AsDynamicMethodDesc()->GetNativeStackArgSize(); + if (pTargetMD->IsNDirect()) { - ComPlusCallInfo *pComInfo = ComPlusCallInfo::FromMethodDesc(pTargetMD); + NDirectMethodDesc *pTargetNMD = (NDirectMethodDesc *)pTargetMD; - if (pComInfo != NULL) + pTargetNMD->SetStackArgumentSize(cbStackArgSize, MetaSig::GetDefaultUnmanagedCallingConvention()); + } +#ifdef FEATURE_COMINTEROP + else + { + if (SF_IsCOMStub(dwStubFlags)) { - pComInfo->SetStackArgumentSize(cbStackArgSize); + ComPlusCallInfo *pComInfo = ComPlusCallInfo::FromMethodDesc(pTargetMD); + + if (pComInfo != NULL) + { + pComInfo->SetStackArgumentSize(cbStackArgSize); + } } } - } #endif // FEATURE_COMINTEROP - } + } #endif // defined(TARGET_X86) - RETURN pStubMD; + RETURN pStubMD; + } } MethodDesc* NDirect::CreateCLRToNativeILStub( @@ -5122,6 +5267,102 @@ MethodDesc* GetStubMethodDescFromInteropMethodDesc(MethodDesc* pMD, DWORD dwStub #ifndef CROSSGEN_COMPILE +namespace +{ + LPVOID NDirectGetEntryPoint(NDirectMethodDesc *pMD, NATIVE_LIBRARY_HANDLE hMod) + { + // GetProcAddress cannot be called while preemptive GC is disabled. + // It requires the OS to take the loader lock. + CONTRACT(LPVOID) + { + STANDARD_VM_CHECK; + PRECONDITION(CheckPointer(pMD)); + POSTCONDITION(CheckPointer(RETVAL, NULL_OK)); + } + CONTRACT_END; + + g_IBCLogger.LogNDirectCodeAccess(pMD); + + RETURN pMD->FindEntryPoint(hMod); + } + + //--------------------------------------------------------- + // Loads the DLL and finds the procaddress for an N/Direct call. + //--------------------------------------------------------- + VOID NDirectLink(NDirectMethodDesc *pMD) + { + CONTRACTL + { + STANDARD_VM_CHECK; + PRECONDITION(CheckPointer(pMD)); + } + CONTRACTL_END; + + if (pMD->IsClassConstructorTriggeredAtLinkTime()) + { + pMD->GetMethodTable()->CheckRunClassInitThrowing(); + } + + if (pMD->IsQCall()) + { + LPVOID pvTarget = pMD->ndirect.m_pNativeNDirectTarget; + + // Do not repeat the lookup if the QCall was hardbound during ngen + if (pvTarget == NULL) + { + pvTarget = ECall::GetQCallImpl(pMD); + } + else + { + _ASSERTE(pvTarget == ECall::GetQCallImpl(pMD)); + } + + pMD->SetNDirectTarget(pvTarget); + return; + } + + // Loading unmanaged dlls can trigger dllmains which certainly count as code execution! + pMD->EnsureActive(); + + { + LPVOID pvTarget = (LPVOID)PInvokeOverride::GetMethodImpl(pMD->GetLibNameRaw(), pMD->GetEntrypointName()); + if (pvTarget != NULL) + { + pMD->SetNDirectTarget(pvTarget); + return; + } + } + + NATIVE_LIBRARY_HANDLE hmod = NativeLibrary::LoadLibraryFromMethodDesc(pMD); + _ASSERTE(hmod != NULL); + + BOOL fSuccess = FALSE; + LPVOID pvTarget = NDirectGetEntryPoint(pMD, hmod); + if (pvTarget) + { + pMD->SetNDirectTarget(pvTarget); + fSuccess = TRUE; + } + + if (!fSuccess) + { + StackSString ssLibName(SString::Utf8, pMD->GetLibName()); + + WCHAR wszEPName[50]; + if (WszMultiByteToWideChar(CP_UTF8, 0, (LPCSTR)pMD->GetEntrypointName(), -1, wszEPName, sizeof(wszEPName)/sizeof(WCHAR)) == 0) + { + wszEPName[0] = W('?'); + wszEPName[1] = W('\0'); + } +#ifdef TARGET_UNIX + COMPlusThrow(kEntryPointNotFoundException, IDS_EE_NDIRECT_GETPROCADDRESS_UNIX, ssLibName.GetUnicode(), wszEPName); +#else + COMPlusThrow(kEntryPointNotFoundException, IDS_EE_NDIRECT_GETPROCADDRESS_WIN, ssLibName.GetUnicode(), wszEPName); +#endif + } + } +} + PCODE NDirect::GetStubForILStub(MethodDesc* pManagedMD, MethodDesc** ppStubMD, DWORD dwStubFlags) { CONTRACT(PCODE) @@ -5424,24 +5665,6 @@ void CreateCLRToDispatchCOMStub( #endif // FEATURE_COMINTEROP -/*static*/ -LPVOID NDirect::NDirectGetEntryPoint(NDirectMethodDesc *pMD, NATIVE_LIBRARY_HANDLE hMod) -{ - // GetProcAddress cannot be called while preemptive GC is disabled. - // It requires the OS to take the loader lock. - CONTRACT(LPVOID) - { - STANDARD_VM_CHECK; - PRECONDITION(CheckPointer(pMD)); - POSTCONDITION(CheckPointer(RETVAL, NULL_OK)); - } - CONTRACT_END; - - g_IBCLogger.LogNDirectCodeAccess(pMD); - - RETURN pMD->FindEntryPoint(hMod); -} - VOID NDirectMethodDesc::SetNDirectTarget(LPVOID pTarget) { CONTRACTL @@ -5460,1111 +5683,138 @@ VOID NDirectMethodDesc::SetNDirectTarget(LPVOID pTarget) pWriteableData->m_pNDirectTarget = pTarget; } - - -// Preserving good error info from DllImport-driven LoadLibrary is tricky because we keep loading from different places -// if earlier loads fail and those later loads obliterate error codes. -// -// This tracker object will keep track of the error code in accordance to priority: -// -// low-priority: unknown error code (should never happen) -// medium-priority: dll not found -// high-priority: dll found but error during loading -// -// We will overwrite the previous load's error code only if the new error code is higher priority. -// - -class LoadLibErrorTracker +void MarshalStructViaILStub(MethodDesc* pStubMD, void* pManagedData, void* pNativeData, StructMarshalStubs::MarshalOperation operation, void** ppCleanupWorkList /* = nullptr */) { -private: - static const DWORD const_priorityNotFound = 10; - static const DWORD const_priorityAccessDenied = 20; - static const DWORD const_priorityCouldNotLoad = 99999; -public: - LoadLibErrorTracker() + CONTRACTL { - LIMITED_METHOD_CONTRACT; - m_hr = E_FAIL; - m_priorityOfLastError = 0; + THROWS; + GC_TRIGGERS; + MODE_COOPERATIVE; + PRECONDITION(CheckPointer(pStubMD)); } + CONTRACTL_END; - VOID TrackErrorCode() + ARG_SLOT args[] = { - LIMITED_METHOD_CONTRACT; + PtrToArgSlot(pManagedData), + PtrToArgSlot(pNativeData), + (ARG_SLOT)operation, + PtrToArgSlot(ppCleanupWorkList) + }; - DWORD priority; + MethodDescCallSite callSite(pStubMD); -#ifdef TARGET_UNIX + callSite.Call(args); +} - SetMessage(PAL_GetLoadLibraryError()); -#else +void MarshalStructViaILStubCode(PCODE pStubCode, void* pManagedData, void* pNativeData, StructMarshalStubs::MarshalOperation operation, void** ppCleanupWorkList /* = nullptr */) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_COOPERATIVE; + PRECONDITION(pStubCode != NULL); + } + CONTRACTL_END; - DWORD dwLastError = GetLastError(); + PREPARE_NONVIRTUAL_CALLSITE_USING_CODE(pStubCode); + DECLARE_ARGHOLDER_ARRAY(args, 4); + args[ARGNUM_0] = PTR_TO_ARGHOLDER(pManagedData); + args[ARGNUM_1] = PTR_TO_ARGHOLDER(pNativeData); + args[ARGNUM_2] = DWORD_TO_ARGHOLDER(operation); + args[ARGNUM_3] = PTR_TO_ARGHOLDER(ppCleanupWorkList); - switch (dwLastError) - { - case ERROR_FILE_NOT_FOUND: - case ERROR_PATH_NOT_FOUND: - case ERROR_MOD_NOT_FOUND: - case ERROR_DLL_NOT_FOUND: - priority = const_priorityNotFound; - break; + CALL_MANAGED_METHOD_NORET(args); +} - // If we can't access a location, we can't know if the dll's there or if it's good. - // Still, this is probably more unusual (and thus of more interest) than a dll-not-found - // so give it an intermediate priority. - case ERROR_ACCESS_DENIED: - priority = const_priorityAccessDenied; - // Assume all others are "dll found but couldn't load." - default: - priority = const_priorityCouldNotLoad; - break; - } - UpdateHR(priority, HRESULT_FROM_WIN32(dwLastError)); -#endif - } +//========================================================================== +// This function is reached only via NDirectImportThunk. It's purpose +// is to ensure that the target DLL is fully loaded and ready to run. +// +// FUN FACTS: Though this function is actually entered in unmanaged mode, +// it can reenter managed mode and throw a COM+ exception if the DLL linking +// fails. +//========================================================================== +EXTERN_C LPVOID STDCALL NDirectImportWorker(NDirectMethodDesc* pMD) +{ + LPVOID ret = NULL; - // Sets the error code to HRESULT as could not load DLL - void TrackHR_CouldNotLoad(HRESULT hr) - { - UpdateHR(const_priorityCouldNotLoad, hr); - } + BEGIN_PRESERVE_LAST_ERROR; - HRESULT GetHR() + CONTRACTL { - return m_hr; + THROWS; + GC_TRIGGERS; + MODE_PREEMPTIVE; } + CONTRACTL_END; - SString& GetMessage() - { - return m_message; - } + INSTALL_MANAGED_EXCEPTION_DISPATCHER; + // this function is called by CLR to native assembly stubs which are called by + // managed code as a result, we need an unwind and continue handler to translate + // any of our internal exceptions into managed exceptions. + INSTALL_UNWIND_AND_CONTINUE_HANDLER; - void DECLSPEC_NORETURN Throw(SString &libraryNameOrPath) + if (pMD->IsEarlyBound()) { - STANDARD_VM_CONTRACT; - -#if defined(__APPLE__) - COMPlusThrow(kDllNotFoundException, IDS_EE_NDIRECT_LOADLIB_MAC, libraryNameOrPath.GetUnicode(), GetMessage()); -#elif defined(TARGET_UNIX) - COMPlusThrow(kDllNotFoundException, IDS_EE_NDIRECT_LOADLIB_LINUX, libraryNameOrPath.GetUnicode(), GetMessage()); -#else // __APPLE__ - HRESULT theHRESULT = GetHR(); - if (theHRESULT == HRESULT_FROM_WIN32(ERROR_BAD_EXE_FORMAT)) - { - COMPlusThrow(kBadImageFormatException); - } - else + if (!pMD->IsZapped()) { - SString hrString; - GetHRMsg(theHRESULT, hrString); - COMPlusThrow(kDllNotFoundException, IDS_EE_NDIRECT_LOADLIB_WIN, libraryNameOrPath.GetUnicode(), hrString); + // we need the MD to be populated in case we decide to build an intercept + // stub to wrap the target in InitEarlyBoundNDirectTarget + PInvokeStaticSigInfo sigInfo; + NDirect::PopulateNDirectMethodDesc(pMD, &sigInfo); } -#endif // TARGET_UNIX - __UNREACHABLE(); + pMD->InitEarlyBoundNDirectTarget(); } - -private: - void UpdateHR(DWORD priority, HRESULT hr) + else { - if (priority > m_priorityOfLastError) + // + // Otherwise we're in an inlined pinvoke late bound MD + // + INDEBUG(Thread *pThread = GetThread()); { - m_hr = hr; - m_priorityOfLastError = priority; - } - } - - void SetMessage(LPCSTR message) - { - m_message = SString(SString::Utf8, message); - } - - HRESULT m_hr; - DWORD m_priorityOfLastError; - SString m_message; -}; // class LoadLibErrorTracker - -// Load the library directly and return the raw system handle -static NATIVE_LIBRARY_HANDLE LocalLoadLibraryHelper( LPCWSTR name, DWORD flags, LoadLibErrorTracker *pErrorTracker ) -{ - STANDARD_VM_CONTRACT; + _ASSERTE(pMD->ShouldSuppressGCTransition() + || pThread->GetFrame()->GetVTablePtr() == InlinedCallFrame::GetMethodFrameVPtr()); - NATIVE_LIBRARY_HANDLE hmod = NULL; + CONSISTENCY_CHECK(pMD->IsNDirect()); + // + // With IL stubs, we don't have to do anything but ensure the DLL is loaded. + // -#ifndef TARGET_UNIX + if (!pMD->IsZapped()) + { + PInvokeStaticSigInfo sigInfo; + NDirect::PopulateNDirectMethodDesc(pMD, &sigInfo); + } + else + { + // must have been populated at NGEN time + _ASSERTE(pMD->GetLibName() != NULL); + } - if ((flags & 0xFFFFFF00) != 0) - { - hmod = CLRLoadLibraryEx(name, NULL, flags & 0xFFFFFF00); - if (hmod != NULL) - { - return hmod; - } + pMD->CheckRestore(); - DWORD dwLastError = GetLastError(); - if (dwLastError != ERROR_INVALID_PARAMETER) - { - pErrorTracker->TrackErrorCode(); - return hmod; + NDirectLink(pMD); } } - hmod = CLRLoadLibraryEx(name, NULL, flags & 0xFF); + ret = pMD->GetNDirectTarget(); -#else // !TARGET_UNIX - hmod = PAL_LoadLibraryDirect(name); -#endif // !TARGET_UNIX + UNINSTALL_UNWIND_AND_CONTINUE_HANDLER; + UNINSTALL_MANAGED_EXCEPTION_DISPATCHER; - if (hmod == NULL) - { - pErrorTracker->TrackErrorCode(); - } + END_PRESERVE_LAST_ERROR; - return hmod; + return ret; } -#define TOLOWER(a) (((a) >= W('A') && (a) <= W('Z')) ? (W('a') + (a - W('A'))) : (a)) -#define TOHEX(a) ((a)>=10 ? W('a')+(a)-10 : W('0')+(a)) - -#ifdef TARGET_UNIX -#define PLATFORM_SHARED_LIB_SUFFIX_W PAL_SHLIB_SUFFIX_W -#define PLATFORM_SHARED_LIB_PREFIX_W PAL_SHLIB_PREFIX_W -#else // !TARGET_UNIX -#define PLATFORM_SHARED_LIB_SUFFIX_W W(".dll") -#define PLATFORM_SHARED_LIB_PREFIX_W W("") -#endif // !TARGET_UNIX - -// The Bit 0x2 has different semantics in DllImportSearchPath and LoadLibraryExA flags. -// In DllImportSearchPath enum, bit 0x2 represents SearchAssemblyDirectory -- which is performed by CLR. -// Unlike other bits in this enum, this bit shouldn't be directly passed on to LoadLibrary() -#define DLLIMPORTSEARCHPATH_ASSEMBLYDIRECTORY 0x2 - -// DllImportSearchPathFlags is a special enumeration, whose values are tied closely with LoadLibrary flags. -// There is no "default" value DllImportSearchPathFlags. In the absence of DllImportSearchPath attribute, -// CoreCLR's LoadLibrary implementation uses the following defaults. -// Other implementations of LoadLibrary callbacks/events are free to use other default conventions. -void GetDefaultDllImportSearchPathFlags(DWORD *dllImportSearchPathFlags, BOOL *searchAssemblyDirectory) -{ - STANDARD_VM_CONTRACT; - - *searchAssemblyDirectory = TRUE; - *dllImportSearchPathFlags = 0; -} - -// If a module has the DefaultDllImportSearchPathsAttribute, get DllImportSearchPathFlags from it, and return true. -// Otherwise, get CoreCLR's default value for DllImportSearchPathFlags, and return false. -BOOL GetDllImportSearchPathFlags(Module *pModule, DWORD *dllImportSearchPathFlags, BOOL *searchAssemblyDirectory) -{ - STANDARD_VM_CONTRACT; - - if (pModule->HasDefaultDllImportSearchPathsAttribute()) - { - *dllImportSearchPathFlags = pModule->DefaultDllImportSearchPathsAttributeCachedValue(); - *searchAssemblyDirectory = pModule->DllImportSearchAssemblyDirectory(); - return TRUE; - } - - GetDefaultDllImportSearchPathFlags(dllImportSearchPathFlags, searchAssemblyDirectory); - return FALSE; -} - -// If a pInvoke has the DefaultDllImportSearchPathsAttribute, get DllImportSearchPathFlags from it, and returns true. -// Otherwise, if the containing assembly has the DefaultDllImportSearchPathsAttribute, get DllImportSearchPathFlags from it, and returns true. -// Otherwise, get CoreCLR's default value for DllImportSearchPathFlags, and return false. -BOOL GetDllImportSearchPathFlags(NDirectMethodDesc * pMD, DWORD *dllImportSearchPathFlags, BOOL *searchAssemblyDirectory) -{ - STANDARD_VM_CONTRACT; - - if (pMD->HasDefaultDllImportSearchPathsAttribute()) - { - *dllImportSearchPathFlags = pMD->DefaultDllImportSearchPathsAttributeCachedValue(); - *searchAssemblyDirectory = pMD->DllImportSearchAssemblyDirectory(); - return TRUE; - } - - return GetDllImportSearchPathFlags(pMD->GetModule(), dllImportSearchPathFlags, searchAssemblyDirectory); -} - -// static -NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryFromPath(LPCWSTR libraryPath, BOOL throwOnError) -{ - CONTRACTL - { - STANDARD_VM_CHECK; - PRECONDITION(CheckPointer(libraryPath)); - } - CONTRACTL_END; - - LoadLibErrorTracker errorTracker; - const NATIVE_LIBRARY_HANDLE hmod = - LocalLoadLibraryHelper(libraryPath, GetLoadWithAlteredSearchPathFlag(), &errorTracker); - - if (throwOnError && (hmod == nullptr)) - { - SString libraryPathSString(libraryPath); - errorTracker.Throw(libraryPathSString); - } - return hmod; -} - -// static -void NDirect::FreeNativeLibrary(NATIVE_LIBRARY_HANDLE handle) -{ - STANDARD_VM_CONTRACT; - _ASSERTE(handle != NULL); - -#ifndef TARGET_UNIX - BOOL retVal = FreeLibrary(handle); -#else // !TARGET_UNIX - BOOL retVal = PAL_FreeLibraryDirect(handle); -#endif // !TARGET_UNIX - - if (retVal == 0) - COMPlusThrow(kInvalidOperationException, W("Arg_InvalidOperationException")); -} - -//static -INT_PTR NDirect::GetNativeLibraryExport(NATIVE_LIBRARY_HANDLE handle, LPCWSTR symbolName, BOOL throwOnError) -{ - CONTRACTL - { - STANDARD_VM_CHECK; - PRECONDITION(CheckPointer(handle)); - PRECONDITION(CheckPointer(symbolName)); - } - CONTRACTL_END; - - MAKE_UTF8PTR_FROMWIDE(lpstr, symbolName); - -#ifndef TARGET_UNIX - INT_PTR address = reinterpret_cast(GetProcAddress((HMODULE)handle, lpstr)); - if ((address == NULL) && throwOnError) - COMPlusThrow(kEntryPointNotFoundException, IDS_EE_NDIRECT_GETPROCADDR_WIN_DLL, symbolName); -#else // !TARGET_UNIX - INT_PTR address = reinterpret_cast(PAL_GetProcAddressDirect(handle, lpstr)); - if ((address == NULL) && throwOnError) - COMPlusThrow(kEntryPointNotFoundException, IDS_EE_NDIRECT_GETPROCADDR_UNIX_SO, symbolName); -#endif // !TARGET_UNIX - - return address; -} - -namespace -{ -#ifndef TARGET_UNIX - BOOL IsWindowsAPISet(PCWSTR wszLibName) - { - STANDARD_VM_CONTRACT; - - // This is replicating quick check from the OS implementation of api sets. - return SString::_wcsnicmp(wszLibName, W("api-"), 4) == 0 || - SString::_wcsnicmp(wszLibName, W("ext-"), 4) == 0; - } -#endif // !TARGET_UNIX - - NATIVE_LIBRARY_HANDLE LoadNativeLibraryViaAssemblyLoadContext(Assembly * pAssembly, PCWSTR wszLibName) - { - STANDARD_VM_CONTRACT; - -#ifndef TARGET_UNIX - if (IsWindowsAPISet(wszLibName)) - { - // Prevent Overriding of Windows API sets. - return NULL; - } -#endif // !TARGET_UNIX - - NATIVE_LIBRARY_HANDLE hmod = NULL; - AppDomain* pDomain = GetAppDomain(); - CLRPrivBinderCoreCLR *pTPABinder = pDomain->GetTPABinderContext(); - - PEFile *pManifestFile = pAssembly->GetManifestFile(); - PTR_ICLRPrivBinder pBindingContext = pManifestFile->GetBindingContext(); - - //Step 0: Check if the assembly was bound using TPA. - // The Binding Context can be null or an overridden TPA context - if (pBindingContext == NULL) - { - // If we do not have any binder associated, then return to the default resolution mechanism. - return NULL; - } - - UINT_PTR assemblyBinderID = 0; - IfFailThrow(pBindingContext->GetBinderID(&assemblyBinderID)); - - ICLRPrivBinder *pCurrentBinder = reinterpret_cast(assemblyBinderID); - - // For assemblies bound via TPA binder, we should use the standard mechanism to make the pinvoke call. - if (AreSameBinderInstance(pCurrentBinder, pTPABinder)) - { - return NULL; - } - - //Step 1: If the assembly was not bound using TPA, - // Call System.Runtime.Loader.AssemblyLoadContext.ResolveUnmanagedDll to give - // The custom assembly context a chance to load the unmanaged dll. - - GCX_COOP(); - - STRINGREF pUnmanagedDllName; - pUnmanagedDllName = StringObject::NewString(wszLibName); - - GCPROTECT_BEGIN(pUnmanagedDllName); - - // Get the pointer to the managed assembly load context - INT_PTR ptrManagedAssemblyLoadContext = ((CLRPrivBinderAssemblyLoadContext *)pCurrentBinder)->GetManagedAssemblyLoadContext(); - - // Prepare to invoke System.Runtime.Loader.AssemblyLoadContext.ResolveUnmanagedDll method. - PREPARE_NONVIRTUAL_CALLSITE(METHOD__ASSEMBLYLOADCONTEXT__RESOLVEUNMANAGEDDLL); - DECLARE_ARGHOLDER_ARRAY(args, 2); - args[ARGNUM_0] = STRINGREF_TO_ARGHOLDER(pUnmanagedDllName); - args[ARGNUM_1] = PTR_TO_ARGHOLDER(ptrManagedAssemblyLoadContext); - - // Make the call - CALL_MANAGED_METHOD(hmod, NATIVE_LIBRARY_HANDLE, args); - - GCPROTECT_END(); - - return hmod; - } - - // Return the AssemblyLoadContext for an assembly - INT_PTR GetManagedAssemblyLoadContext(Assembly* pAssembly) - { - STANDARD_VM_CONTRACT; - - PTR_ICLRPrivBinder pBindingContext = pAssembly->GetManifestFile()->GetBindingContext(); - if (pBindingContext == NULL) - { - // GetBindingContext() returns NULL for System.Private.CoreLib - return NULL; - } - - UINT_PTR assemblyBinderID = 0; - IfFailThrow(pBindingContext->GetBinderID(&assemblyBinderID)); - - AppDomain *pDomain = GetAppDomain(); - ICLRPrivBinder *pCurrentBinder = reinterpret_cast(assemblyBinderID); - - // The code here deals with two implementations of ICLRPrivBinder interface: - // - CLRPrivBinderCoreCLR for the TPA binder in the default ALC, and - // - CLRPrivBinderAssemblyLoadContext for custom ALCs. - // in order obtain the associated ALC handle. - INT_PTR ptrManagedAssemblyLoadContext = AreSameBinderInstance(pCurrentBinder, pDomain->GetTPABinderContext()) - ? ((CLRPrivBinderCoreCLR *)pCurrentBinder)->GetManagedAssemblyLoadContext() - : ((CLRPrivBinderAssemblyLoadContext *)pCurrentBinder)->GetManagedAssemblyLoadContext(); - - return ptrManagedAssemblyLoadContext; - } - - NATIVE_LIBRARY_HANDLE LoadNativeLibraryViaAssemblyLoadContextEvent(Assembly * pAssembly, PCWSTR wszLibName) - { - STANDARD_VM_CONTRACT; - - INT_PTR ptrManagedAssemblyLoadContext = GetManagedAssemblyLoadContext(pAssembly); - if (ptrManagedAssemblyLoadContext == NULL) - { - return NULL; - } - - NATIVE_LIBRARY_HANDLE hmod = NULL; - - GCX_COOP(); - - struct { - STRINGREF DllName; - OBJECTREF AssemblyRef; - } gc = { NULL, NULL }; - - GCPROTECT_BEGIN(gc); - - gc.DllName = StringObject::NewString(wszLibName); - gc.AssemblyRef = pAssembly->GetExposedObject(); - - // Prepare to invoke System.Runtime.Loader.AssemblyLoadContext.ResolveUnmanagedDllUsingEvent method - // While ResolveUnmanagedDllUsingEvent() could compute the AssemblyLoadContext using the AssemblyRef - // argument, it will involve another pInvoke to the runtime. So AssemblyLoadContext is passed in - // as an additional argument. - PREPARE_NONVIRTUAL_CALLSITE(METHOD__ASSEMBLYLOADCONTEXT__RESOLVEUNMANAGEDDLLUSINGEVENT); - DECLARE_ARGHOLDER_ARRAY(args, 3); - args[ARGNUM_0] = STRINGREF_TO_ARGHOLDER(gc.DllName); - args[ARGNUM_1] = OBJECTREF_TO_ARGHOLDER(gc.AssemblyRef); - args[ARGNUM_2] = PTR_TO_ARGHOLDER(ptrManagedAssemblyLoadContext); - - // Make the call - CALL_MANAGED_METHOD(hmod, NATIVE_LIBRARY_HANDLE, args); - - GCPROTECT_END(); - - return hmod; - } - - NATIVE_LIBRARY_HANDLE LoadNativeLibraryViaDllImportResolver(NDirectMethodDesc * pMD, LPCWSTR wszLibName) - { - STANDARD_VM_CONTRACT; - - if (pMD->GetModule()->IsSystem()) - { - // Don't attempt to callback on Corelib itself. - // The LoadLibrary callback stub is managed code that requires CoreLib - return NULL; - } - - DWORD dllImportSearchPathFlags; - BOOL searchAssemblyDirectory; - BOOL hasDllImportSearchPathFlags = GetDllImportSearchPathFlags(pMD, &dllImportSearchPathFlags, &searchAssemblyDirectory); - dllImportSearchPathFlags |= searchAssemblyDirectory ? DLLIMPORTSEARCHPATH_ASSEMBLYDIRECTORY : 0; - - Assembly* pAssembly = pMD->GetMethodTable()->GetAssembly(); - NATIVE_LIBRARY_HANDLE handle = NULL; - - GCX_COOP(); - - struct { - STRINGREF libNameRef; - OBJECTREF assemblyRef; - } gc = { NULL, NULL }; - - GCPROTECT_BEGIN(gc); - - gc.libNameRef = StringObject::NewString(wszLibName); - gc.assemblyRef = pAssembly->GetExposedObject(); - - PREPARE_NONVIRTUAL_CALLSITE(METHOD__NATIVELIBRARY__LOADLIBRARYCALLBACKSTUB); - DECLARE_ARGHOLDER_ARRAY(args, 4); - args[ARGNUM_0] = STRINGREF_TO_ARGHOLDER(gc.libNameRef); - args[ARGNUM_1] = OBJECTREF_TO_ARGHOLDER(gc.assemblyRef); - args[ARGNUM_2] = BOOL_TO_ARGHOLDER(hasDllImportSearchPathFlags); - args[ARGNUM_3] = DWORD_TO_ARGHOLDER(dllImportSearchPathFlags); - - // Make the call - CALL_MANAGED_METHOD(handle, NATIVE_LIBRARY_HANDLE, args); - GCPROTECT_END(); - - return handle; - } - - // Try to load the module alongside the assembly where the PInvoke was declared. - NATIVE_LIBRARY_HANDLE LoadFromPInvokeAssemblyDirectory(Assembly *pAssembly, LPCWSTR libName, DWORD flags, LoadLibErrorTracker *pErrorTracker) - { - STANDARD_VM_CONTRACT; - - NATIVE_LIBRARY_HANDLE hmod = NULL; - - SString path = pAssembly->GetManifestFile()->GetPath(); - - SString::Iterator lastPathSeparatorIter = path.End(); - if (PEAssembly::FindLastPathSeparator(path, lastPathSeparatorIter)) - { - lastPathSeparatorIter++; - path.Truncate(lastPathSeparatorIter); - - path.Append(libName); - hmod = LocalLoadLibraryHelper(path, flags, pErrorTracker); - } - - return hmod; - } - - // Try to load the module from the native DLL search directories - NATIVE_LIBRARY_HANDLE LoadFromNativeDllSearchDirectories(LPCWSTR libName, DWORD flags, LoadLibErrorTracker *pErrorTracker) - { - STANDARD_VM_CONTRACT; - - NATIVE_LIBRARY_HANDLE hmod = NULL; - AppDomain* pDomain = GetAppDomain(); - - if (pDomain->HasNativeDllSearchDirectories()) - { - AppDomain::PathIterator pathIter = pDomain->IterateNativeDllSearchDirectories(); - while (hmod == NULL && pathIter.Next()) - { - SString qualifiedPath(*(pathIter.GetPath())); - qualifiedPath.Append(libName); - if (!Path::IsRelative(qualifiedPath)) - { - hmod = LocalLoadLibraryHelper(qualifiedPath, flags, pErrorTracker); - } - } - } - - return hmod; - } - -#ifdef TARGET_UNIX - const int MaxVariationCount = 4; - void DetermineLibNameVariations(const WCHAR** libNameVariations, int* numberOfVariations, const SString& libName, bool libNameIsRelativePath) - { - // Supported lib name variations - static auto NameFmt = W("%.0s%s%.0s"); - static auto PrefixNameFmt = W("%s%s%.0s"); - static auto NameSuffixFmt = W("%.0s%s%s"); - static auto PrefixNameSuffixFmt = W("%s%s%s"); - - _ASSERTE(*numberOfVariations >= MaxVariationCount); - - int varCount = 0; - if (!libNameIsRelativePath) - { - libNameVariations[varCount++] = NameFmt; - } - else - { - // We check if the suffix is contained in the name, because on Linux it is common to append - // a version number to the library name (e.g. 'libicuuc.so.57'). - bool containsSuffix = false; - SString::CIterator it = libName.Begin(); - if (libName.Find(it, PLATFORM_SHARED_LIB_SUFFIX_W)) - { - it += COUNTOF(PLATFORM_SHARED_LIB_SUFFIX_W); - containsSuffix = it == libName.End() || *it == (WCHAR)'.'; - } - - // If the path contains a path delimiter, we don't add a prefix - it = libName.Begin(); - bool containsDelim = libName.Find(it, DIRECTORY_SEPARATOR_STR_W); - - if (containsSuffix) - { - libNameVariations[varCount++] = NameFmt; - - if (!containsDelim) - libNameVariations[varCount++] = PrefixNameFmt; - - libNameVariations[varCount++] = NameSuffixFmt; - - if (!containsDelim) - libNameVariations[varCount++] = PrefixNameSuffixFmt; - } - else - { - libNameVariations[varCount++] = NameSuffixFmt; - - if (!containsDelim) - libNameVariations[varCount++] = PrefixNameSuffixFmt; - - libNameVariations[varCount++] = NameFmt; - - if (!containsDelim) - libNameVariations[varCount++] = PrefixNameFmt; - } - } - - *numberOfVariations = varCount; - } -#else // TARGET_UNIX - const int MaxVariationCount = 2; - void DetermineLibNameVariations(const WCHAR** libNameVariations, int* numberOfVariations, const SString& libName, bool libNameIsRelativePath) - { - // Supported lib name variations - static auto NameFmt = W("%.0s%s%.0s"); - static auto NameSuffixFmt = W("%.0s%s%s"); - - _ASSERTE(*numberOfVariations >= MaxVariationCount); - - int varCount = 0; - - // The purpose of following code is to workaround LoadLibrary limitation: - // LoadLibrary won't append extension if filename itself contains '.'. Thus it will break the following scenario: - // [DllImport("A.B")] // The full name for file is "A.B.dll". This is common code pattern for cross-platform PInvoke - // The workaround for above scenario is to call LoadLibrary with "A.B" first, if it fails, then call LoadLibrary with "A.B.dll" - auto it = libName.Begin(); - if (!libNameIsRelativePath || - !libName.Find(it, W('.')) || - libName.EndsWith(W(".")) || - libName.EndsWithCaseInsensitive(W(".dll")) || - libName.EndsWithCaseInsensitive(W(".exe"))) - { - // Follow LoadLibrary rules in MSDN doc: https://msdn.microsoft.com/en-us/library/windows/desktop/ms684175(v=vs.85).aspx - // If the string specifies a full path, the function searches only that path for the module. - // If the string specifies a module name without a path and the file name extension is omitted, the function appends the default library extension .dll to the module name. - // To prevent the function from appending .dll to the module name, include a trailing point character (.) in the module name string. - libNameVariations[varCount++] = NameFmt; - } - else - { - libNameVariations[varCount++] = NameFmt; - libNameVariations[varCount++] = NameSuffixFmt; - } - - *numberOfVariations = varCount; - } -#endif // TARGET_UNIX - - // Search for the library and variants of its name in probing directories. - NATIVE_LIBRARY_HANDLE LoadNativeLibraryBySearch(Assembly *callingAssembly, - BOOL searchAssemblyDirectory, DWORD dllImportSearchPathFlags, - LoadLibErrorTracker * pErrorTracker, LPCWSTR wszLibName) - { - STANDARD_VM_CONTRACT; - - NATIVE_LIBRARY_HANDLE hmod = NULL; - -#if defined(FEATURE_CORESYSTEM) && !defined(TARGET_UNIX) - // Try to go straight to System32 for Windows API sets. This is replicating quick check from - // the OS implementation of api sets. - if (IsWindowsAPISet(wszLibName)) - { - hmod = LocalLoadLibraryHelper(wszLibName, LOAD_LIBRARY_SEARCH_SYSTEM32, pErrorTracker); - if (hmod != NULL) - { - return hmod; - } - } -#endif // FEATURE_CORESYSTEM && !TARGET_UNIX - - if (g_hostpolicy_embedded) - { -#ifdef TARGET_WINDOWS - if (wcscmp(wszLibName, W("hostpolicy.dll")) == 0) - { - return WszGetModuleHandle(NULL); - } -#else - if (wcscmp(wszLibName, W("libhostpolicy")) == 0) - { - return PAL_LoadLibraryDirect(NULL); - } -#endif - } - - AppDomain* pDomain = GetAppDomain(); - DWORD loadWithAlteredPathFlags = GetLoadWithAlteredSearchPathFlag(); - bool libNameIsRelativePath = Path::IsRelative(wszLibName); - - // P/Invokes are often declared with variations on the actual library name. - // For example, it's common to leave off the extension/suffix of the library - // even if it has one, or to leave off a prefix like "lib" even if it has one - // (both of these are typically done to smooth over cross-platform differences). - // We try to dlopen with such variations on the original. - const WCHAR* prefixSuffixCombinations[MaxVariationCount] = {}; - int numberOfVariations = COUNTOF(prefixSuffixCombinations); - DetermineLibNameVariations(prefixSuffixCombinations, &numberOfVariations, wszLibName, libNameIsRelativePath); - for (int i = 0; i < numberOfVariations; i++) - { - SString currLibNameVariation; - currLibNameVariation.Printf(prefixSuffixCombinations[i], PLATFORM_SHARED_LIB_PREFIX_W, wszLibName, PLATFORM_SHARED_LIB_SUFFIX_W); - - // NATIVE_DLL_SEARCH_DIRECTORIES set by host is considered well known path - hmod = LoadFromNativeDllSearchDirectories(currLibNameVariation, loadWithAlteredPathFlags, pErrorTracker); - if (hmod != NULL) - { - return hmod; - } - - if (!libNameIsRelativePath) - { - DWORD flags = loadWithAlteredPathFlags; - if ((dllImportSearchPathFlags & LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR) != 0) - { - // LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR is the only flag affecting absolute path. Don't OR the flags - // unconditionally as all absolute path P/Invokes could then lose LOAD_WITH_ALTERED_SEARCH_PATH. - flags |= dllImportSearchPathFlags; - } - - hmod = LocalLoadLibraryHelper(currLibNameVariation, flags, pErrorTracker); - if (hmod != NULL) - { - return hmod; - } - } - else if ((callingAssembly != nullptr) && searchAssemblyDirectory) - { - hmod = LoadFromPInvokeAssemblyDirectory(callingAssembly, currLibNameVariation, loadWithAlteredPathFlags | dllImportSearchPathFlags, pErrorTracker); - if (hmod != NULL) - { - return hmod; - } - } - - hmod = LocalLoadLibraryHelper(currLibNameVariation, dllImportSearchPathFlags, pErrorTracker); - if (hmod != NULL) - { - return hmod; - } - } - - // This may be an assembly name - // Format is "fileName, assemblyDisplayName" - MAKE_UTF8PTR_FROMWIDE(szLibName, wszLibName); - char *szComma = strchr(szLibName, ','); - if (szComma) - { - *szComma = '\0'; - // Trim white spaces - while (COMCharacter::nativeIsWhiteSpace(*(++szComma))); - - AssemblySpec spec; - if (SUCCEEDED(spec.Init(szComma))) - { - // Need to perform case insensitive hashing. - SString moduleName(SString::Utf8, szLibName); - moduleName.LowerCase(); - - StackScratchBuffer buffer; - szLibName = (LPSTR)moduleName.GetUTF8(buffer); - - Assembly *pAssembly = spec.LoadAssembly(FILE_LOADED); - Module *pModule = pAssembly->FindModuleByName(szLibName); - - hmod = LocalLoadLibraryHelper(pModule->GetPath(), loadWithAlteredPathFlags | dllImportSearchPathFlags, pErrorTracker); - } - } - - return hmod; - } - - NATIVE_LIBRARY_HANDLE LoadNativeLibraryBySearch(NDirectMethodDesc *pMD, LoadLibErrorTracker *pErrorTracker, PCWSTR wszLibName) - { - STANDARD_VM_CONTRACT; - - BOOL searchAssemblyDirectory; - DWORD dllImportSearchPathFlags; - - GetDllImportSearchPathFlags(pMD, &dllImportSearchPathFlags, &searchAssemblyDirectory); - - Assembly *pAssembly = pMD->GetMethodTable()->GetAssembly(); - return LoadNativeLibraryBySearch(pAssembly, searchAssemblyDirectory, dllImportSearchPathFlags, pErrorTracker, wszLibName); - } -} - -// static -NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryByName(LPCWSTR libraryName, Assembly *callingAssembly, - BOOL hasDllImportSearchFlags, DWORD dllImportSearchFlags, - BOOL throwOnError) -{ - CONTRACTL - { - STANDARD_VM_CHECK; - PRECONDITION(CheckPointer(libraryName)); - PRECONDITION(CheckPointer(callingAssembly)); - } - CONTRACTL_END; - - NATIVE_LIBRARY_HANDLE hmod = nullptr; - - // Resolve using the AssemblyLoadContext.LoadUnmanagedDll implementation - hmod = LoadNativeLibraryViaAssemblyLoadContext(callingAssembly, libraryName); - if (hmod != nullptr) - return hmod; - - // Check if a default dllImportSearchPathFlags was passed in. If so, use that value. - // Otherwise, check if the assembly has the DefaultDllImportSearchPathsAttribute attribute. - // If so, use that value. - BOOL searchAssemblyDirectory; - DWORD dllImportSearchPathFlags; - if (hasDllImportSearchFlags) - { - dllImportSearchPathFlags = dllImportSearchFlags & ~DLLIMPORTSEARCHPATH_ASSEMBLYDIRECTORY; - searchAssemblyDirectory = dllImportSearchFlags & DLLIMPORTSEARCHPATH_ASSEMBLYDIRECTORY; - - } - else - { - GetDllImportSearchPathFlags(callingAssembly->GetManifestModule(), - &dllImportSearchPathFlags, &searchAssemblyDirectory); - } - - LoadLibErrorTracker errorTracker; - hmod = LoadNativeLibraryBySearch(callingAssembly, searchAssemblyDirectory, dllImportSearchPathFlags, &errorTracker, libraryName); - if (hmod != nullptr) - return hmod; - - // Resolve using the AssemblyLoadContext.ResolvingUnmanagedDll event - hmod = LoadNativeLibraryViaAssemblyLoadContextEvent(callingAssembly, libraryName); - if (hmod != nullptr) - return hmod; - - if (throwOnError) - { - SString libraryPathSString(libraryName); - errorTracker.Throw(libraryPathSString); - } - - return hmod; -} - -NATIVE_LIBRARY_HANDLE NDirect::LoadNativeLibrary(NDirectMethodDesc * pMD, LoadLibErrorTracker * pErrorTracker) -{ - CONTRACTL - { - STANDARD_VM_CHECK; - PRECONDITION( CheckPointer( pMD ) ); - } - CONTRACTL_END; - - LPCUTF8 name = pMD->GetLibName(); - if ( !name || !*name ) - return NULL; - - PREFIX_ASSUME( name != NULL ); - MAKE_WIDEPTR_FROMUTF8( wszLibName, name ); - - NativeLibraryHandleHolder hmod = LoadNativeLibraryViaDllImportResolver(pMD, wszLibName); - if (hmod != NULL) - { - return hmod.Extract(); - } - - AppDomain* pDomain = GetAppDomain(); - Assembly* pAssembly = pMD->GetMethodTable()->GetAssembly(); - - hmod = LoadNativeLibraryViaAssemblyLoadContext(pAssembly, wszLibName); - if (hmod != NULL) - { - return hmod.Extract(); - } - - hmod = pDomain->FindUnmanagedImageInCache(wszLibName); - if (hmod != NULL) - { - return hmod.Extract(); - } - - hmod = LoadNativeLibraryBySearch(pMD, pErrorTracker, wszLibName); - if (hmod != NULL) - { - // If we have a handle add it to the cache. - pDomain->AddUnmanagedImageToCache(wszLibName, hmod); - return hmod.Extract(); - } - - hmod = LoadNativeLibraryViaAssemblyLoadContextEvent(pAssembly, wszLibName); - if (hmod != NULL) - { - return hmod.Extract(); - } - - return hmod.Extract(); -} - -//--------------------------------------------------------- -// Loads the DLL and finds the procaddress for an N/Direct call. -//--------------------------------------------------------- -/* static */ -VOID NDirect::NDirectLink(NDirectMethodDesc *pMD) -{ - CONTRACTL - { - STANDARD_VM_CHECK; - PRECONDITION(CheckPointer(pMD)); - } - CONTRACTL_END; - - // - // On the phone, we only allow platform assemblies to define pinvokes - // unless the host has asked us otherwise. - // - - if (pMD->IsClassConstructorTriggeredAtLinkTime()) - { - pMD->GetMethodTable()->CheckRunClassInitThrowing(); - } - - if (pMD->IsQCall()) - { - LPVOID pvTarget = pMD->ndirect.m_pNativeNDirectTarget; - - // Do not repeat the lookup if the QCall was hardbound during ngen - if (pvTarget == NULL) - { - pvTarget = ECall::GetQCallImpl(pMD); - } - else - { - _ASSERTE(pvTarget == ECall::GetQCallImpl(pMD)); - } - - pMD->SetNDirectTarget(pvTarget); - return; - } - - // Loading unmanaged dlls can trigger dllmains which certainly count as code execution! - pMD->EnsureActive(); - - { - LPVOID pvTarget = (LPVOID)PInvokeOverride::GetMethodImpl(pMD->GetLibNameRaw(), pMD->GetEntrypointName()); - if (pvTarget != NULL) - { - pMD->SetNDirectTarget(pvTarget); - return; - } - } - - LoadLibErrorTracker errorTracker; - - BOOL fSuccess = FALSE; - NATIVE_LIBRARY_HANDLE hmod = LoadNativeLibrary( pMD, &errorTracker ); - if ( hmod ) - { - LPVOID pvTarget = NDirectGetEntryPoint(pMD, hmod); - if (pvTarget) - { - pMD->SetNDirectTarget(pvTarget); - fSuccess = TRUE; - } - } - - if (!fSuccess) - { - if (pMD->GetLibName() == NULL) - COMPlusThrow(kEntryPointNotFoundException, IDS_EE_NDIRECT_GETPROCADDRESS_NONAME); - - StackSString ssLibName(SString::Utf8, pMD->GetLibName()); - - if (!hmod) - { - errorTracker.Throw(ssLibName); - } - - WCHAR wszEPName[50]; - if (WszMultiByteToWideChar(CP_UTF8, 0, (LPCSTR)pMD->GetEntrypointName(), -1, wszEPName, sizeof(wszEPName)/sizeof(WCHAR)) == 0) - { - wszEPName[0] = W('?'); - wszEPName[1] = W('\0'); - } -#ifdef TARGET_UNIX - COMPlusThrow(kEntryPointNotFoundException, IDS_EE_NDIRECT_GETPROCADDRESS_UNIX, ssLibName.GetUnicode(), wszEPName); -#else - COMPlusThrow(kEntryPointNotFoundException, IDS_EE_NDIRECT_GETPROCADDRESS_WIN, ssLibName.GetUnicode(), wszEPName); -#endif - } -} - -void MarshalStructViaILStub(MethodDesc* pStubMD, void* pManagedData, void* pNativeData, StructMarshalStubs::MarshalOperation operation, void** ppCleanupWorkList /* = nullptr */) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(CheckPointer(pStubMD)); - } - CONTRACTL_END; - - ARG_SLOT args[] = - { - PtrToArgSlot(pManagedData), - PtrToArgSlot(pNativeData), - (ARG_SLOT)operation, - PtrToArgSlot(ppCleanupWorkList) - }; - - MethodDescCallSite callSite(pStubMD); - - callSite.Call(args); -} - -void MarshalStructViaILStubCode(PCODE pStubCode, void* pManagedData, void* pNativeData, StructMarshalStubs::MarshalOperation operation, void** ppCleanupWorkList /* = nullptr */) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(pStubCode != NULL); - } - CONTRACTL_END; - - PREPARE_NONVIRTUAL_CALLSITE_USING_CODE(pStubCode); - DECLARE_ARGHOLDER_ARRAY(args, 4); - args[ARGNUM_0] = PTR_TO_ARGHOLDER(pManagedData); - args[ARGNUM_1] = PTR_TO_ARGHOLDER(pNativeData); - args[ARGNUM_2] = DWORD_TO_ARGHOLDER(operation); - args[ARGNUM_3] = PTR_TO_ARGHOLDER(ppCleanupWorkList); - - CALL_MANAGED_METHOD_NORET(args); -} - - -//========================================================================== -// This function is reached only via NDirectImportThunk. It's purpose -// is to ensure that the target DLL is fully loaded and ready to run. -// -// FUN FACTS: Though this function is actually entered in unmanaged mode, -// it can reenter managed mode and throw a COM+ exception if the DLL linking -// fails. -//========================================================================== -EXTERN_C LPVOID STDCALL NDirectImportWorker(NDirectMethodDesc* pMD) -{ - LPVOID ret = NULL; - - BEGIN_PRESERVE_LAST_ERROR; - - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_PREEMPTIVE; - } - CONTRACTL_END; - - INSTALL_MANAGED_EXCEPTION_DISPATCHER; - // this function is called by CLR to native assembly stubs which are called by - // managed code as a result, we need an unwind and continue handler to translate - // any of our internal exceptions into managed exceptions. - INSTALL_UNWIND_AND_CONTINUE_HANDLER; - - if (pMD->IsEarlyBound()) - { - if (!pMD->IsZapped()) - { - // we need the MD to be populated in case we decide to build an intercept - // stub to wrap the target in InitEarlyBoundNDirectTarget - PInvokeStaticSigInfo sigInfo; - NDirect::PopulateNDirectMethodDesc(pMD, &sigInfo); - } - - pMD->InitEarlyBoundNDirectTarget(); - } - else - { - // - // Otherwise we're in an inlined pinvoke late bound MD - // - INDEBUG(Thread *pThread = GetThread()); - { - _ASSERTE(pMD->ShouldSuppressGCTransition() - || pThread->GetFrame()->GetVTablePtr() == InlinedCallFrame::GetMethodFrameVPtr()); - - CONSISTENCY_CHECK(pMD->IsNDirect()); - // - // With IL stubs, we don't have to do anything but ensure the DLL is loaded. - // - - if (!pMD->IsZapped()) - { - PInvokeStaticSigInfo sigInfo; - NDirect::PopulateNDirectMethodDesc(pMD, &sigInfo); - } - else - { - // must have been populated at NGEN time - _ASSERTE(pMD->GetLibName() != NULL); - } - - pMD->CheckRestore(); - - NDirect::NDirectLink(pMD); - } - } - - ret = pMD->GetNDirectTarget(); - - UNINSTALL_UNWIND_AND_CONTINUE_HANDLER; - UNINSTALL_MANAGED_EXCEPTION_DISPATCHER; - - END_PRESERVE_LAST_ERROR; - - return ret; -} - -//=========================================================================== -// Support for Pinvoke Calli instruction -// -//=========================================================================== +//=========================================================================== +// Support for Pinvoke Calli instruction +// +//=========================================================================== EXTERN_C void STDCALL VarargPInvokeStubWorker(TransitionBlock * pTransitionBlock, VASigCookie *pVASigCookie, MethodDesc *pMD) { @@ -6761,18 +6011,3 @@ PCODE GetILStubForCalli(VASigCookie *pVASigCookie, MethodDesc *pMD) #endif // CROSSGEN_COMPILE #endif // #ifndef DACCESS_COMPILE - -// -// Truncates a SString by first converting it to unicode and truncate it -// if it is larger than size. "..." will be appended if it is truncated. -// -void TruncateUnicodeString(SString &string, COUNT_T bufSize) -{ - string.Normalize(); - if ((string.GetCount() + 1) * sizeof(WCHAR) > bufSize) - { - _ASSERTE(bufSize / sizeof(WCHAR) > 4); - string.Truncate(string.Begin() + bufSize / sizeof(WCHAR) - 4); - string.Append(W("...")); - } -} diff --git a/src/coreclr/vm/dllimport.h b/src/coreclr/vm/dllimport.h index 74bd35c1530fa0..6625ec11ca7acd 100644 --- a/src/coreclr/vm/dllimport.h +++ b/src/coreclr/vm/dllimport.h @@ -9,10 +9,7 @@ #include "util.hpp" -class ILStubHashBlob; -class NDirectStubParameters; struct PInvokeStaticSigInfo; -class LoadLibErrorTracker; // This structure groups together data that describe the signature for which a marshaling stub is being generated. struct StubSigDesc @@ -58,8 +55,6 @@ struct StubSigDesc //======================================================================= class NDirect { - friend class NDirectMethodDesc; - public: //--------------------------------------------------------- // Does a class or method have a NAT_L CustomAttribute? @@ -70,17 +65,6 @@ class NDirect //--------------------------------------------------------- static HRESULT HasNAT_LAttribute(IMDInternalImport *pInternalImport, mdToken token, DWORD dwMemberAttrs); - static LPVOID NDirectGetEntryPoint(NDirectMethodDesc *pMD, NATIVE_LIBRARY_HANDLE hMod); - static NATIVE_LIBRARY_HANDLE LoadLibraryFromPath(LPCWSTR libraryPath, BOOL throwOnError); - static NATIVE_LIBRARY_HANDLE LoadLibraryByName(LPCWSTR name, Assembly *callingAssembly, - BOOL hasDllImportSearchPathFlags, DWORD dllImportSearchPathFlags, - BOOL throwOnError); - static NATIVE_LIBRARY_HANDLE LoadNativeLibrary(NDirectMethodDesc * pMD, LoadLibErrorTracker *pErrorTracker); - static void FreeNativeLibrary(NATIVE_LIBRARY_HANDLE handle); - static INT_PTR GetNativeLibraryExport(NATIVE_LIBRARY_HANDLE handle, LPCWSTR symbolName, BOOL throwOnError); - - static VOID NDirectLink(NDirectMethodDesc *pMD); - // Either MD or signature & module must be given. static BOOL MarshalingRequired( _In_opt_ MethodDesc* pMD, @@ -114,15 +98,9 @@ class NDirect MethodDesc* pMD); static MethodDesc* GetILStubMethodDesc(NDirectMethodDesc* pNMD, PInvokeStaticSigInfo* pSigInfo, DWORD dwNGenStubFlags); - static MethodDesc* GetStubMethodDesc(MethodDesc *pTargetMD, NDirectStubParameters* pParams, ILStubHashBlob* pHashParams, AllocMemTracker* pamTracker, bool& bILStubCreator, MethodDesc* pLastMD); - static void AddMethodDescChunkWithLockTaken(NDirectStubParameters* pParams, MethodDesc *pMD); - static void RemoveILStubCacheEntry(NDirectStubParameters* pParams, ILStubHashBlob* pHashParams); - static ILStubHashBlob* CreateHashBlob(NDirectStubParameters* pParams); static PCODE GetStubForILStub(NDirectMethodDesc* pNMD, MethodDesc** ppStubMD, DWORD dwStubFlags); static PCODE GetStubForILStub(MethodDesc* pMD, MethodDesc** ppStubMD, DWORD dwStubFlags); - inline static ILStubCache* GetILStubCache(NDirectStubParameters* pParams); - private: NDirect() {LIMITED_METHOD_CONTRACT;}; // prevent "new"'s on this class }; @@ -565,53 +543,6 @@ class NDirectStubLinker : public ILStubLinker BOOL HeuristicDoesThisLookLikeAGetLastErrorCall(LPBYTE pTarget); DWORD STDMETHODCALLTYPE FalseGetLastError(); -class NDirectStubParameters -{ -public: - - NDirectStubParameters(Signature sig, - SigTypeContext* pTypeContext, - Module* pModule, - Module* pLoaderModule, - CorNativeLinkType nlType, - CorNativeLinkFlags nlFlags, - CorInfoCallConvExtension unmgdCallConv, - DWORD dwStubFlags, // NDirectStubFlags - int nParamTokens, - mdParamDef* pParamTokenArray, - int iLCIDArg, - MethodTable* pMT - ) : - m_sig(sig), - m_pTypeContext(pTypeContext), - m_pModule(pModule), - m_pLoaderModule(pLoaderModule), - m_pParamTokenArray(pParamTokenArray), - m_unmgdCallConv(unmgdCallConv), - m_nlType(nlType), - m_nlFlags(nlFlags), - m_dwStubFlags(dwStubFlags), - m_iLCIDArg(iLCIDArg), - m_nParamTokens(nParamTokens), - m_pMT(pMT) - { - LIMITED_METHOD_CONTRACT; - } - - Signature m_sig; - SigTypeContext* m_pTypeContext; - Module* m_pModule; - Module* m_pLoaderModule; - mdParamDef* m_pParamTokenArray; - CorInfoCallConvExtension m_unmgdCallConv; - CorNativeLinkType m_nlType; - CorNativeLinkFlags m_nlFlags; - DWORD m_dwStubFlags; - int m_iLCIDArg; - int m_nParamTokens; - MethodTable* m_pMT; -}; - PCODE GetILStubForCalli(VASigCookie *pVASigCookie, MethodDesc *pMD); MethodDesc *GetStubMethodDescFromInteropMethodDesc(MethodDesc* pMD, DWORD dwStubFlags); @@ -636,103 +567,4 @@ void MarshalStructViaILStubCode(PCODE pStubCode, void* pManagedData, void* pNati #define ETW_IL_STUB_EVENT_STRING_FIELD_MAXSIZE (1024) #define ETW_IL_STUB_EVENT_CODE_STRING_FIELD_MAXSIZE (1024*32) -class SString; - -// -// Truncates a SString by first converting it to unicode and truncate it -// if it is larger than size. "..." will be appened if it is truncated. -// -void TruncateUnicodeString(SString &string, COUNT_T bufSize); - -//======================================================================= -// ILStubCreatorHelper -// The class is used as a helper class in CreateInteropILStub. It mainly -// puts two methods NDirect::GetStubMethodDesc and NDirect::RemoveILStubCacheEntry -// into a holder. See CreateInteropILStub for more information -//======================================================================= -class ILStubCreatorHelper -{ -public: - ILStubCreatorHelper(MethodDesc *pTargetMD, - NDirectStubParameters* pParams - ) : - m_pTargetMD(pTargetMD), - m_pParams(pParams), - m_pStubMD(NULL), - m_bILStubCreator(false) - { - STANDARD_VM_CONTRACT; - m_pHashParams = NDirect::CreateHashBlob(m_pParams); - } - - ~ILStubCreatorHelper() - { - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } - CONTRACTL_END; - - RemoveILStubCacheEntry(); - } - - inline void GetStubMethodDesc() - { - WRAPPER_NO_CONTRACT; - - m_pStubMD = NDirect::GetStubMethodDesc(m_pTargetMD, m_pParams, m_pHashParams, &m_amTracker, m_bILStubCreator, m_pStubMD); - } - - inline void RemoveILStubCacheEntry() - { - WRAPPER_NO_CONTRACT; - - if (m_bILStubCreator) - { - NDirect::RemoveILStubCacheEntry(m_pParams, m_pHashParams); - m_bILStubCreator = false; - } - } - - inline MethodDesc* GetStubMD() - { - LIMITED_METHOD_CONTRACT; - return m_pStubMD; - } - - inline void SuppressRelease() - { - WRAPPER_NO_CONTRACT; - m_bILStubCreator = false; - m_amTracker.SuppressRelease(); - } - - DEBUG_NOINLINE static void HolderEnter(ILStubCreatorHelper *pThis) - { - WRAPPER_NO_CONTRACT; - ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT; - pThis->GetStubMethodDesc(); - } - - DEBUG_NOINLINE static void HolderLeave(ILStubCreatorHelper *pThis) - { - WRAPPER_NO_CONTRACT; - ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT; - pThis->RemoveILStubCacheEntry(); - } - -private: - MethodDesc* m_pTargetMD; - NDirectStubParameters* m_pParams; - NewArrayHolder m_pHashParams; - AllocMemTracker* m_pAmTracker; - MethodDesc* m_pStubMD; - AllocMemTracker m_amTracker; - bool m_bILStubCreator; // Only the creator can remove the ILStub from the Cache -}; //ILStubCreatorHelper - -typedef Wrapper ILStubCreatorHelperHolder; - #endif // __dllimport_h__ diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index dc8bdb96db7c94..50e44d2837996a 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -6613,6 +6613,29 @@ CORINFO_CLASS_HANDLE CEEInfo::getTypeInstantiationArgument(CORINFO_CLASS_HANDLE return result; } +/*********************************************************************/ +bool CEEInfo::isJitIntrinsic(CORINFO_METHOD_HANDLE ftn) +{ + CONTRACTL { + NOTHROW; + GC_NOTRIGGER; + MODE_PREEMPTIVE; + } CONTRACTL_END; + + bool ret = false; + + JIT_TO_EE_TRANSITION_LEAF(); + + _ASSERTE(ftn); + + MethodDesc *pMD = (MethodDesc*)ftn; + ret = pMD->IsJitIntrinsic(); + + EE_TO_JIT_TRANSITION_LEAF(); + + return ret; +} + /*********************************************************************/ uint32_t CEEInfo::getMethodAttribs (CORINFO_METHOD_HANDLE ftn) { @@ -9109,7 +9132,7 @@ CORINFO_CLASS_HANDLE CEEInfo::getDefaultComparerClassHelper(CORINFO_CLASS_HANDLE // Mirrors the logic in BCL's CompareHelpers.CreateDefaultComparer // And in compile.cpp's SpecializeComparer - // + // // We need to find the appropriate instantiation Instantiation inst(&elemTypeHnd, 1); @@ -9210,7 +9233,7 @@ CORINFO_CLASS_HANDLE CEEInfo::getDefaultEqualityComparerClassHelper(CORINFO_CLAS // Mirrors the logic in BCL's CompareHelpers.CreateDefaultComparer // And in compile.cpp's SpecializeComparer - // + // // We need to find the appropriate instantiation Instantiation inst(&elemTypeHnd, 1); @@ -12094,7 +12117,7 @@ HRESULT CEEJitInfo::getPgoInstrumentationResults( newPgoData->m_next = m_foundPgoData; m_foundPgoData = newPgoData; newPgoData.SuppressRelease(); - + newPgoData->m_hr = PgoManager::getPgoInstrumentationResults(pMD, &newPgoData->m_allocatedData, &newPgoData->m_schema, &newPgoData->m_cSchemaElems, &newPgoData->m_pInstrumentationData); pDataCur = m_foundPgoData; } diff --git a/src/coreclr/vm/nativelibrary.cpp b/src/coreclr/vm/nativelibrary.cpp new file mode 100644 index 00000000000000..8a894f2a115f04 --- /dev/null +++ b/src/coreclr/vm/nativelibrary.cpp @@ -0,0 +1,909 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include "common.h" +#include "nativelibrary.h" + +#include "clr/fs/path.h" +using namespace clr::fs; + +// Specifies whether hostpolicy is embedded in executable or standalone +extern bool g_hostpolicy_embedded; + +// remove when we get an updated SDK +#define LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR 0x00000100 + +#ifdef TARGET_UNIX +#define PLATFORM_SHARED_LIB_SUFFIX_W PAL_SHLIB_SUFFIX_W +#define PLATFORM_SHARED_LIB_PREFIX_W PAL_SHLIB_PREFIX_W +#else // !TARGET_UNIX +#define PLATFORM_SHARED_LIB_SUFFIX_W W(".dll") +#define PLATFORM_SHARED_LIB_PREFIX_W W("") +#endif // !TARGET_UNIX + +// The Bit 0x2 has different semantics in DllImportSearchPath and LoadLibraryExA flags. +// In DllImportSearchPath enum, bit 0x2 represents SearchAssemblyDirectory -- which is performed by CLR. +// Unlike other bits in this enum, this bit shouldn't be directly passed on to LoadLibrary() +#define DLLIMPORTSEARCHPATH_ASSEMBLYDIRECTORY 0x2 + +namespace +{ + // Preserving good error info from DllImport-driven LoadLibrary is tricky because we keep loading from different places + // if earlier loads fail and those later loads obliterate error codes. + // + // This tracker object will keep track of the error code in accordance to priority: + // + // low-priority: unknown error code (should never happen) + // medium-priority: dll not found + // high-priority: dll found but error during loading + // + // We will overwrite the previous load's error code only if the new error code is higher priority. + // + class LoadLibErrorTracker + { + private: + static const DWORD const_priorityNotFound = 10; + static const DWORD const_priorityAccessDenied = 20; + static const DWORD const_priorityCouldNotLoad = 99999; + public: + LoadLibErrorTracker() + { + LIMITED_METHOD_CONTRACT; + m_hr = E_FAIL; + m_priorityOfLastError = 0; + } + + VOID TrackErrorCode() + { + LIMITED_METHOD_CONTRACT; + + DWORD priority; + +#ifdef TARGET_UNIX + SetMessage(PAL_GetLoadLibraryError()); +#else + DWORD dwLastError = GetLastError(); + + switch (dwLastError) + { + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + case ERROR_MOD_NOT_FOUND: + case ERROR_DLL_NOT_FOUND: + priority = const_priorityNotFound; + break; + + // If we can't access a location, we can't know if the dll's there or if it's good. + // Still, this is probably more unusual (and thus of more interest) than a dll-not-found + // so give it an intermediate priority. + case ERROR_ACCESS_DENIED: + priority = const_priorityAccessDenied; + + // Assume all others are "dll found but couldn't load." + default: + priority = const_priorityCouldNotLoad; + break; + } + UpdateHR(priority, HRESULT_FROM_WIN32(dwLastError)); +#endif + } + + HRESULT GetHR() + { + return m_hr; + } + + SString& GetMessage() + { + return m_message; + } + + void DECLSPEC_NORETURN Throw(SString &libraryNameOrPath) + { + STANDARD_VM_CONTRACT; + +#if defined(__APPLE__) + COMPlusThrow(kDllNotFoundException, IDS_EE_NDIRECT_LOADLIB_MAC, libraryNameOrPath.GetUnicode(), GetMessage()); +#elif defined(TARGET_UNIX) + COMPlusThrow(kDllNotFoundException, IDS_EE_NDIRECT_LOADLIB_LINUX, libraryNameOrPath.GetUnicode(), GetMessage()); +#else // __APPLE__ + HRESULT theHRESULT = GetHR(); + if (theHRESULT == HRESULT_FROM_WIN32(ERROR_BAD_EXE_FORMAT)) + { + COMPlusThrow(kBadImageFormatException); + } + else + { + SString hrString; + GetHRMsg(theHRESULT, hrString); + COMPlusThrow(kDllNotFoundException, IDS_EE_NDIRECT_LOADLIB_WIN, libraryNameOrPath.GetUnicode(), hrString); + } +#endif // TARGET_UNIX + + __UNREACHABLE(); + } + + private: + void UpdateHR(DWORD priority, HRESULT hr) + { + if (priority > m_priorityOfLastError) + { + m_hr = hr; + m_priorityOfLastError = priority; + } + } + + void SetMessage(LPCSTR message) + { + m_message = SString(SString::Utf8, message); + } + + HRESULT m_hr; + DWORD m_priorityOfLastError; + SString m_message; + }; // class LoadLibErrorTracker + + // Load the library directly and return the raw system handle + NATIVE_LIBRARY_HANDLE LocalLoadLibraryHelper( LPCWSTR name, DWORD flags, LoadLibErrorTracker *pErrorTracker ) + { + STANDARD_VM_CONTRACT; + + NATIVE_LIBRARY_HANDLE hmod = NULL; + +#ifndef TARGET_UNIX + if ((flags & 0xFFFFFF00) != 0) + { + hmod = CLRLoadLibraryEx(name, NULL, flags & 0xFFFFFF00); + if (hmod != NULL) + { + return hmod; + } + + DWORD dwLastError = GetLastError(); + if (dwLastError != ERROR_INVALID_PARAMETER) + { + pErrorTracker->TrackErrorCode(); + return hmod; + } + } + + hmod = CLRLoadLibraryEx(name, NULL, flags & 0xFF); + +#else // !TARGET_UNIX + hmod = PAL_LoadLibraryDirect(name); +#endif // !TARGET_UNIX + + if (hmod == NULL) + { + pErrorTracker->TrackErrorCode(); + } + + return hmod; + } + + // DllImportSearchPathFlags is a special enumeration, whose values are tied closely with LoadLibrary flags. + // There is no "default" value DllImportSearchPathFlags. In the absence of DllImportSearchPath attribute, + // CoreCLR's LoadLibrary implementation uses the following defaults. + // Other implementations of LoadLibrary callbacks/events are free to use other default conventions. + void GetDefaultDllImportSearchPathFlags(DWORD *dllImportSearchPathFlags, BOOL *searchAssemblyDirectory) + { + STANDARD_VM_CONTRACT; + + *searchAssemblyDirectory = TRUE; + *dllImportSearchPathFlags = 0; + } + + // If a module has the DefaultDllImportSearchPathsAttribute, get DllImportSearchPathFlags from it, and return true. + // Otherwise, get CoreCLR's default value for DllImportSearchPathFlags, and return false. + BOOL GetDllImportSearchPathFlags(Module *pModule, DWORD *dllImportSearchPathFlags, BOOL *searchAssemblyDirectory) + { + STANDARD_VM_CONTRACT; + + if (pModule->HasDefaultDllImportSearchPathsAttribute()) + { + *dllImportSearchPathFlags = pModule->DefaultDllImportSearchPathsAttributeCachedValue(); + *searchAssemblyDirectory = pModule->DllImportSearchAssemblyDirectory(); + return TRUE; + } + + GetDefaultDllImportSearchPathFlags(dllImportSearchPathFlags, searchAssemblyDirectory); + return FALSE; + } + + // If a pInvoke has the DefaultDllImportSearchPathsAttribute, get DllImportSearchPathFlags from it, and returns true. + // Otherwise, if the containing assembly has the DefaultDllImportSearchPathsAttribute, get DllImportSearchPathFlags from it, and returns true. + // Otherwise, get CoreCLR's default value for DllImportSearchPathFlags, and return false. + BOOL GetDllImportSearchPathFlags(NDirectMethodDesc * pMD, DWORD *dllImportSearchPathFlags, BOOL *searchAssemblyDirectory) + { + STANDARD_VM_CONTRACT; + + if (pMD->HasDefaultDllImportSearchPathsAttribute()) + { + *dllImportSearchPathFlags = pMD->DefaultDllImportSearchPathsAttributeCachedValue(); + *searchAssemblyDirectory = pMD->DllImportSearchAssemblyDirectory(); + return TRUE; + } + + return GetDllImportSearchPathFlags(pMD->GetModule(), dllImportSearchPathFlags, searchAssemblyDirectory); + } +} + +// static +NATIVE_LIBRARY_HANDLE NativeLibrary::LoadLibraryFromPath(LPCWSTR libraryPath, BOOL throwOnError) +{ + CONTRACTL + { + STANDARD_VM_CHECK; + PRECONDITION(CheckPointer(libraryPath)); + } + CONTRACTL_END; + + LoadLibErrorTracker errorTracker; + const NATIVE_LIBRARY_HANDLE hmod = + LocalLoadLibraryHelper(libraryPath, GetLoadWithAlteredSearchPathFlag(), &errorTracker); + + if (throwOnError && (hmod == nullptr)) + { + SString libraryPathSString(libraryPath); + errorTracker.Throw(libraryPathSString); + } + return hmod; +} + +// static +void NativeLibrary::FreeNativeLibrary(NATIVE_LIBRARY_HANDLE handle) +{ + STANDARD_VM_CONTRACT; + _ASSERTE(handle != NULL); + +#ifndef TARGET_UNIX + BOOL retVal = FreeLibrary(handle); +#else // !TARGET_UNIX + BOOL retVal = PAL_FreeLibraryDirect(handle); +#endif // !TARGET_UNIX + + if (retVal == 0) + COMPlusThrow(kInvalidOperationException, W("Arg_InvalidOperationException")); +} + +//static +INT_PTR NativeLibrary::GetNativeLibraryExport(NATIVE_LIBRARY_HANDLE handle, LPCWSTR symbolName, BOOL throwOnError) +{ + CONTRACTL + { + STANDARD_VM_CHECK; + PRECONDITION(CheckPointer(handle)); + PRECONDITION(CheckPointer(symbolName)); + } + CONTRACTL_END; + + MAKE_UTF8PTR_FROMWIDE(lpstr, symbolName); + +#ifndef TARGET_UNIX + INT_PTR address = reinterpret_cast(GetProcAddress((HMODULE)handle, lpstr)); + if ((address == NULL) && throwOnError) + COMPlusThrow(kEntryPointNotFoundException, IDS_EE_NDIRECT_GETPROCADDR_WIN_DLL, symbolName); +#else // !TARGET_UNIX + INT_PTR address = reinterpret_cast(PAL_GetProcAddressDirect(handle, lpstr)); + if ((address == NULL) && throwOnError) + COMPlusThrow(kEntryPointNotFoundException, IDS_EE_NDIRECT_GETPROCADDR_UNIX_SO, symbolName); +#endif // !TARGET_UNIX + + return address; +} + +namespace +{ +#ifndef TARGET_UNIX + BOOL IsWindowsAPISet(PCWSTR wszLibName) + { + STANDARD_VM_CONTRACT; + + // This is replicating quick check from the OS implementation of api sets. + return SString::_wcsnicmp(wszLibName, W("api-"), 4) == 0 || + SString::_wcsnicmp(wszLibName, W("ext-"), 4) == 0; + } +#endif // !TARGET_UNIX + + NATIVE_LIBRARY_HANDLE LoadNativeLibraryViaAssemblyLoadContext(Assembly * pAssembly, PCWSTR wszLibName) + { + STANDARD_VM_CONTRACT; + +#ifndef TARGET_UNIX + if (IsWindowsAPISet(wszLibName)) + { + // Prevent Overriding of Windows API sets. + return NULL; + } +#endif // !TARGET_UNIX + + NATIVE_LIBRARY_HANDLE hmod = NULL; + AppDomain* pDomain = GetAppDomain(); + CLRPrivBinderCoreCLR *pTPABinder = pDomain->GetTPABinderContext(); + + PEFile *pManifestFile = pAssembly->GetManifestFile(); + PTR_ICLRPrivBinder pBindingContext = pManifestFile->GetBindingContext(); + + //Step 0: Check if the assembly was bound using TPA. + // The Binding Context can be null or an overridden TPA context + if (pBindingContext == NULL) + { + // If we do not have any binder associated, then return to the default resolution mechanism. + return NULL; + } + + UINT_PTR assemblyBinderID = 0; + IfFailThrow(pBindingContext->GetBinderID(&assemblyBinderID)); + + ICLRPrivBinder *pCurrentBinder = reinterpret_cast(assemblyBinderID); + + // For assemblies bound via TPA binder, we should use the standard mechanism to make the pinvoke call. + if (AreSameBinderInstance(pCurrentBinder, pTPABinder)) + { + return NULL; + } + + //Step 1: If the assembly was not bound using TPA, + // Call System.Runtime.Loader.AssemblyLoadContext.ResolveUnmanagedDll to give + // The custom assembly context a chance to load the unmanaged dll. + + GCX_COOP(); + + STRINGREF pUnmanagedDllName; + pUnmanagedDllName = StringObject::NewString(wszLibName); + + GCPROTECT_BEGIN(pUnmanagedDllName); + + // Get the pointer to the managed assembly load context + INT_PTR ptrManagedAssemblyLoadContext = ((CLRPrivBinderAssemblyLoadContext *)pCurrentBinder)->GetManagedAssemblyLoadContext(); + + // Prepare to invoke System.Runtime.Loader.AssemblyLoadContext.ResolveUnmanagedDll method. + PREPARE_NONVIRTUAL_CALLSITE(METHOD__ASSEMBLYLOADCONTEXT__RESOLVEUNMANAGEDDLL); + DECLARE_ARGHOLDER_ARRAY(args, 2); + args[ARGNUM_0] = STRINGREF_TO_ARGHOLDER(pUnmanagedDllName); + args[ARGNUM_1] = PTR_TO_ARGHOLDER(ptrManagedAssemblyLoadContext); + + // Make the call + CALL_MANAGED_METHOD(hmod, NATIVE_LIBRARY_HANDLE, args); + + GCPROTECT_END(); + + return hmod; + } + + // Return the AssemblyLoadContext for an assembly + INT_PTR GetManagedAssemblyLoadContext(Assembly* pAssembly) + { + STANDARD_VM_CONTRACT; + + PTR_ICLRPrivBinder pBindingContext = pAssembly->GetManifestFile()->GetBindingContext(); + if (pBindingContext == NULL) + { + // GetBindingContext() returns NULL for System.Private.CoreLib + return NULL; + } + + UINT_PTR assemblyBinderID = 0; + IfFailThrow(pBindingContext->GetBinderID(&assemblyBinderID)); + + AppDomain *pDomain = GetAppDomain(); + ICLRPrivBinder *pCurrentBinder = reinterpret_cast(assemblyBinderID); + + // The code here deals with two implementations of ICLRPrivBinder interface: + // - CLRPrivBinderCoreCLR for the TPA binder in the default ALC, and + // - CLRPrivBinderAssemblyLoadContext for custom ALCs. + // in order obtain the associated ALC handle. + INT_PTR ptrManagedAssemblyLoadContext = AreSameBinderInstance(pCurrentBinder, pDomain->GetTPABinderContext()) + ? ((CLRPrivBinderCoreCLR *)pCurrentBinder)->GetManagedAssemblyLoadContext() + : ((CLRPrivBinderAssemblyLoadContext *)pCurrentBinder)->GetManagedAssemblyLoadContext(); + + return ptrManagedAssemblyLoadContext; + } + + NATIVE_LIBRARY_HANDLE LoadNativeLibraryViaAssemblyLoadContextEvent(Assembly * pAssembly, PCWSTR wszLibName) + { + STANDARD_VM_CONTRACT; + + INT_PTR ptrManagedAssemblyLoadContext = GetManagedAssemblyLoadContext(pAssembly); + if (ptrManagedAssemblyLoadContext == NULL) + { + return NULL; + } + + NATIVE_LIBRARY_HANDLE hmod = NULL; + + GCX_COOP(); + + struct { + STRINGREF DllName; + OBJECTREF AssemblyRef; + } gc = { NULL, NULL }; + + GCPROTECT_BEGIN(gc); + + gc.DllName = StringObject::NewString(wszLibName); + gc.AssemblyRef = pAssembly->GetExposedObject(); + + // Prepare to invoke System.Runtime.Loader.AssemblyLoadContext.ResolveUnmanagedDllUsingEvent method + // While ResolveUnmanagedDllUsingEvent() could compute the AssemblyLoadContext using the AssemblyRef + // argument, it will involve another pInvoke to the runtime. So AssemblyLoadContext is passed in + // as an additional argument. + PREPARE_NONVIRTUAL_CALLSITE(METHOD__ASSEMBLYLOADCONTEXT__RESOLVEUNMANAGEDDLLUSINGEVENT); + DECLARE_ARGHOLDER_ARRAY(args, 3); + args[ARGNUM_0] = STRINGREF_TO_ARGHOLDER(gc.DllName); + args[ARGNUM_1] = OBJECTREF_TO_ARGHOLDER(gc.AssemblyRef); + args[ARGNUM_2] = PTR_TO_ARGHOLDER(ptrManagedAssemblyLoadContext); + + // Make the call + CALL_MANAGED_METHOD(hmod, NATIVE_LIBRARY_HANDLE, args); + + GCPROTECT_END(); + + return hmod; + } + + NATIVE_LIBRARY_HANDLE LoadNativeLibraryViaDllImportResolver(NDirectMethodDesc * pMD, LPCWSTR wszLibName) + { + STANDARD_VM_CONTRACT; + + if (pMD->GetModule()->IsSystem()) + { + // Don't attempt to callback on Corelib itself. + // The LoadLibrary callback stub is managed code that requires CoreLib + return NULL; + } + + DWORD dllImportSearchPathFlags; + BOOL searchAssemblyDirectory; + BOOL hasDllImportSearchPathFlags = GetDllImportSearchPathFlags(pMD, &dllImportSearchPathFlags, &searchAssemblyDirectory); + dllImportSearchPathFlags |= searchAssemblyDirectory ? DLLIMPORTSEARCHPATH_ASSEMBLYDIRECTORY : 0; + + Assembly* pAssembly = pMD->GetMethodTable()->GetAssembly(); + NATIVE_LIBRARY_HANDLE handle = NULL; + + GCX_COOP(); + + struct { + STRINGREF libNameRef; + OBJECTREF assemblyRef; + } gc = { NULL, NULL }; + + GCPROTECT_BEGIN(gc); + + gc.libNameRef = StringObject::NewString(wszLibName); + gc.assemblyRef = pAssembly->GetExposedObject(); + + PREPARE_NONVIRTUAL_CALLSITE(METHOD__NATIVELIBRARY__LOADLIBRARYCALLBACKSTUB); + DECLARE_ARGHOLDER_ARRAY(args, 4); + args[ARGNUM_0] = STRINGREF_TO_ARGHOLDER(gc.libNameRef); + args[ARGNUM_1] = OBJECTREF_TO_ARGHOLDER(gc.assemblyRef); + args[ARGNUM_2] = BOOL_TO_ARGHOLDER(hasDllImportSearchPathFlags); + args[ARGNUM_3] = DWORD_TO_ARGHOLDER(dllImportSearchPathFlags); + + // Make the call + CALL_MANAGED_METHOD(handle, NATIVE_LIBRARY_HANDLE, args); + GCPROTECT_END(); + + return handle; + } + + // Try to load the module alongside the assembly where the PInvoke was declared. + NATIVE_LIBRARY_HANDLE LoadFromPInvokeAssemblyDirectory(Assembly *pAssembly, LPCWSTR libName, DWORD flags, LoadLibErrorTracker *pErrorTracker) + { + STANDARD_VM_CONTRACT; + + NATIVE_LIBRARY_HANDLE hmod = NULL; + + SString path = pAssembly->GetManifestFile()->GetPath(); + + SString::Iterator lastPathSeparatorIter = path.End(); + if (PEAssembly::FindLastPathSeparator(path, lastPathSeparatorIter)) + { + lastPathSeparatorIter++; + path.Truncate(lastPathSeparatorIter); + + path.Append(libName); + hmod = LocalLoadLibraryHelper(path, flags, pErrorTracker); + } + + return hmod; + } + + // Try to load the module from the native DLL search directories + NATIVE_LIBRARY_HANDLE LoadFromNativeDllSearchDirectories(LPCWSTR libName, DWORD flags, LoadLibErrorTracker *pErrorTracker) + { + STANDARD_VM_CONTRACT; + + NATIVE_LIBRARY_HANDLE hmod = NULL; + AppDomain* pDomain = GetAppDomain(); + + if (pDomain->HasNativeDllSearchDirectories()) + { + AppDomain::PathIterator pathIter = pDomain->IterateNativeDllSearchDirectories(); + while (hmod == NULL && pathIter.Next()) + { + SString qualifiedPath(*(pathIter.GetPath())); + qualifiedPath.Append(libName); + if (!Path::IsRelative(qualifiedPath)) + { + hmod = LocalLoadLibraryHelper(qualifiedPath, flags, pErrorTracker); + } + } + } + + return hmod; + } + +#ifdef TARGET_UNIX + const int MaxVariationCount = 4; + void DetermineLibNameVariations(const WCHAR** libNameVariations, int* numberOfVariations, const SString& libName, bool libNameIsRelativePath) + { + // Supported lib name variations + static auto NameFmt = W("%.0s%s%.0s"); + static auto PrefixNameFmt = W("%s%s%.0s"); + static auto NameSuffixFmt = W("%.0s%s%s"); + static auto PrefixNameSuffixFmt = W("%s%s%s"); + + _ASSERTE(*numberOfVariations >= MaxVariationCount); + + int varCount = 0; + if (!libNameIsRelativePath) + { + libNameVariations[varCount++] = NameFmt; + } + else + { + // We check if the suffix is contained in the name, because on Linux it is common to append + // a version number to the library name (e.g. 'libicuuc.so.57'). + bool containsSuffix = false; + SString::CIterator it = libName.Begin(); + if (libName.Find(it, PLATFORM_SHARED_LIB_SUFFIX_W)) + { + it += COUNTOF(PLATFORM_SHARED_LIB_SUFFIX_W); + containsSuffix = it == libName.End() || *it == (WCHAR)'.'; + } + + // If the path contains a path delimiter, we don't add a prefix + it = libName.Begin(); + bool containsDelim = libName.Find(it, DIRECTORY_SEPARATOR_STR_W); + + if (containsSuffix) + { + libNameVariations[varCount++] = NameFmt; + + if (!containsDelim) + libNameVariations[varCount++] = PrefixNameFmt; + + libNameVariations[varCount++] = NameSuffixFmt; + + if (!containsDelim) + libNameVariations[varCount++] = PrefixNameSuffixFmt; + } + else + { + libNameVariations[varCount++] = NameSuffixFmt; + + if (!containsDelim) + libNameVariations[varCount++] = PrefixNameSuffixFmt; + + libNameVariations[varCount++] = NameFmt; + + if (!containsDelim) + libNameVariations[varCount++] = PrefixNameFmt; + } + } + + *numberOfVariations = varCount; + } +#else // TARGET_UNIX + const int MaxVariationCount = 2; + void DetermineLibNameVariations(const WCHAR** libNameVariations, int* numberOfVariations, const SString& libName, bool libNameIsRelativePath) + { + // Supported lib name variations + static auto NameFmt = W("%.0s%s%.0s"); + static auto NameSuffixFmt = W("%.0s%s%s"); + + _ASSERTE(*numberOfVariations >= MaxVariationCount); + + int varCount = 0; + + // The purpose of following code is to workaround LoadLibrary limitation: + // LoadLibrary won't append extension if filename itself contains '.'. Thus it will break the following scenario: + // [DllImport("A.B")] // The full name for file is "A.B.dll". This is common code pattern for cross-platform PInvoke + // The workaround for above scenario is to call LoadLibrary with "A.B" first, if it fails, then call LoadLibrary with "A.B.dll" + auto it = libName.Begin(); + if (!libNameIsRelativePath || + !libName.Find(it, W('.')) || + libName.EndsWith(W(".")) || + libName.EndsWithCaseInsensitive(W(".dll")) || + libName.EndsWithCaseInsensitive(W(".exe"))) + { + // Follow LoadLibrary rules in MSDN doc: https://msdn.microsoft.com/en-us/library/windows/desktop/ms684175(v=vs.85).aspx + // If the string specifies a full path, the function searches only that path for the module. + // If the string specifies a module name without a path and the file name extension is omitted, the function appends the default library extension .dll to the module name. + // To prevent the function from appending .dll to the module name, include a trailing point character (.) in the module name string. + libNameVariations[varCount++] = NameFmt; + } + else + { + libNameVariations[varCount++] = NameFmt; + libNameVariations[varCount++] = NameSuffixFmt; + } + + *numberOfVariations = varCount; + } +#endif // TARGET_UNIX + + // Search for the library and variants of its name in probing directories. + NATIVE_LIBRARY_HANDLE LoadNativeLibraryBySearch(Assembly *callingAssembly, + BOOL searchAssemblyDirectory, DWORD dllImportSearchPathFlags, + LoadLibErrorTracker * pErrorTracker, LPCWSTR wszLibName) + { + STANDARD_VM_CONTRACT; + + NATIVE_LIBRARY_HANDLE hmod = NULL; + +#if defined(FEATURE_CORESYSTEM) && !defined(TARGET_UNIX) + // Try to go straight to System32 for Windows API sets. This is replicating quick check from + // the OS implementation of api sets. + if (IsWindowsAPISet(wszLibName)) + { + hmod = LocalLoadLibraryHelper(wszLibName, LOAD_LIBRARY_SEARCH_SYSTEM32, pErrorTracker); + if (hmod != NULL) + { + return hmod; + } + } +#endif // FEATURE_CORESYSTEM && !TARGET_UNIX + + if (g_hostpolicy_embedded) + { +#ifdef TARGET_WINDOWS + if (wcscmp(wszLibName, W("hostpolicy.dll")) == 0) + { + return WszGetModuleHandle(NULL); + } +#else + if (wcscmp(wszLibName, W("libhostpolicy")) == 0) + { + return PAL_LoadLibraryDirect(NULL); + } +#endif + } + + AppDomain* pDomain = GetAppDomain(); + DWORD loadWithAlteredPathFlags = GetLoadWithAlteredSearchPathFlag(); + bool libNameIsRelativePath = Path::IsRelative(wszLibName); + + // P/Invokes are often declared with variations on the actual library name. + // For example, it's common to leave off the extension/suffix of the library + // even if it has one, or to leave off a prefix like "lib" even if it has one + // (both of these are typically done to smooth over cross-platform differences). + // We try to dlopen with such variations on the original. + const WCHAR* prefixSuffixCombinations[MaxVariationCount] = {}; + int numberOfVariations = COUNTOF(prefixSuffixCombinations); + DetermineLibNameVariations(prefixSuffixCombinations, &numberOfVariations, wszLibName, libNameIsRelativePath); + for (int i = 0; i < numberOfVariations; i++) + { + SString currLibNameVariation; + currLibNameVariation.Printf(prefixSuffixCombinations[i], PLATFORM_SHARED_LIB_PREFIX_W, wszLibName, PLATFORM_SHARED_LIB_SUFFIX_W); + + // NATIVE_DLL_SEARCH_DIRECTORIES set by host is considered well known path + hmod = LoadFromNativeDllSearchDirectories(currLibNameVariation, loadWithAlteredPathFlags, pErrorTracker); + if (hmod != NULL) + { + return hmod; + } + + if (!libNameIsRelativePath) + { + DWORD flags = loadWithAlteredPathFlags; + if ((dllImportSearchPathFlags & LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR) != 0) + { + // LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR is the only flag affecting absolute path. Don't OR the flags + // unconditionally as all absolute path P/Invokes could then lose LOAD_WITH_ALTERED_SEARCH_PATH. + flags |= dllImportSearchPathFlags; + } + + hmod = LocalLoadLibraryHelper(currLibNameVariation, flags, pErrorTracker); + if (hmod != NULL) + { + return hmod; + } + } + else if ((callingAssembly != nullptr) && searchAssemblyDirectory) + { + hmod = LoadFromPInvokeAssemblyDirectory(callingAssembly, currLibNameVariation, loadWithAlteredPathFlags | dllImportSearchPathFlags, pErrorTracker); + if (hmod != NULL) + { + return hmod; + } + } + + hmod = LocalLoadLibraryHelper(currLibNameVariation, dllImportSearchPathFlags, pErrorTracker); + if (hmod != NULL) + { + return hmod; + } + } + + // This may be an assembly name + // Format is "fileName, assemblyDisplayName" + MAKE_UTF8PTR_FROMWIDE(szLibName, wszLibName); + char *szComma = strchr(szLibName, ','); + if (szComma) + { + *szComma = '\0'; + // Trim white spaces + while (COMCharacter::nativeIsWhiteSpace(*(++szComma))); + + AssemblySpec spec; + if (SUCCEEDED(spec.Init(szComma))) + { + // Need to perform case insensitive hashing. + SString moduleName(SString::Utf8, szLibName); + moduleName.LowerCase(); + + StackScratchBuffer buffer; + szLibName = (LPSTR)moduleName.GetUTF8(buffer); + + Assembly *pAssembly = spec.LoadAssembly(FILE_LOADED); + Module *pModule = pAssembly->FindModuleByName(szLibName); + + hmod = LocalLoadLibraryHelper(pModule->GetPath(), loadWithAlteredPathFlags | dllImportSearchPathFlags, pErrorTracker); + } + } + + return hmod; + } + + NATIVE_LIBRARY_HANDLE LoadNativeLibraryBySearch(NDirectMethodDesc *pMD, LoadLibErrorTracker *pErrorTracker, PCWSTR wszLibName) + { + STANDARD_VM_CONTRACT; + + BOOL searchAssemblyDirectory; + DWORD dllImportSearchPathFlags; + + GetDllImportSearchPathFlags(pMD, &dllImportSearchPathFlags, &searchAssemblyDirectory); + + Assembly *pAssembly = pMD->GetMethodTable()->GetAssembly(); + return LoadNativeLibraryBySearch(pAssembly, searchAssemblyDirectory, dllImportSearchPathFlags, pErrorTracker, wszLibName); + } +} + +// static +NATIVE_LIBRARY_HANDLE NativeLibrary::LoadLibraryByName(LPCWSTR libraryName, Assembly *callingAssembly, + BOOL hasDllImportSearchFlags, DWORD dllImportSearchFlags, + BOOL throwOnError) +{ + CONTRACTL + { + STANDARD_VM_CHECK; + PRECONDITION(CheckPointer(libraryName)); + PRECONDITION(CheckPointer(callingAssembly)); + } + CONTRACTL_END; + + NATIVE_LIBRARY_HANDLE hmod = nullptr; + + // Resolve using the AssemblyLoadContext.LoadUnmanagedDll implementation + hmod = LoadNativeLibraryViaAssemblyLoadContext(callingAssembly, libraryName); + if (hmod != nullptr) + return hmod; + + // Check if a default dllImportSearchPathFlags was passed in. If so, use that value. + // Otherwise, check if the assembly has the DefaultDllImportSearchPathsAttribute attribute. + // If so, use that value. + BOOL searchAssemblyDirectory; + DWORD dllImportSearchPathFlags; + if (hasDllImportSearchFlags) + { + dllImportSearchPathFlags = dllImportSearchFlags & ~DLLIMPORTSEARCHPATH_ASSEMBLYDIRECTORY; + searchAssemblyDirectory = dllImportSearchFlags & DLLIMPORTSEARCHPATH_ASSEMBLYDIRECTORY; + + } + else + { + GetDllImportSearchPathFlags(callingAssembly->GetManifestModule(), + &dllImportSearchPathFlags, &searchAssemblyDirectory); + } + + LoadLibErrorTracker errorTracker; + hmod = LoadNativeLibraryBySearch(callingAssembly, searchAssemblyDirectory, dllImportSearchPathFlags, &errorTracker, libraryName); + if (hmod != nullptr) + return hmod; + + // Resolve using the AssemblyLoadContext.ResolvingUnmanagedDll event + hmod = LoadNativeLibraryViaAssemblyLoadContextEvent(callingAssembly, libraryName); + if (hmod != nullptr) + return hmod; + + if (throwOnError) + { + SString libraryPathSString(libraryName); + errorTracker.Throw(libraryPathSString); + } + + return hmod; +} + +namespace +{ + NATIVE_LIBRARY_HANDLE LoadNativeLibrary(NDirectMethodDesc * pMD, LoadLibErrorTracker * pErrorTracker) + { + CONTRACTL + { + STANDARD_VM_CHECK; + PRECONDITION( CheckPointer( pMD ) ); + } + CONTRACTL_END; + + LPCUTF8 name = pMD->GetLibName(); + if ( !name || !*name ) + return NULL; + + PREFIX_ASSUME( name != NULL ); + MAKE_WIDEPTR_FROMUTF8( wszLibName, name ); + + NativeLibraryHandleHolder hmod = LoadNativeLibraryViaDllImportResolver(pMD, wszLibName); + if (hmod != NULL) + { + return hmod.Extract(); + } + + AppDomain* pDomain = GetAppDomain(); + Assembly* pAssembly = pMD->GetMethodTable()->GetAssembly(); + + hmod = LoadNativeLibraryViaAssemblyLoadContext(pAssembly, wszLibName); + if (hmod != NULL) + { + return hmod.Extract(); + } + + hmod = pDomain->FindUnmanagedImageInCache(wszLibName); + if (hmod != NULL) + { + return hmod.Extract(); + } + + hmod = LoadNativeLibraryBySearch(pMD, pErrorTracker, wszLibName); + if (hmod != NULL) + { + // If we have a handle add it to the cache. + pDomain->AddUnmanagedImageToCache(wszLibName, hmod); + return hmod.Extract(); + } + + hmod = LoadNativeLibraryViaAssemblyLoadContextEvent(pAssembly, wszLibName); + if (hmod != NULL) + { + return hmod.Extract(); + } + + return hmod.Extract(); + } +} + +NATIVE_LIBRARY_HANDLE NativeLibrary::LoadLibraryFromMethodDesc(NDirectMethodDesc * pMD) +{ + CONTRACT(NATIVE_LIBRARY_HANDLE) + { + STANDARD_VM_CHECK; + PRECONDITION(CheckPointer(pMD)); + POSTCONDITION(RETVAL != NULL); + } + CONTRACT_END; + + LoadLibErrorTracker errorTracker; + NATIVE_LIBRARY_HANDLE hmod = LoadNativeLibrary(pMD, &errorTracker); + if (hmod == NULL) + { + if (pMD->GetLibName() == NULL) + COMPlusThrow(kEntryPointNotFoundException, IDS_EE_NDIRECT_GETPROCADDRESS_NONAME); + + StackSString ssLibName(SString::Utf8, pMD->GetLibName()); + errorTracker.Throw(ssLibName); + } + + RETURN hmod; +} diff --git a/src/coreclr/vm/nativelibrary.h b/src/coreclr/vm/nativelibrary.h new file mode 100644 index 00000000000000..f05146862c285d --- /dev/null +++ b/src/coreclr/vm/nativelibrary.h @@ -0,0 +1,22 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#ifndef _NATIVELIBRARY_H_ +#define _NATIVELIBRARY_H_ + +#include + +class NativeLibrary +{ +public: + static NATIVE_LIBRARY_HANDLE LoadLibraryFromPath(LPCWSTR libraryPath, BOOL throwOnError); + static NATIVE_LIBRARY_HANDLE LoadLibraryByName(LPCWSTR name, Assembly *callingAssembly, + BOOL hasDllImportSearchPathFlags, DWORD dllImportSearchPathFlags, + BOOL throwOnError); + static void FreeNativeLibrary(NATIVE_LIBRARY_HANDLE handle); + static INT_PTR GetNativeLibraryExport(NATIVE_LIBRARY_HANDLE handle, LPCWSTR symbolName, BOOL throwOnError); + + static NATIVE_LIBRARY_HANDLE LoadLibraryFromMethodDesc(NDirectMethodDesc *pMD); +}; + +#endif // _NATIVELIBRARY_H_ diff --git a/src/coreclr/vm/nativelibrarynative.cpp b/src/coreclr/vm/nativelibrarynative.cpp index d059a3f4a9b9c7..f2c26e0d468e0f 100644 --- a/src/coreclr/vm/nativelibrarynative.cpp +++ b/src/coreclr/vm/nativelibrarynative.cpp @@ -5,7 +5,7 @@ // #include "common.h" -#include "dllimport.h" +#include "nativelibrary.h" #include "nativelibrarynative.h" // static @@ -17,7 +17,7 @@ INT_PTR QCALLTYPE NativeLibraryNative::LoadFromPath(LPCWSTR path, BOOL throwOnEr BEGIN_QCALL; - handle = NDirect::LoadLibraryFromPath(path, throwOnError); + handle = NativeLibrary::LoadLibraryFromPath(path, throwOnError); END_QCALL; @@ -36,7 +36,7 @@ INT_PTR QCALLTYPE NativeLibraryNative::LoadByName(LPCWSTR name, QCall::AssemblyH BEGIN_QCALL; - handle = NDirect::LoadLibraryByName(name, pAssembly, hasDllImportSearchPathFlag, dllImportSearchPathFlag, throwOnError); + handle = NativeLibrary::LoadLibraryByName(name, pAssembly, hasDllImportSearchPathFlag, dllImportSearchPathFlag, throwOnError); END_QCALL; @@ -50,7 +50,7 @@ void QCALLTYPE NativeLibraryNative::FreeLib(INT_PTR handle) BEGIN_QCALL; - NDirect::FreeNativeLibrary((NATIVE_LIBRARY_HANDLE) handle); + NativeLibrary::FreeNativeLibrary((NATIVE_LIBRARY_HANDLE) handle); END_QCALL; } @@ -64,7 +64,7 @@ INT_PTR QCALLTYPE NativeLibraryNative::GetSymbol(INT_PTR handle, LPCWSTR symbolN BEGIN_QCALL; - address = NDirect::GetNativeLibraryExport((NATIVE_LIBRARY_HANDLE)handle, symbolName, throwOnError); + address = NativeLibrary::GetNativeLibraryExport((NATIVE_LIBRARY_HANDLE)handle, symbolName, throwOnError); END_QCALL; diff --git a/src/coreclr/vm/versionresilienthashcode.cpp b/src/coreclr/vm/versionresilienthashcode.cpp index cdf11c23536011..28eecdfea05d5b 100644 --- a/src/coreclr/vm/versionresilienthashcode.cpp +++ b/src/coreclr/vm/versionresilienthashcode.cpp @@ -164,6 +164,7 @@ class ILInstructionParser { *data = *_pCode; _cbCode--; + _pCode++; return true; } return false; @@ -175,6 +176,7 @@ class ILInstructionParser { *data = *(uint16_t UNALIGNED*)_pCode; _cbCode -= 2; + _pCode += 2; return true; } return false; @@ -186,6 +188,7 @@ class ILInstructionParser { *data = *(uint32_t UNALIGNED*)_pCode; _cbCode -= 4; + _pCode += 4; return true; } return false; @@ -237,7 +240,7 @@ bool AddVersionResilientHashCodeForInstruction(ILInstructionParser *parser, xxHa switch (opcodeFormat) { case InlineNone: // no inline args - return opcodeValue; + break; case ShortInlineI: case ShortInlineBrTarget: @@ -355,7 +358,7 @@ bool GetVersionResilientILCodeHashCode(MethodDesc *pMD, int* hashCode, unsigned* { COR_ILMETHOD_DECODER header(pMD->GetILHeader(TRUE), pMD->GetMDImport(), NULL); - pILCode = header.GetCode(); + pILCode = header.Code; cbILCode = header.GetCodeSize(); maxStack = header.GetMaxStack(); EHCount = header.EHCount(); diff --git a/src/coreclr/zap/zapinfo.cpp b/src/coreclr/zap/zapinfo.cpp index 12fe2ab074ce55..4f23cc5d4bbb7f 100644 --- a/src/coreclr/zap/zapinfo.cpp +++ b/src/coreclr/zap/zapinfo.cpp @@ -3959,6 +3959,11 @@ unsigned ZapInfo::getMethodHash(CORINFO_METHOD_HANDLE ftn) return m_pEEJitInfo->getMethodHash(ftn); } +bool ZapInfo::isJitIntrinsic(CORINFO_METHOD_HANDLE ftn) +{ + return m_pEEJitInfo->isJitIntrinsic(ftn); +} + uint32_t ZapInfo::getMethodAttribs(CORINFO_METHOD_HANDLE ftn) { DWORD result = m_pEEJitInfo->getMethodAttribs(ftn); diff --git a/src/installer/pkg/sfx/Microsoft.NETCore.App/ReadyToRun.targets b/src/installer/pkg/sfx/Microsoft.NETCore.App/ReadyToRun.targets index 5d3492a286ed67..5b5f23f28b7d08 100644 --- a/src/installer/pkg/sfx/Microsoft.NETCore.App/ReadyToRun.targets +++ b/src/installer/pkg/sfx/Microsoft.NETCore.App/ReadyToRun.targets @@ -1,15 +1,15 @@ - + - - + + diff --git a/src/libraries/Common/src/Interop/Interop.TimeZoneInfo.cs b/src/libraries/Common/src/Interop/Interop.TimeZoneInfo.cs index faa7e4f3a90738..10e73ee4b1d791 100644 --- a/src/libraries/Common/src/Interop/Interop.TimeZoneInfo.cs +++ b/src/libraries/Common/src/Interop/Interop.TimeZoneInfo.cs @@ -16,7 +16,7 @@ internal static extern unsafe ResultCode GetTimeZoneDisplayName( int resultLength); [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_WindowsIdToIanaId")] - internal static extern unsafe int WindowsIdToIanaId(string windowsId, char* ianaId, int ianaIdLength); + internal static extern unsafe int WindowsIdToIanaId(string windowsId, [MarshalAs(UnmanagedType.LPStr)] string? region, char* ianaId, int ianaIdLength); [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_IanaIdToWindowsId")] internal static extern unsafe int IanaIdToWindowsId(string ianaId, char* windowsId, int windowsIdLength); diff --git a/src/libraries/Native/Unix/System.Globalization.Native/pal_timeZoneInfo.c b/src/libraries/Native/Unix/System.Globalization.Native/pal_timeZoneInfo.c index 9173931716c0e7..2620c146b53a0e 100644 --- a/src/libraries/Native/Unix/System.Globalization.Native/pal_timeZoneInfo.c +++ b/src/libraries/Native/Unix/System.Globalization.Native/pal_timeZoneInfo.c @@ -21,13 +21,13 @@ static const UChar EXEMPLAR_CITY_PATTERN_UCHAR[] = {'V', 'V', 'V', '\0'}; /* Convert Windows Time Zone Id to IANA Id */ -int32_t GlobalizationNative_WindowsIdToIanaId(const UChar* windowsId, UChar* ianaId, int32_t ianaIdLength) +int32_t GlobalizationNative_WindowsIdToIanaId(const UChar* windowsId, const char* region, UChar* ianaId, int32_t ianaIdLength) { UErrorCode status = U_ZERO_ERROR; if (ucal_getTimeZoneIDForWindowsID_ptr != NULL) { - int32_t ianaIdFilledLength = ucal_getTimeZoneIDForWindowsID(windowsId, -1, NULL, ianaId, ianaIdLength, &status); + int32_t ianaIdFilledLength = ucal_getTimeZoneIDForWindowsID(windowsId, -1, region, ianaId, ianaIdLength, &status); if (U_SUCCESS(status)) { return ianaIdFilledLength; @@ -91,7 +91,7 @@ static void GetTimeZoneDisplayName_FromPattern(const char* locale, const UChar* if (U_SUCCESS(*err)) { udat_format(dateFormatter, timestamp, result, resultLength, NULL, err); - udat_close(dateFormatter); + udat_close(dateFormatter); } } diff --git a/src/libraries/Native/Unix/System.Globalization.Native/pal_timeZoneInfo.h b/src/libraries/Native/Unix/System.Globalization.Native/pal_timeZoneInfo.h index 49bfb6250eb507..b91469e6a1341a 100644 --- a/src/libraries/Native/Unix/System.Globalization.Native/pal_timeZoneInfo.h +++ b/src/libraries/Native/Unix/System.Globalization.Native/pal_timeZoneInfo.h @@ -20,6 +20,6 @@ typedef enum TimeZoneDisplayName_ExemplarCity = 4, } TimeZoneDisplayNameType; -PALEXPORT int32_t GlobalizationNative_WindowsIdToIanaId(const UChar* windowsId, UChar* ianaId, int32_t ianaIdLength); +PALEXPORT int32_t GlobalizationNative_WindowsIdToIanaId(const UChar* windowsId, const char* region, UChar* ianaId, int32_t ianaIdLength); PALEXPORT int32_t GlobalizationNative_IanaIdToWindowsId(const UChar* ianaId, UChar* windowsId, int32_t windowsIdLength); PALEXPORT ResultCode GlobalizationNative_GetTimeZoneDisplayName(const UChar* localeName, const UChar* timeZoneId, TimeZoneDisplayNameType type, UChar* result, int32_t resultLength); diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index c67c432163c73d..faea9cca673fdd 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -1046,6 +1046,7 @@ + @@ -1904,7 +1905,7 @@ - + diff --git a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.FullGlobalizationData.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.FullGlobalizationData.Unix.cs new file mode 100644 index 00000000000000..d1f306abb0f6df --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.FullGlobalizationData.Unix.cs @@ -0,0 +1,241 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Globalization; + +namespace System +{ + public sealed partial class TimeZoneInfo + { + private const string InvariantUtcStandardDisplayName = "Coordinated Universal Time"; + private const string FallbackCultureName = "en-US"; + private const string GmtId = "GMT"; + + // Some time zones may give better display names using their location names rather than their generic name. + // We can update this list as need arises. + private static readonly string[] s_ZonesThatUseLocationName = new[] { + "Europe/Minsk", // Prefer "Belarus Time" over "Moscow Standard Time (Minsk)" + "Europe/Moscow", // Prefer "Moscow Time" over "Moscow Standard Time" + "Europe/Simferopol", // Prefer "Simferopol Time" over "Moscow Standard Time (Simferopol)" + "Pacific/Apia", // Prefer "Samoa Time" over "Apia Time" + "Pacific/Pitcairn" // Prefer "Pitcairn Islands Time" over "Pitcairn Time" + }; + + // Main function that is called during construction to populate the three display names + private static void TryPopulateTimeZoneDisplayNamesFromGlobalizationData(string timeZoneId, TimeSpan baseUtcOffset, ref string? standardDisplayName, ref string? daylightDisplayName, ref string? displayName) + { + // Determine the culture to use + CultureInfo uiCulture = CultureInfo.CurrentUICulture; + if (uiCulture.Name.Length == 0) + uiCulture = CultureInfo.GetCultureInfo(FallbackCultureName); // ICU doesn't work nicely with InvariantCulture + + // Attempt to populate the fields backing the StandardName, DaylightName, and DisplayName from globalization data. + GetDisplayName(timeZoneId, Interop.Globalization.TimeZoneDisplayNameType.Standard, uiCulture.Name, ref standardDisplayName); + GetDisplayName(timeZoneId, Interop.Globalization.TimeZoneDisplayNameType.DaylightSavings, uiCulture.Name, ref daylightDisplayName); + GetFullValueForDisplayNameField(timeZoneId, baseUtcOffset, uiCulture, ref displayName); + } + + // Helper function to get the standard display name for the UTC static time zone instance + private static string GetUtcStandardDisplayName() + { + // Don't bother looking up the name for invariant or English cultures + CultureInfo uiCulture = CultureInfo.CurrentUICulture; + if (GlobalizationMode.Invariant || uiCulture.Name.Length == 0 || uiCulture.TwoLetterISOLanguageName == "en") + return InvariantUtcStandardDisplayName; + + // Try to get a localized version of "Coordinated Universal Time" from the globalization data + string? standardDisplayName = null; + GetDisplayName(UtcId, Interop.Globalization.TimeZoneDisplayNameType.Standard, uiCulture.Name, ref standardDisplayName); + + // Final safety check. Don't allow null or abbreviations + if (standardDisplayName == null || standardDisplayName == "GMT" || standardDisplayName == "UTC") + standardDisplayName = InvariantUtcStandardDisplayName; + + return standardDisplayName; + } + + // Helper function to get the full display name for the UTC static time zone instance + private static string GetUtcFullDisplayName(string timeZoneId, string standardDisplayName) + { + return $"(UTC) {standardDisplayName}"; + } + + // Helper function that retrieves various forms of time zone display names from ICU + private static unsafe void GetDisplayName(string timeZoneId, Interop.Globalization.TimeZoneDisplayNameType nameType, string uiCulture, ref string? displayName) + { + if (GlobalizationMode.Invariant) + { + return; + } + + string? timeZoneDisplayName; + bool result = Interop.CallStringMethod( + (buffer, locale, id, type) => + { + fixed (char* bufferPtr = buffer) + { + return Interop.Globalization.GetTimeZoneDisplayName(locale, id, type, bufferPtr, buffer.Length); + } + }, + uiCulture, + timeZoneId, + nameType, + out timeZoneDisplayName); + + if (!result && uiCulture != FallbackCultureName) + { + // Try to fallback using FallbackCultureName just in case we can make it work. + result = Interop.CallStringMethod( + (buffer, locale, id, type) => + { + fixed (char* bufferPtr = buffer) + { + return Interop.Globalization.GetTimeZoneDisplayName(locale, id, type, bufferPtr, buffer.Length); + } + }, + FallbackCultureName, + timeZoneId, + nameType, + out timeZoneDisplayName); + } + + // If there is an unknown error, don't set the displayName field. + // It will be set to the abbreviation that was read out of the tzfile. + if (result && !string.IsNullOrEmpty(timeZoneDisplayName)) + { + displayName = timeZoneDisplayName; + } + } + + // Helper function that builds the value backing the DisplayName field from globalization data. + private static void GetFullValueForDisplayNameField(string timeZoneId, TimeSpan baseUtcOffset, CultureInfo uiCulture, ref string? displayName) + { + // There are a few diffent ways we might show the display name depending on the data. + // The algorithm used below should avoid duplicating the same words while still achieving the + // goal of providing a unique, discoverable, and intuitive name. + + // Try to get the generic name for this time zone. + string? genericName = null; + GetDisplayName(timeZoneId, Interop.Globalization.TimeZoneDisplayNameType.Generic, uiCulture.Name, ref genericName); + if (genericName == null) + { + // We'll use the fallback display name value already set. + return; + } + + // Get the base offset to prefix in front of the time zone. + // Only UTC and its aliases have "(UTC)", handled earlier. All other zones include an offset, even if it's zero. + string baseOffsetText = $"(UTC{(baseUtcOffset >= TimeSpan.Zero ? '+' : '-')}{baseUtcOffset:hh\\:mm})"; + + // Get the generic location name. + string? genericLocationName = null; + GetDisplayName(timeZoneId, Interop.Globalization.TimeZoneDisplayNameType.GenericLocation, uiCulture.Name, ref genericLocationName); + + // Some edge cases only apply when the offset is +00:00. + if (baseUtcOffset == TimeSpan.Zero) + { + // GMT and its aliases will just use the equivalent of "Greenwich Mean Time". + string? gmtLocationName = null; + GetDisplayName(GmtId, Interop.Globalization.TimeZoneDisplayNameType.GenericLocation, uiCulture.Name, ref gmtLocationName); + if (genericLocationName == gmtLocationName) + { + displayName = $"{baseOffsetText} {genericName}"; + return; + } + + // Other zones with a zero offset and the equivalent of "Greenwich Mean Time" should only use the location name. + // For example, prefer "Iceland Time" over "Greenwich Mean Time (Reykjavik)". + string? gmtGenericName = null; + GetDisplayName(GmtId, Interop.Globalization.TimeZoneDisplayNameType.Generic, uiCulture.Name, ref gmtGenericName); + if (genericName == gmtGenericName) + { + displayName = $"{baseOffsetText} {genericLocationName}"; + return; + } + } + + if (genericLocationName == genericName) + { + // When the location name is the same as the generic name, + // then it is generally good enough to show by itself. + + // *** Example (en-US) *** + // id = "America/Havana" + // baseOffsetText = "(UTC-05:00)" + // standardName = "Cuba Standard Time" + // genericName = "Cuba Time" + // genericLocationName = "Cuba Time" + // exemplarCityName = "Havana" + // displayName = "(UTC-05:00) Cuba Time" + + displayName = $"{baseOffsetText} {genericLocationName}"; + return; + } + + // Prefer location names in some special cases. + if (StringArrayContains(timeZoneId, s_ZonesThatUseLocationName, StringComparison.OrdinalIgnoreCase)) + { + displayName = $"{baseOffsetText} {genericLocationName}"; + return; + } + + // See if we should include the exemplar city name. + string exemplarCityName = GetExemplarCityName(timeZoneId, uiCulture.Name); + if (uiCulture.CompareInfo.IndexOf(genericName, exemplarCityName, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace) >= 0 && genericLocationName != null) + { + // When an exemplar city is already part of the generic name, + // there's no need to repeat it again so just use the generic name. + + // *** Example (fr-FR) *** + // id = "Australia/Lord_Howe" + // baseOffsetText = "(UTC+10:30)" + // standardName = "heure normale de Lord Howe" + // genericName = "heure de Lord Howe" + // genericLocationName = "heure : Lord Howe" + // exemplarCityName = "Lord Howe" + // displayName = "(UTC+10:30) heure de Lord Howe" + + displayName = $"{baseOffsetText} {genericName}"; + } + else + { + // Finally, use the generic name and the exemplar city together. + // This provides an intuitive name and still disambiguates. + + // *** Example (en-US) *** + // id = "Europe/Rome" + // baseOffsetText = "(UTC+01:00)" + // standardName = "Central European Standard Time" + // genericName = "Central European Time" + // genericLocationName = "Italy Time" + // exemplarCityName = "Rome" + // displayName = "(UTC+01:00) Central European Time (Rome)" + + displayName = $"{baseOffsetText} {genericName} ({exemplarCityName})"; + } + } + + // Helper function that gets an exmplar city name either from ICU or from the IANA time zone ID itself + private static string GetExemplarCityName(string timeZoneId, string uiCultureName) + { + // First try to get the name through the localization data. + string? exemplarCityName = null; + GetDisplayName(timeZoneId, Interop.Globalization.TimeZoneDisplayNameType.ExemplarCity, uiCultureName, ref exemplarCityName); + if (!string.IsNullOrEmpty(exemplarCityName)) + return exemplarCityName; + + // Support for getting exemplar city names was added in ICU 51. + // We may have an older version. For example, in Helix we test on RHEL 7.5 which uses ICU 50.1.2. + // We'll fallback to using an English name generated from the time zone ID. + int i = timeZoneId.LastIndexOf('/'); + return timeZoneId.Substring(i + 1).Replace('_', ' '); + } + + // Helper function that returns an alternative ID using ICU data. Used primarily for converting from Windows IDs. + private static unsafe string? GetAlternativeId(string id, out bool idIsIana) + { + idIsIana = false; + return TryConvertWindowsIdToIanaId(id, null, out string? ianaId) ? ianaId : null; + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.FullGlobalizationData.cs b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.FullGlobalizationData.cs index 3e0230f9e81b2f..557e333d4eb9a5 100644 --- a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.FullGlobalizationData.cs +++ b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.FullGlobalizationData.cs @@ -7,260 +7,75 @@ namespace System { public sealed partial class TimeZoneInfo { - private const string InvariantUtcStandardDisplayName = "Coordinated Universal Time"; - private const string FallbackCultureName = "en-US"; - private const string GmtId = "GMT"; - - // Some time zones may give better display names using their location names rather than their generic name. - // We can update this list as need arises. - private static readonly string[] s_ZonesThatUseLocationName = new[] { - "Europe/Minsk", // Prefer "Belarus Time" over "Moscow Standard Time (Minsk)" - "Europe/Moscow", // Prefer "Moscow Time" over "Moscow Standard Time" - "Europe/Simferopol", // Prefer "Simferopol Time" over "Moscow Standard Time (Simferopol)" - "Pacific/Apia", // Prefer "Samoa Time" over "Apia Time" - "Pacific/Pitcairn" // Prefer "Pitcairn Islands Time" over "Pitcairn Time" - }; - - // Main function that is called during construction to populate the three display names - private static void TryPopulateTimeZoneDisplayNamesFromGlobalizationData(string timeZoneId, TimeSpan baseUtcOffset, ref string? standardDisplayName, ref string? daylightDisplayName, ref string? displayName) - { - // Determine the culture to use - CultureInfo uiCulture = CultureInfo.CurrentUICulture; - if (uiCulture.Name.Length == 0) - uiCulture = CultureInfo.GetCultureInfo(FallbackCultureName); // ICU doesn't work nicely with InvariantCulture - - // Attempt to populate the fields backing the StandardName, DaylightName, and DisplayName from globalization data. - GetDisplayName(timeZoneId, Interop.Globalization.TimeZoneDisplayNameType.Standard, uiCulture.Name, ref standardDisplayName); - GetDisplayName(timeZoneId, Interop.Globalization.TimeZoneDisplayNameType.DaylightSavings, uiCulture.Name, ref daylightDisplayName); - GetFullValueForDisplayNameField(timeZoneId, baseUtcOffset, uiCulture, ref displayName); - } - - // Helper function to get the standard display name for the UTC static time zone instance - private static string GetUtcStandardDisplayName() - { - // Don't bother looking up the name for invariant or English cultures - CultureInfo uiCulture = CultureInfo.CurrentUICulture; - if (GlobalizationMode.Invariant || uiCulture.Name.Length == 0 || uiCulture.TwoLetterISOLanguageName == "en") - return InvariantUtcStandardDisplayName; - - // Try to get a localized version of "Coordinated Universal Time" from the globalization data - string? standardDisplayName = null; - GetDisplayName(UtcId, Interop.Globalization.TimeZoneDisplayNameType.Standard, uiCulture.Name, ref standardDisplayName); - - // Final safety check. Don't allow null or abbreviations - if (standardDisplayName == null || standardDisplayName == "GMT" || standardDisplayName == "UTC") - standardDisplayName = InvariantUtcStandardDisplayName; - - return standardDisplayName; - } - - // Helper function to get the full display name for the UTC static time zone instance - private static string GetUtcFullDisplayName(string timeZoneId, string standardDisplayName) - { - return $"(UTC) {standardDisplayName}"; - } - - // Helper function that retrieves various forms of time zone display names from ICU - private static unsafe void GetDisplayName(string timeZoneId, Interop.Globalization.TimeZoneDisplayNameType nameType, string uiCulture, ref string? displayName) + private static unsafe bool TryConvertIanaIdToWindowsId(string ianaId, bool allocate, out string? windowsId) { - if (GlobalizationMode.Invariant) + if (GlobalizationMode.Invariant || GlobalizationMode.UseNls || ianaId is null) { - return; + windowsId = null; + return false; } - string? timeZoneDisplayName; - bool result = Interop.CallStringMethod( - (buffer, locale, id, type) => - { - fixed (char* bufferPtr = buffer) - { - return Interop.Globalization.GetTimeZoneDisplayName(locale, id, type, bufferPtr, buffer.Length); - } - }, - uiCulture, - timeZoneId, - nameType, - out timeZoneDisplayName); - - if (!result && uiCulture != FallbackCultureName) + foreach (char c in ianaId) { - // Try to fallback using FallbackCultureName just in case we can make it work. - result = Interop.CallStringMethod( - (buffer, locale, id, type) => - { - fixed (char* bufferPtr = buffer) - { - return Interop.Globalization.GetTimeZoneDisplayName(locale, id, type, bufferPtr, buffer.Length); - } - }, - FallbackCultureName, - timeZoneId, - nameType, - out timeZoneDisplayName); + // ICU uses some characters as a separator and trim the id at that character. + // while we should fail if the Id contained one of these characters. + if (c == '\\' || c == '\n' || c == '\r') + { + windowsId = null; + return false; + } } - // If there is an unknown error, don't set the displayName field. - // It will be set to the abbreviation that was read out of the tzfile. - if (result && !string.IsNullOrEmpty(timeZoneDisplayName)) + char* buffer = stackalloc char[100]; + int length = Interop.Globalization.IanaIdToWindowsId(ianaId, buffer, 100); + if (length > 0) { - displayName = timeZoneDisplayName; + windowsId = allocate ? new string(buffer, 0, length) : null; + return true; } + + windowsId = null; + return false; } - // Helper function that builds the value backing the DisplayName field from globalization data. - private static void GetFullValueForDisplayNameField(string timeZoneId, TimeSpan baseUtcOffset, CultureInfo uiCulture, ref string? displayName) + private static unsafe bool TryConvertWindowsIdToIanaId(string windowsId, string? region, bool allocate, out string? ianaId) { - // There are a few diffent ways we might show the display name depending on the data. - // The algorithm used below should avoid duplicating the same words while still achieving the - // goal of providing a unique, discoverable, and intuitive name. - - // Try to get the generic name for this time zone. - string? genericName = null; - GetDisplayName(timeZoneId, Interop.Globalization.TimeZoneDisplayNameType.Generic, uiCulture.Name, ref genericName); - if (genericName == null) + // This functionality is not enabled in the browser for the sake of size reduction. + if (GlobalizationMode.Invariant || GlobalizationMode.UseNls || windowsId is null) { - // We'll use the fallback display name value already set. - return; + ianaId = null; + return false; } - // Get the base offset to prefix in front of the time zone. - // Only UTC and its aliases have "(UTC)", handled earlier. All other zones include an offset, even if it's zero. - string baseOffsetText = $"(UTC{(baseUtcOffset >= TimeSpan.Zero ? '+' : '-')}{baseUtcOffset:hh\\:mm})"; - - // Get the generic location name. - string? genericLocationName = null; - GetDisplayName(timeZoneId, Interop.Globalization.TimeZoneDisplayNameType.GenericLocation, uiCulture.Name, ref genericLocationName); - - // Some edge cases only apply when the offset is +00:00. - if (baseUtcOffset == TimeSpan.Zero) + if (windowsId.Equals("utc", StringComparison.OrdinalIgnoreCase)) { - // GMT and its aliases will just use the equivalent of "Greenwich Mean Time". - string? gmtLocationName = null; - GetDisplayName(GmtId, Interop.Globalization.TimeZoneDisplayNameType.GenericLocation, uiCulture.Name, ref gmtLocationName); - if (genericLocationName == gmtLocationName) - { - displayName = $"{baseOffsetText} {genericName}"; - return; - } - - // Other zones with a zero offset and the equivalent of "Greenwich Mean Time" should only use the location name. - // For example, prefer "Iceland Time" over "Greenwich Mean Time (Reykjavik)". - string? gmtGenericName = null; - GetDisplayName(GmtId, Interop.Globalization.TimeZoneDisplayNameType.Generic, uiCulture.Name, ref gmtGenericName); - if (genericName == gmtGenericName) - { - displayName = $"{baseOffsetText} {genericLocationName}"; - return; - } + // Special case UTC, as previously ICU would convert it to "Etc/GMT" which is incorrect name for UTC. + ianaId = "Etc/UTC"; + return true; } - if (genericLocationName == genericName) + foreach (char c in windowsId) { - // When the location name is the same as the generic name, - // then it is generally good enough to show by itself. - - // *** Example (en-US) *** - // id = "America/Havana" - // baseOffsetText = "(UTC-05:00)" - // standardName = "Cuba Standard Time" - // genericName = "Cuba Time" - // genericLocationName = "Cuba Time" - // exemplarCityName = "Havana" - // displayName = "(UTC-05:00) Cuba Time" - - displayName = $"{baseOffsetText} {genericLocationName}"; - return; - } - - // Prefer location names in some special cases. - if (StringArrayContains(timeZoneId, s_ZonesThatUseLocationName, StringComparison.OrdinalIgnoreCase)) - { - displayName = $"{baseOffsetText} {genericLocationName}"; - return; + // ICU uses some characters as a separator and trim the id at that character. + // while we should fail if the Id contained one of these characters. + if (c == '\\' || c == '\n' || c == '\r') + { + ianaId = null; + return false; + } } - // See if we should include the exemplar city name. - string exemplarCityName = GetExemplarCityName(timeZoneId, uiCulture.Name); - if (uiCulture.CompareInfo.IndexOf(genericName, exemplarCityName, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace) >= 0 && genericLocationName != null) - { - // When an exemplar city is already part of the generic name, - // there's no need to repeat it again so just use the generic name. - - // *** Example (fr-FR) *** - // id = "Australia/Lord_Howe" - // baseOffsetText = "(UTC+10:30)" - // standardName = "heure normale de Lord Howe" - // genericName = "heure de Lord Howe" - // genericLocationName = "heure : Lord Howe" - // exemplarCityName = "Lord Howe" - // displayName = "(UTC+10:30) heure de Lord Howe" - - displayName = $"{baseOffsetText} {genericName}"; - } - else + char* buffer = stackalloc char[100]; + int length = Interop.Globalization.WindowsIdToIanaId(windowsId, region, buffer, 100); + if (length > 0) { - // Finally, use the generic name and the exemplar city together. - // This provides an intuitive name and still disambiguates. - - // *** Example (en-US) *** - // id = "Europe/Rome" - // baseOffsetText = "(UTC+01:00)" - // standardName = "Central European Standard Time" - // genericName = "Central European Time" - // genericLocationName = "Italy Time" - // exemplarCityName = "Rome" - // displayName = "(UTC+01:00) Central European Time (Rome)" - - displayName = $"{baseOffsetText} {genericName} ({exemplarCityName})"; + ianaId = allocate ? new string(buffer, 0, length) : null; + return true; } - } - - // Helper function that gets an exmplar city name either from ICU or from the IANA time zone ID itself - private static string GetExemplarCityName(string timeZoneId, string uiCultureName) - { - // First try to get the name through the localization data. - string? exemplarCityName = null; - GetDisplayName(timeZoneId, Interop.Globalization.TimeZoneDisplayNameType.ExemplarCity, uiCultureName, ref exemplarCityName); - if (!string.IsNullOrEmpty(exemplarCityName)) - return exemplarCityName; - // Support for getting exemplar city names was added in ICU 51. - // We may have an older version. For example, in Helix we test on RHEL 7.5 which uses ICU 50.1.2. - // We'll fallback to using an English name generated from the time zone ID. - int i = timeZoneId.LastIndexOf('/'); - return timeZoneId.Substring(i + 1).Replace('_', ' '); + ianaId = null; + return false; } - // Helper function that returns an alternative ID using ICU data. Used primarily for converting from Windows IDs. - private static unsafe string? GetAlternativeId(string id) - { - if (!GlobalizationMode.Invariant) - { - if (id.Equals("utc", StringComparison.OrdinalIgnoreCase)) - { - // Special case UTC, as previously ICU would convert it to "Etc/GMT" which is incorrect name for UTC. - return "Etc/UTC"; - } - - foreach (char c in id) - { - // ICU uses some characters as a separator and trim the id at that character. - // while we should fail if the Id contained one of these characters. - if (c == '\\' || c == '\n' || c == '\r') - { - return null; - } - } - - char* buffer = stackalloc char[100]; - int length = Interop.Globalization.WindowsIdToIanaId(id, buffer, 100); - if (length > 0) - { - return new string(buffer, 0, length); - } - } - - return null; - } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.MinimalGlobalizationData.cs b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.MinimalGlobalizationData.cs index 234d63366f3e13..5ef4d16edaa152 100644 --- a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.MinimalGlobalizationData.cs +++ b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.MinimalGlobalizationData.cs @@ -22,10 +22,23 @@ private static string GetUtcFullDisplayName(string timeZoneId, string standardDi return $"(UTC) {timeZoneId}"; } - private static string? GetAlternativeId(string id) + private static string? GetAlternativeId(string id, out bool idIsIana) { // No alternative IDs in this target. + idIsIana = false; return null; } + + private static unsafe bool TryConvertIanaIdToWindowsId(string ianaId, bool allocate, out string? windowsId) + { + windowsId = null; + return false; + } + + private static unsafe bool TryConvertWindowsIdToIanaId(string windowsId, string? region, bool allocate, out string? ianaId) + { + ianaId = null; + return false; + } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.cs index 6c7efd4b662b3f..b664b1f9906964 100644 --- a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.cs @@ -41,6 +41,8 @@ private TimeZoneInfo(byte[] data, string id, bool dstDisabled) { _id = id; + HasIanaId = true; + // Handle UTC and its aliases if (StringArrayContains(_id, s_UtcAliases, StringComparison.OrdinalIgnoreCase)) { diff --git a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Win32.cs b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Win32.cs index a13f48d6258de2..c42bfabd6b74ea 100644 --- a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Win32.cs +++ b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Win32.cs @@ -106,29 +106,10 @@ private static void PopulateAllSystemTimeZones(CachedData cachedData) } } - private static unsafe string? GetAlternativeId(string id) + private static string? GetAlternativeId(string id, out bool idIsIana) { - if (!GlobalizationMode.Invariant && !GlobalizationMode.UseNls) - { - foreach (char c in id) - { - // ICU uses some characters as a separator and trim the id at that character. - // while we should fail if the Id contained one of these characters. - if (c == '\\' || c == '\n' || c == '\r') - { - return null; - } - } - - char* buffer = stackalloc char[100]; - int length = Interop.Globalization.IanaIdToWindowsId(id, buffer, 100); - if (length > 0) - { - return new string(buffer, 0, length); - } - } - - return null; + idIsIana = true; + return TryConvertIanaIdToWindowsId(id, out string? windowsId) ? windowsId : null; } private TimeZoneInfo(in TIME_ZONE_INFORMATION zone, bool dstDisabled) diff --git a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.cs b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.cs index 1ef3a1841ffd11..cb41702cdbd766 100644 --- a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.cs +++ b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.cs @@ -6,6 +6,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; +using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Threading; @@ -136,6 +137,11 @@ public DateTimeKind GetCorrespondingKind(TimeZoneInfo? timeZone) public string Id => _id; + /// + /// Returns true if this TimeZoneInfo object has IANA Id. + /// + public bool HasIanaId { get; } + public string DisplayName => _displayName ?? string.Empty; public string StandardName => _standardDisplayName ?? string.Empty; @@ -880,7 +886,8 @@ private TimeZoneInfo( string? standardDisplayName, string? daylightDisplayName, AdjustmentRule[]? adjustmentRules, - bool disableDaylightSavingTime) + bool disableDaylightSavingTime, + bool hasIanaId = false) { ValidateTimeZoneInfo(id, baseUtcOffset, adjustmentRules, out bool adjustmentRulesSupportDst); @@ -891,6 +898,8 @@ private TimeZoneInfo( _daylightDisplayName = disableDaylightSavingTime ? null : daylightDisplayName; _supportsDaylightSavingTime = adjustmentRulesSupportDst && !disableDaylightSavingTime; _adjustmentRules = adjustmentRules; + + HasIanaId = _id.Equals(UtcId, StringComparison.OrdinalIgnoreCase) ? true : hasIanaId; } /// @@ -902,6 +911,8 @@ public static TimeZoneInfo CreateCustomTimeZone( string? displayName, string? standardDisplayName) { + bool hasIanaId = TimeZoneInfo.TryConvertIanaIdToWindowsId(id, allocate: false, out string _); + return new TimeZoneInfo( id, baseUtcOffset, @@ -909,7 +920,8 @@ public static TimeZoneInfo CreateCustomTimeZone( standardDisplayName, standardDisplayName, adjustmentRules: null, - disableDaylightSavingTime: false); + disableDaylightSavingTime: false, + hasIanaId); } /// @@ -950,6 +962,8 @@ public static TimeZoneInfo CreateCustomTimeZone( adjustmentRules = (AdjustmentRule[])adjustmentRules.Clone(); } + bool hasIanaId = TimeZoneInfo.TryConvertIanaIdToWindowsId(id, allocate: false, out string _); + return new TimeZoneInfo( id, baseUtcOffset, @@ -957,9 +971,35 @@ public static TimeZoneInfo CreateCustomTimeZone( standardDisplayName, daylightDisplayName, adjustmentRules, - disableDaylightSavingTime); + disableDaylightSavingTime, + hasIanaId); } + /// + /// Tries to convert IANA time zone Id to Windows Id. + /// + /// The IANA time zone Id. + /// String object hold the Windows Id which resulted from the IANA Id conversion. + /// True if the Id conversion succeed, false otherwise . + public static unsafe bool TryConvertIanaIdToWindowsId(string ianaId, [NotNullWhen(true)] out string? windowsId) => TryConvertIanaIdToWindowsId(ianaId, allocate: true, out windowsId); + + /// + /// Tries to convert Windows time zone Id to IANA Id. + /// + /// The Windows time zone Id. + /// String object hold the IANA Id which resulted from the Windows Id conversion. + /// True if the Id conversion succeed, false otherwise . + public static bool TryConvertWindowsIdToIanaId(string windowsId, [NotNullWhen(true)] out string? ianaId) => TryConvertWindowsIdToIanaId(windowsId, region: null, allocate: true, out ianaId); + + /// + /// Tries to convert Windows time zone Id to IANA Id. + /// + /// The Windows time zone Id. + /// The ISO 3166 for the country/region. + /// String object hold the IANA Id which resulted from the Windows Id conversion. + /// True if the Id conversion succeed, false otherwise . + public static unsafe bool TryConvertWindowsIdToIanaId(string windowsId, string? region, [NotNullWhen(true)] out string? ianaId) => TryConvertWindowsIdToIanaId(windowsId, region, allocate: true, out ianaId); + void IDeserializationCallback.OnDeserialization(object? sender) { try @@ -1794,7 +1834,7 @@ private static TimeZoneInfoResult TryGetTimeZone(string id, bool dstDisabled, ou TimeZoneInfoResult result = TryGetTimeZoneUsingId(id, dstDisabled, out value, out e, cachedData, alwaysFallbackToLocalMachine); if (result != TimeZoneInfoResult.Success) { - string? alternativeId = GetAlternativeId(id); + string? alternativeId = GetAlternativeId(id, out bool idIsIana); if (alternativeId != null) { result = TryGetTimeZoneUsingId(alternativeId, dstDisabled, out value, out e, cachedData, alwaysFallbackToLocalMachine); @@ -1804,7 +1844,7 @@ private static TimeZoneInfoResult TryGetTimeZone(string id, bool dstDisabled, ou if (value!._equivalentZones == null) { zone = new TimeZoneInfo(id, value!._baseUtcOffset, value!._displayName, value!._standardDisplayName, - value!._daylightDisplayName, value!._adjustmentRules, dstDisabled && value!._supportsDaylightSavingTime); + value!._daylightDisplayName, value!._adjustmentRules, dstDisabled && value!._supportsDaylightSavingTime, idIsIana); value!._equivalentZones = new List(); lock (value!._equivalentZones) { @@ -1824,7 +1864,7 @@ private static TimeZoneInfoResult TryGetTimeZone(string id, bool dstDisabled, ou if (zone == null) { zone = new TimeZoneInfo(id, value!._baseUtcOffset, value!._displayName, value!._standardDisplayName, - value!._daylightDisplayName, value!._adjustmentRules, dstDisabled && value!._supportsDaylightSavingTime); + value!._daylightDisplayName, value!._adjustmentRules, dstDisabled && value!._supportsDaylightSavingTime, idIsIana); lock (value!._equivalentZones) { value!._equivalentZones.Add(zone); @@ -1861,7 +1901,7 @@ private static TimeZoneInfoResult TryGetTimeZoneUsingId(string id, bool dstDisab else { value = new TimeZoneInfo(match._id, match._baseUtcOffset, match._displayName, match._standardDisplayName, - match._daylightDisplayName, match._adjustmentRules, disableDaylightSavingTime: false); + match._daylightDisplayName, match._adjustmentRules, disableDaylightSavingTime: false, match.HasIanaId); } return result; diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index c1d6f802c556dc..bb934e3312fbca 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -3853,6 +3853,7 @@ internal TimeZoneInfo() { } public System.TimeSpan BaseUtcOffset { get { throw null; } } public string DaylightName { get { throw null; } } public string DisplayName { get { throw null; } } + public bool HasIanaId { get; } public string Id { get { throw null; } } public static System.TimeZoneInfo Local { get { throw null; } } public string StandardName { get { throw null; } } @@ -3892,6 +3893,9 @@ void System.Runtime.Serialization.IDeserializationCallback.OnDeserialization(obj void System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { } public string ToSerializedString() { throw null; } public override string ToString() { throw null; } + public static bool TryConvertIanaIdToWindowsId(string ianaId, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out string? windowsId) { throw null; } + public static bool TryConvertWindowsIdToIanaId(string windowsId, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out string? ianaId) { throw null; } + public static bool TryConvertWindowsIdToIanaId(string windowsId, string? region, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out string? ianaId) { throw null; } public sealed partial class AdjustmentRule : System.IEquatable, System.Runtime.Serialization.IDeserializationCallback, System.Runtime.Serialization.ISerializable { internal AdjustmentRule() { } diff --git a/src/libraries/System.Runtime/tests/System/TimeZoneInfoTests.cs b/src/libraries/System.Runtime/tests/System/TimeZoneInfoTests.cs index 32a2f6c722db47..3b72bf0bdf8a53 100644 --- a/src/libraries/System.Runtime/tests/System/TimeZoneInfoTests.cs +++ b/src/libraries/System.Runtime/tests/System/TimeZoneInfoTests.cs @@ -2638,6 +2638,65 @@ public static void UsingAlternativeTimeZoneIdsTest(string windowsId, string iana } } + public static bool SupportIanaNamesConversion => PlatformDetection.IsNotBrowser && PlatformDetection.ICUVersion.Major >= 52; + + [ConditionalFact(nameof(SupportIanaNamesConversion))] + public static void IsIanaIdTest() + { + bool expected = !s_isWindows; + + foreach (TimeZoneInfo tzi in TimeZoneInfo.GetSystemTimeZones()) + { + Assert.True((expected || tzi.Id.Equals("Utc", StringComparison.OrdinalIgnoreCase)) == tzi.HasIanaId, $"`{tzi.Id}` has wrong IANA Id indicator"); + } + + Assert.False(TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time").HasIanaId, $"`Pacific Standard Time` should not be IANA Id."); + Assert.True(TimeZoneInfo.FindSystemTimeZoneById("America/Los_Angeles").HasIanaId, $"'America/Los_Angeles' should be IANA Id"); + } + + [ConditionalTheory(nameof(SupportIanaNamesConversion))] + [InlineData("Pacific Standard Time", "America/Los_Angeles")] + [InlineData("AUS Eastern Standard Time", "Australia/Sydney")] + [InlineData("GMT Standard Time", "Europe/London")] + [InlineData("Tonga Standard Time", "Pacific/Tongatapu")] + [InlineData("W. Australia Standard Time", "Australia/Perth")] + [InlineData("E. South America Standard Time", "America/Sao_Paulo")] + [InlineData("E. Africa Standard Time", "Africa/Nairobi")] + [InlineData("W. Europe Standard Time", "Europe/Berlin")] + [InlineData("Russian Standard Time", "Europe/Moscow")] + [InlineData("Libya Standard Time", "Africa/Tripoli")] + [InlineData("South Africa Standard Time", "Africa/Johannesburg")] + [InlineData("Morocco Standard Time", "Africa/Casablanca")] + [InlineData("Argentina Standard Time", "America/Buenos_Aires")] + [InlineData("Newfoundland Standard Time", "America/St_Johns")] + [InlineData("Iran Standard Time", "Asia/Tehran")] + public static void IdsConversionsTest(string windowsId, string ianaId) + { + Assert.True(TimeZoneInfo.TryConvertIanaIdToWindowsId(ianaId, out string winId)); + Assert.Equal(windowsId, winId); + + Assert.True(TimeZoneInfo.TryConvertWindowsIdToIanaId(winId, out string ianaConvertedId)); + Assert.Equal(ianaId, ianaConvertedId); + } + + [ConditionalTheory(nameof(SupportIanaNamesConversion))] + [InlineData("Pacific Standard Time", "America/Vancouver", "CA")] + [InlineData("Pacific Standard Time", "America/Los_Angeles", "US")] + [InlineData("Pacific Standard Time", "America/Los_Angeles", "\u0600NotValidRegion")] + [InlineData("Central Europe Standard Time", "Europe/Budapest", "DJ")] + [InlineData("Central Europe Standard Time", "Europe/Budapest", "\uFFFFNotValidRegion")] + [InlineData("Central Europe Standard Time", "Europe/Prague", "CZ")] + [InlineData("Central Europe Standard Time", "Europe/Ljubljana", "SI")] + [InlineData("Central Europe Standard Time", "Europe/Bratislava", "SK")] + [InlineData("Central Europe Standard Time", "Europe/Tirane", "AL")] + [InlineData("Central Europe Standard Time", "Europe/Podgorica", "ME")] + [InlineData("Central Europe Standard Time", "Europe/Belgrade", "RS")] + public static void IdsConversionsWithRegionTest(string windowsId, string ianaId, string region) + { + Assert.True(TimeZoneInfo.TryConvertWindowsIdToIanaId(windowsId, region, out string ianaConvertedId)); + Assert.Equal(ianaId, ianaConvertedId); + } + // We test the existence of a specific English time zone name to avoid failures on non-English platforms. [ConditionalFact(nameof(IsEnglishUILanguageAndRemoteExecutorSupported))] public static void TestNameWithInvariantCulture() diff --git a/src/mono/mono/metadata/assembly-load-context.c b/src/mono/mono/metadata/assembly-load-context.c index 1dbd387ab117f0..808789d280bdc7 100644 --- a/src/mono/mono/metadata/assembly-load-context.c +++ b/src/mono/mono/metadata/assembly-load-context.c @@ -41,7 +41,7 @@ mono_alc_init (MonoAssemblyLoadContext *alc, gboolean collectible) mono_loaded_images_init (li, alc); alc->loaded_images = li; alc->loaded_assemblies = NULL; - alc->memory_manager = mono_mem_manager_create_singleton (alc, collectible); + alc->memory_manager = mono_mem_manager_new (&alc, 1, collectible); alc->generic_memory_managers = g_ptr_array_new (); mono_coop_mutex_init (&alc->memory_managers_lock); alc->unloading = FALSE; @@ -172,7 +172,7 @@ mono_alc_cleanup (MonoAssemblyLoadContext *alc) mono_alc_cleanup_assemblies (alc); - mono_mem_manager_free_singleton (alc->memory_manager, FALSE); + mono_mem_manager_free (alc->memory_manager, FALSE); alc->memory_manager = NULL; /*for (int i = 0; i < alc->generic_memory_managers->len; i++) { diff --git a/src/mono/mono/metadata/class-init.c b/src/mono/mono/metadata/class-init.c index a009c68b41c066..89f14dcd844e73 100644 --- a/src/mono/mono/metadata/class-init.c +++ b/src/mono/mono/metadata/class-init.c @@ -824,7 +824,7 @@ mono_class_create_generic_inst (MonoGenericClass *gclass) if (gclass->cached_class) return gclass->cached_class; - klass = (MonoClass *)mono_image_set_alloc0 (gclass->owner, sizeof (MonoClassGenericInst)); + klass = (MonoClass *)mono_mem_manager_alloc0 ((MonoMemoryManager*)gclass->owner, sizeof (MonoClassGenericInst)); gklass = gclass->container_class; @@ -850,7 +850,6 @@ mono_class_create_generic_inst (MonoGenericClass *gclass) klass->enumtype = gklass->enumtype; klass->valuetype = gklass->valuetype; - if (gklass->image->assembly_name && !strcmp (gklass->image->assembly_name, "System.Numerics.Vectors") && !strcmp (gklass->name_space, "System.Numerics") && !strcmp (gklass->name, "Vector`1")) { g_assert (gclass->context.class_inst); g_assert (gclass->context.class_inst->type_argc > 0); @@ -1004,22 +1003,25 @@ mono_class_create_bounded_array (MonoClass *eclass, guint32 rank, gboolean bound GSList *list, *rootlist = NULL; int nsize; char *name; - MonoImageSet* image_set; + MonoMemoryManager *mm; if (rank > 1) /* bounded only matters for one-dimensional arrays */ bounded = FALSE; image = eclass->image; - image_set = class_kind_may_contain_generic_instances ((MonoTypeKind)eclass->class_kind) ? mono_metadata_get_image_set_for_class (eclass) : NULL; + // FIXME: Optimize this + mm = class_kind_may_contain_generic_instances ((MonoTypeKind)eclass->class_kind) ? mono_metadata_get_mem_manager_for_class (eclass) : NULL; /* Check cache */ cached = NULL; if (rank == 1 && !bounded) { - if (image_set) { - mono_image_set_lock (image_set); - cached = (MonoClass *)g_hash_table_lookup (image_set->szarray_cache, eclass); - mono_image_set_unlock (image_set); + if (mm) { + mono_mem_manager_lock (mm); + if (!mm->szarray_cache) + mm->szarray_cache = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, NULL); + cached = (MonoClass *)g_hash_table_lookup (mm->szarray_cache, eclass); + mono_mem_manager_unlock (mm); } else { /* * This case is very frequent not just during compilation because of calls @@ -1033,9 +1035,11 @@ mono_class_create_bounded_array (MonoClass *eclass, guint32 rank, gboolean bound mono_os_mutex_unlock (&image->szarray_cache_lock); } } else { - if (image_set) { - mono_image_set_lock (image_set); - rootlist = (GSList *)g_hash_table_lookup (image_set->array_cache, eclass); + if (mm) { + mono_mem_manager_lock (mm); + if (!mm->array_cache) + mm->array_cache = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, NULL); + rootlist = (GSList *)g_hash_table_lookup (mm->array_cache, eclass); for (list = rootlist; list; list = list->next) { k = (MonoClass *)list->data; if ((m_class_get_rank (k) == rank) && (m_class_get_byval_arg (k)->type == (((rank > 1) || bounded) ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) { @@ -1043,7 +1047,7 @@ mono_class_create_bounded_array (MonoClass *eclass, guint32 rank, gboolean bound break; } } - mono_image_set_unlock (image_set); + mono_mem_manager_unlock (mm); } else { mono_loader_lock (); if (!image->array_cache) @@ -1066,7 +1070,7 @@ mono_class_create_bounded_array (MonoClass *eclass, guint32 rank, gboolean bound if (!parent->inited) mono_class_init_internal (parent); - klass = image_set ? (MonoClass *)mono_image_set_alloc0 (image_set, sizeof (MonoClassArray)) : (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassArray)); + klass = mm ? (MonoClass *)mono_mem_manager_alloc0 (mm, sizeof (MonoClassArray)) : (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassArray)); klass->image = image; klass->name_space = eclass->name_space; @@ -1083,7 +1087,7 @@ mono_class_create_bounded_array (MonoClass *eclass, guint32 rank, gboolean bound name [nsize + maxrank] = '*'; name [nsize + maxrank + bounded] = ']'; name [nsize + maxrank + bounded + 1] = 0; - klass->name = image_set ? mono_image_set_strdup (image_set, name) : mono_image_strdup (image, name); + klass->name = mm ? mono_mem_manager_strdup (mm, name) : mono_image_strdup (image, name); g_free (name); klass->type_token = 0; @@ -1135,7 +1139,7 @@ mono_class_create_bounded_array (MonoClass *eclass, guint32 rank, gboolean bound klass->element_class = eclass; if ((rank > 1) || bounded) { - MonoArrayType *at = image_set ? (MonoArrayType *)mono_image_set_alloc0 (image_set, sizeof (MonoArrayType)) : (MonoArrayType *)mono_image_alloc0 (image, sizeof (MonoArrayType)); + MonoArrayType *at = mm ? (MonoArrayType *)mono_mem_manager_alloc0 (mm, sizeof (MonoArrayType)) : (MonoArrayType *)mono_image_alloc0 (image, sizeof (MonoArrayType)); klass->_byval_arg.type = MONO_TYPE_ARRAY; klass->_byval_arg.data.array = at; at->eklass = eclass; @@ -1162,19 +1166,19 @@ mono_class_create_bounded_array (MonoClass *eclass, guint32 rank, gboolean bound /* Check cache again */ cached = NULL; if (rank == 1 && !bounded) { - if (image_set) { - mono_image_set_lock (image_set); - cached = (MonoClass *)g_hash_table_lookup (image_set->szarray_cache, eclass); - mono_image_set_unlock (image_set); + if (mm) { + mono_mem_manager_lock (mm); + cached = (MonoClass *)g_hash_table_lookup (mm->szarray_cache, eclass); + mono_mem_manager_unlock (mm); } else { mono_os_mutex_lock (&image->szarray_cache_lock); cached = (MonoClass *)g_hash_table_lookup (image->szarray_cache, eclass); mono_os_mutex_unlock (&image->szarray_cache_lock); } } else { - if (image_set) { - mono_image_set_lock (image_set); - rootlist = (GSList *)g_hash_table_lookup (image_set->array_cache, eclass); + if (mm) { + mono_mem_manager_lock (mm); + rootlist = (GSList *)g_hash_table_lookup (mm->array_cache, eclass); for (list = rootlist; list; list = list->next) { k = (MonoClass *)list->data; if ((m_class_get_rank (k) == rank) && (m_class_get_byval_arg (k)->type == (((rank > 1) || bounded) ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) { @@ -1182,7 +1186,7 @@ mono_class_create_bounded_array (MonoClass *eclass, guint32 rank, gboolean bound break; } } - mono_image_set_unlock (image_set); + mono_mem_manager_unlock (mm); } else { rootlist = (GSList *)g_hash_table_lookup (image->array_cache, eclass); for (list = rootlist; list; list = list->next) { @@ -1205,21 +1209,21 @@ mono_class_create_bounded_array (MonoClass *eclass, guint32 rank, gboolean bound ++class_array_count; if (rank == 1 && !bounded) { - if (image_set) { - mono_image_set_lock (image_set); - g_hash_table_insert (image_set->szarray_cache, eclass, klass); - mono_image_set_unlock (image_set); + if (mm) { + mono_mem_manager_lock (mm); + g_hash_table_insert (mm->szarray_cache, eclass, klass); + mono_mem_manager_unlock (mm); } else { mono_os_mutex_lock (&image->szarray_cache_lock); g_hash_table_insert (image->szarray_cache, eclass, klass); mono_os_mutex_unlock (&image->szarray_cache_lock); } } else { - if (image_set) { - mono_image_set_lock (image_set); + if (mm) { + mono_mem_manager_lock (mm); list = g_slist_append (rootlist, klass); - g_hash_table_insert (image_set->array_cache, eclass, list); - mono_image_set_unlock (image_set); + g_hash_table_insert (mm->array_cache, eclass, list); + mono_mem_manager_unlock (mm); } else { list = g_slist_append (rootlist, klass); g_hash_table_insert (image->array_cache, eclass, list); @@ -1407,21 +1411,21 @@ mono_class_create_ptr (MonoType *type) MonoClass *el_class; MonoImage *image; char *name; - MonoImageSet* image_set; + MonoMemoryManager *mm; el_class = mono_class_from_mono_type_internal (type); image = el_class->image; - image_set = class_kind_may_contain_generic_instances ((MonoTypeKind)el_class->class_kind) ? mono_metadata_get_image_set_for_class (el_class) : NULL; - - if (image_set) { - mono_image_set_lock (image_set); - if (image_set->ptr_cache) { - if ((result = (MonoClass *)g_hash_table_lookup (image_set->ptr_cache, el_class))) { - mono_image_set_unlock (image_set); - return result; - } - } - mono_image_set_unlock (image_set); + // FIXME: Optimize this + mm = class_kind_may_contain_generic_instances ((MonoTypeKind)el_class->class_kind) ? mono_metadata_get_mem_manager_for_class (el_class) : NULL; + + if (mm) { + mono_mem_manager_lock (mm); + if (!mm->ptr_cache) + mm->ptr_cache = g_hash_table_new (mono_aligned_addr_hash, NULL); + result = (MonoClass *)g_hash_table_lookup (mm->ptr_cache, el_class); + mono_mem_manager_unlock (mm); + if (result) + return result; } else { mono_image_lock (image); if (image->ptr_cache) { @@ -1433,7 +1437,7 @@ mono_class_create_ptr (MonoType *type) mono_image_unlock (image); } - result = image_set ? (MonoClass *)mono_image_set_alloc0 (image_set, sizeof (MonoClassPointer)) : (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassPointer)); + result = mm ? (MonoClass *)mono_mem_manager_alloc0 (mm, sizeof (MonoClassPointer)) : (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassPointer)); UnlockedAdd (&classes_size, sizeof (MonoClassPointer)); ++class_pointer_count; @@ -1441,7 +1445,7 @@ mono_class_create_ptr (MonoType *type) result->parent = NULL; /* no parent for PTR types */ result->name_space = el_class->name_space; name = g_strdup_printf ("%s*", el_class->name); - result->name = image_set ? mono_image_set_strdup (image_set, name) : mono_image_strdup (image, name); + result->name = mm ? mono_mem_manager_strdup (mm, name) : mono_image_strdup (image, name); result->class_kind = MONO_CLASS_POINTER; g_free (name); @@ -1466,21 +1470,17 @@ mono_class_create_ptr (MonoType *type) mono_class_setup_supertypes (result); - if (image_set) { - mono_image_set_lock (image_set); - if (image_set->ptr_cache) { - MonoClass *result2; - if ((result2 = (MonoClass *)g_hash_table_lookup (image_set->ptr_cache, el_class))) { - mono_image_set_unlock (image_set); - MONO_PROFILER_RAISE (class_failed, (result)); - return result2; - } - } - else { - image_set->ptr_cache = g_hash_table_new (mono_aligned_addr_hash, NULL); + if (mm) { + mono_mem_manager_lock (mm); + MonoClass *result2; + result2 = (MonoClass *)g_hash_table_lookup (mm->ptr_cache, el_class); + if (!result2) + g_hash_table_insert (mm->ptr_cache, el_class, result); + mono_mem_manager_unlock (mm); + if (result2) { + MONO_PROFILER_RAISE (class_failed, (result)); + return result2; } - g_hash_table_insert (image_set->ptr_cache, el_class, result); - mono_image_set_unlock (image_set); } else { mono_image_lock (image); if (image->ptr_cache) { diff --git a/src/mono/mono/metadata/class-internals.h b/src/mono/mono/metadata/class-internals.h index f6130da1b81c61..233e4ecc9b655e 100644 --- a/src/mono/mono/metadata/class-internals.h +++ b/src/mono/mono/metadata/class-internals.h @@ -405,7 +405,7 @@ struct _MonoMethodInflated { } method; MonoMethod *declaring; /* the generic method definition. */ MonoGenericContext context; /* The current instantiation */ - MonoImageSet *owner; /* The image set that the inflated method belongs to. */ + MonoMemoryManager *owner; /* The mem manager that the inflated method belongs to. */ }; /* @@ -419,12 +419,8 @@ struct _MonoGenericClass { guint need_sync : 1; /* Only if dynamic. Need to be synchronized with its container class after its finished. */ MonoClass *cached_class; /* if present, the MonoClass corresponding to the instantiation. */ - /* - * The image set which owns this generic class. Memory owned by the generic class - * including cached_class should be allocated from the mempool of the image set, - * so it is easy to free. - */ - MonoImageSet *owner; + /* The mem manager which owns this generic class. */ + MonoMemoryManager *owner; }; /* Additional details about a MonoGenericParam */ @@ -901,11 +897,14 @@ mono_class_inflate_generic_method_full_checked (MonoMethod *method, MonoClass *k MonoMethod * mono_class_inflate_generic_method_checked (MonoMethod *method, MonoGenericContext *context, MonoError *error); -MonoImageSet * -mono_metadata_get_image_set_for_class (MonoClass *klass); +MonoMemoryManager * +mono_metadata_get_mem_manager_for_type (MonoType *type); + +MonoMemoryManager * +mono_metadata_get_mem_manager_for_class (MonoClass *klass); -MonoImageSet * -mono_metadata_get_image_set_for_method (MonoMethodInflated *method); +MonoMemoryManager* +mono_metadata_get_mem_manager_for_method (MonoMethodInflated *method); MONO_API MonoMethodSignature * mono_metadata_get_inflated_signature (MonoMethodSignature *sig, MonoGenericContext *context); diff --git a/src/mono/mono/metadata/class.c b/src/mono/mono/metadata/class.c index 2d472f7b4c8eee..1bf5438e9f4268 100644 --- a/src/mono/mono/metadata/class.c +++ b/src/mono/mono/metadata/class.c @@ -1116,6 +1116,37 @@ mono_class_inflate_generic_method_checked (MonoMethod *method, MonoGenericContex return mono_class_inflate_generic_method_full_checked (method, NULL, context, error); } +static gboolean +inflated_method_equal (gconstpointer a, gconstpointer b) +{ + const MonoMethodInflated *ma = (const MonoMethodInflated *)a; + const MonoMethodInflated *mb = (const MonoMethodInflated *)b; + if (ma->declaring != mb->declaring) + return FALSE; + return mono_metadata_generic_context_equal (&ma->context, &mb->context); +} + +static guint +inflated_method_hash (gconstpointer a) +{ + const MonoMethodInflated *ma = (const MonoMethodInflated *)a; + return (mono_metadata_generic_context_hash (&ma->context) ^ mono_aligned_addr_hash (ma->declaring)); +} + +static void +free_inflated_method (MonoMethodInflated *imethod) +{ + MonoMethod *method = (MonoMethod*)imethod; + + if (method->signature) + mono_metadata_free_inflated_signature (method->signature); + + if (method->wrapper_type) + g_free (((MonoMethodWrapper*)method)->method_data); + + g_free (method); +} + /** * mono_class_inflate_generic_method_full_checked: * Instantiate method \p method with the generic context \p context. @@ -1178,12 +1209,14 @@ mono_class_inflate_generic_method_full_checked (MonoMethod *method, MonoClass *k if (!mono_class_is_gtd (iresult->declaring->klass) && !mono_class_is_ginst (iresult->declaring->klass)) iresult->context.class_inst = NULL; - MonoImageSet *set = mono_metadata_get_image_set_for_method (iresult); + MonoMemoryManager *mm = mono_metadata_get_mem_manager_for_method (iresult); // check cache - mono_image_set_lock (set); - cached = (MonoMethodInflated *)g_hash_table_lookup (set->gmethod_cache, iresult); - mono_image_set_unlock (set); + mono_mem_manager_lock (mm); + if (!mm->gmethod_cache) + mm->gmethod_cache = g_hash_table_new_full (inflated_method_hash, inflated_method_equal, NULL, (GDestroyNotify)free_inflated_method); + cached = (MonoMethodInflated *)g_hash_table_lookup (mm->gmethod_cache, iresult); + mono_mem_manager_unlock (mm); if (cached) { g_free (iresult); @@ -1276,14 +1309,14 @@ mono_class_inflate_generic_method_full_checked (MonoMethod *method, MonoClass *k */ // check cache - mono_image_set_lock (set); - cached = (MonoMethodInflated *)g_hash_table_lookup (set->gmethod_cache, iresult); + mono_mem_manager_lock (mm); + cached = (MonoMethodInflated *)g_hash_table_lookup (mm->gmethod_cache, iresult); if (!cached) { - g_hash_table_insert (set->gmethod_cache, iresult, iresult); - iresult->owner = set; + g_hash_table_insert (mm->gmethod_cache, iresult, iresult); + iresult->owner = mm; cached = iresult; } - mono_image_set_unlock (set); + mono_mem_manager_unlock (mm); return (MonoMethod*)cached; diff --git a/src/mono/mono/metadata/image.c b/src/mono/mono/metadata/image.c index b2171fe6ed8858..182f35cd96f8a4 100644 --- a/src/mono/mono/metadata/image.c +++ b/src/mono/mono/metadata/image.c @@ -2165,8 +2165,6 @@ mono_image_close_except_pools (MonoImage *image) mono_image_invoke_unload_hook (image); - mono_metadata_clean_for_image (image); - #ifdef ENABLE_METADATA_UPDATE mono_metadata_update_cleanup_on_close (image); #endif diff --git a/src/mono/mono/metadata/loader-internals.h b/src/mono/mono/metadata/loader-internals.h index 743e808eb729f3..ec6eb8f80cdf3b 100644 --- a/src/mono/mono/metadata/loader-internals.h +++ b/src/mono/mono/metadata/loader-internals.h @@ -16,6 +16,7 @@ #include #include #include +#include #if defined(TARGET_OSX) #define MONO_LOADER_LIBRARY_NAME "libcoreclr.dylib" @@ -30,8 +31,6 @@ G_BEGIN_DECLS typedef struct _MonoLoadedImages MonoLoadedImages; typedef struct _MonoAssemblyLoadContext MonoAssemblyLoadContext; typedef struct _MonoMemoryManager MonoMemoryManager; -typedef struct _MonoSingletonMemoryManager MonoSingletonMemoryManager; -typedef struct _MonoGenericMemoryManager MonoGenericMemoryManager; struct _MonoBundledSatelliteAssembly { const char *name; @@ -51,6 +50,44 @@ struct _MonoDllMap { }; #endif +typedef struct { + /* + * indexed by MonoMethodSignature + * Protected by the marshal lock + */ + GHashTable *delegate_invoke_cache; + GHashTable *delegate_begin_invoke_cache; + GHashTable *delegate_end_invoke_cache; + GHashTable *runtime_invoke_signature_cache; + GHashTable *runtime_invoke_sig_cache; + + /* + * indexed by SignaturePointerPair + */ + GHashTable *delegate_abstract_invoke_cache; + GHashTable *delegate_bound_static_invoke_cache; + + /* + * indexed by MonoMethod pointers + * Protected by the marshal lock + */ + GHashTable *runtime_invoke_method_cache; + GHashTable *managed_wrapper_cache; + + GHashTable *native_wrapper_cache; + GHashTable *native_wrapper_aot_cache; + GHashTable *native_wrapper_check_cache; + GHashTable *native_wrapper_aot_check_cache; + + GHashTable *native_func_wrapper_aot_cache; + GHashTable *native_func_wrapper_indirect_cache; /* Indexed by MonoMethodSignature. Protected by the marshal lock */ + GHashTable *synchronized_cache; + GHashTable *unbox_wrapper_cache; + GHashTable *cominterop_invoke_cache; + GHashTable *cominterop_wrapper_cache; /* LOCKING: marshal lock */ + GHashTable *thunk_invoke_cache; +} MonoWrapperCaches; + /* Lock-free allocator */ typedef struct { guint8 *mem; @@ -68,7 +105,7 @@ struct _MonoAssemblyLoadContext { // If taking this with the domain assemblies_lock, always take this second MonoCoopMutex assemblies_lock; // Holds ALC-specific memory - MonoSingletonMemoryManager *memory_manager; + MonoMemoryManager *memory_manager; GPtrArray *generic_memory_managers; // Protects generic_memory_managers; if taking this with the domain alcs_lock, always take this second MonoCoopMutex memory_managers_lock; @@ -117,7 +154,6 @@ struct _MonoMemoryManager { /* Information maintained by the execution engine */ gpointer runtime_info; - // !!! REGISTERED AS GC ROOTS !!! // Hashtables for Reflection handles MonoGHashTable *type_hash; MonoConcGHashTable *refobject_hash; @@ -125,22 +161,34 @@ struct _MonoMemoryManager { MonoGHashTable *type_init_exception_hash; // Maps delegate trampoline addr -> delegate object //MonoGHashTable *delegate_hash_table; - // End of GC roots -}; - -struct _MonoSingletonMemoryManager { - MonoMemoryManager memory_manager; - - // Parent ALC, NULL on framework - MonoAssemblyLoadContext *alc; -}; - -struct _MonoGenericMemoryManager { - MonoMemoryManager memory_manager; + /* + * Generic instances and aggregated custom modifiers depend on many alcs, and they need to be deleted if one + * of the alcs they depend on is unloaded. For example, + * List depends on both List's alc and Foo's alc. + * A MemoryManager is the owner of all generic instances depending on the same set of + * alcs. + */ // Parent ALCs int n_alcs; + // Allocated from the mempool MonoAssemblyLoadContext **alcs; + + // Generic-specific caches + GHashTable *ginst_cache, *gmethod_cache, *gsignature_cache; + MonoConcurrentHashTable *gclass_cache; + + /* mirror caches of ones already on MonoImage. These ones contain generics */ + GHashTable *szarray_cache, *array_cache, *ptr_cache; + + MonoWrapperCaches wrapper_caches; + + GHashTable *aggregate_modifiers_cache; + + /* Indexed by MonoGenericParam pointers */ + GHashTable **gshared_types; + /* The length of the above array */ + int gshared_types_len; }; void @@ -236,14 +284,14 @@ mono_alc_get_all_loaded_assemblies (void); MONO_API void mono_loader_save_bundled_library (int fd, uint64_t offset, uint64_t size, const char *destfname); -MonoSingletonMemoryManager * -mono_mem_manager_create_singleton (MonoAssemblyLoadContext *alc, gboolean collectible); +MonoMemoryManager * +mono_mem_manager_new (MonoAssemblyLoadContext **alcs, int nalcs, gboolean collectible); void -mono_mem_manager_free_singleton (MonoSingletonMemoryManager *memory_manager, gboolean debug_unload); +mono_mem_manager_free (MonoMemoryManager *memory_manager, gboolean debug_unload); void -mono_mem_manager_free_objects_singleton (MonoSingletonMemoryManager *memory_manager); +mono_mem_manager_free_objects (MonoMemoryManager *memory_manager); void mono_mem_manager_lock (MonoMemoryManager *memory_manager); @@ -285,6 +333,12 @@ mono_mem_manager_free_debug_info (MonoMemoryManager *memory_manager); gboolean mono_mem_manager_mp_contains_addr (MonoMemoryManager *memory_manager, gpointer addr); +MonoMemoryManager * +mono_mem_manager_get_generic (MonoImage **images, int nimages); + +MonoMemoryManager* +mono_mem_manager_merge (MonoMemoryManager *mm1, MonoMemoryManager *mm2); + G_END_DECLS #endif diff --git a/src/mono/mono/metadata/memory-manager.c b/src/mono/mono/metadata/memory-manager.c index 84fb080e295b39..77904a520d7e41 100644 --- a/src/mono/mono/metadata/memory-manager.c +++ b/src/mono/mono/metadata/memory-manager.c @@ -3,6 +3,7 @@ #include #include #include +#include static LockFreeMempool* lock_free_mempool_new (void) @@ -18,7 +19,7 @@ lock_free_mempool_free (LockFreeMempool *mp) chunk = mp->chunks; while (chunk) { next = (LockFreeMempoolChunk *)chunk->prev; - mono_vfree (chunk, mono_pagesize (), MONO_MEM_ACCOUNT_DOMAIN); + mono_vfree (chunk, mono_pagesize (), MONO_MEM_ACCOUNT_MEM_MANAGER); chunk = next; } g_free (mp); @@ -36,7 +37,7 @@ lock_free_mempool_chunk_new (LockFreeMempool *mp, int len) size = mono_pagesize (); while (size - sizeof (LockFreeMempoolChunk) < len) size += mono_pagesize (); - chunk = (LockFreeMempoolChunk *)mono_valloc (0, size, MONO_MMAP_READ|MONO_MMAP_WRITE, MONO_MEM_ACCOUNT_DOMAIN); + chunk = (LockFreeMempoolChunk *)mono_valloc (0, size, MONO_MMAP_READ|MONO_MMAP_WRITE, MONO_MEM_ACCOUNT_MEM_MANAGER); g_assert (chunk); chunk->mem = (guint8 *)ALIGN_PTR_TO ((char*)chunk + sizeof (LockFreeMempoolChunk), 16); chunk->size = ((char*)chunk + size) - (char*)chunk->mem; @@ -90,12 +91,15 @@ lock_free_mempool_alloc0 (LockFreeMempool *mp, guint size) return res; } -static void -memory_manager_init (MonoMemoryManager *memory_manager, gboolean collectible) +MonoMemoryManager* +mono_mem_manager_new (MonoAssemblyLoadContext **alcs, int nalcs, gboolean collectible) { MonoDomain *domain = mono_get_root_domain (); + MonoMemoryManager *memory_manager; - memory_manager->freeing = FALSE; + memory_manager = g_new0 (MonoMemoryManager, 1); + memory_manager->collectible = collectible; + memory_manager->n_alcs = nalcs; mono_coop_mutex_init_recursive (&memory_manager->lock); mono_os_mutex_init (&memory_manager->mp_mutex); @@ -104,6 +108,9 @@ memory_manager_init (MonoMemoryManager *memory_manager, gboolean collectible) memory_manager->code_mp = mono_code_manager_new (); memory_manager->lock_free_mp = lock_free_mempool_new (); + memory_manager->alcs = mono_mempool_alloc0 (memory_manager->_mp, sizeof (MonoAssemblyLoadContext *) * nalcs); + memcpy (memory_manager->alcs, alcs, sizeof (MonoAssemblyLoadContext *) * nalcs); + memory_manager->class_vtable_array = g_ptr_array_new (); // TODO: make these not linked to the domain for debugging @@ -113,18 +120,8 @@ memory_manager_init (MonoMemoryManager *memory_manager, gboolean collectible) if (mono_get_runtime_callbacks ()->init_mem_manager) mono_get_runtime_callbacks ()->init_mem_manager (memory_manager); -} - -MonoSingletonMemoryManager * -mono_mem_manager_create_singleton (MonoAssemblyLoadContext *alc, gboolean collectible) -{ - MonoSingletonMemoryManager *mem_manager = g_new0 (MonoSingletonMemoryManager, 1); - memory_manager_init ((MonoMemoryManager *)mem_manager, collectible); - mem_manager->memory_manager.is_generic = FALSE; - mem_manager->alc = alc; - - return mem_manager; + return memory_manager; } static void @@ -182,6 +179,8 @@ memory_manager_delete (MonoMemoryManager *memory_manager, gboolean debug_unload) mono_coop_mutex_destroy (&memory_manager->lock); + // FIXME: Free generics caches + if (debug_unload) { mono_mempool_invalidate (memory_manager->_mp); mono_code_manager_invalidate (memory_manager->code_mp); @@ -198,19 +197,19 @@ memory_manager_delete (MonoMemoryManager *memory_manager, gboolean debug_unload) } void -mono_mem_manager_free_objects_singleton (MonoSingletonMemoryManager *memory_manager) +mono_mem_manager_free_objects (MonoMemoryManager *memory_manager) { - g_assert (!memory_manager->memory_manager.freeing); + g_assert (!memory_manager->freeing); - memory_manager_delete_objects (&memory_manager->memory_manager); + memory_manager_delete_objects (memory_manager); } void -mono_mem_manager_free_singleton (MonoSingletonMemoryManager *memory_manager, gboolean debug_unload) +mono_mem_manager_free (MonoMemoryManager *memory_manager, gboolean debug_unload) { - g_assert (!memory_manager->memory_manager.is_generic); + g_assert (!memory_manager->is_generic); - memory_manager_delete (&memory_manager->memory_manager, debug_unload); + memory_manager_delete (memory_manager, debug_unload); g_free (memory_manager); } @@ -344,3 +343,207 @@ gpointer { return lock_free_mempool_alloc0 (memory_manager->lock_free_mp, size); } + +//107, 131, 163 +#define HASH_TABLE_SIZE 163 +static MonoMemoryManager *mem_manager_cache [HASH_TABLE_SIZE]; +static gint32 mem_manager_cache_hit, mem_manager_cache_miss; + +static guint32 +mix_hash (uintptr_t source) +{ + unsigned int hash = source; + + // Actual hash + hash = (((hash * 215497) >> 16) ^ ((hash * 1823231) + hash)); + + // Mix in highest bits on 64-bit systems only + if (sizeof (source) > 4) + hash = hash ^ ((source >> 31) >> 1); + + return hash; +} + +static guint32 +hash_alcs (MonoAssemblyLoadContext **alcs, int nalcs) +{ + guint32 res = 0; + int i; + for (i = 0; i < nalcs; ++i) + res += mix_hash ((size_t)alcs [i]); + + return res; +} + +static gboolean +match_mem_manager (MonoMemoryManager *mm, MonoAssemblyLoadContext **alcs, int nalcs) +{ + int j, k; + + if (mm->n_alcs != nalcs) + return FALSE; + /* The order might differ so check all pairs */ + for (j = 0; j < nalcs; ++j) { + for (k = 0; k < nalcs; ++k) + if (mm->alcs [k] == alcs [j]) + break; + if (k == nalcs) + /* Not found */ + break; + } + + return j == nalcs; +} + +static MonoMemoryManager* +mem_manager_cache_get (MonoAssemblyLoadContext **alcs, int nalcs) +{ + guint32 hash_code = hash_alcs (alcs, nalcs); + int index = hash_code % HASH_TABLE_SIZE; + MonoMemoryManager *mm = mem_manager_cache [index]; + if (!mm || !match_mem_manager (mm, alcs, nalcs)) { + UnlockedIncrement (&mem_manager_cache_miss); + return NULL; + } + UnlockedIncrement (&mem_manager_cache_hit); + return mm; +} + +static void +mem_manager_cache_add (MonoMemoryManager *mem_manager) +{ + guint32 hash_code = hash_alcs (mem_manager->alcs, mem_manager->n_alcs); + int index = hash_code % HASH_TABLE_SIZE; + mem_manager_cache [index] = mem_manager; +} + +static MonoMemoryManager* +get_mem_manager_for_alcs (MonoAssemblyLoadContext **alcs, int nalcs) +{ + MonoAssemblyLoadContext *alc; + GPtrArray *mem_managers; + MonoMemoryManager *res; + gboolean collectible; + + /* Can happen for dynamic images */ + if (nalcs == 0) + return mono_alc_get_default ()->memory_manager; + + /* Common case */ + if (nalcs == 1) + return alcs [0]->memory_manager; + + collectible = FALSE; + for (int i = 0; i < nalcs; ++i) + collectible |= alcs [i]->collectible; + if (!collectible) + /* Can use the default alc */ + return mono_alc_get_default ()->memory_manager; + + // Check in a lock free cache + res = mem_manager_cache_get (alcs, nalcs); + if (res) + return res; + + /* + * Find an existing mem manager for these ALCs. + * This can exist even if the cache lookup fails since the cache is very simple. + */ + + /* We can search any ALC in the list, use the first one for now */ + alc = alcs [0]; + + mono_alc_memory_managers_lock (alc); + + mem_managers = alc->generic_memory_managers; + + res = NULL; + for (int mindex = 0; mindex < mem_managers->len; ++mindex) { + MonoMemoryManager *mm = (MonoMemoryManager*)g_ptr_array_index (mem_managers, mindex); + + if (match_mem_manager (mm, alcs, nalcs)) { + res = mm; + break; + } + } + + mono_alc_memory_managers_unlock (alc); + + if (res) + return res; + + /* Create new mem manager */ + res = mono_mem_manager_new (alcs, nalcs, collectible); + res->is_generic = TRUE; + + /* The hashes are lazily inited in metadata.c */ + + /* Register it into its ALCs */ + for (int i = 0; i < nalcs; ++i) { + mono_alc_memory_managers_lock (alcs [i]); + g_ptr_array_add (alcs [i]->generic_memory_managers, res); + mono_alc_memory_managers_unlock (alcs [i]); + } + + mono_memory_barrier (); + + mem_manager_cache_add (res); + + return res; +} + +/* + * mono_mem_manager_get_generic: + * + * Return a memory manager for allocating memory owned by the set of IMAGES. + */ +MonoMemoryManager* +mono_mem_manager_get_generic (MonoImage **images, int nimages) +{ + MonoAssemblyLoadContext **alcs = g_newa (MonoAssemblyLoadContext*, nimages); + int nalcs, j; + + /* Collect the set of ALCs owning the images */ + nalcs = 0; + for (int i = 0; i < nimages; ++i) { + MonoAssemblyLoadContext *alc = mono_image_get_alc (images [i]); + + if (!alc) + continue; + + /* O(n^2), but shouldn't be a problem in practice */ + for (j = 0; j < nalcs; ++j) + if (alcs [j] == alc) + break; + if (j == nalcs) + alcs [nalcs ++] = alc; + } + + return get_mem_manager_for_alcs (alcs, nalcs); +} + +/* + * mono_mem_manager_merge: + * + * Return a mem manager which depends on the ALCs of MM1/MM2. + */ +MonoMemoryManager* +mono_mem_manager_merge (MonoMemoryManager *mm1, MonoMemoryManager *mm2) +{ + MonoAssemblyLoadContext **alcs = g_newa (MonoAssemblyLoadContext*, mm1->n_alcs + mm2->n_alcs); + + memcpy (alcs, mm1->alcs, sizeof (MonoAssemblyLoadContext*) * mm1->n_alcs); + + int nalcs = mm1->n_alcs; + /* O(n^2), but shouldn't be a problem in practice */ + for (int i = 0; i < mm2->n_alcs; ++i) { + int j; + for (j = 0; j < mm1->n_alcs; ++j) { + if (mm2->alcs [i] == mm1->alcs [j]) + break; + } + if (j == mm1->n_alcs) + alcs [nalcs ++] = mm2->alcs [i]; + } + return get_mem_manager_for_alcs (alcs, nalcs); +} diff --git a/src/mono/mono/metadata/metadata-internals.h b/src/mono/mono/metadata/metadata-internals.h index fed59f11db4782..919abc40b92fb8 100644 --- a/src/mono/mono/metadata/metadata-internals.h +++ b/src/mono/mono/metadata/metadata-internals.h @@ -231,44 +231,6 @@ struct _MonoAssembly { guint32 skipverification:2; /* Has SecurityPermissionFlag.SkipVerification permission */ }; -typedef struct { - /* - * indexed by MonoMethodSignature - * Protected by the marshal lock - */ - GHashTable *delegate_invoke_cache; - GHashTable *delegate_begin_invoke_cache; - GHashTable *delegate_end_invoke_cache; - GHashTable *runtime_invoke_signature_cache; - GHashTable *runtime_invoke_sig_cache; - - /* - * indexed by SignaturePointerPair - */ - GHashTable *delegate_abstract_invoke_cache; - GHashTable *delegate_bound_static_invoke_cache; - - /* - * indexed by MonoMethod pointers - * Protected by the marshal lock - */ - GHashTable *runtime_invoke_method_cache; - GHashTable *managed_wrapper_cache; - - GHashTable *native_wrapper_cache; - GHashTable *native_wrapper_aot_cache; - GHashTable *native_wrapper_check_cache; - GHashTable *native_wrapper_aot_check_cache; - - GHashTable *native_func_wrapper_aot_cache; - GHashTable *native_func_wrapper_indirect_cache; /* Indexed by MonoMethodSignature. Protected by the marshal lock */ - GHashTable *synchronized_cache; - GHashTable *unbox_wrapper_cache; - GHashTable *cominterop_invoke_cache; - GHashTable *cominterop_wrapper_cache; /* LOCKING: marshal lock */ - GHashTable *thunk_invoke_cache; -} MonoWrapperCaches; - typedef struct { const char* data; guint32 size; @@ -584,42 +546,6 @@ struct _MonoImage { mono_mutex_t lock; }; -/* - * Generic instances and aggregated custom modifiers depend on many images, and they need to be deleted if one - * of the images they depend on is unloaded. For example, - * List depends on both List's image and Foo's image. - * A MonoImageSet is the owner of all generic instances depending on the same set of - * images. - */ -typedef struct { - int nimages; - MonoImage **images; - - // Generic-specific caches - GHashTable *ginst_cache, *gmethod_cache, *gsignature_cache; - MonoConcurrentHashTable *gclass_cache; - - /* mirror caches of ones already on MonoImage. These ones contain generics */ - GHashTable *szarray_cache, *array_cache, *ptr_cache; - - MonoWrapperCaches wrapper_caches; - - GHashTable *aggregate_modifiers_cache; - - /* Indexed by MonoGenericParam pointers */ - GHashTable **gshared_types; - /* The length of the above array */ - int gshared_types_len; - - mono_mutex_t lock; - - /* - * Memory for generic instances owned by this image set should be allocated from - * this mempool, using the mono_image_set_alloc family of functions. - */ - MonoMemPool *mempool; -} MonoImageSet; - enum { MONO_SECTION_TEXT, MONO_SECTION_RSRC, @@ -912,32 +838,6 @@ void mono_image_load_enc_delta (MonoImage *base_image, gconstpointer dmeta, uint32_t dmeta_len, gconstpointer dil, uint32_t dil_len, MonoError *error); #endif /* ENABLE_METADATA_UPDATE */ -gpointer -mono_image_set_alloc (MonoImageSet *set, guint size); - -gpointer -mono_image_set_alloc0 (MonoImageSet *set, guint size); - -void -mono_image_set_lock (MonoImageSet *set); - -void -mono_image_set_unlock (MonoImageSet *set); - -char* -mono_image_set_strdup (MonoImageSet *set, const char *s); - -MonoImageSet * -mono_metadata_get_image_set_for_aggregate_modifiers (MonoAggregateModContainer *amods); - -MonoImageSet * -mono_metadata_get_image_set_for_type (MonoType *type); - -MonoImageSet * -mono_metadata_merge_image_sets (MonoImageSet *set1, MonoImageSet *set2); - -#define mono_image_set_new0(image,type,size) ((type *) mono_image_set_alloc0 (image, sizeof (type)* (size))) - gboolean mono_image_load_cli_header (MonoImage *image, MonoCLIImageInfo *iinfo); @@ -959,9 +859,6 @@ mono_metadata_decode_row_dynamic_checked (const MonoDynamicImage *image, const M MonoType* mono_metadata_get_shared_type (MonoType *type); -void -mono_metadata_clean_for_image (MonoImage *image); - void mono_metadata_clean_generic_classes_for_image (MonoImage *image); @@ -1193,12 +1090,6 @@ mono_metadata_parse_type_checked (MonoImage *m, MonoGenericContainer *container, MonoGenericContainer * mono_get_anonymous_container_for_image (MonoImage *image, gboolean is_mvar); -char * -mono_image_set_description (MonoImageSet *); - -MonoImageSet * -mono_find_image_set_owner (void *ptr); - void mono_loader_register_module (const char *name, MonoDl *module); diff --git a/src/mono/mono/metadata/metadata.c b/src/mono/mono/metadata/metadata.c index e5ec41db296f25..e18a6f4ec8b8cc 100644 --- a/src/mono/mono/metadata/metadata.c +++ b/src/mono/mono/metadata/metadata.c @@ -39,9 +39,6 @@ #include #include -static gint32 img_set_cache_hit, img_set_cache_miss, img_set_count; - - /* Auxiliary structure used for caching inflated signatures */ typedef struct { MonoMethodSignature *sig; @@ -1903,12 +1900,6 @@ builtin_types[] = { static GHashTable *type_cache = NULL; static gint32 next_generic_inst_id = 0; -/* Protected by image_sets_mutex */ -static MonoImageSet *mscorlib_image_set; -/* Protected by image_sets_mutex */ -static GPtrArray *image_sets; -static mono_mutex_t image_sets_mutex; - static guint mono_generic_class_hash (gconstpointer data); /* @@ -2038,12 +2029,6 @@ mono_metadata_init (void) for (i = 0; i < NBUILTIN_TYPES (); ++i) g_hash_table_insert (type_cache, (gpointer) &builtin_types [i], (gpointer) &builtin_types [i]); - mono_os_mutex_init_recursive (&image_sets_mutex); - - mono_counters_register ("ImgSet Cache Hit", MONO_COUNTER_METADATA | MONO_COUNTER_INT, &img_set_cache_hit); - mono_counters_register ("ImgSet Cache Miss", MONO_COUNTER_METADATA | MONO_COUNTER_INT, &img_set_cache_miss); - mono_counters_register ("ImgSet Count", MONO_COUNTER_METADATA | MONO_COUNTER_INT, &img_set_count); - #ifdef ENABLE_METADATA_UPDATE mono_metadata_update_init (); #endif @@ -2930,319 +2915,6 @@ aggregate_modifiers_in_image (MonoAggregateModContainer *amods, MonoImage *image return FALSE; } -static void -image_sets_lock (void) -{ - mono_os_mutex_lock (&image_sets_mutex); -} - -static void -image_sets_unlock (void) -{ - mono_os_mutex_unlock (&image_sets_mutex); -} - -//1103, 1327, 1597 -#define HASH_TABLE_SIZE 1103 -static MonoImageSet *img_set_cache [HASH_TABLE_SIZE]; - -static guint32 -mix_hash (uintptr_t source) -{ - unsigned int hash = source; - - // Actual hash - hash = (((hash * 215497) >> 16) ^ ((hash * 1823231) + hash)); - - // Mix in highest bits on 64-bit systems only - if (sizeof (source) > 4) - hash = hash ^ ((source >> 31) >> 1); - - return hash; -} - -static guint32 -hash_images (MonoImage **images, int nimages) -{ - guint32 res = 0; - int i; - for (i = 0; i < nimages; ++i) - res += mix_hash ((size_t)images [i]); - - return res; -} - -static gboolean -compare_img_set (MonoImageSet *set, MonoImage **images, int nimages) -{ - int j, k; - - if (set->nimages != nimages) - return FALSE; - - for (j = 0; j < nimages; ++j) { - for (k = 0; k < nimages; ++k) - if (set->images [k] == images [j]) - break; // Break on match - - // If we iterated all the way through set->images, images[j] was *not* found. - if (k == nimages) - break; // Break on "image not found" - } - - // If we iterated all the way through images without breaking, all items in images were found in set->images - return j == nimages; -} - - -static MonoImageSet* -img_set_cache_get (MonoImage **images, int nimages) -{ - guint32 hash_code = hash_images (images, nimages); - int index = hash_code % HASH_TABLE_SIZE; - MonoImageSet *img = img_set_cache [index]; - if (!img || !compare_img_set (img, images, nimages)) { - UnlockedIncrement (&img_set_cache_miss); - return NULL; - } - UnlockedIncrement (&img_set_cache_hit); - return img; -} - -static void -img_set_cache_add (MonoImageSet *set) -{ - guint32 hash_code = hash_images (set->images, set->nimages); - int index = hash_code % HASH_TABLE_SIZE; - img_set_cache [index] = set; -} - -static void -img_set_cache_remove (MonoImageSet *is) -{ - guint32 hash_code = hash_images (is->images, is->nimages); - int index = hash_code % HASH_TABLE_SIZE; - if (img_set_cache [index] == is) - img_set_cache [index] = NULL; -} -/* - * get_image_set: - * - * Return a MonoImageSet representing the set of images in IMAGES. - */ -static MonoImageSet* -get_image_set (MonoImage **images, int nimages) -{ - int i, j, k; - MonoImageSet *set; - GSList *l; - - /* Common case: Image set contains corlib only. If we've seen that case before, we cached the set. */ - if (nimages == 1 && images [0] == mono_defaults.corlib && mscorlib_image_set) - return mscorlib_image_set; - - /* Happens with empty generic instances */ - // FIXME: Is corlib the correct thing to return here? If so, why? This may be an artifact of generic instances previously defaulting to allocating from corlib. - if (nimages == 0) - return mscorlib_image_set; - - set = img_set_cache_get (images, nimages); - if (set) - return set; - - image_sets_lock (); - - if (!image_sets) - image_sets = g_ptr_array_new (); - - // Before we go on, we should check to see whether a MonoImageSet with these images already exists. - // We can search the referred-by imagesets of any one of our images to do this. Arbitrarily pick one here: - if (images [0] == mono_defaults.corlib && nimages > 1) - l = images [1]->image_sets; // Prefer not to search the imagesets of corlib-- that will be a long list. - else - l = images [0]->image_sets; - - set = NULL; - while (l) // Iterate over selected list, looking for an imageset with members equal to our target one - { - set = (MonoImageSet *)l->data; - - if (set->nimages == nimages) { // Member count differs, this can't be it - // Compare all members to all members-- order might be different - for (j = 0; j < nimages; ++j) { - for (k = 0; k < nimages; ++k) - if (set->images [k] == images [j]) - break; // Break on match - - // If we iterated all the way through set->images, images[j] was *not* found. - if (k == nimages) - break; // Break on "image not found" - } - - // If we iterated all the way through images without breaking, all items in images were found in set->images - if (j == nimages) { - // Break on "found a set with equal members". - // This happens in case of a hash collision with a previously cached set. - break; - } - } - - l = l->next; - } - - // If we iterated all the way through l without breaking, the imageset does not already exist and we should create it - if (!l) { - set = g_new0 (MonoImageSet, 1); - set->nimages = nimages; - set->images = g_new0 (MonoImage*, nimages); - mono_os_mutex_init_recursive (&set->lock); - for (i = 0; i < nimages; ++i) - set->images [i] = images [i]; - set->gclass_cache = mono_conc_hashtable_new_full (mono_generic_class_hash, mono_generic_class_equal, NULL, (GDestroyNotify)free_generic_class); - set->ginst_cache = g_hash_table_new_full (mono_metadata_generic_inst_hash, mono_metadata_generic_inst_equal, NULL, (GDestroyNotify)free_generic_inst); - set->gmethod_cache = g_hash_table_new_full (inflated_method_hash, inflated_method_equal, NULL, (GDestroyNotify)free_inflated_method); - set->gsignature_cache = g_hash_table_new_full (inflated_signature_hash, inflated_signature_equal, NULL, (GDestroyNotify)free_inflated_signature); - - set->szarray_cache = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, NULL); - set->array_cache = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, NULL); - - set->aggregate_modifiers_cache = g_hash_table_new_full (aggregate_modifiers_hash, aggregate_modifiers_equal, NULL, (GDestroyNotify)free_aggregate_modifiers); - - for (i = 0; i < nimages; ++i) - set->images [i]->image_sets = g_slist_prepend (set->images [i]->image_sets, set); - - g_ptr_array_add (image_sets, set); - UnlockedIncrement (&img_set_count); /* locked by image_sets_lock () */ - } - - /* Cache the set. If there was a cache collision, the previously cached value will be replaced. */ - img_set_cache_add (set); - - if (nimages == 1 && images [0] == mono_defaults.corlib) { - mono_memory_barrier (); - mscorlib_image_set = set; - } - - image_sets_unlock (); - - return set; -} - -static void -delete_image_set (MonoImageSet *set) -{ - int i; - - mono_conc_hashtable_destroy (set->gclass_cache); - g_hash_table_destroy (set->ginst_cache); - g_hash_table_destroy (set->gmethod_cache); - g_hash_table_destroy (set->gsignature_cache); - - g_hash_table_destroy (set->szarray_cache); - g_hash_table_destroy (set->array_cache); - if (set->ptr_cache) - g_hash_table_destroy (set->ptr_cache); - - g_hash_table_destroy (set->aggregate_modifiers_cache); - - for (i = 0; i < set->gshared_types_len; ++i) { - if (set->gshared_types [i]) - g_hash_table_destroy (set->gshared_types [i]); - } - g_free (set->gshared_types); - - mono_wrapper_caches_free (&set->wrapper_caches); - - image_sets_lock (); - - for (i = 0; i < set->nimages; ++i) - set->images [i]->image_sets = g_slist_remove (set->images [i]->image_sets, set); - - g_ptr_array_remove (image_sets, set); - - image_sets_unlock (); - - img_set_cache_remove (set); - - if (set->mempool) - mono_mempool_destroy (set->mempool); - g_free (set->images); - mono_os_mutex_destroy (&set->lock); - g_free (set); -} - -void -mono_image_set_lock (MonoImageSet *set) -{ - mono_os_mutex_lock (&set->lock); -} - -void -mono_image_set_unlock (MonoImageSet *set) -{ - mono_os_mutex_unlock (&set->lock); -} - -gpointer -mono_image_set_alloc (MonoImageSet *set, guint size) -{ - gpointer res; - - mono_image_set_lock (set); - if (!set->mempool) - set->mempool = mono_mempool_new_size (INITIAL_IMAGE_SET_SIZE); - res = mono_mempool_alloc (set->mempool, size); - mono_image_set_unlock (set); - - return res; -} - -gpointer -mono_image_set_alloc0 (MonoImageSet *set, guint size) -{ - gpointer res; - - mono_image_set_lock (set); - if (!set->mempool) - set->mempool = mono_mempool_new_size (INITIAL_IMAGE_SET_SIZE); - res = mono_mempool_alloc0 (set->mempool, size); - mono_image_set_unlock (set); - - return res; -} - -char* -mono_image_set_strdup (MonoImageSet *set, const char *s) -{ - char *res; - - mono_image_set_lock (set); - if (!set->mempool) - set->mempool = mono_mempool_new_size (INITIAL_IMAGE_SET_SIZE); - res = mono_mempool_strdup (set->mempool, s); - mono_image_set_unlock (set); - - return res; -} - -// Get a descriptive string for a MonoImageSet -// Callers are obligated to free buffer with g_free after use -char * -mono_image_set_description (MonoImageSet *set) -{ - GString *result = g_string_new (NULL); - int img; - g_string_append (result, "["); - for (img = 0; img < set->nimages; img++) - { - if (img > 0) - g_string_append (result, ", "); - g_string_append (result, set->images[img]->name); - } - g_string_append (result, "]"); - return g_string_free (result, FALSE); -} - /* * Structure used by the collect_..._images functions to store the image list. */ @@ -3500,86 +3172,6 @@ check_gmethod (gpointer key, gpointer value, gpointer data) g_assert (!signature_in_image (mono_method_signature_internal ((MonoMethod*)method), image)); } -/* - * check_image_sets: - * - * Run a consistency check on the image set data structures. - */ -static G_GNUC_UNUSED void -check_image_sets (MonoImage *image) -{ - int i; - GSList *l = image->image_sets; - - if (!image_sets) - return; - - for (i = 0; i < image_sets->len; ++i) { - MonoImageSet *set = (MonoImageSet *)g_ptr_array_index (image_sets, i); - - if (!g_slist_find (l, set)) { - g_hash_table_foreach (set->gmethod_cache, check_gmethod, image); - } - } -} - -void -mono_metadata_clean_for_image (MonoImage *image) -{ - CleanForImageUserData ginst_data, gclass_data, amods_data; - GSList *l, *set_list; - - //check_image_sets (image); - - /* - * The data structures could reference each other so we delete them in two phases. - * This is required because of the hashing functions in gclass/ginst_cache. - */ - ginst_data.image = gclass_data.image = image; - ginst_data.list = gclass_data.list = NULL; - amods_data.image = image; - amods_data.list = NULL; - - /* Collect the items to delete */ - /* delete_image_set () modifies the lists so make a copy */ - for (l = image->image_sets; l; l = l->next) { - MonoImageSet *set = (MonoImageSet *)l->data; - - mono_image_set_lock (set); - mono_conc_hashtable_foreach_steal (set->gclass_cache, steal_gclass_in_image, &gclass_data); - g_hash_table_foreach_steal (set->ginst_cache, steal_ginst_in_image, &ginst_data); - g_hash_table_foreach_remove (set->gmethod_cache, inflated_method_in_image, image); - g_hash_table_foreach_remove (set->gsignature_cache, inflated_signature_in_image, image); - - g_hash_table_foreach_steal (set->szarray_cache, class_in_image, image); - g_hash_table_foreach_steal (set->array_cache, class_in_image, image); - if (set->ptr_cache) - g_hash_table_foreach_steal (set->ptr_cache, class_in_image, image); - - g_hash_table_foreach_steal (set->aggregate_modifiers_cache, steal_aggregate_modifiers_in_image, &amods_data); - - mono_image_set_unlock (set); - } - - /* Delete the removed items */ - for (l = ginst_data.list; l; l = l->next) - free_generic_inst ((MonoGenericInst *)l->data); - for (l = gclass_data.list; l; l = l->next) - free_generic_class ((MonoGenericClass *)l->data); - for (l = amods_data.list; l; l = l->next) - free_aggregate_modifiers ((MonoAggregateModContainer *)l->data); - g_slist_free (ginst_data.list); - g_slist_free (gclass_data.list); - /* delete_image_set () modifies the lists so make a copy */ - set_list = g_slist_copy (image->image_sets); - for (l = set_list; l; l = l->next) { - MonoImageSet *set = (MonoImageSet *)l->data; - - delete_image_set (set); - } - g_slist_free (set_list); -} - static void free_inflated_method (MonoMethodInflated *imethod) { @@ -3616,7 +3208,6 @@ static void free_inflated_signature (MonoInflatedMethodSignature *sig) { mono_metadata_free_inflated_signature (sig->sig); - g_free (sig); } static void @@ -3639,104 +3230,79 @@ mono_metadata_get_inflated_signature (MonoMethodSignature *sig, MonoGenericConte MonoInflatedMethodSignature helper; MonoInflatedMethodSignature *res; CollectData data; - MonoImageSet *set; helper.sig = sig; helper.context.class_inst = context->class_inst; helper.context.method_inst = context->method_inst; collect_data_init (&data); - collect_inflated_signature_images (&helper, &data); - - set = get_image_set (data.images, data.nimages); - + MonoMemoryManager *mm = mono_mem_manager_get_generic (data.images, data.nimages); collect_data_free (&data); - mono_image_set_lock (set); + mono_mem_manager_lock (mm); - res = (MonoInflatedMethodSignature *)g_hash_table_lookup (set->gsignature_cache, &helper); + if (!mm->gsignature_cache) + mm->gsignature_cache = g_hash_table_new_full (inflated_signature_hash, inflated_signature_equal, NULL, (GDestroyNotify)free_inflated_signature); + res = (MonoInflatedMethodSignature *)g_hash_table_lookup (mm->gsignature_cache, &helper); if (!res) { - res = g_new0 (MonoInflatedMethodSignature, 1); + res = mono_mem_manager_alloc0 (mm, sizeof (MonoInflatedMethodSignature)); res->sig = sig; res->context.class_inst = context->class_inst; res->context.method_inst = context->method_inst; - g_hash_table_insert (set->gsignature_cache, res, res); + g_hash_table_insert (mm->gsignature_cache, res, res); } - mono_image_set_unlock (set); + mono_mem_manager_unlock (mm); return res->sig; } -MonoImageSet * -mono_metadata_get_image_set_for_type (MonoType *type) +MonoMemoryManager * +mono_metadata_get_mem_manager_for_type (MonoType *type) { - MonoImageSet *set; + MonoMemoryManager *mm; CollectData image_set_data; collect_data_init (&image_set_data); collect_type_images (type, &image_set_data); - set = get_image_set (image_set_data.images, image_set_data.nimages); + mm = mono_mem_manager_get_generic (image_set_data.images, image_set_data.nimages); collect_data_free (&image_set_data); - return set; + return mm; } -MonoImageSet * -mono_metadata_get_image_set_for_class (MonoClass *klass) +MonoMemoryManager * +mono_metadata_get_mem_manager_for_class (MonoClass *klass) { - return mono_metadata_get_image_set_for_type (m_class_get_byval_arg (klass)); + return mono_metadata_get_mem_manager_for_type (m_class_get_byval_arg (klass)); } -MonoImageSet * -mono_metadata_get_image_set_for_method (MonoMethodInflated *method) +MonoMemoryManager * +mono_metadata_get_mem_manager_for_method (MonoMethodInflated *method) { - MonoImageSet *set; + MonoMemoryManager *mm; CollectData image_set_data; collect_data_init (&image_set_data); collect_method_images (method, &image_set_data); - set = get_image_set (image_set_data.images, image_set_data.nimages); + mm = mono_mem_manager_get_generic (image_set_data.images, image_set_data.nimages); collect_data_free (&image_set_data); - return set; + return mm; } -MonoImageSet * -mono_metadata_get_image_set_for_aggregate_modifiers (MonoAggregateModContainer *amods) +static MonoMemoryManager * +mono_metadata_get_mem_manager_for_aggregate_modifiers (MonoAggregateModContainer *amods) { - MonoImageSet *set; + MonoMemoryManager *mm; CollectData image_set_data; collect_data_init (&image_set_data); collect_aggregate_modifiers_images (amods, &image_set_data); - set = get_image_set (image_set_data.images, image_set_data.nimages); + mm = mono_mem_manager_get_generic (image_set_data.images, image_set_data.nimages); collect_data_free (&image_set_data); - return set; -} - -MonoImageSet * -mono_metadata_merge_image_sets (MonoImageSet *set1, MonoImageSet *set2) -{ - MonoImage **images = g_newa (MonoImage*, set1->nimages + set2->nimages); - - /* Add images from set1 */ - memcpy (images, set1->images, sizeof (MonoImage*) * set1->nimages); - - int nimages = set1->nimages; - // FIXME: Quaratic - /* Add images from set2 */ - for (int i = 0; i < set2->nimages; ++i) { - int j; - for (j = 0; j < set1->nimages; ++j) { - if (set2->images [i] == set1->images [j]) - break; - } - if (j == set1->nimages) - images [nimages ++] = set2->images [i]; - } - return get_image_set (images, nimages); + return mm; } static gboolean @@ -3807,35 +3373,36 @@ mono_metadata_get_canonical_generic_inst (MonoGenericInst *candidate) CollectData data; int type_argc = candidate->type_argc; gboolean is_open = candidate->is_open; - MonoImageSet *set; collect_data_init (&data); - collect_ginst_images (candidate, &data); - - set = get_image_set (data.images, data.nimages); - + MonoMemoryManager *mm = mono_mem_manager_get_generic (data.images, data.nimages); collect_data_free (&data); - mono_image_set_lock (set); + mono_mem_manager_lock (mm); + + if (!mm->ginst_cache) + mm->ginst_cache = g_hash_table_new_full (mono_metadata_generic_inst_hash, mono_metadata_generic_inst_equal, NULL, (GDestroyNotify)free_generic_inst); - MonoGenericInst *ginst = (MonoGenericInst *)g_hash_table_lookup (set->ginst_cache, candidate); + MonoGenericInst *ginst = (MonoGenericInst *)g_hash_table_lookup (mm->ginst_cache, candidate); if (!ginst) { int size = MONO_SIZEOF_GENERIC_INST + type_argc * sizeof (MonoType *); - ginst = (MonoGenericInst *)mono_image_set_alloc0 (set, size); + ginst = (MonoGenericInst *)mono_mem_manager_alloc0 (mm, size); #ifndef MONO_SMALL_CONFIG ginst->id = mono_atomic_inc_i32 (&next_generic_inst_id); #endif ginst->is_open = is_open; ginst->type_argc = type_argc; + // FIXME: Dup into the mem manager for (int i = 0; i < type_argc; ++i) ginst->type_argv [i] = mono_metadata_type_dup (NULL, candidate->type_argv [i]); - g_hash_table_insert (set->ginst_cache, ginst, ginst); + g_hash_table_insert (mm->ginst_cache, ginst, ginst); } - mono_image_set_unlock (set); + mono_mem_manager_unlock (mm); + return ginst; } @@ -3843,23 +3410,26 @@ MonoAggregateModContainer * mono_metadata_get_canonical_aggregate_modifiers (MonoAggregateModContainer *candidate) { g_assert (candidate->count > 0); - MonoImageSet *set = mono_metadata_get_image_set_for_aggregate_modifiers (candidate); + MonoMemoryManager *mm = mono_metadata_get_mem_manager_for_aggregate_modifiers (candidate); - mono_image_set_lock (set); + mono_mem_manager_lock (mm); + + if (!mm->aggregate_modifiers_cache) + mm->aggregate_modifiers_cache = g_hash_table_new_full (aggregate_modifiers_hash, aggregate_modifiers_equal, NULL, (GDestroyNotify)free_aggregate_modifiers); - MonoAggregateModContainer *amods = (MonoAggregateModContainer *)g_hash_table_lookup (set->aggregate_modifiers_cache, candidate); + MonoAggregateModContainer *amods = (MonoAggregateModContainer *)g_hash_table_lookup (mm->aggregate_modifiers_cache, candidate); if (!amods) { size_t size = mono_sizeof_aggregate_modifiers (candidate->count); - amods = (MonoAggregateModContainer *)mono_image_set_alloc0 (set, size); + amods = (MonoAggregateModContainer *)mono_mem_manager_alloc0 (mm, size); amods->count = candidate->count; for (int i = 0; i < candidate->count; ++i) { amods->modifiers [i].required = candidate->modifiers [i].required; amods->modifiers [i].type = mono_metadata_type_dup (NULL, candidate->modifiers [i].type); } - g_hash_table_insert (set->aggregate_modifiers_cache, amods, amods); + g_hash_table_insert (mm->aggregate_modifiers_cache, amods, amods); } - mono_image_set_unlock (set); + mono_mem_manager_unlock (mm); return amods; } @@ -3885,7 +3455,6 @@ mono_metadata_lookup_generic_class (MonoClass *container_class, MonoGenericInst MonoGenericClass *gclass; MonoGenericClass helper; gboolean is_tb_open = mono_metadata_is_type_builder_generic_type_definition (container_class, inst, is_dynamic); - MonoImageSet *set; CollectData data; g_assert (mono_class_get_generic_container (container_class)->type_argc == inst->type_argc); @@ -3897,14 +3466,21 @@ mono_metadata_lookup_generic_class (MonoClass *container_class, MonoGenericInst helper.is_tb_open = is_tb_open; collect_data_init (&data); - collect_gclass_images (&helper, &data); - - set = get_image_set (data.images, data.nimages); - + MonoMemoryManager *mm = mono_mem_manager_get_generic (data.images, data.nimages); collect_data_free (&data); - gclass = (MonoGenericClass *)mono_conc_hashtable_lookup (set->gclass_cache, &helper); + if (!mm->gclass_cache) { + mono_mem_manager_lock (mm); + if (!mm->gclass_cache) { + MonoConcurrentHashTable *cache = mono_conc_hashtable_new_full (mono_generic_class_hash, mono_generic_class_equal, NULL, (GDestroyNotify)free_generic_class); + mono_memory_barrier (); + mm->gclass_cache = cache; + } + mono_mem_manager_unlock (mm); + } + + gclass = (MonoGenericClass *)mono_conc_hashtable_lookup (mm->gclass_cache, &helper); /* A tripwire just to keep us honest */ g_assert (!helper.cached_class); @@ -3912,7 +3488,9 @@ mono_metadata_lookup_generic_class (MonoClass *container_class, MonoGenericInst if (gclass) return gclass; - gclass = mono_image_set_new0 (set, MonoGenericClass, 1); + mono_mem_manager_lock (mm); + + gclass = mono_mem_manager_alloc0 (mm, sizeof (MonoGenericClass)); if (is_dynamic) gclass->is_dynamic = 1; @@ -3920,19 +3498,17 @@ mono_metadata_lookup_generic_class (MonoClass *container_class, MonoGenericInst gclass->container_class = container_class; gclass->context.class_inst = inst; gclass->context.method_inst = NULL; - gclass->owner = set; + gclass->owner = mm; if (inst == mono_class_get_generic_container (container_class)->context.class_inst && !is_tb_open) gclass->cached_class = container_class; - mono_image_set_lock (set); - - MonoGenericClass *gclass2 = (MonoGenericClass*)mono_conc_hashtable_insert (set->gclass_cache, gclass, gclass); + MonoGenericClass *gclass2 = (MonoGenericClass*)mono_conc_hashtable_insert (mm->gclass_cache, gclass, gclass); if (!gclass2) gclass2 = gclass; // g_hash_table_insert (set->gclass_cache, gclass, gclass); - mono_image_set_unlock (set); + mono_mem_manager_unlock (mm); return gclass2; } @@ -8006,35 +7582,6 @@ mono_method_get_wrapper_cache (MonoMethod *method) } } -// This is support for the mempool reference tracking feature in checked-build, but lives in metadata.c due to use of static variables of this file. - -/** - * mono_find_image_set_owner: - * - * Find the imageset, if any, which a given pointer is located in the memory of. - */ -MonoImageSet * -mono_find_image_set_owner (void *ptr) -{ - MonoImageSet *owner = NULL; - int i; - - image_sets_lock (); - - if (image_sets) - { - for (i = 0; !owner && i < image_sets->len; ++i) { - MonoImageSet *set = (MonoImageSet *)g_ptr_array_index (image_sets, i); - if (mono_mempool_contains_addr (set->mempool, ptr)) - owner = set; - } - } - - image_sets_unlock (); - - return owner; -} - void mono_loader_set_strict_assembly_name_check (gboolean enabled) { diff --git a/src/mono/mono/mini/method-to-ir.c b/src/mono/mono/mini/method-to-ir.c index 88148513cdd573..d8477389eb9935 100644 --- a/src/mono/mono/mini/method-to-ir.c +++ b/src/mono/mono/mini/method-to-ir.c @@ -1690,7 +1690,7 @@ MONO_RESTORE_WARNING ji.type = patch_type; ji.data.target = data; - target = mono_resolve_patch_target (NULL, NULL, &ji, FALSE, error); + target = mono_resolve_patch_target_ext (cfg->mem_manager, NULL, NULL, &ji, FALSE, error); mono_error_assert_ok (error); EMIT_NEW_PCONST (cfg, ins, target); @@ -3603,7 +3603,7 @@ handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, Mono jit_mm->method_code_hash = g_hash_table_new (NULL, NULL); code_slot = (guint8 **)g_hash_table_lookup (jit_mm->method_code_hash, method); if (!code_slot) { - code_slot = (guint8 **)m_method_alloc0 (method, sizeof (gpointer)); + code_slot = (guint8 **)mono_mem_manager_alloc0 (jit_mm->mem_manager, sizeof (gpointer)); g_hash_table_insert (jit_mm->method_code_hash, method, code_slot); } jit_mm_unlock (jit_mm); diff --git a/src/mono/mono/mini/mini-amd64.c b/src/mono/mono/mini/mini-amd64.c index 94c009d334ba03..7861797eeb91f7 100644 --- a/src/mono/mono/mini/mini-amd64.c +++ b/src/mono/mono/mini/mini-amd64.c @@ -8618,6 +8618,7 @@ mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoIMTCheckItem **imt_entri guint8 *code, *start; gboolean vtable_is_32bit = ((gsize)(vtable) == (gsize)(int)(gsize)(vtable)); GSList *unwind_ops; + MonoMemoryManager *mem_manager = m_class_get_mem_manager (vtable->klass); for (i = 0; i < count; ++i) { MonoIMTCheckItem *item = imt_entries [i]; @@ -8666,7 +8667,6 @@ mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoIMTCheckItem **imt_entri if (fail_tramp) { code = (guint8 *)mini_alloc_generic_virtual_trampoline (vtable, size + MONO_TRAMPOLINE_UNWINDINFO_SIZE(0)); } else { - MonoMemoryManager *mem_manager = m_class_get_mem_manager (vtable->klass); code = (guint8 *)mono_mem_manager_code_reserve (mem_manager, size + MONO_TRAMPOLINE_UNWINDINFO_SIZE(0)); } start = code; @@ -8763,7 +8763,7 @@ mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoIMTCheckItem **imt_entri MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_IMT_TRAMPOLINE, NULL)); - mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), NULL); + mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), mem_manager); return start; } diff --git a/src/mono/mono/mini/mini-arm.c b/src/mono/mono/mini/mini-arm.c index c58ab2707e9302..b08a5bcb649d28 100644 --- a/src/mono/mono/mini/mini-arm.c +++ b/src/mono/mono/mini/mini-arm.c @@ -6935,6 +6935,7 @@ mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoIMTCheckItem **imt_entri char * cond; #endif GSList *unwind_ops; + MonoMemoryManager *mem_manager = m_class_get_mem_manager (vtable->klass); size = BASE_SIZE; constant_pool_starts = g_new0 (guint32*, count); @@ -6976,7 +6977,6 @@ mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoIMTCheckItem **imt_entri if (fail_tramp) { code = (arminstr_t *)mini_alloc_generic_virtual_trampoline (vtable, size); } else { - MonoMemoryManager *mem_manager = m_class_get_mem_manager (vtable->klass); code = mono_mem_manager_code_reserve (mem_manager, size); } start = code; @@ -7154,7 +7154,7 @@ mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoIMTCheckItem **imt_entri g_assert (DISTANCE (start, code) <= size); - mono_tramp_info_register (mono_tramp_info_create (NULL, (guint8*)start, DISTANCE (start, code), NULL, unwind_ops), NULL); + mono_tramp_info_register (mono_tramp_info_create (NULL, (guint8*)start, DISTANCE (start, code), NULL, unwind_ops), mem_manager); return start; } diff --git a/src/mono/mono/mini/mini-generic-sharing.c b/src/mono/mono/mini/mini-generic-sharing.c index 6661dd6576d348..d1cc5e0eaacb77 100644 --- a/src/mono/mono/mini/mini-generic-sharing.c +++ b/src/mono/mono/mini/mini-generic-sharing.c @@ -3048,8 +3048,7 @@ mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot, { MonoRuntimeGenericContext *rgctx, *new_rgctx; gpointer info; - // FIXME: - MonoJitMemoryManager *jit_mm = get_default_jit_mm (); + MonoJitMemoryManager *jit_mm = jit_mm_for_class (class_vtable->klass); error_init (error); @@ -3964,14 +3963,14 @@ shared_gparam_equal (gconstpointer ka, gconstpointer kb) MonoType* mini_get_shared_gparam (MonoType *t, MonoType *constraint) { - MonoImageSet *set; + MonoMemoryManager *mm; MonoGenericParam *par = t->data.generic_param; MonoGSharedGenericParam *copy, key; MonoType *res; MonoImage *image = NULL; char *name; - set = mono_metadata_merge_image_sets (mono_metadata_get_image_set_for_type (t), mono_metadata_get_image_set_for_type (constraint)); + mm = mono_mem_manager_merge (mono_metadata_get_mem_manager_for_type (t), mono_metadata_get_mem_manager_for_type (constraint)); memset (&key, 0, sizeof (key)); key.parent = par; @@ -3984,24 +3983,24 @@ mini_get_shared_gparam (MonoType *t, MonoType *constraint) * Need a cache to ensure the newly created gparam * is unique wrt T/CONSTRAINT. */ - mono_image_set_lock (set); - if (!set->gshared_types) { - set->gshared_types_len = MONO_TYPE_INTERNAL; - set->gshared_types = g_new0 (GHashTable*, set->gshared_types_len); - } - if (!set->gshared_types [constraint->type]) - set->gshared_types [constraint->type] = g_hash_table_new (shared_gparam_hash, shared_gparam_equal); - res = (MonoType *)g_hash_table_lookup (set->gshared_types [constraint->type], &key); - mono_image_set_unlock (set); + mono_mem_manager_lock (mm); + if (!mm->gshared_types) { + mm->gshared_types_len = MONO_TYPE_INTERNAL; + mm->gshared_types = g_new0 (GHashTable*, mm->gshared_types_len); + } + if (!mm->gshared_types [constraint->type]) + mm->gshared_types [constraint->type] = g_hash_table_new (shared_gparam_hash, shared_gparam_equal); + res = (MonoType *)g_hash_table_lookup (mm->gshared_types [constraint->type], &key); + mono_mem_manager_unlock (mm); if (res) return res; - copy = (MonoGSharedGenericParam *)mono_image_set_alloc0 (set, sizeof (MonoGSharedGenericParam)); + copy = (MonoGSharedGenericParam *)mono_mem_manager_alloc0 (mm, sizeof (MonoGSharedGenericParam)); memcpy (©->param, par, sizeof (MonoGenericParamFull)); copy->param.info.pklass = NULL; // FIXME: constraint = mono_metadata_type_dup (NULL, constraint); name = get_shared_gparam_name (constraint->type, ((MonoGenericParamFull*)copy)->info.name); - copy->param.info.name = mono_image_set_strdup (set, name); + copy->param.info.name = mono_mem_manager_strdup (mm, name); g_free (name); copy->param.owner = par->owner; @@ -4012,10 +4011,10 @@ mini_get_shared_gparam (MonoType *t, MonoType *constraint) res = mono_metadata_type_dup (NULL, t); res->data.generic_param = (MonoGenericParam*)copy; - mono_image_set_lock (set); + mono_mem_manager_lock (mm); /* Duplicates are ok */ - g_hash_table_insert (set->gshared_types [constraint->type], copy, res); - mono_image_set_unlock (set); + g_hash_table_insert (mm->gshared_types [constraint->type], copy, res); + mono_mem_manager_unlock (mm); return res; } diff --git a/src/mono/mono/mini/mini-ppc.c b/src/mono/mono/mini/mini-ppc.c index 88f8e2fcd75502..19097c9df89d91 100644 --- a/src/mono/mono/mini/mini-ppc.c +++ b/src/mono/mono/mini/mini-ppc.c @@ -5474,6 +5474,7 @@ mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoIMTCheckItem **imt_entri int i; int size = 0; guint8 *code, *start; + MonoMemoryManager *mem_manager = m_class_get_mem_manager (vtable->klass); for (i = 0; i < count; ++i) { MonoIMTCheckItem *item = imt_entries [i]; @@ -5508,7 +5509,6 @@ mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoIMTCheckItem **imt_entri if (fail_tramp) { code = (guint8 *)mini_alloc_generic_virtual_trampoline (vtable, size); } else { - MonoMemoryManager *mem_manager = m_class_get_mem_manager (vtable->klass); code = mono_mem_manager_code_reserve (mem_manager, size); } start = code; @@ -5605,7 +5605,7 @@ mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoIMTCheckItem **imt_entri mono_arch_flush_icache (start, size); MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_IMT_TRAMPOLINE, NULL)); - mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), NULL); + mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), mem_manager); return start; } diff --git a/src/mono/mono/mini/mini-runtime.c b/src/mono/mono/mini/mini-runtime.c index bb25304af2dfa6..f1c43bcabaea95 100644 --- a/src/mono/mono/mini/mini-runtime.c +++ b/src/mono/mono/mini/mini-runtime.c @@ -472,11 +472,11 @@ mono_tramp_info_free (MonoTrampInfo *info) } static void -register_trampoline_jit_info (MonoDomain *domain, MonoTrampInfo *info) +register_trampoline_jit_info (MonoMemoryManager *mem_manager, MonoTrampInfo *info) { MonoJitInfo *ji; - ji = (MonoJitInfo *)mono_mem_manager_alloc0 (get_default_mem_manager (), mono_jit_info_size ((MonoJitInfoFlags)0, 0, 0)); + ji = (MonoJitInfo *)mono_mem_manager_alloc0 (mem_manager, mono_jit_info_size ((MonoJitInfoFlags)0, 0, 0)); mono_jit_info_init (ji, NULL, (guint8*)MINI_FTNPTR_TO_ADDR (info->code), info->code_size, (MonoJitInfoFlags)0, 0, 0); ji->d.tramp_info = info; ji->is_trampoline = TRUE; @@ -494,18 +494,15 @@ register_trampoline_jit_info (MonoDomain *domain, MonoTrampInfo *info) * Frees INFO. */ static void -mono_tramp_info_register_internal (MonoTrampInfo *info, MonoDomain *domain, gboolean aot) +mono_tramp_info_register_internal (MonoTrampInfo *info, MonoMemoryManager *mem_manager, gboolean aot) { MonoTrampInfo *copy; + MonoDomain *domain = mono_get_root_domain (); if (!info) return; - if (!domain) - domain = mono_get_root_domain (); - - // domain might be unset during startup - if (domain) { + if (mem_manager) { copy = mono_mem_manager_alloc0 (get_default_mem_manager (), sizeof (MonoTrampInfo)); } else { copy = g_new0 (MonoTrampInfo, 1); @@ -519,10 +516,9 @@ mono_tramp_info_register_internal (MonoTrampInfo *info, MonoDomain *domain, gboo if (info->unwind_ops) { copy->uw_info = mono_unwind_ops_encode (info->unwind_ops, ©->uw_info_len); copy->owns_uw_info = TRUE; - if (domain) { - /* Move unwind info into the domain's memory pool so that it is removed once the domain is released. */ + if (mem_manager) { guint8 *temp = copy->uw_info; - copy->uw_info = mono_mem_manager_alloc (get_default_mem_manager (), copy->uw_info_len); + copy->uw_info = mono_mem_manager_alloc (mem_manager, copy->uw_info_len); memcpy (copy->uw_info, temp, copy->uw_info_len); g_free (temp); } @@ -541,13 +537,13 @@ mono_tramp_info_register_internal (MonoTrampInfo *info, MonoDomain *domain, gboo #endif if (!domain) { - /* If no root domain has been created yet, postpone the registration. */ + /* If no domain has been created yet, postpone the registration. */ mono_jit_lock (); tramp_infos = g_slist_prepend (tramp_infos, copy); mono_jit_unlock (); } else if (copy->uw_info || info->method) { /* Only register trampolines that have unwind info */ - register_trampoline_jit_info (domain, copy); + register_trampoline_jit_info (mem_manager ? mem_manager : get_default_mem_manager (), copy); } if (mono_jit_map_is_enabled ()) @@ -557,15 +553,15 @@ mono_tramp_info_register_internal (MonoTrampInfo *info, MonoDomain *domain, gboo } void -mono_tramp_info_register (MonoTrampInfo *info, MonoDomain *domain) +mono_tramp_info_register (MonoTrampInfo *info, MonoMemoryManager *mem_manager) { - mono_tramp_info_register_internal (info, domain, FALSE); + mono_tramp_info_register_internal (info, mem_manager, FALSE); } void -mono_aot_tramp_info_register (MonoTrampInfo *info, MonoDomain *domain) +mono_aot_tramp_info_register (MonoTrampInfo *info, MonoMemoryManager *mem_manager) { - mono_tramp_info_register_internal (info, domain, TRUE); + mono_tramp_info_register_internal (info, mem_manager, TRUE); } /* Register trampolines created before the root domain was created in the jit info tables */ @@ -577,7 +573,7 @@ register_trampolines (MonoDomain *domain) for (l = tramp_infos; l; l = l->next) { MonoTrampInfo *info = (MonoTrampInfo *)l->data; - register_trampoline_jit_info (domain, info); + register_trampoline_jit_info (get_default_mem_manager (), info); } } @@ -1348,7 +1344,7 @@ mono_patch_info_equal (gconstpointer ka, gconstpointer kb) } gpointer -mono_resolve_patch_target (MonoMethod *method, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors, MonoError *error) +mono_resolve_patch_target_ext (MonoMemoryManager *mem_manager, MonoMethod *method, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors, MonoError *error) { unsigned char *ip = patch_info->ip.i + code; gconstpointer target = NULL; @@ -1424,7 +1420,7 @@ mono_resolve_patch_target (MonoMethod *method, guint8 *code, MonoJumpInfo *patch break; } case MONO_PATCH_INFO_METHOD_PINVOKE_ADDR_CACHE: { - target = mono_mem_manager_alloc0 (get_default_mem_manager (), sizeof (gpointer)); + target = mono_mem_manager_alloc0 (mem_manager, sizeof (gpointer)); break; } case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG: @@ -1642,7 +1638,7 @@ mono_resolve_patch_target (MonoMethod *method, guint8 *code, MonoJumpInfo *patch break; } case MONO_PATCH_INFO_CASTCLASS_CACHE: { - target = mono_mem_manager_alloc0 (get_default_mem_manager (), sizeof (gpointer)); + target = mono_mem_manager_alloc0 (mem_manager, sizeof (gpointer)); break; } case MONO_PATCH_INFO_OBJC_SELECTOR_REF: { @@ -1654,7 +1650,7 @@ mono_resolve_patch_target (MonoMethod *method, guint8 *code, MonoJumpInfo *patch char *s; len = strlen ((const char *)patch_info->data.target); - s = (char *)mono_mem_manager_alloc0 (get_default_mem_manager (), len + 1); + s = (char *)mono_mem_manager_alloc0 (mem_manager, len + 1); memcpy (s, patch_info->data.target, len); target = s; @@ -1685,6 +1681,12 @@ mono_resolve_patch_target (MonoMethod *method, guint8 *code, MonoJumpInfo *patch return (gpointer)target; } +gpointer +mono_resolve_patch_target (MonoMethod *method, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors, MonoError *error) +{ + return mono_resolve_patch_target_ext (get_default_mem_manager (), method, code, patch_info, run_cctors, error); +} + /* * mini_register_jump_site: * @@ -1823,7 +1825,11 @@ mini_lookup_method (MonoMethod *method, MonoMethod *shared) jit_code_hash_lock (jit_mm); ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&jit_mm->jit_code_hash, method); + jit_code_hash_unlock (jit_mm); if (!ji && shared) { + jit_mm = jit_mm_for_method (shared); + + jit_code_hash_lock (jit_mm); /* Try generic sharing */ ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&jit_mm->jit_code_hash, shared); if (ji && !ji->has_generic_jit_info) @@ -1837,8 +1843,8 @@ mini_lookup_method (MonoMethod *method, MonoMethod *shared) ++lookups; if (!ji) ++failed_lookups; + jit_code_hash_unlock (jit_mm); } - jit_code_hash_unlock (jit_mm); return ji; } diff --git a/src/mono/mono/mini/mini-runtime.h b/src/mono/mono/mini/mini-runtime.h index cfc7dd12f6706f..67d441495bcc84 100644 --- a/src/mono/mono/mini/mini-runtime.h +++ b/src/mono/mono/mini/mini-runtime.h @@ -78,12 +78,13 @@ get_default_mem_manager (void) static inline MonoJitMemoryManager* jit_mm_for_method (MonoMethod *method) { - /* - * Some places might not look up the correct memory manager because of generic instances/generic sharing etc. - * So use the same memory manager everywhere, this is not a problem since we don't support unloading yet. - */ - //return (MonoJitMemoryManager*)m_method_get_mem_manager (method)->runtime_info; - return get_default_jit_mm (); + return (MonoJitMemoryManager*)m_method_get_mem_manager (method)->runtime_info; +} + +static inline MonoJitMemoryManager* +jit_mm_for_class (MonoClass *klass) +{ + return (MonoJitMemoryManager*)m_class_get_mem_manager (klass)->runtime_info; } static inline void @@ -550,6 +551,7 @@ MonoJumpInfo *mono_patch_info_list_prepend (MonoJumpInfo *list, int ip, MonoJum MonoJumpInfoToken* mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token); MonoJumpInfoToken* mono_jump_info_token_new2 (MonoMemPool *mp, MonoImage *image, guint32 token, MonoGenericContext *context); gpointer mono_resolve_patch_target (MonoMethod *method, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors, MonoError *error); +gpointer mono_resolve_patch_target_ext (MonoMemoryManager *mem_manager, MonoMethod *method, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors, MonoError *error); void mini_register_jump_site (MonoMethod *method, gpointer ip); void mini_patch_jump_sites (MonoMethod *method, gpointer addr); void mini_patch_llvm_jit_callees (MonoMethod *method, gpointer addr); diff --git a/src/mono/mono/mini/mini-s390x.c b/src/mono/mono/mini/mini-s390x.c index 1cc8f83e2b72c5..e16cae80658af3 100644 --- a/src/mono/mono/mini/mini-s390x.c +++ b/src/mono/mono/mini/mini-s390x.c @@ -6484,6 +6484,7 @@ mono_arch_build_imt_trampoline (MonoVTable *vtable, int i; int size = 0; guchar *code, *start; + MonoMemoryManager *mem_manager = m_class_get_mem_manager (vtable->klass); for (i = 0; i < count; ++i) { MonoIMTCheckItem *item = imt_entries [i]; @@ -6519,7 +6520,6 @@ mono_arch_build_imt_trampoline (MonoVTable *vtable, if (fail_tramp) { code = (guint8 *)mini_alloc_generic_virtual_trampoline (vtable, size); } else { - MonoMemoryManager *mem_manager = m_class_get_mem_manager (vtable->klass); code = mono_mem_manager_code_reserve (mem_manager, size); } @@ -6606,7 +6606,7 @@ mono_arch_build_imt_trampoline (MonoVTable *vtable, g_assert (code - start <= size); - mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), NULL); + mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), mem_manager); return (start); } diff --git a/src/mono/mono/mini/mini-x86.c b/src/mono/mono/mini/mini-x86.c index d07ba7687ac6da..5cc9c3bfa6d3ce 100644 --- a/src/mono/mono/mini/mini-x86.c +++ b/src/mono/mono/mini/mini-x86.c @@ -5525,6 +5525,7 @@ mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoIMTCheckItem **imt_entri int size = 0; guint8 *code, *start; GSList *unwind_ops; + MonoMemoryManager *mem_manager = m_class_get_mem_manager (vtable->klass); for (i = 0; i < count; ++i) { MonoIMTCheckItem *item = imt_entries [i]; @@ -5552,7 +5553,6 @@ mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoIMTCheckItem **imt_entri if (fail_tramp) { code = (guint8 *)mini_alloc_generic_virtual_trampoline (vtable, size); } else { - MonoMemoryManager *mem_manager = m_class_get_mem_manager (vtable->klass); code = mono_mem_manager_code_reserve (mem_manager, size); } start = code; @@ -5644,7 +5644,7 @@ mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoIMTCheckItem **imt_entri MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_IMT_TRAMPOLINE, NULL)); - mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), NULL); + mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), mem_manager); return start; } diff --git a/src/mono/mono/mini/mini.h b/src/mono/mono/mini/mini.h index ac00a72237556a..6446d666efad90 100644 --- a/src/mono/mono/mini/mini.h +++ b/src/mono/mono/mini/mini.h @@ -2298,8 +2298,8 @@ void mono_emit_unwind_op (MonoCompile *cfg, int when, int val); MonoTrampInfo* mono_tramp_info_create (const char *name, guint8 *code, guint32 code_size, MonoJumpInfo *ji, GSList *unwind_ops); void mono_tramp_info_free (MonoTrampInfo *info); -void mono_aot_tramp_info_register (MonoTrampInfo *info, MonoDomain *domain); -void mono_tramp_info_register (MonoTrampInfo *info, MonoDomain *domain); +void mono_aot_tramp_info_register (MonoTrampInfo *info, MonoMemoryManager *mem_manager); +void mono_tramp_info_register (MonoTrampInfo *info, MonoMemoryManager *mem_manager); int mini_exception_id_by_name (const char *name); gboolean mini_type_is_hfa (MonoType *t, int *out_nfields, int *out_esize); diff --git a/src/mono/mono/mini/tramp-amd64.c b/src/mono/mono/mini/tramp-amd64.c index 805ae1694535bc..086796f51daa8a 100644 --- a/src/mono/mono/mini/tramp-amd64.c +++ b/src/mono/mono/mini/tramp-amd64.c @@ -78,7 +78,7 @@ mono_arch_get_unbox_trampoline (MonoMethod *m, gpointer addr) mono_arch_flush_icache (start, code - start); MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_UNBOX_TRAMPOLINE, m)); - mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), NULL); + mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), mem_manager); return start; } @@ -117,7 +117,7 @@ mono_arch_get_static_rgctx_trampoline (MonoMemoryManager *mem_manager, gpointer mono_arch_flush_icache (start, code - start); MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL)); - mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), NULL); + mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), mem_manager); return start; } diff --git a/src/mono/mono/mini/tramp-arm.c b/src/mono/mono/mini/tramp-arm.c index 1ad45caf2ffee3..3a9f87e02ae3ca 100644 --- a/src/mono/mono/mini/tramp-arm.c +++ b/src/mono/mono/mini/tramp-arm.c @@ -538,7 +538,7 @@ mono_arch_get_unbox_trampoline (MonoMethod *m, gpointer addr) /*g_print ("unbox trampoline at %d for %s:%s\n", this_pos, m->klass->name, m->name); g_print ("unbox code is at %p for method at %p\n", start, addr);*/ - mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), NULL); + mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), mem_manager); return start; } @@ -566,7 +566,7 @@ mono_arch_get_static_rgctx_trampoline (MonoMemoryManager *mem_manager, gpointer mono_arch_flush_icache (start, code - start); MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL)); - mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), NULL); + mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), mem_manager); return start; } @@ -595,7 +595,7 @@ mono_arch_get_ftnptr_arg_trampoline (MonoMemoryManager *mem_manager, gpointer ar mono_arch_flush_icache (start, code - start); MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL)); - mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), NULL); + mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), mem_manager); return start; } @@ -1189,7 +1189,7 @@ mono_arch_get_gsharedvt_arg_trampoline (gpointer arg, gpointer addr) mono_arch_flush_icache (buf, code - buf); MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL)); - mono_tramp_info_register (mono_tramp_info_create (NULL, buf, code - buf, NULL, NULL), NULL); + mono_tramp_info_register (mono_tramp_info_create (NULL, buf, code - buf, NULL, NULL), mem_manager); return buf; } diff --git a/src/mono/mono/mini/tramp-ppc.c b/src/mono/mono/mini/tramp-ppc.c index 850753e7b9600e..67eb7c24db3bab 100644 --- a/src/mono/mono/mini/tramp-ppc.c +++ b/src/mono/mono/mini/tramp-ppc.c @@ -107,7 +107,7 @@ mono_arch_get_unbox_trampoline (MonoMethod *m, gpointer addr) /*g_print ("unbox trampoline at %d for %s:%s\n", this_pos, m->klass->name, m->name); g_print ("unbox code is at %p for method at %p\n", start, addr);*/ - mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), NULL); + mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), mem_manager); return start; } @@ -152,7 +152,7 @@ mono_arch_get_static_rgctx_trampoline (MonoMemoryManager *mem_manager, gpointer MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL)); g_assert ((code - start) <= size); - mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), NULL); + mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), mem_manager); return start; } diff --git a/src/mono/mono/mini/tramp-s390x.c b/src/mono/mono/mini/tramp-s390x.c index d5d69093444de9..963416900435bb 100644 --- a/src/mono/mono/mini/tramp-s390x.c +++ b/src/mono/mono/mini/tramp-s390x.c @@ -117,7 +117,7 @@ mono_arch_get_unbox_trampoline (MonoMethod *m, gpointer addr) snprintf(trampName, sizeof(trampName), "%s_unbox_trampoline", m->name); - mono_tramp_info_register (mono_tramp_info_create (trampName, start, code - start, NULL, NULL), NULL); + mono_tramp_info_register (mono_tramp_info_create (trampName, start, code - start, NULL, NULL), mem_manager); return start; } @@ -747,7 +747,7 @@ mono_arch_get_static_rgctx_trampoline (MonoMemoryManager *mem_manager, gpointer mono_arch_flush_icache (start, code - start); MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL)); - mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), NULL); + mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), mem_manager); return(start); } diff --git a/src/mono/mono/mini/tramp-x86.c b/src/mono/mono/mini/tramp-x86.c index 395ae092f5af73..218e961dc16483 100644 --- a/src/mono/mono/mini/tramp-x86.c +++ b/src/mono/mono/mini/tramp-x86.c @@ -55,7 +55,7 @@ mono_arch_get_unbox_trampoline (MonoMethod *m, gpointer addr) MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_UNBOX_TRAMPOLINE, m)); - mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), NULL); + mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), mem_manager); return start; } @@ -79,7 +79,7 @@ mono_arch_get_static_rgctx_trampoline (MonoMemoryManager *mem_manager, gpointer mono_arch_flush_icache (start, code - start); MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL)); - mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), NULL); + mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), mem_manager); return start; } @@ -609,7 +609,7 @@ mono_arch_get_gsharedvt_arg_trampoline (gpointer arg, gpointer addr) mono_arch_flush_icache (start, code - start); MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL)); - mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), NULL); + mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), mem_manager); return start; } diff --git a/src/mono/mono/utils/mono-mmap.c b/src/mono/mono/utils/mono-mmap.c index 2484163e9cf196..e362b698dc454c 100644 --- a/src/mono/mono/utils/mono-mmap.c +++ b/src/mono/mono/utils/mono-mmap.c @@ -115,7 +115,7 @@ mono_mem_account_type_name (MonoMemAccountType type) static const char *names[] = { "code", "hazard pointers", - "domain", + "mem manager", "SGen internal", "SGen nursery", "SGen LOS", diff --git a/src/mono/mono/utils/mono-mmap.h b/src/mono/mono/utils/mono-mmap.h index 14e6a096567e5b..9d4849fc432dc0 100644 --- a/src/mono/mono/utils/mono-mmap.h +++ b/src/mono/mono/utils/mono-mmap.h @@ -28,7 +28,7 @@ enum { typedef enum { MONO_MEM_ACCOUNT_CODE, MONO_MEM_ACCOUNT_HAZARD_POINTERS, - MONO_MEM_ACCOUNT_DOMAIN, + MONO_MEM_ACCOUNT_MEM_MANAGER, MONO_MEM_ACCOUNT_SGEN_INTERNAL, MONO_MEM_ACCOUNT_SGEN_NURSERY, MONO_MEM_ACCOUNT_SGEN_LOS, diff --git a/src/tests/build.cmd b/src/tests/build.cmd index b4f9a7b0702a41..18a85d6ae62214 100644 --- a/src/tests/build.cmd +++ b/src/tests/build.cmd @@ -578,7 +578,7 @@ exit /b 1 set "__CrossgenOutputDir=%__TestIntermediatesDir%\crossgen.out" -set __CrossgenCmd="%__RepoRootDir%\dotnet.cmd" "%CORE_ROOT%\R2RTest\R2RTest.dll" compile-framework -cr "%CORE_ROOT%" --output-directory "%__CrossgenOutputDir%" --release --nocleanup --target-arch %__BuildArch% -dop %NUMBER_OF_PROCESSORS% +set __CrossgenCmd="%__RepoRootDir%\dotnet.cmd" "%CORE_ROOT%\R2RTest\R2RTest.dll" compile-framework -cr "%CORE_ROOT%" --output-directory "%__CrossgenOutputDir%" --release --nocleanup --target-arch %__BuildArch% -dop %NUMBER_OF_PROCESSORS% -m "%CORE_ROOT%\StandardOptimizationData.mibc" if defined __CreatePdb ( set __CrossgenCmd=!__CrossgenCmd! --pdb diff --git a/src/tests/build.sh b/src/tests/build.sh index 4531a07e3d77fc..0d15d53b53910e 100755 --- a/src/tests/build.sh +++ b/src/tests/build.sh @@ -158,7 +158,7 @@ precompile_coreroot_fx() fi local outputDir="$__TestIntermediatesDir/crossgen.out" - local crossgenCmd="\"$__DotNetCli\" \"$CORE_ROOT/R2RTest/R2RTest.dll\" compile-framework -cr \"$CORE_ROOT\" --output-directory \"$outputDir\" --release --nocleanup --target-arch $__BuildArch -dop $__NumProc" + local crossgenCmd="\"$__DotNetCli\" \"$CORE_ROOT/R2RTest/R2RTest.dll\" compile-framework -cr \"$CORE_ROOT\" --output-directory \"$outputDir\" --release --nocleanup --target-arch $__BuildArch -dop $__NumProc -m \"$CORE_ROOT/StandardOptimizationData.mibc\"" if [[ "$__CompositeBuildMode" != 0 ]]; then crossgenCmd="$crossgenCmd --composite"