diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index a75171aeda1b04..e72c4bf950c2c2 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -15,7 +15,7 @@ ] }, "microsoft.dotnet.xharness.cli": { - "version": "9.0.0-prerelease.24452.1", + "version": "10.0.0-prerelease.24459.1", "commands": [ "xharness" ] diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 77c06d86deee33..238887c6bd0983 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -316,17 +316,17 @@ https://github.com/dotnet/runtime 7cb32e193a55a95c74fc3bd56501b951b48b700f - + https://github.com/dotnet/xharness - c2215b88cdac5390888de3e6ad301c113f40ed6c + df9b6509e6b3976d158e46c23d72d6acd9f0d326 - + https://github.com/dotnet/xharness - c2215b88cdac5390888de3e6ad301c113f40ed6c + df9b6509e6b3976d158e46c23d72d6acd9f0d326 - + https://github.com/dotnet/xharness - c2215b88cdac5390888de3e6ad301c113f40ed6c + df9b6509e6b3976d158e46c23d72d6acd9f0d326 https://github.com/dotnet/arcade diff --git a/eng/Versions.props b/eng/Versions.props index a6407d4ed6c891..44522b33fd4a59 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -180,9 +180,9 @@ 1.4.0 17.4.0-preview-20220707-01 - 9.0.0-prerelease.24452.1 - 9.0.0-prerelease.24452.1 - 9.0.0-prerelease.24452.1 + 10.0.0-prerelease.24459.1 + 10.0.0-prerelease.24459.1 + 10.0.0-prerelease.24459.1 9.0.0-alpha.0.24419.1 3.12.0 4.5.0 diff --git a/eng/pipelines/common/templates/runtimes/build-runtime-tests-and-send-to-helix.yml b/eng/pipelines/common/templates/runtimes/build-runtime-tests-and-send-to-helix.yml index a189770cb81be4..2ac52ca77eb353 100644 --- a/eng/pipelines/common/templates/runtimes/build-runtime-tests-and-send-to-helix.yml +++ b/eng/pipelines/common/templates/runtimes/build-runtime-tests-and-send-to-helix.yml @@ -70,7 +70,7 @@ steps: displayName: "AOT compile CoreCLR tests" target: ${{ coalesce(parameters.llvmAotStepContainer, parameters.container) }} - ${{ if in(parameters.runtimeVariant, 'llvmfullaot', 'minifullaot') }}: - - script: $(Build.SourcesDirectory)/src/tests/build$(scriptExt) $(logRootNameArg)MonoAot mono_fullaot ${{ parameters.buildConfig }} ${{ parameters.archType }} /p:RuntimeVariant=${{ parameters.runtimeVariant }} -maxcpucount:2 + - script: $(Build.SourcesDirectory)/src/tests/build$(scriptExt) $(logRootNameArg)MonoAot mono_fullaot ${{ parameters.buildConfig }} ${{ parameters.archType }} /p:RuntimeVariant=${{ parameters.runtimeVariant }} -maxcpucount:1 displayName: "AOT compile CoreCLR tests" target: ${{ coalesce(parameters.llvmAotStepContainer, parameters.container) }} - ${{ if eq(parameters.archType, 'arm64') }}: diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs index ccd3d9aa9efc5e..95bcf0652648ab 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs @@ -115,8 +115,6 @@ public override string? CodeBase } } - internal RuntimeAssembly GetNativeHandle() => this; - // If the assembly is copied before it is loaded, the codebase will be set to the // actual file loaded if copiedName is true. If it is false, then the original code base // is returned. @@ -263,7 +261,7 @@ public override Type[] GetExportedTypes() public override IEnumerable DefinedTypes { [RequiresUnreferencedCode("Types might be removed")] - get => GetManifestModule(GetNativeHandle()).GetDefinedTypes(); + get => GetManifestModule().GetDefinedTypes(); } [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "AssemblyNative_GetIsCollectible")] @@ -324,7 +322,7 @@ public override void GetObjectData(SerializationInfo info, StreamingContext cont public override Module ManifestModule => // We don't need to return the "external" ModuleBuilder because // it is meant to be read-only - GetManifestModule(GetNativeHandle()); + GetManifestModule(); public override object[] GetCustomAttributes(bool inherit) { @@ -586,9 +584,17 @@ private CultureInfo GetLocale() } [MethodImpl(MethodImplOptions.InternalCall)] - private static extern bool FCallIsDynamic(RuntimeAssembly assembly); + private static extern bool GetIsDynamic(IntPtr assembly); - public override bool IsDynamic => FCallIsDynamic(GetNativeHandle()); + public override bool IsDynamic + { + get + { + bool isDynamic = GetIsDynamic(GetUnderlyingNativeHandle()); + GC.KeepAlive(this); // We directly pass the native handle above - make sure this object stays alive for the call + return isDynamic; + } + } [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "AssemblyNative_GetSimpleName")] private static partial void GetSimpleName(QCallAssembly assembly, StringHandleOnStack retSimpleName); @@ -701,8 +707,24 @@ public override Module[] GetLoadedModules(bool getResourceModules) return GetModulesInternal(false, getResourceModules); } + private RuntimeModule GetManifestModule() + { + return GetManifestModule(this) ?? GetManifestModuleWorker(this); + + [MethodImpl(MethodImplOptions.NoInlining)] + static RuntimeModule GetManifestModuleWorker(RuntimeAssembly assembly) + { + RuntimeModule? module = null; + GetManifestModuleSlow(ObjectHandleOnStack.Create(ref assembly), ObjectHandleOnStack.Create(ref module)); + return module!; + } + } + [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern RuntimeModule GetManifestModule(RuntimeAssembly assembly); + private static extern RuntimeModule? GetManifestModule(RuntimeAssembly assembly); + + [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "AssemblyHandle_GetManifestModuleSlow")] + private static partial void GetManifestModuleSlow(ObjectHandleOnStack assembly, ObjectHandleOnStack module); [MethodImpl(MethodImplOptions.InternalCall)] internal static extern int GetToken(RuntimeAssembly assembly); @@ -713,7 +735,7 @@ public sealed override Type[] GetForwardedTypes() List types = new List(); List exceptions = new List(); - MetadataImport scope = GetManifestModule(GetNativeHandle()).MetadataImport; + MetadataImport scope = GetManifestModule().MetadataImport; scope.Enum(MetadataTokenType.ExportedType, 0, out MetadataEnumResult enumResult); RuntimeAssembly runtimeAssembly = this; QCallAssembly pAssembly = new QCallAssembly(ref runtimeAssembly); diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs index a610a5cbe3eab8..2ac866f246fce9 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs @@ -82,7 +82,7 @@ internal static IList GetCustomAttributesInternal(RuntimeAs // No pseudo attributes for RuntimeAssembly - return GetCustomAttributes((RuntimeModule)target.ManifestModule, RuntimeAssembly.GetToken(target.GetNativeHandle())); + return GetCustomAttributes((RuntimeModule)target.ManifestModule, RuntimeAssembly.GetToken(target)); } internal static IList GetCustomAttributesInternal(RuntimeParameterInfo target) @@ -1227,7 +1227,7 @@ internal static bool IsDefined(RuntimeAssembly assembly, RuntimeType caType) Debug.Assert(caType is not null); // No pseudo attributes for RuntimeAssembly - return IsCustomAttributeDefined((assembly.ManifestModule as RuntimeModule)!, RuntimeAssembly.GetToken(assembly.GetNativeHandle()), caType); + return IsCustomAttributeDefined((assembly.ManifestModule as RuntimeModule)!, RuntimeAssembly.GetToken(assembly), caType); } internal static bool IsDefined(RuntimeModule module, RuntimeType caType) @@ -1388,7 +1388,7 @@ internal static object[] GetCustomAttributes(RuntimeAssembly assembly, RuntimeTy // No pseudo attributes for RuntimeAssembly - int assemblyToken = RuntimeAssembly.GetToken(assembly.GetNativeHandle()); + int assemblyToken = RuntimeAssembly.GetToken(assembly); return GetCustomAttributes((assembly.ManifestModule as RuntimeModule)!, assemblyToken, 0, caType); } diff --git a/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs b/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs index 3d230536519cea..d78cc1ea86bc19 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs @@ -306,11 +306,43 @@ internal RuntimeType GetRuntimeType() [MethodImpl(MethodImplOptions.InternalCall)] internal static extern CorElementType GetCorElementType(RuntimeType type); + internal static RuntimeAssembly GetAssembly(RuntimeType type) + { + return GetAssemblyIfExists(type) ?? GetAssemblyWorker(type); + + [MethodImpl(MethodImplOptions.NoInlining)] + static RuntimeAssembly GetAssemblyWorker(RuntimeType type) + { + RuntimeAssembly? assembly = null; + GetAssemblySlow(ObjectHandleOnStack.Create(ref type), ObjectHandleOnStack.Create(ref assembly)); + return assembly!; + } + } + [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern RuntimeAssembly GetAssembly(RuntimeType type); + private static extern RuntimeAssembly? GetAssemblyIfExists(RuntimeType type); + + [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_GetAssemblySlow")] + private static partial void GetAssemblySlow(ObjectHandleOnStack type, ObjectHandleOnStack assembly); + + internal static RuntimeModule GetModule(RuntimeType type) + { + return GetModuleIfExists(type) ?? GetModuleWorker(type); + + [MethodImpl(MethodImplOptions.NoInlining)] + static RuntimeModule GetModuleWorker(RuntimeType type) + { + RuntimeModule? module = null; + GetModuleSlow(ObjectHandleOnStack.Create(ref type), ObjectHandleOnStack.Create(ref module)); + return module!; + } + } [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern RuntimeModule GetModule(RuntimeType type); + private static extern RuntimeModule? GetModuleIfExists(RuntimeType type); + + [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_GetModuleSlow")] + private static partial void GetModuleSlow(ObjectHandleOnStack type, ObjectHandleOnStack module); public ModuleHandle GetModuleHandle() { diff --git a/src/coreclr/System.Private.CoreLib/src/System/Threading/LowLevelLifoSemaphore.Unix.cs b/src/coreclr/System.Private.CoreLib/src/System/Threading/LowLevelLifoSemaphore.Unix.cs index 8fe80e72868584..25fc6ff09ad2a1 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Threading/LowLevelLifoSemaphore.Unix.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Threading/LowLevelLifoSemaphore.Unix.cs @@ -31,7 +31,7 @@ public bool WaitCore(int timeoutMs) return waitResult == WaitHandle.WaitSuccess; } - [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "WaitHandle_CorWaitOnePrioritizedNative")] + [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "WaitHandle_WaitOnePrioritized")] private static partial int WaitNative(SafeWaitHandle handle, int timeoutMs); private void ReleaseCore(int count) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.cs index 486e5a505abeb7..08b3ae8944d630 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.cs @@ -151,13 +151,24 @@ public static void SpinWait(int iterations) public static bool Yield() => YieldInternal() != Interop.BOOL.FALSE; [MethodImpl(MethodImplOptions.NoInlining)] - private static Thread InitializeCurrentThread() => t_currentThread = GetCurrentThreadNative(); + private static Thread InitializeCurrentThread() + { + Thread? thread = null; + GetCurrentThread(ObjectHandleOnStack.Create(ref thread)); + return t_currentThread = thread!; + } - [MethodImpl(MethodImplOptions.InternalCall)] - private static extern Thread GetCurrentThreadNative(); + [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ThreadNative_GetCurrentThread")] + private static partial void GetCurrentThread(ObjectHandleOnStack thread); - [MethodImpl(MethodImplOptions.InternalCall)] - private extern void Initialize(); + private void Initialize() + { + Thread _this = this; + Initialize(ObjectHandleOnStack.Create(ref _this)); + } + + [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ThreadNative_Initialize")] + private static partial void Initialize(ObjectHandleOnStack thread); /// Clean up the thread when it goes away. ~Thread() => InternalFinalize(); // Delegate to the unmanaged portion. @@ -175,11 +186,7 @@ partial void ThreadNameChanged(string? value) private static partial void InformThreadNameChange(ThreadHandle t, string? name, int len); /// Returns true if the thread has been started and is not dead. - public extern bool IsAlive - { - [MethodImpl(MethodImplOptions.InternalCall)] - get; - } + public bool IsAlive => (ThreadState & (ThreadState.Unstarted | ThreadState.Stopped | ThreadState.Aborted)) == 0; /// /// Return whether or not this thread is a background thread. Background @@ -247,10 +254,19 @@ public ThreadPriority Priority /// Return the thread state as a consistent set of bits. This is more /// general then IsAlive or IsBackground. /// - public ThreadState ThreadState => (ThreadState)GetThreadStateNative(); + public ThreadState ThreadState + { + get + { + var state = (ThreadState)GetThreadState(GetNativeHandle()); + GC.KeepAlive(this); + return state; + } + } - [MethodImpl(MethodImplOptions.InternalCall)] - private extern int GetThreadStateNative(); + [SuppressGCTransition] + [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ThreadNative_GetThreadState")] + private static partial int GetThreadState(ThreadHandle t); /// /// An unstarted thread can be marked to indicate that it will host a @@ -327,6 +343,7 @@ public void DisableComObjectEagerCleanup() GC.KeepAlive(this); } + [SuppressGCTransition] [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ThreadNative_DisableComObjectEagerCleanup")] private static partial void DisableComObjectEagerCleanup(ThreadHandle t); #else // !FEATURE_COMINTEROP diff --git a/src/coreclr/System.Private.CoreLib/src/System/Threading/WaitHandle.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Threading/WaitHandle.CoreCLR.cs index f1bfe33e8c8bc2..a9fc4d8b2a0458 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Threading/WaitHandle.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Threading/WaitHandle.CoreCLR.cs @@ -8,23 +8,18 @@ namespace System.Threading { public abstract partial class WaitHandle { - [MethodImpl(MethodImplOptions.InternalCall)] - private static extern int WaitOneCore(IntPtr waitHandle, int millisecondsTimeout, bool useTrivialWaits); + [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "WaitHandle_WaitOneCore")] + private static partial int WaitOneCore(IntPtr waitHandle, int millisecondsTimeout, [MarshalAs(UnmanagedType.Bool)] bool useTrivialWaits); private static unsafe int WaitMultipleIgnoringSyncContextCore(ReadOnlySpan waitHandles, bool waitAll, int millisecondsTimeout) - { - fixed (IntPtr* pWaitHandles = &MemoryMarshal.GetReference(waitHandles)) - { - return WaitMultipleIgnoringSyncContext(pWaitHandles, waitHandles.Length, waitAll, millisecondsTimeout); - } - } + => WaitMultipleIgnoringSyncContext(waitHandles, waitHandles.Length, waitAll, millisecondsTimeout); - [MethodImpl(MethodImplOptions.InternalCall)] - private static extern unsafe int WaitMultipleIgnoringSyncContext(IntPtr* waitHandles, int numHandles, bool waitAll, int millisecondsTimeout); + [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "WaitHandle_WaitMultipleIgnoringSyncContext")] + private static partial int WaitMultipleIgnoringSyncContext(ReadOnlySpan waitHandles, int numHandles, [MarshalAs(UnmanagedType.Bool)] bool waitAll, int millisecondsTimeout); private static int SignalAndWaitCore(IntPtr waitHandleToSignal, IntPtr waitHandleToWaitOn, int millisecondsTimeout) { - int ret = SignalAndWaitNative(waitHandleToSignal, waitHandleToWaitOn, millisecondsTimeout); + int ret = SignalAndWait(waitHandleToSignal, waitHandleToWaitOn, millisecondsTimeout); if (ret == Interop.Errors.ERROR_TOO_MANY_POSTS) { @@ -34,7 +29,7 @@ private static int SignalAndWaitCore(IntPtr waitHandleToSignal, IntPtr waitHandl return ret; } - [MethodImpl(MethodImplOptions.InternalCall)] - private static extern int SignalAndWaitNative(IntPtr waitHandleToSignal, IntPtr waitHandleToWaitOn, int millisecondsTimeout); + [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "WaitHandle_SignalAndWait")] + private static partial int SignalAndWait(IntPtr waitHandleToSignal, IntPtr waitHandleToWaitOn, int millisecondsTimeout); } } diff --git a/src/coreclr/debug/daccess/dacdbiimpl.cpp b/src/coreclr/debug/daccess/dacdbiimpl.cpp index 6309533648bb20..223d675df254ae 100644 --- a/src/coreclr/debug/daccess/dacdbiimpl.cpp +++ b/src/coreclr/debug/daccess/dacdbiimpl.cpp @@ -5557,6 +5557,8 @@ CorDebugUserState DacDbiInterfaceImpl::GetPartialUserState(VMPTR_Thread vmThread result |= USER_STOPPED; } + // Don't report Thread::TS_AbortRequested + // The interruptible flag is unreliable (see issue 699245) // The Debugger_SleepWaitJoin is always accurate when it is present, but it is still // just a band-aid fix to cover some of the race conditions interruptible has. diff --git a/src/coreclr/debug/daccess/dacimpl.h b/src/coreclr/debug/daccess/dacimpl.h index 0d3ab3ad7bd18c..cec666bc02bc1b 100644 --- a/src/coreclr/debug/daccess/dacimpl.h +++ b/src/coreclr/debug/daccess/dacimpl.h @@ -1061,7 +1061,7 @@ class ClrDataAccess virtual HRESULT STDMETHODCALLTYPE GetAppDomainData(CLRDATA_ADDRESS addr, struct DacpAppDomainData *data); virtual HRESULT STDMETHODCALLTYPE GetAppDomainName(CLRDATA_ADDRESS addr, unsigned int count, _Inout_updates_z_(count) WCHAR *name, unsigned int *pNeeded); virtual HRESULT STDMETHODCALLTYPE GetAssemblyList(CLRDATA_ADDRESS appDomain, int count, CLRDATA_ADDRESS values[], int *fetched); - virtual HRESULT STDMETHODCALLTYPE GetAssemblyData(CLRDATA_ADDRESS baseDomainPtr, CLRDATA_ADDRESS assembly, struct DacpAssemblyData *data); + virtual HRESULT STDMETHODCALLTYPE GetAssemblyData(CLRDATA_ADDRESS domainPtr, CLRDATA_ADDRESS assembly, struct DacpAssemblyData *data); virtual HRESULT STDMETHODCALLTYPE GetAssemblyName(CLRDATA_ADDRESS assembly, unsigned int count, _Inout_updates_z_(count) WCHAR *name, unsigned int *pNeeded); virtual HRESULT STDMETHODCALLTYPE GetThreadData(CLRDATA_ADDRESS thread, struct DacpThreadData *data); virtual HRESULT STDMETHODCALLTYPE GetThreadFromThinlockID(UINT thinLockId, CLRDATA_ADDRESS *pThread); diff --git a/src/coreclr/debug/daccess/request.cpp b/src/coreclr/debug/daccess/request.cpp index 2be13b91e98aa9..5e73d02325112f 100644 --- a/src/coreclr/debug/daccess/request.cpp +++ b/src/coreclr/debug/daccess/request.cpp @@ -2834,19 +2834,17 @@ ClrDataAccess::GetAppDomainData(CLRDATA_ADDRESS addr, struct DacpAppDomainData * } else { - PTR_BaseDomain pBaseDomain = PTR_BaseDomain(TO_TADDR(addr)); - ZeroMemory(appdomainData, sizeof(DacpAppDomainData)); - appdomainData->AppDomainPtr = PTR_CDADDR(pBaseDomain); + appdomainData->AppDomainPtr = addr; PTR_LoaderAllocator pLoaderAllocator = SystemDomain::GetGlobalLoaderAllocator(); appdomainData->pHighFrequencyHeap = HOST_CDADDR(pLoaderAllocator->GetHighFrequencyHeap()); appdomainData->pLowFrequencyHeap = HOST_CDADDR(pLoaderAllocator->GetLowFrequencyHeap()); appdomainData->pStubHeap = HOST_CDADDR(pLoaderAllocator->GetStubHeap()); appdomainData->appDomainStage = STAGE_OPEN; - if (pBaseDomain->IsAppDomain()) + if (addr != HOST_CDADDR(SystemDomain::System())) { - AppDomain * pAppDomain = pBaseDomain->AsAppDomain(); + PTR_AppDomain pAppDomain = PTR_AppDomain(TO_TADDR(addr)); appdomainData->DomainLocalBlock = 0; appdomainData->pDomainLocalModules = 0; @@ -2963,15 +2961,19 @@ ClrDataAccess::GetAssemblyList(CLRDATA_ADDRESS addr, int count, CLRDATA_ADDRESS SOSDacEnter(); - BaseDomain* pBaseDomain = PTR_BaseDomain(TO_TADDR(addr)); - - int n=0; - if (pBaseDomain->IsAppDomain()) + if (addr == HOST_CDADDR(SystemDomain::System())) + { + // We shouldn't be asking for the assemblies in SystemDomain + hr = E_INVALIDARG; + } + else { - AppDomain::AssemblyIterator i = pBaseDomain->AsAppDomain()->IterateAssembliesEx( + PTR_AppDomain pAppDomain = PTR_AppDomain(TO_TADDR(addr)); + AppDomain::AssemblyIterator i = pAppDomain->IterateAssembliesEx( (AssemblyIterationFlags)(kIncludeLoading | kIncludeLoaded | kIncludeExecution)); CollectibleAssemblyHolder pDomainAssembly; + int n = 0; if (values) { while (i.Next(pDomainAssembly.This()) && (n < count)) @@ -2994,13 +2996,6 @@ ClrDataAccess::GetAssemblyList(CLRDATA_ADDRESS addr, int count, CLRDATA_ADDRESS if (pNeeded) *pNeeded = n; } - else - { - // The only other type of BaseDomain is the SystemDomain, and we shouldn't be asking - // for the assemblies in it. - _ASSERTE(false); - hr = E_INVALIDARG; - } SOSDacLeave(); return hr; @@ -3040,10 +3035,9 @@ ClrDataAccess::GetAppDomainName(CLRDATA_ADDRESS addr, unsigned int count, _Inout { SOSDacEnter(); - PTR_BaseDomain pBaseDomain = PTR_BaseDomain(TO_TADDR(addr)); - if (!pBaseDomain->IsAppDomain()) + if (addr == HOST_CDADDR(SystemDomain::System())) { - // Shared domain and SystemDomain don't have this field. + // SystemDomain doesn't have this field. if (pNeeded) *pNeeded = 1; if (name) @@ -3051,8 +3045,7 @@ ClrDataAccess::GetAppDomainName(CLRDATA_ADDRESS addr, unsigned int count, _Inout } else { - AppDomain* pAppDomain = pBaseDomain->AsAppDomain(); - + PTR_AppDomain pAppDomain = PTR_AppDomain(TO_TADDR(addr)); if (!pAppDomain->m_friendlyName.IsEmpty()) { if (!pAppDomain->m_friendlyName.DacGetUnicode(count, name, pNeeded)) @@ -3103,9 +3096,9 @@ ClrDataAccess::GetAppDomainConfigFile(CLRDATA_ADDRESS appDomain, int count, } HRESULT -ClrDataAccess::GetAssemblyData(CLRDATA_ADDRESS cdBaseDomainPtr, CLRDATA_ADDRESS assembly, struct DacpAssemblyData *assemblyData) +ClrDataAccess::GetAssemblyData(CLRDATA_ADDRESS domain, CLRDATA_ADDRESS assembly, struct DacpAssemblyData *assemblyData) { - if (assembly == (CLRDATA_ADDRESS)NULL && cdBaseDomainPtr == (CLRDATA_ADDRESS)NULL) + if (assembly == (CLRDATA_ADDRESS)NULL && domain == (CLRDATA_ADDRESS)NULL) { return E_INVALIDARG; } @@ -3117,14 +3110,9 @@ ClrDataAccess::GetAssemblyData(CLRDATA_ADDRESS cdBaseDomainPtr, CLRDATA_ADDRESS // Make sure conditionally-assigned fields like AssemblySecDesc, LoadContext, etc. are zeroed ZeroMemory(assemblyData, sizeof(DacpAssemblyData)); - // If the specified BaseDomain is an AppDomain, get a pointer to it - AppDomain * pDomain = NULL; - if (cdBaseDomainPtr != (CLRDATA_ADDRESS)NULL) + if (domain != (CLRDATA_ADDRESS)NULL) { - assemblyData->BaseDomainPtr = cdBaseDomainPtr; - PTR_BaseDomain baseDomain = PTR_BaseDomain(TO_TADDR(cdBaseDomainPtr)); - if( baseDomain->IsAppDomain() ) - pDomain = baseDomain->AsAppDomain(); + assemblyData->DomainPtr = domain; } assemblyData->AssemblyPtr = HOST_CDADDR(pAssembly); diff --git a/src/coreclr/debug/di/process.cpp b/src/coreclr/debug/di/process.cpp index aae787486adbc9..fffd6df484825f 100644 --- a/src/coreclr/debug/di/process.cpp +++ b/src/coreclr/debug/di/process.cpp @@ -11157,17 +11157,49 @@ void CordbProcess::HandleSetThreadContextNeeded(DWORD dwThreadId) LOG((LF_CORDB, LL_INFO10000, "RS HandleSetThreadContextNeeded\n")); #if defined(TARGET_WINDOWS) && defined(TARGET_AMD64) - HandleHolder hThread = OpenThread( - THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_QUERY_INFORMATION | THREAD_SUSPEND_RESUME, - FALSE, // thread handle is not inheritable. - dwThreadId); + // Before we can read the left side context information, we must: + // 1. obtain the thread handle + // 2. suspened the thread + // 3. read the thread context, and from that read the pointer to the left-side context and the size of the context + // 4. then we can perform the actual SetThreadContext operation + // 5. lastly, we must resume the thread + // For the first step of obtaining the thread handle, + // we have previously attempted to use ::OpenThread to get a handle to the thread. + // However, there are situations where OpenThread can fail with an Access Denied error. + // From https://github.com/dotnet/runtime/issues/107263, the control-c handler in + // Windows causes the process to have higher privileges. + // We are now using the following approach to access the thread handle, which is the same + // approach used by CordbThread::RefreshHandle: + // 1. Get the thread handle from the DAC + // 2. Duplicate the handle to the current process + + // lookup the CordbThread by thread ID, so that we can access the left-side thread handle + CordbThread * pThread = TryLookupOrCreateThreadByVolatileOSId(dwThreadId); + + IDacDbiInterface* pDAC = GetDAC(); + if (pDAC == NULL) + { + LOG((LF_CORDB, LL_INFO10000, "RS HandleSetThreadContextNeeded - DAC not initialized\n")); + ThrowHR(E_UNEXPECTED); + } - if (hThread == NULL) + HANDLE hOutOfProcThread = pDAC->GetThreadHandle(pThread->m_vmThreadToken); + if (hOutOfProcThread == NULL) { - LOG((LF_CORDB, LL_INFO10000, "RS HandleSetThreadContextNeeded - Unexpected result from OpenThread\n")); + LOG((LF_CORDB, LL_INFO10000, "RS HandleSetThreadContextNeeded - Failed to get thread handle\n")); ThrowHR(E_UNEXPECTED); } + // Duplicate the thread handle to the current process + HandleHolder hThread; + BOOL fSuccess = DuplicateHandle(UnsafeGetProcessHandle(), hOutOfProcThread, ::GetCurrentProcess(), &hThread, 0, FALSE, DUPLICATE_SAME_ACCESS); + if (!fSuccess) + { + LOG((LF_CORDB, LL_INFO10000, "RS HandleSetThreadContextNeeded - Unexpected result from DuplicateHandle\n")); + ThrowHR(HRESULT_FROM_GetLastError()); + } + + // Suspend the thread and so that we can read the thread context. DWORD previousSuspendCount = ::SuspendThread(hThread); if (previousSuspendCount == (DWORD)-1) { @@ -11178,12 +11210,22 @@ void CordbProcess::HandleSetThreadContextNeeded(DWORD dwThreadId) DT_CONTEXT context = { 0 }; context.ContextFlags = CONTEXT_FULL; - HRESULT hr = GetDataTarget()->GetThreadContext(dwThreadId, CONTEXT_FULL, sizeof(DT_CONTEXT), reinterpret_cast (&context)); - IfFailThrow(hr); + // we originally used GetDataTarget()->GetThreadContext, but + // the implementation uses ShimLocalDataTarget::GetThreadContext which + // depends on OpenThread which might fail with an Access Denied error (see note above) + BOOL success = ::GetThreadContext(hThread, (CONTEXT*)(&context)); + if (!success) + { + LOG((LF_CORDB, LL_INFO10000, "RS HandleSetThreadContextNeeded - Unexpected result from GetThreadContext\n")); + ThrowHR(HRESULT_FROM_GetLastError()); + } + // Read the pointer to the left-side context and the size of the context from the thread context. TADDR lsContextAddr = (TADDR)context.Rcx; DWORD contextSize = (DWORD)context.Rdx; + // Read the expected Rip and Rsp from the thread context. This is used to + // validate the context read from the left-side. TADDR expectedRip = (TADDR)context.R8; TADDR expectedRsp = (TADDR)context.R9; @@ -11198,7 +11240,7 @@ void CordbProcess::HandleSetThreadContextNeeded(DWORD dwThreadId) PCONTEXT pContext = (PCONTEXT)_alloca(contextSize); ULONG32 cbRead; - hr = GetDataTarget()->ReadVirtual(lsContextAddr, reinterpret_cast(pContext), contextSize, &cbRead); + HRESULT hr = GetDataTarget()->ReadVirtual(lsContextAddr, reinterpret_cast(pContext), contextSize, &cbRead); if (FAILED(hr)) { _ASSERTE(!"ReadVirtual failed"); @@ -11232,7 +11274,7 @@ void CordbProcess::HandleSetThreadContextNeeded(DWORD dwThreadId) // The initialize call should fail but return contextSize contextSize = 0; DWORD contextFlags = pContext->ContextFlags; - BOOL success = InitializeContext(NULL, contextFlags, NULL, &contextSize); + success = InitializeContext(NULL, contextFlags, NULL, &contextSize); if(success || GetLastError() != ERROR_INSUFFICIENT_BUFFER) { @@ -11276,6 +11318,7 @@ void CordbProcess::HandleSetThreadContextNeeded(DWORD dwThreadId) DWORD lastError = 0; + // Perform the actual SetThreadContext operation. success = ::SetThreadContext(hThread, pFrameContext); if (!success) { @@ -11285,6 +11328,7 @@ void CordbProcess::HandleSetThreadContextNeeded(DWORD dwThreadId) LOG((LF_CORDB, LL_INFO10000, "RS HandleSetThreadContextNeeded - Set Thread Context Completed: Success=%d GetLastError=%d hr=0x%X\n", success, lastError, HRESULT_FROM_WIN32(lastError))); _ASSERTE(success); + // Now that we have completed the SetThreadContext, resume the thread DWORD suspendCount = ::ResumeThread(hThread); if (suspendCount == (DWORD)-1) { diff --git a/src/coreclr/dlls/mscorrc/mscorrc.rc b/src/coreclr/dlls/mscorrc/mscorrc.rc index 927b287844df73..1d58a0681b584c 100644 --- a/src/coreclr/dlls/mscorrc/mscorrc.rc +++ b/src/coreclr/dlls/mscorrc/mscorrc.rc @@ -467,7 +467,6 @@ BEGIN IDS_EE_INVALID_CA "Invalid custom attribute provided." - IDS_EE_THREAD_CANNOT_GET "Unable to retrieve thread information." IDS_EE_THREAD_ABORT_WHILE_SUSPEND "Thread is suspended; attempting to abort." IDS_EE_NOVARIANTRETURN "PInvoke restriction: cannot return variants." diff --git a/src/coreclr/dlls/mscorrc/resource.h b/src/coreclr/dlls/mscorrc/resource.h index 09bf78dfb93c49..964cb7128325d9 100644 --- a/src/coreclr/dlls/mscorrc/resource.h +++ b/src/coreclr/dlls/mscorrc/resource.h @@ -232,7 +232,6 @@ #define IDS_EE_INVALID_CA 0x1a10 -#define IDS_EE_THREAD_CANNOT_GET 0x1a15 #define IDS_EE_THREAD_ABORT_WHILE_SUSPEND 0x1a1c #define IDS_EE_NOVARIANTRETURN 0x1a1d diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 566d1ecb769a4f..bf57e9ea28073c 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -930,7 +930,6 @@ struct PatchpointInfo; // Cookie types consumed by the code generator (these are opaque values // not inspected by the code generator): -typedef struct CORINFO_ASSEMBLY_STRUCT_* CORINFO_ASSEMBLY_HANDLE; typedef struct CORINFO_MODULE_STRUCT_* CORINFO_MODULE_HANDLE; typedef struct CORINFO_DEPENDENCY_STRUCT_* CORINFO_DEPENDENCY_HANDLE; typedef struct CORINFO_CLASS_STRUCT_* CORINFO_CLASS_HANDLE; @@ -2321,18 +2320,9 @@ class ICorStaticInfo CORINFO_CLASS_HANDLE cls ) = 0; - virtual CORINFO_MODULE_HANDLE getClassModule ( - CORINFO_CLASS_HANDLE cls - ) = 0; - - // Returns the assembly that contains the module "mod". - virtual CORINFO_ASSEMBLY_HANDLE getModuleAssembly ( - CORINFO_MODULE_HANDLE mod - ) = 0; - - // Returns the name of the assembly "assem". - virtual const char* getAssemblyName ( - CORINFO_ASSEMBLY_HANDLE assem + // Returns the assembly name of the class "cls", or nullptr if there is none. + virtual const char* getClassAssemblyName ( + CORINFO_CLASS_HANDLE cls ) = 0; // Allocate and delete process-lifetime objects. Should only be diff --git a/src/coreclr/inc/dacprivate.h b/src/coreclr/inc/dacprivate.h index 305029634406c9..62821f71395afc 100644 --- a/src/coreclr/inc/dacprivate.h +++ b/src/coreclr/inc/dacprivate.h @@ -425,11 +425,11 @@ enum DacpAppDomainDataStage { STAGE_CLOSED }; -// Information about a BaseDomain (AppDomain, SharedDomain or SystemDomain). +// Information about an AppDomain or SystemDomain. // For types other than AppDomain, some fields (like dwID, DomainLocalBlock, etc.) will be 0/null. struct MSLAYOUT DacpAppDomainData { - // The pointer to the BaseDomain (not necessarily an AppDomain). + // The pointer to the AppDomain or SystemDomain. // It's useful to keep this around in the structure CLRDATA_ADDRESS AppDomainPtr = 0; CLRDATA_ADDRESS AppSecDesc = 0; @@ -455,7 +455,7 @@ struct MSLAYOUT DacpAssemblyData CLRDATA_ADDRESS AssemblyPtr = 0; //useful to have CLRDATA_ADDRESS ClassLoader = 0; CLRDATA_ADDRESS ParentDomain = 0; - CLRDATA_ADDRESS BaseDomainPtr = 0; + CLRDATA_ADDRESS DomainPtr = 0; CLRDATA_ADDRESS AssemblySecDesc = 0; BOOL isDynamic = FALSE; UINT ModuleCount = FALSE; @@ -463,9 +463,9 @@ struct MSLAYOUT DacpAssemblyData BOOL isDomainNeutral = FALSE; // Always false, preserved for backward compatibility DWORD dwLocationFlags = 0; - HRESULT Request(ISOSDacInterface *sos, CLRDATA_ADDRESS addr, CLRDATA_ADDRESS baseDomainPtr) + HRESULT Request(ISOSDacInterface *sos, CLRDATA_ADDRESS addr, CLRDATA_ADDRESS domainPtr) { - return sos->GetAssemblyData(baseDomainPtr, addr, this); + return sos->GetAssemblyData(domainPtr, addr, this); } HRESULT Request(ISOSDacInterface *sos, CLRDATA_ADDRESS addr) diff --git a/src/coreclr/inc/eventtracebase.h b/src/coreclr/inc/eventtracebase.h index 316104f649a1d8..38868fe528f797 100644 --- a/src/coreclr/inc/eventtracebase.h +++ b/src/coreclr/inc/eventtracebase.h @@ -689,7 +689,6 @@ class Module; class Assembly; class MethodDesc; class MethodTable; -class BaseDomain; class AppDomain; class SString; class CrawlFrame; @@ -750,12 +749,11 @@ namespace ETW #ifdef FEATURE_EVENT_TRACE static VOID SendThreadRundownEvent(); static VOID SendGCRundownEvent(); - static VOID IterateDomain(BaseDomain *pDomain, DWORD enumerationOptions); - static VOID IterateAppDomain(AppDomain * pAppDomain, DWORD enumerationOptions); + static VOID IterateAppDomain(DWORD enumerationOptions); static VOID IterateCollectibleLoaderAllocator(AssemblyLoaderAllocator *pLoaderAllocator, DWORD enumerationOptions); static VOID IterateAssembly(Assembly *pAssembly, DWORD enumerationOptions); static VOID IterateModule(Module *pModule, DWORD enumerationOptions); - static VOID EnumerationHelper(Module *moduleFilter, BaseDomain *domainFilter, DWORD enumerationOptions); + static VOID EnumerationHelper(Module *moduleFilter, DWORD enumerationOptions); static DWORD GetEnumerationOptionsFromRuntimeKeywords(); public: typedef union _EnumerationStructs @@ -839,7 +837,7 @@ namespace ETW static VOID SendModuleEvent(Module *pModule, DWORD dwEventOptions, BOOL bFireDomainModuleEvents=FALSE); static ULONG SendModuleRange(_In_ Module *pModule, _In_ DWORD dwEventOptions); static VOID SendAssemblyEvent(Assembly *pAssembly, DWORD dwEventOptions); - static VOID SendDomainEvent(BaseDomain *pBaseDomain, DWORD dwEventOptions, LPCWSTR wszFriendlyName=NULL); + static VOID SendDomainEvent(DWORD dwEventOptions, LPCWSTR wszFriendlyName=NULL); public: typedef union _LoaderStructs { @@ -877,23 +875,23 @@ namespace ETW }LoaderStructs; - static VOID DomainLoadReal(BaseDomain *pDomain, _In_opt_ LPWSTR wszFriendlyName=NULL); + static VOID DomainLoadReal(_In_opt_ LPWSTR wszFriendlyName=NULL); - static VOID DomainLoad(BaseDomain *pDomain, _In_opt_ LPWSTR wszFriendlyName = NULL) + static VOID DomainLoad(_In_opt_ LPWSTR wszFriendlyName = NULL) { if (ETW_PROVIDER_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER)) { - DomainLoadReal(pDomain, wszFriendlyName); + DomainLoadReal(wszFriendlyName); } } - static VOID DomainUnload(AppDomain *pDomain); + static VOID DomainUnload(); static VOID CollectibleLoaderAllocatorUnload(AssemblyLoaderAllocator *pLoaderAllocator); static VOID ModuleLoad(Module *pModule, LONG liReportedSharedModule); #else public: - static VOID DomainLoad(BaseDomain *pDomain, _In_opt_ LPWSTR wszFriendlyName=NULL) {}; - static VOID DomainUnload(AppDomain *pDomain) {}; + static VOID DomainLoad(_In_opt_ LPWSTR wszFriendlyName=NULL) {}; + static VOID DomainUnload() {}; static VOID CollectibleLoaderAllocatorUnload(AssemblyLoaderAllocator *pLoaderAllocator) {}; static VOID ModuleLoad(Module *pModule, LONG liReportedSharedModule) {}; #endif // FEATURE_EVENT_TRACE @@ -904,7 +902,7 @@ namespace ETW { friend class ETW::EnumerationLog; #ifdef FEATURE_EVENT_TRACE - static VOID SendEventsForJitMethods(BaseDomain *pDomainFilter, LoaderAllocator *pLoaderAllocatorFilter, DWORD dwEventOptions); + static VOID SendEventsForJitMethods(BOOL getCodeVersionIds, LoaderAllocator *pLoaderAllocatorFilter, DWORD dwEventOptions); static VOID SendEventsForJitMethodsHelper( LoaderAllocator *pLoaderAllocatorFilter, DWORD dwEventOptions, diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h index bbaf43a6ee0ce0..ffc4659cb9fb8b 100644 --- a/src/coreclr/inc/icorjitinfoimpl_generated.h +++ b/src/coreclr/inc/icorjitinfoimpl_generated.h @@ -193,15 +193,9 @@ bool isValueClass( uint32_t getClassAttribs( CORINFO_CLASS_HANDLE cls) override; -CORINFO_MODULE_HANDLE getClassModule( +const char* getClassAssemblyName( CORINFO_CLASS_HANDLE cls) override; -CORINFO_ASSEMBLY_HANDLE getModuleAssembly( - CORINFO_MODULE_HANDLE mod) override; - -const char* getAssemblyName( - CORINFO_ASSEMBLY_HANDLE assem) override; - void* LongLifetimeMalloc( size_t sz) override; diff --git a/src/coreclr/inc/jiteeversionguid.h b/src/coreclr/inc/jiteeversionguid.h index 6aef89b2afd768..bce13e8aabcc30 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 = { /* 7f7fd340-4779-455a-8046-628f3cd8c3c7 */ - 0x7f7fd340, - 0x4779, - 0x455a, - {0x80, 0x46, 0x62, 0x8f, 0x3c, 0xd8, 0xc3, 0xc7} +constexpr GUID JITEEVersionIdentifier = { /* b75a5475-ff22-4078-9551-2024ce03d383 */ + 0xb75a5475, + 0xff22, + 0x4078, + {0x95, 0x51, 0x20, 0x24, 0xce, 0x03, 0xd3, 0x83} }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/coreclr/jit/ICorJitInfo_names_generated.h b/src/coreclr/jit/ICorJitInfo_names_generated.h index 2d3865018d1de4..15665a14b69ba3 100644 --- a/src/coreclr/jit/ICorJitInfo_names_generated.h +++ b/src/coreclr/jit/ICorJitInfo_names_generated.h @@ -45,9 +45,7 @@ DEF_CLR_API(getTypeInstantiationArgument) DEF_CLR_API(printClassName) DEF_CLR_API(isValueClass) DEF_CLR_API(getClassAttribs) -DEF_CLR_API(getClassModule) -DEF_CLR_API(getModuleAssembly) -DEF_CLR_API(getAssemblyName) +DEF_CLR_API(getClassAssemblyName) DEF_CLR_API(LongLifetimeMalloc) DEF_CLR_API(LongLifetimeFree) DEF_CLR_API(getIsClassInitedFlagAddress) diff --git a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp index ff3270192dc5f7..f45110fe0caba1 100644 --- a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp +++ b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp @@ -416,30 +416,12 @@ uint32_t WrapICorJitInfo::getClassAttribs( return temp; } -CORINFO_MODULE_HANDLE WrapICorJitInfo::getClassModule( +const char* WrapICorJitInfo::getClassAssemblyName( CORINFO_CLASS_HANDLE cls) { - API_ENTER(getClassModule); - CORINFO_MODULE_HANDLE temp = wrapHnd->getClassModule(cls); - API_LEAVE(getClassModule); - return temp; -} - -CORINFO_ASSEMBLY_HANDLE WrapICorJitInfo::getModuleAssembly( - CORINFO_MODULE_HANDLE mod) -{ - API_ENTER(getModuleAssembly); - CORINFO_ASSEMBLY_HANDLE temp = wrapHnd->getModuleAssembly(mod); - API_LEAVE(getModuleAssembly); - return temp; -} - -const char* WrapICorJitInfo::getAssemblyName( - CORINFO_ASSEMBLY_HANDLE assem) -{ - API_ENTER(getAssemblyName); - const char* temp = wrapHnd->getAssemblyName(assem); - API_LEAVE(getAssemblyName); + API_ENTER(getClassAssemblyName); + const char* temp = wrapHnd->getClassAssemblyName(cls); + API_LEAVE(getClassAssemblyName); return temp; } diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index 3f28580aba68a0..2b9425e6fe5025 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -2586,8 +2586,7 @@ void Compiler::compInitOptions(JitFlags* jitFlags) // We have an exclusion list. See if this method is in an assembly that is on the list. // Note that we check this for every method, since we might inline across modules, and // if the inlinee module is on the list, we don't want to use the altjit for it. - const char* methodAssemblyName = info.compCompHnd->getAssemblyName( - info.compCompHnd->getModuleAssembly(info.compCompHnd->getClassModule(info.compClassHnd))); + const char* methodAssemblyName = eeGetClassAssemblyName(info.compClassHnd); if (s_pAltJitExcludeAssembliesList->IsInList(methodAssemblyName)) { opts.altJit = false; @@ -2614,8 +2613,7 @@ void Compiler::compInitOptions(JitFlags* jitFlags) bool assemblyInIncludeList = true; // assume we'll dump, if there's not an include list (or it's empty). if (s_pJitDisasmIncludeAssembliesList != nullptr && !s_pJitDisasmIncludeAssembliesList->IsEmpty()) { - const char* assemblyName = info.compCompHnd->getAssemblyName( - info.compCompHnd->getModuleAssembly(info.compCompHnd->getClassModule(info.compClassHnd))); + const char* assemblyName = eeGetClassAssemblyName(info.compClassHnd); if (!s_pJitDisasmIncludeAssembliesList->IsInList(assemblyName)) { // We have a list, and the current assembly is not in it, so we won't dump. @@ -5238,11 +5236,12 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl m_pLowering->FinalizeOutgoingArgSpace(); // We can not add any new tracked variables after this point. - lvaTrackedFixed = true; + lvaTrackedFixed = true; + const unsigned numBlocksBeforeLSRA = fgBBcount; // Now that lowering is completed we can proceed to perform register allocation // - auto linearScanPhase = [this]() { + auto linearScanPhase = [this] { m_pLinearScan->doLinearScan(); }; DoPhase(this, PHASE_LINEAR_SCAN, linearScanPhase); @@ -5252,8 +5251,25 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl if (opts.OptimizationEnabled()) { - // LSRA and stack level setting can modify the flowgraph. - // Now that it won't change, run post-layout optimizations. + // LSRA may introduce new blocks. If it does, rerun layout. + if ((fgBBcount != numBlocksBeforeLSRA) && JitConfig.JitDoReversePostOrderLayout()) + { + auto lateLayoutPhase = [this] { + fgDoReversePostOrderLayout(); + fgMoveColdBlocks(); + return PhaseStatus::MODIFIED_EVERYTHING; + }; + + DoPhase(this, PHASE_OPTIMIZE_LAYOUT, lateLayoutPhase); + + if (fgFirstColdBlock != nullptr) + { + fgFirstColdBlock = nullptr; + DoPhase(this, PHASE_DETERMINE_FIRST_COLD_BLOCK, &Compiler::fgDetermineFirstColdBlock); + } + } + + // Now that the flowgraph is finalized, run post-layout optimizations. DoPhase(this, PHASE_OPTIMIZE_POST_LAYOUT, &Compiler::optOptimizePostLayout); } @@ -6335,39 +6351,29 @@ int Compiler::compCompile(CORINFO_MODULE_HANDLE classPtr, #ifdef DEBUG if (JitConfig.EnableExtraSuperPmiQueries()) { - // This call to getClassModule/getModuleAssembly/getAssemblyName fails in crossgen2 due to these - // APIs being unimplemented. So disable this extra info for pre-jit mode. See - // https://github.com/dotnet/runtime/issues/48888. - // - // Ditto for some of the class name queries for generic params. - // - if (!compileFlags->IsSet(JitFlags::JIT_FLAG_PREJIT)) - { - // Get the assembly name, to aid finding any particular SuperPMI method context function - (void)info.compCompHnd->getAssemblyName( - info.compCompHnd->getModuleAssembly(info.compCompHnd->getClassModule(info.compClassHnd))); + // Get the assembly name, to aid finding any particular SuperPMI method context function + (void)eeGetClassAssemblyName(info.compClassHnd); - // Fetch class names for the method's generic parameters. - // - CORINFO_SIG_INFO sig; - info.compCompHnd->getMethodSig(info.compMethodHnd, &sig, nullptr); + // Fetch class names for the method's generic parameters. + // + CORINFO_SIG_INFO sig; + info.compCompHnd->getMethodSig(info.compMethodHnd, &sig, nullptr); - const unsigned classInst = sig.sigInst.classInstCount; - if (classInst > 0) + const unsigned classInst = sig.sigInst.classInstCount; + if (classInst > 0) + { + for (unsigned i = 0; i < classInst; i++) { - for (unsigned i = 0; i < classInst; i++) - { - eeGetClassName(sig.sigInst.classInst[i]); - } + eeGetClassName(sig.sigInst.classInst[i]); } + } - const unsigned methodInst = sig.sigInst.methInstCount; - if (methodInst > 0) + const unsigned methodInst = sig.sigInst.methInstCount; + if (methodInst > 0) + { + for (unsigned i = 0; i < methodInst; i++) { - for (unsigned i = 0; i < methodInst; i++) - { - eeGetClassName(sig.sigInst.methInst[i]); - } + eeGetClassName(sig.sigInst.methInst[i]); } } } @@ -9221,8 +9227,7 @@ void JitTimer::PrintCsvMethodStats(Compiler* comp) } else { - const char* methodAssemblyName = comp->info.compCompHnd->getAssemblyName( - comp->info.compCompHnd->getModuleAssembly(comp->info.compCompHnd->getClassModule(comp->info.compClassHnd))); + const char* methodAssemblyName = comp->eeGetClassAssemblyName(comp->info.compClassHnd); fprintf(s_csvFile, "\"%s\",", methodAssemblyName); } fprintf(s_csvFile, "%u,", comp->info.compILCodeSize); diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 6fe0555691bd8f..a23a650a805f25 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -5316,6 +5316,8 @@ class Compiler unsigned xcptnIndex, bool putInTryRegion); + BasicBlock* fgNewBBatTryRegionEnd(BBKinds jumpKind, unsigned tryIndex); + void fgInsertBBbefore(BasicBlock* insertBeforeBlk, BasicBlock* newBlk); void fgInsertBBafter(BasicBlock* insertAfterBlk, BasicBlock* newBlk); void fgUnlinkBlock(BasicBlock* block); @@ -8335,6 +8337,8 @@ class Compiler void eePrintObjectDescription(const char* prefix, CORINFO_OBJECT_HANDLE handle); const char* eeGetShortClassName(CORINFO_CLASS_HANDLE clsHnd); + const char* eeGetClassAssemblyName(CORINFO_CLASS_HANDLE clsHnd); + #if defined(DEBUG) unsigned eeTryGetClassSize(CORINFO_CLASS_HANDLE clsHnd); #endif diff --git a/src/coreclr/jit/eeinterface.cpp b/src/coreclr/jit/eeinterface.cpp index fb07912ebf7d98..7ac73a22d27e05 100644 --- a/src/coreclr/jit/eeinterface.cpp +++ b/src/coreclr/jit/eeinterface.cpp @@ -596,6 +596,27 @@ const char* Compiler::eeGetShortClassName(CORINFO_CLASS_HANDLE clsHnd) return printer.GetBuffer(); } +//------------------------------------------------------------------------ +// eeGetClassAssemblyName: +// Get the assembly name of a type. +// If missing information (in SPMI), then return a placeholder string. +// +// Parameters: +// clsHnd - the handle of the class +// +// Return value: +// The name string. +// +const char* Compiler::eeGetClassAssemblyName(CORINFO_CLASS_HANDLE clsHnd) +{ + const char* assemblyName = ""; + eeRunFunctorWithSPMIErrorTrap([&]() { + assemblyName = info.compCompHnd->getClassAssemblyName(clsHnd); + }); + + return assemblyName != nullptr ? assemblyName : ""; +} + void Compiler::eePrintObjectDescription(const char* prefix, CORINFO_OBJECT_HANDLE handle) { const size_t maxStrSize = 64; diff --git a/src/coreclr/jit/emitarm.cpp b/src/coreclr/jit/emitarm.cpp index fd0a27f61818e1..902399f58e4fe7 100644 --- a/src/coreclr/jit/emitarm.cpp +++ b/src/coreclr/jit/emitarm.cpp @@ -3914,10 +3914,7 @@ void emitter::emitIns_S_R(instruction ins, emitAttr attr, regNumber reg1, int va { regNumber rsvdReg = codeGen->rsGetRsvdReg(); emitIns_genStackOffset(rsvdReg, varx, offs, /* isFloatUsage */ true, &baseRegUsed); - - // Ensure the baseReg calculated is correct. - assert(baseRegUsed == reg2); - emitIns_R_R(INS_add, EA_4BYTE, rsvdReg, reg2); + emitIns_R_R(INS_add, EA_4BYTE, rsvdReg, baseRegUsed); emitIns_R_R_I(ins, attr, reg1, rsvdReg, 0); return; } diff --git a/src/coreclr/jit/fgbasic.cpp b/src/coreclr/jit/fgbasic.cpp index f8e7ead56b3235..774e456f5e761a 100644 --- a/src/coreclr/jit/fgbasic.cpp +++ b/src/coreclr/jit/fgbasic.cpp @@ -6723,6 +6723,39 @@ BasicBlock* Compiler::fgNewBBinRegionWorker(BBKinds jumpKind, return newBlk; } +//----------------------------------------------------------------------------- +// fgNewBBatTryRegionEnd: Creates and inserts a new block at the end of the specified +// try region, updating the try end pointers in the EH table as necessary. +// +// Arguments: +// jumpKind - The jump kind of the new block +// tryIndex - The index of the try region to insert the new block in +// +// Returns: +// The new block +// +BasicBlock* Compiler::fgNewBBatTryRegionEnd(BBKinds jumpKind, unsigned tryIndex) +{ + BasicBlock* const oldTryLast = ehGetDsc(tryIndex)->ebdTryLast; + BasicBlock* const newBlock = fgNewBBafter(jumpKind, oldTryLast, /* extendRegion */ false); + newBlock->setTryIndex(tryIndex); + newBlock->clearHndIndex(); + + // Update this try region's (and all parent try regions') last block pointer + // + for (unsigned XTnum = tryIndex; XTnum < compHndBBtabCount; XTnum++) + { + EHblkDsc* const HBtab = ehGetDsc(XTnum); + if (HBtab->ebdTryLast == oldTryLast) + { + assert((XTnum == tryIndex) || (ehGetDsc(tryIndex)->ebdEnclosingTryIndex != EHblkDsc::NO_ENCLOSING_INDEX)); + fgSetTryEnd(HBtab, newBlock); + } + } + + return newBlock; +} + //------------------------------------------------------------------------ // fgUseThrowHelperBlocks: Determinate does compiler use throw helper blocks. // diff --git a/src/coreclr/jit/lowerarmarch.cpp b/src/coreclr/jit/lowerarmarch.cpp index a74bb3651c88f9..6b96564af8668b 100644 --- a/src/coreclr/jit/lowerarmarch.cpp +++ b/src/coreclr/jit/lowerarmarch.cpp @@ -4050,47 +4050,49 @@ GenTree* Lowering::LowerHWIntrinsicCndSel(GenTreeHWIntrinsic* cndSelNode) GenTree* nestedOp1 = nestedCndSel->Op(1); GenTree* nestedOp2 = nestedCndSel->Op(2); assert(varTypeIsMask(nestedOp1)); - assert(nestedOp2->OperIsHWIntrinsic()); - NamedIntrinsic nestedOp2Id = nestedOp2->AsHWIntrinsic()->GetHWIntrinsicId(); - - // If the nested op uses Pg/Z, then inactive lanes will result in zeros, so can only transform if - // op3 is all zeros. Such a Csel operation is absorbed into the instruction when emitted. Skip this optimisation - // when the nestedOp is a reduce operation. - - if (nestedOp1->IsMaskAllBitsSet() && !HWIntrinsicInfo::IsReduceOperation(nestedOp2Id) && - (!HWIntrinsicInfo::IsZeroingMaskedOperation(nestedOp2Id) || op3->IsVectorZero())) + if (nestedOp2->OperIsHWIntrinsic()) { - GenTree* nestedOp2 = nestedCndSel->Op(2); - GenTree* nestedOp3 = nestedCndSel->Op(3); + NamedIntrinsic nestedOp2Id = nestedOp2->AsHWIntrinsic()->GetHWIntrinsicId(); - JITDUMP("lowering nested ConditionalSelect HWIntrinisic (before):\n"); - DISPTREERANGE(BlockRange(), cndSelNode); - JITDUMP("\n"); + // If the nested op uses Pg/Z, then inactive lanes will result in zeros, so can only transform if + // op3 is all zeros. Such a Csel operation is absorbed into the instruction when emitted. Skip this + // optimisation when the nestedOp is a reduce operation. - // Transform: - // - // CndSel(mask, CndSel(AllTrue, embeddedMask(trueValOp2), trueValOp3), op3) to - // CndSel(mask, embedded(trueValOp2), op3) - // - cndSelNode->Op(2) = nestedCndSel->Op(2); - if (nestedOp3->IsMaskZero()) - { - BlockRange().Remove(nestedOp3); - } - else + if (nestedOp1->IsMaskAllBitsSet() && !HWIntrinsicInfo::IsReduceOperation(nestedOp2Id) && + (!HWIntrinsicInfo::IsZeroingMaskedOperation(nestedOp2Id) || op3->IsVectorZero())) { - nestedOp3->SetUnusedValue(); - } + GenTree* nestedOp2 = nestedCndSel->Op(2); + GenTree* nestedOp3 = nestedCndSel->Op(3); + + JITDUMP("lowering nested ConditionalSelect HWIntrinisic (before):\n"); + DISPTREERANGE(BlockRange(), cndSelNode); + JITDUMP("\n"); + + // Transform: + // + // CndSel(mask, CndSel(AllTrue, embeddedMask(trueValOp2), trueValOp3), op3) to + // CndSel(mask, embedded(trueValOp2), op3) + // + cndSelNode->Op(2) = nestedCndSel->Op(2); + if (nestedOp3->IsMaskZero()) + { + BlockRange().Remove(nestedOp3); + } + else + { + nestedOp3->SetUnusedValue(); + } - BlockRange().Remove(nestedOp1); - BlockRange().Remove(nestedCndSel); + BlockRange().Remove(nestedOp1); + BlockRange().Remove(nestedCndSel); - JITDUMP("lowering nested ConditionalSelect HWIntrinisic (after):\n"); - DISPTREERANGE(BlockRange(), cndSelNode); - JITDUMP("\n"); + JITDUMP("lowering nested ConditionalSelect HWIntrinisic (after):\n"); + DISPTREERANGE(BlockRange(), cndSelNode); + JITDUMP("\n"); - return cndSelNode; + return cndSelNode; + } } } else if (op1->IsMaskAllBitsSet()) diff --git a/src/coreclr/jit/lsra.cpp b/src/coreclr/jit/lsra.cpp index 763a28989b3a8e..3f603fa0c221bd 100644 --- a/src/coreclr/jit/lsra.cpp +++ b/src/coreclr/jit/lsra.cpp @@ -9789,10 +9789,26 @@ void LinearScan::resolveEdge(BasicBlock* fromBlock, if (location[targetReg] == REG_NA) { #ifdef TARGET_ARM - regNumber sourceReg = (regNumber)source[targetReg]; - Interval* interval = sourceIntervals[sourceReg]; + // For Arm, check two things: + // 1. If sourceReg relates to DOUBLE interval, then make sure + // the second half of targetReg is not participating in the resolution. + // 2. On the contrary, if targetReg is second half of a DOUBLE interval, + // then make sure the first half is not participating in the resolution. + // Only when both these conditions are met, can we safely assume + // that sourceReg can be moved to targetReg. + regNumber sourceReg = (regNumber)source[targetReg]; + Interval* interval = sourceIntervals[sourceReg]; + Interval* otherTargetInterval = nullptr; + regNumber otherHalfTargetReg = REG_NA; + if (genIsValidFloatReg(targetReg) && !genIsValidDoubleReg(targetReg)) + { + otherHalfTargetReg = REG_PREV(targetReg); + otherTargetInterval = sourceIntervals[otherHalfTargetReg]; + } + if (interval->registerType == TYP_DOUBLE) { + // Condition 1 above. // For ARM32, make sure that both of the float halves of the double register are available. assert(genIsValidDoubleReg(targetReg)); regNumber anotherHalfRegNum = REG_NEXT(targetReg); @@ -9801,11 +9817,22 @@ void LinearScan::resolveEdge(BasicBlock* fromBlock, targetRegsReady.AddRegNumInMask(targetReg); } } + else if ((otherTargetInterval != nullptr) && (otherTargetInterval->registerType == TYP_DOUBLE)) + { + // Condition 2 above. + assert(otherHalfTargetReg != REG_NA); + if (location[otherHalfTargetReg] == REG_NA) + { + targetRegsReady.AddRegNumInMask(targetReg); + } + } else -#endif // TARGET_ARM { targetRegsReady.AddRegNumInMask(targetReg); } +#else + targetRegsReady.AddRegNumInMask(targetReg); +#endif } } @@ -10019,6 +10046,13 @@ void LinearScan::resolveEdge(BasicBlock* fromBlock, { compiler->codeGen->regSet.rsSetRegsModified(genRegMask(tempReg) DEBUGARG(true)); #ifdef TARGET_ARM + Interval* otherTargetInterval = nullptr; + regNumber otherHalfTargetReg = REG_NA; + if (genIsValidFloatReg(targetReg) && !genIsValidDoubleReg(targetReg)) + { + otherHalfTargetReg = REG_PREV(targetReg); + otherTargetInterval = sourceIntervals[otherHalfTargetReg]; + } if (sourceIntervals[fromReg]->registerType == TYP_DOUBLE) { assert(genIsValidDoubleReg(targetReg)); @@ -10027,8 +10061,15 @@ void LinearScan::resolveEdge(BasicBlock* fromBlock, addResolutionForDouble(block, insertionPoint, sourceIntervals, location, tempReg, targetReg, resolveType DEBUG_ARG(fromBlock) DEBUG_ARG(toBlock)); } + else if (otherTargetInterval != nullptr) + { + assert(otherHalfTargetReg != REG_NA); + assert(otherTargetInterval->registerType == TYP_DOUBLE); + + addResolutionForDouble(block, insertionPoint, sourceIntervals, location, tempReg, + otherHalfTargetReg, resolveType DEBUG_ARG(fromBlock) DEBUG_ARG(toBlock)); + } else -#endif // TARGET_ARM { assert(sourceIntervals[targetReg] != nullptr); @@ -10037,6 +10078,14 @@ void LinearScan::resolveEdge(BasicBlock* fromBlock, DEBUG_ARG(resolveTypeName[resolveType])); location[targetReg] = (regNumberSmall)tempReg; } +#else + assert(sourceIntervals[targetReg] != nullptr); + + addResolution(block, insertionPoint, sourceIntervals[targetReg], tempReg, + targetReg DEBUG_ARG(fromBlock) DEBUG_ARG(toBlock) + DEBUG_ARG(resolveTypeName[resolveType])); + location[targetReg] = (regNumberSmall)tempReg; +#endif // TARGET_ARM targetRegsReady |= targetRegMask; } } diff --git a/src/coreclr/jit/optimizer.cpp b/src/coreclr/jit/optimizer.cpp index 27aedb6eb9af2f..f9880026eab268 100644 --- a/src/coreclr/jit/optimizer.cpp +++ b/src/coreclr/jit/optimizer.cpp @@ -2891,16 +2891,10 @@ bool Compiler::optCreatePreheader(FlowGraphNaturalLoop* loop) } } - BasicBlock* insertBefore = loop->GetLexicallyTopMostBlock(); - if (!BasicBlock::sameEHRegion(insertBefore, header)) - { - insertBefore = header; - } - - BasicBlock* preheader = fgNewBBbefore(BBJ_ALWAYS, insertBefore, false); + BasicBlock* preheader = fgNewBBbefore(BBJ_ALWAYS, header, false); preheader->SetFlags(BBF_INTERNAL); fgSetEHRegionForNewPreheaderOrExit(preheader); - preheader->bbCodeOffs = insertBefore->bbCodeOffs; + preheader->bbCodeOffs = header->bbCodeOffs; JITDUMP("Created new preheader " FMT_BB " for " FMT_LP "\n", preheader->bbNum, loop->GetIndex()); @@ -3003,21 +2997,11 @@ bool Compiler::optCanonicalizeExit(FlowGraphNaturalLoop* loop, BasicBlock* exit) { // Branches to a BBJ_CALLFINALLY _must_ come from inside its associated // try region, and when we have callfinally thunks the BBJ_CALLFINALLY - // is outside it. First try to see if the lexically bottom most block - // is part of the try; if so, inserting after that is a good choice. + // is outside it. Thus, insert newExit at the end of the finally's + // try region. BasicBlock* finallyBlock = exit->GetTarget(); assert(finallyBlock->hasHndIndex()); - BasicBlock* bottom = loop->GetLexicallyBottomMostBlock(); - if (bottom->hasTryIndex() && (bottom->getTryIndex() == finallyBlock->getHndIndex()) && !bottom->hasHndIndex()) - { - newExit = fgNewBBafter(BBJ_ALWAYS, bottom, true); - } - else - { - // Otherwise just do the heavy-handed thing and insert it anywhere in the right region. - newExit = fgNewBBinRegion(BBJ_ALWAYS, finallyBlock->bbHndIndex, 0, nullptr, /* putInFilter */ false, - /* runRarely */ false, /* insertAtEnd */ true); - } + newExit = fgNewBBatTryRegionEnd(BBJ_ALWAYS, finallyBlock->getHndIndex()); } else { diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs index 7db11a82041778..4b0967e372bbcb 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs @@ -120,6 +120,32 @@ public static unsafe Array NewMultiDimArray(RuntimeTypeHandle typeHandleForArray return Array.NewMultiDimArray(typeHandleForArrayType.ToMethodTable(), pImmutableLengths, lengths.Length); } + public static unsafe void SetArrayValue(Array array, int[] indices, object value) + { + MethodTable* elementMT = array.ElementMethodTable; + + if (elementMT->IsPointer || elementMT->IsFunctionPointer) + { + Debug.Assert(value.GetMethodTable()->ValueTypeSize == IntPtr.Size); + elementMT = value.GetMethodTable(); + } + + if (elementMT->IsValueType) + { + Debug.Assert(value.GetMethodTable()->IsValueType && elementMT->ValueTypeSize == value.GetMethodTable()->ValueTypeSize); + nint flattenedIndex = array.GetFlattenedIndex(indices); + ref byte element = ref Unsafe.AddByteOffset(ref MemoryMarshal.GetArrayDataReference(array), (nuint)flattenedIndex * array.ElementSize); + RuntimeImports.RhUnbox(value, ref element, elementMT); + } + else + { + RuntimeImports.RhCheckArrayStore(array, value); + nint flattenedIndex = array.GetFlattenedIndex(indices); + ref object element = ref Unsafe.Add(ref Unsafe.As(ref MemoryMarshal.GetArrayDataReference(array)), flattenedIndex); + element = value; + } + } + public static IntPtr GetAllocateObjectHelperForType(RuntimeTypeHandle type) { return RuntimeImports.RhGetRuntimeHelperForType(type.ToMethodTable(), RuntimeHelperKind.AllocateObject); diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Array.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Array.NativeAot.cs index 58378b92a9c5f0..faa4d51e935325 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Array.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Array.NativeAot.cs @@ -727,7 +727,7 @@ private unsafe nint GetFlattenedIndex(int rawIndex) return rawIndex; } - private unsafe nint GetFlattenedIndex(ReadOnlySpan indices) + internal unsafe nint GetFlattenedIndex(ReadOnlySpan indices) { // Checked by the caller Debug.Assert(indices.Length == Rank); diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeArrayTypeInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeArrayTypeInfo.cs index ab9fd61a3587ea..1f2f374b2436ec 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeArrayTypeInfo.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeArrayTypeInfo.cs @@ -213,7 +213,7 @@ internal sealed override IEnumerable SyntheticMethods for (int i = 0; i < rank; i++) indices[i] = (int)(args[i]); object value = args[rank]; - array.SetValue(value, indices); + RuntimeAugments.SetArrayValue(array, indices, value); return null; } ); diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 987bbc6508f132..d766ded60142ed 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -2092,12 +2092,17 @@ private uint getClassAttribsInternal(TypeDesc type) return (uint)result; } - private CORINFO_MODULE_STRUCT_* getClassModule(CORINFO_CLASS_STRUCT_* cls) - { throw new NotImplementedException("getClassModule"); } - private CORINFO_ASSEMBLY_STRUCT_* getModuleAssembly(CORINFO_MODULE_STRUCT_* mod) - { throw new NotImplementedException("getModuleAssembly"); } - private byte* getAssemblyName(CORINFO_ASSEMBLY_STRUCT_* assem) - { throw new NotImplementedException("getAssemblyName"); } + private byte* getClassAssemblyName(CORINFO_CLASS_STRUCT_* cls) + { + TypeDesc type = HandleToObject(cls); + + if (type is MetadataType mdType) + { + return (byte*)GetPin(StringToUTF8(mdType.Module.Assembly.GetName().Name)); + } + + return null; + } #pragma warning disable CA1822 // Mark members as static private void* LongLifetimeMalloc(UIntPtr sz) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs index 9213d42aba3272..26291e015b4285 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs @@ -614,42 +614,12 @@ private static uint _getClassAttribs(IntPtr thisHandle, IntPtr* ppException, COR } [UnmanagedCallersOnly] - private static CORINFO_MODULE_STRUCT_* _getClassModule(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) + private static byte* _getClassAssemblyName(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) { var _this = GetThis(thisHandle); try { - return _this.getClassModule(cls); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default; - } - } - - [UnmanagedCallersOnly] - private static CORINFO_ASSEMBLY_STRUCT_* _getModuleAssembly(IntPtr thisHandle, IntPtr* ppException, CORINFO_MODULE_STRUCT_* mod) - { - var _this = GetThis(thisHandle); - try - { - return _this.getModuleAssembly(mod); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default; - } - } - - [UnmanagedCallersOnly] - private static byte* _getAssemblyName(IntPtr thisHandle, IntPtr* ppException, CORINFO_ASSEMBLY_STRUCT_* assem) - { - var _this = GetThis(thisHandle); - try - { - return _this.getAssemblyName(assem); + return _this.getClassAssemblyName(cls); } catch (Exception ex) { @@ -2623,7 +2593,7 @@ private static uint _getJitFlags(IntPtr thisHandle, IntPtr* ppException, CORJIT_ private static IntPtr GetUnmanagedCallbacks() { - void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 177); + void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 175); callbacks[0] = (delegate* unmanaged)&_isIntrinsic; callbacks[1] = (delegate* unmanaged)&_notifyMethodInfoUsage; @@ -2666,142 +2636,140 @@ private static IntPtr GetUnmanagedCallbacks() callbacks[38] = (delegate* unmanaged)&_printClassName; callbacks[39] = (delegate* unmanaged)&_isValueClass; callbacks[40] = (delegate* unmanaged)&_getClassAttribs; - callbacks[41] = (delegate* unmanaged)&_getClassModule; - callbacks[42] = (delegate* unmanaged)&_getModuleAssembly; - callbacks[43] = (delegate* unmanaged)&_getAssemblyName; - callbacks[44] = (delegate* unmanaged)&_LongLifetimeMalloc; - callbacks[45] = (delegate* unmanaged)&_LongLifetimeFree; - callbacks[46] = (delegate* unmanaged)&_getIsClassInitedFlagAddress; - callbacks[47] = (delegate* unmanaged)&_getClassThreadStaticDynamicInfo; - callbacks[48] = (delegate* unmanaged)&_getClassStaticDynamicInfo; - callbacks[49] = (delegate* unmanaged)&_getStaticBaseAddress; - callbacks[50] = (delegate* unmanaged)&_getClassSize; - callbacks[51] = (delegate* unmanaged)&_getHeapClassSize; - callbacks[52] = (delegate* unmanaged)&_canAllocateOnStack; - callbacks[53] = (delegate* unmanaged)&_getClassAlignmentRequirement; - callbacks[54] = (delegate* unmanaged)&_getClassGClayout; - callbacks[55] = (delegate* unmanaged)&_getClassNumInstanceFields; - callbacks[56] = (delegate* unmanaged)&_getFieldInClass; - callbacks[57] = (delegate* unmanaged)&_getTypeLayout; - 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)&_getTypeForBoxOnStack; - callbacks[65] = (delegate* unmanaged)&_getBoxHelper; - callbacks[66] = (delegate* unmanaged)&_getUnBoxHelper; - callbacks[67] = (delegate* unmanaged)&_getRuntimeTypePointer; - callbacks[68] = (delegate* unmanaged)&_isObjectImmutable; - callbacks[69] = (delegate* unmanaged)&_getStringChar; - callbacks[70] = (delegate* unmanaged)&_getObjectType; - callbacks[71] = (delegate* unmanaged)&_getReadyToRunHelper; - callbacks[72] = (delegate* unmanaged)&_getReadyToRunDelegateCtorHelper; - callbacks[73] = (delegate* unmanaged)&_initClass; - callbacks[74] = (delegate* unmanaged)&_classMustBeLoadedBeforeCodeIsRun; - callbacks[75] = (delegate* unmanaged)&_getBuiltinClass; - callbacks[76] = (delegate* unmanaged)&_getTypeForPrimitiveValueClass; - callbacks[77] = (delegate* unmanaged)&_getTypeForPrimitiveNumericClass; - callbacks[78] = (delegate* unmanaged)&_canCast; - callbacks[79] = (delegate* unmanaged)&_compareTypesForCast; - callbacks[80] = (delegate* unmanaged)&_compareTypesForEquality; - callbacks[81] = (delegate* unmanaged)&_isMoreSpecificType; - callbacks[82] = (delegate* unmanaged)&_isExactType; - callbacks[83] = (delegate* unmanaged)&_isGenericType; - callbacks[84] = (delegate* unmanaged)&_isNullableType; - callbacks[85] = (delegate* unmanaged)&_isEnum; - callbacks[86] = (delegate* unmanaged)&_getParentType; - callbacks[87] = (delegate* unmanaged)&_getChildType; - callbacks[88] = (delegate* unmanaged)&_isSDArray; - callbacks[89] = (delegate* unmanaged)&_getArrayRank; - callbacks[90] = (delegate* unmanaged)&_getArrayIntrinsicID; - callbacks[91] = (delegate* unmanaged)&_getArrayInitializationData; - callbacks[92] = (delegate* unmanaged)&_canAccessClass; - callbacks[93] = (delegate* unmanaged)&_printFieldName; - callbacks[94] = (delegate* unmanaged)&_getFieldClass; - callbacks[95] = (delegate* unmanaged)&_getFieldType; - callbacks[96] = (delegate* unmanaged)&_getFieldOffset; - callbacks[97] = (delegate* unmanaged)&_getFieldInfo; - callbacks[98] = (delegate* unmanaged)&_getThreadLocalFieldInfo; - callbacks[99] = (delegate* unmanaged)&_getThreadLocalStaticBlocksInfo; - callbacks[100] = (delegate* unmanaged)&_getThreadLocalStaticInfo_NativeAOT; - callbacks[101] = (delegate* unmanaged)&_isFieldStatic; - callbacks[102] = (delegate* unmanaged)&_getArrayOrStringLength; - callbacks[103] = (delegate* unmanaged)&_getBoundaries; - callbacks[104] = (delegate* unmanaged)&_setBoundaries; - callbacks[105] = (delegate* unmanaged)&_getVars; - callbacks[106] = (delegate* unmanaged)&_setVars; - callbacks[107] = (delegate* unmanaged)&_reportRichMappings; - callbacks[108] = (delegate* unmanaged)&_reportMetadata; - callbacks[109] = (delegate* unmanaged)&_allocateArray; - callbacks[110] = (delegate* unmanaged)&_freeArray; - callbacks[111] = (delegate* unmanaged)&_getArgNext; - callbacks[112] = (delegate* unmanaged)&_getArgType; - callbacks[113] = (delegate* unmanaged)&_getExactClasses; - callbacks[114] = (delegate* unmanaged)&_getArgClass; - callbacks[115] = (delegate* unmanaged)&_getHFAType; - callbacks[116] = (delegate* unmanaged)&_runWithErrorTrap; - callbacks[117] = (delegate* unmanaged)&_runWithSPMIErrorTrap; - callbacks[118] = (delegate* unmanaged)&_getEEInfo; - callbacks[119] = (delegate* unmanaged)&_getJitTimeLogFilename; - callbacks[120] = (delegate* unmanaged)&_getMethodDefFromMethod; - callbacks[121] = (delegate* unmanaged)&_printMethodName; - callbacks[122] = (delegate* unmanaged)&_getMethodNameFromMetadata; - callbacks[123] = (delegate* unmanaged)&_getMethodHash; - callbacks[124] = (delegate* unmanaged)&_getSystemVAmd64PassStructInRegisterDescriptor; - callbacks[125] = (delegate* unmanaged)&_getSwiftLowering; - callbacks[126] = (delegate* unmanaged)&_getFpStructLowering; - callbacks[127] = (delegate* unmanaged)&_getThreadTLSIndex; - callbacks[128] = (delegate* unmanaged)&_getAddrOfCaptureThreadGlobal; - callbacks[129] = (delegate* unmanaged)&_getHelperFtn; - callbacks[130] = (delegate* unmanaged)&_getFunctionEntryPoint; - callbacks[131] = (delegate* unmanaged)&_getFunctionFixedEntryPoint; - callbacks[132] = (delegate* unmanaged)&_getMethodSync; - callbacks[133] = (delegate* unmanaged)&_getLazyStringLiteralHelper; - callbacks[134] = (delegate* unmanaged)&_embedModuleHandle; - callbacks[135] = (delegate* unmanaged)&_embedClassHandle; - callbacks[136] = (delegate* unmanaged)&_embedMethodHandle; - callbacks[137] = (delegate* unmanaged)&_embedFieldHandle; - callbacks[138] = (delegate* unmanaged)&_embedGenericHandle; - callbacks[139] = (delegate* unmanaged)&_getLocationOfThisType; - callbacks[140] = (delegate* unmanaged)&_getAddressOfPInvokeTarget; - callbacks[141] = (delegate* unmanaged)&_GetCookieForPInvokeCalliSig; - callbacks[142] = (delegate* unmanaged)&_canGetCookieForPInvokeCalliSig; - callbacks[143] = (delegate* unmanaged)&_getJustMyCodeHandle; - callbacks[144] = (delegate* unmanaged)&_GetProfilingHandle; - callbacks[145] = (delegate* unmanaged)&_getCallInfo; - callbacks[146] = (delegate* unmanaged)&_getStaticFieldContent; - callbacks[147] = (delegate* unmanaged)&_getObjectContent; - callbacks[148] = (delegate* unmanaged)&_getStaticFieldCurrentClass; - callbacks[149] = (delegate* unmanaged)&_getVarArgsHandle; - callbacks[150] = (delegate* unmanaged)&_canGetVarArgsHandle; - callbacks[151] = (delegate* unmanaged)&_constructStringLiteral; - callbacks[152] = (delegate* unmanaged)&_emptyStringLiteral; - callbacks[153] = (delegate* unmanaged)&_getFieldThreadLocalStoreID; - callbacks[154] = (delegate* unmanaged)&_GetDelegateCtor; - callbacks[155] = (delegate* unmanaged)&_MethodCompileComplete; - callbacks[156] = (delegate* unmanaged)&_getTailCallHelpers; - callbacks[157] = (delegate* unmanaged)&_convertPInvokeCalliToCall; - callbacks[158] = (delegate* unmanaged)&_notifyInstructionSetUsage; - callbacks[159] = (delegate* unmanaged)&_updateEntryPointForTailCall; - callbacks[160] = (delegate* unmanaged)&_allocMem; - callbacks[161] = (delegate* unmanaged)&_reserveUnwindInfo; - callbacks[162] = (delegate* unmanaged)&_allocUnwindInfo; - callbacks[163] = (delegate* unmanaged)&_allocGCInfo; - callbacks[164] = (delegate* unmanaged)&_setEHcount; - callbacks[165] = (delegate* unmanaged)&_setEHinfo; - callbacks[166] = (delegate* unmanaged)&_logMsg; - callbacks[167] = (delegate* unmanaged)&_doAssert; - callbacks[168] = (delegate* unmanaged)&_reportFatalError; - callbacks[169] = (delegate* unmanaged)&_getPgoInstrumentationResults; - callbacks[170] = (delegate* unmanaged)&_allocPgoInstrumentationBySchema; - callbacks[171] = (delegate* unmanaged)&_recordCallSite; - callbacks[172] = (delegate* unmanaged)&_recordRelocation; - callbacks[173] = (delegate* unmanaged)&_getRelocTypeHint; - callbacks[174] = (delegate* unmanaged)&_getExpectedTargetArchitecture; - callbacks[175] = (delegate* unmanaged)&_getJitFlags; - callbacks[176] = (delegate* unmanaged)&_getSpecialCopyHelper; + callbacks[41] = (delegate* unmanaged)&_getClassAssemblyName; + callbacks[42] = (delegate* unmanaged)&_LongLifetimeMalloc; + callbacks[43] = (delegate* unmanaged)&_LongLifetimeFree; + callbacks[44] = (delegate* unmanaged)&_getIsClassInitedFlagAddress; + callbacks[45] = (delegate* unmanaged)&_getClassThreadStaticDynamicInfo; + callbacks[46] = (delegate* unmanaged)&_getClassStaticDynamicInfo; + callbacks[47] = (delegate* unmanaged)&_getStaticBaseAddress; + callbacks[48] = (delegate* unmanaged)&_getClassSize; + callbacks[49] = (delegate* unmanaged)&_getHeapClassSize; + callbacks[50] = (delegate* unmanaged)&_canAllocateOnStack; + callbacks[51] = (delegate* unmanaged)&_getClassAlignmentRequirement; + callbacks[52] = (delegate* unmanaged)&_getClassGClayout; + callbacks[53] = (delegate* unmanaged)&_getClassNumInstanceFields; + callbacks[54] = (delegate* unmanaged)&_getFieldInClass; + callbacks[55] = (delegate* unmanaged)&_getTypeLayout; + callbacks[56] = (delegate* unmanaged)&_checkMethodModifier; + callbacks[57] = (delegate* unmanaged)&_getNewHelper; + callbacks[58] = (delegate* unmanaged)&_getNewArrHelper; + callbacks[59] = (delegate* unmanaged)&_getCastingHelper; + callbacks[60] = (delegate* unmanaged)&_getSharedCCtorHelper; + callbacks[61] = (delegate* unmanaged)&_getTypeForBox; + callbacks[62] = (delegate* unmanaged)&_getTypeForBoxOnStack; + callbacks[63] = (delegate* unmanaged)&_getBoxHelper; + callbacks[64] = (delegate* unmanaged)&_getUnBoxHelper; + callbacks[65] = (delegate* unmanaged)&_getRuntimeTypePointer; + callbacks[66] = (delegate* unmanaged)&_isObjectImmutable; + callbacks[67] = (delegate* unmanaged)&_getStringChar; + callbacks[68] = (delegate* unmanaged)&_getObjectType; + callbacks[69] = (delegate* unmanaged)&_getReadyToRunHelper; + callbacks[70] = (delegate* unmanaged)&_getReadyToRunDelegateCtorHelper; + callbacks[71] = (delegate* unmanaged)&_initClass; + callbacks[72] = (delegate* unmanaged)&_classMustBeLoadedBeforeCodeIsRun; + callbacks[73] = (delegate* unmanaged)&_getBuiltinClass; + callbacks[74] = (delegate* unmanaged)&_getTypeForPrimitiveValueClass; + callbacks[75] = (delegate* unmanaged)&_getTypeForPrimitiveNumericClass; + callbacks[76] = (delegate* unmanaged)&_canCast; + callbacks[77] = (delegate* unmanaged)&_compareTypesForCast; + callbacks[78] = (delegate* unmanaged)&_compareTypesForEquality; + callbacks[79] = (delegate* unmanaged)&_isMoreSpecificType; + callbacks[80] = (delegate* unmanaged)&_isExactType; + callbacks[81] = (delegate* unmanaged)&_isGenericType; + callbacks[82] = (delegate* unmanaged)&_isNullableType; + callbacks[83] = (delegate* unmanaged)&_isEnum; + callbacks[84] = (delegate* unmanaged)&_getParentType; + callbacks[85] = (delegate* unmanaged)&_getChildType; + callbacks[86] = (delegate* unmanaged)&_isSDArray; + callbacks[87] = (delegate* unmanaged)&_getArrayRank; + callbacks[88] = (delegate* unmanaged)&_getArrayIntrinsicID; + callbacks[89] = (delegate* unmanaged)&_getArrayInitializationData; + callbacks[90] = (delegate* unmanaged)&_canAccessClass; + callbacks[91] = (delegate* unmanaged)&_printFieldName; + callbacks[92] = (delegate* unmanaged)&_getFieldClass; + callbacks[93] = (delegate* unmanaged)&_getFieldType; + callbacks[94] = (delegate* unmanaged)&_getFieldOffset; + callbacks[95] = (delegate* unmanaged)&_getFieldInfo; + callbacks[96] = (delegate* unmanaged)&_getThreadLocalFieldInfo; + callbacks[97] = (delegate* unmanaged)&_getThreadLocalStaticBlocksInfo; + callbacks[98] = (delegate* unmanaged)&_getThreadLocalStaticInfo_NativeAOT; + callbacks[99] = (delegate* unmanaged)&_isFieldStatic; + callbacks[100] = (delegate* unmanaged)&_getArrayOrStringLength; + callbacks[101] = (delegate* unmanaged)&_getBoundaries; + callbacks[102] = (delegate* unmanaged)&_setBoundaries; + callbacks[103] = (delegate* unmanaged)&_getVars; + callbacks[104] = (delegate* unmanaged)&_setVars; + callbacks[105] = (delegate* unmanaged)&_reportRichMappings; + callbacks[106] = (delegate* unmanaged)&_reportMetadata; + callbacks[107] = (delegate* unmanaged)&_allocateArray; + callbacks[108] = (delegate* unmanaged)&_freeArray; + callbacks[109] = (delegate* unmanaged)&_getArgNext; + callbacks[110] = (delegate* unmanaged)&_getArgType; + callbacks[111] = (delegate* unmanaged)&_getExactClasses; + callbacks[112] = (delegate* unmanaged)&_getArgClass; + callbacks[113] = (delegate* unmanaged)&_getHFAType; + callbacks[114] = (delegate* unmanaged)&_runWithErrorTrap; + callbacks[115] = (delegate* unmanaged)&_runWithSPMIErrorTrap; + callbacks[116] = (delegate* unmanaged)&_getEEInfo; + callbacks[117] = (delegate* unmanaged)&_getJitTimeLogFilename; + callbacks[118] = (delegate* unmanaged)&_getMethodDefFromMethod; + callbacks[119] = (delegate* unmanaged)&_printMethodName; + callbacks[120] = (delegate* unmanaged)&_getMethodNameFromMetadata; + callbacks[121] = (delegate* unmanaged)&_getMethodHash; + callbacks[122] = (delegate* unmanaged)&_getSystemVAmd64PassStructInRegisterDescriptor; + callbacks[123] = (delegate* unmanaged)&_getSwiftLowering; + callbacks[124] = (delegate* unmanaged)&_getFpStructLowering; + callbacks[125] = (delegate* unmanaged)&_getThreadTLSIndex; + callbacks[126] = (delegate* unmanaged)&_getAddrOfCaptureThreadGlobal; + callbacks[127] = (delegate* unmanaged)&_getHelperFtn; + callbacks[128] = (delegate* unmanaged)&_getFunctionEntryPoint; + callbacks[129] = (delegate* unmanaged)&_getFunctionFixedEntryPoint; + callbacks[130] = (delegate* unmanaged)&_getMethodSync; + callbacks[131] = (delegate* unmanaged)&_getLazyStringLiteralHelper; + callbacks[132] = (delegate* unmanaged)&_embedModuleHandle; + callbacks[133] = (delegate* unmanaged)&_embedClassHandle; + callbacks[134] = (delegate* unmanaged)&_embedMethodHandle; + callbacks[135] = (delegate* unmanaged)&_embedFieldHandle; + callbacks[136] = (delegate* unmanaged)&_embedGenericHandle; + callbacks[137] = (delegate* unmanaged)&_getLocationOfThisType; + callbacks[138] = (delegate* unmanaged)&_getAddressOfPInvokeTarget; + callbacks[139] = (delegate* unmanaged)&_GetCookieForPInvokeCalliSig; + callbacks[140] = (delegate* unmanaged)&_canGetCookieForPInvokeCalliSig; + callbacks[141] = (delegate* unmanaged)&_getJustMyCodeHandle; + callbacks[142] = (delegate* unmanaged)&_GetProfilingHandle; + callbacks[143] = (delegate* unmanaged)&_getCallInfo; + callbacks[144] = (delegate* unmanaged)&_getStaticFieldContent; + callbacks[145] = (delegate* unmanaged)&_getObjectContent; + callbacks[146] = (delegate* unmanaged)&_getStaticFieldCurrentClass; + callbacks[147] = (delegate* unmanaged)&_getVarArgsHandle; + callbacks[148] = (delegate* unmanaged)&_canGetVarArgsHandle; + callbacks[149] = (delegate* unmanaged)&_constructStringLiteral; + callbacks[150] = (delegate* unmanaged)&_emptyStringLiteral; + callbacks[151] = (delegate* unmanaged)&_getFieldThreadLocalStoreID; + callbacks[152] = (delegate* unmanaged)&_GetDelegateCtor; + callbacks[153] = (delegate* unmanaged)&_MethodCompileComplete; + callbacks[154] = (delegate* unmanaged)&_getTailCallHelpers; + callbacks[155] = (delegate* unmanaged)&_convertPInvokeCalliToCall; + callbacks[156] = (delegate* unmanaged)&_notifyInstructionSetUsage; + callbacks[157] = (delegate* unmanaged)&_updateEntryPointForTailCall; + callbacks[158] = (delegate* unmanaged)&_allocMem; + callbacks[159] = (delegate* unmanaged)&_reserveUnwindInfo; + callbacks[160] = (delegate* unmanaged)&_allocUnwindInfo; + callbacks[161] = (delegate* unmanaged)&_allocGCInfo; + callbacks[162] = (delegate* unmanaged)&_setEHcount; + callbacks[163] = (delegate* unmanaged)&_setEHinfo; + callbacks[164] = (delegate* unmanaged)&_logMsg; + callbacks[165] = (delegate* unmanaged)&_doAssert; + callbacks[166] = (delegate* unmanaged)&_reportFatalError; + callbacks[167] = (delegate* unmanaged)&_getPgoInstrumentationResults; + callbacks[168] = (delegate* unmanaged)&_allocPgoInstrumentationBySchema; + callbacks[169] = (delegate* unmanaged)&_recordCallSite; + callbacks[170] = (delegate* unmanaged)&_recordRelocation; + callbacks[171] = (delegate* unmanaged)&_getRelocTypeHint; + callbacks[172] = (delegate* unmanaged)&_getExpectedTargetArchitecture; + callbacks[173] = (delegate* unmanaged)&_getJitFlags; + callbacks[174] = (delegate* unmanaged)&_getSpecialCopyHelper; return (IntPtr)callbacks; } diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs index 4be84d0c316f82..74b260578fd003 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs @@ -52,10 +52,6 @@ public struct CORINFO_MODULE_STRUCT_ { } - public struct CORINFO_ASSEMBLY_STRUCT_ - { - } - public struct CORINFO_CONTEXT_STRUCT { } diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt index 76d3ea9d3864af..bf98cf70a7e2d7 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -144,7 +144,6 @@ CORINFO_METHOD_HANDLE,CORINFO_METHOD_STRUCT_* CORINFO_FIELD_HANDLE,CORINFO_FIELD_STRUCT_* CORINFO_OBJECT_HANDLE,CORINFO_OBJECT_STRUCT_* CORINFO_CLASS_HANDLE,CORINFO_CLASS_STRUCT_* -CORINFO_ASSEMBLY_HANDLE,CORINFO_ASSEMBLY_STRUCT_* CORINFO_JUST_MY_CODE_HANDLE,CORINFO_JUST_MY_CODE_HANDLE_* CORINFO_MODULE_HANDLE*,CORINFO_MODULE_STRUCT_** CORINFO_CLASS_HANDLE*,CORINFO_CLASS_STRUCT_** @@ -205,9 +204,7 @@ FUNCTIONS size_t printClassName(CORINFO_CLASS_HANDLE cls, char* buffer, size_t bufferSize, size_t* pRequiredBufferSize) bool isValueClass(CORINFO_CLASS_HANDLE cls) uint32_t getClassAttribs(CORINFO_CLASS_HANDLE cls) - CORINFO_MODULE_HANDLE getClassModule(CORINFO_CLASS_HANDLE cls) - CORINFO_ASSEMBLY_HANDLE getModuleAssembly(CORINFO_MODULE_HANDLE mod) - const char* getAssemblyName(CORINFO_ASSEMBLY_HANDLE assem) + const char* getClassAssemblyName(CORINFO_CLASS_HANDLE cls) void* LongLifetimeMalloc(size_t sz) void LongLifetimeFree(void* obj) bool getIsClassInitedFlagAddress(CORINFO_CLASS_HANDLE cls, CORINFO_CONST_LOOKUP* addr, int* offset) diff --git a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h index 0ba43d2a45885f..0e9bde0b4def1e 100644 --- a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h +++ b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h @@ -52,9 +52,7 @@ struct JitInterfaceCallbacks size_t (* printClassName)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls, char* buffer, size_t bufferSize, size_t* pRequiredBufferSize); bool (* isValueClass)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls); uint32_t (* getClassAttribs)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls); - CORINFO_MODULE_HANDLE (* getClassModule)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls); - CORINFO_ASSEMBLY_HANDLE (* getModuleAssembly)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_MODULE_HANDLE mod); - const char* (* getAssemblyName)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_ASSEMBLY_HANDLE assem); + const char* (* getClassAssemblyName)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls); void* (* LongLifetimeMalloc)(void * thisHandle, CorInfoExceptionClass** ppException, size_t sz); void (* LongLifetimeFree)(void * thisHandle, CorInfoExceptionClass** ppException, void* obj); bool (* getIsClassInitedFlagAddress)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls, CORINFO_CONST_LOOKUP* addr, int* offset); @@ -607,29 +605,11 @@ class JitInterfaceWrapper : public ICorJitInfo return temp; } - virtual CORINFO_MODULE_HANDLE getClassModule( + virtual const char* getClassAssemblyName( CORINFO_CLASS_HANDLE cls) { CorInfoExceptionClass* pException = nullptr; - CORINFO_MODULE_HANDLE temp = _callbacks->getClassModule(_thisHandle, &pException, cls); - if (pException != nullptr) throw pException; - return temp; -} - - virtual CORINFO_ASSEMBLY_HANDLE getModuleAssembly( - CORINFO_MODULE_HANDLE mod) -{ - CorInfoExceptionClass* pException = nullptr; - CORINFO_ASSEMBLY_HANDLE temp = _callbacks->getModuleAssembly(_thisHandle, &pException, mod); - if (pException != nullptr) throw pException; - return temp; -} - - virtual const char* getAssemblyName( - CORINFO_ASSEMBLY_HANDLE assem) -{ - CorInfoExceptionClass* pException = nullptr; - const char* temp = _callbacks->getAssemblyName(_thisHandle, &pException, assem); + const char* temp = _callbacks->getClassAssemblyName(_thisHandle, &pException, cls); if (pException != nullptr) throw pException; return temp; } diff --git a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h index e00f86d1b64587..64b394309f567a 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h @@ -102,9 +102,7 @@ LWM(GetLocationOfThisType, DWORDLONG, Agnostic_CORINFO_LOOKUP_KIND) LWM(IsIntrinsic, DWORDLONG, DWORD) LWM(NotifyMethodInfoUsage, DWORDLONG, DWORD) LWM(GetMethodAttribs, DWORDLONG, DWORD) -LWM(GetClassModule, DWORDLONG, DWORDLONG) -LWM(GetModuleAssembly, DWORDLONG, DWORDLONG) -LWM(GetAssemblyName, DWORDLONG, DWORD) +LWM(GetClassAssemblyName, DWORDLONG, DWORD) LWM(GetMethodClass, DWORDLONG, DWORDLONG) LWM(GetMethodDefFromMethod, DWORDLONG, DWORD) LWM(GetMethodHash, DWORDLONG, DWORD) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index ddfc401aff1f26..36974d6534a71e 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -816,93 +816,44 @@ DWORD MethodContext::repGetMethodAttribs(CORINFO_METHOD_HANDLE methodHandle) return value; } -void MethodContext::recGetClassModule(CORINFO_CLASS_HANDLE cls, CORINFO_MODULE_HANDLE mod) +void MethodContext::recGetClassAssemblyName(CORINFO_CLASS_HANDLE cls, const char* assemblyName) { - if (GetClassModule == nullptr) - GetClassModule = new LightWeightMap(); - - DWORDLONG key = CastHandle(cls); - DWORDLONG value = CastHandle(mod); - GetClassModule->Add(key, value); - DEBUG_REC(dmpGetClassModule(key, value)); -} -void MethodContext::dmpGetClassModule(DWORDLONG key, DWORDLONG value) -{ - printf("GetClassModule cls-%016" PRIX64 ", mod-%016" PRIX64 "", key, value); -} -CORINFO_MODULE_HANDLE MethodContext::repGetClassModule(CORINFO_CLASS_HANDLE cls) -{ - DWORDLONG key = CastHandle(cls); - DWORDLONG value = LookupByKeyOrMiss(GetClassModule, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpGetClassModule(key, value)); - CORINFO_MODULE_HANDLE result = (CORINFO_MODULE_HANDLE)value; - return result; -} - -void MethodContext::recGetModuleAssembly(CORINFO_MODULE_HANDLE mod, CORINFO_ASSEMBLY_HANDLE assem) -{ - if (GetModuleAssembly == nullptr) - GetModuleAssembly = new LightWeightMap(); - - DWORDLONG key = CastHandle(mod); - DWORDLONG value = CastHandle(assem); - GetModuleAssembly->Add(key, value); - DEBUG_REC(dmpGetModuleAssembly(key, value)); -} -void MethodContext::dmpGetModuleAssembly(DWORDLONG key, DWORDLONG value) -{ - printf("GetModuleAssembly mod-%016" PRIX64 ", assem-%016" PRIX64 "", key, value); -} -CORINFO_ASSEMBLY_HANDLE MethodContext::repGetModuleAssembly(CORINFO_MODULE_HANDLE mod) -{ - DWORDLONG key = CastHandle(mod); - DWORDLONG value = LookupByKeyOrMiss(GetModuleAssembly, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpGetModuleAssembly(key, value)); - CORINFO_ASSEMBLY_HANDLE result = (CORINFO_ASSEMBLY_HANDLE)value; - return result; -} - -void MethodContext::recGetAssemblyName(CORINFO_ASSEMBLY_HANDLE assem, const char* assemblyName) -{ - if (GetAssemblyName == nullptr) - GetAssemblyName = new LightWeightMap(); + if (GetClassAssemblyName == nullptr) + GetClassAssemblyName = new LightWeightMap(); DWORD value; if (assemblyName != nullptr) { - value = GetAssemblyName->AddBuffer((const unsigned char*)assemblyName, (DWORD)strlen(assemblyName) + 1); + value = GetClassAssemblyName->AddBuffer((const unsigned char*)assemblyName, (DWORD)strlen(assemblyName) + 1); } else { value = (DWORD)-1; } - DWORDLONG key = CastHandle(assem); - GetAssemblyName->Add(key, value); - DEBUG_REC(dmpGetAssemblyName(key, value)); + DWORDLONG key = CastHandle(cls); + GetClassAssemblyName->Add(key, value); + DEBUG_REC(dmpGetClassAssemblyName(key, value)); } -void MethodContext::dmpGetAssemblyName(DWORDLONG key, DWORD value) +void MethodContext::dmpGetClassAssemblyName(DWORDLONG key, DWORD value) { - const char* assemblyName = (const char*)GetAssemblyName->GetBuffer(value); - printf("GetAssemblyName assem-%016" PRIX64 ", value-%u '%s'", key, value, assemblyName); - GetAssemblyName->Unlock(); + const char* assemblyName = (const char*)GetClassAssemblyName->GetBuffer(value); + printf("GetClassAssemblyName cls-%016" PRIX64 ", value-%u '%s'", key, value, assemblyName); + GetClassAssemblyName->Unlock(); } -const char* MethodContext::repGetAssemblyName(CORINFO_ASSEMBLY_HANDLE assem) +const char* MethodContext::repGetClassAssemblyName(CORINFO_CLASS_HANDLE cls) { - DWORDLONG key = CastHandle(assem); - const char* result = "hackishAssemblyName"; - DWORD value = (DWORD)-1; - int itemIndex = -1; - if (GetAssemblyName != nullptr) - { - itemIndex = GetAssemblyName->GetIndex(key); - } - if (itemIndex >= 0) + DWORDLONG key = CastHandle(cls); + DWORD value = LookupByKeyOrMiss(GetClassAssemblyName, key, ": key %016" PRIX64 "", key); + const char* result = nullptr; + + DEBUG_REP(dmpGetClassAssemblyName(key, value)); + + if (value != (DWORD)-1) { - value = GetAssemblyName->Get(key); - result = (const char*)GetAssemblyName->GetBuffer(value); + result = (const char*)GetClassAssemblyName->GetBuffer(value); } - DEBUG_REP(dmpGetAssemblyName(key, value)); + return result; } diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h index ffe0e7aaa5bdc7..0fd63deb1bad4b 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h @@ -130,17 +130,9 @@ class MethodContext void dmpGetMethodAttribs(DWORDLONG key, DWORD value); DWORD repGetMethodAttribs(CORINFO_METHOD_HANDLE methodHandle); - void recGetClassModule(CORINFO_CLASS_HANDLE cls, CORINFO_MODULE_HANDLE mod); - void dmpGetClassModule(DWORDLONG key, DWORDLONG value); - CORINFO_MODULE_HANDLE repGetClassModule(CORINFO_CLASS_HANDLE cls); - - void recGetModuleAssembly(CORINFO_MODULE_HANDLE mod, CORINFO_ASSEMBLY_HANDLE assem); - void dmpGetModuleAssembly(DWORDLONG key, DWORDLONG value); - CORINFO_ASSEMBLY_HANDLE repGetModuleAssembly(CORINFO_MODULE_HANDLE mod); - - void recGetAssemblyName(CORINFO_ASSEMBLY_HANDLE assem, const char* assemblyName); - void dmpGetAssemblyName(DWORDLONG key, DWORD value); - const char* repGetAssemblyName(CORINFO_ASSEMBLY_HANDLE assem); + void recGetClassAssemblyName(CORINFO_CLASS_HANDLE cls, const char* assemblyName); + void dmpGetClassAssemblyName(DWORDLONG key, DWORD value); + const char* repGetClassAssemblyName(CORINFO_CLASS_HANDLE cls); void recGetVars(CORINFO_METHOD_HANDLE ftn, ULONG32* cVars, ICorDebugInfo::ILVarInfo** vars, bool* extendOthers); void dmpGetVars(DWORDLONG key, const Agnostic_GetVars& value); @@ -1158,9 +1150,9 @@ enum mcPackets Packet_AllocPgoInstrumentationBySchema = 186, Packet_GetPgoInstrumentationResults = 187, Packet_GetDefaultComparerClass = 188, - Packet_GetClassModule = 189, - Packet_GetModuleAssembly = 190, - Packet_GetAssemblyName = 191, + //Packet_GetClassModule = 189, + //Packet_GetModuleAssembly = 190, + //Packet_GetAssemblyName = 191, Packet_IsIntrinsic = 192, Packet_UpdateEntryPointForTailCall = 193, //Packet_GetLoongArch64PassStructInRegisterFlags = 194, @@ -1194,6 +1186,7 @@ enum mcPackets Packet_GetTypeDefinition = 222, Packet_GetFpStructLowering = 223, Packet_GetSpecialCopyHelper = 224, + Packet_GetClassAssemblyName = 225, }; void SetDebugDumpVariables(); diff --git a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp index 5cf11bf9420dfb..274ebcaa7eb001 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -491,29 +491,12 @@ uint32_t interceptor_ICJI::getClassAttribs(CORINFO_CLASS_HANDLE cls) return temp; } -CORINFO_MODULE_HANDLE interceptor_ICJI::getClassModule(CORINFO_CLASS_HANDLE cls) +// Returns the assembly name of the class "cls". +const char* interceptor_ICJI::getClassAssemblyName(CORINFO_CLASS_HANDLE cls) { - mc->cr->AddCall("getClassModule"); - CORINFO_MODULE_HANDLE temp = original_ICorJitInfo->getClassModule(cls); - mc->recGetClassModule(cls, temp); - return temp; -} - -// Returns the assembly that contains the module "mod". -CORINFO_ASSEMBLY_HANDLE interceptor_ICJI::getModuleAssembly(CORINFO_MODULE_HANDLE mod) -{ - mc->cr->AddCall("getModuleAssembly"); - CORINFO_ASSEMBLY_HANDLE temp = original_ICorJitInfo->getModuleAssembly(mod); - mc->recGetModuleAssembly(mod, temp); - return temp; -} - -// Returns the name of the assembly "assem". -const char* interceptor_ICJI::getAssemblyName(CORINFO_ASSEMBLY_HANDLE assem) -{ - mc->cr->AddCall("getAssemblyName"); - const char* temp = original_ICorJitInfo->getAssemblyName(assem); - mc->recGetAssemblyName(assem, temp); + mc->cr->AddCall("getClassAssemblyName"); + const char* temp = original_ICorJitInfo->getClassAssemblyName(cls); + mc->recGetClassAssemblyName(cls, temp); return temp; } diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp index 9d5eb18dfc4d9f..bba12312ee908e 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp @@ -348,25 +348,11 @@ uint32_t interceptor_ICJI::getClassAttribs( return original_ICorJitInfo->getClassAttribs(cls); } -CORINFO_MODULE_HANDLE interceptor_ICJI::getClassModule( +const char* interceptor_ICJI::getClassAssemblyName( CORINFO_CLASS_HANDLE cls) { - mcs->AddCall("getClassModule"); - return original_ICorJitInfo->getClassModule(cls); -} - -CORINFO_ASSEMBLY_HANDLE interceptor_ICJI::getModuleAssembly( - CORINFO_MODULE_HANDLE mod) -{ - mcs->AddCall("getModuleAssembly"); - return original_ICorJitInfo->getModuleAssembly(mod); -} - -const char* interceptor_ICJI::getAssemblyName( - CORINFO_ASSEMBLY_HANDLE assem) -{ - mcs->AddCall("getAssemblyName"); - return original_ICorJitInfo->getAssemblyName(assem); + mcs->AddCall("getClassAssemblyName"); + return original_ICorJitInfo->getClassAssemblyName(cls); } void* interceptor_ICJI::LongLifetimeMalloc( diff --git a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp index 8e3bff4eb70674..2c789226b7f56c 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp @@ -307,22 +307,10 @@ uint32_t interceptor_ICJI::getClassAttribs( return original_ICorJitInfo->getClassAttribs(cls); } -CORINFO_MODULE_HANDLE interceptor_ICJI::getClassModule( +const char* interceptor_ICJI::getClassAssemblyName( CORINFO_CLASS_HANDLE cls) { - return original_ICorJitInfo->getClassModule(cls); -} - -CORINFO_ASSEMBLY_HANDLE interceptor_ICJI::getModuleAssembly( - CORINFO_MODULE_HANDLE mod) -{ - return original_ICorJitInfo->getModuleAssembly(mod); -} - -const char* interceptor_ICJI::getAssemblyName( - CORINFO_ASSEMBLY_HANDLE assem) -{ - return original_ICorJitInfo->getAssemblyName(assem); + return original_ICorJitInfo->getClassAssemblyName(cls); } void* interceptor_ICJI::LongLifetimeMalloc( diff --git a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp index c3c4fd276490ef..0fc1df067dd7dc 100644 --- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp @@ -416,24 +416,11 @@ uint32_t MyICJI::getClassAttribs(CORINFO_CLASS_HANDLE cls) return jitInstance->mc->repGetClassAttribs(cls); } -CORINFO_MODULE_HANDLE MyICJI::getClassModule(CORINFO_CLASS_HANDLE cls) +// Returns the assembly name of the class "cls". +const char* MyICJI::getClassAssemblyName(CORINFO_CLASS_HANDLE cls) { - jitInstance->mc->cr->AddCall("getClassModule"); - return jitInstance->mc->repGetClassModule(cls); -} - -// Returns the assembly that contains the module "mod". -CORINFO_ASSEMBLY_HANDLE MyICJI::getModuleAssembly(CORINFO_MODULE_HANDLE mod) -{ - jitInstance->mc->cr->AddCall("getModuleAssembly"); - return jitInstance->mc->repGetModuleAssembly(mod); -} - -// Returns the name of the assembly "assem". -const char* MyICJI::getAssemblyName(CORINFO_ASSEMBLY_HANDLE assem) -{ - jitInstance->mc->cr->AddCall("getAssemblyName"); - return jitInstance->mc->repGetAssemblyName(assem); + jitInstance->mc->cr->AddCall("getClassAssemblyName"); + return jitInstance->mc->repGetClassAssemblyName(cls); } // Allocate and delete process-lifetime objects. Should only be diff --git a/src/coreclr/vm/appdomain.cpp b/src/coreclr/vm/appdomain.cpp index 8d3395cd8ebbd2..287823cac17f6e 100644 --- a/src/coreclr/vm/appdomain.cpp +++ b/src/coreclr/vm/appdomain.cpp @@ -1546,15 +1546,15 @@ void SystemDomain::NotifyProfilerStartup() { BEGIN_PROFILER_CALLBACK(CORProfilerTrackAppDomainLoads()); - _ASSERTE(System()->DefaultDomain()); - (&g_profControlBlock)->AppDomainCreationStarted((AppDomainID) System()->DefaultDomain()); + _ASSERTE(AppDomain::GetCurrentDomain()); + (&g_profControlBlock)->AppDomainCreationStarted((AppDomainID) AppDomain::GetCurrentDomain()); END_PROFILER_CALLBACK(); } { BEGIN_PROFILER_CALLBACK(CORProfilerTrackAppDomainLoads()); - _ASSERTE(System()->DefaultDomain()); - (&g_profControlBlock)->AppDomainCreationFinished((AppDomainID) System()->DefaultDomain(), S_OK); + _ASSERTE(AppDomain::GetCurrentDomain()); + (&g_profControlBlock)->AppDomainCreationFinished((AppDomainID) AppDomain::GetCurrentDomain(), S_OK); END_PROFILER_CALLBACK(); } } @@ -1585,15 +1585,15 @@ HRESULT SystemDomain::NotifyProfilerShutdown() { BEGIN_PROFILER_CALLBACK(CORProfilerTrackAppDomainLoads()); - _ASSERTE(System()->DefaultDomain()); - (&g_profControlBlock)->AppDomainShutdownStarted((AppDomainID) System()->DefaultDomain()); + _ASSERTE(AppDomain::GetCurrentDomain()); + (&g_profControlBlock)->AppDomainShutdownStarted((AppDomainID) AppDomain::GetCurrentDomain()); END_PROFILER_CALLBACK(); } { BEGIN_PROFILER_CALLBACK(CORProfilerTrackAppDomainLoads()); - _ASSERTE(System()->DefaultDomain()); - (&g_profControlBlock)->AppDomainShutdownFinished((AppDomainID) System()->DefaultDomain(), S_OK); + _ASSERTE(AppDomain::GetCurrentDomain()); + (&g_profControlBlock)->AppDomainShutdownFinished((AppDomainID) AppDomain::GetCurrentDomain(), S_OK); END_PROFILER_CALLBACK(); } return (S_OK); @@ -2481,6 +2481,9 @@ DomainAssembly *AppDomain::LoadDomainAssemblyInternal(AssemblySpec* pIdentity, fileLock = FileLoadLock::Create(lock, pPEAssembly, pDomainAssembly); pDomainAssembly.SuppressRelease(); pamTracker->SuppressRelease(); + + // Set the assembly module to be tenured now that we know it won't be deleted + pDomainAssembly->GetAssembly()->SetIsTenured(); if (pDomainAssembly->IsCollectible()) { // We add the assembly to the LoaderAllocator only when we are sure that it can be added @@ -2516,7 +2519,9 @@ DomainAssembly *AppDomain::LoadDomainAssemblyInternal(AssemblySpec* pIdentity, } } else + { result->EnsureLoadLevel(targetLevel); + } // Cache result in all cases, since found pPEAssembly could be from a different AssemblyRef than pIdentity if (pIdentity == NULL) diff --git a/src/coreclr/vm/appdomain.hpp b/src/coreclr/vm/appdomain.hpp index b357f6e1a512a9..ef026a3704de7a 100644 --- a/src/coreclr/vm/appdomain.hpp +++ b/src/coreclr/vm/appdomain.hpp @@ -2014,7 +2014,7 @@ class SystemDomain : public BaseDomain m_pDelayedUnloadListOfLoaderAllocators=NULL; - m_GlobalAllocator.Init(this); + m_GlobalAllocator.Init(); } #endif @@ -2023,7 +2023,6 @@ class SystemDomain : public BaseDomain GlobalLoaderAllocator m_GlobalAllocator; - InlineSString<100> m_BaseLibrary; InlineSString<100> m_SystemDirectory; diff --git a/src/coreclr/vm/assembly.cpp b/src/coreclr/vm/assembly.cpp index 9c4209c268bcf0..0d344df01297bd 100644 --- a/src/coreclr/vm/assembly.cpp +++ b/src/coreclr/vm/assembly.cpp @@ -456,7 +456,7 @@ Assembly *Assembly::CreateDynamic(AssemblyBinder* pBinder, NativeAssemblyNamePar // Some of the initialization functions are not virtual. Call through the derived class // to prevent calling the base class version. - pCollectibleLoaderAllocator->Init(pDomain); + pCollectibleLoaderAllocator->Init(); // Setup the managed proxy now, but do not actually transfer ownership to it. // Once everything is setup and nothing can fail anymore, the ownership will be @@ -531,6 +531,7 @@ Assembly *Assembly::CreateDynamic(AssemblyBinder* pBinder, NativeAssemblyNamePar pLoaderAllocator.SuppressRelease(); } + // Set the assembly module to be tenured now that we know it won't be deleted pAssem->SetIsTenured(); pRetVal = pAssem; } diff --git a/src/coreclr/vm/assemblynative.cpp b/src/coreclr/vm/assemblynative.cpp index 94220a1e35bad8..cad3829428c15c 100644 --- a/src/coreclr/vm/assemblynative.cpp +++ b/src/coreclr/vm/assemblynative.cpp @@ -513,16 +513,16 @@ extern "C" void QCALLTYPE AssemblyNative_GetForwardedType(QCall::AssemblyHandle END_QCALL; } -FCIMPL1(FC_BOOL_RET, AssemblyNative::IsDynamic, AssemblyBaseObject* pAssemblyUNSAFE) +FCIMPL1(FC_BOOL_RET, AssemblyNative::GetIsDynamic, Assembly* pAssembly) { - FCALL_CONTRACT; - - ASSEMBLYREF refAssembly = (ASSEMBLYREF)ObjectToOBJECTREF(pAssemblyUNSAFE); - - if (refAssembly == NULL) - FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle")); + CONTRACTL + { + FCALL_CHECK; + PRECONDITION(CheckPointer(pAssembly)); + } + CONTRACTL_END; - FC_RETURN_BOOL(refAssembly->GetAssembly()->GetPEAssembly()->IsReflectionEmit()); + FC_RETURN_BOOL(pAssembly->GetPEAssembly()->IsReflectionEmit()); } FCIMPLEND @@ -1205,7 +1205,7 @@ extern "C" INT_PTR QCALLTYPE AssemblyNative_InitializeAssemblyLoadContext(INT_PT GCX_PREEMP(); // Some of the initialization functions are not virtual. Call through the derived class // to prevent calling the base class version. - loaderAllocator->Init(pCurDomain); + loaderAllocator->Init(); loaderAllocator->InitVirtualCallStubManager(); // Setup the managed proxy now, but do not actually transfer ownership to it. diff --git a/src/coreclr/vm/assemblynative.hpp b/src/coreclr/vm/assemblynative.hpp index 80ae3da8c2bd59..1ff73a406c70ae 100644 --- a/src/coreclr/vm/assemblynative.hpp +++ b/src/coreclr/vm/assemblynative.hpp @@ -19,10 +19,6 @@ class CustomAssemblyBinder; class AssemblyNative { - friend class Assembly; - friend class BaseDomain; - friend class DomainAssembly; - public: static Assembly* LoadFromPEImage(AssemblyBinder* pBinder, PEImage *pImage, bool excludeAppPaths = false); @@ -35,7 +31,7 @@ class AssemblyNative // static - FCDECL1(FC_BOOL_RET, IsDynamic, AssemblyBaseObject * pAssemblyUNSAFE); + FCDECL1(FC_BOOL_RET, GetIsDynamic, Assembly* pAssembly); }; extern "C" uint32_t QCALLTYPE AssemblyNative_GetAssemblyCount(); diff --git a/src/coreclr/vm/clsload.cpp b/src/coreclr/vm/clsload.cpp index 0c42ca20161eee..ce23d1e907f31d 100644 --- a/src/coreclr/vm/clsload.cpp +++ b/src/coreclr/vm/clsload.cpp @@ -836,27 +836,6 @@ void ClassLoader::EnsureLoaded(TypeHandle typeHnd, ClassLoadLevel level) #endif // DACCESS_COMPILE } -/*static*/ -void ClassLoader::TryEnsureLoaded(TypeHandle typeHnd, ClassLoadLevel level) -{ - WRAPPER_NO_CONTRACT; - -#ifndef DACCESS_COMPILE // Nothing to do for the DAC case - - EX_TRY - { - ClassLoader::EnsureLoaded(typeHnd, level); - } - EX_CATCH - { - // Some type may not load successfully. For eg. generic instantiations - // that do not satisfy the constraints of the type arguments. - } - EX_END_CATCH(RethrowTerminalExceptions); - -#endif // DACCESS_COMPILE -} - /* static */ TypeHandle ClassLoader::LookupTypeKey(const TypeKey *pKey, EETypeHashTable *pTable) { diff --git a/src/coreclr/vm/clsload.hpp b/src/coreclr/vm/clsload.hpp index 95afa2716ec9f7..f6cb4f06c0021d 100644 --- a/src/coreclr/vm/clsload.hpp +++ b/src/coreclr/vm/clsload.hpp @@ -564,11 +564,6 @@ class ClassLoader Module * pLookInThisModuleOnly, Loader::LoadFlag loadFlag); - static PTR_Module ComputeLoaderModuleForCompilation(Module *pDefinitionModule, // the module that declares the generic type or method - mdToken token, - Instantiation classInst, // the type arguments to the type (if any) - Instantiation methodInst); // the type arguments to the method (if any) - public: void Init(AllocMemTracker *pamTracker); @@ -718,7 +713,6 @@ class ClassLoader BOOL * pfUsesTypeForwarder = NULL); static void EnsureLoaded(TypeHandle typeHnd, ClassLoadLevel level = CLASS_LOADED); - static void TryEnsureLoaded(TypeHandle typeHnd, ClassLoadLevel level = CLASS_LOADED); public: // Look up a class by name @@ -889,24 +883,7 @@ class ClassLoader static void DECLSPEC_NORETURN ThrowTypeLoadException(const TypeKey *pKey, UINT resIDWhy); - - BOOL IsNested(const NameHandle* pName, mdToken *mdEncloser); - static BOOL IsNested(ModuleBase *pModude, mdToken typeDefOrRef, mdToken *mdEncloser); - public: - // Helpers for FindClassModule() - BOOL CompareNestedEntryWithTypeDef(IMDInternalImport *pImport, - mdTypeDef mdCurrent, - EEClassHashTable *pClassHash, - PTR_EEClassHashEntry pEntry); - BOOL CompareNestedEntryWithTypeRef(IMDInternalImport *pImport, - mdTypeRef mdCurrent, - EEClassHashTable *pClassHash, - PTR_EEClassHashEntry pEntry); - BOOL CompareNestedEntryWithExportedType(IMDInternalImport *pImport, - mdExportedType mdCurrent, - EEClassHashTable *pClassHash, - PTR_EEClassHashEntry pEntry); //Attempts to find/load/create a type handle but does not throw // if used in "find" mode. diff --git a/src/coreclr/vm/codeman.cpp b/src/coreclr/vm/codeman.cpp index d019affc33b334..0314a2920f074f 100644 --- a/src/coreclr/vm/codeman.cpp +++ b/src/coreclr/vm/codeman.cpp @@ -2376,6 +2376,16 @@ HeapList* LoaderCodeHeap::CreateCodeHeap(CodeHeapRequestInfo *pInfo, LoaderHeap } else { + // Include internal CodeHeap structures in the reserve + allocationSize = ALIGN_UP(allocationSize, VIRTUAL_ALLOC_RESERVE_GRANULARITY); + reserveSize = max(reserveSize, allocationSize); + + if (reserveSize != (DWORD) reserveSize) + { + _ASSERTE(!"reserveSize does not fit in a DWORD"); + EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE); + } + if (loAddr != NULL || hiAddr != NULL) { #ifdef _DEBUG diff --git a/src/coreclr/vm/comsynchronizable.cpp b/src/coreclr/vm/comsynchronizable.cpp index 73cc949ec66d5c..7f1751aaa15f58 100644 --- a/src/coreclr/vm/comsynchronizable.cpp +++ b/src/coreclr/vm/comsynchronizable.cpp @@ -362,63 +362,17 @@ extern "C" void QCALLTYPE ThreadNative_SetPriority(QCall::ObjectHandleOnStack th END_QCALL; } -FCIMPL1(FC_BOOL_RET, ThreadNative::IsAlive, ThreadBaseObject* pThisUNSAFE) +extern "C" void QCALLTYPE ThreadNative_GetCurrentThread(QCall::ObjectHandleOnStack thread) { - FCALL_CONTRACT; - - if (pThisUNSAFE==NULL) - FCThrowRes(kNullReferenceException, W("NullReference_This")); - - THREADBASEREF thisRef(pThisUNSAFE); - BOOL ret = false; - - // Keep managed Thread object alive, since the native object's - // lifetime is tied to the managed object's finalizer. And with - // resurrection, it may be possible to get a dangling pointer here - - // consider both protecting thisRef and setting the managed object's - // Thread* to NULL in the GC's ScanForFinalization method. - HELPER_METHOD_FRAME_BEGIN_RET_1(thisRef); - - Thread *thread = thisRef->GetInternal(); - - if (thread == 0) - COMPlusThrow(kThreadStateException, IDS_EE_THREAD_CANNOT_GET); - - ret = ThreadIsRunning(thread); - - HELPER_METHOD_POLL(); - HELPER_METHOD_FRAME_END(); - - FC_RETURN_BOOL(ret); -} -FCIMPLEND - -NOINLINE static Object* GetCurrentThreadHelper() -{ - FCALL_CONTRACT; - FC_INNER_PROLOG(ThreadNative::GetCurrentThread); - OBJECTREF refRetVal = NULL; - - HELPER_METHOD_FRAME_BEGIN_RET_ATTRIB_1(Frame::FRAME_ATTR_EXACT_DEPTH|Frame::FRAME_ATTR_CAPTURE_DEPTH_2, refRetVal); - refRetVal = GetThread()->GetExposedObject(); - HELPER_METHOD_FRAME_END(); + QCALL_CONTRACT; - FC_INNER_EPILOG(); - return OBJECTREFToObject(refRetVal); -} + BEGIN_QCALL; -FCIMPL0(Object*, ThreadNative::GetCurrentThread) -{ - FCALL_CONTRACT; - OBJECTHANDLE ExposedObject = GetThread()->m_ExposedObject; - _ASSERTE(ExposedObject != 0); //Thread's constructor always initializes its GCHandle - Object* result = *((Object**) ExposedObject); - if (result != 0) - return result; + GCX_COOP(); + thread.Set(GetThread()->GetExposedObject()); - FC_INNER_RETURN(Object*, GetCurrentThreadHelper()); + END_QCALL; } -FCIMPLEND extern "C" UINT64 QCALLTYPE ThreadNative_GetCurrentOSThreadId() { @@ -442,33 +396,36 @@ extern "C" UINT64 QCALLTYPE ThreadNative_GetCurrentOSThreadId() return threadId; } -FCIMPL1(void, ThreadNative::Initialize, ThreadBaseObject* pThisUNSAFE) +extern "C" void QCALLTYPE ThreadNative_Initialize(QCall::ObjectHandleOnStack t) { - FCALL_CONTRACT; + QCALL_CONTRACT; - THREADBASEREF pThis = (THREADBASEREF) pThisUNSAFE; + BEGIN_QCALL; - HELPER_METHOD_FRAME_BEGIN_1(pThis); + GCX_COOP(); + + THREADBASEREF threadRef = NULL; + GCPROTECT_BEGIN(threadRef) + threadRef = (THREADBASEREF)t.Get(); - _ASSERTE(pThis != NULL); - _ASSERTE(pThis->m_InternalThread == NULL); + _ASSERTE(threadRef != NULL); + _ASSERTE(threadRef->GetInternal() == NULL); // if we don't have an internal Thread object associated with this exposed object, // now is our first opportunity to create one. - Thread *unstarted = SetupUnstartedThread(); - + Thread* unstarted = SetupUnstartedThread(); PREFIX_ASSUME(unstarted != NULL); - pThis->SetInternal(unstarted); - pThis->SetManagedThreadId(unstarted->GetThreadId()); - unstarted->SetExposedObject(pThis); + threadRef->SetInternal(unstarted); + threadRef->SetManagedThreadId(unstarted->GetThreadId()); + unstarted->SetExposedObject(threadRef); // Initialize the thread priority to normal. - pThis->SetPriority(ThreadNative::PRIORITY_NORMAL); + threadRef->SetPriority(ThreadNative::PRIORITY_NORMAL); - HELPER_METHOD_FRAME_END(); + GCPROTECT_END(); + END_QCALL; } -FCIMPLEND // Return whether or not this is a background thread. FCIMPL1(FC_BOOL_RET, ThreadNative::GetIsBackground, ThreadBaseObject* pThisUNSAFE) @@ -489,57 +446,43 @@ FCIMPL1(FC_BOOL_RET, ThreadNative::GetIsBackground, ThreadBaseObject* pThisUNSAF FCIMPLEND // Deliver the state of the thread as a consistent set of bits. -// This copied in VM\EEDbgInterfaceImpl.h's -// CorDebugUserState GetUserState( Thread *pThread ) -// , so propagate changes to both functions -FCIMPL1(INT32, ThreadNative::GetThreadState, ThreadBaseObject* pThisUNSAFE) +// Duplicate logic in DacDbiInterfaceImpl::GetPartialUserState() +extern "C" INT32 QCALLTYPE ThreadNative_GetThreadState(QCall::ThreadHandle thread) { - FCALL_CONTRACT; - - INT32 res = 0; - Thread::ThreadState state; - - if (pThisUNSAFE==NULL) - FCThrowRes(kNullReferenceException, W("NullReference_This")); - - // validate the thread. Failure here implies that the thread was finalized - // and then resurrected. - Thread *thread = pThisUNSAFE->GetInternal(); - - if (!thread) - FCThrowEx(kThreadStateException, IDS_EE_THREAD_CANNOT_GET, NULL, NULL, NULL); + CONTRACTL + { + QCALL_CHECK_NO_GC_TRANSITION; + PRECONDITION(thread != NULL); + } + CONTRACTL_END; - HELPER_METHOD_FRAME_BEGIN_RET_0(); + INT32 res = 0; // grab a snapshot - state = thread->GetSnapshotState(); + Thread::ThreadState state = thread->GetSnapshotState(); if (state & Thread::TS_Background) - res |= ThreadBackground; + res |= ThreadNative::ThreadBackground; if (state & Thread::TS_Unstarted) - res |= ThreadUnstarted; + res |= ThreadNative::ThreadUnstarted; // Don't report a StopRequested if the thread has actually stopped. if (state & Thread::TS_Dead) { - res |= ThreadStopped; + res |= ThreadNative::ThreadStopped; } else { if (state & Thread::TS_AbortRequested) - res |= ThreadAbortRequested; + res |= ThreadNative::ThreadAbortRequested; } if (state & Thread::TS_Interruptible) - res |= ThreadWaitSleepJoin; - - HELPER_METHOD_POLL(); - HELPER_METHOD_FRAME_END(); + res |= ThreadNative::ThreadWaitSleepJoin; return res; } -FCIMPLEND #ifdef FEATURE_COMINTEROP_APARTMENT_SUPPORT @@ -942,16 +885,12 @@ extern "C" void QCALLTYPE ThreadNative_DisableComObjectEagerCleanup(QCall::Threa { CONTRACTL { - QCALL_CHECK; + QCALL_CHECK_NO_GC_TRANSITION; PRECONDITION(thread != NULL); } CONTRACTL_END; - BEGIN_QCALL; - thread->SetDisableComObjectEagerCleanup(); - - END_QCALL; } #endif //FEATURE_COMINTEROP diff --git a/src/coreclr/vm/comsynchronizable.h b/src/coreclr/vm/comsynchronizable.h index 9180216deeea90..b7c64c529084f8 100644 --- a/src/coreclr/vm/comsynchronizable.h +++ b/src/coreclr/vm/comsynchronizable.h @@ -52,13 +52,9 @@ friend class ThreadBaseObject; ThreadAbortRequested = 128, }; - static FCDECL1(FC_BOOL_RET, IsAlive, ThreadBaseObject* pThisUNSAFE); - static FCDECL1(void, Initialize, ThreadBaseObject* pThisUNSAFE); static FCDECL1(FC_BOOL_RET, GetIsBackground, ThreadBaseObject* pThisUNSAFE); - static FCDECL1(INT32, GetThreadState, ThreadBaseObject* pThisUNSAFE); static FCDECL0(INT32, GetOptimalMaxSpinWaitsPerSpinIteration); - static FCDECL0(Object*, GetCurrentThread); static FCDECL1(void, Finalize, ThreadBaseObject* pThis); static FCDECL1(FC_BOOL_RET,IsThreadpoolThread, ThreadBaseObject* thread); static FCDECL1(void, SetIsThreadpoolThread, ThreadBaseObject* thread); @@ -79,10 +75,13 @@ friend class ThreadBaseObject; extern "C" void QCALLTYPE ThreadNative_Start(QCall::ThreadHandle thread, int threadStackSize, int priority, PCWSTR pThreadName); extern "C" void QCALLTYPE ThreadNative_SetPriority(QCall::ObjectHandleOnStack thread, INT32 iPriority); +extern "C" void QCALLTYPE ThreadNative_GetCurrentThread(QCall::ObjectHandleOnStack thread); extern "C" void QCALLTYPE ThreadNative_SetIsBackground(QCall::ThreadHandle thread, BOOL value); extern "C" void QCALLTYPE ThreadNative_InformThreadNameChange(QCall::ThreadHandle thread, LPCWSTR name, INT32 len); extern "C" BOOL QCALLTYPE ThreadNative_YieldThread(); extern "C" UINT64 QCALLTYPE ThreadNative_GetCurrentOSThreadId(); +extern "C" void QCALLTYPE ThreadNative_Initialize(QCall::ObjectHandleOnStack t); +extern "C" INT32 QCALLTYPE ThreadNative_GetThreadState(QCall::ThreadHandle thread); #ifdef FEATURE_COMINTEROP_APARTMENT_SUPPORT extern "C" INT32 QCALLTYPE ThreadNative_GetApartmentState(QCall::ObjectHandleOnStack t); diff --git a/src/coreclr/vm/comwaithandle.cpp b/src/coreclr/vm/comwaithandle.cpp index b43e255068bb50..e80675cc03febf 100644 --- a/src/coreclr/vm/comwaithandle.cpp +++ b/src/coreclr/vm/comwaithandle.cpp @@ -11,106 +11,93 @@ ** ===========================================================*/ #include "common.h" -#include "object.h" -#include "field.h" -#include "excep.h" #include "comwaithandle.h" -FCIMPL3(INT32, WaitHandleNative::CorWaitOneNative, HANDLE handle, INT32 timeout, FC_BOOL_ARG useTrivialWaits) +extern "C" INT32 QCALLTYPE WaitHandle_WaitOneCore(HANDLE handle, INT32 timeout, BOOL useTrivialWaits) { - FCALL_CONTRACT; + QCALL_CONTRACT; INT32 retVal = 0; - HELPER_METHOD_FRAME_BEGIN_RET_0(); + + BEGIN_QCALL; _ASSERTE(handle != 0); _ASSERTE(handle != INVALID_HANDLE_VALUE); Thread* pThread = GET_THREAD(); - - WaitMode waitMode = (WaitMode)((!FC_ACCESS_BOOL(useTrivialWaits) ? WaitMode_Alertable : WaitMode_None) | WaitMode_IgnoreSyncCtx); + WaitMode waitMode = (WaitMode)((!useTrivialWaits ? WaitMode_Alertable : WaitMode_None) | WaitMode_IgnoreSyncCtx); retVal = pThread->DoAppropriateWait(1, &handle, TRUE, timeout, waitMode); - HELPER_METHOD_FRAME_END(); + END_QCALL; return retVal; } -FCIMPLEND -#ifdef TARGET_UNIX -extern "C" INT32 QCALLTYPE WaitHandle_CorWaitOnePrioritizedNative(HANDLE handle, INT32 timeoutMs) +extern "C" INT32 QCALLTYPE WaitHandle_WaitMultipleIgnoringSyncContext(HANDLE *handleArray, INT32 numHandles, BOOL waitForAll, INT32 timeout) { QCALL_CONTRACT; - DWORD result = WAIT_FAILED; - - BEGIN_QCALL; - - _ASSERTE(handle != NULL); - _ASSERTE(handle != INVALID_HANDLE_VALUE); - - result = PAL_WaitForSingleObjectPrioritized(handle, timeoutMs); - - END_QCALL; - return (INT32)result; -} -#endif - -FCIMPL4(INT32, WaitHandleNative::CorWaitMultipleNative, HANDLE *handleArray, INT32 numHandles, FC_BOOL_ARG waitForAll, INT32 timeout) -{ - FCALL_CONTRACT; - INT32 ret = 0; - HELPER_METHOD_FRAME_BEGIN_RET_0(); + BEGIN_QCALL; Thread * pThread = GET_THREAD(); #ifdef FEATURE_COMINTEROP_APARTMENT_SUPPORT // There are some issues with wait-all from an STA thread // - https://github.com/dotnet/runtime/issues/10243#issuecomment-385117537 - if (FC_ACCESS_BOOL(waitForAll) && numHandles > 1 && pThread->GetApartment() == Thread::AS_InSTA) + if (waitForAll && numHandles > 1 && pThread->GetApartment() == Thread::AS_InSTA) { COMPlusThrow(kNotSupportedException, W("NotSupported_WaitAllSTAThread")); } #endif // FEATURE_COMINTEROP_APARTMENT_SUPPORT - ret = pThread->DoAppropriateWait(numHandles, handleArray, FC_ACCESS_BOOL(waitForAll), timeout, (WaitMode)(WaitMode_Alertable | WaitMode_IgnoreSyncCtx)); + ret = pThread->DoAppropriateWait(numHandles, handleArray, waitForAll, timeout, (WaitMode)(WaitMode_Alertable | WaitMode_IgnoreSyncCtx)); - HELPER_METHOD_FRAME_END(); + END_QCALL; return ret; } -FCIMPLEND -FCIMPL3(INT32, WaitHandleNative::CorSignalAndWaitOneNative, HANDLE waitHandleSignalUNSAFE, HANDLE waitHandleWaitUNSAFE, INT32 timeout) +extern "C" INT32 QCALLTYPE WaitHandle_SignalAndWait(HANDLE waitHandleSignal, HANDLE waitHandleWait, INT32 timeout) { - FCALL_CONTRACT; + QCALL_CONTRACT; - INT32 retVal = 0; + INT32 retVal = (DWORD)-1; - HELPER_METHOD_FRAME_BEGIN_RET_0(); + BEGIN_QCALL; - _ASSERTE(waitHandleSignalUNSAFE != 0); - _ASSERTE(waitHandleWaitUNSAFE != 0); + _ASSERTE(waitHandleSignal != 0); + _ASSERTE(waitHandleWait != 0); Thread* pThread = GET_THREAD(); -#ifdef FEATURE_COMINTEROP - if (pThread->GetApartment() == Thread::AS_InSTA) { - COMPlusThrow(kNotSupportedException, W("NotSupported_SignalAndWaitSTAThread")); // Change this message - } -#endif - - DWORD res = (DWORD) -1; - - HANDLE handles[2]; - handles[0] = waitHandleSignalUNSAFE; - handles[1] = waitHandleWaitUNSAFE; +#ifdef FEATURE_COMINTEROP_APARTMENT_SUPPORT + if (pThread->GetApartment() == Thread::AS_InSTA) { - res = pThread->DoSignalAndWait(handles, timeout, TRUE /*alertable*/); + COMPlusThrow(kNotSupportedException, W("NotSupported_SignalAndWaitSTAThread")); } +#endif // FEATURE_COMINTEROP_APARTMENT_SUPPORT - retVal = res; + HANDLE handles[] = { waitHandleSignal, waitHandleWait }; + retVal = pThread->DoSignalAndWait(handles, timeout, TRUE /*alertable*/); - HELPER_METHOD_FRAME_END(); + END_QCALL; return retVal; } -FCIMPLEND + +#ifdef TARGET_UNIX +extern "C" INT32 QCALLTYPE WaitHandle_WaitOnePrioritized(HANDLE handle, INT32 timeoutMs) +{ + QCALL_CONTRACT; + + DWORD result = WAIT_FAILED; + + BEGIN_QCALL; + + _ASSERTE(handle != NULL); + _ASSERTE(handle != INVALID_HANDLE_VALUE); + + result = PAL_WaitForSingleObjectPrioritized(handle, timeoutMs); + + END_QCALL; + return (INT32)result; +} +#endif // TARGET_UNIX diff --git a/src/coreclr/vm/comwaithandle.h b/src/coreclr/vm/comwaithandle.h index d0af3076bf1c42..ac605389129138 100644 --- a/src/coreclr/vm/comwaithandle.h +++ b/src/coreclr/vm/comwaithandle.h @@ -14,15 +14,12 @@ #ifndef _COM_WAITABLE_HANDLE_H #define _COM_WAITABLE_HANDLE_H +extern "C" INT32 QCALLTYPE WaitHandle_WaitOneCore(HANDLE handle, INT32 timeout, BOOL useTrivialWaits); +extern "C" INT32 QCALLTYPE WaitHandle_WaitMultipleIgnoringSyncContext(HANDLE *handleArray, INT32 numHandles, BOOL waitForAll, INT32 timeout); +extern "C" INT32 QCALLTYPE WaitHandle_SignalAndWait(HANDLE waitHandleSignal, HANDLE waitHandleWait, INT32 timeout); -class WaitHandleNative -{ -public: - static FCDECL3(INT32, CorWaitOneNative, HANDLE handle, INT32 timeout, FC_BOOL_ARG useTrivialWaits); - static FCDECL4(INT32, CorWaitMultipleNative, HANDLE *handleArray, INT32 numHandles, FC_BOOL_ARG waitForAll, INT32 timeout); - static FCDECL3(INT32, CorSignalAndWaitOneNative, HANDLE waitHandleSignalUNSAFE, HANDLE waitHandleWaitUNSAFE, INT32 timeout); -}; #ifdef TARGET_UNIX -extern "C" INT32 QCALLTYPE WaitHandle_CorWaitOnePrioritizedNative(HANDLE handle, INT32 timeoutMs); -#endif -#endif +extern "C" INT32 QCALLTYPE WaitHandle_WaitOnePrioritized(HANDLE handle, INT32 timeoutMs); +#endif // TARGET_UNIX + +#endif // _COM_WAITABLE_HANDLE_H diff --git a/src/coreclr/vm/corhost.cpp b/src/coreclr/vm/corhost.cpp index 35c724e10a9caf..990eb02b00dc86 100644 --- a/src/coreclr/vm/corhost.cpp +++ b/src/coreclr/vm/corhost.cpp @@ -559,11 +559,11 @@ HRESULT CorHost2::CreateAppDomainWithManager( BEGIN_EXTERNAL_ENTRYPOINT(&hr); - AppDomain* pDomain = SystemDomain::System()->DefaultDomain(); + AppDomain* pDomain = AppDomain::GetCurrentDomain(); pDomain->SetFriendlyName(wszFriendlyName); - ETW::LoaderLog::DomainLoad(pDomain, (LPWSTR)wszFriendlyName); + ETW::LoaderLog::DomainLoad((LPWSTR)wszFriendlyName); if (dwFlags & APPDOMAIN_IGNORE_UNHANDLED_EXCEPTIONS) pDomain->SetIgnoreUnhandledExceptions(); diff --git a/src/coreclr/vm/domainassembly.cpp b/src/coreclr/vm/domainassembly.cpp index 58272366971660..64fb98569f10f8 100644 --- a/src/coreclr/vm/domainassembly.cpp +++ b/src/coreclr/vm/domainassembly.cpp @@ -56,7 +56,6 @@ DomainAssembly::DomainAssembly(PEAssembly* pPEAssembly, LoaderAllocator* pLoader // Create the Assembly NewHolder assembly = Assembly::Create(GetPEAssembly(), GetDebuggerInfoBits(), IsCollectible(), memTracker, IsCollectible() ? GetLoaderAllocator() : NULL); - assembly->SetIsTenured(); m_pAssembly = assembly.Extract(); m_pModule = m_pAssembly->GetModule(); diff --git a/src/coreclr/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h index 2b065fd3380341..b1f475b3b16406 100644 --- a/src/coreclr/vm/ecalllist.h +++ b/src/coreclr/vm/ecalllist.h @@ -109,8 +109,8 @@ FCFuncStart(gCOMTypeHandleFuncs) FCFuncElement("GetFirstIntroducedMethod", RuntimeTypeHandle::GetFirstIntroducedMethod) FCFuncElement("GetNextIntroducedMethod", RuntimeTypeHandle::GetNextIntroducedMethod) FCFuncElement("GetCorElementType", RuntimeTypeHandle::GetCorElementType) - FCFuncElement("GetAssembly", RuntimeTypeHandle::GetAssembly) - FCFuncElement("GetModule", RuntimeTypeHandle::GetModule) + FCFuncElement("GetAssemblyIfExists", RuntimeTypeHandle::GetAssemblyIfExists) + FCFuncElement("GetModuleIfExists", RuntimeTypeHandle::GetModuleIfExists) FCFuncElement("GetBaseType", RuntimeTypeHandle::GetBaseType) FCFuncElement("GetElementType", RuntimeTypeHandle::GetElementType) FCFuncElement("GetArrayRank", RuntimeTypeHandle::GetArrayRank) @@ -222,7 +222,7 @@ FCFuncStart(gCOMModuleHandleFuncs) FCFuncEnd() FCFuncStart(gRuntimeAssemblyFuncs) - FCFuncElement("FCallIsDynamic", AssemblyNative::IsDynamic) + FCFuncElement("GetIsDynamic", AssemblyNative::GetIsDynamic) FCFuncElement("GetManifestModule", AssemblyHandle::GetManifestModule) FCFuncElement("GetToken", AssemblyHandle::GetToken) FCFuncEnd() @@ -298,14 +298,10 @@ FCFuncStart(gMathFFuncs) FCFuncEnd() FCFuncStart(gThreadFuncs) - FCFuncElement("Initialize", ThreadNative::Initialize) - FCFuncElement("GetCurrentThreadNative", ThreadNative::GetCurrentThread) FCFuncElement("InternalFinalize", ThreadNative::Finalize) - FCFuncElement("get_IsAlive", ThreadNative::IsAlive) FCFuncElement("GetIsBackground", ThreadNative::GetIsBackground) FCFuncElement("get_IsThreadPoolThread", ThreadNative::IsThreadpoolThread) FCFuncElement("set_IsThreadPoolThread", ThreadNative::SetIsThreadpoolThread) - FCFuncElement("GetThreadStateNative", ThreadNative::GetThreadState) FCFuncElement("get_OptimalMaxSpinWaitsPerSpinIteration", ThreadNative::GetOptimalMaxSpinWaitsPerSpinIteration) FCFuncEnd() @@ -313,12 +309,6 @@ FCFuncStart(gThreadPoolFuncs) FCFuncElement("GetNextConfigUInt32Value", ThreadPoolNative::GetNextConfigUInt32Value) FCFuncEnd() -FCFuncStart(gWaitHandleFuncs) - FCFuncElement("WaitOneCore", WaitHandleNative::CorWaitOneNative) - FCFuncElement("WaitMultipleIgnoringSyncContext", WaitHandleNative::CorWaitMultipleNative) - FCFuncElement("SignalAndWaitNative", WaitHandleNative::CorSignalAndWaitOneNative) -FCFuncEnd() - FCFuncStart(gCastHelpers) FCFuncElement("IsInstanceOfAny_NoCacheLookup", ::IsInstanceOfAny_NoCacheLookup) FCFuncElement("ChkCastAny_NoCacheLookup", ::ChkCastAny_NoCacheLookup) @@ -493,7 +483,6 @@ FCClassElement("Thread", "System.Threading", gThreadFuncs) FCClassElement("ThreadPool", "System.Threading", gThreadPoolFuncs) FCClassElement("Type", "System", gSystem_Type) FCClassElement("TypedReference", "System", gTypedReferenceFuncs) -FCClassElement("WaitHandle", "System.Threading", gWaitHandleFuncs) #undef FCFuncElement #undef FCFuncElementSig diff --git a/src/coreclr/vm/eventtrace.cpp b/src/coreclr/vm/eventtrace.cpp index 79c3043a249640..4f563dd5b2744e 100644 --- a/src/coreclr/vm/eventtrace.cpp +++ b/src/coreclr/vm/eventtrace.cpp @@ -1926,7 +1926,7 @@ VOID ETW::EnumerationLog::ModuleRangeRundown() TRACE_LEVEL_INFORMATION, CLR_PERFTRACK_PRIVATE_KEYWORD)) { - ETW::EnumerationLog::EnumerationHelper(NULL, NULL, ETW::EnumerationLog::EnumerationStructs::ModuleRangeLoadPrivate); + ETW::EnumerationLog::EnumerationHelper(NULL, ETW::EnumerationLog::EnumerationStructs::ModuleRangeLoadPrivate); } } EX_CATCH { } EX_END_CATCH(SwallowAllExceptions); } @@ -2037,7 +2037,7 @@ VOID ETW::EnumerationLog::StartRundown() enumerationOptions |= ETW::EnumerationLog::EnumerationStructs::JittedMethodRichDebugInfo; } - ETW::EnumerationLog::EnumerationHelper(NULL, NULL, enumerationOptions); + ETW::EnumerationLog::EnumerationHelper(NULL, enumerationOptions); if (bIsThreadingRundownEnabled) { @@ -2124,9 +2124,8 @@ VOID ETW::EnumerationLog::EnumerateForCaptureState() { DWORD enumerationOptions = GetEnumerationOptionsFromRuntimeKeywords(); - // Send unload events for all remaining domains, including shared domain and - // default domain. - ETW::EnumerationLog::EnumerationHelper(NULL /* module filter */, NULL /* domain filter */, enumerationOptions); + // Send unload events for all remaining modules + ETW::EnumerationLog::EnumerationHelper(NULL /* module filter */, enumerationOptions); // Send thread created events for all currently active threads, if requested if (ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_DOTNET_Context, @@ -2227,7 +2226,7 @@ VOID ETW::EnumerationLog::EndRundown() enumerationOptions |= ETW::EnumerationLog::EnumerationStructs::JittedMethodRichDebugInfo; } - ETW::EnumerationLog::EnumerationHelper(NULL, NULL, enumerationOptions); + ETW::EnumerationLog::EnumerationHelper(NULL, enumerationOptions); if (bIsThreadingRundownEnabled) { @@ -2964,7 +2963,7 @@ VOID ETW::ExceptionLog::ExceptionFilterEnd() /****************************************************************************/ /* This is called by the runtime when a domain is loaded */ /****************************************************************************/ -VOID ETW::LoaderLog::DomainLoadReal(BaseDomain *pDomain, _In_opt_ LPWSTR wszFriendlyName) +VOID ETW::LoaderLog::DomainLoadReal(_In_opt_ LPWSTR wszFriendlyName) { CONTRACTL { NOTHROW; @@ -2978,7 +2977,7 @@ VOID ETW::LoaderLog::DomainLoadReal(BaseDomain *pDomain, _In_opt_ LPWSTR wszFrie CLR_LOADER_KEYWORD)) { DWORD dwEventOptions = ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleLoad; - ETW::LoaderLog::SendDomainEvent(pDomain, dwEventOptions, wszFriendlyName); + ETW::LoaderLog::SendDomainEvent(dwEventOptions, wszFriendlyName); } } EX_CATCH { } EX_END_CATCH(SwallowAllExceptions); } @@ -2986,7 +2985,7 @@ VOID ETW::LoaderLog::DomainLoadReal(BaseDomain *pDomain, _In_opt_ LPWSTR wszFrie /****************************************************************************/ /* This is called by the runtime when an AppDomain is unloaded */ /****************************************************************************/ -VOID ETW::LoaderLog::DomainUnload(AppDomain *pDomain) +VOID ETW::LoaderLog::DomainUnload() { CONTRACTL { NOTHROW; @@ -3009,7 +3008,7 @@ VOID ETW::LoaderLog::DomainUnload(AppDomain *pDomain) enumerationOptions |= ETW::EnumerationLog::EnumerationStructs::TypeUnload; } - ETW::EnumerationLog::EnumerationHelper(NULL, pDomain, enumerationOptions); + ETW::EnumerationLog::EnumerationHelper(NULL, enumerationOptions); } } EX_CATCH { } EX_END_CATCH(SwallowAllExceptions); } @@ -3873,7 +3872,7 @@ VOID ETW::LoaderLog::ModuleLoad(Module *pModule, LONG liReportedSharedModule) if(bTraceFlagLoaderSet || bTraceFlagPerfTrackSet) ETW::LoaderLog::SendModuleEvent(pModule, ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleLoad | ETW::EnumerationLog::EnumerationStructs::ModuleRangeLoad); - ETW::EnumerationLog::EnumerationHelper(pModule, NULL, enumerationOptions); + ETW::EnumerationLog::EnumerationHelper(pModule, enumerationOptions); } // we want to report domainmodule events whenever they are loaded in any AppDomain @@ -3910,9 +3909,8 @@ VOID ETW::EnumerationLog::ProcessShutdown() { DWORD enumerationOptions = GetEnumerationOptionsFromRuntimeKeywords(); - // Send unload events for all remaining domains, including shared domain and - // default domain. - ETW::EnumerationLog::EnumerationHelper(NULL /* module filter */, NULL /* domain filter */, enumerationOptions); + // Send unload events for all remaining modules + ETW::EnumerationLog::EnumerationHelper(NULL /* module filter */, enumerationOptions); } } EX_CATCH { } EX_END_CATCH(SwallowAllExceptions); } @@ -3926,20 +3924,20 @@ VOID ETW::EnumerationLog::ProcessShutdown() /****************************************************************************/ /* This routine is used to send a domain load/unload or rundown event */ /****************************************************************************/ -VOID ETW::LoaderLog::SendDomainEvent(BaseDomain *pBaseDomain, DWORD dwEventOptions, LPCWSTR wszFriendlyName) +VOID ETW::LoaderLog::SendDomainEvent(DWORD dwEventOptions, LPCWSTR wszFriendlyName) { CONTRACTL { THROWS; GC_TRIGGERS; + PRECONDITION(AppDomain::GetCurrentDomain() != NULL); } CONTRACTL_END; - if(!pBaseDomain) - return; + AppDomain* pDomain = AppDomain::GetCurrentDomain(); PCWSTR szDtraceOutput1=W(""); - BOOL bIsAppDomain = pBaseDomain->IsAppDomain(); + BOOL bIsAppDomain = TRUE; - ULONGLONG ullDomainId = (ULONGLONG)pBaseDomain; + ULONGLONG ullDomainId = (ULONGLONG)pDomain; ULONG ulDomainFlags = ETW::LoaderLog::LoaderStructs::DefaultDomain | ETW::LoaderLog::LoaderStructs::ExecutableDomain; LPCWSTR wsEmptyString = W(""); @@ -3949,7 +3947,7 @@ VOID ETW::LoaderLog::SendDomainEvent(BaseDomain *pBaseDomain, DWORD dwEventOptio if(wszFriendlyName) lpswzDomainName = (PWCHAR)wszFriendlyName; else - lpswzDomainName = (PWCHAR)pBaseDomain->AsAppDomain()->GetFriendlyName(); + lpswzDomainName = (PWCHAR)pDomain->GetFriendlyName(); /* prepare events args for ETW and ETM */ szDtraceOutput1 = (PCWSTR)lpswzDomainName; @@ -5238,12 +5236,9 @@ VOID ETW::MethodLog::SendEventsForJitMethodsHelper(LoaderAllocator *pLoaderAlloc /****************************************************************************/ /* This routine sends back method events of type 'dwEventOptions', for all JITed methods in either a given LoaderAllocator (if pLoaderAllocatorFilter is non NULL) - or in a given Domain (if pDomainFilter is non NULL) or for - all methods (if both filters are null) */ + or all methods (if pLoaderAllocatorFilter is null) */ /****************************************************************************/ -// Code review indicates this method is never called with both filters NULL. Ideally we would -// assert this and change the comment above, but given I am making a change late in the release I am being cautious -VOID ETW::MethodLog::SendEventsForJitMethods(BaseDomain *pDomainFilter, LoaderAllocator *pLoaderAllocatorFilter, DWORD dwEventOptions) +VOID ETW::MethodLog::SendEventsForJitMethods(BOOL getCodeVersionIds, LoaderAllocator *pLoaderAllocatorFilter, DWORD dwEventOptions) { CONTRACTL { NOTHROW; @@ -5303,9 +5298,8 @@ VOID ETW::MethodLog::SendEventsForJitMethods(BaseDomain *pDomainFilter, LoaderAl // table lock that corresponds to the domain or module we're currently iterating over. // - // We only support getting rejit IDs when filtering by domain. #ifdef FEATURE_CODE_VERSIONING - if (pDomainFilter) + if (getCodeVersionIds) { CodeVersionManager::LockHolder codeVersioningLockHolder; SendEventsForJitMethodsHelper( @@ -5337,21 +5331,24 @@ VOID ETW::MethodLog::SendEventsForJitMethods(BaseDomain *pDomainFilter, LoaderAl //--------------------------------------------------------------------------------------- // -// Wrapper around IterateDomain, which locks the AppDomain to be < -// STAGE_FINALIZED until the iteration is complete. +// This routine fires ETW events for +// Domain +// Assemblies in them +// Modules in them +// JIT methods in them +// R2R methods in them +// based on enumeration options // // Arguments: -// pAppDomain - AppDomain to iterate -// enumerationOptions - Flags indicating what to enumerate. Just passed -// straight through to IterateDomain +// enumerationOptions - Flags indicating what to enumerate. // -VOID ETW::EnumerationLog::IterateAppDomain(AppDomain * pAppDomain, DWORD enumerationOptions) +VOID ETW::EnumerationLog::IterateAppDomain(DWORD enumerationOptions) { CONTRACTL { THROWS; GC_TRIGGERS; - PRECONDITION(pAppDomain != NULL); + PRECONDITION(AppDomain::GetCurrentDomain() != NULL); } CONTRACTL_END; @@ -5359,54 +5356,22 @@ VOID ETW::EnumerationLog::IterateAppDomain(AppDomain * pAppDomain, DWORD enumera // ensure the App Domain does not get finalized until we're all done SystemDomain::LockHolder lh; - // Now it's safe to do the iteration - IterateDomain(pAppDomain, enumerationOptions); -} - -/********************************************************************************/ -/* This routine fires ETW events for - Domain, - Assemblies in them, - DomainModule's in them, - Modules in them, - JIT methods in them, - and the NGEN methods in them - based on enumerationOptions.*/ -/********************************************************************************/ -VOID ETW::EnumerationLog::IterateDomain(BaseDomain *pDomain, DWORD enumerationOptions) -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - PRECONDITION(pDomain != NULL); - } CONTRACTL_END; - -#if defined(_DEBUG) && !defined(DACCESS_COMPILE) - // Do not call IterateDomain() directly with an AppDomain. Use - // IterateAppDomain(), which wraps this function with a hold on the - // SystemDomain lock, which ensures pDomain's type data doesn't disappear - // on us. - if (pDomain->IsAppDomain()) - { - _ASSERTE(SystemDomain::IsUnderDomainLock()); - } -#endif // defined(_DEBUG) && !defined(DACCESS_COMPILE) - + AppDomain* pDomain = AppDomain::GetCurrentDomain(); EX_TRY { // DC Start events for Domain if(enumerationOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleDCStart) { - ETW::LoaderLog::SendDomainEvent(pDomain, enumerationOptions); + ETW::LoaderLog::SendDomainEvent(enumerationOptions); } // DC End or Unload Jit Method events if (enumerationOptions & ETW::EnumerationLog::EnumerationStructs::JitMethodUnloadOrDCEndAny) { - ETW::MethodLog::SendEventsForJitMethods(pDomain, NULL, enumerationOptions); + ETW::MethodLog::SendEventsForJitMethods(TRUE /*getCodeVersionIds*/, NULL, enumerationOptions); } - AppDomain::AssemblyIterator assemblyIterator = pDomain->AsAppDomain()->IterateAssembliesEx( + AppDomain::AssemblyIterator assemblyIterator = pDomain->IterateAssembliesEx( (AssemblyIterationFlags)(kIncludeLoaded | kIncludeExecution)); CollectibleAssemblyHolder pDomainAssembly; while (assemblyIterator.Next(pDomainAssembly.This())) @@ -5430,14 +5395,14 @@ VOID ETW::EnumerationLog::IterateDomain(BaseDomain *pDomain, DWORD enumerationOp // DC Start or Load Jit Method events if (enumerationOptions & ETW::EnumerationLog::EnumerationStructs::JitMethodLoadOrDCStartAny) { - ETW::MethodLog::SendEventsForJitMethods(pDomain, NULL, enumerationOptions); + ETW::MethodLog::SendEventsForJitMethods(TRUE /*getCodeVersionIds*/, NULL, enumerationOptions); } // DC End or Unload events for Domain if((enumerationOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleDCEnd) || (enumerationOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleUnload)) { - ETW::LoaderLog::SendDomainEvent(pDomain, enumerationOptions); + ETW::LoaderLog::SendDomainEvent(enumerationOptions); } } EX_CATCH { } EX_END_CATCH(SwallowAllExceptions); } @@ -5465,7 +5430,7 @@ VOID ETW::EnumerationLog::IterateCollectibleLoaderAllocator(AssemblyLoaderAlloca // Unload Jit Method events if (enumerationOptions & ETW::EnumerationLog::EnumerationStructs::JitMethodUnload) { - ETW::MethodLog::SendEventsForJitMethods(NULL, pLoaderAllocator, enumerationOptions); + ETW::MethodLog::SendEventsForJitMethods(FALSE /*getCodeVersionIds*/, pLoaderAllocator, enumerationOptions); } // Iterate on all DomainAssembly loaded from the same AssemblyLoaderAllocator @@ -5488,7 +5453,7 @@ VOID ETW::EnumerationLog::IterateCollectibleLoaderAllocator(AssemblyLoaderAlloca // Load Jit Method events if (enumerationOptions & ETW::EnumerationLog::EnumerationStructs::JitMethodLoad) { - ETW::MethodLog::SendEventsForJitMethods(NULL, pLoaderAllocator, enumerationOptions); + ETW::MethodLog::SendEventsForJitMethods(FALSE /*getCodeVersionIds*/, pLoaderAllocator, enumerationOptions); } } EX_CATCH { } EX_END_CATCH(SwallowAllExceptions); } @@ -5593,17 +5558,12 @@ VOID ETW::EnumerationLog::IterateModule(Module *pModule, DWORD enumerationOption // // Arguments: // * moduleFilter - if non-NULL, events from only moduleFilter module are reported -// * domainFilter - if non-NULL, events from only domainFilter domain are reported // * enumerationOptions - Flags from ETW::EnumerationLog::EnumerationStructs which // describe which events should be sent. // -// Notes: -// * if all filter args are NULL, events from all domains are reported -// -// // static -VOID ETW::EnumerationLog::EnumerationHelper(Module *moduleFilter, BaseDomain *domainFilter, DWORD enumerationOptions) +VOID ETW::EnumerationLog::EnumerationHelper(Module *moduleFilter, DWORD enumerationOptions) { CONTRACTL { THROWS; @@ -5625,36 +5585,18 @@ VOID ETW::EnumerationLog::EnumerationHelper(Module *moduleFilter, BaseDomain *do // DC End or Unload Jit Method events from all Domains if (enumerationOptions & ETW::EnumerationLog::EnumerationStructs::JitMethodUnloadOrDCEndAny) { - ETW::MethodLog::SendEventsForJitMethods(NULL, NULL, enumerationOptions); + ETW::MethodLog::SendEventsForJitMethods(FALSE /*getCodeVersionIds*/, NULL, enumerationOptions); } // DC Start or Load Jit Method events from all Domains if (enumerationOptions & ETW::EnumerationLog::EnumerationStructs::JitMethodLoadOrDCStartAny) { - ETW::MethodLog::SendEventsForJitMethods(NULL, NULL, enumerationOptions); + ETW::MethodLog::SendEventsForJitMethods(FALSE /*getCodeVersionIds*/, NULL, enumerationOptions); } } else { - if(domainFilter) - { - if(domainFilter->IsAppDomain()) - { - ETW::EnumerationLog::IterateAppDomain(domainFilter->AsAppDomain(), enumerationOptions); - } - else - { - ETW::EnumerationLog::IterateDomain(domainFilter, enumerationOptions); - } - } - else - { - AppDomain *pDomain = AppDomain::GetCurrentDomain(); - if (pDomain != NULL) - { - ETW::EnumerationLog::IterateAppDomain(pDomain, enumerationOptions); - } - } + ETW::EnumerationLog::IterateAppDomain(enumerationOptions); } } diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index b9d260cfe78308..9e265926481706 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -3476,49 +3476,7 @@ size_t CEEInfo::printClassName(CORINFO_CLASS_HANDLE cls, char* buffer, size_t bu } /*********************************************************************/ -CORINFO_MODULE_HANDLE CEEInfo::getClassModule(CORINFO_CLASS_HANDLE clsHnd) -{ - CONTRACTL { - NOTHROW; - GC_NOTRIGGER; - MODE_PREEMPTIVE; - } CONTRACTL_END; - - CORINFO_MODULE_HANDLE result = NULL; - - JIT_TO_EE_TRANSITION_LEAF(); - - TypeHandle VMClsHnd(clsHnd); - - result = CORINFO_MODULE_HANDLE(VMClsHnd.GetModule()); - - EE_TO_JIT_TRANSITION_LEAF(); - - return result; -} - -/*********************************************************************/ -CORINFO_ASSEMBLY_HANDLE CEEInfo::getModuleAssembly(CORINFO_MODULE_HANDLE modHnd) -{ - CONTRACTL { - NOTHROW; - GC_NOTRIGGER; - MODE_PREEMPTIVE; - } CONTRACTL_END; - - CORINFO_ASSEMBLY_HANDLE result = NULL; - - JIT_TO_EE_TRANSITION_LEAF(); - - result = CORINFO_ASSEMBLY_HANDLE(GetModule(modHnd)->GetAssembly()); - - EE_TO_JIT_TRANSITION_LEAF(); - - return result; -} - -/*********************************************************************/ -const char* CEEInfo::getAssemblyName(CORINFO_ASSEMBLY_HANDLE asmHnd) +const char* CEEInfo::getClassAssemblyName(CORINFO_CLASS_HANDLE clsHnd) { CONTRACTL { THROWS; @@ -3526,10 +3484,11 @@ const char* CEEInfo::getAssemblyName(CORINFO_ASSEMBLY_HANDLE asmHnd) MODE_PREEMPTIVE; } CONTRACTL_END; - const char* result = NULL; + const char* result = NULL; JIT_TO_EE_TRANSITION(); - result = ((Assembly*)asmHnd)->GetSimpleName(); + TypeHandle th(clsHnd); + result = th.GetAssembly()->GetSimpleName(); EE_TO_JIT_TRANSITION(); return result; diff --git a/src/coreclr/vm/loaderallocator.cpp b/src/coreclr/vm/loaderallocator.cpp index ff6506b76292a6..dde9db0f76a003 100644 --- a/src/coreclr/vm/loaderallocator.cpp +++ b/src/coreclr/vm/loaderallocator.cpp @@ -62,7 +62,6 @@ LoaderAllocator::LoaderAllocator(bool collectible) : m_fUnloaded = false; m_fMarked = false; m_pLoaderAllocatorDestroyNext = NULL; - m_pDomain = NULL; m_pCodeHeapInitialAlloc = NULL; m_pVSDHeapInitialAlloc = NULL; m_pLastUsedCodeHeap = NULL; @@ -506,13 +505,16 @@ void LoaderAllocator::GCLoaderAllocators(LoaderAllocator* pOriginalLoaderAllocat THROWS; GC_TRIGGERS; MODE_PREEMPTIVE; + PRECONDITION(pOriginalLoaderAllocator != NULL); + PRECONDITION(pOriginalLoaderAllocator->IsCollectible()); + PRECONDITION(pOriginalLoaderAllocator->Id()->GetType() == LAT_Assembly); } CONTRACTL_END; // List of LoaderAllocators being deleted LoaderAllocator * pFirstDestroyedLoaderAllocator = NULL; - AppDomain* pAppDomain = (AppDomain*)pOriginalLoaderAllocator->GetDomain(); + AppDomain* pAppDomain = AppDomain::GetCurrentDomain(); // Collect all LoaderAllocators that don't have anymore DomainAssemblies alive // Note: that it may not collect our pOriginalLoaderAllocator in case this @@ -1059,12 +1061,10 @@ void LoaderAllocator::ActivateManagedTracking() #define COLLECTIBLE_CODEHEAP_SIZE (10 * GetOsPageSize()) #define COLLECTIBLE_VIRTUALSTUBDISPATCH_HEAP_SPACE (2 * GetOsPageSize()) -void LoaderAllocator::Init(BaseDomain *pDomain, BYTE *pExecutableHeapMemory) +void LoaderAllocator::Init(BYTE *pExecutableHeapMemory) { STANDARD_VM_CONTRACT; - m_pDomain = pDomain; - m_crstLoaderAllocator.Init(CrstLoaderAllocator, (CrstFlags)CRST_UNSAFE_COOPGC); m_crstLoaderAllocatorHandleTable.Init(CrstLeafLock, (CrstFlags)CRST_UNSAFE_COOPGC); m_InteropDataCrst.Init(CrstInteropData, CRST_REENTRANCY); @@ -1446,7 +1446,6 @@ void LoaderAllocator::Terminate() m_pFuncPtrStubs = NULL; } - // This was the block reserved by BaseDomain::Init for the loaderheaps. if (m_InitialReservedMemForLoaderHeaps) { ExecutableAllocator::Instance()->Release(m_InitialReservedMemForLoaderHeaps); @@ -1725,7 +1724,7 @@ void DomainAssemblyIterator::operator++() #ifndef DACCESS_COMPILE -void AssemblyLoaderAllocator::Init(AppDomain* pAppDomain) +void AssemblyLoaderAllocator::Init() { m_Id.Init(); @@ -1733,7 +1732,7 @@ void AssemblyLoaderAllocator::Init(AppDomain* pAppDomain) // GC mode, in case the caller requires that m_dependentHandleToNativeObjectSetCrst.Init(CrstLeafLock, CRST_UNSAFE_ANYMODE); - LoaderAllocator::Init((BaseDomain *)pAppDomain); + LoaderAllocator::Init(NULL /*pExecutableHeapMemory*/); if (IsCollectible()) { // TODO: the ShuffleThunkCache should really be using the m_pStubHeap, however the unloadability support @@ -1933,10 +1932,11 @@ void AssemblyLoaderAllocator::CleanupHandles() NOTHROW; MODE_ANY; CAN_TAKE_LOCK; + PRECONDITION(IsCollectible()); + PRECONDITION(Id()->GetType() == LAT_Assembly); } CONTRACTL_END; - _ASSERTE(GetDomain()->IsAppDomain()); if (m_hLoaderAllocatorObjectHandle != NULL) { @@ -2058,12 +2058,12 @@ void LoaderAllocator::CleanupFailedTypeInit() return; } - _ASSERTE(GetDomain()->IsAppDomain()); + _ASSERTE(Id()->GetType() == LAT_Assembly); // This method doesn't take a lock around loader allocator state access, because // it's supposed to be called only during cleanup. However, the domain-level state // might be accessed by multiple threads. - ListLock *pLock = ((AppDomain*)GetDomain())->GetClassInitLock(); + ListLock *pLock = AppDomain::GetCurrentDomain()->GetClassInitLock(); while (!m_failedTypeInitCleanupList.IsEmpty()) { diff --git a/src/coreclr/vm/loaderallocator.hpp b/src/coreclr/vm/loaderallocator.hpp index 82f24813cb8d1a..2bce73a85cc241 100644 --- a/src/coreclr/vm/loaderallocator.hpp +++ b/src/coreclr/vm/loaderallocator.hpp @@ -264,6 +264,8 @@ class SegmentedHandleIndexStack public: + ~SegmentedHandleIndexStack(); + // Push the value to the stack. If the push cannot be done due to OOM, return false; inline bool Push(DWORD value); @@ -360,8 +362,6 @@ class LoaderAllocator BYTE *GetVSDHeapInitialBlock(DWORD *pSize); BYTE *GetCodeHeapInitialBlock(const BYTE * loAddr, const BYTE * hiAddr, DWORD minimumSize, DWORD *pSize); - BaseDomain *m_pDomain; - // ExecutionManager caches void * m_pLastUsedCodeHeap; void * m_pLastUsedDynamicCodeHeap; @@ -735,9 +735,8 @@ class LoaderAllocator LoaderAllocator(bool collectible); virtual ~LoaderAllocator(); - BaseDomain *GetDomain() { LIMITED_METHOD_CONTRACT; return m_pDomain; } virtual BOOL CanUnload() = 0; - void Init(BaseDomain *pDomain, BYTE *pExecutableHeapMemory = NULL); + void Init(BYTE *pExecutableHeapMemory); void Terminate(); virtual void ReleaseManagedAssemblyLoadContext() {} @@ -887,7 +886,7 @@ class GlobalLoaderAllocator : public LoaderAllocator LoaderAllocatorID m_Id; public: - void Init(BaseDomain *pDomain); + void Init(); GlobalLoaderAllocator() : LoaderAllocator(false), m_Id(LAT_Global, (void*)1) { LIMITED_METHOD_CONTRACT;}; virtual LoaderAllocatorID* Id(); virtual BOOL CanUnload(); @@ -913,7 +912,7 @@ class AssemblyLoaderAllocator : public LoaderAllocator , m_binderToRelease(NULL) #endif { LIMITED_METHOD_CONTRACT; } - void Init(AppDomain *pAppDomain); + void Init(); virtual BOOL CanUnload(); void AddDomainAssembly(DomainAssembly *pDomainAssembly) diff --git a/src/coreclr/vm/loaderallocator.inl b/src/coreclr/vm/loaderallocator.inl index d839a4632277f5..374e19902fd329 100644 --- a/src/coreclr/vm/loaderallocator.inl +++ b/src/coreclr/vm/loaderallocator.inl @@ -24,9 +24,9 @@ inline bool LoaderAllocator::IsExposedObjectLive() return !ObjectHandleIsNull(m_hLoaderAllocatorObjectHandle); } -inline void GlobalLoaderAllocator::Init(BaseDomain *pDomain) +inline void GlobalLoaderAllocator::Init() { - LoaderAllocator::Init(pDomain, m_ExecutableHeapInstance); + LoaderAllocator::Init(m_ExecutableHeapInstance); } inline BOOL LoaderAllocatorID::Equals(LoaderAllocatorID *pId) @@ -208,6 +208,19 @@ inline DWORD SegmentedHandleIndexStack::Pop() return m_TOSSegment->m_data[--m_TOSIndex]; } +inline SegmentedHandleIndexStack::~SegmentedHandleIndexStack() +{ + LIMITED_METHOD_CONTRACT; + + while (m_TOSSegment != NULL) + { + Segment* prevSegment = m_TOSSegment->m_prev; + delete m_TOSSegment; + m_TOSSegment = prevSegment; + } + m_freeSegment = NULL; +} + inline bool SegmentedHandleIndexStack::IsEmpty() { LIMITED_METHOD_CONTRACT; diff --git a/src/coreclr/vm/object.h b/src/coreclr/vm/object.h index 1afd632dea09e1..6c17bf93c800e9 100644 --- a/src/coreclr/vm/object.h +++ b/src/coreclr/vm/object.h @@ -1219,13 +1219,6 @@ class ReflectModuleBaseObject : public Object } }; -NOINLINE ReflectModuleBaseObject* GetRuntimeModuleHelper(LPVOID __me, Module *pModule, OBJECTREF keepAlive); -#define FC_RETURN_MODULE_OBJECT(pModule, refKeepAlive) FC_INNER_RETURN(ReflectModuleBaseObject*, GetRuntimeModuleHelper(__me, pModule, refKeepAlive)) - - - - - class ThreadBaseObject; class SynchronizationContextObject: public Object { @@ -1302,7 +1295,6 @@ typedef DPTR(class ThreadBaseObject) PTR_ThreadBaseObject; class ThreadBaseObject : public Object { friend class ClrDataAccess; - friend class ThreadNative; friend class CoreLibBinder; friend class Object; @@ -1439,8 +1431,6 @@ class AssemblyBaseObject : public Object SetObjectReference(&m_pSyncRoot, pSyncRoot); } }; -NOINLINE AssemblyBaseObject* GetRuntimeAssemblyHelper(LPVOID __me, Assembly *pAssembly, OBJECTREF keepAlive); -#define FC_RETURN_ASSEMBLY_OBJECT(pAssembly, refKeepAlive) FC_INNER_RETURN(AssemblyBaseObject*, GetRuntimeAssemblyHelper(__me, pAssembly, refKeepAlive)) // AssemblyLoadContextBaseObject // This class is the base class for AssemblyLoadContext diff --git a/src/coreclr/vm/proftoeeinterfaceimpl.cpp b/src/coreclr/vm/proftoeeinterfaceimpl.cpp index e99273beb5d133..614a6036fdf8a5 100644 --- a/src/coreclr/vm/proftoeeinterfaceimpl.cpp +++ b/src/coreclr/vm/proftoeeinterfaceimpl.cpp @@ -3148,9 +3148,9 @@ HRESULT ProfToEEInterfaceImpl::GetAppDomainStaticAddress(ClassID classId, return E_INVALIDARG; } - // Some domains, like the system domain, aren't APP domains, and thus don't contain any + // The system domain isn't an APP domain and thus doesn't contain any // statics. See if the profiler is trying to be naughty. - if (!((BaseDomain*) appDomainId)->IsAppDomain()) + if (appDomainId == (AppDomainID)SystemDomain::System()) { return E_INVALIDARG; } @@ -3382,9 +3382,9 @@ HRESULT ProfToEEInterfaceImpl::GetThreadStaticAddress2(ClassID classId, return E_INVALIDARG; } - // Some domains, like the system domain, aren't APP domains, and thus don't contain any + // The system domain isn't an APP domain and thus doesn't contain any // statics. See if the profiler is trying to be naughty. - if (!((BaseDomain*) appDomainId)->IsAppDomain()) + if (appDomainId == (AppDomainID)SystemDomain::System()) { return E_INVALIDARG; } @@ -5479,25 +5479,8 @@ HRESULT ProfToEEInterfaceImpl::GetAppDomainInfo(AppDomainID appDomainId, return E_INVALIDARG; } - BaseDomain *pDomain; // Internal data structure. HRESULT hr = S_OK; - // @todo: - // Right now, this ID is not a true AppDomain, since we use the old - // AppDomain/SystemDomain model in the profiling API. This means that - // the profiler exposes the SharedDomain and the SystemDomain to the - // outside world. It's not clear whether this is actually the right thing - // to do or not. - seantrow - // - // Postponed to V2. - // - - pDomain = (BaseDomain *) appDomainId; - - // Make sure they've passed in a valid appDomainId - if (pDomain == NULL) - return (E_INVALIDARG); - // Pick sensible defaults. if (pcchName) *pcchName = 0; @@ -5507,10 +5490,10 @@ HRESULT ProfToEEInterfaceImpl::GetAppDomainInfo(AppDomainID appDomainId, *pProcessId = 0; LPCWSTR szFriendlyName; - if (pDomain == SystemDomain::System()) + if (appDomainId == (AppDomainID)SystemDomain::System()) szFriendlyName = g_pwBaseLibrary; else - szFriendlyName = ((AppDomain*)pDomain)->GetFriendlyNameForDebugger(); + szFriendlyName = ((AppDomain*)appDomainId)->GetFriendlyNameForDebugger(); if (szFriendlyName != NULL) { diff --git a/src/coreclr/vm/qcallentrypoints.cpp b/src/coreclr/vm/qcallentrypoints.cpp index 2d2345ca214c12..4181a027e669c8 100644 --- a/src/coreclr/vm/qcallentrypoints.cpp +++ b/src/coreclr/vm/qcallentrypoints.cpp @@ -118,6 +118,8 @@ static const Entry s_QCall[] = DllImportEntry(RuntimeTypeHandle_MakeArray) DllImportEntry(RuntimeTypeHandle_IsCollectible) DllImportEntry(RuntimeTypeHandle_GetConstraints) + DllImportEntry(RuntimeTypeHandle_GetAssemblySlow) + DllImportEntry(RuntimeTypeHandle_GetModuleSlow) DllImportEntry(RuntimeTypeHandle_GetNumVirtualsAndStaticVirtuals) DllImportEntry(RuntimeTypeHandle_VerifyInterfaceIsImplemented) DllImportEntry(RuntimeTypeHandle_GetInterfaceMethodImplementation) @@ -158,6 +160,7 @@ static const Entry s_QCall[] = DllImportEntry(ModuleHandle_ResolveMethod) DllImportEntry(ModuleHandle_ResolveField) DllImportEntry(ModuleHandle_GetPEKind) + DllImportEntry(AssemblyHandle_GetManifestModuleSlow) DllImportEntry(TypeBuilder_DefineGenericParam) DllImportEntry(TypeBuilder_DefineType) DllImportEntry(TypeBuilder_SetParentType) @@ -235,10 +238,13 @@ static const Entry s_QCall[] = DllImportEntry(AppDomain_CreateDynamicAssembly) DllImportEntry(ThreadNative_Start) DllImportEntry(ThreadNative_SetPriority) + DllImportEntry(ThreadNative_GetCurrentThread) DllImportEntry(ThreadNative_SetIsBackground) DllImportEntry(ThreadNative_InformThreadNameChange) DllImportEntry(ThreadNative_YieldThread) DllImportEntry(ThreadNative_GetCurrentOSThreadId) + DllImportEntry(ThreadNative_Initialize) + DllImportEntry(ThreadNative_GetThreadState) #ifdef FEATURE_COMINTEROP_APARTMENT_SUPPORT DllImportEntry(ThreadNative_GetApartmentState) DllImportEntry(ThreadNative_SetApartmentState) @@ -252,9 +258,12 @@ static const Entry s_QCall[] = #ifdef FEATURE_COMINTEROP DllImportEntry(ThreadNative_DisableComObjectEagerCleanup) #endif // FEATURE_COMINTEROP + DllImportEntry(WaitHandle_WaitOneCore) + DllImportEntry(WaitHandle_WaitMultipleIgnoringSyncContext) + DllImportEntry(WaitHandle_SignalAndWait) #ifdef TARGET_UNIX - DllImportEntry(WaitHandle_CorWaitOnePrioritizedNative) -#endif + DllImportEntry(WaitHandle_WaitOnePrioritized) +#endif // TARGET_UNIX DllImportEntry(ClrConfig_GetConfigBoolValue) DllImportEntry(Buffer_Clear) DllImportEntry(Buffer_MemMove) diff --git a/src/coreclr/vm/runtimehandles.cpp b/src/coreclr/vm/runtimehandles.cpp index dca024a0d7b5cf..7b067cf8103af8 100644 --- a/src/coreclr/vm/runtimehandles.cpp +++ b/src/coreclr/vm/runtimehandles.cpp @@ -161,43 +161,6 @@ NOINLINE static ReflectClassBaseObject* GetRuntimeTypeHelper(LPVOID __me, TypeHa #define RETURN_CLASS_OBJECT(typeHandle, keepAlive) FC_INNER_RETURN(ReflectClassBaseObject*, GetRuntimeTypeHelper(__me, typeHandle, keepAlive)) -NOINLINE ReflectModuleBaseObject* GetRuntimeModuleHelper(LPVOID __me, Module *pModule, OBJECTREF keepAlive) -{ - FC_INNER_PROLOG_NO_ME_SETUP(); - if (pModule == NULL) - return NULL; - - OBJECTREF refModule = pModule->GetExposedObjectIfExists(); - if (refModule != NULL) - return (ReflectModuleBaseObject*)OBJECTREFToObject(refModule); - - HELPER_METHOD_FRAME_BEGIN_RET_ATTRIB_1(Frame::FRAME_ATTR_EXACT_DEPTH|Frame::FRAME_ATTR_CAPTURE_DEPTH_2, keepAlive); - refModule = pModule->GetExposedObject(); - HELPER_METHOD_FRAME_END(); - - FC_INNER_EPILOG(); - return (ReflectModuleBaseObject*)OBJECTREFToObject(refModule); -} - -NOINLINE AssemblyBaseObject* GetRuntimeAssemblyHelper(LPVOID __me, Assembly *pAssembly, OBJECTREF keepAlive) -{ - FC_INNER_PROLOG_NO_ME_SETUP(); - if (pAssembly == NULL) - return NULL; - - OBJECTREF refAssembly = (pAssembly != NULL) ? pAssembly->GetExposedObjectIfExists() : NULL; - - if(refAssembly != NULL) - return (AssemblyBaseObject*)OBJECTREFToObject(refAssembly); - - HELPER_METHOD_FRAME_BEGIN_RET_ATTRIB_1(Frame::FRAME_ATTR_EXACT_DEPTH|Frame::FRAME_ATTR_CAPTURE_DEPTH_2, keepAlive); - refAssembly = pAssembly->GetExposedObject(); - HELPER_METHOD_FRAME_END(); - - FC_INNER_EPILOG(); - return (AssemblyBaseObject*)OBJECTREFToObject(refAssembly); -} - FCIMPL1(ReflectClassBaseObject*, RuntimeTypeHandle::GetRuntimeType, EnregisteredTypeHandle th) { FCALL_CONTRACT; @@ -298,23 +261,35 @@ FCIMPL1(INT32, RuntimeTypeHandle::GetCorElementType, ReflectClassBaseObject *pTy } FCIMPLEND -FCIMPL1(AssemblyBaseObject*, RuntimeTypeHandle::GetAssembly, ReflectClassBaseObject *pTypeUNSAFE) { - CONTRACTL { - FCALL_CHECK; - } - CONTRACTL_END; +FCIMPL1(AssemblyBaseObject*, RuntimeTypeHandle::GetAssemblyIfExists, ReflectClassBaseObject *pTypeUNSAFE) +{ + FCALL_CONTRACT; REFLECTCLASSBASEREF refType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pTypeUNSAFE); - if (refType == NULL) - FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle")); + return NULL; Assembly* pAssembly = refType->GetType().GetAssembly(); - - FC_RETURN_ASSEMBLY_OBJECT(pAssembly, refType); + OBJECTREF refAssembly = pAssembly->GetExposedObjectIfExists(); + return (AssemblyBaseObject*)OBJECTREFToObject(refAssembly); } FCIMPLEND +extern "C" void QCALLTYPE RuntimeTypeHandle_GetAssemblySlow(QCall::ObjectHandleOnStack type, QCall::ObjectHandleOnStack assembly) +{ + QCALL_CONTRACT; + + BEGIN_QCALL; + GCX_COOP(); + + if (type.Get() == NULL) + COMPlusThrow(kArgumentNullException, W("Arg_InvalidHandle")); + + Assembly* pAssembly = ((REFLECTCLASSBASEREF)type.Get())->GetType().GetAssembly(); + assembly.Set(pAssembly->GetExposedObject()); + END_QCALL; +} + FCIMPL1(FC_BOOL_RET, RuntimeFieldHandle::AcquiresContextFromThis, FieldDesc* pField) { CONTRACTL { @@ -351,25 +326,35 @@ FCIMPL1(Object*, RuntimeFieldHandle::GetLoaderAllocator, FieldDesc* pField) } FCIMPLEND -FCIMPL1(ReflectModuleBaseObject*, RuntimeTypeHandle::GetModule, ReflectClassBaseObject *pTypeUNSAFE) { - CONTRACTL { - FCALL_CHECK; - } - CONTRACTL_END; - - Module *result; +FCIMPL1(ReflectModuleBaseObject*, RuntimeTypeHandle::GetModuleIfExists, ReflectClassBaseObject *pTypeUNSAFE) +{ + FCALL_CONTRACT; REFLECTCLASSBASEREF refType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pTypeUNSAFE); - if (refType == NULL) - FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle")); - - result = refType->GetType().GetModule(); + return NULL; - FC_RETURN_MODULE_OBJECT(result, refType); + Module* pModule = refType->GetType().GetModule(); + OBJECTREF refModule = pModule->GetExposedObjectIfExists(); + return (ReflectModuleBaseObject*)OBJECTREFToObject(refModule); } FCIMPLEND +extern "C" void QCALLTYPE RuntimeTypeHandle_GetModuleSlow(QCall::ObjectHandleOnStack type, QCall::ObjectHandleOnStack module) +{ + QCALL_CONTRACT; + + BEGIN_QCALL; + GCX_COOP(); + + if (type.Get() == NULL) + COMPlusThrow(kArgumentNullException, W("Arg_InvalidHandle")); + + Module* pModule = ((REFLECTCLASSBASEREF)type.Get())->GetType().GetModule(); + module.Set(pModule->GetExposedObject()); + END_QCALL; +} + FCIMPL1(ReflectClassBaseObject *, RuntimeTypeHandle::GetBaseType, ReflectClassBaseObject *pTypeUNSAFE) { CONTRACTL { FCALL_CHECK; @@ -2679,17 +2664,17 @@ FCIMPL2(FieldDesc*, RuntimeFieldHandle::GetStaticFieldForGenericType, FieldDesc } FCIMPLEND -FCIMPL1(ReflectModuleBaseObject*, AssemblyHandle::GetManifestModule, AssemblyBaseObject* pAssemblyUNSAFE) { +FCIMPL1(ReflectModuleBaseObject*, AssemblyHandle::GetManifestModule, AssemblyBaseObject* pAssemblyUNSAFE) +{ FCALL_CONTRACT; ASSEMBLYREF refAssembly = (ASSEMBLYREF)ObjectToOBJECTREF(pAssemblyUNSAFE); - if (refAssembly == NULL) - FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle")); - - Assembly* currentAssembly = refAssembly->GetAssembly(); + return NULL; - FC_RETURN_MODULE_OBJECT(currentAssembly->GetModule(), refAssembly); + Module* pModule = refAssembly->GetAssembly()->GetModule(); + OBJECTREF refModule = pModule->GetExposedObjectIfExists(); + return (ReflectModuleBaseObject*)OBJECTREFToObject(refModule); } FCIMPLEND @@ -2716,6 +2701,20 @@ FCIMPL1(INT32, AssemblyHandle::GetToken, AssemblyBaseObject* pAssemblyUNSAFE) { } FCIMPLEND +extern "C" void QCALLTYPE AssemblyHandle_GetManifestModuleSlow(QCall::ObjectHandleOnStack assembly, QCall::ObjectHandleOnStack module) +{ + QCALL_CONTRACT; + + BEGIN_QCALL; + GCX_COOP(); + + if (assembly.Get() == NULL) + COMPlusThrow(kArgumentNullException, W("Arg_InvalidHandle")); + + Module* pModule = ((ASSEMBLYREF)assembly.Get())->GetAssembly()->GetModule(); + module.Set(pModule->GetExposedObject()); + END_QCALL; +} extern "C" void QCALLTYPE ModuleHandle_GetPEKind(QCall::ModuleHandle pModule, DWORD* pdwPEKind, DWORD* pdwMachine) { diff --git a/src/coreclr/vm/runtimehandles.h b/src/coreclr/vm/runtimehandles.h index ee1977997feccc..fd6661b791ca35 100644 --- a/src/coreclr/vm/runtimehandles.h +++ b/src/coreclr/vm/runtimehandles.h @@ -119,9 +119,9 @@ class RuntimeTypeHandle { static FCDECL2(FC_BOOL_RET, IsEquivalentTo, ReflectClassBaseObject *rtType1UNSAFE, ReflectClassBaseObject *rtType2UNSAFE); - static FCDECL1(AssemblyBaseObject*, GetAssembly, ReflectClassBaseObject *pType); + static FCDECL1(AssemblyBaseObject*, GetAssemblyIfExists, ReflectClassBaseObject *pType); static FCDECL1(ReflectClassBaseObject*, GetBaseType, ReflectClassBaseObject* pType); - static FCDECL1(ReflectModuleBaseObject*, GetModule, ReflectClassBaseObject* pType); + static FCDECL1(ReflectModuleBaseObject*, GetModuleIfExists, ReflectClassBaseObject* pType); static FCDECL1(INT32, GetAttributes, ReflectClassBaseObject* pType); static FCDECL1(INT32, GetToken, ReflectClassBaseObject* pType); static FCDECL1(LPCUTF8, GetUtf8Name, ReflectClassBaseObject* pType); @@ -191,6 +191,8 @@ extern "C" void QCALLTYPE RuntimeTypeHandle_GetInstantiation(QCall::TypeHandle p extern "C" void QCALLTYPE RuntimeTypeHandle_Instantiate(QCall::TypeHandle pTypeHandle, TypeHandle * pInstArray, INT32 cInstArray, QCall::ObjectHandleOnStack retType); extern "C" void QCALLTYPE RuntimeTypeHandle_GetGenericTypeDefinition(QCall::TypeHandle pTypeHandle, QCall::ObjectHandleOnStack retType); extern "C" void QCALLTYPE RuntimeTypeHandle_GetConstraints(QCall::TypeHandle pTypeHandle, QCall::ObjectHandleOnStack retTypes); +extern "C" void QCALLTYPE RuntimeTypeHandle_GetAssemblySlow(QCall::ObjectHandleOnStack type, QCall::ObjectHandleOnStack assembly); +extern "C" void QCALLTYPE RuntimeTypeHandle_GetModuleSlow(QCall::ObjectHandleOnStack type, QCall::ObjectHandleOnStack module); extern "C" INT32 QCALLTYPE RuntimeTypeHandle_GetNumVirtualsAndStaticVirtuals(QCall::TypeHandle pTypeHandle); extern "C" void QCALLTYPE RuntimeTypeHandle_VerifyInterfaceIsImplemented(QCall::TypeHandle pTypeHandle, QCall::TypeHandle pIFaceHandle); extern "C" MethodDesc* QCALLTYPE RuntimeTypeHandle_GetInterfaceMethodImplementation(QCall::TypeHandle pTypeHandle, QCall::TypeHandle pOwner, MethodDesc * pMD); @@ -330,14 +332,15 @@ extern "C" void QCALLTYPE ModuleHandle_GetAssembly(QCall::ModuleHandle pModule, extern "C" void QCALLTYPE ModuleHandle_GetPEKind(QCall::ModuleHandle pModule, DWORD* pdwPEKind, DWORD* pdwMachine); -class AssemblyHandle { - +class AssemblyHandle +{ public: static FCDECL1(ReflectModuleBaseObject*, GetManifestModule, AssemblyBaseObject *pAssemblyUNSAFE); - static FCDECL1(INT32, GetToken, AssemblyBaseObject *pAssemblyUNSAFE); }; +extern "C" void QCALLTYPE AssemblyHandle_GetManifestModuleSlow(QCall::ObjectHandleOnStack assembly, QCall::ObjectHandleOnStack module); + class SignatureNative; typedef DPTR(SignatureNative) PTR_SignatureNative; diff --git a/src/coreclr/vm/threads.cpp b/src/coreclr/vm/threads.cpp index f9fbfec9bc6611..99a366e9a2f131 100644 --- a/src/coreclr/vm/threads.cpp +++ b/src/coreclr/vm/threads.cpp @@ -3116,14 +3116,14 @@ DWORD MsgWaitHelper(int numWaiters, HANDLE* phEvent, BOOL bWaitAll, DWORD millis // want true WAIT_ALL, we need to fire up a different thread in the MTA and wait // on its result. This isn't implemented yet. // - // A change was added to WaitHandleNative::CorWaitMultipleNative to disable WaitAll + // A change was added to WaitHandle_WaitMultipleIgnoringSyncContext to disable WaitAll // in an STA with more than one handle. if (bWaitAll) { if (numWaiters == 1) bWaitAll = FALSE; - // The check that's supposed to prevent this condition from occurring, in WaitHandleNative::CorWaitMultipleNative, + // The check that's supposed to prevent this condition from occurring, in WaitHandle_WaitMultipleIgnoringSyncContext, // is unfortunately behind FEATURE_COMINTEROP instead of FEATURE_COMINTEROP_APARTMENT_SUPPORT. // So on CoreCLR (where FEATURE_COMINTEROP is not currently defined) we can actually reach this point. // We can't fix this, because it's a breaking change, so we just won't assert here. diff --git a/src/coreclr/vm/threads.h b/src/coreclr/vm/threads.h index f3b7894c3dea64..44a537e7fe9050 100644 --- a/src/coreclr/vm/threads.h +++ b/src/coreclr/vm/threads.h @@ -468,7 +468,6 @@ class Thread friend class ThreadSuspend; friend class SyncBlock; friend struct PendingSync; - friend class ThreadNative; #ifdef _DEBUG friend class EEContract; #endif @@ -2706,6 +2705,24 @@ class Thread #endif // TRACK_SYNC + // Access to thread handle and ThreadId. + HANDLE GetThreadHandle() + { + LIMITED_METHOD_CONTRACT; +#if defined(_DEBUG) && !defined(DACCESS_COMPILE) + { + CounterHolder handleHolder(&m_dwThreadHandleBeingUsed); + HANDLE handle = m_ThreadHandle; + _ASSERTE ( handle == INVALID_HANDLE_VALUE + || m_OSThreadId == 0 + || m_OSThreadId == 0xbaadf00d + || ::MatchThreadHandleToOsId(handle, (DWORD)m_OSThreadId) ); + } +#endif + DACCOP_IGNORE(FieldAccess, "Treated as raw address, no marshaling is necessary"); + return m_ThreadHandle; + } + private: // For suspends: CLREvent m_DebugSuspendEvent; @@ -2729,25 +2746,6 @@ class Thread return walk; } - // Access to thread handle and ThreadId. - HANDLE GetThreadHandle() - { - LIMITED_METHOD_CONTRACT; -#if defined(_DEBUG) && !defined(DACCESS_COMPILE) - { - CounterHolder handleHolder(&m_dwThreadHandleBeingUsed); - HANDLE handle = m_ThreadHandle; - _ASSERTE ( handle == INVALID_HANDLE_VALUE - || m_OSThreadId == 0 - || m_OSThreadId == 0xbaadf00d - || ::MatchThreadHandleToOsId(handle, (DWORD)m_OSThreadId) ); - } -#endif - - DACCOP_IGNORE(FieldAccess, "Treated as raw address, no marshaling is necessary"); - return m_ThreadHandle; - } - void SetThreadHandle(HANDLE h) { LIMITED_METHOD_CONTRACT; diff --git a/src/coreclr/vm/threadstatics.cpp b/src/coreclr/vm/threadstatics.cpp index 14252ca2ae06c1..dbb218464a61ed 100644 --- a/src/coreclr/vm/threadstatics.cpp +++ b/src/coreclr/vm/threadstatics.cpp @@ -33,7 +33,6 @@ static TLSIndexToMethodTableMap *g_pThreadStaticCollectibleTypeIndices; static TLSIndexToMethodTableMap *g_pThreadStaticNonCollectibleTypeIndices; static PTR_MethodTable g_pMethodTablesForDirectThreadLocalData[offsetof(ThreadLocalData, ExtendedDirectThreadLocalTLSData) - offsetof(ThreadLocalData, ThreadBlockingInfo_First) + EXTENDED_DIRECT_THREAD_LOCAL_SIZE]; -static Volatile s_GCsWhichDoRelocateAndCanEmptyOutTheTLSIndices = 0; static uint32_t g_NextTLSSlot = 1; static uint32_t g_NextNonCollectibleTlsSlot = NUMBER_OF_TLSOFFSETS_NOT_USED_IN_NONCOLLECTIBLE_ARRAY; static uint32_t g_directThreadLocalTLSBytesAvailable = EXTENDED_DIRECT_THREAD_LOCAL_SIZE; @@ -277,7 +276,7 @@ void TLSIndexToMethodTableMap::Clear(TLSIndex index, uint8_t whenCleared) _ASSERTE(IsClearedValue(pMap[index.GetIndexOffset()])); } -bool TLSIndexToMethodTableMap::FindClearedIndex(uint8_t whenClearedMarkerToAvoid, TLSIndex* pIndex) +bool TLSIndexToMethodTableMap::FindClearedIndex(TLSIndex* pIndex) { CONTRACTL { @@ -291,15 +290,6 @@ bool TLSIndexToMethodTableMap::FindClearedIndex(uint8_t whenClearedMarkerToAvoid { if (entry.IsClearedValue) { - uint8_t whenClearedMarker = entry.ClearedMarker; - if ((whenClearedMarker == whenClearedMarkerToAvoid) || - (whenClearedMarker == (whenClearedMarkerToAvoid - 1)) || - (whenClearedMarker == (whenClearedMarkerToAvoid - 2))) - { - // Make sure we are not within 2 of the marker we are trying to avoid - // Use multiple compares instead of trying to fuss around with the overflow style comparisons - continue; - } *pIndex = entry.TlsIndex; return true; } @@ -317,7 +307,7 @@ void InitializeThreadStaticData() } CONTRACTL_END; - g_pThreadStaticCollectibleTypeIndices = new TLSIndexToMethodTableMap(TLSIndexType::NonCollectible); + g_pThreadStaticCollectibleTypeIndices = new TLSIndexToMethodTableMap(TLSIndexType::Collectible); g_pThreadStaticNonCollectibleTypeIndices = new TLSIndexToMethodTableMap(TLSIndexType::NonCollectible); g_TLSCrst.Init(CrstThreadLocalStorageLock, CRST_UNSAFE_ANYMODE); } @@ -387,7 +377,7 @@ void FreeLoaderAllocatorHandlesForTLSData(Thread *pThread) #endif for (const auto& entry : g_pThreadStaticCollectibleTypeIndices->CollectibleEntries()) { - _ASSERTE((entry.TlsIndex.GetIndexOffset() < pThread->cLoaderHandles) || allRemainingIndicesAreNotValid); + _ASSERTE((entry.TlsIndex.GetIndexOffset() <= pThread->cLoaderHandles) || allRemainingIndicesAreNotValid); if (entry.TlsIndex.GetIndexOffset() >= pThread->cLoaderHandles) { #ifndef _DEBUG @@ -405,6 +395,13 @@ void FreeLoaderAllocatorHandlesForTLSData(Thread *pThread) } } } + + pThread->cLoaderHandles = -1; // Sentinel value indicating that there are no LoaderHandles and the thread is permanently dead. + if (pThread->pLoaderHandles != NULL) + { + delete[] pThread->pLoaderHandles; + pThread->pLoaderHandles = NULL; + } } } @@ -431,34 +428,46 @@ void FreeThreadStaticData(Thread* pThread) } CONTRACTL_END; - SpinLockHolder spinLock(&pThread->m_TlsSpinLock); + InFlightTLSData* pOldInFlightData = nullptr; - ThreadLocalData *pThreadLocalData = &t_ThreadStatics; + int32_t oldCollectibleTlsDataCount = 0; + DPTR(OBJECTHANDLE) pOldCollectibleTlsArrayData = nullptr; - for (int32_t iTlsSlot = 0; iTlsSlot < pThreadLocalData->cCollectibleTlsData; ++iTlsSlot) { - if (!IsHandleNullUnchecked(pThreadLocalData->pCollectibleTlsArrayData[iTlsSlot])) + SpinLockHolder spinLock(&pThread->m_TlsSpinLock); + + ThreadLocalData *pThreadLocalData = &t_ThreadStatics; + + pOldCollectibleTlsArrayData = pThreadLocalData->pCollectibleTlsArrayData; + oldCollectibleTlsDataCount = pThreadLocalData->cCollectibleTlsData; + + pThreadLocalData->pCollectibleTlsArrayData = NULL; + pThreadLocalData->cCollectibleTlsData = 0; + pThreadLocalData->pNonCollectibleTlsArrayData = NULL; + pThreadLocalData->cNonCollectibleTlsData = 0; + + pOldInFlightData = pThreadLocalData->pInFlightData; + pThreadLocalData->pInFlightData = NULL; + _ASSERTE(pThreadLocalData->pThread == pThread); + pThreadLocalData->pThread = NULL; + } + + for (int32_t iTlsSlot = 0; iTlsSlot < oldCollectibleTlsDataCount; ++iTlsSlot) + { + if (!IsHandleNullUnchecked(pOldCollectibleTlsArrayData[iTlsSlot])) { - DestroyLongWeakHandle(pThreadLocalData->pCollectibleTlsArrayData[iTlsSlot]); + DestroyLongWeakHandle(pOldCollectibleTlsArrayData[iTlsSlot]); } } - delete[] (uint8_t*)pThreadLocalData->pCollectibleTlsArrayData; - - pThreadLocalData->pCollectibleTlsArrayData = 0; - pThreadLocalData->cCollectibleTlsData = 0; - pThreadLocalData->pNonCollectibleTlsArrayData = 0; - pThreadLocalData->cNonCollectibleTlsData = 0; + delete[] (uint8_t*)pOldCollectibleTlsArrayData; - while (pThreadLocalData->pInFlightData != NULL) + while (pOldInFlightData != NULL) { - InFlightTLSData* pInFlightData = pThreadLocalData->pInFlightData; - pThreadLocalData->pInFlightData = pInFlightData->pNext; + InFlightTLSData* pInFlightData = pOldInFlightData; + pOldInFlightData = pInFlightData->pNext; delete pInFlightData; } - - _ASSERTE(pThreadLocalData->pThread == pThread); - pThreadLocalData->pThread = NULL; } void SetTLSBaseValue(TADDR *ppTLSBaseAddress, TADDR pTLSBaseAddress, bool useGCBarrierInsteadOfHandleStore) @@ -553,6 +562,8 @@ void* GetThreadLocalStaticBase(TLSIndex index) delete[] pOldArray; } + _ASSERTE(t_ThreadStatics.pThread->cLoaderHandles != -1); // Check sentinel value indicating that there are no LoaderHandles, the thread has gone through termination and is permanently dead. + if (isCollectible && t_ThreadStatics.pThread->cLoaderHandles <= index.GetIndexOffset()) { // Grow the underlying TLS array @@ -594,9 +605,11 @@ void* GetThreadLocalStaticBase(TLSIndex index) gcBaseAddresses.pTLSBaseAddress = dac_cast(OBJECTREFToObject(ObjectFromHandle(pInFlightData->hTLSData))); if (pMT->IsClassInited()) { - SpinLockHolder spinLock(&t_ThreadStatics.pThread->m_TlsSpinLock); - SetTLSBaseValue(gcBaseAddresses.ppTLSBaseAddress, gcBaseAddresses.pTLSBaseAddress, staticIsNonCollectible); - *ppOldNextPtr = pInFlightData->pNext; + { + SpinLockHolder spinLock(&t_ThreadStatics.pThread->m_TlsSpinLock); + SetTLSBaseValue(gcBaseAddresses.ppTLSBaseAddress, gcBaseAddresses.pTLSBaseAddress, staticIsNonCollectible); + *ppOldNextPtr = pInFlightData->pNext; + } delete pInFlightData; } break; @@ -744,7 +757,7 @@ void GetTLSIndexForThreadStatic(MethodTable* pMT, bool gcStatic, TLSIndex* pInde } else { - if (!g_pThreadStaticCollectibleTypeIndices->FindClearedIndex(s_GCsWhichDoRelocateAndCanEmptyOutTheTLSIndices, &newTLSIndex)) + if (!g_pThreadStaticCollectibleTypeIndices->FindClearedIndex(&newTLSIndex)) { uint32_t tlsRawIndex = g_NextTLSSlot; newTLSIndex = TLSIndex(TLSIndexType::Collectible, tlsRawIndex); @@ -777,7 +790,7 @@ void FreeTLSIndicesForLoaderAllocator(LoaderAllocator *pLoaderAllocator) while (current != end) { - g_pThreadStaticCollectibleTypeIndices->Clear(tlsIndicesToCleanup[current], s_GCsWhichDoRelocateAndCanEmptyOutTheTLSIndices); + g_pThreadStaticCollectibleTypeIndices->Clear(tlsIndicesToCleanup[current], 0); ++current; } } diff --git a/src/coreclr/vm/threadstatics.h b/src/coreclr/vm/threadstatics.h index 3ab3806cbf952a..4d979d168bf013 100644 --- a/src/coreclr/vm/threadstatics.h +++ b/src/coreclr/vm/threadstatics.h @@ -304,7 +304,7 @@ class TLSIndexToMethodTableMap #ifndef DACCESS_COMPILE void Set(TLSIndex index, PTR_MethodTable pMT, bool isGCStatic); - bool FindClearedIndex(uint8_t whenClearedMarkerToAvoid, TLSIndex* pIndex); + bool FindClearedIndex(TLSIndex* pIndex); void Clear(TLSIndex index, uint8_t whenCleared); #endif // !DACCESS_COMPILE diff --git a/src/installer/tests/HostActivation.Tests/FrameworkResolution/ApplyPatchesSettings.cs b/src/installer/tests/HostActivation.Tests/FrameworkResolution/ApplyPatchesSettings.cs index d747ee016f47df..3d00d7a02db589 100644 --- a/src/installer/tests/HostActivation.Tests/FrameworkResolution/ApplyPatchesSettings.cs +++ b/src/installer/tests/HostActivation.Tests/FrameworkResolution/ApplyPatchesSettings.cs @@ -5,6 +5,8 @@ using Microsoft.DotNet.Cli.Build.Framework; using Xunit; +using static Microsoft.DotNet.CoreSetup.Test.Constants; + namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.FrameworkResolution { public class ApplyPatchesSettings : diff --git a/src/installer/tests/HostActivation.Tests/FrameworkResolution/ComplexHierarchies.cs b/src/installer/tests/HostActivation.Tests/FrameworkResolution/ComplexHierarchies.cs index 9a474ba7de7c06..b8c3f82e77485a 100644 --- a/src/installer/tests/HostActivation.Tests/FrameworkResolution/ComplexHierarchies.cs +++ b/src/installer/tests/HostActivation.Tests/FrameworkResolution/ComplexHierarchies.cs @@ -6,6 +6,8 @@ using System; using Xunit; +using static Microsoft.DotNet.CoreSetup.Test.Constants; + namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.FrameworkResolution { public class ComplexHierarchies : diff --git a/src/installer/tests/HostActivation.Tests/FrameworkResolution/FrameworkResolutionBase.Settings.cs b/src/installer/tests/HostActivation.Tests/FrameworkResolution/FrameworkResolutionBase.Settings.cs index 81f2e14a35f527..9b8a63b9a65025 100644 --- a/src/installer/tests/HostActivation.Tests/FrameworkResolution/FrameworkResolutionBase.Settings.cs +++ b/src/installer/tests/HostActivation.Tests/FrameworkResolution/FrameworkResolutionBase.Settings.cs @@ -85,7 +85,7 @@ public enum SettingLocation public static Func RollForwardSetting( SettingLocation location, string value, - string frameworkReferenceName = MicrosoftNETCoreApp) + string frameworkReferenceName = Constants.MicrosoftNETCoreApp) { if (value == null || location == SettingLocation.None) { @@ -114,7 +114,7 @@ public static Func RollForwardSetting( public static Func RollForwardOnNoCandidateFxSetting( SettingLocation location, int? value, - string frameworkReferenceName = MicrosoftNETCoreApp) + string frameworkReferenceName = Constants.MicrosoftNETCoreApp) { if (!value.HasValue || location == SettingLocation.None) { @@ -143,7 +143,7 @@ public static Func RollForwardOnNoCandidateFxSetting public static Func ApplyPatchesSetting( SettingLocation location, bool? value, - string frameworkReferenceName = MicrosoftNETCoreApp) + string frameworkReferenceName = Constants.MicrosoftNETCoreApp) { if (!value.HasValue || location == SettingLocation.None) { diff --git a/src/installer/tests/HostActivation.Tests/FrameworkResolution/FrameworkResolutionBase.cs b/src/installer/tests/HostActivation.Tests/FrameworkResolution/FrameworkResolutionBase.cs index a0ce8d0cf3963d..b098994df8ae65 100644 --- a/src/installer/tests/HostActivation.Tests/FrameworkResolution/FrameworkResolutionBase.cs +++ b/src/installer/tests/HostActivation.Tests/FrameworkResolution/FrameworkResolutionBase.cs @@ -11,8 +11,6 @@ namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.FrameworkResolution { public abstract partial class FrameworkResolutionBase { - protected const string MicrosoftNETCoreApp = "Microsoft.NETCore.App"; - public static class ResolvedFramework { public const string NotFound = "[not found]"; @@ -23,7 +21,6 @@ protected CommandResult RunTest( DotNetCli dotnet, TestApp app, TestSettings settings, - Action resultAction = null, bool? multiLevelLookup = false) { using (DotNetCliExtensions.DotNetCliCustomizer dotnetCustomizer = settings.DotnetCustomizer == null ? null : dotnet.Customize()) @@ -53,8 +50,6 @@ protected CommandResult RunTest( .Environment(settings.Environment) .Execute(); - resultAction?.Invoke(result); - return result; } } diff --git a/src/installer/tests/HostActivation.Tests/FrameworkResolution/FxVersionCLI.cs b/src/installer/tests/HostActivation.Tests/FrameworkResolution/FxVersionCLI.cs index 10057216bc36de..5d09a35ff67b84 100644 --- a/src/installer/tests/HostActivation.Tests/FrameworkResolution/FxVersionCLI.cs +++ b/src/installer/tests/HostActivation.Tests/FrameworkResolution/FxVersionCLI.cs @@ -5,6 +5,8 @@ using Microsoft.DotNet.Cli.Build.Framework; using Xunit; +using static Microsoft.DotNet.CoreSetup.Test.Constants; + namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.FrameworkResolution { public class FXVersionCLI : diff --git a/src/installer/tests/HostActivation.Tests/FrameworkResolution/IncludedFrameworksSettings.cs b/src/installer/tests/HostActivation.Tests/FrameworkResolution/IncludedFrameworksSettings.cs index af8aa1dc3b5931..ec5ae8306693cf 100644 --- a/src/installer/tests/HostActivation.Tests/FrameworkResolution/IncludedFrameworksSettings.cs +++ b/src/installer/tests/HostActivation.Tests/FrameworkResolution/IncludedFrameworksSettings.cs @@ -5,6 +5,8 @@ using Microsoft.DotNet.Cli.Build.Framework; using Xunit; +using static Microsoft.DotNet.CoreSetup.Test.Constants; + namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.FrameworkResolution { public class IncludedFrameworksSettings : diff --git a/src/installer/tests/HostActivation.Tests/FrameworkResolution/MultipleHives.cs b/src/installer/tests/HostActivation.Tests/FrameworkResolution/MultipleHives.cs index 1fb612efb38264..e44a58272515f5 100644 --- a/src/installer/tests/HostActivation.Tests/FrameworkResolution/MultipleHives.cs +++ b/src/installer/tests/HostActivation.Tests/FrameworkResolution/MultipleHives.cs @@ -8,6 +8,7 @@ using Microsoft.DotNet.Cli.Build; using Microsoft.DotNet.Cli.Build.Framework; using Xunit; +using static Microsoft.DotNet.CoreSetup.Test.Constants; namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.FrameworkResolution { @@ -217,6 +218,50 @@ public void FrameworkResolutionError(string tfm, bool? multiLevelLookup, bool ef .And.HaveStdErrContaining("Ignoring FX version [9999.9.9] without .deps.json"); } + [Fact] + public void FrameworkResolutionError_ListOtherArchitectures() + { + using (var registeredInstallLocationOverride = new RegisteredInstallLocationOverride(SharedState.DotNetMainHive.GreatestVersionHostFxrFilePath)) + using (var otherArchArtifact = TestArtifact.Create("otherArch")) + { + string requestedVersion = "9999.9.9"; + string[] otherArchs = ["arm64", "x64", "x86"]; + var installLocations = new (string, string)[otherArchs.Length]; + for (int i = 0; i < otherArchs.Length; i++) + { + string arch = otherArchs[i]; + + // Create a .NET install with Microsoft.NETCoreApp at the registered location + var dotnet = new DotNetBuilder(otherArchArtifact.Location, TestContext.BuiltDotNet.BinPath, arch) + .AddMicrosoftNETCoreAppFrameworkMockHostPolicy(requestedVersion) + .Build(); + installLocations[i] = (arch, dotnet.BinPath); + } + + registeredInstallLocationOverride.SetInstallLocation(installLocations); + + CommandResult result = RunTest( + new TestSettings() + .WithRuntimeConfigCustomizer(c => c.WithFramework(MicrosoftNETCoreApp, requestedVersion)) + .WithEnvironment(TestOnlyEnvironmentVariables.RegisteredConfigLocation, registeredInstallLocationOverride.PathValueOverride), + multiLevelLookup: null); + + result.ShouldFailToFindCompatibleFrameworkVersion(MicrosoftNETCoreApp, requestedVersion) + .And.HaveStdErrContaining("The following frameworks for other architectures were found:"); + + // Error message should list framework found for other architectures + foreach ((string arch, string path) in installLocations) + { + if (arch == TestContext.BuildArchitecture) + continue; + + string expectedPath = System.Text.RegularExpressions.Regex.Escape(Path.Combine(path, "shared", MicrosoftNETCoreApp)); + result.Should() + .HaveStdErrMatching($@"{arch}\s*{requestedVersion} at \[{expectedPath}\]", System.Text.RegularExpressions.RegexOptions.Multiline); + } + } + } + private CommandResult RunTest(Func runtimeConfig, bool? multiLevelLookup = true) => RunTest(new TestSettings().WithRuntimeConfigCustomizer(runtimeConfig), multiLevelLookup); diff --git a/src/installer/tests/HostActivation.Tests/FrameworkResolution/RollForwardAndRollForwardOnNoCandidateFxSettings.cs b/src/installer/tests/HostActivation.Tests/FrameworkResolution/RollForwardAndRollForwardOnNoCandidateFxSettings.cs index 6555683bacd121..ab486868f661eb 100644 --- a/src/installer/tests/HostActivation.Tests/FrameworkResolution/RollForwardAndRollForwardOnNoCandidateFxSettings.cs +++ b/src/installer/tests/HostActivation.Tests/FrameworkResolution/RollForwardAndRollForwardOnNoCandidateFxSettings.cs @@ -5,6 +5,8 @@ using Microsoft.DotNet.Cli.Build.Framework; using Xunit; +using static Microsoft.DotNet.CoreSetup.Test.Constants; + namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.FrameworkResolution { public class RollForwardAndRollForwardOnNoCandidateFxSettings : diff --git a/src/installer/tests/HostActivation.Tests/FrameworkResolution/RollForwardMultipleFrameworks.cs b/src/installer/tests/HostActivation.Tests/FrameworkResolution/RollForwardMultipleFrameworks.cs index 26e2d11a2f13ae..8501e85e3698aa 100644 --- a/src/installer/tests/HostActivation.Tests/FrameworkResolution/RollForwardMultipleFrameworks.cs +++ b/src/installer/tests/HostActivation.Tests/FrameworkResolution/RollForwardMultipleFrameworks.cs @@ -6,6 +6,8 @@ using System; using Xunit; +using static Microsoft.DotNet.CoreSetup.Test.Constants; + namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.FrameworkResolution { public class RollForwardMultipleFrameworks : diff --git a/src/installer/tests/HostActivation.Tests/FrameworkResolution/RollForwardOnNoCandidateFx.cs b/src/installer/tests/HostActivation.Tests/FrameworkResolution/RollForwardOnNoCandidateFx.cs index 20a3f7796de864..835976248aed9d 100644 --- a/src/installer/tests/HostActivation.Tests/FrameworkResolution/RollForwardOnNoCandidateFx.cs +++ b/src/installer/tests/HostActivation.Tests/FrameworkResolution/RollForwardOnNoCandidateFx.cs @@ -1,11 +1,13 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; using Microsoft.DotNet.Cli.Build; using Microsoft.DotNet.Cli.Build.Framework; -using System; using Xunit; +using static Microsoft.DotNet.CoreSetup.Test.Constants; + namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.FrameworkResolution { public class RollForwardOnNoCandidateFx : diff --git a/src/installer/tests/HostActivation.Tests/FrameworkResolution/RollForwardOnNoCandidateFxMultipleFrameworks.cs b/src/installer/tests/HostActivation.Tests/FrameworkResolution/RollForwardOnNoCandidateFxMultipleFrameworks.cs index 8db6771f6c0423..ff756cb7c774fb 100644 --- a/src/installer/tests/HostActivation.Tests/FrameworkResolution/RollForwardOnNoCandidateFxMultipleFrameworks.cs +++ b/src/installer/tests/HostActivation.Tests/FrameworkResolution/RollForwardOnNoCandidateFxMultipleFrameworks.cs @@ -6,6 +6,8 @@ using System; using Xunit; +using static Microsoft.DotNet.CoreSetup.Test.Constants; + namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.FrameworkResolution { public class RollForwardOnNoCandidateFxMultipleFrameworks : diff --git a/src/installer/tests/HostActivation.Tests/FrameworkResolution/RollForwardOnNoCandidateFxSettings.cs b/src/installer/tests/HostActivation.Tests/FrameworkResolution/RollForwardOnNoCandidateFxSettings.cs index b18b8c8131c6b1..1e32c44da644ba 100644 --- a/src/installer/tests/HostActivation.Tests/FrameworkResolution/RollForwardOnNoCandidateFxSettings.cs +++ b/src/installer/tests/HostActivation.Tests/FrameworkResolution/RollForwardOnNoCandidateFxSettings.cs @@ -5,6 +5,8 @@ using Microsoft.DotNet.Cli.Build.Framework; using Xunit; +using static Microsoft.DotNet.CoreSetup.Test.Constants; + namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.FrameworkResolution { public class RollForwardOnNoCandidateFxSettings : diff --git a/src/installer/tests/HostActivation.Tests/FrameworkResolution/RollForwardPreReleaseOnly.cs b/src/installer/tests/HostActivation.Tests/FrameworkResolution/RollForwardPreReleaseOnly.cs index 9e35ed8ff2a630..332a1b6e2a978f 100644 --- a/src/installer/tests/HostActivation.Tests/FrameworkResolution/RollForwardPreReleaseOnly.cs +++ b/src/installer/tests/HostActivation.Tests/FrameworkResolution/RollForwardPreReleaseOnly.cs @@ -5,6 +5,8 @@ using Microsoft.DotNet.Cli.Build.Framework; using Xunit; +using static Microsoft.DotNet.CoreSetup.Test.Constants; + namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.FrameworkResolution { /// diff --git a/src/installer/tests/HostActivation.Tests/FrameworkResolution/RollForwardReleaseAndPreRelease.cs b/src/installer/tests/HostActivation.Tests/FrameworkResolution/RollForwardReleaseAndPreRelease.cs index 5305d1abbc60bf..88d6f0c459d0ac 100644 --- a/src/installer/tests/HostActivation.Tests/FrameworkResolution/RollForwardReleaseAndPreRelease.cs +++ b/src/installer/tests/HostActivation.Tests/FrameworkResolution/RollForwardReleaseAndPreRelease.cs @@ -5,6 +5,8 @@ using Microsoft.DotNet.Cli.Build.Framework; using Xunit; +using static Microsoft.DotNet.CoreSetup.Test.Constants; + namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.FrameworkResolution { /// diff --git a/src/installer/tests/HostActivation.Tests/FrameworkResolution/RollForwardReleaseOnly.cs b/src/installer/tests/HostActivation.Tests/FrameworkResolution/RollForwardReleaseOnly.cs index cd92cabd1b7726..48e2f551a473d2 100644 --- a/src/installer/tests/HostActivation.Tests/FrameworkResolution/RollForwardReleaseOnly.cs +++ b/src/installer/tests/HostActivation.Tests/FrameworkResolution/RollForwardReleaseOnly.cs @@ -5,6 +5,8 @@ using Microsoft.DotNet.Cli.Build.Framework; using Xunit; +using static Microsoft.DotNet.CoreSetup.Test.Constants; + namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.FrameworkResolution { /// diff --git a/src/installer/tests/HostActivation.Tests/FrameworkResolution/RollForwardSettings.cs b/src/installer/tests/HostActivation.Tests/FrameworkResolution/RollForwardSettings.cs index b5e278c74ccabc..2f5d836c639718 100644 --- a/src/installer/tests/HostActivation.Tests/FrameworkResolution/RollForwardSettings.cs +++ b/src/installer/tests/HostActivation.Tests/FrameworkResolution/RollForwardSettings.cs @@ -5,6 +5,8 @@ using Microsoft.DotNet.Cli.Build.Framework; using Xunit; +using static Microsoft.DotNet.CoreSetup.Test.Constants; + namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.FrameworkResolution { public class RollForwardSettings : diff --git a/src/installer/tests/TestUtils/Constants.cs b/src/installer/tests/TestUtils/Constants.cs index 4ae6587dd6407e..9eb5b6e661e32f 100644 --- a/src/installer/tests/TestUtils/Constants.cs +++ b/src/installer/tests/TestUtils/Constants.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; + namespace Microsoft.DotNet.CoreSetup.Test { public static class Constants @@ -82,8 +84,10 @@ public static class DisableGuiErrors public static class TestOnlyEnvironmentVariables { public const string DefaultInstallPath = "_DOTNET_TEST_DEFAULT_INSTALL_PATH"; - public const string RegistryPath = "_DOTNET_TEST_REGISTRY_PATH"; public const string GloballyRegisteredPath = "_DOTNET_TEST_GLOBALLY_REGISTERED_PATH"; + + public static string RegisteredConfigLocation = OperatingSystem.IsWindows() ? RegistryPath : InstallLocationPath; + public const string RegistryPath = "_DOTNET_TEST_REGISTRY_PATH"; public const string InstallLocationPath = "_DOTNET_TEST_INSTALL_LOCATION_PATH"; } diff --git a/src/libraries/Common/tests/WasmTestRunner/WasmTestRunner.cs b/src/libraries/Common/tests/WasmTestRunner/WasmTestRunner.cs index 1cf1b35cf291a1..8c393b95f69c21 100644 --- a/src/libraries/Common/tests/WasmTestRunner/WasmTestRunner.cs +++ b/src/libraries/Common/tests/WasmTestRunner/WasmTestRunner.cs @@ -20,7 +20,7 @@ public static int Main(string[] args) return PollWasiEventLoopUntilResolved((Thread)null!, MainAsync(args)); [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "PollWasiEventLoopUntilResolved")] - static extern int PollWasiEventLoopUntilResolved(Thread t, Task mainTask); + static extern T PollWasiEventLoopUntilResolved(Thread t, Task mainTask); } diff --git a/src/libraries/System.Numerics.Tensors/tests/TensorSpanTests.cs b/src/libraries/System.Numerics.Tensors/tests/TensorSpanTests.cs index f03f682f94f704..737ba5cf5374bc 100644 --- a/src/libraries/System.Numerics.Tensors/tests/TensorSpanTests.cs +++ b/src/libraries/System.Numerics.Tensors/tests/TensorSpanTests.cs @@ -486,12 +486,13 @@ public void TensorExtensionsTwoSpanInSpanOut(TensorPrimitivesTwoSpanInSpanOut public static IEnumerable TwoSpanInFloatOutData() { yield return Create(TensorPrimitives.Distance, Tensor.Distance); - //yield return Create(TensorPrimitives.Dot, Tensor.Dot); + yield return Create(TensorPrimitives.Dot, Tensor.Dot); static object[] Create(TensorPrimitivesTwoSpanInTOut tensorPrimitivesMethod, TensorTwoSpanInTOut tensorOperation) => new object[] { tensorPrimitivesMethod, tensorOperation }; } + [ActiveIssue("https://github.com/dotnet/runtime/issues/107254")] [Theory, MemberData(nameof(TwoSpanInFloatOutData))] public void TensorExtensionsTwoSpanInFloatOut(TensorPrimitivesTwoSpanInTOut tensorPrimitivesOperation, TensorTwoSpanInTOut tensorOperation) where T : INumberBase diff --git a/src/libraries/System.Numerics.Vectors/tests/GenericVectorTests.cs b/src/libraries/System.Numerics.Vectors/tests/GenericVectorTests.cs index 822bb136dffbcb..28ed4f701d4693 100644 --- a/src/libraries/System.Numerics.Vectors/tests/GenericVectorTests.cs +++ b/src/libraries/System.Numerics.Vectors/tests/GenericVectorTests.cs @@ -52,7 +52,6 @@ static GenericVectorTests() } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/81785", TestPlatforms.Browser)] public unsafe void IsHardwareAcceleratedTest() { MethodInfo methodInfo = typeof(Vector).GetMethod("get_IsHardwareAccelerated"); @@ -1094,10 +1093,8 @@ private void TestToString(string format, IFormatProvider provider) where T : [Fact] public void AdditionInt64() { TestAddition(); } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))] public void AdditionSingle() { TestAddition(); } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))] public void AdditionDouble() { TestAddition(); } private void TestAddition() where T : struct, INumber { @@ -1161,10 +1158,8 @@ private void TestAdditionOverflow() where T : struct, INumber [Fact] public void SubtractionInt64() { TestSubtraction(); } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))] public void SubtractionSingle() { TestSubtraction(); } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))] public void SubtractionDouble() { TestSubtraction(); } private void TestSubtraction() where T : struct, INumber { @@ -1228,10 +1223,8 @@ private void TestSubtractionOverflow() where T : struct, INumber [Fact] public void MultiplicationInt64() { TestMultiplication(); } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))] public void MultiplicationSingle() { TestMultiplication(); } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))] public void MultiplicationDouble() { TestMultiplication(); } private void TestMultiplication() where T : struct, INumber { @@ -1272,11 +1265,9 @@ private void TestMultiplication() where T : struct, INumber [ActiveIssue("https://github.com/dotnet/runtime/issues/67893", TestPlatforms.tvOS)] public void MultiplicationWithScalarInt64() { TestMultiplicationWithScalar(); } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))] [ActiveIssue("https://github.com/dotnet/runtime/issues/67893", TestPlatforms.tvOS)] public void MultiplicationWithScalarSingle() { TestMultiplicationWithScalar(); } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))] [ActiveIssue("https://github.com/dotnet/runtime/issues/67893", TestPlatforms.tvOS)] public void MultiplicationWithScalarDouble() { TestMultiplicationWithScalar(); } private void TestMultiplicationWithScalar() where T : struct, INumber @@ -1318,10 +1309,8 @@ private void TestMultiplicationWithScalar() where T : struct, INumber [Fact] public void DivisionInt64() { TestDivision(); } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))] public void DivisionSingle() { TestDivision(); } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))] public void DivisionDouble() { TestDivision(); } private void TestDivision() where T : struct, INumber { @@ -1388,11 +1377,9 @@ private void TestDivisionByZeroException() where T : struct public void DivisionWithScalarInt64() { TestDivisionWithScalar(); } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))] public void DivisionWithScalarSingle() { TestDivisionWithScalar(); } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))] public void DivisionWithScalarDouble() { TestDivisionWithScalar(); } private void TestDivisionWithScalar() where T : struct, INumber @@ -1460,10 +1447,8 @@ private void TestDivisionWithScalarByZeroException() where T : struct, INumbe [Fact] public void UnaryMinusInt64() { TestUnaryMinus(); } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))] public void UnaryMinusSingle() { TestUnaryMinus(); } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))] public void UnaryMinusDouble() { TestUnaryMinus(); } private void TestUnaryMinus() where T : struct, INumber { @@ -1850,10 +1835,8 @@ private void TestShiftRightLogical() where T : unmanaged, IBinaryInteger [Fact] public void VectorGreaterThanInt64() { TestVectorGreaterThan(); } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))] public void VectorGreaterThanSingle() { TestVectorGreaterThan(); } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))] public void VectorGreaterThanDouble() { TestVectorGreaterThan(); } private void TestVectorGreaterThan() where T : struct, INumber { @@ -1889,10 +1872,8 @@ private void TestVectorGreaterThan() where T : struct, INumber [Fact] public void GreaterThanOrEqualInt64() { TestVectorGreaterThanOrEqual(); } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))] public void GreaterThanOrEqualSingle() { TestVectorGreaterThanOrEqual(); } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))] public void GreaterThanOrEqualDouble() { TestVectorGreaterThanOrEqual(); } private void TestVectorGreaterThanOrEqual() where T : struct, INumber { @@ -2144,10 +2125,8 @@ private void TestVectorGreaterThanOrEqualAll() where T : struct [Fact] public void LessThanInt64() { TestVectorLessThan(); } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))] public void LessThanSingle() { TestVectorLessThan(); } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))] public void LessThanDouble() { TestVectorLessThan(); } private void TestVectorLessThan() where T : struct, INumber { @@ -2183,10 +2162,8 @@ private void TestVectorLessThan() where T : struct, INumber [Fact] public void LessThanOrEqualInt64() { TestVectorLessThanOrEqual(); } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))] public void LessThanOrEqualSingle() { TestVectorLessThanOrEqual(); } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))] public void LessThanOrEqualDouble() { TestVectorLessThanOrEqual(); } private void TestVectorLessThanOrEqual() where T : struct, INumber { @@ -2222,10 +2199,8 @@ private void TestVectorLessThanOrEqual() where T : struct, INumber [Fact] public void LessThanAnyInt64() { TestVectorLessThanAny(); } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))] public void LessThanAnySingle() { TestVectorLessThanAny(); } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))] public void LessThanAnyDouble() { TestVectorLessThanAny(); } private void TestVectorLessThanAny() where T : struct, INumber { @@ -2550,10 +2525,8 @@ private void TestVectorEqualsAll() where T : struct, INumber [Fact] public void ConditionalSelectInt64() { TestConditionalSelect(); } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))] public void ConditionalSelectSingle() { TestConditionalSelect(); } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))] public void ConditionalSelectDouble() { TestConditionalSelect(); } private void TestConditionalSelect() where T : struct, INumber { @@ -2604,10 +2577,8 @@ private void TestConditionalSelect() where T : struct, INumber [Fact] public void DotProductInt64() { TestDotProduct(); } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))] public void DotProductSingle() { TestDotProduct(); } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))] public void DotProductDouble() { TestDotProduct(); } private void TestDotProduct() where T : struct, INumber { @@ -2642,10 +2613,8 @@ private void TestDotProduct() where T : struct, INumber [Fact] public void MaxInt64() { TestMax(); } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))] public void MaxSingle() { TestMax(); } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))] public void MaxDouble() { TestMax(); } private void TestMax() where T : struct, INumber { @@ -2680,10 +2649,8 @@ private void TestMax() where T : struct, INumber [Fact] public void MinInt64() { TestMin(); } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))] public void MinSingle() { TestMin(); } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))] public void MinDouble() { TestMin(); } private void TestMin() where T : struct, INumber { @@ -2718,10 +2685,8 @@ private void TestMin() where T : struct, INumber [Fact] public void SquareRootInt64() { TestSquareRoot(-1); } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))] public void SquareRootSingle() { TestSquareRoot(6); } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))] public void SquareRootDouble() { TestSquareRoot(15); } private void TestSquareRoot(int precision = -1) where T : struct, INumber, IEquatable { @@ -2814,10 +2779,8 @@ public void FloorDouble() [Fact] public void AbsInt64() { TestAbs(); } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))] public void AbsSingle() { TestAbs(); } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))] public void AbsDouble() { TestAbs(); } private void TestAbs() where T : struct, INumber { @@ -2854,10 +2817,8 @@ private void TestAbs() where T : struct, INumber [Fact] public void MultiplicationReflectionInt64() { TestMultiplicationReflection(); } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))] public void MultiplicationReflectionSingle() { TestMultiplicationReflection(); } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))] public void MultiplicationReflectionDouble() { TestMultiplicationReflection(); } private void TestMultiplicationReflection() where T : struct, INumber { @@ -2893,10 +2854,8 @@ private void TestMultiplicationReflection() where T : struct, INumber [Fact] public void AdditionReflectionInt64() { TestAdditionReflection(); } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))] public void AdditionReflectionSingle() { TestAdditionReflection(); } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))] public void AdditionReflectionDouble() { TestAdditionReflection(); } private void TestAdditionReflection() where T : struct, INumber { @@ -2932,10 +2891,8 @@ private void TestAdditionReflection() where T : struct, INumber [Fact] public void DivisionReflectionInt64() { TestDivisionReflection(); } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))] public void DivisionReflectionSingle() { TestDivisionReflection(); } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))] public void DivisionReflectionDouble() { TestDivisionReflection(); } private void TestDivisionReflection() where T : struct, INumber { diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/CancellationTokenSource.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/CancellationTokenSource.cs index 26c2eb70785980..7ea36b67c970be 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/CancellationTokenSource.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/CancellationTokenSource.cs @@ -22,6 +22,7 @@ namespace System.Threading /// concurrently from multiple threads. /// /// + [DebuggerDisplay("IsCancellationRequested = {IsCancellationRequested}")] public class CancellationTokenSource : IDisposable { /// A that's already canceled. diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.Unix.cs index a3302b3bedc38c..592f0244e011a6 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.Unix.cs @@ -18,22 +18,16 @@ internal static System.Threading.Tasks.Task RegisterWasiPollableHandle(int handl return WasiEventLoop.RegisterWasiPollableHandle(handle, cancellationToken); } - internal static int PollWasiEventLoopUntilResolved(Task mainTask) + internal static T PollWasiEventLoopUntilResolved(Task mainTask) { - while (!mainTask.IsCompleted) - { - WasiEventLoop.DispatchWasiEventLoop(); - } - var exception = mainTask.Exception; - if (exception is not null) - { - throw exception; - } - - return mainTask.Result; + return WasiEventLoop.PollWasiEventLoopUntilResolved(mainTask); } -#endif + internal static void PollWasiEventLoopUntilResolvedVoid(Task mainTask) + { + WasiEventLoop.PollWasiEventLoopUntilResolvedVoid(mainTask); + } +#endif // TARGET_WASI // the closest analog to Sleep(0) on Unix is sched_yield internal static void UninterruptibleSleep0() => Thread.Yield(); diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPoolWorkQueue.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPoolWorkQueue.cs index 279932486e58a6..69a59198a40f4e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPoolWorkQueue.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPoolWorkQueue.cs @@ -906,10 +906,7 @@ internal static bool Dispatch() // thread because it sees a Determining or Scheduled stage, and the current thread is the last thread processing // work items, the current thread must either see the work item queued by the enqueuer, or it must see a stage of // Scheduled, and try to dequeue again or request another thread. -#if !TARGET_WASI - // TODO https://github.com/dotnet/runtime/issues/104803 Debug.Assert(workQueue._separated.queueProcessingStage == QueueProcessingStage.Scheduled); -#endif workQueue._separated.queueProcessingStage = QueueProcessingStage.Determining; Interlocked.MemoryBarrier(); diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Wasi/WasiEventLoop.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Wasi/WasiEventLoop.cs index e8e7b20dc34736..f2a5d898566cd5 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Wasi/WasiEventLoop.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Wasi/WasiEventLoop.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using WasiPollWorld.wit.imports.wasi.io.v0_2_1; using Pollable = WasiPollWorld.wit.imports.wasi.io.v0_2_1.IPoll.Pollable; +using MonotonicClockInterop = WasiPollWorld.wit.imports.wasi.clocks.v0_2_1.MonotonicClockInterop; namespace System.Threading { @@ -14,7 +15,9 @@ internal static class WasiEventLoop // it will be leaked and stay in this list forever. // it will also keep the Pollable handle alive and prevent it from being disposed private static readonly List s_pollables = new(); - private static bool s_tasksCanceled; + private static bool s_checkScheduled; + private static Pollable? s_resolvedPollable; + private static Task? s_mainTask; internal static Task RegisterWasiPollableHandle(int handle, CancellationToken cancellationToken) { @@ -29,18 +32,70 @@ internal static Task RegisterWasiPollable(Pollable pollable, CancellationToken c // this will register the pollable holder into s_pollables var holder = new PollableHolder(pollable, cancellationToken); s_pollables.Add(holder); + + ScheduleCheck(); + return holder.taskCompletionSource.Task; } - // this is not thread safe - internal static void DispatchWasiEventLoop() + + internal static T PollWasiEventLoopUntilResolved(Task mainTask) + { + try + { + s_mainTask = mainTask; + while (!mainTask.IsCompleted) + { + ThreadPoolWorkQueue.Dispatch(); + } + } + finally + { + s_mainTask = null; + } + var exception = mainTask.Exception; + if (exception is not null) + { + throw exception; + } + + return mainTask.Result; + } + + internal static void PollWasiEventLoopUntilResolvedVoid(Task mainTask) + { + try + { + s_mainTask = mainTask; + while (!mainTask.IsCompleted) + { + ThreadPoolWorkQueue.Dispatch(); + } + } + finally + { + s_mainTask = null; + } + + var exception = mainTask.Exception; + if (exception is not null) + { + throw exception; + } + } + + internal static void ScheduleCheck() { - ThreadPoolWorkQueue.Dispatch(); - if (s_tasksCanceled) + if (!s_checkScheduled && s_pollables.Count > 0) { - s_tasksCanceled = false; - return; + s_checkScheduled = true; + ThreadPool.UnsafeQueueUserWorkItem(CheckPollables, null); } + } + + internal static void CheckPollables(object? _) + { + s_checkScheduled = false; var holders = new List(s_pollables.Count); var pending = new List(s_pollables.Count); @@ -58,13 +113,28 @@ internal static void DispatchWasiEventLoop() if (pending.Count > 0) { + var resolvedPollableIndex = -1; + // if there is CPU-bound work to do, we should not block on PollInterop.Poll below + // so we will append pollable resolved in 0ms + // in effect, the PollInterop.Poll would not block us + if (ThreadPool.PendingWorkItemCount > 0 || (s_mainTask != null && s_mainTask.IsCompleted)) + { + s_resolvedPollable ??= MonotonicClockInterop.SubscribeDuration(0); + resolvedPollableIndex = pending.Count; + pending.Add(s_resolvedPollable); + } + var readyIndexes = PollInterop.Poll(pending); for (int i = 0; i < readyIndexes.Length; i++) { uint readyIndex = readyIndexes[i]; - var holder = holders[(int)readyIndex]; - holder.ResolveAndDispose(); + if (resolvedPollableIndex != readyIndex) + { + var holder = holders[(int)readyIndex]; + holder.ResolveAndDispose(); + } } + for (int i = 0; i < holders.Count; i++) { PollableHolder holder = holders[i]; @@ -73,6 +143,8 @@ internal static void DispatchWasiEventLoop() s_pollables.Add(holder); } } + + ScheduleCheck(); } } @@ -112,7 +184,7 @@ public void ResolveAndDispose() } // for GC of abandoned Tasks or for cancellation - private static void CancelAndDispose(object? s) + public static void CancelAndDispose(object? s) { PollableHolder self = (PollableHolder)s!; if (self.isDisposed) @@ -120,11 +192,6 @@ private static void CancelAndDispose(object? s) return; } - // Tell event loop to exit early, giving the application a - // chance to quit if the task(s) it is interested in have - // completed. - s_tasksCanceled = true; - // it will be removed from s_pollables on the next run self.isDisposed = true; self.pollable.Dispose(); diff --git a/src/libraries/System.Private.Uri/src/System/UriExt.cs b/src/libraries/System.Private.Uri/src/System/UriExt.cs index 6f2f61c76721d7..ee35d01e96232e 100644 --- a/src/libraries/System.Private.Uri/src/System/UriExt.cs +++ b/src/libraries/System.Private.Uri/src/System/UriExt.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Buffers; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; @@ -216,32 +217,49 @@ private void InitializeUri(ParsingError err, UriKind uriKind, out UriFormatExcep } } - // Unescapes entire string and checks if it has unicode chars - // Also checks for sequences that are 3986 Unreserved characters as these should be un-escaped + /// SearchValues for all ASCII characters other than % + private static readonly SearchValues s_asciiOtherThanPercent = SearchValues.Create( + "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\u000A\u000B\u000C\u000D\u000E\u000F" + + "\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001A\u001B\u001C\u001D\u001E\u001F" + + "\u0020\u0021\u0022\u0023\u0024" + "\u0026\u0027\u0028\u0029\u002A\u002B\u002C\u002D\u002E\u002F" + + "\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037\u0038\u0039\u003A\u003B\u003C\u003D\u003E\u003F" + + "\u0040\u0041\u0042\u0043\u0044\u0045\u0046\u0047\u0048\u0049\u004A\u004B\u004C\u004D\u004E\u004F" + + "\u0050\u0051\u0052\u0053\u0054\u0055\u0056\u0057\u0058\u0059\u005A\u005B\u005C\u005D\u005E\u005F" + + "\u0060\u0061\u0062\u0063\u0064\u0065\u0066\u0067\u0068\u0069\u006A\u006B\u006C\u006D\u006E\u006F" + + "\u0070\u0071\u0072\u0073\u0074\u0075\u0076\u0077\u0078\u0079\u007A\u007B\u007C\u007D\u007E\u007F"); + + /// + /// Unescapes entire string and checks if it has unicode chars.Also checks for sequences that are 3986 Unreserved characters as these should be un-escaped + /// private static bool CheckForUnicodeOrEscapedUnreserved(string data) { - for (int i = 0; i < data.Length; i++) + int i = data.AsSpan().IndexOfAnyExcept(s_asciiOtherThanPercent); + if (i >= 0) { - char c = data[i]; - if (c == '%') + for ( ; i < data.Length; i++) { - if ((uint)(i + 2) < (uint)data.Length) + char c = data[i]; + if (c == '%') { - char value = UriHelper.DecodeHexChars(data[i + 1], data[i + 2]); - - if (!char.IsAscii(value) || UriHelper.Unreserved.Contains(value)) + if ((uint)(i + 2) < (uint)data.Length) { - return true; - } + char value = UriHelper.DecodeHexChars(data[i + 1], data[i + 2]); + + if (!char.IsAscii(value) || UriHelper.Unreserved.Contains(value)) + { + return true; + } - i += 2; + i += 2; + } + } + else if (c > 0x7F) + { + return true; } - } - else if (c > 0x7F) - { - return true; } } + return false; } diff --git a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector128Tests.cs b/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector128Tests.cs index 27955248daac8c..09153068d91439 100644 --- a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector128Tests.cs +++ b/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector128Tests.cs @@ -36,7 +36,6 @@ internal static void AssertEqual(Vector128 expected, Vector128 a [Fact] [DynamicDependency(DynamicallyAccessedMemberTypes.PublicProperties, typeof(Vector128))] - [ActiveIssue("https://github.com/dotnet/runtime/issues/81785", TestPlatforms.Browser)] public unsafe void Vector128IsHardwareAcceleratedTest() { MethodInfo methodInfo = typeof(Vector128).GetMethod("get_IsHardwareAccelerated"); diff --git a/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs b/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs index a64b43d6884737..ea3ced24ee08e0 100644 --- a/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs +++ b/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs @@ -452,12 +452,40 @@ private static string EmitSearchValues(char[] chars, Dictionary "s_asciiExceptWhiteSpace", "FFFFFFFFFFFF00FC01000078010000F8" => "s_asciiExceptWordChars", + "FFFFFFFFFFDF00FCFFFFFFFFFFFFFFFF" => "s_asciiExceptDigitsAndDash", + "000000000040FF03FEFFFF07FEFFFF07" => "s_asciiLettersAndDigitsAndDot", + "000000000020FF03FEFFFF07FEFFFF07" => "s_asciiLettersAndDigitsAndDash", + "000000000060FF03FEFFFF07FEFFFF07" => "s_asciiLettersAndDigitsAndDashDot", + "000000000040FF03FEFFFF87FEFFFF07" => "s_asciiLettersAndDigitsAndDotUnderscore", + "000000000020FF03FEFFFF87FEFFFF07" => "s_asciiLettersAndDigitsAndDashUnderscore", + "000000000060FF03FEFFFF87FEFFFF07" => "s_asciiLettersAndDigitsAndDashDotUnderscore", + "000000000040FF030000000000000000" => "s_asciiDigitsAndDot", + "000000000020FF030000000000000000" => "s_asciiDigitsAndDash", + "0000000000200000FEFFFF07FEFFFF07" => "s_asciiLettersAndDash", + "0000000000000000FEFFFF87FEFFFF07" => "s_asciiLettersAndUnderscore", + "000000000000FF0300000000FEFFFF07" => "s_asciiLettersLowerAndDigits", + "000000000000FF03FEFFFF0700000000" => "s_asciiLettersUpperAndDigits", + "000000000020FF0300000000FEFFFF07" => "s_asciiLettersLowerAndDigitsAndDash", + _ => $"s_ascii_{hexBitmap.TrimStart('0')}" }; } else { fieldName = GetSHA256FieldName("s_nonAscii_", new string(chars)); + + fieldName = fieldName switch + { + "s_nonAscii_326E1FD0AD567A84CAD13F2BE521A57789829F59D59ABE37F9E111D0182B6601" => "s_asciiLettersAndKelvinSign", + "s_nonAscii_46E3FAA2E94950B9D41E9AB1B570CAB55D04A30009110072B4BC074D57272527" => "s_asciiLettersAndDigitsAndKelvinSign", + "s_nonAscii_2D5586687DC37F0329E3CA4127326E68B5A3A090B13B7834AEA7BFC4EDDE220F" => "s_asciiLettersAndDigitsAndDashKelvinSign", + "s_nonAscii_83AFA3CC45CC4C2D8C316947CFC319199813C7F90226BDF348E2B3236D6237C1" => "s_asciiLettersAndDigitsAndDashDotKelvinSign", + "s_nonAscii_9FA52D3BAECB644578472387D5284CC6F36F408FEB88A04BA674CE14F24D2386" => "s_asciiLettersAndDigitsAndUnderscoreKelvinSign", + "s_nonAscii_D41BEF0BEAFBA32A45D2356E3F1579596F35B7C67CAA9CF7C4B3F2A5422DCA51" => "s_asciiLettersAndDigitsAndDashUnderscoreKelvinSign", + "s_nonAscii_0D7E5600013B3F0349C00277028B6DEA566BB9BAF991CCB7AC92DEC54C4544C1" => "s_asciiLettersAndDigitsAndDashDotUnderscoreKelvinSign", + + _ => fieldName + }; } } diff --git a/src/mono/System.Private.CoreLib/src/System/Threading/ThreadPool.Wasi.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Threading/ThreadPool.Wasi.Mono.cs index bad9fbdbaaddf5..0d082fd863cb95 100644 --- a/src/mono/System.Private.CoreLib/src/System/Threading/ThreadPool.Wasi.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Threading/ThreadPool.Wasi.Mono.cs @@ -35,7 +35,7 @@ public static partial class ThreadPool { // Indicates whether the thread pool should yield the thread from the dispatch loop to the runtime periodically so that // the runtime may use the thread for processing other work - internal static bool YieldFromDispatchLoop => false; + internal static bool YieldFromDispatchLoop => true; private const bool IsWorkerTrackingEnabledInConfig = false; diff --git a/src/mono/browser/runtime/jiterpreter-jit-call.ts b/src/mono/browser/runtime/jiterpreter-jit-call.ts index f9ee806540c60f..48e9797cb29e8f 100644 --- a/src/mono/browser/runtime/jiterpreter-jit-call.ts +++ b/src/mono/browser/runtime/jiterpreter-jit-call.ts @@ -61,7 +61,6 @@ const maxJitQueueLength = 6, let trampBuilder: WasmBuilder; let fnTable: WebAssembly.Table; -let wasmEhSupported: boolean | undefined = undefined; let nextDisambiguateIndex = 0; const fnCache: Array = []; const targetCache: { [target: number]: TrampolineInfo } = {}; @@ -276,18 +275,6 @@ export function mono_interp_jit_wasm_jit_call_trampoline ( mono_interp_flush_jitcall_queue(); } -function getIsWasmEhSupported (): boolean { - if (wasmEhSupported !== undefined) - return wasmEhSupported; - - // Probe whether the current environment can handle wasm exceptions - wasmEhSupported = runtimeHelpers.featureWasmEh === true; - if (!wasmEhSupported) - mono_log_info("Disabling Jiterpreter Exception Handling"); - - return wasmEhSupported; -} - export function mono_interp_flush_jitcall_queue (): void { const jitQueue: TrampolineInfo[] = []; let methodPtr = 0; @@ -336,7 +323,7 @@ export function mono_interp_flush_jitcall_queue (): void { } if (builder.options.enableWasmEh) { - if (!getIsWasmEhSupported()) { + if (!runtimeHelpers.featureWasmEh) { // The user requested to enable wasm EH but it's not supported, so turn the option back off applyOptions({ enableWasmEh: false }); builder.options.enableWasmEh = false; diff --git a/src/mono/browser/runtime/jiterpreter-trace-generator.ts b/src/mono/browser/runtime/jiterpreter-trace-generator.ts index b994927d308d88..fb36b03e2cdfe6 100644 --- a/src/mono/browser/runtime/jiterpreter-trace-generator.ts +++ b/src/mono/browser/runtime/jiterpreter-trace-generator.ts @@ -449,10 +449,9 @@ export function generateWasmBody ( if (pruneOpcodes) { // We emit an unreachable opcode so that if execution somehow reaches a pruned opcode, we will abort // This should be impossible anyway but it's also useful to have pruning visible in the wasm - // FIXME: Ideally we would stop generating opcodes after the first unreachable, but that causes v8 to hang if (!hasEmittedUnreachable) builder.appendU8(WasmOpcode.unreachable); - // Each unreachable opcode could generate a bunch of native code in a bad wasm jit so generate nops after it + // Don't generate multiple unreachable opcodes in a row hasEmittedUnreachable = true; } break; @@ -467,7 +466,7 @@ export function generateWasmBody ( } case MintOpcode.MINT_LOCALLOC: { // dest - append_ldloca(builder, getArgU16(ip, 1)); + append_ldloca(builder, getArgU16(ip, 1), 0); // len append_ldloc(builder, getArgU16(ip, 2), WasmOpcode.i32_load); // frame @@ -648,10 +647,12 @@ export function generateWasmBody ( // locals[ip[1]] = &locals[ip[2]] const offset = getArgU16(ip, 2), flag = isAddressTaken(builder, offset), - destOffset = getArgU16(ip, 1); + destOffset = getArgU16(ip, 1), + // Size value stored for us by emit_compacted_instruction so we can do invalidation + size = getArgU16(ip, 3); if (!flag) mono_log_error(`${traceName}: Expected local ${offset} to have address taken flag`); - append_ldloca(builder, offset); + append_ldloca(builder, offset, size); append_stloc_tail(builder, destOffset, WasmOpcode.i32_store); // Record this ldloca as a known constant so that later uses of it turn into a lea, // and the wasm runtime can constant fold them with other constants. It's not uncommon @@ -875,9 +876,8 @@ export function generateWasmBody ( } case MintOpcode.MINT_LD_DELEGATE_METHOD_PTR: { - // FIXME: ldloca invalidation size - append_ldloca(builder, getArgU16(ip, 1), 8); - append_ldloca(builder, getArgU16(ip, 2), 8); + append_ldloca(builder, getArgU16(ip, 1), 4); + append_ldloca(builder, getArgU16(ip, 2), 4); builder.callImport("ld_del_ptr"); break; } @@ -1280,6 +1280,21 @@ export function generateWasmBody ( break; } + case MintOpcode.MINT_NEWARR: { + builder.block(); + append_ldloca(builder, getArgU16(ip, 1), 4); + const vtable = get_imethod_data(frame, getArgU16(ip, 3)); + builder.i32_const(vtable); + append_ldloc(builder, getArgU16(ip, 2), WasmOpcode.i32_load); + builder.callImport("newarr"); + // If the newarr operation succeeded, continue, otherwise bailout + builder.appendU8(WasmOpcode.br_if); + builder.appendULeb(0); + append_bailout(builder, ip, BailoutReason.AllocFailed); + builder.endBlock(); + break; + } + case MintOpcode.MINT_NEWOBJ_INLINED: { builder.block(); // MonoObject *o = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass)); @@ -1368,7 +1383,9 @@ export function generateWasmBody ( (builder.callHandlerReturnAddresses.length <= maxCallHandlerReturnAddresses) ) { // mono_log_info(`endfinally @0x${(ip).toString(16)}. return addresses:`, builder.callHandlerReturnAddresses.map(ra => (ra).toString(16))); - // FIXME: Clean this codegen up + // FIXME: Replace this with a chain of selects to more efficiently map from RA -> index, then + // a single jump table at the end to jump to the right place. This will generate much smaller + // code and be able to handle a larger number of return addresses. // Load ret_ip const clauseIndex = getArgU16(ip, 1), clauseDataOffset = get_imethod_clause_data_offset(frame, clauseIndex); @@ -1957,10 +1974,7 @@ function append_stloc_tail (builder: WasmBuilder, offset: number, opcodeOrPrefix // Pass bytesInvalidated=0 if you are reading from the local and the address will never be // used for writes -function append_ldloca (builder: WasmBuilder, localOffset: number, bytesInvalidated?: number) { - if (typeof (bytesInvalidated) !== "number") - bytesInvalidated = 512; - // FIXME: We need to know how big this variable is so we can invalidate the whole space it occupies +function append_ldloca (builder: WasmBuilder, localOffset: number, bytesInvalidated: number) { if (bytesInvalidated > 0) invalidate_local_range(localOffset, bytesInvalidated); builder.lea("pLocals", localOffset); @@ -2461,7 +2475,8 @@ function emit_sfieldop ( builder.ptr_const(pStaticData); // src append_ldloca(builder, localOffset, 0); - // FIXME: Use mono_gc_wbarrier_set_field_internal + // We don't need to use gc_wbarrier_set_field_internal here because there's no object + // reference, interp does a raw write builder.callImport("copy_ptr"); return true; case MintOpcode.MINT_LDSFLD_VT: { @@ -2888,7 +2903,6 @@ function emit_branch ( ); cwraps.mono_jiterp_boost_back_branch_target(destination); - // FIXME: Should there be a safepoint here? append_bailout(builder, destination, BailoutReason.BackwardBranch); modifyCounter(JiterpCounter.BackBranchesNotEmitted, 1); return true; @@ -3526,19 +3540,6 @@ function emit_arrayop (builder: WasmBuilder, frame: NativePointer, ip: MintOpcod return true; } -let wasmSimdSupported: boolean | undefined; - -function getIsWasmSimdSupported (): boolean { - if (wasmSimdSupported !== undefined) - return wasmSimdSupported; - - wasmSimdSupported = runtimeHelpers.featureWasmSimd === true; - if (!wasmSimdSupported) - mono_log_info("Disabling Jiterpreter SIMD"); - - return wasmSimdSupported; -} - function get_import_name ( builder: WasmBuilder, typeName: string, functionPtr: number @@ -3557,7 +3558,7 @@ function emit_simd ( ): boolean { // First, if compiling an intrinsic attempt to emit the special vectorized implementation // We only do this if SIMD is enabled since we'll be using the v128 opcodes. - if (builder.options.enableSimd && getIsWasmSimdSupported()) { + if (builder.options.enableSimd && runtimeHelpers.featureWasmSimd) { switch (argCount) { case 2: if (emit_simd_2(builder, ip, index)) @@ -3577,7 +3578,7 @@ function emit_simd ( // Fall back to a mix of non-vectorized wasm and the interpreter's implementation of the opcodes switch (opcode) { case MintOpcode.MINT_SIMD_V128_LDC: { - if (builder.options.enableSimd && getIsWasmSimdSupported()) { + if (builder.options.enableSimd && runtimeHelpers.featureWasmSimd) { builder.local("pLocals"); const view = localHeapViewU8().slice(ip + 4, ip + 4 + sizeOfV128); builder.v128_const(view); @@ -4034,7 +4035,6 @@ function emit_atomics ( if (!builder.options.enableAtomics) return false; - // FIXME: memory barrier might be worthwhile to implement // FIXME: We could probably unify most of the xchg/cmpxchg implementation into one implementation const xchg = xchgTable[opcode]; diff --git a/src/mono/browser/runtime/jiterpreter.ts b/src/mono/browser/runtime/jiterpreter.ts index f665d0cccc7dcf..996e7ed34f9d15 100644 --- a/src/mono/browser/runtime/jiterpreter.ts +++ b/src/mono/browser/runtime/jiterpreter.ts @@ -272,6 +272,7 @@ function getTraceImports () { ["ckovr_u4", "overflow_check_i4", getRawCwrap("mono_jiterp_overflow_check_u4")], importDef("newobj_i", getRawCwrap("mono_jiterp_try_newobj_inlined")), importDef("newstr", getRawCwrap("mono_jiterp_try_newstr")), + importDef("newarr", getRawCwrap("mono_jiterp_try_newarr")), importDef("ld_del_ptr", getRawCwrap("mono_jiterp_ld_delegate_method_ptr")), importDef("ldtsflda", getRawCwrap("mono_jiterp_ldtsflda")), importDef("conv", getRawCwrap("mono_jiterp_conv")), @@ -465,6 +466,15 @@ function initialize_builder (builder: WasmBuilder) { }, WasmValtype.i32, true ); + builder.defineType( + "newarr", + { + "ppDestination": WasmValtype.i32, + "vtable": WasmValtype.i32, + "length": WasmValtype.i32, + }, + WasmValtype.i32, true + ); builder.defineType( "localloc", { @@ -841,18 +851,6 @@ function generate_wasm ( // Get the exported trace function const fn = traceInstance.exports[traceName]; - // FIXME: Before threading can be supported, we will need to ensure that - // once we assign a function pointer index to a given trace, the trace is - // broadcast to all the JS workers and compiled + installed at the appropriate - // index in every worker's function pointer table. This also means that we - // would need to fill empty slots with a dummy function when growing the table - // so that any erroneous ENTERs will skip the opcode instead of crashing due - // to calling a null function pointer. - // Table grow operations will need to be synchronized between workers somehow, - // probably by storing the table size in a volatile global or something so that - // we know the range of indexes available to us and can ensure that threads - // independently jitting traces will not stomp on each other and all threads - // have a globally consistent view of which function pointer maps to each trace. rejected = false; let idx: number; @@ -985,7 +983,6 @@ export function mono_interp_tier_prepare_jiterpreter ( if (!mostRecentOptions) mostRecentOptions = getOptions(); - // FIXME: We shouldn't need this check if (!mostRecentOptions.enableTraces) return JITERPRETER_NOT_JITTED; else if (mostRecentOptions.wasmBytesLimit <= getCounter(JiterpCounter.BytesGenerated)) diff --git a/src/mono/browser/runtime/pinvoke.c b/src/mono/browser/runtime/pinvoke.c index eb422204826474..c82033cd2d85c1 100644 --- a/src/mono/browser/runtime/pinvoke.c +++ b/src/mono/browser/runtime/pinvoke.c @@ -23,39 +23,71 @@ mono_wasm_pinvoke_vararg_stub (void) /* This is just a stub used to mark vararg pinvokes */ } +int +table_compare_name (const void *t1, const void *t2) +{ + return strcmp (((PinvokeTable*)t1)->name, ((PinvokeTable*)t2)->name); +} + void* wasm_dl_lookup_pinvoke_table (const char *name) { - for (int i = 0; i < sizeof (pinvoke_tables) / sizeof (void*); ++i) { - if (!strcmp (name, pinvoke_names [i])) - return pinvoke_tables [i]; - } - return NULL; + PinvokeImport needle = { name, NULL }; + return bsearch (&needle, pinvoke_tables, (sizeof (pinvoke_tables) / sizeof (PinvokeTable)), sizeof (PinvokeTable), table_compare_name); } int wasm_dl_is_pinvoke_table (void *handle) { - for (int i = 0; i < sizeof (pinvoke_tables) / sizeof (void*); ++i) { - if (pinvoke_tables [i] == handle) { + for (int i = 0; i < sizeof (pinvoke_tables) / sizeof (PinvokeTable); ++i) { + if (&pinvoke_tables[i] == handle) { return 1; } } return 0; } +static int +export_compare_key (const void *k1, const void *k2) +{ + return strcmp (((UnmanagedExport*)k1)->key, ((UnmanagedExport*)k2)->key); +} + +static int +export_compare_key_and_token (const void *k1, const void *k2) +{ + UnmanagedExport *e1 = (UnmanagedExport*)k1; + UnmanagedExport *e2 = (UnmanagedExport*)k2; + + // first compare by key + int compare = strcmp (e1->key, e2->key); + if (compare) + return compare; + + // then by token + return (int)(e1->token - e2->token); +} + void* -wasm_dl_get_native_to_interp (const char *key, void *extra_arg) +wasm_dl_get_native_to_interp (uint32_t token, const char *key, void *extra_arg) { #ifdef GEN_PINVOKE - for (int i = 0; i < sizeof (wasm_native_to_interp_map) / sizeof (void*); ++i) { - if (!strcmp (wasm_native_to_interp_map [i], key)) { - void *addr = wasm_native_to_interp_funcs [i]; - wasm_native_to_interp_ftndescs [i] = *(InterpFtnDesc*)extra_arg; - return addr; - } + UnmanagedExport needle = { key, token, NULL }; + int count = (sizeof (wasm_native_to_interp_table) / sizeof (UnmanagedExport)); + + // comparison must match the one used in the PInvokeTableGenerator to ensure the same order + UnmanagedExport *result = bsearch (&needle, wasm_native_to_interp_table, count, sizeof (UnmanagedExport), export_compare_key_and_token); + if (!result) { + // assembly may have been trimmed / modified, try to find by key only + result = bsearch (&needle, wasm_native_to_interp_table, count, sizeof (UnmanagedExport), export_compare_key); } - return NULL; + + if (!result) + return NULL; + + void *addr = result->func; + wasm_native_to_interp_ftndescs [result - wasm_native_to_interp_table] = *(InterpFtnDesc*)extra_arg; + return addr; #else return NULL; #endif diff --git a/src/mono/browser/runtime/pinvoke.h b/src/mono/browser/runtime/pinvoke.h index a89030d92f4bec..a2d32dfa2c9c52 100644 --- a/src/mono/browser/runtime/pinvoke.h +++ b/src/mono/browser/runtime/pinvoke.h @@ -8,6 +8,18 @@ typedef struct { void *func; } PinvokeImport; +typedef struct { + const char *name; + PinvokeImport *imports; + int count; +} PinvokeTable; + +typedef struct { + const char *key; + uint32_t token; + void *func; +} UnmanagedExport; + typedef struct { void *func; void *arg; @@ -20,7 +32,7 @@ int wasm_dl_is_pinvoke_table (void *handle); void* -wasm_dl_get_native_to_interp (const char *key, void *extra_arg); +wasm_dl_get_native_to_interp (uint32_t token, const char *key, void *extra_arg); void mono_wasm_pinvoke_vararg_stub (void); @@ -45,6 +57,6 @@ double mono_wasm_interp_method_args_get_darg (MonoInterpMethodArguments *margs, int i); void* -mono_wasm_interp_method_args_get_retval (MonoInterpMethodArguments *margs); +mono_wasm_interp_method_args_get_retval (MonoInterpMethodArguments *margs); #endif diff --git a/src/mono/browser/runtime/runtime.c b/src/mono/browser/runtime/runtime.c index 2cf5b7605a5f7f..7e8851fcd6bc0d 100644 --- a/src/mono/browser/runtime/runtime.c +++ b/src/mono/browser/runtime/runtime.c @@ -199,29 +199,43 @@ init_icall_table (void) static void* get_native_to_interp (MonoMethod *method, void *extra_arg) { - void *addr; - + void *addr = NULL; MONO_ENTER_GC_UNSAFE; MonoClass *klass = mono_method_get_class (method); MonoImage *image = mono_class_get_image (klass); MonoAssembly *assembly = mono_image_get_assembly (image); MonoAssemblyName *aname = mono_assembly_get_name (assembly); const char *name = mono_assembly_name_get_name (aname); + const char *namespace = mono_class_get_namespace (klass); const char *class_name = mono_class_get_name (klass); const char *method_name = mono_method_get_name (method); - char key [128]; + MonoMethodSignature *sig = mono_method_signature (method); + uint32_t param_count = mono_signature_get_param_count (sig); + uint32_t token = mono_method_get_token (method); + + char buf [128]; + char *key = buf; int len; + if (name != NULL) { + // the key must match the one used in PInvokeTableGenerator + len = snprintf (key, sizeof(buf), "%s#%d:%s:%s:%s", method_name, param_count, name, namespace, class_name); + + if (len >= sizeof (buf)) { + // The key is too long, try again with a larger buffer + key = g_new (char, len + 1); + snprintf (key, len + 1, "%s#%d:%s:%s:%s", method_name, param_count, name, namespace, class_name); + } - assert (strlen (name) < 100); - snprintf (key, sizeof(key), "%s_%s_%s", name, class_name, method_name); - char *fixedName = mono_fixup_symbol_name ("", key, ""); - addr = wasm_dl_get_native_to_interp (fixedName, extra_arg); - free (fixedName); + addr = wasm_dl_get_native_to_interp (token, key, extra_arg); + + if (key != buf) + free (key); + } MONO_EXIT_GC_UNSAFE; return addr; } -static void *sysglobal_native_handle; +static void *sysglobal_native_handle = (void *)0xDeadBeef; static void* wasm_dl_load (const char *name, int flags, char **err, void *user_data) @@ -248,24 +262,33 @@ wasm_dl_load (const char *name, int flags, char **err, void *user_data) return NULL; } +int +import_compare_name (const void *k1, const void *k2) +{ + const PinvokeImport *e1 = (const PinvokeImport*)k1; + const PinvokeImport *e2 = (const PinvokeImport*)k2; + + return strcmp (e1->name, e2->name); +} + static void* wasm_dl_symbol (void *handle, const char *name, char **err, void *user_data) { - if (handle == sysglobal_native_handle) - assert (0); + assert (handle != sysglobal_native_handle); #if WASM_SUPPORTS_DLOPEN if (!wasm_dl_is_pinvoke_tables (handle)) { return dlsym (handle, name); } #endif - - PinvokeImport *table = (PinvokeImport*)handle; - for (int i = 0; table [i].name; ++i) { - if (!strcmp (table [i].name, name)) - return table [i].func; - } - return NULL; + PinvokeTable* index = (PinvokeTable*)handle; + PinvokeImport key = { name, NULL }; + PinvokeImport* result = (PinvokeImport *)bsearch(&key, index->imports, index->count, sizeof(PinvokeImport), import_compare_name); + if (!result) { + // *err = g_strdup_printf ("Symbol not found: %s", name); + return NULL; + } + return result->func; } MonoDomain * @@ -363,6 +386,28 @@ mono_wasm_assembly_find_method (MonoClass *klass, const char *name, int argument return result; } +MonoMethod* +mono_wasm_get_method_matching (MonoImage *image, uint32_t token, MonoClass *klass, const char* name, int param_count) +{ + MonoMethod *result = NULL; + MONO_ENTER_GC_UNSAFE; + MonoMethod *method = mono_get_method (image, token, klass); + MonoMethodSignature *sig = mono_method_signature (method); + // Lookp by token but verify the name and param count in case assembly was trimmed + if (mono_signature_get_param_count (sig) == param_count) { + const char *method_name = mono_method_get_name (method); + if (!strcmp (method_name, name)) { + result = method; + } + } + // If the token lookup failed, try to find the method by name and param count + if (!result) { + result = mono_class_get_method_from_name (klass, name, param_count); + } + MONO_EXIT_GC_UNSAFE; + return result; +} + /* * mono_wasm_marshal_get_managed_wrapper: * Creates a wrapper for a function pointer to a method marked with @@ -370,17 +415,21 @@ mono_wasm_assembly_find_method (MonoClass *klass, const char *name, int argument * This wrapper ensures that the interpreter initializes the pointers. */ void -mono_wasm_marshal_get_managed_wrapper (const char* assemblyName, const char* namespaceName, const char* typeName, const char* methodName, int num_params) +mono_wasm_marshal_get_managed_wrapper (const char* assemblyName, const char* namespaceName, const char* typeName, const char* methodName, uint32_t token, int param_count) { MonoError error; mono_error_init (&error); + MONO_ENTER_GC_UNSAFE; MonoAssembly* assembly = mono_wasm_assembly_load (assemblyName); assert (assembly); - MonoClass* class = mono_wasm_assembly_find_class (assembly, namespaceName, typeName); - assert (class); - MonoMethod* method = mono_wasm_assembly_find_method (class, methodName, num_params); + MonoImage *image = mono_assembly_get_image (assembly); + assert (image); + MonoClass* klass = mono_class_from_name (image, namespaceName, typeName); + assert (klass); + MonoMethod *method = mono_wasm_get_method_matching (image, token, klass, methodName, param_count); assert (method); MonoMethod *managedWrapper = mono_marshal_get_managed_wrapper (method, NULL, 0, &error); assert (managedWrapper); mono_compile_method (managedWrapper); -} + MONO_EXIT_GC_UNSAFE; +} \ No newline at end of file diff --git a/src/mono/browser/runtime/runtime.h b/src/mono/browser/runtime/runtime.h index f630762ded2173..e8591d0a19e206 100644 --- a/src/mono/browser/runtime/runtime.h +++ b/src/mono/browser/runtime/runtime.h @@ -19,7 +19,7 @@ MonoDomain *mono_wasm_load_runtime_common (int debug_level, MonoLogCallback log_ MonoAssembly *mono_wasm_assembly_load (const char *name); MonoClass *mono_wasm_assembly_find_class (MonoAssembly *assembly, const char *namespace, const char *name); MonoMethod *mono_wasm_assembly_find_method (MonoClass *klass, const char *name, int arguments); -void mono_wasm_marshal_get_managed_wrapper (const char* assemblyName, const char* namespaceName, const char* typeName, const char* methodName, int num_params); +void mono_wasm_marshal_get_managed_wrapper (const char* assemblyName, const char* namespaceName, const char* typeName, const char* methodName, uint32_t token, int param_count); int initialize_runtime (); #endif diff --git a/src/mono/browser/runtime/startup.ts b/src/mono/browser/runtime/startup.ts index 4d07e712358b08..834ceb81f2f7bb 100644 --- a/src/mono/browser/runtime/startup.ts +++ b/src/mono/browser/runtime/startup.ts @@ -128,6 +128,9 @@ async function instantiateWasmWorker ( successCallback: InstantiateWasmSuccessCallback ): Promise { if (!WasmEnableThreads) return; + + await ensureUsedWasmFeatures(); + // wait for the config to arrive by message from the main thread await loaderHelpers.afterConfigLoaded.promise; diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index 12f2cdd50350ee..1dda6c21648917 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -7657,7 +7657,8 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; MINT_IN_CASE(MINT_LDLOCA_S) LOCAL_VAR (ip [1], gpointer) = locals + ip [2]; - ip += 3; + // ip[3] reserved for size data for jiterpreter + ip += 4; MINT_IN_BREAK; #define MOV(argtype1,argtype2) \ diff --git a/src/mono/mono/mini/interp/jiterpreter-opcode-values.h b/src/mono/mono/mini/interp/jiterpreter-opcode-values.h index a509b8471cfa95..d360bceb0fc32b 100644 --- a/src/mono/mono/mini/interp/jiterpreter-opcode-values.h +++ b/src/mono/mono/mini/interp/jiterpreter-opcode-values.h @@ -98,6 +98,7 @@ OP(MINT_BOX, NORMAL) OP(MINT_BOX_VT, NORMAL) OP(MINT_UNBOX, NORMAL) OP(MINT_NEWSTR, NORMAL) +OP(MINT_NEWARR, NORMAL) OP(MINT_LD_DELEGATE_METHOD_PTR, NORMAL) OP(MINT_LDTSFLDA, NORMAL) OP(MINT_ADD_MUL_I4_IMM, NORMAL) diff --git a/src/mono/mono/mini/interp/jiterpreter.c b/src/mono/mono/mini/interp/jiterpreter.c index 362f01a2390b20..b63ec1b284e48f 100644 --- a/src/mono/mono/mini/interp/jiterpreter.c +++ b/src/mono/mono/mini/interp/jiterpreter.c @@ -202,6 +202,18 @@ mono_jiterp_try_newstr (MonoString **destination, int length) { return *destination != 0; } +EMSCRIPTEN_KEEPALIVE int +mono_jiterp_try_newarr (MonoArray **destination, MonoVTable *vtable, int length) { + if (length < 0) + return 0; + ERROR_DECL(error); + *destination = mono_array_new_specific_checked (vtable, length, error); + if (!is_ok (error)) + *destination = 0; + mono_error_cleanup (error); // FIXME: do not swallow the error + return *destination != 0; +} + EMSCRIPTEN_KEEPALIVE int mono_jiterp_gettype_ref ( MonoObject **destination, MonoObject **source diff --git a/src/mono/mono/mini/interp/mintops.def b/src/mono/mono/mini/interp/mintops.def index 11e65fb97ade69..5e2c41d60c47f1 100644 --- a/src/mono/mono/mini/interp/mintops.def +++ b/src/mono/mono/mini/interp/mintops.def @@ -128,7 +128,11 @@ OPDEF(MINT_MOV_8_2, "mov.8.2", 5, 0, 0, MintOpPair2) OPDEF(MINT_MOV_8_3, "mov.8.3", 7, 0, 0, MintOpPair3) OPDEF(MINT_MOV_8_4, "mov.8.4", 9, 0, 0, MintOpPair4) -OPDEF(MINT_LDLOCA_S, "ldloca.s", 3, 1, 0, MintOpUShortInt) +// NOTE: We reserve an extra ushort at the end of this specifically to communicate information +// to the jiterpreter about how large the local is so that invalidation can be correct. +// FIXME: genmintops.py is way too simple to handle this having a different size on different targets, +// so it's got a size of 4 everywhere. +OPDEF(MINT_LDLOCA_S, "ldloca.s", 4, 1, 0, MintOpUShortInt) OPDEF(MINT_LDIND_I1, "ldind.i1", 3, 1, 1, MintOpNoArgs) OPDEF(MINT_LDIND_U1, "ldind.u1", 3, 1, 1, MintOpNoArgs) @@ -838,7 +842,7 @@ OPDEF(MINT_INTRINS_WIDEN_ASCII_TO_UTF16, "intrins_widen_ascii_to_utf16", 5, 1, 3 OPDEF(MINT_METADATA_UPDATE_LDFLDA, "metadata_update.ldflda", 5, 1, 1, MintOpTwoShorts) // This ifdef is fine because genmintops.py is generating output for HOST_BROWSER -#if HOST_BROWSER +#ifdef HOST_BROWSER OPDEF(MINT_TIER_PREPARE_JITERPRETER, "tier_prepare_jiterpreter", 4, 0, 0, MintOpShortAndInt) OPDEF(MINT_TIER_NOP_JITERPRETER, "tier_nop_jiterpreter", 4, 0, 0, MintOpShortAndInt) OPDEF(MINT_TIER_ENTER_JITERPRETER, "tier_enter_jiterpreter", 4, 0, 0, MintOpShortAndInt) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index 4b1865b8310b53..22c5518a82c041 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -9241,6 +9241,12 @@ emit_compacted_instruction (TransformData *td, guint16* start_ip, InterpInst *in } else if (opcode == MINT_LDLOCA_S) { // This opcode receives a local but it is not viewed as a sreg since we don't load the value *ip++ = GINT_TO_UINT16 (get_var_offset (td, ins->sregs [0])); + +#if HOST_BROWSER + // We reserve an extra 2 bytes at the end of ldloca_s so the jiterpreter knows how large + // the var is when taking its address so that it can invalidate a properly sized range. + *ip++ = GINT_TO_UINT16 (td->vars [ins->sregs [0]].size); +#endif } int left = interp_get_ins_length (ins) - GPTRDIFF_TO_INT(ip - start_ip); diff --git a/src/mono/sample/wasi/http-p2/Program.cs b/src/mono/sample/wasi/http-p2/Program.cs index e940c0a4100b6b..9bf6140161db5b 100644 --- a/src/mono/sample/wasi/http-p2/Program.cs +++ b/src/mono/sample/wasi/http-p2/Program.cs @@ -13,6 +13,7 @@ public static class WasiMainWrapper { public static async Task MainAsync(string[] args) { + _ = Task.Delay(100_000_000); // create a task that will not complete before main await Task.Delay(100); GC.Collect(); // test that Pollable->Task is not collected until resolved @@ -78,7 +79,7 @@ public static int Main(string[] args) return PollWasiEventLoopUntilResolved((Thread)null!, MainAsync(args)); [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "PollWasiEventLoopUntilResolved")] - static extern int PollWasiEventLoopUntilResolved(Thread t, Task mainTask); + static extern T PollWasiEventLoopUntilResolved(Thread t, Task mainTask); } } diff --git a/src/mono/wasi/testassets/Http.cs b/src/mono/wasi/testassets/Http.cs index 49bc33f28fa3c5..87b1f8437f71f0 100644 --- a/src/mono/wasi/testassets/Http.cs +++ b/src/mono/wasi/testassets/Http.cs @@ -83,6 +83,6 @@ public static int Main(string[] args) return PollWasiEventLoopUntilResolved((Thread)null!, MainAsync(args)); [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "PollWasiEventLoopUntilResolved")] - static extern int PollWasiEventLoopUntilResolved(Thread t, Task mainTask); + static extern T PollWasiEventLoopUntilResolved(Thread t, Task mainTask); } } diff --git a/src/mono/wasm/Wasm.Build.Tests/PInvokeTableGeneratorTests.cs b/src/mono/wasm/Wasm.Build.Tests/PInvokeTableGeneratorTests.cs index eb0959fcdb6425..24715f44740baf 100644 --- a/src/mono/wasm/Wasm.Build.Tests/PInvokeTableGeneratorTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/PInvokeTableGeneratorTests.cs @@ -437,6 +437,71 @@ file class Foo Assert.Contains("Main running", output); } + [Theory] + [BuildAndRun(host: RunHost.Chrome)] + public void UnmanagedCallersOnly_Namespaced(BuildArgs buildArgs, RunHost host, string id) + { + string code = + """ + using System; + using System.Runtime.InteropServices; + + public class Test + { + public unsafe static int Main() + { + ((delegate* unmanaged)&A.Conflict.C)(); + ((delegate* unmanaged)&B.Conflict.C)(); + ((delegate* unmanaged)&A.Conflict.C\u733f)(); + ((delegate* unmanaged)&B.Conflict.C\u733f)(); + return 42; + } + } + + namespace A { + public class Conflict { + [UnmanagedCallersOnly(EntryPoint = "A_Conflict_C")] + public static void C() { + Console.WriteLine("A.Conflict.C"); + } + + [UnmanagedCallersOnly(EntryPoint = "A_Conflict_C\u733f")] + public static void C\u733f() { + Console.WriteLine("A.Conflict.C\U0001F412"); + } + } + } + + namespace B { + public class Conflict { + [UnmanagedCallersOnly(EntryPoint = "B_Conflict_C")] + public static void C() { + Console.WriteLine("B.Conflict.C"); + } + + [UnmanagedCallersOnly(EntryPoint = "B_Conflict_C\u733f")] + public static void C\u733f() { + Console.WriteLine("B.Conflict.C\U0001F412"); + } + } + } + """; + + (buildArgs, string output) = BuildForVariadicFunctionTests( + code, + buildArgs with { ProjectName = $"cb_namespace_{buildArgs.Config}" }, + id + ); + + Assert.DoesNotMatch(".*(warning|error).*>[A-Z0-9]+__Foo", output); + + output = RunAndTestWasmApp(buildArgs, buildDir: _projectDir, expectedExitCode: 42, host: host, id: id); + Assert.Contains("A.Conflict.C", output); + Assert.Contains("B.Conflict.C", output); + Assert.Contains("A.Conflict.C\U0001F412", output); + Assert.Contains("B.Conflict.C\U0001F412", output); + } + [Theory] [BuildAndRun(host: RunHost.None)] public void IcallWithOverloadedParametersAndEnum(BuildArgs buildArgs, string id) @@ -951,6 +1016,7 @@ public void UCOWithSpecialCharacters(BuildArgs buildArgs, RunHost host, string i DotnetWasmFromRuntimePack: false)); var runOutput = RunAndTestWasmApp(buildArgs, buildDir: _projectDir, expectedExitCode: 42, host: host, id: id); + Assert.DoesNotContain("Conflict.A.Managed8\u4F60Func(123) -> 123", runOutput); Assert.Contains("ManagedFunc returned 42", runOutput); } } diff --git a/src/mono/wasm/testassets/Wasm.Buid.Tests.Programs/UnmanagedCallback.cs b/src/mono/wasm/testassets/Wasm.Buid.Tests.Programs/UnmanagedCallback.cs index 2157909c3d5fc6..623cd2c5cb707d 100644 --- a/src/mono/wasm/testassets/Wasm.Buid.Tests.Programs/UnmanagedCallback.cs +++ b/src/mono/wasm/testassets/Wasm.Buid.Tests.Programs/UnmanagedCallback.cs @@ -6,13 +6,24 @@ public unsafe partial class Test public unsafe static int Main(string[] args) { ((IntPtr)(delegate* unmanaged)&Interop.Managed8\u4F60Func).ToString(); - Console.WriteLine($"main: {args.Length}"); Interop.UnmanagedFunc(); + return 42; } } +namespace Conflict.A { + file class Interop { + [UnmanagedCallersOnly(EntryPoint = "ConflictManagedFunc")] + public static int Managed8\u4F60Func(int number) + { + Console.WriteLine($"Conflict.A.Managed8\u4F60Func({number}) -> {number}"); + return number; + } + } +} + file partial class Interop { [UnmanagedCallersOnly(EntryPoint = "ManagedFunc")] diff --git a/src/mono/wasm/testassets/native-libs/local.c b/src/mono/wasm/testassets/native-libs/local.c index 4d7a660513c1fb..df7987bb8f38df 100644 --- a/src/mono/wasm/testassets/native-libs/local.c +++ b/src/mono/wasm/testassets/native-libs/local.c @@ -7,4 +7,4 @@ void UnmanagedFunc() printf("UnmanagedFunc calling ManagedFunc\n"); ret = ManagedFunc(123); printf("ManagedFunc returned %d\n", ret); -} \ No newline at end of file +} diff --git a/src/native/corehost/fxr/fx_resolver.cpp b/src/native/corehost/fxr/fx_resolver.cpp index e78bd63eca1096..c109fa257121c7 100644 --- a/src/native/corehost/fxr/fx_resolver.cpp +++ b/src/native/corehost/fxr/fx_resolver.cpp @@ -540,7 +540,7 @@ StatusCode fx_resolver_t::resolve_frameworks_for_app( _X("Architecture: %s"), app_display_name, get_current_arch_name()); - display_missing_framework_error(resolution_failure.missing.get_fx_name(), resolution_failure.missing.get_fx_version(), pal::string_t(), dotnet_root, app_config.get_is_multilevel_lookup_disabled()); + display_missing_framework_error(resolution_failure.missing.get_fx_name(), resolution_failure.missing.get_fx_version(), dotnet_root, app_config.get_is_multilevel_lookup_disabled()); break; case StatusCode::FrameworkCompatFailure: display_incompatible_framework_error(resolution_failure.incompatible_higher.get_fx_version(), resolution_failure.incompatible_lower); diff --git a/src/native/corehost/fxr/fx_resolver.h b/src/native/corehost/fxr/fx_resolver.h index 466decd846fc90..9abfd706baadc1 100644 --- a/src/native/corehost/fxr/fx_resolver.h +++ b/src/native/corehost/fxr/fx_resolver.h @@ -64,7 +64,6 @@ class fx_resolver_t static void display_missing_framework_error( const pal::string_t& fx_name, const pal::string_t& fx_version, - const pal::string_t& fx_dir, const pal::string_t& dotnet_root, bool disable_multilevel_lookup); static void display_incompatible_framework_error( diff --git a/src/native/corehost/fxr/fx_resolver.messages.cpp b/src/native/corehost/fxr/fx_resolver.messages.cpp index e87cd6d0fbacb4..a922858ae5b390 100644 --- a/src/native/corehost/fxr/fx_resolver.messages.cpp +++ b/src/native/corehost/fxr/fx_resolver.messages.cpp @@ -3,6 +3,7 @@ #include "fx_resolver.h" #include "framework_info.h" +#include "install_info.h" /** * When the framework is referenced more than once in a non-compatible way, display detailed error message @@ -92,23 +93,9 @@ void fx_resolver_t::display_summary_of_frameworks( void fx_resolver_t::display_missing_framework_error( const pal::string_t& fx_name, const pal::string_t& fx_version, - const pal::string_t& fx_dir, const pal::string_t& dotnet_root, bool disable_multilevel_lookup) { - std::vector framework_infos; - pal::string_t fx_ver_dirs; - if (fx_dir.length()) - { - fx_ver_dirs = fx_dir; - framework_info::get_all_framework_infos(get_directory(fx_dir), fx_name.c_str(), disable_multilevel_lookup, &framework_infos); - } - else - { - fx_ver_dirs = dotnet_root; - } - - framework_info::get_all_framework_infos(dotnet_root, fx_name.c_str(), disable_multilevel_lookup, &framework_infos); // Display the error message about missing FX. if (fx_version.length()) @@ -122,6 +109,8 @@ void fx_resolver_t::display_missing_framework_error( trace::error(_X(".NET location: %s\n"), dotnet_root.c_str()); + std::vector framework_infos; + framework_info::get_all_framework_infos(dotnet_root, fx_name.c_str(), disable_multilevel_lookup, &framework_infos); if (framework_infos.size()) { trace::error(_X("The following frameworks were found:")); @@ -135,6 +124,30 @@ void fx_resolver_t::display_missing_framework_error( trace::error(_X("No frameworks were found.")); } + std::vector>> other_arch_framework_infos; + install_info::enumerate_other_architectures( + [&](pal::architecture arch, const pal::string_t& install_location, bool is_registered) + { + std::vector other_arch_infos; + framework_info::get_all_framework_infos(install_location, fx_name.c_str(), disable_multilevel_lookup, &other_arch_infos); + if (!other_arch_infos.empty()) + { + other_arch_framework_infos.push_back(std::make_pair(arch, std::move(other_arch_infos))); + } + }); + if (!other_arch_framework_infos.empty()) + { + trace::error(_X("\nThe following frameworks for other architectures were found:")); + for (const auto& arch_info_pair : other_arch_framework_infos) + { + trace::error(_X(" %s"), get_arch_name(arch_info_pair.first)); + for (const framework_info& info : arch_info_pair.second) + { + trace::error(_X(" %s at [%s]"), info.version.as_str().c_str(), info.path.c_str()); + } + } + } + pal::string_t url = get_download_url(fx_name.c_str(), fx_version.c_str()); trace::error( _X("\n") diff --git a/src/native/corehost/fxr/install_info.cpp b/src/native/corehost/fxr/install_info.cpp index ff231938db0d87..281457f115820f 100644 --- a/src/native/corehost/fxr/install_info.cpp +++ b/src/native/corehost/fxr/install_info.cpp @@ -31,7 +31,7 @@ bool install_info::print_environment(const pal::char_t* leading_whitespace) return found_any; } -bool install_info::print_other_architectures(const pal::char_t* leading_whitespace) +bool install_info::enumerate_other_architectures(std::function callback) { bool found_any = false; for (uint32_t i = 0; i < static_cast(pal::architecture::__last); ++i) @@ -47,13 +47,22 @@ bool install_info::print_other_architectures(const pal::char_t* leading_whitespa { found_any = true; remove_trailing_dir_separator(&install_location); + callback(arch, install_location, is_registered); + } + } + + return found_any; +} + +bool install_info::print_other_architectures(const pal::char_t* leading_whitespace) +{ + return enumerate_other_architectures( + [&](pal::architecture arch, const pal::string_t& install_location, bool is_registered) + { trace::println(_X("%s%-5s [%s]"), leading_whitespace, get_arch_name(arch), install_location.c_str()); if (is_registered) { trace::println(_X("%s registered at [%s]"), leading_whitespace, pal::get_dotnet_self_registered_config_location(arch).c_str()); } - } - } - - return found_any; + }); } diff --git a/src/native/corehost/fxr/install_info.h b/src/native/corehost/fxr/install_info.h index 3a100486b8f3e5..3f9d5910268487 100644 --- a/src/native/corehost/fxr/install_info.h +++ b/src/native/corehost/fxr/install_info.h @@ -5,9 +5,11 @@ #define __INSTALL_INFO_H__ #include "pal.h" +#include namespace install_info { + bool enumerate_other_architectures(std::function callback); bool print_environment(const pal::char_t* leading_whitespace); bool print_other_architectures(const pal::char_t* leading_whitespace); }; diff --git a/src/native/corehost/hostmisc/utils.h b/src/native/corehost/hostmisc/utils.h index 5d782a070f8b8e..52c6754d290a7f 100644 --- a/src/native/corehost/hostmisc/utils.h +++ b/src/native/corehost/hostmisc/utils.h @@ -10,13 +10,6 @@ #include #include -#if defined(_WIN32) -#define DOTNET_CORE_INSTALL_PREREQUISITES_URL _X("https://go.microsoft.com/fwlink/?linkid=798306") -#elif defined(TARGET_OSX) -#define DOTNET_CORE_INSTALL_PREREQUISITES_URL _X("https://go.microsoft.com/fwlink/?linkid=2063366") -#else -#define DOTNET_CORE_INSTALL_PREREQUISITES_URL _X("https://go.microsoft.com/fwlink/?linkid=2063370") -#endif #define DOTNET_CORE_DOWNLOAD_URL _X("https://aka.ms/dotnet/download") #define DOTNET_CORE_APPLAUNCH_URL _X("https://aka.ms/dotnet-core-applaunch") diff --git a/src/tasks/AotCompilerTask/MonoAOTCompiler.cs b/src/tasks/AotCompilerTask/MonoAOTCompiler.cs index 89241ebdd85f46..e6dfe75f3a8a05 100644 --- a/src/tasks/AotCompilerTask/MonoAOTCompiler.cs +++ b/src/tasks/AotCompilerTask/MonoAOTCompiler.cs @@ -16,6 +16,8 @@ using Microsoft.Build.Utilities; using System.Reflection.PortableExecutable; +using JoinedString; + public class MonoAOTCompiler : Microsoft.Build.Utilities.Task { /// @@ -714,16 +716,12 @@ private PrecompileArguments GetPrecompileArgumentsFor(ITaskItem assemblyItem, st if (DirectPInvokes.Length > 0) { - var directPInvokesSB = new StringBuilder("direct-pinvokes="); - Array.ForEach(DirectPInvokes, directPInvokeItem => directPInvokesSB.Append($"{directPInvokeItem.ItemSpec};")); - aotArgs.Add(directPInvokesSB.ToString()); + aotArgs.Add($$"""direct-pinvokes={{DirectPInvokes.Join("", d => $"{d.ItemSpec};")}}"""); } if (DirectPInvokeLists.Length > 0) { - var directPInvokeListsSB = new StringBuilder("direct-pinvoke-lists="); - Array.ForEach(DirectPInvokeLists, directPInvokeListItem => directPInvokeListsSB.Append($"{directPInvokeListItem.GetMetadata("FullPath")};")); - aotArgs.Add(directPInvokeListsSB.ToString()); + aotArgs.Add($$"""direct-pinvoke-lists={{DirectPInvokeLists.Join("", d => $"{d.GetMetadata("FullPath")};")}}"""); } if (UseDwarfDebug) @@ -1109,62 +1107,66 @@ private bool GenerateAotModulesTable(IEnumerable assemblies, string[] Directory.CreateDirectory(Path.GetDirectoryName(outputFile)!); using TempFileName tmpAotModulesTablePath = new(); - using (var writer = File.CreateText(tmpAotModulesTablePath.Path)) + using (var writer = new JoinedStringStreamWriter(tmpAotModulesTablePath.Path, false)) { if (parsedAotModulesTableLanguage == MonoAotModulesTableLanguage.C) { - writer.WriteLine("#include "); - - foreach (var symbol in symbols) - { - writer.WriteLine($"extern void *{symbol};"); - } - writer.WriteLine("void register_aot_modules (void);"); - writer.WriteLine("void register_aot_modules (void)"); - writer.WriteLine("{"); - foreach (var symbol in symbols) - { - writer.WriteLine($"\tmono_aot_register_module ({symbol});"); - } - writer.WriteLine("}"); - - foreach (var profiler in profilers ?? Enumerable.Empty()) - { - writer.WriteLine($"void mono_profiler_init_{profiler} (const char *desc);"); - writer.WriteLine("EMSCRIPTEN_KEEPALIVE void mono_wasm_load_profiler_" + profiler + " (const char *desc) { mono_profiler_init_" + profiler + " (desc); }"); - } - - if (parsedAotMode == MonoAotMode.LLVMOnly) - { - writer.WriteLine("#define EE_MODE_LLVMONLY 1"); - } - - if (parsedAotMode == MonoAotMode.LLVMOnlyInterp) - { - writer.WriteLine("#define EE_MODE_LLVMONLY_INTERP 1"); - } + profilers ??= Array.Empty(); + writer.Write( + $$""" + #include " + {{symbols.Join(writer.NewLine, s => + $"extern void *{s};") + }} + + void register_aot_modules (void); + void register_aot_modules (void) + { + {{symbols.Join(writer.NewLine, s => + $" mono_aot_register_module ({s});") + }} + } + + {{profilers.Join(writer.NewLine, profiler => + $$$"""" + void mono_profiler_init_{{{profiler}}} (const char *desc); + EMSCRIPTEN_KEEPALIVE void mono_wasm_load_profiler_{{{profiler}}} (const char *desc) + { + mono_profiler_init_{{{profiler}}} (desc); + } + """") + }} + + {{parsedAotMode switch + { + MonoAotMode.LLVMOnly => "#define EE_MODE_LLVMONLY 1", + MonoAotMode.LLVMOnlyInterp => "#define EE_MODE_LLVMONLY_INTERP 1", + _ => "" + } + }} + """); } else if (parsedAotModulesTableLanguage == MonoAotModulesTableLanguage.ObjC) { - writer.WriteLine("#include "); - writer.WriteLine("#include "); - writer.WriteLine(""); - writer.WriteLine("#if TARGET_OS_IPHONE && (!TARGET_IPHONE_SIMULATOR || FORCE_AOT)"); - - foreach (var symbol in symbols) - { - writer.WriteLine($"extern void *{symbol};"); - } - - writer.WriteLine("void register_aot_modules (void);"); - writer.WriteLine("void register_aot_modules (void)"); - writer.WriteLine("{"); - foreach (var symbol in symbols) - { - writer.WriteLine($"\tmono_aot_register_module ({symbol});"); - } - writer.WriteLine("}"); - writer.WriteLine("#endif"); + writer.Write( + $$""" + #include + #include + + #if TARGET_OS_IPHONE && (!TARGET_IPHONE_SIMULATOR || FORCE_AOT) + {{symbols.Join(writer.NewLine, s => + $"extern void *{s};") + }} + + void register_aot_modules (void); + void register_aot_modules (void) + { + {{symbols.Join(writer.NewLine, s => + $" mono_aot_register_module ({s});") + }} + } + #endif + """); } else { diff --git a/src/tasks/AotCompilerTask/MonoAOTCompiler.csproj b/src/tasks/AotCompilerTask/MonoAOTCompiler.csproj index 0afdb5563cc660..288fa81b94c262 100644 --- a/src/tasks/AotCompilerTask/MonoAOTCompiler.csproj +++ b/src/tasks/AotCompilerTask/MonoAOTCompiler.csproj @@ -24,6 +24,8 @@ + + diff --git a/src/tasks/Common/JoinedString.cs b/src/tasks/Common/JoinedString.cs new file mode 100644 index 00000000000000..fea81cc88f729a --- /dev/null +++ b/src/tasks/Common/JoinedString.cs @@ -0,0 +1,182 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.IO; +using System.Runtime.CompilerServices; +using System.Collections; +using System.Collections.Generic; +using System.Text; + +namespace JoinedString; + +internal static class JoinedStringExtensions +{ + public static ConcatinatedString Join(this IEnumerable list, string separator) + => ConcatinatedString.Join(list, separator); + public static ConcatinatedString Join(this IEnumerable list, string separator, Func formatter) + => ConcatinatedString.Join(list, separator, formatter); + public static ConcatinatedString Join(this IEnumerable list, string separator, Func formatter) + => ConcatinatedString.Join(list, separator, formatter); + + public static JoinedList Join(this IList list, string separator) + => new JoinedList(list, separator, (item, _) => $"{item}"); + public static JoinedList Join(this IList list, string separator, Func formatter) + => new JoinedList(list, separator, (str, _) => formatter(str)); + public static JoinedList Join(this IList list, string separator, Func formatter) + => new JoinedList(list, separator, formatter); +} + +internal sealed record JoinedList(IList items, string separator, Func formatter) : IStringSegments +{ + public IEnumerator GetEnumerator() + { + bool hasSeparator = !string.IsNullOrEmpty(separator); + + for (int i = 0; i < items.Count; i++) + { + if (hasSeparator && i != 0) + yield return separator; + yield return formatter(items[i], i); + } + } + + public override string ToString() + { + var sb = new StringBuilder(); + foreach (var item in this) + { + sb.Append(item); + } + return sb.ToString(); + } +} + +internal interface IStringSegments { + public IEnumerator GetEnumerator(); +} + +internal sealed class ConcatinatedString : IStringSegments, IEnumerable +{ + private readonly IEnumerable _values; + + public ConcatinatedString(IEnumerable values) + { + _values = values; + } + + public static ConcatinatedString Join(IEnumerable values, string separator) + => new ConcatinatedString(JoinInternal(values, separator, (x, _) => x)); + + public static ConcatinatedString Join(IEnumerable values, string separator, Func format) + => new ConcatinatedString(JoinInternal(values, separator, (x, _) => format(x))); + + public static ConcatinatedString Join(IEnumerable values, string separator, Func format) + => new ConcatinatedString(JoinInternal(values, separator, format)); + + private static IEnumerable JoinInternal(IEnumerable values, string separator, Func format) + { + int index = 0; + bool hasSeparator = !string.IsNullOrEmpty(separator); + + foreach (var value in values) + { + if (hasSeparator && index != 0) + yield return separator; + yield return format(value, index++); + } + } + + public IEnumerator GetEnumerator() => _values.GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)_values).GetEnumerator(); + + public override string ToString() + { + var sb = new StringBuilder(); + foreach (var item in this) + { + sb.Append(item); + } + return sb.ToString(); + } +} + +internal sealed class JoinedStringStreamWriter : StreamWriter +{ + // since we are intentionally using multi-line string writes, + // we want to capture the compile-time new line + private string CompileTimeNewLine = @" +"; + + public JoinedStringStreamWriter(Stream stream) : base(stream) + { + NewLine = CompileTimeNewLine; + } + + public JoinedStringStreamWriter(string path, bool append) : base(path, append) + { + NewLine = CompileTimeNewLine; + } + +#if NET8_0_OR_GREATER +#pragma warning disable CA1822 // Mark members as static +#pragma warning disable IDE0060 // Remove unused parameter + public void Write([InterpolatedStringHandlerArgument("")] StringSegmentStreamWriterHandler builder) + { + // The builder writes directly to the writer + } +#pragma warning restore IDE0060 +#pragma warning restore CA1822 +#endif + + public void Write(IStringSegments list) + { + foreach (var item in list) + { + Write(item); + } + } + + public void WriteLine(IStringSegments list) + { + foreach (var item in list) + { + Write(item); + } + WriteLine(); + } +} + +#if NET8_0_OR_GREATER +[InterpolatedStringHandler] +internal ref struct StringSegmentStreamWriterHandler +{ + private JoinedStringStreamWriter _writer; + +#pragma warning disable IDE0060 + public StringSegmentStreamWriterHandler(int literalLength, int formattedCount, JoinedStringStreamWriter writer) + { + _writer = writer; + } +#pragma warning restore IDE0060 + + public void AppendLiteral(string s) => _writer.Write(s); + public void AppendFormatted(T value) => _writer.Write(value); + public void AppendFormatted(Span value) => _writer.Write(value); + public void AppendFormatted(char[] buffer, int index, int count) => _writer.Write(buffer, index, count); + public void AppendFormatted(string format, object? arg0, object? arg1, object? arg2) => _writer.Write(format, arg0, arg1, arg2); + + public void AppendFormatted(IStringSegments list) + { + foreach (var item in list) + { + _writer.Write(item); + } + } + + public override string ToString() + {; + return ""; + } +} +#endif diff --git a/src/tasks/MonoTargetsTasks/ILStrip/ILStrip.cs b/src/tasks/MonoTargetsTasks/ILStrip/ILStrip.cs index 1814cba54eb18d..34cc69f7752839 100644 --- a/src/tasks/MonoTargetsTasks/ILStrip/ILStrip.cs +++ b/src/tasks/MonoTargetsTasks/ILStrip/ILStrip.cs @@ -127,13 +127,14 @@ private bool StripAssembly(ITaskItem assemblyItem) try { - if(!AssemblyStripper.AssemblyStripper.TryStripAssembly(assemblyFile, outputPath)) + if (!AssemblyStripper.AssemblyStripper.TryStripAssembly(assemblyFile, outputPath)) { Log.LogMessage(MessageImportance.Low, $"[ILStrip] Skipping {assemblyFile} because it is not a managed assembly."); } else { - _processedAssemblies.GetOrAdd(assemblyItem.ItemSpec, GetTrimmedAssemblyItem(assemblyItem, outputPath, assemblyFile)); + var fullPath = assemblyItem.GetMetadata("FullPath"); + _processedAssemblies.GetOrAdd(fullPath, GetTrimmedAssemblyItem(assemblyItem, outputPath, assemblyFile)); } } catch (Exception ex) diff --git a/src/tasks/WasmAppBuilder/IcallTableGenerator.cs b/src/tasks/WasmAppBuilder/IcallTableGenerator.cs index bd90bb31199e05..5d4d3ec7ede384 100644 --- a/src/tasks/WasmAppBuilder/IcallTableGenerator.cs +++ b/src/tasks/WasmAppBuilder/IcallTableGenerator.cs @@ -11,6 +11,7 @@ using Microsoft.Build.Framework; using Microsoft.Build.Utilities; using WasmAppBuilder; +using JoinedString; internal sealed class IcallTableGenerator { @@ -48,7 +49,7 @@ public IEnumerable Generate(string? outputPath) if (outputPath != null) { using TempFileName tmpFileName = new(); - using (var w = File.CreateText(tmpFileName.Path)) + using (var w = new JoinedStringStreamWriter(tmpFileName.Path, false)) EmitTable(w); if (Utils.CopyIfDifferent(tmpFileName.Path, outputPath, useHash: false)) @@ -71,30 +72,28 @@ private void EmitTable(StreamWriter w) var sorted = _icalls.Where(i => i.Assembly == assembly).ToArray(); Array.Sort(sorted); - string aname; - if (assembly == "System.Private.CoreLib") - aname = "corlib"; - else - aname = _fixupSymbolName(assembly); - w.WriteLine($"#define ICALL_TABLE_{aname} 1\n"); - - w.WriteLine($"static int {aname}_icall_indexes [] = {{"); - foreach (var icall in sorted) - w.WriteLine(string.Format("{0},", icall.TokenIndex)); - w.WriteLine("};"); - foreach (var icall in sorted) - w.WriteLine(GenIcallDecl(icall)); - w.WriteLine($"static void *{aname}_icall_funcs [] = {{"); - foreach (var icall in sorted) - { - w.WriteLine(string.Format("// token {0},", icall.TokenIndex)); - w.WriteLine(string.Format("{0},", icall.Func)); - } - w.WriteLine("};"); - w.WriteLine($"static uint8_t {aname}_icall_flags [] = {{"); - foreach (var icall in sorted) - w.WriteLine(string.Format("{0},", icall.Flags)); - w.WriteLine("};"); + string aname = assembly == "System.Private.CoreLib" ? "corlib" : _fixupSymbolName(assembly); + + w.Write( + $$""" + + #define ICALL_TABLE_{{aname}} 1 + + static int {{aname}}_icall_indexes [] = { + {{sorted.Join($",{w.NewLine} ", (icall, i) => $"/* {i} */ {icall.TokenIndex}")}} + }; + + {{sorted.Join($" {w.NewLine}", GenIcallDecl)}} + + static void *{{aname}}_icall_funcs [] = { + {{sorted.Join($",{w.NewLine} ", (icall, i) => $"/* {i}:{icall.TokenIndex} */ {icall.Func}" )}} + }; + + static uint8_t {{aname}}_icall_flags [] = { + {{sorted.Join($",{w.NewLine} ", (icall, i) => $"/* {i}:{icall.TokenIndex} */ {icall.Flags}")}} + }; + + """); } } @@ -275,33 +274,18 @@ private void AppendType(StringBuilder sb, Type t) _ => "int", }; + private static string GenIcallDecl(Icall icall) { - var sb = new StringBuilder(); + List args = new(); var method = icall.Method!; - sb.Append(MapType(method.ReturnType)); - sb.Append($" {icall.Func} ("); - int aindex = 0; if (!method.IsStatic) - { - sb.Append("int"); - aindex++; - } - foreach (var p in method.GetParameters()) - { - if (aindex > 0) - sb.Append(','); - sb.Append(MapType(p.ParameterType)); - aindex++; - } + args.Add("int"); + args.AddRange(method.GetParameters().Select(p => MapType(p.ParameterType))); if (icall.Handles) - { - if (aindex > 0) - sb.Append(','); - sb.Append("int"); - } - sb.Append(");"); - return sb.ToString(); + args.Add("int"); + + return $"{MapType(method.ReturnType)} {icall.Func} ({args.Join(", ")});"; } private sealed class Icall : IComparable diff --git a/src/tasks/WasmAppBuilder/InterpToNativeGenerator.cs b/src/tasks/WasmAppBuilder/InterpToNativeGenerator.cs index 7dfcab267a8431..ad8a6a7df38745 100644 --- a/src/tasks/WasmAppBuilder/InterpToNativeGenerator.cs +++ b/src/tasks/WasmAppBuilder/InterpToNativeGenerator.cs @@ -12,6 +12,7 @@ using System.Diagnostics.CodeAnalysis; using WasmAppBuilder; +using JoinedString; // // This class generates the icall_trampoline_dispatch () function used by the interpreter to call native code on WASM. // It should be kept in sync with mono_wasm_interp_to_native_trampoline () in the runtime. @@ -41,7 +42,22 @@ public void Generate(IEnumerable cookies, string outputPath) private static void Emit(StreamWriter w, IEnumerable cookies) { - w.WriteLine(""" + // Use OrderBy because Order() is not available in net472 + var signatures = cookies.OrderBy(c => c).Distinct().ToArray(); + Array.Sort(signatures, StringComparer.Ordinal); + + + static IEnumerable Args (string signature) + { + for (int i = 1; i < signature.Length; ++i) + yield return signature[i]; + } + + static (bool isVoid, string nativeType) Result (string signature) + => new (SignatureMapper.IsVoidSignature(signature), SignatureMapper.CharToNativeType(signature[0])); + + w.Write( + """ /* * GENERATED FILE, DON'T EDIT * Generated by InterpToNativeGenerator @@ -49,55 +65,37 @@ private static void Emit(StreamWriter w, IEnumerable cookies) #include "pinvoke.h" #include + """); - // Use OrderBy because Order() is not available in net472 - var signatures = cookies.OrderBy(c => c).Distinct().ToArray(); foreach (var signature in signatures) { try { - w.WriteLine("static void"); - w.WriteLine($"wasm_invoke_{signature.ToLower(CultureInfo.InvariantCulture)} (void *target_func, MonoInterpMethodArguments *margs)"); - w.WriteLine("{"); - - w.Write($"\ttypedef {SignatureMapper.CharToNativeType(signature[0])} (*T)("); - for (int i = 1; i < signature.Length; ++i) - { - char p = signature[i]; - if (i > 1) - w.Write(", "); - w.Write($"{SignatureMapper.CharToNativeType(p)} arg_{i - 1}"); - } - - if (signature.Length == 1) - w.Write("void"); - - w.WriteLine(");\n\tT func = (T)target_func;"); - var ctx = new EmitCtx(); - - w.Write("\t"); - if (!SignatureMapper.IsVoidSignature(signature)) - w.Write($"{SignatureMapper.CharToNativeType(signature[0])} res = "); - - w.Write("func ("); - for (int i = 1; i < signature.Length; ++i) - { - char p = signature[i]; - if (i > 1) - w.Write(", "); - w.Write(ctx.Emit(p)); - } - w.WriteLine(");"); - - if (!SignatureMapper.IsVoidSignature(signature)) - { - w.WriteLine($"\tvoid *retval = mono_wasm_interp_method_args_get_retval (margs);"); - w.WriteLine($"\t*({SignatureMapper.CharToNativeType(signature[0])}*)retval = res;"); - } - - w.WriteLine("}\n"); + var result = Result(signature); + var args = Args(signature); + w.Write( + $$""" + + static void + wasm_invoke_{{signature.ToLower(CultureInfo.InvariantCulture)}} (void *target_func, MonoInterpMethodArguments *margs) + { + typedef {{result.nativeType}} (*T)({{args.Join(", ", (p, i) => $"{SignatureMapper.CharToNativeType(p)} arg_{i}")}}{{(signature.Length == 1 ? "void" : "")}}); + T func = (T)target_func; + {{(result.isVoid ? + $$"""" + func ({{args.Join(", ", p => $"{ctx.Emit(p)}")}}); + """" : + $$"""" + {{result.nativeType}} res = func ({{args.Join(", ", p => $"{ctx.Emit(p)}")}}); + + void *retval = mono_wasm_interp_method_args_get_retval (margs); + *({{result.nativeType}} *)retval = res; + """")}} + } + + """); } catch (InvalidSignatureCharException e) { @@ -105,42 +103,35 @@ private static void Emit(StreamWriter w, IEnumerable cookies) } } - Array.Sort(signatures); + w.Write( + $$""" - w.WriteLine("static void* interp_to_native_invokes[] = {"); - foreach (var sig in signatures) - { - var lsig = sig.ToLower(CultureInfo.InvariantCulture); - w.WriteLine($"\twasm_invoke_{lsig},"); - } - w.WriteLine("};"); - - w.WriteLine("static const char* interp_to_native_signatures[] = {"); - - foreach (var signature in signatures) - w.WriteLine($"\t\"{signature}\","); + typedef struct { + const char* signature; + void* func; + } InterpToNative; - w.WriteLine("};"); + static InterpToNative interp_to_native_invokes [] = { + {{signatures.Join($",{w.NewLine}", signature => + $" {{\"{signature}\", wasm_invoke_{signature.ToLower(CultureInfo.InvariantCulture)}}}") + }} + }; - w.WriteLine($"static unsigned int interp_to_native_signatures_count = {signatures.Length};"); - w.WriteLine(); - w.WriteLine(""" - static int - compare_icall_tramp (const void *key, const void *elem) - { - return strcmp (key, *(void**)elem); - } + static int + compare_signature (const void *key, const void *elem) + { + return strcmp (key, ((InterpToNative *)elem)->signature); + } - static void* - mono_wasm_interp_to_native_callback (char* cookie) - { - void* p = bsearch (cookie, interp_to_native_signatures, interp_to_native_signatures_count, sizeof (void*), compare_icall_tramp); - if (!p) - return NULL; - int idx = (const char**)p - (const char**)interp_to_native_signatures; - return interp_to_native_invokes [idx]; - }; - """); + static void* + mono_wasm_interp_to_native_callback (char* cookie) + { + InterpToNative *m2n = bsearch (cookie, interp_to_native_invokes, sizeof(interp_to_native_invokes) / sizeof(InterpToNative), sizeof (InterpToNative), compare_signature); + if (!m2n) + return NULL; + return m2n->func; + }; + """); } private sealed class EmitCtx diff --git a/src/tasks/WasmAppBuilder/JoinedString.cs b/src/tasks/WasmAppBuilder/JoinedString.cs new file mode 100644 index 00000000000000..28d411e6522734 --- /dev/null +++ b/src/tasks/WasmAppBuilder/JoinedString.cs @@ -0,0 +1,170 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.IO; +using System.Runtime.CompilerServices; +using System.Collections; +using System.Collections.Generic; +using System.Text; + +namespace JoinedString; + +internal static class JoinedStringExtensions +{ + public static JoinedStringEnumerable Join(this IEnumerable list, string separator) + => JoinedStringEnumerable.Join(list, separator); + public static JoinedStringEnumerable Join(this IEnumerable list, string separator, Func formatter) + => JoinedStringEnumerable.Join(list, separator, formatter); + public static JoinedStringEnumerable Join(this IEnumerable list, string separator, Func formatter) + => JoinedStringEnumerable.Join(list, separator, formatter); + + public static JoinedList Join(this IList list, string separator) + => new JoinedList(list, separator, (item, _) => $"{item}"); + public static JoinedList Join(this IList list, string separator, Func formatter) + => new JoinedList(list, separator, (str, _) => formatter(str)); + public static JoinedList Join(this IList list, string separator, Func formatter) + => new JoinedList(list, separator, formatter); +} + + +internal sealed record JoinedList(IList items, string separator, Func formatter) +{ + public IEnumerator GetEnumerator() + { + for (int i = 0; i < items.Count; i++) + { + if (i != 0) + yield return separator; + yield return formatter(items[i], i); + } + } + + public override string ToString() + { + var sb = new StringBuilder(); + foreach (var item in this) + { + sb.Append(item); + } + return sb.ToString(); + } +} + +internal sealed class JoinedStringEnumerable : IEnumerable +{ + private readonly IEnumerable _values; + + private JoinedStringEnumerable(IEnumerable values) + { + _values = values; + } + + public static JoinedStringEnumerable Join(IEnumerable values, string separator) + => new JoinedStringEnumerable(JoinInternal(values, separator, (x, _) => x)); + + public static JoinedStringEnumerable Join(IEnumerable values, string separator, Func format) + => new JoinedStringEnumerable(JoinInternal(values, separator, (x, _) => format(x))); + + public static JoinedStringEnumerable Join(IEnumerable values, string separator, Func format) + => new JoinedStringEnumerable(JoinInternal(values, separator, format)); + + private static IEnumerable JoinInternal(IEnumerable values, string separator, Func format) + { + int index = 0; + foreach (var value in values) + { + if (index != 0) + yield return separator; + yield return format(value, index++); + } + } + + public IEnumerator GetEnumerator() => _values.GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)_values).GetEnumerator(); + + public override string ToString() + { + var sb = new StringBuilder(); + foreach (var item in this) + { + sb.Append(item); + } + return sb.ToString(); + } +} + +internal sealed class JoinedStringStreamWriter : StreamWriter +{ + + // since we are intentionally using multi-line string writes, + // we want to capture the compile-time new line + private string CompileTimeNewLine = +@" +"; + + public JoinedStringStreamWriter(Stream stream) : base(stream) + { + NewLine = CompileTimeNewLine; + } + + public JoinedStringStreamWriter(string path, bool append) : base(path, append) + { + NewLine = CompileTimeNewLine; + } + +#if NET8_0_OR_GREATER +#pragma warning disable CA1822 // Mark members as static +#pragma warning disable IDE0060 // Remove unused parameter + public void Write([InterpolatedStringHandlerArgument("")] JoinedStringWriterHandler builder) + { + // The builder writes directly to the writer + } +#pragma warning restore IDE0060 +#pragma warning restore CA1822 +#endif +} + +#if NET8_0_OR_GREATER +[InterpolatedStringHandler] +internal ref struct JoinedStringWriterHandler +{ + private JoinedStringStreamWriter _writer; + +#pragma warning disable IDE0060 + public JoinedStringWriterHandler(int literalLength, int formattedCount, JoinedStringStreamWriter writer) + { + writer.Flush(); + _writer = writer; + } +#pragma warning restore IDE0060 + + public void AppendLiteral(string s) => _writer.Write(s); + public void AppendFormatted(T value) => _writer.Write(value); + public void AppendFormatted(Span value) => _writer.Write(value); + public void AppendFormatted(char[] buffer, int index, int count) => _writer.Write(buffer, index, count); + public void AppendFormatted(string format, object? arg0, object? arg1, object? arg2) => _writer.Write(format, arg0, arg1, arg2); + + public void AppendFormatted(JoinedStringEnumerable list) + { + foreach (var item in list) + { + _writer.Write(item); + } + } + + public void AppendFormatted(JoinedList list) + { + foreach (var item in list) + { + _writer.Write(item); + } + } + + public override string ToString() + { + _writer.Flush(); + return ""; + } +} +#endif diff --git a/src/tasks/WasmAppBuilder/PInvokeCollector.cs b/src/tasks/WasmAppBuilder/PInvokeCollector.cs index 2aa95be749a4be..574bcd7889e765 100644 --- a/src/tasks/WasmAppBuilder/PInvokeCollector.cs +++ b/src/tasks/WasmAppBuilder/PInvokeCollector.cs @@ -210,12 +210,40 @@ private bool HasAssemblyDisableRuntimeMarshallingAttribute(Assembly assembly) } } +internal sealed class PInvokeCallbackComparer : IComparer +{ + public int Compare(PInvokeCallback? x, PInvokeCallback? y) + { + int compare = string.Compare(x!.Key, y!.Key, StringComparison.Ordinal); + return compare != 0 ? compare : (int)(x.Token - y.Token); + } +} + #pragma warning disable CS0649 internal sealed class PInvokeCallback { public PInvokeCallback(MethodInfo method) { Method = method; + TypeName = method.DeclaringType!.Name!; + AssemblyName = method.DeclaringType!.Module!.Assembly!.GetName()!.Name!; + Namespace = method.DeclaringType!.Namespace; + MethodName = method.Name!; + ReturnType = method.ReturnType!; + IsVoid = ReturnType.Name == "Void"; + Token = (uint)method.MetadataToken; + + // FIXME: this is a hack, we need to encode this better and allow reflection in the interp case + // but either way it needs to match the key generated in get_native_to_interp since the key is + // used to look up the interp entry function. It must be unique for each callback runtime errors + // can occur since it is used to look up the index in the wasm_native_to_interp_ftndescs and + // the signature of the interp entry function must match the native signature + // + // the key also needs to survive being encoded in C literals, if in doubt + // add something like "\U0001F412" to the key on both the managed and unmanaged side + Key = $"{MethodName}#{Method.GetParameters().Length}:{AssemblyName}:{Namespace}:{TypeName}"; + + IsExport = false; foreach (var attr in method.CustomAttributes) { if (attr.AttributeType.Name == "UnmanagedCallersOnlyAttribute") @@ -225,6 +253,7 @@ public PInvokeCallback(MethodInfo method) if (arg.MemberName == "EntryPoint") { EntryPoint = arg.TypedValue.Value!.ToString(); + IsExport = true; return; } } @@ -232,8 +261,19 @@ public PInvokeCallback(MethodInfo method) } } - public string? EntryPoint; - public MethodInfo Method; - public string? EntryName; + + public ParameterInfo[] Parameters => Method.GetParameters(); + public string? EntryPoint { get; } + public MethodInfo Method { get; } + public string? EntrySymbol { get; set; } + public string AssemblyName { get; } + public string TypeName { get; } + public string? Namespace { get;} + public string MethodName { get; } + public Type ReturnType { get;} + public bool IsExport { get; } + public bool IsVoid { get; } + public uint Token { get; } + public string Key { get; } } #pragma warning restore CS0649 diff --git a/src/tasks/WasmAppBuilder/PInvokeTableGenerator.cs b/src/tasks/WasmAppBuilder/PInvokeTableGenerator.cs index 19e4181b2217e0..a15faea3873384 100644 --- a/src/tasks/WasmAppBuilder/PInvokeTableGenerator.cs +++ b/src/tasks/WasmAppBuilder/PInvokeTableGenerator.cs @@ -13,6 +13,7 @@ using Microsoft.Build.Framework; using Microsoft.Build.Utilities; using WasmAppBuilder; +using JoinedString; internal sealed class PInvokeTableGenerator { @@ -42,12 +43,12 @@ public void ScanAssembly(Assembly asm) public IEnumerable Generate(string[] pinvokeModules, string outputPath) { - var modules = new Dictionary(); + var modules = new SortedDictionary(StringComparer.Ordinal); foreach (var module in pinvokeModules) modules[module] = module; using TempFileName tmpFileName = new(); - using (var w = File.CreateText(tmpFileName.Path)) + using (var w = new JoinedStringStreamWriter(tmpFileName.Path, false)) { EmitPInvokeTable(w, modules, pinvokes); EmitNativeToInterp(w, callbacks); @@ -61,7 +62,7 @@ public IEnumerable Generate(string[] pinvokeModules, string outputPath) return signatures; } - private void EmitPInvokeTable(StreamWriter w, Dictionary modules, List pinvokes) + private void EmitPInvokeTable(StreamWriter w, SortedDictionary modules, List pinvokes) { foreach (var pinvoke in pinvokes) @@ -87,14 +88,20 @@ private void EmitPInvokeTable(StreamWriter w, Dictionary modules w.WriteLine( $""" - // GENERATED FILE, DO NOT MODIFY"); - + // GENERATED FILE, DO NOT MODIFY (PInvokeTableGenerator.cs) + #include + #include + #include + #include + #include + #include "runtime.h" + #include "pinvoke.h" """); var pinvokesGroupedByEntryPoint = pinvokes .Where(l => modules.ContainsKey(l.Module)) - .OrderBy(l => l.EntryPoint) - .GroupBy(CEntryPoint); + .OrderBy(l => l.EntryPoint, StringComparer.Ordinal) + .GroupBy(CEntryPoint, StringComparer.Ordinal); var comparer = new PInvokeComparer(); foreach (IGrouping group in pinvokesGroupedByEntryPoint) { @@ -127,20 +134,25 @@ private void EmitPInvokeTable(StreamWriter w, Dictionary modules } } + var moduleImports = new Dictionary>(); foreach (var module in modules.Keys) { - var assemblies_pinvokes = pinvokes + static string ListRefs(IGrouping l) => + string.Join(", ", l.Select(c => c.Method.DeclaringType!.Module!.Assembly!.GetName()!.Name!).Distinct().OrderBy(n => n)); + + var imports = pinvokes .Where(l => l.Module == module && !l.Skip) - .OrderBy(l => l.EntryPoint) - .GroupBy(d => d.EntryPoint) - .Select(l => $"{{\"{EscapeLiteral(l.Key)}\", {CEntryPoint(l.First())}}}, " - + "// " + string.Join(", ", l.Select(c => c.Method.DeclaringType!.Module!.Assembly!.GetName()!.Name!).Distinct().OrderBy(n => n))) - .Append("{NULL, NULL}"); + .OrderBy(l => l.EntryPoint, StringComparer.Ordinal) + .GroupBy(d => d.EntryPoint, StringComparer.Ordinal) + .Select(l => $"{{\"{EscapeLiteral(l.Key)}\", {CEntryPoint(l.First())}}}, // {ListRefs(l)}{w.NewLine} ") + .ToList(); + moduleImports[module] = imports; w.Write( $$""" + static PinvokeImport {{_fixupSymbolName(module)}}_imports [] = { - {{string.Join("\n ", assemblies_pinvokes)}} + {{string.Join("", imports)}}{NULL, NULL} }; """); @@ -149,12 +161,8 @@ private void EmitPInvokeTable(StreamWriter w, Dictionary modules w.Write( $$""" - static void *pinvoke_tables[] = { - {{string.Join(", ", modules.Keys.Select(m => $"(void*){_fixupSymbolName(m)}_imports"))}} - }; - - static char *pinvoke_names[] = { - {{string.Join(", ", modules.Keys.Select(m => $"\"{EscapeLiteral(m)}\""))}} + static PinvokeTable pinvoke_tables[] = { + {{modules.Keys.Join($",{w.NewLine} ", m => $"{{\"{EscapeLiteral(m)}\", {_fixupSymbolName(m)}_imports, {moduleImports[m].Count}}}")}} }; """); @@ -255,13 +263,6 @@ private static bool TryIsMethodGetParametersUnsupported(MethodInfo method, [NotN { var method = pinvoke.Method; - if (method.Name == "EnumCalendarInfo") - { - // FIXME: System.Reflection.MetadataLoadContext can't decode function pointer types - // https://github.com/dotnet/runtime/issues/43791 - return $"int {_fixupSymbolName(pinvoke.EntryPoint)} (int, int, int, int, int);"; - } - if (TryIsMethodGetParametersUnsupported(pinvoke.Method, out string? reason)) { // Don't use method.ToString() or any of it's parameters, or return type @@ -288,37 +289,37 @@ private static bool TryIsMethodGetParametersUnsupported(MethodInfo method, [NotN """; } - private string CEntryPoint(PInvokeCallback export) + private static string? EscapeLiteral(string? input) { - if (export.EntryPoint is not null) - { - return _fixupSymbolName(export.EntryPoint); - } + if (input == null) + return null; - var method = export.Method; - string namespaceName = method.DeclaringType?.Namespace ?? string.Empty; - string assemblyName = method.DeclaringType?.Module?.Assembly?.GetName()?.Name ?? string.Empty; - string declaringTypeName = method.DeclaringType?.Name ?? string.Empty; + StringBuilder sb = new StringBuilder(); - string entryPoint = $"wasm_native_to_interp_{namespaceName}_{assemblyName}_{declaringTypeName}_{method.Name}"; + for (int i = 0; i < input.Length; i++) + { + char c = input[i]; - return _fixupSymbolName(entryPoint); - } + sb.Append(c switch + { + '\\' => "\\\\", + '\"' => "\\\"", + '\n' => "\\n", + '\r' => "\\r", + '\t' => "\\t", + // take special care with surrogate pairs to avoid + // potential decoding issues in generated C literals + _ when char.IsHighSurrogate(c) && i + 1 < input.Length && char.IsLowSurrogate(input[i + 1]) + => $"\\U{char.ConvertToUtf32(c, input[++i]):X8}", + _ when char.IsControl(c) || c > 127 + => $"\\u{(int)c:X4}", + _ => c.ToString() + }); + } - private string DelegateKey(PInvokeCallback export) - { - // FIXME: this is a hack, we need to encode this better - // and allow reflection in the interp case but either way - // it needs to match the key generated in get_native_to_interp - var method = export.Method; - string module_symbol = method.DeclaringType!.Module!.Assembly!.GetName()!.Name!; - return $"\"{_fixupSymbolName($"{module_symbol}_{method.DeclaringType.Name}_{method.Name}")}\""; + return sb.ToString(); } -#pragma warning disable SYSLIB1045 // framework doesn't support GeneratedRegexAttribute - private static string EscapeLiteral(string s) => Regex.Replace(s, @"(\\|\"")", @"\$1"); -#pragma warning restore SYSLIB1045 - private void EmitNativeToInterp(StreamWriter w, List callbacks) { // Generate native->interp entry functions @@ -327,114 +328,74 @@ private void EmitNativeToInterp(StreamWriter w, List callbacks) // They also need to have a signature matching what the // native code expects, which is the native signature // of the delegate invoke in the [MonoPInvokeCallback] - // attribute. + // or [UnmanagedCallersOnly] attribute. // Only blittable parameter/return types are supposed. - int cb_index = 0; + w.Write( + $$""" - w.Write(@"#include - #include - #include - #include - #include - #include ""runtime.h"" - "); + InterpFtnDesc wasm_native_to_interp_ftndescs[{{callbacks.Count}}] = {}; - // Arguments to interp entry functions in the runtime - w.WriteLine($"InterpFtnDesc wasm_native_to_interp_ftndescs[{callbacks.Count}] = {{}};"); + """); var callbackNames = new HashSet(); + var keys = new HashSet(); + int cb_index = 0; + callbacks = callbacks.OrderBy(c => c, new PInvokeCallbackComparer()).ToList(); foreach (var cb in callbacks) { - var sb = new StringBuilder(); - var method = cb.Method; - bool is_void = method.ReturnType.Name == "Void"; + cb.EntrySymbol = _fixupSymbolName(cb.IsExport ? cb.EntryPoint! : $"wasm_native_to_interp_{cb.AssemblyName}_{cb.Namespace}_{cb.TypeName}_{cb.MethodName}"); - // The signature of the interp entry function - // This is a gsharedvt_in signature - sb.Append($"typedef void (*WasmInterpEntrySig_{cb_index}) ("); - - if (!is_void) + if (callbackNames.Contains(cb.EntrySymbol)) { - sb.Append("int*, "); + Error($"Two callbacks with the same symbol '{cb.EntrySymbol}' are not supported."); } - foreach (var p in method.GetParameters()) + callbackNames.Add(cb.EntrySymbol); + if (keys.Contains(cb.Key)) { - sb.Append("int*, "); + Error($"Two callbacks with the same Name and number of arguments '{cb.Key}' are not supported."); } - // Extra arg - sb.Append("int*);\n"); + keys.Add(cb.Key); - cb.EntryName = CEntryPoint(cb); - if (callbackNames.Contains(cb.EntryName)) - { - Error($"Two callbacks with the same name '{cb.EntryName}' are not supported."); - } - callbackNames.Add(cb.EntryName); - if (cb.EntryPoint is not null) - { - sb.Append($"__attribute__((export_name(\"{EscapeLiteral(cb.EntryPoint)}\")))\n"); - } - sb.Append($"{MapType(method.ReturnType)} {cb.EntryName} ("); - int pindex = 0; - foreach (var p in method.GetParameters()) + // The signature of the interp entry function + // This is a gsharedvt_in signature + var entryArgs = new List(); + if (!cb.IsVoid) { - if (pindex > 0) - sb.Append(", "); - sb.Append($"{MapType(p.ParameterType)} arg{pindex}"); - pindex++; + entryArgs.Add("(int*)&result"); } - sb.Append(") { \n"); - if (!is_void) - sb.Append($" {MapType(method.ReturnType)} res;\n"); + entryArgs.AddRange(cb.Parameters.Select((_, i) => $"(int*)&arg{i}")); + entryArgs.Add($"(int*)wasm_native_to_interp_ftndescs [{cb_index}].arg"); - if (_isLibraryMode && HasAttribute(method, "System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute")) - { - sb.Append($" initialize_runtime(); \n"); - } + w.Write( + $$""" - // In case when null force interpreter to initialize the pointers - sb.Append($" if (!(WasmInterpEntrySig_{cb_index})wasm_native_to_interp_ftndescs [{cb_index}].func) {{\n"); - var assemblyFullName = cb.Method.DeclaringType == null ? "" : cb.Method.DeclaringType.Assembly.FullName; - var assemblyName = assemblyFullName != null && assemblyFullName.Split(',').Length > 0 ? assemblyFullName.Split(',')[0].Trim() : ""; - var namespaceName = cb.Method.DeclaringType == null ? "" : cb.Method.DeclaringType.Namespace; - var typeName = cb.Method.DeclaringType == null || cb.Method.DeclaringType.Name == null ? "" : cb.Method.DeclaringType.Name; - var methodName = cb.Method.Name; - int numParams = method.GetParameters().Length; - sb.Append($" mono_wasm_marshal_get_managed_wrapper (\"{assemblyName}\",\"{namespaceName}\", \"{typeName}\", \"{methodName}\", {numParams});\n"); - sb.Append($" }}\n"); - - sb.Append($" ((WasmInterpEntrySig_{cb_index})wasm_native_to_interp_ftndescs [{cb_index}].func) ("); - if (!is_void) - { - sb.Append("(int*)&res, "); - pindex++; - } - int aindex = 0; - foreach (var p in method.GetParameters()) - { - sb.Append($"(int*)&arg{aindex}, "); - aindex++; - } + {{(cb.IsExport ? + $"__attribute__((export_name(\"{EscapeLiteral(cb.EntryPoint!)}\"))){w.NewLine}" : "")}}{{ + MapType(cb.ReturnType)}} + {{cb.EntrySymbol}} ({{cb.Parameters.Join(", ", (info, i) => $"{MapType(info.ParameterType)} arg{i}")}}) { + typedef void (*InterpEntry_T{{cb_index}}) ({{entryArgs.Join(", ", _ => "int*")}});{{ + (!cb.IsVoid ? $"{w.NewLine} {MapType(cb.ReturnType)} result;" : "")}} - sb.Append($"wasm_native_to_interp_ftndescs [{cb_index}].arg);\n"); + if (!(InterpEntry_T{{cb_index}})wasm_native_to_interp_ftndescs [{{cb_index}}].func) {{{ + (cb.IsExport && _isLibraryMode ? $"initialize_runtime();{w.NewLine}" : "")}} + mono_wasm_marshal_get_managed_wrapper ("{{EscapeLiteral(cb.AssemblyName)}}", "{{EscapeLiteral(cb.Namespace)}}", "{{EscapeLiteral(cb.TypeName)}}", "{{EscapeLiteral(cb.MethodName)}}", {{cb.Token}}, {{cb.Parameters.Length}}); + } - if (!is_void) - sb.Append(" return res;\n"); - sb.Append("}\n"); - w.WriteLine(sb); + ((InterpEntry_T{{cb_index}})wasm_native_to_interp_ftndescs [{{cb_index}}].func) ({{entryArgs.Join(", ")}});{{ + (!cb.IsVoid ? $"{w.NewLine} return result;" : "")}} + } + + """); cb_index++; } w.Write( $$""" - static void *wasm_native_to_interp_funcs[] = { - {{string.Join(", ", callbacks.Select(cb => cb.EntryName))}} - }; - - // these strings need to match the keys generated in get_native_to_interp - static const char *wasm_native_to_interp_map[] = { - {{string.Join(", ", callbacks.Select(DelegateKey))}} + static UnmanagedExport wasm_native_to_interp_table[] = { + {{callbacks.Join($",{w.NewLine}", cb => + $" {{\"{EscapeLiteral(cb.Key)}\", {cb.Token}, {cb.EntrySymbol}}}" + )}} }; """); diff --git a/src/tasks/WasmAppBuilder/WasmAppBuilder.csproj b/src/tasks/WasmAppBuilder/WasmAppBuilder.csproj index 34a689f680da40..e1d281d3d1a217 100644 --- a/src/tasks/WasmAppBuilder/WasmAppBuilder.csproj +++ b/src/tasks/WasmAppBuilder/WasmAppBuilder.csproj @@ -20,6 +20,7 @@ + diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_105619/Runtime_105619.cs b/src/tests/JIT/Regression/JitBlue/Runtime_105619/Runtime_105619.cs new file mode 100644 index 00000000000000..1956903c95f156 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_105619/Runtime_105619.cs @@ -0,0 +1,246 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// Generated by Fuzzlyn v2.1 on 2024-07-28 15:37:46 +// Run on Arm Linux +// Seed: 8024459297219020330 +// Reduced from 3285.8 KiB to 12.2 KiB in 01:46:03 +// Hits JIT assert in Release: +// Assertion failed 'varDsc->IsAlwaysAliveInMemory() || ((regSet.GetMaskVars() & regMask) == 0)' in 'Program:Main(Fuzzlyn.ExecutionServer.IRuntime)' during 'Generate code' (IL size 7170; hash 0xade6b36b; FullOpts) +// +// File: /__w/1/s/src/coreclr/jit/codegencommon.cpp Line: 664 +// +using System; +using System.Runtime.CompilerServices; +using Xunit; + +public interface I1 +{ +} + +public struct S0 +{ + public double F0; + public sbyte F1; + public ulong F2; + public int F3; + public ulong F4; + public ulong F6; + public int F7; + public long F8; + public S0(double f0, ulong f2, ulong f4, float f5, ulong f6, int f7, long f8) : this() + { + } +} + +public struct S1 +{ + public int F0; + public S0 F2; + public S0 F3; + public S0 F4; + public S1(int f0, double f1, S0 f2, S0 f3, S0 f4) : this() + { + } +} + +public struct S2 : I1 +{ + public S1 F2; + public ushort F4; + public S1 F6; + public S1 F7; + public S2(sbyte f0, ulong f1, S1 f2, ushort f4, byte f5, S1 f6, S1 f7) : this() + { + } +} + +public class C0 +{ + public S1 F1; + public C0(S1 f1) + { + } +} + +public struct S3 : I1 +{ + public S3(short f0) : this() + { + } +} + +public struct S4 : I1 +{ + public S3 F0; + public S2 F1; + public S4(S3 f0, S2 f1, float f2, S0 f3, int f5) : this() + { + } +} + +public struct S5 +{ + public C0 F0; + public S5(C0 f0, S1 f3) : this() + { + } +} + +public class C1 +{ + public bool F1; +} + +public class Program +{ + public static IRuntime s_rt; + public static S2 s_13; + public static S1 s_18; + public static bool[] s_22; + public static C0 s_24; + public static ushort[, ] s_31; + public static S1 s_35; + public static bool s_37; + public static S5[] s_44; + public static S4 s_54; + public static S1 s_58; + public static C1[, ] s_59; + public static S4 s_60; + public static S2 s_88; + public static S2[] s_90; + + [Fact] + public static void TestEntryPoint() + { + try + { + CollectibleALC alc = new CollectibleALC(); + System.Reflection.Assembly asm = alc.LoadFromAssemblyPath(System.Reflection.Assembly.GetExecutingAssembly().Location); + System.Reflection.MethodInfo mi = asm.GetType(typeof(Program).FullName).GetMethod(nameof(MainInner)); + System.Type runtimeTy = asm.GetType(typeof(Runtime).FullName); + mi.Invoke(null, new object[] { System.Activator.CreateInstance(runtimeTy) }); + } catch {} + } + +// Allow reflection lookup on public method +#pragma warning disable xUnit1013 + public static void MainInner(IRuntime rt) + { + S0 vr8 = default(S0); + if (s_59[0, 0].F1) + { + bool[] vr9 = new bool[] + { + true + }; + s_88 = new S2(s_54.F1.F2.F4.F1, s_24.F1.F2.F4--, new S1(s_35.F2.F3, 0, new S0(-2, 0, 0, 0, 11218621709493063492UL, 450420498, 0), s_60.F1.F7.F2, new S0(0, 0, 0, 0, 0, 1, 0)), s_13.F4--, (byte)s_31[0, 0], new S1(0, 0, new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0)), s_54.F1.F2); + vr9[0] = vr9[0]; + } + + s_rt.WriteLine("c_6973", vr8.F2); + s_rt.WriteLine("c_6975", vr8.F4); + s_rt.WriteLine("c_6978", vr8.F7); + I1[] vr10 = new I1[] + { + new S2(0, 0, new S1(0, 0, new S0(0, 0, 0, -3.4028235E+38F, 0, 0, 0), new S0(0, 0, 0, 1, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0)), 0, 0, new S1(1, 0, new S0(0, 0, 0, 0, 0, 1, 0), new S0(0, 0, 0, 0, 0, 1, 0), new S0(0, 0, 0, 0, 0, 0, 0)), new S1(0, 0, new S0(0, 0, 16728947367172946933UL, 0, 0, 0, 0), new S0(1, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0))), + new S3(0), + new S2(0, 0, new S1(0, 0, new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0)), 1, 0, new S1(0, 0, new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 2102657202, 0)), new S1(0, 0, new S0(0, 0, 0, 0, 0, 1, 0), new S0(0, 16794536930986757818UL, 0, 0, 0, 0, 0), new S0(0, 0, 11911619636908597430UL, 0, 0, 0, 0))), + new S3(0), + new S2(0, 0, new S1(-2147483647, 0, new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0)), 1, 0, new S1(0, -2, new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0), new S0(1, 0, 0, 0, 0, 0, 0)), new S1(1, 1, new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 1, 0))), + new S2(0, 0, new S1(0, -1, new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0)), 0, 0, new S1(-1, 0, new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, -3.4028235E+38F, 0, 0, 0), new S0(0, 0, 0, 0, 0, 1, 0)), new S1(0, 0, new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0))), + new S4(new S3(0), new S2(1, 0, new S1(0, 1, new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 1, 0)), 1, 0, new S1(1, 0, new S0(0, 0, 0, 0, 0, 1, 0), new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 1, 0)), new S1(0, 0, new S0(0, 0, 0, 0, 0, 1, 0), new S0(1, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0))), 0, new S0(0, 0, 0, 0, 0, 0, 0), 0) + }; + var vr11 = new S3(0); + var vr12 = s_44[0].F0.F1.F3.F0; + M75(vr11, vr12); + if (s_22[0]) + { + S3 vr13 = new S3(0); + try + { + var vr14 = s_54.F0; + var vr15 = s_18.F4.F0; + S3 vr23 = vr14; + } + finally + { + var vr16 = new S3(0); + var vr17 = s_58.F4.F0--; + M75(vr16, vr17); + if (s_37) + { + for (int vr18 = 0; vr18 < 2; vr18++) + { + var vr19 = new S3(0); + vr10[0] = new S4(new S3(0), new S2(1, 5461410436353764379UL, new S1(0, 0, new S0(0, 18446744073709551614UL, 0, 0, 17533718527758593297UL, 0, 0), new S0(0, 8592301711847430801UL, 0, 0, 0, 0, 0), new S0(-1, 7862269010569978854UL, 0, 0, 0, 0, 0)), 0, 0, new S1(0, 0, new S0(0, 3156588052453432602UL, 0, 0, 0, 810788132, 0), new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0)), new S1(1, 0, new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 15070356010362475091UL, 0, 0))), 0, new S0(0, 0, 0, 0, 0, 0, 0), 0); + vr10 = new I1[] + { + new S2(1, 0, new S1(0, 0, new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, -3.4028235E+38F, 0, -1, 0), new S0(0, 7703692348755595801UL, 0, 0, 0, 0, 0)), 0, 0, new S1(1, 1.7976931348623157E+308, new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 1, 0)), new S1(0, -1, new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 3991586019811875011UL, 0, 0, 0, -2147483648, 0))), + new S4(new S3(-1), new S2(0, 9890997199408041578UL, new S1(0, 0, new S0(0, 0, 0, 0, 0, 1, 0), new S0(0, 0, 0, 0, 0, 0, -7424873608279851173L), new S0(0, 0, 9698347484967702837UL, 0, 0, 0, 0)), 0, 0, new S1(0, 0, new S0(1, 0, 0, 0, 0, 0, 8154649548600176800L), new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, -9223372036854775808L)), new S1(0, 0, new S0(1, 0, 0, 0, 0, 0, 0), new S0(0, 778004003835070330UL, 0, 0, 0, 0, 0), new S0(0, 0, 8658698987098108904UL, 0, 0, 0, 0))), 0, new S0(0, 0, 0, 0, 0, 0, 0), 956596481), + new S4(new S3(0), new S2(0, 453734974695362841UL, new S1(0, 0, new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, -8941433507005588199L)), 0, 1, new S1(0, 0, new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 1, 0)), new S1(0, 0, new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 10794758865549560580UL, 0, 7077610171127139841UL, 1, 0), new S0(1, 0, 0, 0, 0, 0, 0))), 0, new S0(1, 0, 0, 0, 17621340021635995622UL, 0, 0), 1), + new S2(0, 0, new S1(0, 0, new S0(0, 0, 0, 0, 0, 0, 0), new S0(1, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0)), 0, 0, new S1(0, 0, new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0)), new S1(0, 0, new S0(1, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0))), + new S2(0, 6130557987521252430UL, new S1(0, -2, new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 1, 0), new S0(1, 12555188232274105334UL, 0, 0, 0, 0, 0)), 1, 0, new S1(0, 0, new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0)), new S1(0, 0, new S0(0, 1828388993980413842UL, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 5800380996067047058UL, 0, 0))), + new S3(1) + }; + s_rt.WriteLine("c_7152", vr18); + } + + S0 vr20 = new S0(0, 0, 0, 0, 0, 0, 0); + C0 vr21 = new C0(new S1(0, 0, new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0))); + s_rt.WriteLine("c_7159", vr20.F6); + s_rt.WriteLine("c_7164", vr21.F1.F0); + s_rt.WriteLine("c_7168", vr21.F1.F2.F2); + s_rt.WriteLine("c_7170", vr21.F1.F2.F4); + s_rt.WriteLine("c_7173", vr21.F1.F2.F7); + s_rt.WriteLine("c_7176", vr21.F1.F3.F1); + s_rt.WriteLine("c_7177", vr21.F1.F3.F2); + s_rt.WriteLine("c_7181", vr21.F1.F3.F6); + s_rt.WriteLine("c_7185", vr21.F1.F4.F1); + s_rt.WriteLine("c_7191", vr21.F1.F4.F7); + s_rt.WriteLine("c_7192", vr21.F1.F4.F8); + } + + s_54.F1.F2.F0 = s_90[0].F6.F0++; + } + + var vr22 = new S5(new C0(new S1(0, 0, new S0(-2, 0, 0, 0, 0, 0, 0), new S0(1, 0, 0, 0, 0, -1, 0), new S0(0, 0, 0, 0, 0, 0, 0))), new S1(0, 0, new S0(-1, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0))); + } + + vr10 = new I1[] + { + new S4(new S3(-18643), new S2(0, 0, new S1(1, 0, new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 11398096482162480173UL, 0, 0, 0, 9223372036854775806L), new S0(0, 0, 0, 0, 0, 2134113955, 0)), 0, 0, new S1(0, 0, new S0(0, 0, 15971873843035984033UL, 0, 5979847448536525346UL, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0), new S0(1, 0, 0, 0, 11276959574309188693UL, 0, 0)), new S1(0, 0, new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 1, 0), new S0(0, 0, 0, 0, 0, 0, 0))), 0, new S0(0, 0, 0, 0, 0, 0, 0), 0), + new S3(1), + new S3(0), + new S4(new S3(0), new S2(0, 0, new S1(0, 0, new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 1, 0), new S0(0, 0, 0, 0, 0, 1, 0)), 1, 0, new S1(0, 0, new S0(0, 0, 0, 0, 11829847737932804605UL, 0, 0), new S0(1, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0)), new S1(0, -2, new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 9919258226402299883UL, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0))), 0, new S0(0, 0, 0, 0, 0, 1, 0), 0), + new S2(0, 0, new S1(0, 0, new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0)), 0, 0, new S1(0, 0, new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0)), new S1(-1, 0, new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 1, 0), new S0(0, 0, 0, 0, 0, 0, 0))), + new S4(new S3(0), new S2(0, 0, new S1(0, 0, new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0)), 0, 0, new S1(0, 1, new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, -1, 0), new S0(0, 0, 0, 0, 0, 0, 0)), new S1(0, 0, new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0), new S0(1, 0, 0, 0, 0, 0, 0))), 0, new S0(0, 0, 0, 0, 0, 1, 0), 0), + new S4(new S3(0), new S2(0, 0, new S1(0, 0, new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0)), 0, 0, new S1(0, 0, new S0(1, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0)), new S1(0, 0, new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0), new S0(0, 0, 0, 0, 0, 0, 0))), 0, new S0(1, 0, 0, 0, 0, 0, 0), 0), + new S3(0), + new S3(0), + new S3(0) + }; + } +#pragma warning restore xUnit1013 + + private static void M75(S3 argThis, double arg1) + { + } +} + +public interface IRuntime +{ + void WriteLine(string site, T value); +} + +public class Runtime : IRuntime +{ + public void WriteLine(string site, T value) => System.Console.WriteLine(value); +} + +public class CollectibleALC : System.Runtime.Loader.AssemblyLoadContext +{ + public CollectibleALC() : base(true) + { + } +} \ No newline at end of file diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_105619/Runtime_105619.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_105619/Runtime_105619.csproj new file mode 100644 index 00000000000000..de6d5e08882e86 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_105619/Runtime_105619.csproj @@ -0,0 +1,8 @@ + + + True + + + + + diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_105620/Runtime_105620.cs b/src/tests/JIT/Regression/JitBlue/Runtime_105620/Runtime_105620.cs new file mode 100644 index 00000000000000..486afcffb12c0e --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_105620/Runtime_105620.cs @@ -0,0 +1,199 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// Generated by Fuzzlyn v2.1 on 2024-07-28 20:48:11 +// Run on Arm Linux +// Seed: 7638843082097772896 +// Reduced from 1010.6 KiB to 5.3 KiB in 00:18:13 +// Hits JIT assert in Release: +// Assertion failed 'baseRegUsed == reg2' in 'Program:M48(S0,S3,S2,S2)' during 'Generate code' (IL size 2164; hash 0x03983244; FullOpts) +// +// File: /__w/1/s/src/coreclr/jit/emitarm.cpp Line: 3919 +// +using System; +using System.Runtime.CompilerServices; +using Xunit; + +public struct S0 +{ + public ulong F0; + public int F1; + public long F2; + public uint F3; + public byte F4; + public float F5; + public sbyte F6; + public double F7; + public sbyte F8; +} + +public struct S1 +{ + public double F0; + public short F1; + public bool F2; + public S0 F3; + public sbyte F4; + public ushort F5; + public ulong F6; + public int F7; + public S0 F8; +} + +public struct S2 +{ + public double F0; + public S0 F1; + public S1 F2; + public ushort F4; + public S2(S1 f2) + { + F2 = f2; + } +} + +public class C0 +{ +} + +public struct S3 +{ + public double F0; + public float F1; + public ushort F2; + public long F3; + public S1 F4; + public S2 F5; + public S2 F6; + public uint F7; + public S2 F8; + public S3(S2 f5, S2 f8) : this() + { + F5 = f5; + F8 = f8; + } +} + +public struct S4 +{ + public double F0; + public double F1; + public float F2; + public ulong F3; + public bool F4; + public int F5; + public bool F6; + public S3 F7; + public float F8; + public S4(S3 f7) + { + F7 = f7; + } +} + +public class Program +{ + public static IRuntime s_rt; + public static S4 s_2; + public static S4 s_3; + public static S4[][] s_6; + public static S3[] s_23 = new S3[] + { + new S3(new S2(new S1()), new S2(new S1())) + }; + + [Fact] + public static void TestEntryPoint() + { + try + { + var vr8 = new S4(new S3(new S2(new S1()), new S2(new S1()))); + var vr9 = s_23[0].F6.F1; + var vr13 = s_2.F7; + var vr14 = vr8.F7.F6; + var vr15 = vr8.F7.F6; + M48(vr9, vr13, vr14, vr15); + } catch {} + } + + private static void M48(S0 argThis, S3 arg0, S2 arg1, S2 arg2) + { + arg2.F2.F0 = arg2.F2.F0; + S4 var1 = new S4(new S3(new S2(new S1()), new S2(new S1()))); + var1.F7.F5.F2.F8.F5 = s_6[0][0].F7.F8.F2.F3.F5; + var vr2 = new C0(); + M49(0, vr2, ref arg2.F2.F1, ref s_3.F7, ref arg1.F1.F8); + S4 var2 = var1; + s_rt.WriteLine(System.BitConverter.DoubleToUInt64Bits(var2.F7.F0)); + s_rt.WriteLine(System.BitConverter.SingleToUInt32Bits(var2.F7.F1)); + s_rt.WriteLine(var2.F7.F2); + s_rt.WriteLine(var2.F7.F3); + s_rt.WriteLine(System.BitConverter.DoubleToUInt64Bits(var2.F7.F4.F0)); + s_rt.WriteLine(var2.F7.F4.F1); + s_rt.WriteLine(var2.F7.F4.F2); + s_rt.WriteLine(var2.F7.F4.F3.F0); + s_rt.WriteLine(var2.F7.F4.F3.F1); + s_rt.WriteLine(var2.F7.F4.F3.F2); + s_rt.WriteLine(var2.F7.F4.F3.F3); + s_rt.WriteLine(var2.F7.F4.F3.F4); + s_rt.WriteLine(System.BitConverter.SingleToUInt32Bits(var2.F7.F4.F3.F5)); + s_rt.WriteLine(var2.F7.F4.F3.F6); + s_rt.WriteLine(System.BitConverter.DoubleToUInt64Bits(var2.F7.F4.F3.F7)); + s_rt.WriteLine(var2.F7.F4.F3.F8); + s_rt.WriteLine(var2.F7.F4.F4); + s_rt.WriteLine(var2.F7.F4.F5); + s_rt.WriteLine(var2.F7.F4.F6); + s_rt.WriteLine(var2.F7.F4.F7); + s_rt.WriteLine(var2.F7.F4.F8.F0); + s_rt.WriteLine(var2.F7.F4.F8.F1); + s_rt.WriteLine(var2.F7.F4.F8.F2); + s_rt.WriteLine(var2.F7.F4.F8.F3); + s_rt.WriteLine(var2.F7.F4.F8.F4); + s_rt.WriteLine(System.BitConverter.SingleToUInt32Bits(var2.F7.F4.F8.F5)); + s_rt.WriteLine(var2.F7.F4.F8.F6); + s_rt.WriteLine(System.BitConverter.DoubleToUInt64Bits(var2.F7.F4.F8.F7)); + s_rt.WriteLine(var2.F7.F4.F8.F8); + s_rt.WriteLine(System.BitConverter.DoubleToUInt64Bits(var2.F7.F5.F0)); + s_rt.WriteLine(var2.F7.F5.F1.F0); + s_rt.WriteLine(var2.F7.F5.F1.F1); + s_rt.WriteLine(var2.F7.F5.F1.F2); + s_rt.WriteLine(var2.F7.F5.F1.F3); + s_rt.WriteLine(var2.F7.F5.F1.F4); + s_rt.WriteLine(System.BitConverter.SingleToUInt32Bits(var2.F7.F5.F1.F5)); + s_rt.WriteLine(var2.F7.F5.F1.F6); + s_rt.WriteLine(System.BitConverter.DoubleToUInt64Bits(var2.F7.F5.F1.F7)); + s_rt.WriteLine(var2.F7.F5.F1.F8); + s_rt.WriteLine(System.BitConverter.DoubleToUInt64Bits(var2.F7.F5.F2.F0)); + s_rt.WriteLine(var2.F7.F5.F2.F1); + s_rt.WriteLine(var2.F7.F5.F2.F2); + s_rt.WriteLine(var2.F7.F5.F2.F3.F0); + s_rt.WriteLine(var2.F7.F5.F2.F3.F1); + s_rt.WriteLine(var2.F7.F5.F2.F3.F2); + s_rt.WriteLine(var2.F7.F5.F2.F3.F3); + s_rt.WriteLine(var2.F7.F5.F2.F3.F4); + s_rt.WriteLine(System.BitConverter.SingleToUInt32Bits(var2.F7.F5.F2.F3.F5)); + s_rt.WriteLine(var2.F7.F5.F2.F3.F6); + s_rt.WriteLine(System.BitConverter.DoubleToUInt64Bits(var2.F7.F5.F2.F3.F7)); + s_rt.WriteLine(var2.F7.F5.F2.F3.F8); + s_rt.WriteLine(var2.F7.F5.F2.F4); + s_rt.WriteLine(var2.F7.F5.F2.F5); + s_rt.WriteLine(var2.F7.F5.F2.F6); + s_rt.WriteLine(var2.F7.F5.F2.F7); + s_rt.WriteLine(var2.F7.F5.F2.F8.F0); + } + + private static void M49(short arg0, C0 arg2, ref short arg3, ref S3 arg4, ref sbyte arg5) + { + s_rt.WriteLine(arg0); + } +} + +public interface IRuntime +{ + void WriteLine(T value); +} + +public class Runtime : IRuntime +{ + public void WriteLine(T value) => System.Console.WriteLine(value); +} \ No newline at end of file diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_105620/Runtime_105620.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_105620/Runtime_105620.csproj new file mode 100644 index 00000000000000..de6d5e08882e86 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_105620/Runtime_105620.csproj @@ -0,0 +1,8 @@ + + + True + + + + + diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_106869/Runtime_106869.cs b/src/tests/JIT/Regression/JitBlue/Runtime_106869/Runtime_106869.cs new file mode 100644 index 00000000000000..b4b9856c795950 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_106869/Runtime_106869.cs @@ -0,0 +1,59 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Xunit; +using System.Runtime.CompilerServices; + +// Generated by Fuzzlyn v2.3 on 2024-08-23 10:25:51 +// Run on Arm64 Windows +// Seed: 13938901376337307772-vectort,vector64,vector128,armsve +// Reduced from 210.5 KiB to 1.1 KiB in 00:02:19 +// Hits JIT assert in Release: +// Assertion failed 'nestedOp2->OperIsHWIntrinsic()' in 'Program:Main(Fuzzlyn.ExecutionServer.IRuntime)' during 'Lowering nodeinfo' (IL size 119; hash 0xade6b36b; FullOpts) +// +// File: C:\dev\dotnet\runtime2\src\coreclr\jit\lowerarmarch.cpp Line: 4062 +// +using System; +using System.Numerics; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +public struct S0 +{ + public ulong F5; +} + +public class C0 +{ + public int F1; +} + +public class Runtime_1068867 +{ + public static S0 s_7; + public static byte s_14; + + [Fact] + public static void TestEntryPoint() + { + if (Sve.IsSupported) + { + var vr12 = new C0(); + var vr14 = vr12.F1; + var vr15 = Vector128.CreateScalar(vr14).AsVector(); + var vr16 = Vector128.CreateScalar(0).AsVector(); + var vr17 = Vector128.CreateScalar(0).AsVector(); + var vr18 = Vector128.CreateScalar(0).AsVector(); + var vr19 = Vector128.CreateScalar(1).AsVector(); + var vr20 = Sve.ConditionalSelect(vr17, vr18, vr19); + var vr21 = Vector128.CreateScalar(0).AsVector(); + var vr22 = Sve.ConditionalSelect(vr16, vr20, vr21); + Consume(vr22); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static void Consume(T val) + { + } +} diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_106869/Runtime_106869.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_106869/Runtime_106869.csproj new file mode 100644 index 00000000000000..1352ebe3277bc7 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_106869/Runtime_106869.csproj @@ -0,0 +1,9 @@ + + + True + $(NoWarn),SYSLIB5003 + + + + +