Runtime Execution Modes
The mono for WebAssembly runtime provides three execution modes, Interpreter, AOT (Ahead of Time) and Mixed Mode Interpreter/AOT.
The execution mode can be set as follows:
The possible values are:
Interpreter(the default mode)
This mode is the slowest, but allows for great flexibility and debugging, as well as an efficient payload size.
The linker mode can also be completely disabled for troubleshooting, as this will not impact the wasm payload size.
This mode is a hybrid between the interpreter and the AOT modes, where the interpreter is used to execute the code, but the JIT engine is used to generate some WebAssembly code on the fly. This mode is generally faster than the interpreter, but slower than the AOT mode.
To enable this mode, use the following option:
<PropertyGroup> <WasmShellEnableJiterpreter>true</WasmShellEnableJiterpreter> </PropertyGroup>
Additionally, some options can be used to fine tune the Jiterpreter mode, using options found in this file:
<PropertyGroup> <WasmShellRuntimeOptions>--jiterpreter-stats-enable --jiterpreter-estimate-heat</WasmShellRuntimeOptions> </PropertyGroup>
Finally, runtime statistics are maintained by the jiterpreter and can be displayed by running
INTERNAL.jiterpreter_dump_stats() in the browser debugger console.
Mixed Interpreter and AOT Mode
This mode enable AOT compilation for most of the assemblies, with some specific exceptions.
This mode is generally prefered to FullAOT as it allows to load arbitrary assemblies and execute their code through the interpreter.
These modes are not supported on macOS as of .NET 6 (Bootstrapper 3.x), and .NET 7 (Bootstrapper 4.x). You'll need to use a Linux container to build with AOT, see below for more details.
Required configuration for AOT, Mixed Mode or static linking on Linux
- Ubuntu 18.04+ or a container
- A stable build of mono
- A .NET SDK >= 6.0
apt-get install ninja-build
The easiest is to build using the environment provided by the unoplatform/wasm-build docker image.
Profile Guided AOT
This mode allows for the AOT engine to selectively optimize methods to WebAssembly, and keep the rest as interpreted. This gives a very good balance when choosing between performance and payload size. It also has the advantage of reducing the build time, as less code needs to be compiled down to WebAssembly.
This feature is used in two passes:
- The first pass needs the creation of a profiled interpreter build, which records any methods invoked during the profiling session.
- The second pass rebuilds the application using the Mixed AOT/Interpreter mode augmented by the recording created during the first pass.
This mode gives very good results, where the RayTracer sample of this repository goes from an uncomressed size of 5.5MB to 2.9MB.
To create a profiled build:
- In your Wasm csproj, add the following:
- In your
LinkerConfig.xmlfile, add the following:
<assembly fullname="WebAssembly.Bindings" />
- Run the application once, without the debugger (e.g. Ctrl+F5)
- Navigate throughout the application in high usage places.
- Once done, either:
- Press the
- Launch App.saveProfile()
- Press the
- Download the
aot.profilefile next to the csproj file
- Comment the
- Add the following lines:
<ItemGroup> <WasmShellEnableAotProfile Include="aot.profile" /> </ItemGroup>
- Make sure that Mixed mode is enabled:
- Build you application again
Note that the AOT profile is a snapshot of the current set of assemblies and methods in your application. If that set changes significantly, you'll need to re-create the AOT profile to get optimal results.
AOT Profile method exclusion
The generated profile contains all the methods found to be executed during the profiling session, but some methods may still need to be manually excluded for some reasons (e.g. runtime or compile time errors).
WasmShellAOTProfileExcludedMethods property specifies a semi-colon separated list of regular expressions to exclude methods from the profile:
<PropertyGroup> <WasmShellAOTProfileExcludedMethods>Class1\.Method1;Class2\.OtherMethod</WasmShellAOTProfileExcludedMethods> <!-- use this syntax to separate the list on multiple lines --> <WasmShellAOTProfileExcludedMethods>$(WasmShellAOTProfileExcludedMethods);Class3.*</WasmShellAOTProfileExcludedMethods> </PropertyGroup>
MixedModeExcludedAssembly is also used to filter the profile for assemblies, see below for more information.
Dumping the whole list of original and filtered list is possible by adding:
<PropertyGroup> <WasmShellGenerateAOTProfileDebugList>true</WasmShellGenerateAOTProfileDebugList> </PropertyGroup>
This will generate files named
AOTProfileDump.*.txt in the
obj folder for inspection.
Mixed AOT/Interpreter Mode
This modes allows for the WebAssembly generation of parts of the referenced assemblies, and falls back to the interpreter for code that was excluded or not known at build time.
This allows for a fine balance between payload size and execution performance.
At this time, it is only possible to exclude assemblies from being compiled to WebAssembly through the use of this item group:
<ItemGroup> <MonoRuntimeMixedModeExcludedAssembly Include="Newtonsoft.Json" /> </ItemGroup>
Adding assemblies to this list will exclude them from being compiled to WebAssembly.
Troubleshooting Mixed AOT/Interpreter Mode
When using the Mixed AOT/Interpreter mode, it is possible that some methods may not be compiled to WebAssembly for a variety of reasons. This can cause performance issues, as the interpreter is slower than the AOT generated code.
In order to determine which methods are still using the interpreter, you can use the following property:
<PropertyGroup> <WasmShellPrintAOTSkippedMethods>true</WasmShellPrintAOTSkippedMethods> </PropertyGroup>
The logs from the AOT compiler can be found in binlogs generated from the build.
Required configuration for AOT, Mixed Mode or external bitcode support compilation on Windows 10
Native windows tooling
This mode is compatible with CI servers which have Python installed by default, such as Azure Devops Hosted Agents.
The bootstrapper needs to use powershell, and configuration is needed.
You'll need to run the following command in an elevated (administrator) PowerShell prompt:
Set-ExecutionPolicy RemoteSigned -Force
You may also need to enable the developer mode for Windows 10 and 11 by using Control panel / System / Privacy & Security / For developers / PowerShell and setting Change execution policy to allow local scripts to run without signing to On.
Using Windows Subsystem for Linux
This mode can be enabled by adding this property to the
<PropertyGroup> <WasmShellEnableEmscriptenWindows>false</WasmShellEnableEmscriptenWindows> </PropertyGroup>
- A Windows 10 machine with WSL 1 or 2 with Ubuntu 20.04 installed.
- A stable build of mono
- A .NET SDK >= 3.1
apt-get install ninja-buildin WSL
If you have another distribution installed make sure that the 20.04 is the default using
wslconfig /s "Ubuntu-20.04". You can list your active distributions with
Note that WSL 2 is considerably slower than WSL 1 for the boostrapper scenario. You will need to set your distribution to version 1 using
wsl --set-version "Ubuntu-20.04" 1.
During the first use of WSL, if the environment is not properly setup, you will be guided to run the
dotnet-setup.sh script that will install Mono, .NET Core and some additional dependencies.
The emscripten installation is automatically done as part of the build.
The boostrapper uses its own installation of emscripten, installed by default in
$HOME/.uno/emsdk in the WSL filesystem. This can be globally overriden by setting the
WASMSHELL_WSLEMSDK environment variable.
WSL Integration for Windows 10
The integration with WSL provides a way for using AOT, Mixed mode or external bitcode support using Windows 10.
This feature is active only if one of those condition is true:
- There is a
*.afile in the
WasmShellForceUseWSLis set to