WebAssembly, or Wasm for short, is a hot topic these days and for good reasons. It has lots of promise, and for the Uno Platform, it promises to open up the Web to other languages and frameworks.
What is WebAssembly ?
WebAssembly is a low-level bytecode for the web, meant to be used as a compilation target for any language, much like ARM or x86. It has been built over the past few years by a W3C group, composed of various people from mostly browser, framework and hardware vendors. They have the simple concrete goal of being able to securely run arbitrary binary code with near-native performance.
It’s currently supported by all major browsers, making it a viable target today.
WebAssembly is agnostic in its definition. Even though its name contains “Web”, it is designed as a generic bytecode. That’s what allows for projects like Ethereum, Life, Nebulet or WebAssembly for .NET to run without any browser in sight. As Jay Phelps often mentions, WebAssembly is neither Web nor Assembly and can be adapted to many scenarios. It has the potential to ultimately be a true universal binary format, for any kind of programming.
Other good resources can be found in Matteo Basso’s Awesome Wasm curated list.
What does WebAssembly look like?
WebAssembly being a binary format, it’s not human readable, but it has a textual representation that makes it easier to reason with.
WebAssembly Studio is a good way have a peek inside the generated WebAssembly, where building this C code :
becomes this WebAssembly literal code:
It’s not particularly easy to read, as would any similar assembler code, but it gives an idea of how a stack-based virtual machine language works.
WebAssembly is a target that most developers will never have to interact with directly, in the same way, that most developers never have to interact with x86_64 or ARM64 directly. It will mostly remain a build target, an element in a drop-down list next to x86 and ARM64.
Consuming a WebAssembly module is generally composed of a
.wasm file and a JS glue file, as can be found in the default
main.js sample of WebAssembly Studio. The JS file is present to use the WebAssembly.instantiate method to load WebAssembly code.
Why WebAssembly ?
WebAssembly is mainly trying to solve the issues that make it difficult to optimize performance for large applications, provide access to binary-producing languages and improve the security of running the resulting code.
Security-wise, WebAssembly is very different from previous attempts to run arbitrary binary code in the browser, such as Flash, Java applets, VBA, Silverlight, ActiveX, … which all had (and continue to have) security and portability issues. For instance, security features include the inability to execute arbitrary memory locations. While this makes optionally JIT’ed languages (such as .NET based languages) a difficult target, it promises a higher security execution environment than its similar add-in based predecessors.
WebAssembly and .NET
Microsoft has been working on a WebAssembly port of the Mono runtime for a while now, and progress has been steady since the beginning of 2018. The runtime is looking as stable as it is on iOS and Android using the Uno Platform as a point of reference, which is quite the achievement.
There’s also the .NET Core Runtime (CoreRT) team who are working on a WebAssembly port of the .NET Native engine, and significant progress is being made there as well.
The security aspect of WebAssembly, with the inability to execute data segments of memory, makes for a difficult time running IL code. Commonly, Just-In-Time (JIT) compilation is used to emit code using the underlying platform’s instructions in data memory segments, then the CPU executes that data as code. The security constraint in WebAssembly is similar to the constraints found in iOS and watchOS, which do not allow such a compilation technique. The Mono team already worked under those constraints, and WebAssembly support requires the same kind of treatment to get around this limitation.
The obvious answer to this is the use of Ahead-of-Time Compilation (AOT), employing the same technique used for iOS and watchOS. Due to technical considerations such as the integration of Emscripten and its
The Mono interpreter is similar to a piece of code that to one that has been around for a long while (mint), used in the early days of Mono when the JIT engine (mini) wasn’t yet available. Its role is to take IL instructions one-by-one and execute them on top of a natively compiled runtime. It allows for IL code to instantly run in the proper environment, at the expense of execution performance.
While this makes for a good kick start solution, such an implementation contains a giant switch for each and every available opcode in the IL specification. This is giving a hard time to browsers when going through this hot execution path. It is also not really playing nice with CPU data caches, such as devices with i5 CPU or below with limited L2 cache size.
This situation is fortunately only temporary. When Mono’s AOT will be available, the code will instantly be a lot faster, even though by how much remains to be seen. The size aspect of the generated WASM binary is also an unknown variable, and it can also be difficult to extrapolate from other similar looking AOT target CPU architectures.
The interpreter mode will stay in Mono as a mixed execution mode. This will allow for scenarios of dynamic code generation using Roslyn to be viable in a non-JIT friendly environment, and enable pieces of the BCL such as Expression compilation to be functional.
Bootstrapping the mono-wasm SDK
The current challenge when using the mono-wasm SDK is its barrier to entry. There are still lots of things to fiddle around with and it’s not integrated in any way to Visual Studio or VS Code.
Based on the work from Frank A. Krueger on OOui, we built Uno.Wasm.Bootstrap, a simple NuGet package with no ties to any framework (not even the Uno Platform), other than mono-wasm. This allows the user to take a simple .NET Standard 2.0 library, and run it in the browser, using
We expect this package to change significantly in the near future. This includes the addition of new Mono features (such as the AOT and debugger support), Nuget integration, VS integration, etc…
In the second part of this article, we’ll touch on more advanced topics about the integration of Mono in WebAssembly and upcoming features.