diff --git a/docs/workflow/building/coreclr/nativeaot.md b/docs/workflow/building/coreclr/nativeaot.md index bb3d2817da0c..e2e6e0df31ba 100644 --- a/docs/workflow/building/coreclr/nativeaot.md +++ b/docs/workflow/building/coreclr/nativeaot.md @@ -76,6 +76,19 @@ You should now be able to publish the project for Wasm: `dotnet publish -r brows Once you build the repo, you can use the produced binaries in one of four ways specified below ("Using built binaries", "Building packages", "Convenience Visual Studio "repro" project", "Running tests"). +## Building for Multithreaded packages + +This is a work in progress and far from functional. Currently there exists just enough infrastructure to build packages for multithreaded runtime and libs, but they are not functional in the sense that they support multithreaded programs yet. +To build the browser multithreaded packages: +``` +build clr.aot+libs+nativeaot.packages -c Debug -a wasm -os browser '/p:WasmEnableThreads=true' +``` +To build the runtime tests for browser +``` +src\tests\build nativeaot Debug wasm tree nativeaot browser /p:LibrariesConfiguration=debug /p:WasmEnableThreads=true +``` + + ### Using built binaries In this workflow, you have a project file that you want to `dotnet publish`, but you want to use your own build of the compiler/runtime/framework. You need to be using a daily build of the .NET SDK downloaded from the dotnet/sdk repo. It's typically enough to just download the daily build ZIP file, unpack it, and make sure the unpacked directory is the first thing in your PATH. Don't forget to add a NuGet.config as specified by the dotnet/sdk repo- you'll hit restore issues otherwise. diff --git a/eng/native/configurecompiler.cmake b/eng/native/configurecompiler.cmake index b4aaa7fedbf5..1f4cfaeb68a4 100644 --- a/eng/native/configurecompiler.cmake +++ b/eng/native/configurecompiler.cmake @@ -148,6 +148,10 @@ elseif (CLR_CMAKE_HOST_UNIX) add_compile_options(-Wno-alloca) add_compile_options(-Wno-implicit-int-float-conversion) endif() + + if (CMAKE_USE_PTHREADS AND CLR_CMAKE_HOST_BROWSER) + add_compile_options(-pthread) + endif(CMAKE_USE_PTHREADS AND CLR_CMAKE_HOST_BROWSER) endif(MSVC) if (CLR_CMAKE_ENABLE_SANITIZERS) diff --git a/eng/pipelines/runtimelab.yml b/eng/pipelines/runtimelab.yml index 29e389806642..4e493e930bb5 100644 --- a/eng/pipelines/runtimelab.yml +++ b/eng/pipelines/runtimelab.yml @@ -71,6 +71,26 @@ extends: parameters: librariesConfiguration: Debug + # + # Build and test Wasm Debug multithreaded libraries and Debug runtime + # + - template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/common/global-build-job.yml + helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml + buildConfig: debug + platforms: + - browser_wasm_win + jobParameters: + timeoutInMinutes: 300 + buildArgs: -s clr.aot+libs -c debug -rc $(_BuildConfig) '/p:WasmEnableThreads=true' + nameSuffix: Multithreaded + postBuildSteps: + - template: /eng/pipelines/runtimelab/runtimelab-post-build-steps.yml + parameters: + librariesConfiguration: Debug + wasmEnableThreadsArg: /p:WasmEnableThreads=true + # # Build and test with Debug libraries and Checked runtime # diff --git a/eng/pipelines/runtimelab/runtimelab-post-build-steps.yml b/eng/pipelines/runtimelab/runtimelab-post-build-steps.yml index 30c759c705eb..c32174630dbf 100644 --- a/eng/pipelines/runtimelab/runtimelab-post-build-steps.yml +++ b/eng/pipelines/runtimelab/runtimelab-post-build-steps.yml @@ -8,6 +8,7 @@ parameters: runtimeVariant: '' isOfficialBuild: false librariesConfiguration: Debug + wasmEnableThreadsArg: '' steps: # For NativeAOT-LLVM, we have just built the Wasm-targeting native artifacts (the runtime and libraries). @@ -17,7 +18,7 @@ steps: displayName: Build the ILC and RyuJit cross-compilers # Build target packages (note: target libs already built). - - script: $(Build.SourcesDirectory)/build$(scriptExt) nativeaot.packages -os ${{ parameters.osGroup }} -a wasm -c $(buildConfigUpper) $(_officialBuildParameter) -ci + - script: $(Build.SourcesDirectory)/build$(scriptExt) nativeaot.packages -os ${{ parameters.osGroup }} -a wasm -c $(buildConfigUpper) $(_officialBuildParameter) -ci $(wasmEnableThreadsArg) displayName: Build target packages # Build host packages. @@ -26,12 +27,12 @@ steps: # Build coreclr native test output outside of official build - ${{ if ne(parameters.isOfficialBuild, true) }}: - - ${{ if and(eq(parameters.archType, 'wasm'), ne(parameters.nameSuffix, '')) }}: + - ${{ if and(eq(parameters.archType, 'wasm'), ne(parameters.nameSuffix, ''), eq(parameters.wasmEnableThreadsArg, '')) }}: - script: pwsh $(Build.SourcesDirectory)/eng/pipelines/runtimelab/set-ilc-emulation-environment.ps1 -Arch $(hostedTargetArch) displayName: Set up ILC emulation environment - ${{ if eq(parameters.archType, 'wasm') }}: - - script: $(Build.SourcesDirectory)/src/tests/build$(scriptExt) nativeaot $(buildConfigUpper) ${{ parameters.osGroup }} $(crossArg) $(_officialBuildParameter) ci tree nativeaot /p:LibrariesConfiguration=${{ parameters.librariesConfiguration }} + - script: $(Build.SourcesDirectory)/src/tests/build$(scriptExt) nativeaot $(buildConfigUpper) ${{ parameters.osGroup }} $(crossArg) $(_officialBuildParameter) ci tree nativeaot /p:LibrariesConfiguration=${{ parameters.librariesConfiguration }} ${{ parameters.wasmEnableThreadsArg }} displayName: Build runtime tests - ${{ else }}: - ${{ if eq(parameters.osGroup, 'windows') }}: @@ -42,14 +43,15 @@ steps: displayName: Build runtime tests - ${{ if contains(parameters.platform, 'win') }}: - - script: $(Build.SourcesDirectory)/src/tests/run$(scriptExt) runnativeaottests $(buildConfigUpper) ${{ parameters.archType }} ${{ parameters.osGroup }} - displayName: Run runtime tests + - ${{ if eq(parameters.wasmEnableThreadsArg, '') }}: + - script: $(Build.SourcesDirectory)/src/tests/run$(scriptExt) runnativeaottests $(buildConfigUpper) ${{ parameters.archType }} ${{ parameters.osGroup }} + displayName: Run runtime tests - ${{ else }}: - script: $(Build.SourcesDirectory)/src/tests/run$(scriptExt) --runnativeaottests $(buildConfigUpper) ${{ parameters.archType }} ${{ parameters.osGroup }} displayName: Run runtime tests # Don't compile/run the libraries tests with emulated ILC to save CI time/resources. - - ${{ if and(eq(parameters.archType, 'wasm'), eq(parameters.nameSuffix, '')) }}: + - ${{ if and(eq(parameters.archType, 'wasm'), eq(parameters.nameSuffix, ''), eq(parameters.wasmEnableThreadsArg, '')) }}: - script: $(Build.SourcesDirectory)/build$(scriptExt) libs.tests -test -a ${{ parameters.archType }} -os ${{ parameters.osGroup }} -lc ${{ parameters.librariesConfiguration }} -rc $(buildConfigUpper) /p:TestNativeAot=true /p:RunSmokeTestsOnly=true displayName: Build and run WebAssembly libraries tests diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets index 81d474349d49..5b267fe2bc28 100644 --- a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets +++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets @@ -438,6 +438,7 @@ The .NET Foundation licenses this file to you under the MIT license. $(CompileWasmArgs) -g3 $(CompileWasmArgs) -mnontrapping-fptoint $(CompileWasmArgs) -fwasm-exceptions + $(CompileWasmArgs) -pthread @@ -604,6 +605,8 @@ The .NET Foundation licenses this file to you under the MIT license. + + diff --git a/src/coreclr/nativeaot/CMakeLists.txt b/src/coreclr/nativeaot/CMakeLists.txt index aff6c47180c9..c26e0d1ae2bf 100644 --- a/src/coreclr/nativeaot/CMakeLists.txt +++ b/src/coreclr/nativeaot/CMakeLists.txt @@ -32,6 +32,12 @@ if(CLR_CMAKE_TARGET_OS STREQUAL wasi) add_definitions(-DTARGET_UNIX) endif(CLR_CMAKE_TARGET_OS STREQUAL wasi) +if((CLR_CMAKE_TARGET_OS STREQUAL wasi OR CLR_CMAKE_TARGET_OS STREQUAL emscripten) + AND CMAKE_USE_PTHREADS) + add_definitions(-DFEATURE_WASM_MANAGED_THREADS) +endif((CLR_CMAKE_TARGET_OS STREQUAL wasi OR CLR_CMAKE_TARGET_OS STREQUAL emscripten) + AND CMAKE_USE_PTHREADS) + if(CLR_CMAKE_TARGET_ANDROID) add_definitions(-DFEATURE_EMULATED_TLS) endif() diff --git a/src/coreclr/nativeaot/Runtime/eventpipe/CMakeLists.txt b/src/coreclr/nativeaot/Runtime/eventpipe/CMakeLists.txt index 739738e67434..4368bb84bb30 100644 --- a/src/coreclr/nativeaot/Runtime/eventpipe/CMakeLists.txt +++ b/src/coreclr/nativeaot/Runtime/eventpipe/CMakeLists.txt @@ -2,6 +2,11 @@ project(Runtime) include(FindPython) +# Workaround from https://github.com/dotnet/runtime/pull/117513 +if (NOT "$ENV{EMSDK_PYTHON}" STREQUAL "") + set(Python_EXECUTABLE "$ENV{EMSDK_PYTHON}") +endif() + set(CMAKE_INCLUDE_CURRENT_DIR ON) set(EVENT_MANIFEST ${VM_DIR}/ClrEtwAll.man) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj index afd176a315c0..8c769d77019c 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj @@ -35,6 +35,9 @@ true true + + true + $(DefineConstants);FEATURE_WASM_MANAGED_THREADS true @@ -347,6 +350,8 @@ + + diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Monitor.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Monitor.NativeAot.cs index 4c90bbaa42ad..9c33774f1619 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Monitor.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Monitor.NativeAot.cs @@ -143,7 +143,9 @@ public static bool IsEntered(object obj) #region Public Wait/Pulse methods +#if !FEATURE_WASM_MANAGED_THREADS [UnsupportedOSPlatform("browser")] +#endif public static bool Wait(object obj, int millisecondsTimeout) { return GetCondition(obj).Wait(millisecondsTimeout, obj); diff --git a/src/coreclr/runtime.proj b/src/coreclr/runtime.proj index 0e0bff962b16..ef6b5dd29d93 100644 --- a/src/coreclr/runtime.proj +++ b/src/coreclr/runtime.proj @@ -94,6 +94,10 @@ <_CoreClrBuildArg Include="-cmakeargs "-DCLR_CMAKE_ESRP_CLIENT=$(DotNetEsrpToolPath)"" /> + + <_CoreClrBuildArg Include="-cmakeargs "-DCMAKE_USE_PTHREADS=1"" /> + + <_CoreClrBuildScript Condition="$([MSBuild]::IsOsPlatform(Windows))">build-runtime.cmd <_CoreClrBuildScript Condition="!$([MSBuild]::IsOsPlatform(Windows))">build-runtime.sh diff --git a/src/installer/pkg/projects/nativeaot-packages.proj b/src/installer/pkg/projects/nativeaot-packages.proj index 8a640a9c08c0..0a1404df62c1 100644 --- a/src/installer/pkg/projects/nativeaot-packages.proj +++ b/src/installer/pkg/projects/nativeaot-packages.proj @@ -4,7 +4,8 @@ - + + diff --git a/src/libraries/Common/src/Interop/Browser/Interop.Runtime.NativeAOT.cs b/src/libraries/Common/src/Interop/Browser/Interop.Runtime.NativeAOT.cs index 3d2fdaae538d..7f33ff8ae73c 100644 --- a/src/libraries/Common/src/Interop/Browser/Interop.Runtime.NativeAOT.cs +++ b/src/libraries/Common/src/Interop/Browser/Interop.Runtime.NativeAOT.cs @@ -28,6 +28,30 @@ internal static unsafe partial class Runtime [LibraryImport(JSLibrary, EntryPoint = "mono_wasm_cancel_promise", StringMarshalling = StringMarshalling.Utf16)] public static unsafe partial void CancelPromise(IntPtr gcHandle); +#if FEATURE_WASM_MANAGED_THREADS + // Required by JavaScript/JSFunctionBinding.cs + [LibraryImport(JSLibrary, EntryPoint = "mono_wasm_invoke_js_function_send")] + public static unsafe partial void InvokeJSFunctionSend(nint targetNativeTID, nint functionHandle, nint data); + [LibraryImport(JSLibrary, EntryPoint = "mono_wasm_invoke_jsimport_MT")] + public static unsafe partial void InvokeJSImportSync(nint signature, nint args); + [LibraryImport(JSLibrary, EntryPoint = "mono_wasm_invoke_jsimport_sync_send")] + public static unsafe partial void InvokeJSImportSyncSend(nint targetNativeTID, nint signature, nint args); + [LibraryImport(JSLibrary, EntryPoint = "mono_wasm_invoke_jsimport_async_post")] + public static unsafe partial void InvokeJSImportAsyncPost(nint targetNativeTID, nint signature, nint args); + [LibraryImport(JSLibrary, EntryPoint = "mono_wasm_resolve_or_reject_promise_post")] + public static unsafe partial void ResolveOrRejectPromisePost(nint targetNativeTID, nint data); + [LibraryImport(JSLibrary, EntryPoint = "mono_wasm_install_js_worker_interop_wrapper")] + public static unsafe partial void InstallWebWorkerInterop(nint proxyContextGCHandle, void* beforeSyncJSImport, void* afterSyncJSImport, void* pumpHandler); + // Required by JavaScript/JSProxyContext.cs + [LibraryImport(JSLibrary, EntryPoint = "mono_wasm_release_cs_owned_object_post")] + internal static unsafe partial void ReleaseCSOwnedObjectPost(nint targetNativeTID, nint jsHandle); + [LibraryImport(JSLibrary, EntryPoint = "mono_wasm_uninstall_js_worker_interop")] + public static unsafe partial void UninstallWebWorkerInterop(); + // Required by JavaScript/CancelablePromise.cs + [LibraryImport(JSLibrary, EntryPoint = "mono_wasm_cancel_promise_post")] + public static unsafe partial void CancelPromisePost(nint targetNativeTID, nint taskHolderGCHandle); +#endif + #region Not used by NativeAOT public static IntPtr RegisterGCRoot(void* start, int bytesSize, IntPtr name) => throw new NotImplementedException(); public static void DeregisterGCRoot(IntPtr handle) => throw new NotImplementedException(); diff --git a/src/mono/browser/runtime/loader/polyfills.ts b/src/mono/browser/runtime/loader/polyfills.ts index 181323b0fe0a..4b230101a57f 100644 --- a/src/mono/browser/runtime/loader/polyfills.ts +++ b/src/mono/browser/runtime/loader/polyfills.ts @@ -22,7 +22,8 @@ export function verifyEnvironment () { mono_assert(ENVIRONMENT_IS_SHELL || typeof globalThis.URL === "function", "This browser/engine doesn't support URL API. Please use a modern version. See also https://aka.ms/dotnet-wasm-features"); mono_assert(typeof globalThis.BigInt64Array === "function", "This browser/engine doesn't support BigInt64Array API. Please use a modern version. See also https://aka.ms/dotnet-wasm-features"); if (WasmEnableThreads) { - mono_assert(!ENVIRONMENT_IS_SHELL && !ENVIRONMENT_IS_NODE, "This build of dotnet is multi-threaded, it doesn't support shell environments like V8 or NodeJS. See also https://aka.ms/dotnet-wasm-features"); + // TODO-LLVM: Comment this check out for now so we can run at least some tests. + //mono_assert(!ENVIRONMENT_IS_SHELL && !ENVIRONMENT_IS_NODE, "This build of dotnet is multi-threaded, it doesn't support shell environments like V8 or NodeJS. See also https://aka.ms/dotnet-wasm-features"); mono_assert(globalThis.SharedArrayBuffer !== undefined, "SharedArrayBuffer is not enabled on this page. Please use a modern browser and set Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy http headers. See also https://aka.ms/dotnet-wasm-features"); mono_assert(typeof globalThis.EventTarget === "function", "This browser/engine doesn't support EventTarget API. Please use a modern version. See also https://aka.ms/dotnet-wasm-features"); } diff --git a/src/tests/Common/dirs.proj b/src/tests/Common/dirs.proj index 7931d4bd7b7b..a25d5c9ac1a8 100644 --- a/src/tests/Common/dirs.proj +++ b/src/tests/Common/dirs.proj @@ -31,6 +31,11 @@ + + + + + diff --git a/src/tests/build.proj b/src/tests/build.proj index 66652353a200..baff7199bda3 100644 --- a/src/tests/build.proj +++ b/src/tests/build.proj @@ -490,6 +490,7 @@ $(GroupBuildCmd) "/p:MonoForceInterpreter=true" $(GroupBuildCmd) "/p:RunAOTCompilation=true" $(GroupBuildCmd) "/p:DevTeamProvisioning=$(DevTeamProvisioning)" + $(GroupBuildCmd) "/p:WasmEnableThreads=$(WasmEnableThreads)"