diff options
-rwxr-xr-x | scripts/test/lld.py | 30 | ||||
-rw-r--r-- | src/ir/table-utils.h | 15 | ||||
-rw-r--r-- | src/wasm.h | 2 | ||||
-rw-r--r-- | src/wasm/wasm-emscripten.cpp | 79 | ||||
-rw-r--r-- | test/lld/main_module_table.wat.out | 8 | ||||
-rw-r--r-- | test/lld/main_module_table_2.wat.out | 8 | ||||
-rw-r--r-- | test/lld/main_module_table_3.wat.out | 6 | ||||
-rw-r--r-- | test/lld/shared.wat.out | 36 | ||||
-rw-r--r-- | test/lld/shared_add_to_table.wasm | bin | 0 -> 810 bytes | |||
-rw-r--r-- | test/lld/shared_add_to_table.wasm.out | 144 |
10 files changed, 251 insertions, 77 deletions
diff --git a/scripts/test/lld.py b/scripts/test/lld.py index 6256ea003..cdbb2878d 100755 --- a/scripts/test/lld.py +++ b/scripts/test/lld.py @@ -32,10 +32,10 @@ def args_for_finalize(filename): def test_wasm_emscripten_finalize(): print('\n[ checking wasm-emscripten-finalize testcases... ]\n') - for wat_path in shared.get_tests(shared.get_test_dir('lld'), ['.wat']): - print('..', wat_path) - is_passive = '.passive.' in wat_path - mem_file = wat_path + '.mem' + for input_path in shared.get_tests(shared.get_test_dir('lld'), ['.wat', '.wasm']): + print('..', input_path) + is_passive = '.passive.' in input_path + mem_file = input_path + '.mem' extension_arg_map = { '.out': [], } @@ -44,13 +44,13 @@ def test_wasm_emscripten_finalize(): '.mem.out': ['--separate-data-segments', mem_file], }) for ext, ext_args in extension_arg_map.items(): - expected_file = wat_path + ext + expected_file = input_path + ext if ext != '.out' and not os.path.exists(expected_file): continue - cmd = shared.WASM_EMSCRIPTEN_FINALIZE + [wat_path, '-S'] + \ + cmd = shared.WASM_EMSCRIPTEN_FINALIZE + [input_path, '-S'] + \ ext_args - cmd += args_for_finalize(os.path.basename(wat_path)) + cmd += args_for_finalize(os.path.basename(input_path)) actual = support.run_command(cmd) if not os.path.exists(expected_file): @@ -61,7 +61,7 @@ def test_wasm_emscripten_finalize(): if ext == '.mem.out': with open(mem_file) as mf: mem = mf.read() - shared.fail_if_not_identical_to_file(mem, wat_path + + shared.fail_if_not_identical_to_file(mem, input_path + '.mem.mem') os.remove(mem_file) @@ -69,10 +69,10 @@ def test_wasm_emscripten_finalize(): def update_lld_tests(): print('\n[ updating wasm-emscripten-finalize testcases... ]\n') - for wat_path in shared.get_tests(shared.get_test_dir('lld'), ['.wat']): - print('..', wat_path) - is_passive = '.passive.' in wat_path - mem_file = wat_path + '.mem' + for input_path in shared.get_tests(shared.get_test_dir('lld'), ['.wat', '.wasm']): + print('..', input_path) + is_passive = '.passive.' in input_path + mem_file = input_path + '.mem' extension_arg_map = { '.out': [], } @@ -81,12 +81,12 @@ def update_lld_tests(): '.mem.out': ['--separate-data-segments', mem_file + '.mem'], }) for ext, ext_args in extension_arg_map.items(): - out_path = wat_path + ext + out_path = input_path + ext if ext != '.out' and not os.path.exists(out_path): continue - cmd = shared.WASM_EMSCRIPTEN_FINALIZE + [wat_path, '-S'] + \ + cmd = shared.WASM_EMSCRIPTEN_FINALIZE + [input_path, '-S'] + \ ext_args - cmd += args_for_finalize(os.path.basename(wat_path)) + cmd += args_for_finalize(os.path.basename(input_path)) actual = support.run_command(cmd) with open(out_path, 'w') as o: o.write(actual) diff --git a/src/ir/table-utils.h b/src/ir/table-utils.h index e0453dece..da0bb7241 100644 --- a/src/ir/table-utils.h +++ b/src/ir/table-utils.h @@ -50,16 +50,9 @@ struct FlatTable { } }; -// Ensure one table segment exists. This adds the table if necessary, then -// adds a segment if we need one. -inline Table::Segment& ensureTableWithOneSegment(Table& table, Module& wasm) { - table.exists = true; - if (table.segments.size() == 0) { - table.segments.resize(1); - table.segments[0].offset = LiteralUtils::makeZero(Type::i32, wasm); - } +inline Table::Segment& getSingletonSegment(Table& table, Module& wasm) { if (table.segments.size() != 1) { - Fatal() << "can't ensure 1 segment"; + Fatal() << "Table doesn't have a singleton segment."; } return table.segments[0]; } @@ -72,7 +65,7 @@ inline Table::Segment& ensureTableWithOneSegment(Table& table, Module& wasm) { // module has a single table segment, and that the dylink section indicates // we can validly append to that segment, see the check below. inline Index append(Table& table, Name name, Module& wasm) { - auto& segment = ensureTableWithOneSegment(table, wasm); + auto& segment = getSingletonSegment(table, wasm); auto tableIndex = segment.data.size(); if (wasm.dylinkSection) { if (segment.data.size() != wasm.dylinkSection->tableSize) { @@ -92,7 +85,7 @@ inline Index append(Table& table, Name name, Module& wasm) { // Checks if a function is already in the table. Returns that index if so, // otherwise appends it. inline Index getOrAppend(Table& table, Name name, Module& wasm) { - auto& segment = ensureTableWithOneSegment(table, wasm); + auto& segment = getSingletonSegment(table, wasm); for (Index i = 0; i < segment.data.size(); i++) { if (segment.data[i] == name) { return i; diff --git a/src/wasm.h b/src/wasm.h index 73f22e7d7..f0d8f13ba 100644 --- a/src/wasm.h +++ b/src/wasm.h @@ -1437,7 +1437,7 @@ class Global : public Importable { public: Name name; Type type; - Expression* init; + Expression* init = nullptr; bool mutable_ = false; }; diff --git a/src/wasm/wasm-emscripten.cpp b/src/wasm/wasm-emscripten.cpp index 5c411b454..0d71e8f00 100644 --- a/src/wasm/wasm-emscripten.cpp +++ b/src/wasm/wasm-emscripten.cpp @@ -22,7 +22,6 @@ #include "asmjs/shared-constants.h" #include "ir/import-utils.h" #include "ir/literal-utils.h" -#include "ir/manipulation.h" #include "ir/module-utils.h" #include "ir/table-utils.h" #include "shared-constants.h" @@ -217,6 +216,7 @@ void EmscriptenGlueGenerator::generateRuntimeFunctions() { static Function* ensureFunctionImport(Module* module, Name name, Signature sig) { // See if its already imported. + // FIXME: O(N) ImportInfo info(*module); if (auto* f = info.getImportedFunction(ENV, name)) { return f; @@ -231,6 +231,23 @@ ensureFunctionImport(Module* module, Name name, Signature sig) { return import; } +static Global* ensureGlobalImport(Module* module, Name name, Type type) { + // See if its already imported. + // FIXME: O(N) + ImportInfo info(*module); + if (auto* g = info.getImportedGlobal(ENV, name)) { + return g; + } + // Failing that create a new import. + auto import = new Global; + import->name = name; + import->module = ENV; + import->base = name; + import->type = type; + module->addGlobal(import); + return import; +} + // Convert LLVM PIC ABI to emscripten ABI // // When generating -fPIC code llvm will generate imports call GOT.mem and @@ -281,43 +298,47 @@ Function* EmscriptenGlueGenerator::generateAssignGOTEntriesFunction() { ImportInfo importInfo(wasm); + // We may have to add things to the table. + Global* tableBase = nullptr; + for (Global* g : gotFuncEntries) { - Function* f = nullptr; // The function has to exist either as export or an import. // Note that we don't search for the function by name since its internal // name may be different. auto* ex = wasm.getExportOrNull(g->base); if (ex) { assert(ex->kind == ExternalKind::Function); - f = wasm.getFunction(ex->value); - if (!sideModule) { - // This is exported, so must be one of the functions implemented here. - // Simply add it to the table, and use that index. The loader will - // know to reuse that index for other modules so they all share the - // same index and function pointer equality works. - // We may be able to do something for side modules as well, however, - // that would require at least updating the dylink section. - if (f->imported()) { - Fatal() << "GOT.func entry is both imported and exported: " - << g->base; - } - auto tableIndex = TableUtils::getOrAppend(wasm.table, f->name, wasm); - auto* c = LiteralUtils::makeFromInt32(tableIndex, Type::i32, wasm); - // The base relative to which we are computed is the offset of the - // singleton segment. - auto* getBase = - ExpressionManipulator::copy(wasm.table.segments[0].offset, wasm); - auto* add = builder.makeBinary(AddInt32, getBase, c); - auto* globalSet = builder.makeGlobalSet(g->name, add); - block->list.push_back(globalSet); - continue; + auto* f = wasm.getFunction(ex->value); + // This is exported, so must be one of the functions implemented here. + // Simply add it to the table, and use that index. The loader will + // know to reuse that index for other modules so they all share the + // same index and function pointer equality works. + if (f->imported()) { + Fatal() << "GOT.func entry is both imported and exported: " << g->base; } - // Otherwise, this is a side module, and fall through to join the case - // of an import. - } else { - // This is imported. Create an fp$ import to get the function table index. - f = importInfo.getImportedFunction(ENV, g->base); + // The base relative to which we are computed is the offset of the + // singleton segment, which we must ensure exists + if (!tableBase) { + tableBase = ensureGlobalImport(&wasm, TABLE_BASE, Type::i32); + } + if (!wasm.table.exists) { + wasm.table.exists = true; + } + if (wasm.table.segments.empty()) { + wasm.table.segments.resize(1); + wasm.table.segments[0].offset = + builder.makeGlobalGet(tableBase->name, Type::i32); + } + auto tableIndex = TableUtils::getOrAppend(wasm.table, f->name, wasm); + auto* c = LiteralUtils::makeFromInt32(tableIndex, Type::i32, wasm); + auto* getBase = builder.makeGlobalGet(tableBase->name, Type::i32); + auto* add = builder.makeBinary(AddInt32, getBase, c); + auto* globalSet = builder.makeGlobalSet(g->name, add); + block->list.push_back(globalSet); + continue; } + // This is imported. Create an fp$ import to get the function table index. + auto* f = importInfo.getImportedFunction(ENV, g->base); if (!f) { Fatal() << "GOT.func entry with no import/export: " << g->base; } diff --git a/test/lld/main_module_table.wat.out b/test/lld/main_module_table.wat.out index fd292809f..412d1715f 100644 --- a/test/lld/main_module_table.wat.out +++ b/test/lld/main_module_table.wat.out @@ -4,8 +4,9 @@ (type $i32_=>_i32 (func (param i32) (result i32))) (type $none_=>_i32 (func (result i32))) (import "env" "__stack_pointer" (global $sp_import i32)) + (import "env" "__table_base" (global $__table_base i32)) (table $0 1 funcref) - (elem (i32.const 0) $__stdio_write) + (elem (global.get $__table_base) $__stdio_write) (global $gimport$9 (mut i32) (i32.const 0)) (global $global i32 (i32.const 42)) (global $sp (mut i32) (global.get $sp_import)) @@ -51,7 +52,7 @@ (func $__assign_got_enties (; 5 ;) (global.set $gimport$9 (i32.add - (i32.const 0) + (global.get $__table_base) (i32.const 0) ) ) @@ -73,7 +74,8 @@ "declares": [ ], "externs": [ - "___stack_pointer" + "___stack_pointer", + "___table_base" ], "implementedFunctions": [ "___stdio_write", diff --git a/test/lld/main_module_table_2.wat.out b/test/lld/main_module_table_2.wat.out index 92a40d5f2..1dd833150 100644 --- a/test/lld/main_module_table_2.wat.out +++ b/test/lld/main_module_table_2.wat.out @@ -4,8 +4,9 @@ (type $i32_=>_i32 (func (param i32) (result i32))) (type $none_=>_i32 (func (result i32))) (import "env" "table" (table $0 2 funcref)) - (elem (i32.const 0) $__stdio_write) + (elem (global.get $__table_base) $__stdio_write) (import "env" "__stack_pointer" (global $sp_import i32)) + (import "env" "__table_base" (global $__table_base i32)) (global $gimport$9 (mut i32) (i32.const 0)) (global $global i32 (i32.const 42)) (global $sp (mut i32) (global.get $sp_import)) @@ -51,7 +52,7 @@ (func $__assign_got_enties (; 5 ;) (global.set $gimport$9 (i32.add - (i32.const 0) + (global.get $__table_base) (i32.const 0) ) ) @@ -73,7 +74,8 @@ "declares": [ ], "externs": [ - "___stack_pointer" + "___stack_pointer", + "___table_base" ], "implementedFunctions": [ "___stdio_write", diff --git a/test/lld/main_module_table_3.wat.out b/test/lld/main_module_table_3.wat.out index 92a40d5f2..f48ab6216 100644 --- a/test/lld/main_module_table_3.wat.out +++ b/test/lld/main_module_table_3.wat.out @@ -6,6 +6,7 @@ (import "env" "table" (table $0 2 funcref)) (elem (i32.const 0) $__stdio_write) (import "env" "__stack_pointer" (global $sp_import i32)) + (import "env" "__table_base" (global $__table_base i32)) (global $gimport$9 (mut i32) (i32.const 0)) (global $global i32 (i32.const 42)) (global $sp (mut i32) (global.get $sp_import)) @@ -51,7 +52,7 @@ (func $__assign_got_enties (; 5 ;) (global.set $gimport$9 (i32.add - (i32.const 0) + (global.get $__table_base) (i32.const 0) ) ) @@ -73,7 +74,8 @@ "declares": [ ], "externs": [ - "___stack_pointer" + "___stack_pointer", + "___table_base" ], "implementedFunctions": [ "___stdio_write", diff --git a/test/lld/shared.wat.out b/test/lld/shared.wat.out index 5cc1cf88f..64f97b984 100644 --- a/test/lld/shared.wat.out +++ b/test/lld/shared.wat.out @@ -4,13 +4,13 @@ (type $i32_=>_i32 (func (param i32) (result i32))) (import "env" "memory" (memory $0 0)) (data (global.get $gimport$2) "Hello, world\00\00\00\00\00\00\00\00\00\00\00\00") - (import "env" "table" (table $0 0 funcref)) + (import "env" "table" (table $0 1 funcref)) + (elem (global.get $gimport$3) $print_message\28\29) (import "env" "__memory_base" (global $gimport$2 i32)) (import "env" "__table_base" (global $gimport$3 i32)) (import "env" "puts" (func $puts (param i32) (result i32))) (import "env" "g$external_var" (func $g$external_var (result i32))) (import "env" "fp$puts$ii" (func $fp$puts$ii (result i32))) - (import "env" "fp$_Z13print_messagev$i" (func $fp$_Z13print_messagev$i (result i32))) (global $gimport$5 (mut i32) (i32.const 0)) (global $gimport$6 (mut i32) (i32.const 0)) (global $gimport$7 (mut i32) (i32.const 0)) @@ -20,10 +20,11 @@ (export "ptr_puts" (global $global$0)) (export "ptr_local_func" (global $global$1)) (export "__post_instantiate" (func $__post_instantiate)) - (func $__wasm_call_ctors (; 4 ;) + (export "dynCall_i" (func $dynCall_i)) + (func $__wasm_call_ctors (; 3 ;) (call $__wasm_apply_relocs) ) - (func $__wasm_apply_relocs (; 5 ;) + (func $__wasm_apply_relocs (; 4 ;) (i32.store (i32.add (global.get $gimport$2) @@ -39,7 +40,7 @@ (global.get $gimport$7) ) ) - (func $print_message\28\29 (; 6 ;) (result i32) + (func $print_message\28\29 (; 5 ;) (result i32) (drop (call $puts (i32.add @@ -52,11 +53,11 @@ (global.get $gimport$5) ) ) - (func $__post_instantiate (; 7 ;) + (func $__post_instantiate (; 6 ;) (call $__assign_got_enties) (call $__wasm_call_ctors) ) - (func $__assign_got_enties (; 8 ;) + (func $__assign_got_enties (; 7 ;) (global.set $gimport$5 (call $g$external_var) ) @@ -64,7 +65,15 @@ (call $fp$puts$ii) ) (global.set $gimport$7 - (call $fp$_Z13print_messagev$i) + (i32.add + (global.get $gimport$3) + (i32.const 0) + ) + ) + ) + (func $dynCall_i (; 8 ;) (param $fptr i32) (result i32) + (call_indirect (type $none_=>_i32) + (local.get $fptr) ) ) ) @@ -72,12 +81,11 @@ --BEGIN METADATA -- { "staticBump": 0, - "tableSize": 0, + "tableSize": 1, "declares": [ "puts", "g$external_var", - "fp$puts$ii", - "fp$_Z13print_messagev$i" + "fp$puts$ii" ], "externs": [ "___memory_base", @@ -85,11 +93,13 @@ ], "implementedFunctions": [ "__Z13print_messagev", - "___post_instantiate" + "___post_instantiate", + "_dynCall_i" ], "exports": [ "_Z13print_messagev", - "__post_instantiate" + "__post_instantiate", + "dynCall_i" ], "namedGlobals": { "ptr_puts" : "16", diff --git a/test/lld/shared_add_to_table.wasm b/test/lld/shared_add_to_table.wasm Binary files differnew file mode 100644 index 000000000..00ea9f906 --- /dev/null +++ b/test/lld/shared_add_to_table.wasm diff --git a/test/lld/shared_add_to_table.wasm.out b/test/lld/shared_add_to_table.wasm.out new file mode 100644 index 000000000..c561a89d3 --- /dev/null +++ b/test/lld/shared_add_to_table.wasm.out @@ -0,0 +1,144 @@ +(module + (type $none_=>_none (func)) + (type $none_=>_i32 (func (result i32))) + (type $i32_=>_i32 (func (param i32) (result i32))) + (type $i32_i32_=>_i32 (func (param i32 i32) (result i32))) + (import "env" "memory" (memory $0 0)) + (data (global.get $gimport$3) "*\00\00\00") + (import "env" "table" (table $timport$1 1 funcref)) + (elem (global.get $gimport$4) $waka_func_mine\28int\29) + (import "env" "__memory_base" (global $gimport$3 i32)) + (import "env" "__table_base" (global $gimport$4 i32)) + (import "env" "_Z16waka_func_theirsi" (func $waka_func_theirs\28int\29 (param i32) (result i32))) + (import "env" "g$waka_mine" (func $g$waka_mine (result i32))) + (import "env" "g$waka_others" (func $g$waka_others (result i32))) + (import "env" "fp$_Z16waka_func_theirsi$ii" (func $fp$_Z16waka_func_theirsi$ii (result i32))) + (global $gimport$6 (mut i32) (i32.const 0)) + (global $gimport$7 (mut i32) (i32.const 0)) + (global $gimport$8 (mut i32) (i32.const 0)) + (global $gimport$9 (mut i32) (i32.const 0)) + (global $global$0 i32 (i32.const 0)) + (global $global$1 i32 (i32.const 0)) + (export "__wasm_apply_relocs" (func $__wasm_apply_relocs)) + (export "_Z14waka_func_minei" (func $waka_func_mine\28int\29)) + (export "__original_main" (func $__original_main)) + (export "waka_mine" (global $global$0)) + (export "main" (func $main)) + (export "__dso_handle" (global $global$1)) + (export "__post_instantiate" (func $__post_instantiate)) + (export "dynCall_ii" (func $dynCall_ii)) + (func $__wasm_call_ctors (; 4 ;) + (call $__wasm_apply_relocs) + ) + (func $__wasm_apply_relocs (; 5 ;) + ) + (func $waka_func_mine\28int\29 (; 6 ;) (param $0 i32) (result i32) + (i32.add + (local.get $0) + (i32.const 1) + ) + ) + (func $__original_main (; 7 ;) (result i32) + (local $0 i32) + (local $1 i32) + (local.set $0 + (global.get $gimport$6) + ) + (local.set $1 + (global.get $gimport$7) + ) + (i32.add + (i32.add + (i32.load + (global.get $gimport$8) + ) + (i32.add + (local.get $1) + (local.get $0) + ) + ) + (i32.load + (global.get $gimport$9) + ) + ) + ) + (func $main (; 8 ;) (param $0 i32) (param $1 i32) (result i32) + (call $__original_main) + ) + (func $__post_instantiate (; 9 ;) + (call $__assign_got_enties) + (call $__wasm_call_ctors) + ) + (func $__assign_got_enties (; 10 ;) + (global.set $gimport$8 + (call $g$waka_mine) + ) + (global.set $gimport$9 + (call $g$waka_others) + ) + (global.set $gimport$6 + (call $fp$_Z16waka_func_theirsi$ii) + ) + (global.set $gimport$7 + (i32.add + (global.get $gimport$4) + (i32.const 0) + ) + ) + ) + (func $dynCall_ii (; 11 ;) (param $fptr i32) (param $0 i32) (result i32) + (call_indirect (type $i32_=>_i32) + (local.get $0) + (local.get $fptr) + ) + ) + ;; dylink section + ;; memorysize: 4 + ;; memoryalignment: 2 + ;; tablesize: 1 + ;; tablealignment: 0 + ;; custom section "producers", size 157 +) +(; +--BEGIN METADATA -- +{ + "staticBump": 0, + "tableSize": 1, + "declares": [ + "_Z16waka_func_theirsi", + "g$waka_mine", + "g$waka_others", + "fp$_Z16waka_func_theirsi$ii" + ], + "externs": [ + "___memory_base", + "___table_base" + ], + "implementedFunctions": [ + "___wasm_apply_relocs", + "__Z14waka_func_minei", + "___original_main", + "_main", + "___post_instantiate", + "_dynCall_ii" + ], + "exports": [ + "__wasm_apply_relocs", + "_Z14waka_func_minei", + "__original_main", + "main", + "__post_instantiate", + "dynCall_ii" + ], + "namedGlobals": { + "waka_mine" : "0", + "__dso_handle" : "0" + }, + "invokeFuncs": [ + ], + "features": [ + ], + "mainReadsParams": 0 +} +-- END METADATA -- +;) |