diff options
Diffstat (limited to '_posts')
-rw-r--r-- | _posts/2020-02-11-on-webassembly-killing-javascript.md | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/_posts/2020-02-11-on-webassembly-killing-javascript.md b/_posts/2020-02-11-on-webassembly-killing-javascript.md new file mode 100644 index 0000000..bab3b6e --- /dev/null +++ b/_posts/2020-02-11-on-webassembly-killing-javascript.md @@ -0,0 +1,206 @@ +--- +title: On WebAssembly killing JavaScript +date: 2020-02-11 +layout: post +lang: en +ref: on-webassembly-killing-javascript +--- +When discussing WebAssembly (WASM), I often see people portraiting it too much +as a JavaScript replacement, but I think this framing misses the point of some +of the aspects on how WASM can be a great tool: being a portability oportunity, +which means increasing the reach to code. + +If you think of WASM strictly as a optimization of JavaScript, that's where +you'll end up: WASM is the same as JavaScript, but faster. + +But there's a more interesting aspect (to me) of it: portability. That means you +can now write multiplatformr code that runs everywhere. I mean, everywhere, even +in the browser. Let's imagine how you could write SQLite and mke it run on the Web. + +# SQLite + + If I were to create, say, SQLite today, I would consider adding +web support for it. SQLite already is available everywhere[^1]. This is due to +it having very few dependencies and + +Imagine having writing SQLite today + +There are also other legimate uses of WASM, such as WASI and etc. + +Here's how I would start writing an application that could run on any POSIX +system and, on top of that, could run on the browser: + +``` +// api.h + +extern void platformDependentPersistInt(int); +extern int platformDependentRetrieveInt(); + + +// api-posix.c + +/* POSIX implementation of "api.h" interface to be used in non-web contexts */ + +#include <stdio.h> + +void platformDependentPersistInt(int n) { + FILE* fp = fopen("/tmp/persisted.txt", "w+"); + fprintf(fp, "%d", n); + fclose(fp); +} + +int platformDependentRetrieveInt() { + FILE* fp = fopen("/tmp/persisted.txt", "r"); + int persisted = fgetc(fp); + return persisted; +} + + +// api-wasm.js + +/* WASM implementation of "api.h" interface to be used in web contexts */ + +export const platformDependentPersistInt = (n) => + localStorage.setItem("persisted", n.toString()); + +export const platformDependentRetrieveInt = () => + parseInt(localStorage.getItem("persisted")); + + +// add.h + +int add(int a, int b); +void persistInt(int n); +int retrieveInt(); + + +// add.c + +#include "api.h" + +int add(int a, int b) { + return a * a + b; +} + +void persistInt(int n) { + platformDependentPersistInt(n); +} + +int retrieveInt() { + return platformDependentRetrieveInt(); +} +``` + +``` +// main.c + +#include <stdio.h> +#include "add.h" + +int main() { + int added = add(4, 5); + printf("Adding 4 and 5: %d\n", added); + + persistInt(6); + int persisted = retrieveInt(); + printf("Persisted number: %c\n", persisted); + return 0; +} + + +// index.html + +<script type="module"> + import * as api from "./api-wasm.js"; + + WebAssembly + .instantiateStreaming(fetch("add.wasm"), { env: api }) + .then(({instance: {exports}}) => { + const added = exports.add(4, 5); + console.log("Adding 4 and 5:", added); + + exports.persistInt(6); + const persisted = exports.retrieveInt(); + console.log("Persisted number:", persisted); + }); +</script> +``` + +In order to +``` +// server.py + +#!/usr/bin/env python +import SimpleHTTPServer +import SocketServer + +PORT = 8001 + +class Handler(SimpleHTTPServer.SimpleHTTPRequestHandler): + pass + +Handler.extensions_map['.wasm'] = 'application/wasm' + +httpd = SocketServer.TCPServer(("", PORT), Handler) + +print "serving at port", PORT +httpd.serve_forever() +``` + +Dependency graph: +FIXME +api-posix.c api-wasm.js +api.h +add.h +add.c +main.c index.html + +Compiling and running the POSIX code: +```shell +$ clang -o add main.c add.c api-posix.c +$ ./add +Adding 4 and 5: 21 +Persisted number: 6 +``` + +Compiling and running the WASM +```shell +$ clang \ + --target=wasm32 \ + -nostdlib \ + -Wl,--no-entry \ + -Wl,--export-all \ + -Wl,--allow-undefined \ + -o add.wasm \ + add.c +$ ./server.py +``` + +After opening the browser, the console shows: +``` +Adding 4 and 5: 21 +Persisted number: 6 +``` + +Rust, C, Zig + +No Emscripten, no GC, no runtime + +Emscripten 11KB + +# Limitations + +"System call" cost in WebAssembly. + +WASM is very new, no flush guarantees. + +Confusing dependency tree + +AFAICT you can't package WASM with JavaScript. + + +[^1]: [Platforms supported by SQLite are](https://sqlite.org/features.html): + "Android, *BSD, iOS, Linux, Mac, Solaris, VxWorks, and Windows (Win32, + WinCE, WinRT) are supported out of the box. Easy to port to other systems". + +https://sqlite.org/selfcontained.html |