summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xauto_update_tests.py1
-rwxr-xr-xscripts/test/lld.py55
-rwxr-xr-xscripts/test/s2wasm.py1
-rw-r--r--src/tools/s2wasm.cpp12
-rw-r--r--src/tools/wasm-emscripten-finalize.cpp10
-rw-r--r--src/tools/wasm-link-metadata.cpp12
-rw-r--r--src/wasm-emscripten.cpp134
-rw-r--r--src/wasm-emscripten.h11
-rw-r--r--test/dot_s/reserved_func_ptrs.jscall.wast281
-rw-r--r--test/dot_s/reserved_func_ptrs.s59
-rw-r--r--test/dot_s/reserved_func_ptrs.wast147
-rw-r--r--test/lld/reserved_func_ptr.cpp34
-rw-r--r--test/lld/reserved_func_ptr.jscall.json1
-rw-r--r--test/lld/reserved_func_ptr.json1
-rw-r--r--test/lld/reserved_func_ptr.obin0 -> 566 bytes
-rw-r--r--test/lld/reserved_func_ptr.wast111
-rw-r--r--test/lld/reserved_func_ptr.wast.jscall.out294
-rw-r--r--test/lld/reserved_func_ptr.wast.out155
18 files changed, 1289 insertions, 30 deletions
diff --git a/auto_update_tests.py b/auto_update_tests.py
index 050dab1d1..1ec8f23c5 100755
--- a/auto_update_tests.py
+++ b/auto_update_tests.py
@@ -53,6 +53,7 @@ extension_arg_map = {
'.wast': [],
'.clamp.wast': ['--trap-mode=clamp'],
'.js.wast': ['--trap-mode=js'],
+ '.jscall.wast': ['--emscripten-reserved-function-pointers=3'],
}
for dot_s_dir in ['dot_s', 'llvm_autogenerated']:
for s in sorted(os.listdir(os.path.join('test', dot_s_dir))):
diff --git a/scripts/test/lld.py b/scripts/test/lld.py
index 793031ca6..85159ba3a 100755
--- a/scripts/test/lld.py
+++ b/scripts/test/lld.py
@@ -25,36 +25,53 @@ from shared import (
def test_wasm_link_metadata():
print '\n[ checking wasm-link-metadata testcases... ]\n'
+ extension_arg_map = {
+ '.json': [],
+ '.jscall.json': ['--emscripten-reserved-function-pointers=3'],
+ }
+
for obj_path in files_with_pattern(options.binaryen_test, 'lld', '*.o'):
print '..', obj_path
- expected_file = obj_path.replace('.o', '.json')
+ for ext, ext_args in extension_arg_map.items():
+ expected_file = obj_path.replace('.o', ext)
+ if ext != '.json' and not os.path.exists(expected_file):
+ continue
- cmd = WASM_LINK_METADATA + [obj_path]
- actual = run_command(cmd)
+ cmd = WASM_LINK_METADATA + [obj_path] + ext_args
+ actual = run_command(cmd)
- if not os.path.exists(expected_file):
- print actual
- fail_with_error('output ' + expected_file + ' does not exist')
- expected = open(expected_file, 'rb').read()
- if actual != expected:
- fail(actual, expected)
+ if not os.path.exists(expected_file):
+ print actual
+ fail_with_error('output ' + expected_file + ' does not exist')
+ expected = open(expected_file, 'rb').read()
+ if actual != expected:
+ fail(actual, expected)
def test_wasm_emscripten_finalize():
print '\n[ checking wasm-emscripten-finalize testcases... ]\n'
+ extension_arg_map = {
+ '.out': [],
+ '.jscall.out': ['--emscripten-reserved-function-pointers=3'],
+ }
+
for wast_path in files_with_pattern(options.binaryen_test, 'lld', '*.wast'):
print '..', wast_path
- expected_file = wast_path + '.out'
- cmd = WASM_EMSCRIPTEN_FINALIZE + [wast_path, '-S']
- actual = run_command(cmd)
-
- if not os.path.exists(expected_file):
- print actual
- fail_with_error('output ' + expected_file + ' does not exist')
- expected = open(expected_file, 'rb').read()
- if actual != expected:
- fail(actual, expected)
+ for ext, ext_args in extension_arg_map.items():
+ expected_file = wast_path + ext
+ if ext != '.out' and not os.path.exists(expected_file):
+ continue
+
+ cmd = WASM_EMSCRIPTEN_FINALIZE + [wast_path, '-S'] + ext_args
+ actual = run_command(cmd)
+
+ if not os.path.exists(expected_file):
+ print actual
+ fail_with_error('output ' + expected_file + ' does not exist')
+ expected = open(expected_file, 'rb').read()
+ if actual != expected:
+ fail(actual, expected)
if __name__ == '__main__':
diff --git a/scripts/test/s2wasm.py b/scripts/test/s2wasm.py
index 405ed5fdf..a3345f87b 100755
--- a/scripts/test/s2wasm.py
+++ b/scripts/test/s2wasm.py
@@ -36,6 +36,7 @@ def test_s2wasm():
'.wast': [],
'.clamp.wast': ['--trap-mode=clamp'],
'.js.wast': ['--trap-mode=js'],
+ '.jscall.wast': ['--emscripten-reserved-function-pointers=3'],
}
for dot_s_dir in ['dot_s', 'llvm_autogenerated']:
dot_s_path = os.path.join(options.binaryen_test, dot_s_dir)
diff --git a/src/tools/s2wasm.cpp b/src/tools/s2wasm.cpp
index d4e7731c5..a2c4e4a38 100644
--- a/src/tools/s2wasm.cpp
+++ b/src/tools/s2wasm.cpp
@@ -41,6 +41,7 @@ int main(int argc, const char *argv[]) {
std::string startFunction;
std::vector<std::string> archiveLibraries;
TrapMode trapMode = TrapMode::Allow;
+ unsigned numReservedFunctionPointers = 0;
Options options("s2wasm", "Link .s file into .wast");
options.extra["validate"] = "wasm";
options
@@ -121,6 +122,14 @@ int main(int argc, const char *argv[]) {
}
o->extra["validate"] = argument;
})
+ .add("--emscripten-reserved-function-pointers", "",
+ "Number of reserved function pointers for emscripten addFunction "
+ "support",
+ Options::Arguments::One,
+ [&numReservedFunctionPointers](Options *o,
+ const std::string &argument) {
+ numReservedFunctionPointers = std::stoi(argument);
+ })
.add_positional("INFILE", Options::Arguments::One,
[](Options *o, const std::string& argument) {
o->extra["infile"] = argument;
@@ -189,7 +198,8 @@ int main(int argc, const char *argv[]) {
allowMemoryGrowth,
linker.getStackPointerAddress(),
linker.getStaticBump(),
- linker.getOutput().getInitializerFunctions());
+ linker.getOutput().getInitializerFunctions(),
+ numReservedFunctionPointers);
}
if (options.extra["validate"] != "none") {
diff --git a/src/tools/wasm-emscripten-finalize.cpp b/src/tools/wasm-emscripten-finalize.cpp
index 223fa3082..28f5a7c06 100644
--- a/src/tools/wasm-emscripten-finalize.cpp
+++ b/src/tools/wasm-emscripten-finalize.cpp
@@ -39,6 +39,7 @@ int main(int argc, const char *argv[]) {
std::string infile;
std::string outfile;
bool emitBinary = true;
+ unsigned numReservedFunctionPointers = 0;
std::vector<Name> forcedExports;
Options options("wasm-emscripten-finalize",
"Performs Emscripten-specific transforms on .wasm files");
@@ -54,6 +55,14 @@ int main(int argc, const char *argv[]) {
[&emitBinary](Options*, const std::string& ) {
emitBinary = false;
})
+ .add("--emscripten-reserved-function-pointers", "",
+ "Number of reserved function pointers for emscripten addFunction "
+ "support",
+ Options::Arguments::One,
+ [&numReservedFunctionPointers](Options *,
+ const std::string &argument) {
+ numReservedFunctionPointers = std::stoi(argument);
+ })
.add_positional("INFILE", Options::Arguments::One,
[&infile](Options *o, const std::string& argument) {
infile = argument;
@@ -80,6 +89,7 @@ int main(int argc, const char *argv[]) {
generator.generateRuntimeFunctions();
generator.generateMemoryGrowthFunction();
generator.generateDynCallThunks();
+ generator.generateJSCallThunks(numReservedFunctionPointers);
generator.fixEmAsmConsts();
if (options.debug) {
diff --git a/src/tools/wasm-link-metadata.cpp b/src/tools/wasm-link-metadata.cpp
index 96e06f95b..3af00fbbf 100644
--- a/src/tools/wasm-link-metadata.cpp
+++ b/src/tools/wasm-link-metadata.cpp
@@ -67,6 +67,7 @@ void parseLinkingSection(std::vector<char> const& data, uint32_t &dataSize) {
int main(int argc, const char *argv[]) {
std::string infile;
std::string outfile;
+ unsigned numReservedFunctionPointers = 0;
Options options("wasm-link-metadata",
"Reads wasm .o file and emits .json metadata");
options
@@ -76,6 +77,14 @@ int main(int argc, const char *argv[]) {
outfile = argument;
Colors::disable();
})
+ .add("--emscripten-reserved-function-pointers", "",
+ "Number of reserved function pointers for emscripten addFunction "
+ "support",
+ Options::Arguments::One,
+ [&numReservedFunctionPointers](Options *o,
+ const std::string &argument) {
+ numReservedFunctionPointers = std::stoi(argument);
+ })
.add_positional("INFILE", Options::Arguments::One,
[&infile](Options *o, const std::string& argument) {
infile = argument;
@@ -110,7 +119,8 @@ int main(int argc, const char *argv[]) {
initializerFunctions.push_back("__wasm_call_ctors");
EmscriptenGlueGenerator generator(wasm);
- std::string metadata = generator.generateEmscriptenMetadata(dataSize, initializerFunctions);
+ std::string metadata = generator.generateEmscriptenMetadata(
+ dataSize, initializerFunctions, numReservedFunctionPointers);
Output output(outfile, Flags::Text, Flags::Release);
output << metadata;
diff --git a/src/wasm-emscripten.cpp b/src/wasm-emscripten.cpp
index 60bf5cce3..821f3aa9d 100644
--- a/src/wasm-emscripten.cpp
+++ b/src/wasm-emscripten.cpp
@@ -196,6 +196,106 @@ void EmscriptenGlueGenerator::generateDynCallThunks() {
}
}
+struct JSCallWalker : public PostWalker<JSCallWalker> {
+ Module &wasm;
+ JSCallWalker(Module &_wasm) : wasm(_wasm) {
+ if (wasm.table.segments.size() == 0) {
+ auto emptySegment =
+ wasm.allocator.alloc<Const>()->set(Literal(uint32_t(0)));
+ wasm.table.segments.emplace_back(emptySegment);
+ }
+ const auto& tableSegmentData = wasm.table.segments[0].data;
+
+ // Check if jsCalls have already been created
+ for (Index i = 0; i < tableSegmentData.size(); ++i) {
+ if (tableSegmentData[i].startsWith("jsCall_")) {
+ jsCallStartIndex = i;
+ return;
+ }
+ }
+ jsCallStartIndex =
+ wasm.table.segments[0].offset->cast<Const>()->value.getInteger() +
+ tableSegmentData.size();
+ }
+
+ // Gather all function signatures used in call_indirect, because any of them
+ // can be used to call function pointers created by emscripten's addFunction.
+ void visitCallIndirect(CallIndirect *curr) {
+ // dynCall thunks are generated in binaryen and call_indirect instructions
+ // within them cannot be used to call function pointers returned by
+ // emscripten's addFunction.
+ if (!getFunction()->name.startsWith("dynCall_")) {
+ indirectlyCallableSigs.insert(
+ getSig(wasm.getFunctionType(curr->fullType)));
+ }
+ }
+
+ bool createJSCallThunks;
+ Index jsCallStartIndex;
+ // Function type signatures used in call_indirect instructions
+ std::set<std::string> indirectlyCallableSigs;
+};
+
+JSCallWalker getJSCallWalker(Module& wasm) {
+ JSCallWalker walker(wasm);
+ walker.walkModule(&wasm);
+ return walker;
+}
+
+void EmscriptenGlueGenerator::generateJSCallThunks(
+ unsigned numReservedFunctionPointers) {
+ if (numReservedFunctionPointers == 0)
+ return;
+
+ JSCallWalker walker = getJSCallWalker(wasm);
+ auto& tableSegmentData = wasm.table.segments[0].data;
+ for (std::string sig : walker.indirectlyCallableSigs) {
+ // Add imports for jsCall_sig (e.g. jsCall_vi).
+ // Imported jsCall_sig functions have their first parameter as an index to
+ // the function table, so we should prepend an 'i' to parameters' signature
+ // (e.g. If the signature of the callee is 'vi', the imported jsCall_vi
+ // function would have signature 'vii'.)
+ std::string importSig = std::string(1, sig[0]) + 'i' + sig.substr(1);
+ FunctionType *importType = ensureFunctionType(importSig, &wasm);
+ auto import = new Import;
+ import->name = import->base = "jsCall_" + sig;
+ import->module = ENV;
+ import->functionType = importType->name;
+ import->kind = ExternalKind::Function;
+ wasm.addImport(import);
+ FunctionType *funcType = ensureFunctionType(sig, &wasm);
+
+ // Create jsCall_sig_index thunks (e.g. jsCall_vi_0, jsCall_vi_1, ...)
+ // e.g. If # of reserved function pointers (given by a command line
+ // argument) is 3 and there are two possible signature 'vi' and 'ii', the
+ // genereated thunks will be jsCall_vi_0, jsCall_vi_1, jsCall_vi_2,
+ // jsCall_ii_0, jsCall_ii_1, and jsCall_ii_2.
+ for (unsigned fp = 0; fp < numReservedFunctionPointers; ++fp) {
+ std::vector<NameType> params;
+ int p = 0;
+ for (const auto& ty : funcType->params) {
+ params.emplace_back(std::to_string(p++), ty);
+ }
+ Function* f = builder.makeFunction(
+ std::string("jsCall_") + sig + "_" + std::to_string(fp),
+ std::move(params), funcType->result, {});
+ std::vector<Expression*> args;
+ args.push_back(builder.makeConst(Literal(fp)));
+ for (unsigned i = 0; i < funcType->params.size(); ++i) {
+ args.push_back(builder.makeGetLocal(i, funcType->params[i]));
+ }
+ Expression* call =
+ builder.makeCallImport(import->name, args, funcType->result);
+ f->body = call;
+ wasm.addFunction(f);
+ tableSegmentData.push_back(f->name);
+ }
+ }
+ wasm.table.initial = wasm.table.max =
+ wasm.table.segments[0].offset->cast<Const>()->value.getInteger() +
+ tableSegmentData.size();
+}
+
struct AsmConstWalker : public PostWalker<AsmConstWalker> {
Module& wasm;
std::vector<Address> segmentOffsets; // segment index => address offset
@@ -362,22 +462,22 @@ void printSet(std::ostream& o, C& c) {
}
std::string EmscriptenGlueGenerator::generateEmscriptenMetadata(
- Address staticBump,
- std::vector<Name> const& initializerFunctions) {
+ Address staticBump, std::vector<Name> const& initializerFunctions,
+ unsigned numReservedFunctionPointers) {
std::stringstream meta;
meta << "{ ";
- AsmConstWalker walker = fixEmAsmConstsAndReturnWalker(wasm);
+ AsmConstWalker emAsmWalker = fixEmAsmConstsAndReturnWalker(wasm);
// print
meta << "\"asmConsts\": {";
bool first = true;
- for (auto& pair : walker.sigsForCode) {
+ for (auto& pair : emAsmWalker.sigsForCode) {
auto& code = pair.first;
auto& sigs = pair.second;
if (first) first = false;
else meta << ",";
- meta << '"' << walker.ids[code] << "\": [\"" << code << "\", ";
+ meta << '"' << emAsmWalker.ids[code] << "\": [\"" << code << "\", ";
printSet(meta, sigs);
meta << "]";
}
@@ -394,6 +494,20 @@ std::string EmscriptenGlueGenerator::generateEmscriptenMetadata(
}
meta << "]";
+ if (numReservedFunctionPointers) {
+ JSCallWalker jsCallWalker = getJSCallWalker(wasm);
+ meta << ", ";
+ meta << "\"jsCallStartIndex\": " << jsCallWalker.jsCallStartIndex << ", ";
+ meta << "\"jsCallFuncType\": [";
+ bool first = true;
+ for (std::string sig : jsCallWalker.indirectlyCallableSigs) {
+ if (!first) meta << ", ";
+ first = false;
+ meta << "\"" << sig << "\"";
+ }
+ meta << "]";
+ }
+
meta << " }\n";
return meta.str();
@@ -404,7 +518,8 @@ std::string emscriptenGlue(
bool allowMemoryGrowth,
Address stackPointer,
Address staticBump,
- std::vector<Name> const& initializerFunctions) {
+ std::vector<Name> const& initializerFunctions,
+ unsigned numReservedFunctionPointers) {
EmscriptenGlueGenerator generator(wasm, stackPointer);
generator.generateRuntimeFunctions();
@@ -414,7 +529,12 @@ std::string emscriptenGlue(
generator.generateDynCallThunks();
- return generator.generateEmscriptenMetadata(staticBump, initializerFunctions);
+ if (numReservedFunctionPointers) {
+ generator.generateJSCallThunks(numReservedFunctionPointers);
+ }
+
+ return generator.generateEmscriptenMetadata(staticBump, initializerFunctions,
+ numReservedFunctionPointers);
}
} // namespace wasm
diff --git a/src/wasm-emscripten.h b/src/wasm-emscripten.h
index 1878e6531..d2a0a8e3e 100644
--- a/src/wasm-emscripten.h
+++ b/src/wasm-emscripten.h
@@ -39,8 +39,14 @@ public:
// signature in the indirect function table.
void generateDynCallThunks();
+ // Create thunks to support emscripten's addFunction functionality. Creates (#
+ // of reserved function pointers) thunks for each indirectly called function
+ // signature.
+ void generateJSCallThunks(unsigned numReservedFunctionPointers);
+
std::string generateEmscriptenMetadata(
- Address staticBump, std::vector<Name> const& initializerFunctions);
+ Address staticBump, std::vector<Name> const& initializerFunctions,
+ unsigned numReservedFunctionPointers);
// Replace placeholder emscripten_asm_const functions with *_signature versions.
void fixEmAsmConsts();
@@ -64,7 +70,8 @@ std::string emscriptenGlue(
bool allowMemoryGrowth,
Address stackPointer,
Address staticBump,
- std::vector<Name> const& initializerFunctions);
+ std::vector<Name> const& initializerFunctions,
+ unsigned numReservedFunctionPointers);
} // namespace wasm
diff --git a/test/dot_s/reserved_func_ptrs.jscall.wast b/test/dot_s/reserved_func_ptrs.jscall.wast
new file mode 100644
index 000000000..fd48f0a90
--- /dev/null
+++ b/test/dot_s/reserved_func_ptrs.jscall.wast
@@ -0,0 +1,281 @@
+(module
+ (type $FUNCSIG$v (func))
+ (type $FUNCSIG$vi (func (param i32)))
+ (type $FUNCSIG$iii (func (param i32 i32) (result i32)))
+ (type $FUNCSIG$fffi (func (param f32 f32 i32) (result f32)))
+ (type $FUNCSIG$ddi (func (param f64 i32) (result f64)))
+ (type $FUNCSIG$viii (func (param i32 i32 i32)))
+ (type $FUNCSIG$ii (func (param i32) (result i32)))
+ (type $FUNCSIG$didi (func (param i32 f64 i32) (result f64)))
+ (type $FUNCSIG$fiffi (func (param i32 f32 f32 i32) (result f32)))
+ (type $FUNCSIG$iiii (func (param i32 i32 i32) (result i32)))
+ (type $FUNCSIG$vii (func (param i32 i32)))
+ (type $FUNCSIG$viiii (func (param i32 i32 i32 i32)))
+ (import "env" "atoi" (func $atoi (param i32) (result i32)))
+ (import "env" "memory" (memory $0 1))
+ (import "env" "jsCall_ddi" (func $jsCall_ddi (param i32 f64 i32) (result f64)))
+ (import "env" "jsCall_fffi" (func $jsCall_fffi (param i32 f32 f32 i32) (result f32)))
+ (import "env" "jsCall_iii" (func $jsCall_iii (param i32 i32 i32) (result i32)))
+ (import "env" "jsCall_v" (func $jsCall_v (param i32)))
+ (import "env" "jsCall_vi" (func $jsCall_vi (param i32 i32)))
+ (import "env" "jsCall_viii" (func $jsCall_viii (param i32 i32 i32 i32)))
+ (table 21 21 anyfunc)
+ (elem (i32.const 0) $__wasm_nullptr $_Z18address_taken_funciii $_Z19address_taken_func2iii $jsCall_ddi_0 $jsCall_ddi_1 $jsCall_ddi_2 $jsCall_fffi_0 $jsCall_fffi_1 $jsCall_fffi_2 $jsCall_iii_0 $jsCall_iii_1 $jsCall_iii_2 $jsCall_v_0 $jsCall_v_1 $jsCall_v_2 $jsCall_vi_0 $jsCall_vi_1 $jsCall_vi_2 $jsCall_viii_0 $jsCall_viii_1 $jsCall_viii_2)
+ (export "main" (func $main))
+ (export "stackSave" (func $stackSave))
+ (export "stackAlloc" (func $stackAlloc))
+ (export "stackRestore" (func $stackRestore))
+ (export "dynCall_viii" (func $dynCall_viii))
+ (func $_Z18address_taken_funciii (; 7 ;) (type $FUNCSIG$viii) (param $0 i32) (param $1 i32) (param $2 i32)
+ )
+ (func $_Z19address_taken_func2iii (; 8 ;) (type $FUNCSIG$viii) (param $0 i32) (param $1 i32) (param $2 i32)
+ )
+ (func $main (; 9 ;) (param $0 i32) (param $1 i32) (result i32)
+ (local $2 i32)
+ (local $3 i32)
+ (local $4 i32)
+ (local $5 i32)
+ (set_local $2
+ (call $atoi
+ (i32.load offset=4
+ (get_local $1)
+ )
+ )
+ )
+ (set_local $3
+ (call $atoi
+ (i32.load offset=8
+ (get_local $1)
+ )
+ )
+ )
+ (set_local $4
+ (call $atoi
+ (i32.load offset=12
+ (get_local $1)
+ )
+ )
+ )
+ (set_local $5
+ (call $atoi
+ (i32.load offset=16
+ (get_local $1)
+ )
+ )
+ )
+ (set_local $1
+ (call $atoi
+ (i32.load offset=20
+ (get_local $1)
+ )
+ )
+ )
+ (call_indirect (type $FUNCSIG$v)
+ (get_local $2)
+ )
+ (call_indirect (type $FUNCSIG$vi)
+ (i32.const 3)
+ (get_local $3)
+ )
+ (drop
+ (call_indirect (type $FUNCSIG$iii)
+ (i32.const 4)
+ (i32.const 5)
+ (get_local $4)
+ )
+ )
+ (drop
+ (call_indirect (type $FUNCSIG$fffi)
+ (f32.const 3.0999999046325684)
+ (f32.const 4.199999809265137)
+ (i32.const 5)
+ (get_local $5)
+ )
+ )
+ (drop
+ (call_indirect (type $FUNCSIG$ddi)
+ (f64.const 4.2)
+ (i32.const 5)
+ (get_local $1)
+ )
+ )
+ (call_indirect (type $FUNCSIG$viii)
+ (i32.const 1)
+ (i32.const 2)
+ (i32.const 3)
+ (select
+ (i32.const 1)
+ (i32.const 2)
+ (i32.gt_s
+ (get_local $0)
+ (i32.const 3)
+ )
+ )
+ )
+ (i32.const 0)
+ )
+ (func $__wasm_nullptr (; 10 ;) (type $FUNCSIG$v)
+ (unreachable)
+ )
+ (func $stackSave (; 11 ;) (result i32)
+ (i32.load offset=4
+ (i32.const 0)
+ )
+ )
+ (func $stackAlloc (; 12 ;) (param $0 i32) (result i32)
+ (local $1 i32)
+ (i32.store offset=4
+ (i32.const 0)
+ (tee_local $1
+ (i32.and
+ (i32.sub
+ (i32.load offset=4
+ (i32.const 0)
+ )
+ (get_local $0)
+ )
+ (i32.const -16)
+ )
+ )
+ )
+ (get_local $1)
+ )
+ (func $stackRestore (; 13 ;) (param $0 i32)
+ (i32.store offset=4
+ (i32.const 0)
+ (get_local $0)
+ )
+ )
+ (func $dynCall_viii (; 14 ;) (param $fptr i32) (param $0 i32) (param $1 i32) (param $2 i32)
+ (call_indirect (type $FUNCSIG$viii)
+ (get_local $0)
+ (get_local $1)
+ (get_local $2)
+ (get_local $fptr)
+ )
+ )
+ (func $jsCall_ddi_0 (; 15 ;) (param $0 f64) (param $1 i32) (result f64)
+ (call $jsCall_ddi
+ (i32.const 0)
+ (get_local $0)
+ (get_local $1)
+ )
+ )
+ (func $jsCall_ddi_1 (; 16 ;) (param $0 f64) (param $1 i32) (result f64)
+ (call $jsCall_ddi
+ (i32.const 1)
+ (get_local $0)
+ (get_local $1)
+ )
+ )
+ (func $jsCall_ddi_2 (; 17 ;) (param $0 f64) (param $1 i32) (result f64)
+ (call $jsCall_ddi
+ (i32.const 2)
+ (get_local $0)
+ (get_local $1)
+ )
+ )
+ (func $jsCall_fffi_0 (; 18 ;) (param $0 f32) (param $1 f32) (param $2 i32) (result f32)
+ (call $jsCall_fffi
+ (i32.const 0)
+ (get_local $0)
+ (get_local $1)
+ (get_local $2)
+ )
+ )
+ (func $jsCall_fffi_1 (; 19 ;) (param $0 f32) (param $1 f32) (param $2 i32) (result f32)
+ (call $jsCall_fffi
+ (i32.const 1)
+ (get_local $0)
+ (get_local $1)
+ (get_local $2)
+ )
+ )
+ (func $jsCall_fffi_2 (; 20 ;) (param $0 f32) (param $1 f32) (param $2 i32) (result f32)
+ (call $jsCall_fffi
+ (i32.const 2)
+ (get_local $0)
+ (get_local $1)
+ (get_local $2)
+ )
+ )
+ (func $jsCall_iii_0 (; 21 ;) (param $0 i32) (param $1 i32) (result i32)
+ (call $jsCall_iii
+ (i32.const 0)
+ (get_local $0)
+ (get_local $1)
+ )
+ )
+ (func $jsCall_iii_1 (; 22 ;) (param $0 i32) (param $1 i32) (result i32)
+ (call $jsCall_iii
+ (i32.const 1)
+ (get_local $0)
+ (get_local $1)
+ )
+ )
+ (func $jsCall_iii_2 (; 23 ;) (param $0 i32) (param $1 i32) (result i32)
+ (call $jsCall_iii
+ (i32.const 2)
+ (get_local $0)
+ (get_local $1)
+ )
+ )
+ (func $jsCall_v_0 (; 24 ;)
+ (call $jsCall_v
+ (i32.const 0)
+ )
+ )
+ (func $jsCall_v_1 (; 25 ;)
+ (call $jsCall_v
+ (i32.const 1)
+ )
+ )
+ (func $jsCall_v_2 (; 26 ;)
+ (call $jsCall_v
+ (i32.const 2)
+ )
+ )
+ (func $jsCall_vi_0 (; 27 ;) (param $0 i32)
+ (call $jsCall_vi
+ (i32.const 0)
+ (get_local $0)
+ )
+ )
+ (func $jsCall_vi_1 (; 28 ;) (param $0 i32)
+ (call $jsCall_vi
+ (i32.const 1)
+ (get_local $0)
+ )
+ )
+ (func $jsCall_vi_2 (; 29 ;) (param $0 i32)
+ (call $jsCall_vi
+ (i32.const 2)
+ (get_local $0)
+ )
+ )
+ (func $jsCall_viii_0 (; 30 ;) (param $0 i32) (param $1 i32) (param $2 i32)
+ (call $jsCall_viii
+ (i32.const 0)
+ (get_local $0)
+ (get_local $1)
+ (get_local $2)
+ )
+ )
+ (func $jsCall_viii_1 (; 31 ;) (param $0 i32) (param $1 i32) (param $2 i32)
+ (call $jsCall_viii
+ (i32.const 1)
+ (get_local $0)
+ (get_local $1)
+ (get_local $2)
+ )
+ )
+ (func $jsCall_viii_2 (; 32 ;) (param $0 i32) (param $1 i32) (param $2 i32)
+ (call $jsCall_viii
+ (i32.const 2)
+ (get_local $0)
+ (get_local $1)
+ (get_local $2)
+ )
+ )
+)
+;; METADATA: { "asmConsts": {},"staticBump": 12, "initializers": [], "jsCallStartIndex": 3, "jsCallFuncType": ["ddi", "fffi", "iii", "v", "vi", "viii"] }
diff --git a/test/dot_s/reserved_func_ptrs.s b/test/dot_s/reserved_func_ptrs.s
new file mode 100644
index 000000000..2e838c795
--- /dev/null
+++ b/test/dot_s/reserved_func_ptrs.s
@@ -0,0 +1,59 @@
+ .text
+ .file "reserved_func_ptrs.cpp"
+ .type _Z18address_taken_funciii,@function
+_Z18address_taken_funciii:
+ .param i32, i32, i32
+ .endfunc
+.Lfunc_end0:
+ .size _Z18address_taken_funciii, .Lfunc_end0-_Z18address_taken_funciii
+
+ .type _Z19address_taken_func2iii,@function
+_Z19address_taken_func2iii:
+ .param i32, i32, i32
+ .endfunc
+.Lfunc_end1:
+ .size _Z19address_taken_func2iii, .Lfunc_end1-_Z19address_taken_func2iii
+
+ .hidden main
+ .globl main
+ .type main,@function
+main:
+ .param i32, i32
+ .result i32
+ .local i32, i32, i32, i32
+ i32.load $push0=, 4($1)
+ i32.call $2=, atoi@FUNCTION, $pop0
+ i32.load $push1=, 8($1)
+ i32.call $3=, atoi@FUNCTION, $pop1
+ i32.load $push2=, 12($1)
+ i32.call $4=, atoi@FUNCTION, $pop2
+ i32.load $push3=, 16($1)
+ i32.call $5=, atoi@FUNCTION, $pop3
+ i32.load $push4=, 20($1)
+ i32.call $1=, atoi@FUNCTION, $pop4
+ call_indirect $2
+ i32.const $push5=, 3
+ call_indirect $pop5, $3
+ i32.const $push7=, 4
+ i32.const $push6=, 5
+ i32.call_indirect $drop=, $pop7, $pop6, $4
+ f32.const $push9=, 0x1.8cccccp1
+ f32.const $push8=, 0x1.0cccccp2
+ i32.const $push21=, 5
+ f32.call_indirect $drop=, $pop9, $pop8, $pop21, $5
+ f64.const $push10=, 0x1.0cccccccccccdp2
+ i32.const $push20=, 5
+ f64.call_indirect $drop=, $pop10, $pop20, $1
+ i32.const $push16=, 1
+ i32.const $push15=, 2
+ i32.const $push19=, 3
+ i32.const $push13=, _Z18address_taken_funciii@FUNCTION
+ i32.const $push12=, _Z19address_taken_func2iii@FUNCTION
+ i32.const $push18=, 3
+ i32.gt_s $push11=, $0, $pop18
+ i32.select $push14=, $pop13, $pop12, $pop11
+ call_indirect $pop16, $pop15, $pop19, $pop14
+ i32.const $push17=, 0
+ .endfunc
+.Lfunc_end2:
+ .size main, .Lfunc_end2-main
diff --git a/test/dot_s/reserved_func_ptrs.wast b/test/dot_s/reserved_func_ptrs.wast
new file mode 100644
index 000000000..08cf95282
--- /dev/null
+++ b/test/dot_s/reserved_func_ptrs.wast
@@ -0,0 +1,147 @@
+(module
+ (type $FUNCSIG$v (func))
+ (type $FUNCSIG$vi (func (param i32)))
+ (type $FUNCSIG$iii (func (param i32 i32) (result i32)))
+ (type $FUNCSIG$fffi (func (param f32 f32 i32) (result f32)))
+ (type $FUNCSIG$ddi (func (param f64 i32) (result f64)))
+ (type $FUNCSIG$viii (func (param i32 i32 i32)))
+ (type $FUNCSIG$ii (func (param i32) (result i32)))
+ (import "env" "atoi" (func $atoi (param i32) (result i32)))
+ (import "env" "memory" (memory $0 1))
+ (table 3 3 anyfunc)
+ (elem (i32.const 0) $__wasm_nullptr $_Z18address_taken_funciii $_Z19address_taken_func2iii)
+ (export "main" (func $main))
+ (export "stackSave" (func $stackSave))
+ (export "stackAlloc" (func $stackAlloc))
+ (export "stackRestore" (func $stackRestore))
+ (export "dynCall_viii" (func $dynCall_viii))
+ (func $_Z18address_taken_funciii (; 1 ;) (type $FUNCSIG$viii) (param $0 i32) (param $1 i32) (param $2 i32)
+ )
+ (func $_Z19address_taken_func2iii (; 2 ;) (type $FUNCSIG$viii) (param $0 i32) (param $1 i32) (param $2 i32)
+ )
+ (func $main (; 3 ;) (param $0 i32) (param $1 i32) (result i32)
+ (local $2 i32)
+ (local $3 i32)
+ (local $4 i32)
+ (local $5 i32)
+ (set_local $2
+ (call $atoi
+ (i32.load offset=4
+ (get_local $1)
+ )
+ )
+ )
+ (set_local $3
+ (call $atoi
+ (i32.load offset=8
+ (get_local $1)
+ )
+ )
+ )
+ (set_local $4
+ (call $atoi
+ (i32.load offset=12
+ (get_local $1)
+ )
+ )
+ )
+ (set_local $5
+ (call $atoi
+ (i32.load offset=16
+ (get_local $1)
+ )
+ )
+ )
+ (set_local $1
+ (call $atoi
+ (i32.load offset=20
+ (get_local $1)
+ )
+ )
+ )
+ (call_indirect (type $FUNCSIG$v)
+ (get_local $2)
+ )
+ (call_indirect (type $FUNCSIG$vi)
+ (i32.const 3)
+ (get_local $3)
+ )
+ (drop
+ (call_indirect (type $FUNCSIG$iii)
+ (i32.const 4)
+ (i32.const 5)
+ (get_local $4)
+ )
+ )
+ (drop
+ (call_indirect (type $FUNCSIG$fffi)
+ (f32.const 3.0999999046325684)
+ (f32.const 4.199999809265137)
+ (i32.const 5)
+ (get_local $5)
+ )
+ )
+ (drop
+ (call_indirect (type $FUNCSIG$ddi)
+ (f64.const 4.2)
+ (i32.const 5)
+ (get_local $1)
+ )
+ )
+ (call_indirect (type $FUNCSIG$viii)
+ (i32.const 1)
+ (i32.const 2)
+ (i32.const 3)
+ (select
+ (i32.const 1)
+ (i32.const 2)
+ (i32.gt_s
+ (get_local $0)
+ (i32.const 3)
+ )
+ )
+ )
+ (i32.const 0)
+ )
+ (func $__wasm_nullptr (; 4 ;) (type $FUNCSIG$v)
+ (unreachable)
+ )
+ (func $stackSave (; 5 ;) (result i32)
+ (i32.load offset=4
+ (i32.const 0)
+ )
+ )
+ (func $stackAlloc (; 6 ;) (param $0 i32) (result i32)
+ (local $1 i32)
+ (i32.store offset=4
+ (i32.const 0)
+ (tee_local $1
+ (i32.and
+ (i32.sub
+ (i32.load offset=4
+ (i32.const 0)
+ )
+ (get_local $0)
+ )
+ (i32.const -16)
+ )
+ )
+ )
+ (get_local $1)
+ )
+ (func $stackRestore (; 7 ;) (param $0 i32)
+ (i32.store offset=4
+ (i32.const 0)
+ (get_local $0)
+ )
+ )
+ (func $dynCall_viii (; 8 ;) (param $fptr i32) (param $0 i32) (param $1 i32) (param $2 i32)
+ (call_indirect (type $FUNCSIG$viii)
+ (get_local $0)
+ (get_local $1)
+ (get_local $2)
+ (get_local $fptr)
+ )
+ )
+)
+;; METADATA: { "asmConsts": {},"staticBump": 12, "initializers": [] }
diff --git a/test/lld/reserved_func_ptr.cpp b/test/lld/reserved_func_ptr.cpp
new file mode 100644
index 000000000..f40613ea0
--- /dev/null
+++ b/test/lld/reserved_func_ptr.cpp
@@ -0,0 +1,34 @@
+int atoi(const char *nptr);
+
+void address_taken_func(int a, int b, int c) {}
+void address_taken_func2(int a, int b, int c) {}
+
+int main(int argc, char **argv) {
+ int fp_v = atoi(argv[1]);
+ int fp_vi = atoi(argv[2]);
+ int fp_iii = atoi(argv[3]);
+ int fp_fffi = atoi(argv[4]);
+ int fp_ddi = atoi(argv[5]);
+
+ void (*f_viiii)(int, int, int) = 0;
+ if (argc > 3)
+ f_viiii = address_taken_func;
+ else
+ f_viiii = address_taken_func2;
+
+ void (*f_v)() = reinterpret_cast<void (*)()>(fp_v);
+ void (*f_vi)(int) = reinterpret_cast<void (*)(int)>(fp_vi);
+ int (*f_iii)(int, int) = reinterpret_cast<int (*)(int, int)>(fp_iii);
+ float (*f_fffi)(float, float, int) =
+ reinterpret_cast<float (*)(float, float, int)>(fp_fffi);
+ double (*f_ddi)(double, int) =
+ reinterpret_cast<double (*)(double, int)>(fp_ddi);
+
+ f_v();
+ f_vi(3);
+ f_iii(4, 5);
+ f_fffi(3.1f, 4.2f, 5);
+ f_ddi(4.2, 5);
+ f_viiii(1, 2, 3);
+ return 0;
+}
diff --git a/test/lld/reserved_func_ptr.jscall.json b/test/lld/reserved_func_ptr.jscall.json
new file mode 100644
index 000000000..e463aafe7
--- /dev/null
+++ b/test/lld/reserved_func_ptr.jscall.json
@@ -0,0 +1 @@
+{ "asmConsts": {},"staticBump": 0, "initializers": ["__wasm_call_ctors"], "jsCallStartIndex": 3, "jsCallFuncType": ["ddi", "fffi", "iii", "v", "vi", "viii"] }
diff --git a/test/lld/reserved_func_ptr.json b/test/lld/reserved_func_ptr.json
new file mode 100644
index 000000000..82f73d077
--- /dev/null
+++ b/test/lld/reserved_func_ptr.json
@@ -0,0 +1 @@
+{ "asmConsts": {},"staticBump": 0, "initializers": ["__wasm_call_ctors"] }
diff --git a/test/lld/reserved_func_ptr.o b/test/lld/reserved_func_ptr.o
new file mode 100644
index 000000000..f352c5cfe
--- /dev/null
+++ b/test/lld/reserved_func_ptr.o
Binary files differ
diff --git a/test/lld/reserved_func_ptr.wast b/test/lld/reserved_func_ptr.wast
new file mode 100644
index 000000000..6a77ec71b
--- /dev/null
+++ b/test/lld/reserved_func_ptr.wast
@@ -0,0 +1,111 @@
+(module
+ (type $0 (func))
+ (type $1 (func (param i32)))
+ (type $2 (func (param i32 i32) (result i32)))
+ (type $3 (func (param f32 f32 i32) (result f32)))
+ (type $4 (func (param f64 i32) (result f64)))
+ (type $5 (func (param i32 i32 i32)))
+ (type $6 (func (param i32) (result i32)))
+ (import "env" "_Z4atoiPKc" (func $_Z4atoiPKc (param i32) (result i32)))
+ (global $global$0 (mut i32) (i32.const 66560))
+ (global $global$1 i32 (i32.const 66560))
+ (table 3 3 anyfunc)
+ (elem (i32.const 1) $_Z18address_taken_funciii $_Z19address_taken_func2iii)
+ (memory $0 2)
+ (export "memory" (memory $0))
+ (export "__wasm_call_ctors" (func $__wasm_call_ctors))
+ (export "main" (func $main))
+ (export "__heap_base" (global $global$1))
+ (func $_Z18address_taken_funciii (; 1 ;) (type $5) (param $var$0 i32) (param $var$1 i32) (param $var$2 i32)
+ )
+ (func $_Z19address_taken_func2iii (; 2 ;) (type $5) (param $var$0 i32) (param $var$1 i32) (param $var$2 i32)
+ )
+ (func $main (; 3 ;) (type $2) (param $var$0 i32) (param $var$1 i32) (result i32)
+ (local $var$2 i32)
+ (local $var$3 i32)
+ (local $var$4 i32)
+ (local $var$5 i32)
+ (set_local $var$2
+ (call $_Z4atoiPKc
+ (i32.load offset=4
+ (get_local $var$1)
+ )
+ )
+ )
+ (set_local $var$3
+ (call $_Z4atoiPKc
+ (i32.load offset=8
+ (get_local $var$1)
+ )
+ )
+ )
+ (set_local $var$4
+ (call $_Z4atoiPKc
+ (i32.load offset=12
+ (get_local $var$1)
+ )
+ )
+ )
+ (set_local $var$5
+ (call $_Z4atoiPKc
+ (i32.load offset=16
+ (get_local $var$1)
+ )
+ )
+ )
+ (set_local $var$1
+ (call $_Z4atoiPKc
+ (i32.load offset=20
+ (get_local $var$1)
+ )
+ )
+ )
+ (call_indirect (type $0)
+ (get_local $var$2)
+ )
+ (call_indirect (type $1)
+ (i32.const 3)
+ (get_local $var$3)
+ )
+ (drop
+ (call_indirect (type $2)
+ (i32.const 4)
+ (i32.const 5)
+ (get_local $var$4)
+ )
+ )
+ (drop
+ (call_indirect (type $3)
+ (f32.const 3.0999999046325684)
+ (f32.const 4.199999809265137)
+ (i32.const 5)
+ (get_local $var$5)
+ )
+ )
+ (drop
+ (call_indirect (type $4)
+ (f64.const 4.2)
+ (i32.const 5)
+ (get_local $var$1)
+ )
+ )
+ (call_indirect (type $5)
+ (i32.const 1)
+ (i32.const 2)
+ (i32.const 3)
+ (select
+ (i32.const 1)
+ (i32.const 2)
+ (i32.gt_s
+ (get_local $var$0)
+ (i32.const 3)
+ )
+ )
+ )
+ (i32.const 0)
+ )
+ (func $__wasm_call_ctors (; 4 ;) (type $0)
+ )
+ ;; custom section "linking", size 3
+)
+
diff --git a/test/lld/reserved_func_ptr.wast.jscall.out b/test/lld/reserved_func_ptr.wast.jscall.out
new file mode 100644
index 000000000..02166bf6c
--- /dev/null
+++ b/test/lld/reserved_func_ptr.wast.jscall.out
@@ -0,0 +1,294 @@
+(module
+ (type $0 (func))
+ (type $1 (func (param i32)))
+ (type $2 (func (param i32 i32) (result i32)))
+ (type $3 (func (param f32 f32 i32) (result f32)))
+ (type $4 (func (param f64 i32) (result f64)))
+ (type $5 (func (param i32 i32 i32)))
+ (type $6 (func (param i32) (result i32)))
+ (type $FUNCSIG$ii (func (param i32) (result i32)))
+ (type $FUNCSIG$viii (func (param i32 i32 i32)))
+ (type $FUNCSIG$didi (func (param i32 f64 i32) (result f64)))
+ (type $FUNCSIG$ddi (func (param f64 i32) (result f64)))
+ (type $FUNCSIG$fiffi (func (param i32 f32 f32 i32) (result f32)))
+ (type $FUNCSIG$fffi (func (param f32 f32 i32) (result f32)))
+ (type $FUNCSIG$iiii (func (param i32 i32 i32) (result i32)))
+ (type $FUNCSIG$iii (func (param i32 i32) (result i32)))
+ (type $FUNCSIG$vi (func (param i32)))
+ (type $FUNCSIG$v (func))
+ (type $FUNCSIG$vii (func (param i32 i32)))
+ (type $FUNCSIG$viiii (func (param i32 i32 i32 i32)))
+ (import "env" "_Z4atoiPKc" (func $_Z4atoiPKc (param i32) (result i32)))
+ (import "env" "jsCall_ddi" (func $jsCall_ddi (param i32 f64 i32) (result f64)))
+ (import "env" "jsCall_fffi" (func $jsCall_fffi (param i32 f32 f32 i32) (result f32)))
+ (import "env" "jsCall_iii" (func $jsCall_iii (param i32 i32 i32) (result i32)))
+ (import "env" "jsCall_v" (func $jsCall_v (param i32)))
+ (import "env" "jsCall_vi" (func $jsCall_vi (param i32 i32)))
+ (import "env" "jsCall_viii" (func $jsCall_viii (param i32 i32 i32 i32)))
+ (global $global$0 (mut i32) (i32.const 66560))
+ (global $global$1 i32 (i32.const 66560))
+ (table 21 21 anyfunc)
+ (elem (i32.const 1) $_Z18address_taken_funciii $_Z19address_taken_func2iii $jsCall_ddi_0 $jsCall_ddi_1 $jsCall_ddi_2 $jsCall_fffi_0 $jsCall_fffi_1 $jsCall_fffi_2 $jsCall_iii_0 $jsCall_iii_1 $jsCall_iii_2 $jsCall_v_0 $jsCall_v_1 $jsCall_v_2 $jsCall_vi_0 $jsCall_vi_1 $jsCall_vi_2 $jsCall_viii_0 $jsCall_viii_1 $jsCall_viii_2)
+ (memory $0 2)
+ (export "memory" (memory $0))
+ (export "__wasm_call_ctors" (func $__wasm_call_ctors))
+ (export "main" (func $main))
+ (export "__heap_base" (global $global$1))
+ (export "stackSave" (func $stackSave))
+ (export "stackAlloc" (func $stackAlloc))
+ (export "stackRestore" (func $stackRestore))
+ (export "__growWasmMemory" (func $__growWasmMemory))
+ (export "dynCall_viii" (func $dynCall_viii))
+ (func $_Z18address_taken_funciii (; 7 ;) (type $5) (param $var$0 i32) (param $var$1 i32) (param $var$2 i32)
+ (nop)
+ )
+ (func $_Z19address_taken_func2iii (; 8 ;) (type $5) (param $var$0 i32) (param $var$1 i32) (param $var$2 i32)
+ (nop)
+ )
+ (func $main (; 9 ;) (type $2) (param $var$0 i32) (param $var$1 i32) (result i32)
+ (local $var$2 i32)
+ (local $var$3 i32)
+ (local $var$4 i32)
+ (local $var$5 i32)
+ (set_local $var$2
+ (call $_Z4atoiPKc
+ (i32.load offset=4
+ (get_local $var$1)
+ )
+ )
+ )
+ (set_local $var$3
+ (call $_Z4atoiPKc
+ (i32.load offset=8
+ (get_local $var$1)
+ )
+ )
+ )
+ (set_local $var$4
+ (call $_Z4atoiPKc
+ (i32.load offset=12
+ (get_local $var$1)
+ )
+ )
+ )
+ (set_local $var$5
+ (call $_Z4atoiPKc
+ (i32.load offset=16
+ (get_local $var$1)
+ )
+ )
+ )
+ (set_local $var$1
+ (call $_Z4atoiPKc
+ (i32.load offset=20
+ (get_local $var$1)
+ )
+ )
+ )
+ (call_indirect (type $0)
+ (get_local $var$2)
+ )
+ (call_indirect (type $1)
+ (i32.const 3)
+ (get_local $var$3)
+ )
+ (drop
+ (call_indirect (type $2)
+ (i32.const 4)
+ (i32.const 5)
+ (get_local $var$4)
+ )
+ )
+ (drop
+ (call_indirect (type $3)
+ (f32.const 3.0999999046325684)
+ (f32.const 4.199999809265137)
+ (i32.const 5)
+ (get_local $var$5)
+ )
+ )
+ (drop
+ (call_indirect (type $4)
+ (f64.const 4.2)
+ (i32.const 5)
+ (get_local $var$1)
+ )
+ )
+ (call_indirect (type $5)
+ (i32.const 1)
+ (i32.const 2)
+ (i32.const 3)
+ (select
+ (i32.const 1)
+ (i32.const 2)
+ (i32.gt_s
+ (get_local $var$0)
+ (i32.const 3)
+ )
+ )
+ )
+ (i32.const 0)
+ )
+ (func $__wasm_call_ctors (; 10 ;) (type $0)
+ (nop)
+ )
+ (func $stackSave (; 11 ;) (result i32)
+ (get_global $global$0)
+ )
+ (func $stackAlloc (; 12 ;) (param $0 i32) (result i32)
+ (local $1 i32)
+ (set_global $global$0
+ (tee_local $1
+ (i32.and
+ (i32.sub
+ (get_global $global$0)
+ (get_local $0)
+ )
+ (i32.const -16)
+ )
+ )
+ )
+ (get_local $1)
+ )
+ (func $stackRestore (; 13 ;) (param $0 i32)
+ (set_global $global$0
+ (get_local $0)
+ )
+ )
+ (func $__growWasmMemory (; 14 ;) (param $newSize i32) (result i32)
+ (grow_memory
+ (get_local $newSize)
+ )
+ )
+ (func $dynCall_viii (; 15 ;) (param $fptr i32) (param $0 i32) (param $1 i32) (param $2 i32)
+ (call_indirect (type $FUNCSIG$viii)
+ (get_local $0)
+ (get_local $1)
+ (get_local $2)
+ (get_local $fptr)
+ )
+ )
+ (func $jsCall_ddi_0 (; 16 ;) (param $0 f64) (param $1 i32) (result f64)
+ (call $jsCall_ddi
+ (i32.const 0)
+ (get_local $0)
+ (get_local $1)
+ )
+ )
+ (func $jsCall_ddi_1 (; 17 ;) (param $0 f64) (param $1 i32) (result f64)
+ (call $jsCall_ddi
+ (i32.const 1)
+ (get_local $0)
+ (get_local $1)
+ )
+ )
+ (func $jsCall_ddi_2 (; 18 ;) (param $0 f64) (param $1 i32) (result f64)
+ (call $jsCall_ddi
+ (i32.const 2)
+ (get_local $0)
+ (get_local $1)
+ )
+ )
+ (func $jsCall_fffi_0 (; 19 ;) (param $0 f32) (param $1 f32) (param $2 i32) (result f32)
+ (call $jsCall_fffi
+ (i32.const 0)
+ (get_local $0)
+ (get_local $1)
+ (get_local $2)
+ )
+ )
+ (func $jsCall_fffi_1 (; 20 ;) (param $0 f32) (param $1 f32) (param $2 i32) (result f32)
+ (call $jsCall_fffi
+ (i32.const 1)
+ (get_local $0)
+ (get_local $1)
+ (get_local $2)
+ )
+ )
+ (func $jsCall_fffi_2 (; 21 ;) (param $0 f32) (param $1 f32) (param $2 i32) (result f32)
+ (call $jsCall_fffi
+ (i32.const 2)
+ (get_local $0)
+ (get_local $1)
+ (get_local $2)
+ )
+ )
+ (func $jsCall_iii_0 (; 22 ;) (param $0 i32) (param $1 i32) (result i32)
+ (call $jsCall_iii
+ (i32.const 0)
+ (get_local $0)
+ (get_local $1)
+ )
+ )
+ (func $jsCall_iii_1 (; 23 ;) (param $0 i32) (param $1 i32) (result i32)
+ (call $jsCall_iii
+ (i32.const 1)
+ (get_local $0)
+ (get_local $1)
+ )
+ )
+ (func $jsCall_iii_2 (; 24 ;) (param $0 i32) (param $1 i32) (result i32)
+ (call $jsCall_iii
+ (i32.const 2)
+ (get_local $0)
+ (get_local $1)
+ )
+ )
+ (func $jsCall_v_0 (; 25 ;)
+ (call $jsCall_v
+ (i32.const 0)
+ )
+ )
+ (func $jsCall_v_1 (; 26 ;)
+ (call $jsCall_v
+ (i32.const 1)
+ )
+ )
+ (func $jsCall_v_2 (; 27 ;)
+ (call $jsCall_v
+ (i32.const 2)
+ )
+ )
+ (func $jsCall_vi_0 (; 28 ;) (param $0 i32)
+ (call $jsCall_vi
+ (i32.const 0)
+ (get_local $0)
+ )
+ )
+ (func $jsCall_vi_1 (; 29 ;) (param $0 i32)
+ (call $jsCall_vi
+ (i32.const 1)
+ (get_local $0)
+ )
+ )
+ (func $jsCall_vi_2 (; 30 ;) (param $0 i32)
+ (call $jsCall_vi
+ (i32.const 2)
+ (get_local $0)
+ )
+ )
+ (func $jsCall_viii_0 (; 31 ;) (param $0 i32) (param $1 i32) (param $2 i32)
+ (call $jsCall_viii
+ (i32.const 0)
+ (get_local $0)
+ (get_local $1)
+ (get_local $2)
+ )
+ )
+ (func $jsCall_viii_1 (; 32 ;) (param $0 i32) (param $1 i32) (param $2 i32)
+ (call $jsCall_viii
+ (i32.const 1)
+ (get_local $0)
+ (get_local $1)
+ (get_local $2)
+ )
+ )
+ (func $jsCall_viii_2 (; 33 ;) (param $0 i32) (param $1 i32) (param $2 i32)
+ (call $jsCall_viii
+ (i32.const 2)
+ (get_local $0)
+ (get_local $1)
+ (get_local $2)
+ )
+ )
+)
diff --git a/test/lld/reserved_func_ptr.wast.out b/test/lld/reserved_func_ptr.wast.out
new file mode 100644
index 000000000..983269810
--- /dev/null
+++ b/test/lld/reserved_func_ptr.wast.out
@@ -0,0 +1,155 @@
+(module
+ (type $0 (func))
+ (type $1 (func (param i32)))
+ (type $2 (func (param i32 i32) (result i32)))
+ (type $3 (func (param f32 f32 i32) (result f32)))
+ (type $4 (func (param f64 i32) (result f64)))
+ (type $5 (func (param i32 i32 i32)))
+ (type $6 (func (param i32) (result i32)))
+ (type $FUNCSIG$ii (func (param i32) (result i32)))
+ (type $FUNCSIG$viii (func (param i32 i32 i32)))
+ (import "env" "_Z4atoiPKc" (func $_Z4atoiPKc (param i32) (result i32)))
+ (global $global$0 (mut i32) (i32.const 66560))
+ (global $global$1 i32 (i32.const 66560))
+ (table 3 3 anyfunc)
+ (elem (i32.const 1) $_Z18address_taken_funciii $_Z19address_taken_func2iii)
+ (memory $0 2)
+ (export "memory" (memory $0))
+ (export "__wasm_call_ctors" (func $__wasm_call_ctors))
+ (export "main" (func $main))
+ (export "__heap_base" (global $global$1))
+ (export "stackSave" (func $stackSave))
+ (export "stackAlloc" (func $stackAlloc))
+ (export "stackRestore" (func $stackRestore))
+ (export "__growWasmMemory" (func $__growWasmMemory))
+ (export "dynCall_viii" (func $dynCall_viii))
+ (func $_Z18address_taken_funciii (; 1 ;) (type $5) (param $var$0 i32) (param $var$1 i32) (param $var$2 i32)
+ (nop)
+ )
+ (func $_Z19address_taken_func2iii (; 2 ;) (type $5) (param $var$0 i32) (param $var$1 i32) (param $var$2 i32)
+ (nop)
+ )
+ (func $main (; 3 ;) (type $2) (param $var$0 i32) (param $var$1 i32) (result i32)
+ (local $var$2 i32)
+ (local $var$3 i32)
+ (local $var$4 i32)
+ (local $var$5 i32)
+ (set_local $var$2
+ (call $_Z4atoiPKc
+ (i32.load offset=4
+ (get_local $var$1)
+ )
+ )
+ )
+ (set_local $var$3
+ (call $_Z4atoiPKc
+ (i32.load offset=8
+ (get_local $var$1)
+ )
+ )
+ )
+ (set_local $var$4
+ (call $_Z4atoiPKc
+ (i32.load offset=12
+ (get_local $var$1)
+ )
+ )
+ )
+ (set_local $var$5
+ (call $_Z4atoiPKc
+ (i32.load offset=16
+ (get_local $var$1)
+ )
+ )
+ )
+ (set_local $var$1
+ (call $_Z4atoiPKc
+ (i32.load offset=20
+ (get_local $var$1)
+ )
+ )
+ )
+ (call_indirect (type $0)
+ (get_local $var$2)
+ )
+ (call_indirect (type $1)
+ (i32.const 3)
+ (get_local $var$3)
+ )
+ (drop
+ (call_indirect (type $2)
+ (i32.const 4)
+ (i32.const 5)
+ (get_local $var$4)
+ )
+ )
+ (drop
+ (call_indirect (type $3)
+ (f32.const 3.0999999046325684)
+ (f32.const 4.199999809265137)
+ (i32.const 5)
+ (get_local $var$5)
+ )
+ )
+ (drop
+ (call_indirect (type $4)
+ (f64.const 4.2)
+ (i32.const 5)
+ (get_local $var$1)
+ )
+ )
+ (call_indirect (type $5)
+ (i32.const 1)
+ (i32.const 2)
+ (i32.const 3)
+ (select
+ (i32.const 1)
+ (i32.const 2)
+ (i32.gt_s
+ (get_local $var$0)
+ (i32.const 3)
+ )
+ )
+ )
+ (i32.const 0)
+ )
+ (func $__wasm_call_ctors (; 4 ;) (type $0)
+ (nop)
+ )
+ (func $stackSave (; 5 ;) (result i32)
+ (get_global $global$0)
+ )
+ (func $stackAlloc (; 6 ;) (param $0 i32) (result i32)
+ (local $1 i32)
+ (set_global $global$0
+ (tee_local $1
+ (i32.and
+ (i32.sub
+ (get_global $global$0)
+ (get_local $0)
+ )
+ (i32.const -16)
+ )
+ )
+ )
+ (get_local $1)
+ )
+ (func $stackRestore (; 7 ;) (param $0 i32)
+ (set_global $global$0
+ (get_local $0)
+ )
+ )
+ (func $__growWasmMemory (; 8 ;) (param $newSize i32) (result i32)
+ (grow_memory
+ (get_local $newSize)
+ )
+ )
+ (func $dynCall_viii (; 9 ;) (param $fptr i32) (param $0 i32) (param $1 i32) (param $2 i32)
+ (call_indirect (type $FUNCSIG$viii)
+ (get_local $0)
+ (get_local $1)
+ (get_local $2)
+ (get_local $fptr)
+ )
+ )
+)