-
Notifications
You must be signed in to change notification settings - Fork 3.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This adds an option to build "standalone" wasm files, that is, files that can be run without JavaScript. They idea is that they can be run in either A wasm server runtime like wasmer or wasmtime, where the supported APIs are wasi. A custom wasm embedding that uses wasm as plugins or dynamic libraries, where the supported APIs may include application-specific imports and exports, some subset of wasi, and other stuff (but probably not JS-specific things). This removes the old EMITTING_JS flag, which was only used to check whether to minify wasm imports and exports. The new STANDALONE_WASM flag also prevents such minification (since we can't assume the JS will be the only thing to run the wasm), but is more general, in that we may still emit JS with that flag, but when we do the JS is only a convenient way to run the code on the Web or in Node.js, as the wasm can also be run standalone. Note that SIDE_MODULE is an interesting case here: with wasm, a side module is just a wasm file (no JS), so we used to set EMITTING_JS to 0. However, we can't just set STANDALONE_WASM in that case, since the side module may expect to be linked with a main module that is not standalone, that is, that depends on JS (i.e. the side module may call things in the main module which are from JS). Aside from side modules, though, if the user says -o X.wasm (emit wasm, no JS file) then we do set STANDALONE_WASM, since that is the likely intention (otherwise, without this flag running such a wasm file would be incredibly difficult since it wasn't designed for it!). The main reason for needing a new flag here is that while we can use many wasi APIs by default, like fd_write, there are some changes that are bad for JS. The main one is Memory handling: it's better to create the Memory early in JS, both to avoid fragmentation issues on 32-bit, and to allow using the Memory by JS while the wasm is still loading (e.g. to set up files). For standalone wasm, though, we can't do that since there is no JS to create it for us, and indeed wasi runtimes expect the memory to be created and not imported. So STANDALONE_WASM basically means, "make an effort to make the wasm as standalone as possible, even that wouldn't be good for JS." Without this flag we do still try to do that, but not when it compromises JS size. This adds libstandalone_wasm which contains things in C to avoid using JS, like routing exit to wasi's proc_exit. There may be better ways to do some of those things, which I intend to look into as followups, but I think this is a good first step to get the flag landed in a working and tested state, in as small a PR as possible. This adds testing in the form of running standalone wasm files in wasmer and wasmtime, on Linux. I have some ideas about how to generalize that in a nicer way, but want to leave that for followups. This updates EMSCRIPTEN_METADATA - we need a new field to know whether a wasm is standalone or not, as the ABI is different.
- Loading branch information
Showing
13 changed files
with
232 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
/* | ||
* Copyright 2019 The Emscripten Authors. All rights reserved. | ||
* Emscripten is available under two separate licenses, the MIT license and the | ||
* University of Illinois/NCSA Open Source License. Both these licenses can be | ||
* found in the LICENSE file. | ||
*/ | ||
|
||
mergeInto(LibraryManager.library, { | ||
proc_exit__deps: ['exit'], | ||
proc_exit: function(code) { | ||
return _exit(code); | ||
}, | ||
}); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
/* | ||
* Copyright 2019 The Emscripten Authors. All rights reserved. | ||
* Emscripten is available under two separate licenses, the MIT license and the | ||
* University of Illinois/NCSA Open Source License. Both these licenses can be | ||
* found in the LICENSE file. | ||
*/ | ||
|
||
#include <emscripten.h> | ||
#include <errno.h> | ||
#include <stdio.h> | ||
#include <string.h> | ||
|
||
#include <wasi/wasi.h> | ||
|
||
/* | ||
* WASI support code. These are compiled with the program, and call out | ||
* using wasi APIs, which can be provided either by a wasi VM or by our | ||
* emitted JS. | ||
*/ | ||
|
||
// libc | ||
|
||
void exit(int status) { | ||
__wasi_proc_exit(status); | ||
__builtin_unreachable(); | ||
} | ||
|
||
void abort() { | ||
exit(1); | ||
} | ||
|
||
// Musl lock internals. As we assume wasi is single-threaded for now, these | ||
// are no-ops. | ||
|
||
void __lock(void* ptr) {} | ||
void __unlock(void* ptr) {} | ||
|
||
// Emscripten additions | ||
|
||
void *emscripten_memcpy_big(void *restrict dest, const void *restrict src, size_t n) { | ||
// This normally calls out into JS which can do a single fast operation, | ||
// but with wasi we can't do that. As this is called when n >= 8192, we | ||
// can just split into smaller calls. | ||
// TODO optimize, maybe build our memcpy with a wasi variant, maybe have | ||
// a SIMD variant, etc. | ||
const int CHUNK = 8192; | ||
unsigned char* d = (unsigned char*)dest; | ||
unsigned char* s = (unsigned char*)src; | ||
while (n > 0) { | ||
size_t curr_n = n; | ||
if (curr_n > CHUNK) curr_n = CHUNK; | ||
memcpy(d, s, curr_n); | ||
d += CHUNK; | ||
s += CHUNK; | ||
n -= curr_n; | ||
} | ||
return dest; | ||
} | ||
|
||
static const int WASM_PAGE_SIZE = 65536; | ||
|
||
// Note that this does not support memory growth in JS because we don't update the JS | ||
// heaps. Wasm and wasi lack a good API for that. | ||
int emscripten_resize_heap(size_t size) { | ||
size_t result = __builtin_wasm_memory_grow(0, (size + WASM_PAGE_SIZE - 1) / WASM_PAGE_SIZE); | ||
return result != (size_t)-1; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.