[WebAssembly] Use hardcoded list expected undefined symbols (#21)

Rather than generate wasm.syms from wasm.js (which includes
a huge superset of the number of symbols actaully expected
to be undefined at link time) simply hardcode that list as
a test file, which lld can read.
This commit is contained in:
Sam Clegg 2017-11-07 15:17:25 -08:00 committed by GitHub
parent 8116ebcd0c
commit c185c68dd0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 110 additions and 81 deletions

View File

@ -951,88 +951,83 @@ var ffi = (function() {
if (arguments.length < 1) if (arguments.length < 1)
throw new Error('Expected at least one wasm module to load.'); throw new Error('Expected at least one wasm module to load.');
if (arguments[0] == '--dump-ffi-symbols') { function load_wasm(file_path) {
for (var name in ffi["env"]) // TODO this should be split up in load, check dependencies, and then resolve
print(name) // dependencies. That would make it easier to do lazy loading. We could do
} else { // this by catching load exceptions + adding to ffi and trying again, but
function load_wasm(file_path) { // we're talking silly there: modules should just tell us what they want.
// TODO this should be split up in load, check dependencies, and then resolve const buf = (typeof readbuffer === 'function')
// dependencies. That would make it easier to do lazy loading. We could do ? new Uint8Array(readbuffer(file_path))
// this by catching load exceptions + adding to ffi and trying again, but : read(file_path, 'binary');
// we're talking silly there: modules should just tell us what they want. instance = new WebAssembly.Instance(new WebAssembly.Module(buf), ffi)
const buf = (typeof readbuffer === 'function') // For the application exports its memory, we use that rather than
? new Uint8Array(readbuffer(file_path)) // the one we created. In this way this code works with modules that
: read(file_path, 'binary'); // import or export their memory.
instance = new WebAssembly.Instance(new WebAssembly.Module(buf), ffi) if (instance.exports.memory) {
// For the application exports its memory, we use that rather than heap = instance.exports.memory.buffer;
// the one we created. In this way this code works with modules that heap_uint8 = new Uint8Array(heap);
// import or export their memory. heap_size_bytes = heap.byteLength;
if (instance.exports.memory) {
heap = instance.exports.memory.buffer;
heap_uint8 = new Uint8Array(heap);
heap_size_bytes = heap.byteLength;
}
return instance;
} }
return instance;
}
// Load modules in reverse, adding their exports to the ffi object. // Load modules in reverse, adding their exports to the ffi object.
// This is analogous to how the linker resolves symbols: the later modules // This is analogous to how the linker resolves symbols: the later modules
// export symbols used by the earlier modules, and allow shadowing. // export symbols used by the earlier modules, and allow shadowing.
// Note that all modules, as well as the main module, share a heap. // Note that all modules, as well as the main module, share a heap.
var modules = {}; var modules = {};
for (var i = arguments.length - 1; i > 0; --i) { for (var i = arguments.length - 1; i > 0; --i) {
var path = arguments[i]; var path = arguments[i];
modules[i] = load_wasm(path); modules[i] = load_wasm(path);
for (var f in modules[i].exports) { for (var f in modules[i].exports) {
// TODO wasm modules don't have hasOwnProperty. They probably should. // TODO wasm modules don't have hasOwnProperty. They probably should.
// The code should look like: // The code should look like:
// if (modules[i].hasOwnProperty(f) && // if (modules[i].hasOwnProperty(f) &&
// modules[i][f] instanceof Function) // modules[i][f] instanceof Function)
if (modules[i].exports[f] instanceof Function) if (modules[i].exports[f] instanceof Function)
ffi['env'][f] = modules[i].exports[f]; ffi['env'][f] = modules[i].exports[f];
} }
} }
// Load the main module once the ffi object has been fully populated. // Load the main module once the ffi object has been fully populated.
var main_module = arguments[0]; var main_module = arguments[0];
modules[0] = load_wasm(main_module); modules[0] = load_wasm(main_module);
// TODO check that `main` exists in modules[0].exports and error out if not. // TODO check that `main` exists in modules[0].exports and error out if not.
try { try {
var ret = modules[0].exports.main(); var ret = modules[0].exports.main();
stdio.__flush_stdout(); stdio.__flush_stdout();
print(main_module + '::main() returned ' + ret); print(main_module + '::main() returned ' + ret);
if (ret != stdlib.EXIT_SUCCESS) if (ret != stdlib.EXIT_SUCCESS)
throw new Error('main reported failure'); throw new Error('main reported failure');
} catch (e) { } catch (e) {
stdio.__flush_stdout(); stdio.__flush_stdout();
if (e instanceof TerminateWasmException) { if (e instanceof TerminateWasmException) {
print('Program terminated with: ' + e); print('Program terminated with: ' + e);
if (stdlib.__get_exit_code() != stdlib.EXIT_SUCCESS) { if (stdlib.__get_exit_code() != stdlib.EXIT_SUCCESS) {
throw stdlib.__get_exit_code(); throw stdlib.__get_exit_code();
} }
} else if (e instanceof NotYetImplementedException) { } else if (e instanceof NotYetImplementedException) {
print(e); print(e);
throw e; throw e;
} else { } else {
function is_runtime_trap(e) { function is_runtime_trap(e) {
if ('string' != typeof e) return false; if ('string' != typeof e) return false;
var traps = ['unreachable', var traps = ['unreachable',
'memory access out of bounds', 'memory access out of bounds',
'divide by zero', 'divide by zero',
'divide result unrepresentable', 'divide result unrepresentable',
'remainder by zero', 'remainder by zero',
'integer result unrepresentable', 'integer result unrepresentable',
'invalid function', 'invalid function',
'function signature mismatch']; 'function signature mismatch'];
for (var msg in traps) if (e == traps[msg]) return true; for (var msg in traps) if (e == traps[msg]) return true;
return false; return false;
} }
print(is_runtime_trap(e) ? print(is_runtime_trap(e) ?
('Runtime trap: ' + e) : ('Runtime trap: ' + e) :
('Unknown exception of type `' + typeof(e) + '`: ' + e)); ('Unknown exception of type `' + typeof(e) + '`: ' + e));
throw e; throw e;
}
} }
} }

34
arch/wasm32/wasm.syms Normal file
View File

@ -0,0 +1,34 @@
# Symbols we want wasm.js to define at runtime
_Exit
abort
puts
# Musl syscall interface, provided by wasm.js
__syscall
__syscall0
__syscall1
__syscall2
__syscall3
__syscall4
__syscall5
__syscall6
__syscall_cp
# Symbols not supported by clang but currently expected to work on the
# wasm waterfall
# TODO(sbc): remove these
__builtin_isinff
__builtin_isinfl
__builtin_clrsb
__builtin_clrsbl
__builtin_clrsbll
__builtin_apply
__builtin_apply_args
__builtin_malloc
# Part of musl we still don't compile for wasm
__lock
__unlock
__set_thread_area
setjmp
longjmp