Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

STANDALONE_WASM option #9461

Merged
merged 25 commits into from
Sep 20, 2019
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,16 @@ jobs:
command: |
apt-get update -q
apt-get install -q -y python3 cmake
- run:
name: get wasmer
command: |
curl https://get.wasmer.io -sSfL | sh
- run:
name: get wasmtime
command: |
wget https://github.com/CraneStation/wasmtime/releases/download/dev/wasmtime-dev-x86_64-linux.tar.xz
tar -xf wasmtime-dev-x86_64-linux.tar.xz
cp wasmtime-dev-x86_64-linux/wasmtime ~/
- run:
name: install emsdk
command: |
Expand Down
4 changes: 4 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ Current Trunk
- Module.abort is no longer exported by default. It can be exported in the normal
way using `EXTRA_EXPORTED_RUNTIME_METHODS`, and as with other such changes in
the past, forgetting to export it with show a clear error in `ASSERTIONS` mode.
- Remove `EMITTING_JS` flag, and replace it with `STANDALONE_WASM`. That flag indicates
that we want the wasm to be as standalone as possible. We may still emit JS in
that case, but the JS would just be a convenient way to run the wasm on the Web
or in Node.js.

v.1.38.44: 09/11/2019
---------------------
Expand Down
21 changes: 19 additions & 2 deletions emcc.py
Original file line number Diff line number Diff line change
Expand Up @@ -1674,9 +1674,13 @@ def check_human_readable_list(items):
if use_source_map(options):
exit_with_error('wasm2js does not support source maps yet (debug in wasm for now)')

# wasm outputs are only possible with a side wasm
if target.endswith(WASM_ENDINGS):
shared.Settings.EMITTING_JS = 0
# if the output is just a wasm file, it will normally be a standalone one,
# as there is no JS. an exception are side modules, as we can't tell at
# compile time whether JS will be involved or not - the main module may
# have JS, and the side module is expected to link against that.
if not shared.Settings.SIDE_MODULE:
shared.Settings.STANDALONE_WASM = 1
js_target = misc_temp_files.get(suffix='.js').name

if shared.Settings.EVAL_CTORS:
Expand Down Expand Up @@ -1741,6 +1745,19 @@ def check_human_readable_list(items):
if shared.Settings.MINIMAL_RUNTIME and not shared.Settings.WASM:
options.separate_asm = True

if shared.Settings.STANDALONE_WASM:
if not shared.Settings.WASM_BACKEND:
exit_with_error('STANDALONE_WASM is only available in the upstream wasm backend path')
if shared.Settings.USE_PTHREADS:
exit_with_error('STANDALONE_WASM does not support pthreads yet')
if shared.Settings.SIMD:
exit_with_error('STANDALONE_WASM does not support simd yet')
if shared.Settings.ALLOW_MEMORY_GROWTH:
exit_with_error('STANDALONE_WASM does not support memory growth yet')
# the wasm must be runnable without the JS, so there cannot be anything that
# requires JS legalization
shared.Settings.LEGALIZE_JS_FFI = 0

if shared.Settings.WASM_BACKEND:
if shared.Settings.SIMD:
newargs.append('-msimd128')
Expand Down
2 changes: 2 additions & 0 deletions emscripten.py
Original file line number Diff line number Diff line change
Expand Up @@ -2321,6 +2321,8 @@ def debug_copy(src, dst):
cmd.append('--global-base=%s' % shared.Settings.GLOBAL_BASE)
if shared.Settings.SAFE_STACK:
cmd.append('--check-stack-overflow')
if shared.Settings.STANDALONE_WASM:
cmd.append('--standalone-wasm')
shared.print_compiler_stage(cmd)
stdout = shared.check_call(cmd, stdout=subprocess.PIPE).stdout
if write_source_map:
Expand Down
2 changes: 1 addition & 1 deletion site/source/docs/tools_reference/emcc.rst
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,7 @@ Options that are modified or new in *emcc* are listed below:
- <name> **.html** : HTML + separate JavaScript file (**<name>.js**; + separate **<name>.wasm** file if emitting WebAssembly).
- <name> **.bc** : LLVM bitcode.
- <name> **.o** : LLVM bitcode (same as .bc), unless in `WASM_OBJECT_FILES` mode, in which case it will contain a WebAssembly object.
- <name> **.wasm** : WebAssembly without JavaScript support code ("standalone wasm").
- <name> **.wasm** : WebAssembly without JavaScript support code ("standalone wasm"; this enables ``STANDALONE_WASM``).

.. note:: If ``--memory-init-file`` is used, a **.mem** file will be created in addition to the generated **.js** and/or **.html** file.

Expand Down
14 changes: 14 additions & 0 deletions src/library_wasi.js
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);
},
});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this. I really hope we can move fd_read in there and link it by default in the future.


4 changes: 4 additions & 0 deletions src/modules.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,10 @@ var LibraryManager = {
libraries.push('library_glemu.js');
}

if (STANDALONE_WASM) {
libraries.push('library_wasi.js');
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why make this conditional? Aren't all the library functions only included on demand anyway?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it's all on demand, but we also include some libraries only based on their flags, like the GL stuff right above this. I think it's nice as it reflects the fact that nothing should be used from those libraries without the flag, the error is clearer that way.

}

libraries = libraries.concat(additionalLibraries);

if (BOOTSTRAPPING_STRUCT_INFO) libraries = ['library_bootstrap_structInfo.js', 'library_formatString.js'];
Expand Down
6 changes: 6 additions & 0 deletions src/preamble.js
Original file line number Diff line number Diff line change
Expand Up @@ -989,6 +989,12 @@ function createWasm() {
exports = Asyncify.instrumentWasmExports(exports);
#endif
Module['asm'] = exports;
#if STANDALONE_WASM
// In pure wasm mode the memory is created in the wasm (not imported), and
// then exported.
// TODO: do not create a Memory earlier in JS
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like a TODO we certainly want to fix.

updateGlobalBufferAndViews(exports['memory'].buffer);
#endif
#if USE_PTHREADS
// Keep a reference to the compiled module so we can post it to the workers.
wasmModule = module;
Expand Down
29 changes: 26 additions & 3 deletions src/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -1049,9 +1049,6 @@ var EMTERPRETIFY_SYNCLIST = [];
// whether js opts will be run, after the main compiler
var RUNNING_JS_OPTS = 0;

// whether we are emitting JS glue code
var EMITTING_JS = 1;

// whether we are in the generate struct_info bootstrap phase
var BOOTSTRAPPING_STRUCT_INFO = 0;

Expand All @@ -1072,6 +1069,31 @@ var USE_GLFW = 2;
// port, which can useful for local dev work on binaryen itself).
var WASM = 1;

// STANDALONE_WASM indicates that we want to emit a wasm file that can run without
// JavaScript. The file will use standard APIs such as wasi as much as possible
// to achieve that.
//
// This option does not guarantee that the wasm can be used by itself - if you
// use APIs with no non-JS alternative, we will still use those (e.g., OpenGL
// at the time of writing this). This gives you the option to see which APIs
// are missing, and if you are compiling for a custom wasi embedding, to add
// those to your embedding.
//
// We may still emit JS with this flag, but the JS should only be a convenient
// way to run the wasm on the Web or in Node.js, and you can run the wasm by
// itself without that JS (again, unless you use APIs for which there is no
// non-JS alternative) in a wasm runtime like wasmer or wasmtime.
//
// Note that even without this option we try to use wasi etc. syscalls as much
// as possible. What this option changes is that we do so even when it means
// a tradeoff with JS size. For example, when this option is set we do not
// import the Memory - importing it is useful for JS, so that JS can start to
// use it before the wasm is even loaded, but in wasi and other wasm-only
// environments the expectation is to create the memory in the wasm itself.
// Doing so prevents some possible JS optimizations, so we only do it behind
// this flag.
var STANDALONE_WASM = 0;

// Whether to use the WebAssembly backend that is in development in LLVM. You
// should not set this yourself, instead set EMCC_WASM_BACKEND=1 in the
// environment.
Expand Down Expand Up @@ -1628,4 +1650,5 @@ var LEGACY_SETTINGS = [
['PRECISE_I64_MATH', [1, 2], 'Starting from Emscripten 1.38.26, PRECISE_I64_MATH is always enabled (https://github.com/emscripten-core/emscripten/pull/7935)'],
['MEMFS_APPEND_TO_TYPED_ARRAYS', [1], 'Starting from Emscripten 1.38.26, MEMFS_APPEND_TO_TYPED_ARRAYS=0 is no longer supported. MEMFS no longer supports using JS arrays for file data (https://github.com/emscripten-core/emscripten/pull/7918)'],
['ERROR_ON_MISSING_LIBRARIES', [1], 'missing libraries are always an error now'],
['EMITTING_JS', [1], 'The new STANDALONE_WASM flag replaces this (replace EMITTING_JS=0 with STANDALONE_WASM=1)'],
];
67 changes: 67 additions & 0 deletions system/lib/standalone_wasm.c
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;
}
45 changes: 35 additions & 10 deletions tests/test_other.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
raise Exception('do not run this file directly; do something like: tests/runner.py other')

from tools.shared import Building, PIPE, run_js, run_process, STDOUT, try_delete, listify
from tools.shared import EMCC, EMXX, EMAR, EMRANLIB, PYTHON, FILE_PACKAGER, WINDOWS, MACOS, LLVM_ROOT, EMCONFIG, EM_BUILD_VERBOSE
from tools.shared import EMCC, EMXX, EMAR, EMRANLIB, PYTHON, FILE_PACKAGER, WINDOWS, MACOS, LINUX, LLVM_ROOT, EMCONFIG, EM_BUILD_VERBOSE
from tools.shared import CLANG, CLANG_CC, CLANG_CPP, LLVM_AR
from tools.shared import COMPILER_ENGINE, NODE_JS, SPIDERMONKEY_ENGINE, JS_ENGINES, V8_ENGINE
from tools.shared import WebAssembly
Expand Down Expand Up @@ -8296,16 +8296,21 @@ def run(args, expected):
run(['-s', 'TOTAL_MEMORY=32MB', '-s', 'ALLOW_MEMORY_GROWTH=1', '-s', 'BINARYEN=1'], (2 * 1024 * 1024 * 1024 - 65536) // 16384)
run(['-s', 'TOTAL_MEMORY=32MB', '-s', 'ALLOW_MEMORY_GROWTH=1', '-s', 'BINARYEN=1', '-s', 'WASM_MEM_MAX=128MB'], 2048 * 4)

def test_wasm_targets(self):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it ok that we seems to have lost of test coverage for fastcomp here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, good point, I missed something here. I thought it was fine to remove this, but actually it hid a possible regression: building in fastcomp without SIDE_MODULE but with -o X.wasm.

That never worked very well anyhow, it was a half-hearted attempt at standalone wasm files. So I am leaning towards showing a clear error in that case that the user should use the upstream wasm backend for standalone wasm?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like there is a reasonable fix actually, pushed now.

@no_fastcomp('only upstream supports STANDALONE_WASM')
def test_wasm_target_and_STANDALONE_WASM(self):
# STANDALONE_WASM means we never minify imports and exports.
for opts, potentially_expect_minified_exports_and_imports in (
([], False),
(['-O2'], False),
(['-O3'], True),
(['-Os'], True),
([], False),
(['-O2'], False),
(['-O3'], True),
(['-O3', '-s', 'STANDALONE_WASM'], False),
(['-Os'], True),
):
# targeting .wasm (without .js) means we enable STANDALONE_WASM automatically, and don't minify imports/exports
for target in ('out.js', 'out.wasm'):
expect_minified_exports_and_imports = potentially_expect_minified_exports_and_imports and target.endswith('.js')
print(opts, potentially_expect_minified_exports_and_imports, target, ' => ', expect_minified_exports_and_imports)
standalone = target.endswith('.wasm') or 'STANDALONE_WASM' in opts
print(opts, potentially_expect_minified_exports_and_imports, target, ' => ', expect_minified_exports_and_imports, standalone)

self.clear()
run_process([PYTHON, EMCC, path_from_root('tests', 'hello_world.cpp'), '-o', target] + opts)
Expand All @@ -8317,13 +8322,33 @@ def test_wasm_targets(self):
exports = [line.strip().split(' ')[1].replace('"', '') for line in wast_lines if "(export " in line]
imports = [line.strip().split(' ')[2].replace('"', '') for line in wast_lines if "(import " in line]
exports_and_imports = exports + imports
print(exports)
print(imports)
print(' exports', exports)
print(' imports', imports)
if expect_minified_exports_and_imports:
assert 'a' in exports_and_imports
else:
assert 'a' not in exports_and_imports
assert 'memory' in exports_and_imports, 'some things are not minified anyhow'
assert 'memory' in exports_and_imports or 'fd_write' in exports_and_imports, 'some things are not minified anyhow'
# verify the wasm runs with the JS
if target.endswith('.js'):
self.assertContained('hello, world!', run_js('out.js'))
# verify the wasm runs in a wasm VM, without the JS
if LINUX: # TODO: other platforms
if standalone:
WASMER = os.path.expanduser(os.path.join('~', '.wasmer', 'bin', 'wasmer'))
if os.path.isfile(WASMER):
print(' running in wasmer')
out = run_process([WASMER, 'run', 'out.wasm'], stdout=PIPE).stdout
self.assertContained('hello, world!', out)
else:
print('[WARNING - no wasmer]')
WASMTIME = os.path.expanduser(os.path.join('~', 'wasmtime'))
if os.path.isfile(WASMTIME):
print(' running in wasmtime')
out = run_process([WASMTIME, 'out.wasm'], stdout=PIPE).stdout
self.assertContained('hello, world!', out)
else:
print('[WARNING - no wasmtime]')

def test_wasm_targets_side_module(self):
# side modules do allow a wasm target
Expand Down
33 changes: 25 additions & 8 deletions tools/shared.py
Original file line number Diff line number Diff line change
Expand Up @@ -500,7 +500,7 @@ def get_emscripten_version(path):
# NB: major version 0 implies no compatibility
# NB: when changing the metadata format, we should only append new fields, not
# reorder, modify, or remove existing ones.
(EMSCRIPTEN_METADATA_MAJOR, EMSCRIPTEN_METADATA_MINOR) = (0, 2)
(EMSCRIPTEN_METADATA_MAJOR, EMSCRIPTEN_METADATA_MINOR) = (0, 3)
# For the JS/WASM ABI, specifies the minimum ABI version required of
# the WASM runtime implementation by the generated WASM binary. It follows
# semver and changes whenever C types change size/signedness or
Expand All @@ -509,7 +509,7 @@ def get_emscripten_version(path):
# change, increment EMSCRIPTEN_ABI_MINOR if EMSCRIPTEN_ABI_MAJOR == 0
# or the ABI change is backwards compatible, otherwise increment
# EMSCRIPTEN_ABI_MAJOR and set EMSCRIPTEN_ABI_MINOR = 0.
(EMSCRIPTEN_ABI_MAJOR, EMSCRIPTEN_ABI_MINOR) = (0, 6)
(EMSCRIPTEN_ABI_MAJOR, EMSCRIPTEN_ABI_MINOR) = (0, 7)


def generate_sanity():
Expand Down Expand Up @@ -1819,11 +1819,16 @@ def link_lld(args, target, opts=[], lto_level=0):
'-o',
target,
'--allow-undefined',
'--import-memory',
'--import-table',
'--lto-O%d' % lto_level,
] + args

# wasi does not import the memory (but for JS it is efficient to do so,
# as it allows us to set up memory, preload files, etc. even before the
# wasm module arrives)
if not Settings.STANDALONE_WASM:
cmd.append('--import-memory')
cmd.append('--import-table')

if Settings.USE_PTHREADS:
cmd.append('--shared-memory')

Expand Down Expand Up @@ -2487,11 +2492,11 @@ def minify_wasm_js(js_file, wasm_file, expensive_optimizations, minify_whitespac
passes.append('minifyWhitespace')
logger.debug('running post-meta-DCE cleanup on shell code: ' + ' '.join(passes))
js_file = Building.acorn_optimizer(js_file, passes)
# also minify the names used between js and wasm, if we emitting JS (then the JS knows how to load the minified names)
# Also minify the names used between js and wasm, if we are emitting an optimized JS+wasm combo (then the JS knows how to load the minified names).
# If we are building with DECLARE_ASM_MODULE_EXPORTS=0, we must *not* minify the exports from the wasm module, since in DECLARE_ASM_MODULE_EXPORTS=0 mode, the code that
# reads out the exports is compacted by design that it does not have a chance to unminify the functions. If we are building with DECLARE_ASM_MODULE_EXPORTS=1, we might
# as well minify wasm exports to regain some of the code size loss that setting DECLARE_ASM_MODULE_EXPORTS=1 caused.
if Settings.EMITTING_JS and not Settings.AUTODEBUG and not Settings.ASSERTIONS:
if not Settings.STANDALONE_WASM and not Settings.AUTODEBUG and not Settings.ASSERTIONS and not Settings.SIDE_MODULE:
js_file = Building.minify_wasm_imports_and_exports(js_file, wasm_file, minify_whitespace=minify_whitespace, minify_exports=Settings.DECLARE_ASM_MODULE_EXPORTS, debug_info=debug_info)
return js_file

Expand Down Expand Up @@ -2526,8 +2531,19 @@ def metadce(js_file, wasm_file, minify_whitespace, debug_info):
export = '_' + export
if export in Building.user_requested_exports or Settings.EXPORT_ALL:
item['root'] = True
# in standalone wasm, always export the memory
if Settings.STANDALONE_WASM:
graph.append({
'export': 'memory',
'name': 'emcc$export$memory',
'reaches': [],
'root': True
})
# fix wasi imports TODO: support wasm stable with an option?
WASI_IMPORTS = set(['fd_write'])
WASI_IMPORTS = set([
'fd_write',
'proc_exit',
])
for item in graph:
if 'import' in item and item['import'][1][1:] in WASI_IMPORTS:
item['import'][0] = 'wasi_unstable'
Expand Down Expand Up @@ -3090,7 +3106,8 @@ def add_emscripten_metadata(js_file, wasm_file):
WebAssembly.lebify(global_base) +
WebAssembly.lebify(dynamic_base) +
WebAssembly.lebify(dynamictop_ptr) +
WebAssembly.lebify(tempdouble_ptr)
WebAssembly.lebify(tempdouble_ptr) +
WebAssembly.lebify(int(Settings.STANDALONE_WASM))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we should just not add this metadata for STANDALONE_WASM? Since the metadata was mostly to support for loading of emscripten-like wasm binaries outside of emscripten? Perhaps we can do that as a followup after consulting with the users of the metadata? Who are the users exactly I'm not sure.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can check with people if it's unnecessary, but we should either land this with the change (which is the safe thing) or block this until we decide whether to add this change or not. I lean towards the former since the latter may take a while.

In general I think this may still be useful for the same people for the same reasons as before - these wasms are as standalone as we can make them, but still may contain e.g. WebGL calls if using OpenGL, etc. So they are not pure wasi in general. Which means it's useful to have metadata about the emscripten ABI, and this flag does affect the ABI.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure we can land this now.. I was just suggesting this as a followup.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I remembered that we have promised to only append to the metadata list. So if we land this we probably don't want to remove the field later.

However, as I said earlier, I think we do want this field, so I'm not worried. Are you still concerned?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reading your posts, were you saying that we should not emit EMSCRIPTEN_METADATA at all for STANDALONE_WASM? (I initially understood you to mean this new field specifically.)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not talking about the field, but the entire metadata section. Its seems to be that the point of this section is so that runtimes and extract the information needs from the "emscripten-flavor" wasm file and run it without JS.

My idea is that for PURE_WASM we may not need the section at all in the future. In which case .. this field would be zeor by definition... or we could bump the major version which allows is the change it however we like.

My real long term hope is that the users of this metadata section are in fact that exact same users who want to use PURE_WASM instead and that PURE_WASM don't needs to self-describe in this way, and so we may be able to simply remove this completely?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see now, thanks.

Yeah, maybe we eventually won't need this metadata at all, if we only use standard APIs. That seems like the very far future though, as we'll need nonstandard APIs to do many things for quite some time, if not forever (e.g. WebGL).


# NB: more data can be appended here as long as you increase
# the EMSCRIPTEN_METADATA_MINOR
Expand Down
Loading