summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xscripts/test/lld.py30
-rw-r--r--src/ir/table-utils.h15
-rw-r--r--src/wasm.h2
-rw-r--r--src/wasm/wasm-emscripten.cpp79
-rw-r--r--test/lld/main_module_table.wat.out8
-rw-r--r--test/lld/main_module_table_2.wat.out8
-rw-r--r--test/lld/main_module_table_3.wat.out6
-rw-r--r--test/lld/shared.wat.out36
-rw-r--r--test/lld/shared_add_to_table.wasmbin0 -> 810 bytes
-rw-r--r--test/lld/shared_add_to_table.wasm.out144
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
new file mode 100644
index 000000000..00ea9f906
--- /dev/null
+++ b/test/lld/shared_add_to_table.wasm
Binary files differ
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 --
+;)