summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt10
-rwxr-xr-xauto_update_tests.py20
-rwxr-xr-xcheck.py22
-rw-r--r--src/shared-constants.h8
-rw-r--r--src/tools/wasm-merge.cpp639
-rw-r--r--src/wasm-validator.h4
-rw-r--r--src/wasm.h1
-rw-r--r--src/wasm/wasm.cpp2
-rw-r--r--test/merge/basics.wast38
-rw-r--r--test/merge/basics.wast.combined133
-rw-r--r--test/merge/basics.wast.combined.finalized133
-rw-r--r--test/merge/basics.wast.combined.finalized.opt86
-rw-r--r--test/merge/basics.wast.combined.finalized.opt.stdout3
-rw-r--r--test/merge/basics.wast.combined.finalized.stdout3
-rw-r--r--test/merge/basics.wast.combined.opt122
-rw-r--r--test/merge/basics.wast.combined.opt.stdout3
-rw-r--r--test/merge/basics.wast.combined.stdout3
-rw-r--r--test/merge/basics.wast.toMerge63
-rw-r--r--test/merge/dylib.wasmbin0 -> 364 bytes
-rw-r--r--test/merge/dylib.wasm.combined91
-rw-r--r--test/merge/dylib.wasm.combined.finalized91
-rw-r--r--test/merge/dylib.wasm.combined.finalized.opt81
-rw-r--r--test/merge/dylib.wasm.combined.finalized.opt.stdout3
-rw-r--r--test/merge/dylib.wasm.combined.finalized.stdout3
-rw-r--r--test/merge/dylib.wasm.combined.opt90
-rw-r--r--test/merge/dylib.wasm.combined.opt.stdout3
-rw-r--r--test/merge/dylib.wasm.combined.stdout3
-rw-r--r--test/merge/dylib.wasm.toMergebin0 -> 318 bytes
-rw-r--r--test/merge/fusing.wast18
-rw-r--r--test/merge/fusing.wast.combined44
-rw-r--r--test/merge/fusing.wast.combined.finalized44
-rw-r--r--test/merge/fusing.wast.combined.finalized.opt32
-rw-r--r--test/merge/fusing.wast.combined.finalized.opt.stdout3
-rw-r--r--test/merge/fusing.wast.combined.finalized.stdout3
-rw-r--r--test/merge/fusing.wast.combined.opt35
-rw-r--r--test/merge/fusing.wast.combined.opt.stdout3
-rw-r--r--test/merge/fusing.wast.combined.stdout3
-rw-r--r--test/merge/fusing.wast.toMerge20
-rw-r--r--test/merge/global-init.wast10
-rw-r--r--test/merge/global-init.wast.combined16
-rw-r--r--test/merge/global-init.wast.combined.finalized16
-rw-r--r--test/merge/global-init.wast.combined.finalized.opt5
-rw-r--r--test/merge/global-init.wast.combined.finalized.opt.stdout3
-rw-r--r--test/merge/global-init.wast.combined.finalized.stdout3
-rw-r--r--test/merge/global-init.wast.combined.opt8
-rw-r--r--test/merge/global-init.wast.combined.opt.stdout3
-rw-r--r--test/merge/global-init.wast.combined.stdout3
-rw-r--r--test/merge/global-init.wast.toMerge10
-rw-r--r--test/merge/main-lacks-segments.wast7
-rw-r--r--test/merge/main-lacks-segments.wast.combined25
-rw-r--r--test/merge/main-lacks-segments.wast.combined.finalized25
-rw-r--r--test/merge/main-lacks-segments.wast.combined.finalized.opt10
-rw-r--r--test/merge/main-lacks-segments.wast.combined.finalized.opt.stdout3
-rw-r--r--test/merge/main-lacks-segments.wast.combined.finalized.stdout3
-rw-r--r--test/merge/main-lacks-segments.wast.combined.opt19
-rw-r--r--test/merge/main-lacks-segments.wast.combined.opt.stdout3
-rw-r--r--test/merge/main-lacks-segments.wast.combined.stdout3
-rw-r--r--test/merge/main-lacks-segments.wast.toMerge13
-rw-r--r--test/merge/post-instantiate-a.wast9
-rw-r--r--test/merge/post-instantiate-a.wast.combined19
-rw-r--r--test/merge/post-instantiate-a.wast.combined.finalized19
-rw-r--r--test/merge/post-instantiate-a.wast.combined.finalized.opt10
-rw-r--r--test/merge/post-instantiate-a.wast.combined.finalized.opt.stdout3
-rw-r--r--test/merge/post-instantiate-a.wast.combined.finalized.stdout3
-rw-r--r--test/merge/post-instantiate-a.wast.combined.opt12
-rw-r--r--test/merge/post-instantiate-a.wast.combined.opt.stdout3
-rw-r--r--test/merge/post-instantiate-a.wast.combined.stdout3
-rw-r--r--test/merge/post-instantiate-a.wast.toMerge6
-rw-r--r--test/merge/post-instantiate-b.wast6
-rw-r--r--test/merge/post-instantiate-b.wast.combined19
-rw-r--r--test/merge/post-instantiate-b.wast.combined.finalized19
-rw-r--r--test/merge/post-instantiate-b.wast.combined.finalized.opt10
-rw-r--r--test/merge/post-instantiate-b.wast.combined.finalized.opt.stdout3
-rw-r--r--test/merge/post-instantiate-b.wast.combined.finalized.stdout3
-rw-r--r--test/merge/post-instantiate-b.wast.combined.opt12
-rw-r--r--test/merge/post-instantiate-b.wast.combined.opt.stdout3
-rw-r--r--test/merge/post-instantiate-b.wast.combined.stdout3
-rw-r--r--test/merge/post-instantiate-b.wast.toMerge9
-rw-r--r--test/merge/printf.wast13
-rw-r--r--test/merge/printf.wast.combined28
-rw-r--r--test/merge/printf.wast.combined.finalized28
-rw-r--r--test/merge/printf.wast.combined.finalized.opt12
-rw-r--r--test/merge/printf.wast.combined.finalized.opt.stdout3
-rw-r--r--test/merge/printf.wast.combined.finalized.stdout3
-rw-r--r--test/merge/printf.wast.combined.opt15
-rw-r--r--test/merge/printf.wast.combined.opt.stdout3
-rw-r--r--test/merge/printf.wast.combined.stdout3
-rw-r--r--test/merge/printf.wast.toMerge14
88 files changed, 2346 insertions, 1 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f7ba5c71d..6c75b5688 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -168,6 +168,16 @@ SET_PROPERTY(TARGET wasm-opt PROPERTY CXX_STANDARD 11)
SET_PROPERTY(TARGET wasm-opt PROPERTY CXX_STANDARD_REQUIRED ON)
INSTALL(TARGETS wasm-opt DESTINATION ${CMAKE_INSTALL_BINDIR})
+SET(wasm-merge_SOURCES
+ src/tools/wasm-merge.cpp
+)
+ADD_EXECUTABLE(wasm-merge
+ ${wasm-merge_SOURCES})
+TARGET_LINK_LIBRARIES(wasm-merge wasm asmjs emscripten-optimizer ${all_passes} ast support)
+SET_PROPERTY(TARGET wasm-merge PROPERTY CXX_STANDARD 11)
+SET_PROPERTY(TARGET wasm-merge PROPERTY CXX_STANDARD_REQUIRED ON)
+INSTALL(TARGETS wasm-merge DESTINATION bin)
+
SET(asm2wasm_SOURCES
src/tools/asm2wasm.cpp
src/wasm-emscripten.cpp
diff --git a/auto_update_tests.py b/auto_update_tests.py
index 9f569d14d..76cd02cbb 100755
--- a/auto_update_tests.py
+++ b/auto_update_tests.py
@@ -193,6 +193,26 @@ for t in os.listdir('test'):
open(t + '.fromBinary', 'w').write(actual)
+print '\n[ checking wasm-merge... ]\n'
+
+for t in os.listdir(os.path.join('test', 'merge')):
+ if t.endswith(('.wast', '.wasm')):
+ print '..', t
+ t = os.path.join('test', 'merge', t)
+ u = t + '.toMerge'
+ for finalize in [0, 1]:
+ for opt in [0, 1]:
+ cmd = [os.path.join('bin', 'wasm-merge'), t, u, '-o', 'a.wast', '-S', '--verbose']
+ if finalize: cmd += ['--finalize-memory-base=1024', '--finalize-table-base=8']
+ if opt: cmd += ['-O']
+ stdout = run_command(cmd)
+ actual = open('a.wast').read()
+ out = t + '.combined'
+ if finalize: out += '.finalized'
+ if opt: out += '.opt'
+ with open(out, 'w') as o: o.write(actual)
+ with open(out + '.stdout', 'w') as o: o.write(stdout)
+
print '\n[ checking binaryen.js testcases... ]\n'
for s in sorted(os.listdir(os.path.join('test', 'binaryen.js'))):
diff --git a/check.py b/check.py
index f9ef1145b..57eedc423 100755
--- a/check.py
+++ b/check.py
@@ -215,6 +215,28 @@ for t in tests:
if actual != expected:
fail(actual, expected)
+print '\n[ checking wasm-merge... ]\n'
+
+for t in os.listdir(os.path.join('test', 'merge')):
+ if t.endswith(('.wast', '.wasm')):
+ print '..', t
+ t = os.path.join('test', 'merge', t)
+ u = t + '.toMerge'
+ for finalize in [0, 1]:
+ for opt in [0, 1]:
+ cmd = [os.path.join('bin', 'wasm-merge'), t, u, '-o', 'a.wast', '-S', '--verbose']
+ if finalize: cmd += ['--finalize-memory-base=1024', '--finalize-table-base=8']
+ if opt: cmd += ['-O']
+ stdout = run_command(cmd)
+ actual = open('a.wast').read()
+ out = t + '.combined'
+ if finalize: out += '.finalized'
+ if opt: out += '.opt'
+ with open(out) as f:
+ fail_if_not_identical(f.read(), actual)
+ with open(out + '.stdout') as f:
+ fail_if_not_identical(f.read(), stdout)
+
print '\n[ checking wasm-shell spec testcases... ]\n'
if len(requested) == 0:
diff --git a/src/shared-constants.h b/src/shared-constants.h
index 923ccc7de..a3d8e4fda 100644
--- a/src/shared-constants.h
+++ b/src/shared-constants.h
@@ -14,9 +14,15 @@
* limitations under the License.
*/
+#ifndef wasm_shared_constants_h
+
+#include "wasm.h"
+
namespace wasm {
extern Name GROW_WASM_MEMORY,
+ MEMORY_BASE,
+ TABLE_BASE,
NEW_SIZE,
MODULE,
START,
@@ -54,3 +60,5 @@ extern Name GROW_WASM_MEMORY,
} // namespace wasm
+#endif // wasm_shared_constants_h
+
diff --git a/src/tools/wasm-merge.cpp b/src/tools/wasm-merge.cpp
new file mode 100644
index 000000000..766beac8f
--- /dev/null
+++ b/src/tools/wasm-merge.cpp
@@ -0,0 +1,639 @@
+/*
+ * Copyright 2017 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// A WebAssembly merger: loads multiple files, smashes them together,
+// and emits the result.
+//
+// This is *not* a real linker. It just does naive merging.
+//
+
+#include <memory>
+
+#include "parsing.h"
+#include "pass.h"
+#include "shared-constants.h"
+#include "asmjs/shared-constants.h"
+#include "asm_v_wasm.h"
+#include "support/command-line.h"
+#include "support/file.h"
+#include "wasm-io.h"
+#include "wasm-binary.h"
+#include "wasm-builder.h"
+#include "wasm-validator.h"
+
+using namespace wasm;
+
+// Calls note() on every import that has form "env".(base)
+static void findImportsByBase(Module& wasm, Name base, std::function<void (Name)> note) {
+ for (auto& curr : wasm.imports) {
+ if (curr->module == ENV) {
+ if (curr->base == base) {
+ note(curr->name);
+ }
+ }
+ }
+}
+
+// Ensure a memory or table is of at least a size
+template<typename T>
+static void ensureSize(T& what, Index size) {
+ // ensure the size is sufficient
+ while (what.initial * what.kPageSize < size) {
+ what.initial = what.initial + 1;
+ }
+ what.max = std::max(what.initial, what.max);
+}
+
+// A mergeable unit. This class contains basic logic to prepare for merging
+// of two modules.
+struct Mergeable {
+ Mergeable(Module& wasm) : wasm(wasm) {
+ // scan the module
+ findSizes();
+ findImports();
+ standardizeSegments();
+ }
+
+ // The module we are working on
+ Module& wasm;
+
+ // Total sizes of the memory and table data, including things
+ // link a bump from the dylink section
+ Index totalMemorySize, totalTableSize;
+
+ // The names of the imported globals for the memory and table bases
+ // (sets, as each may be imported more than once)
+ std::set<Name> memoryBaseGlobals, tableBaseGlobals;
+
+ // Imported functions and globals provided by the other mergeable
+ // are fused together. We track those here, then remove them
+ std::map<Name, Name> implementedFunctionImports;
+ std::map<Name, Name> implementedGlobalImports;
+
+ // setups
+
+ // find the memory and table sizes. if there are relocatable sections for them,
+ // that is the base size, and a dylink section may increase things further
+ void findSizes() {
+ totalMemorySize = 0;
+ totalTableSize = 0;
+ for (auto& segment : wasm.memory.segments) {
+ Expression* offset = segment.offset;
+ if (offset->is<GetGlobal>()) {
+ totalMemorySize = segment.data.size();
+ break;
+ }
+ }
+ for (auto& segment : wasm.table.segments) {
+ Expression* offset = segment.offset;
+ if (offset->is<GetGlobal>()) {
+ totalTableSize = segment.data.size();
+ break;
+ }
+ }
+ for (auto& section : wasm.userSections) {
+ if (section.name == "dylink") {
+ WasmBinaryBuilder builder(wasm, section.data, false);
+ totalMemorySize = std::max(totalMemorySize, builder.getU32LEB());
+ totalTableSize = std::max(totalTableSize, builder.getU32LEB());
+ break; // there can be only one
+ }
+ }
+ // align them
+ while (totalMemorySize % 16 != 0) totalMemorySize++;
+ while (totalTableSize % 2 != 0) totalTableSize++;
+ }
+
+ void findImports() {
+ findImportsByBase(wasm, MEMORY_BASE, [&](Name name) {
+ memoryBaseGlobals.insert(name);
+ });
+ if (memoryBaseGlobals.size() == 0) {
+ Fatal() << "no memory base was imported";
+ }
+ findImportsByBase(wasm, TABLE_BASE, [&](Name name) {
+ tableBaseGlobals.insert(name);
+ });
+ if (tableBaseGlobals.size() == 0) {
+ Fatal() << "no table base was imported";
+ }
+ }
+
+ void standardizeSegments() {
+ standardizeSegment<Memory, char, Memory::Segment>(wasm, wasm.memory, totalMemorySize, 0, *memoryBaseGlobals.begin());
+ // if there are no functions, and we need one, we need to add one as the zero
+ if (totalTableSize > 0 && wasm.functions.empty()) {
+ auto func = new Function;
+ func->name = Name("binaryen$merge-zero");
+ func->body = Builder(wasm).makeNop();
+ func->type = ensureFunctionType("v", &wasm)->name;
+ wasm.addFunction(func);
+ }
+ Name zero;
+ if (totalTableSize > 0) {
+ zero = wasm.functions.begin()->get()->name;
+ }
+ standardizeSegment<Table, Name, Table::Segment>(wasm, wasm.table, totalTableSize, zero, *tableBaseGlobals.begin());
+ }
+
+ // utilities
+
+ Name getNonColliding(Name initial, std::function<bool (Name)> checkIfCollides) {
+ if (!checkIfCollides(initial)) {
+ return initial;
+ }
+ int x = 0;
+ while (1) {
+ auto curr = Name(std::string(initial.str) + '$' + std::to_string(x));
+ if (!checkIfCollides(curr)) {
+ return curr;
+ }
+ x++;
+ }
+ }
+
+ // ensure a relocatable segment exists, of the proper size, including
+ // the dylink bump applied into it, standardized into the form of
+ // not using a dylink section and instead having enough zeros at
+ // the end. this makes linking much simpler.
+ template<typename T, typename U, typename Segment>
+ void standardizeSegment(Module& wasm, T& what, Index size, U zero, Name globalName) {
+ Segment* relocatable = nullptr;
+ for (auto& segment : what.segments) {
+ Expression* offset = segment.offset;
+ if (offset->is<GetGlobal>()) {
+ // this is the relocatable one.
+ relocatable = &segment;
+ break;
+ }
+ }
+ if (!relocatable) {
+ // none existing, add one
+ what.segments.resize(what.segments.size() + 1);
+ relocatable = &what.segments.back();
+ relocatable->offset = Builder(wasm).makeGetGlobal(globalName, i32);
+ }
+ // make sure it is the right size
+ while (relocatable->data.size() < size) {
+ relocatable->data.push_back(zero);
+ }
+ ensureSize(what, relocatable->data.size());
+ }
+
+ // copies a relocatable segment from the input to the output
+ template<typename T, typename V>
+ void copySegment(T& output, T& input, V updater) {
+ for (auto& inputSegment : input.segments) {
+ Expression* inputOffset = inputSegment.offset;
+ if (inputOffset->is<GetGlobal>()) {
+ // this is the relocatable one. find the output's relocatable
+ for (auto& segment : output.segments) {
+ Expression* offset = segment.offset;
+ if (offset->is<GetGlobal>()) {
+ // copy our data in
+ for (auto item : inputSegment.data) {
+ segment.data.push_back(updater(item));
+ }
+ ensureSize(output, segment.data.size());
+ return; // there can be only one
+ }
+ }
+ WASM_UNREACHABLE(); // we must find a relocatable one in the output, as we standardized
+ }
+ }
+ }
+};
+
+// A mergeable that is an output, that is, that we merge into. This adds
+// logic to update it for the new data, namely, when an import is provided
+// by the other merged unit, we resolve to access that value directly.
+struct OutputMergeable : public PostWalker<OutputMergeable, Visitor<OutputMergeable>>, public Mergeable {
+ OutputMergeable(Module& wasm) : Mergeable(wasm) {}
+
+ void visitCallImport(CallImport* curr) {
+ auto iter = implementedFunctionImports.find(curr->target);
+ if (iter != implementedFunctionImports.end()) {
+ // this import is now in the module - call it
+ replaceCurrent(Builder(*getModule()).makeCall(iter->second, curr->operands, curr->type));
+ }
+ }
+
+ void visitGetGlobal(GetGlobal* curr) {
+ auto iter = implementedGlobalImports.find(curr->name);
+ if (iter != implementedGlobalImports.end()) {
+ // this global is now in the module - get it
+ curr->name = iter->second;
+ assert(curr->name.is());
+ }
+ }
+
+ void visitModule(Module* curr) {
+ // remove imports that are being implemented
+ for (auto& pair : implementedFunctionImports) {
+ curr->removeImport(pair.first);
+ }
+ for (auto& pair : implementedGlobalImports) {
+ curr->removeImport(pair.first);
+ }
+ }
+};
+
+// A mergeable that is an input, that is, that we merge into another.
+// This adds logic to disambiguate its names from the other, and to
+// perform all other merging operations.
+struct InputMergeable : public ExpressionStackWalker<InputMergeable, Visitor<InputMergeable>>, public Mergeable {
+ InputMergeable(Module& wasm, OutputMergeable& outputMergeable) : Mergeable(wasm), outputMergeable(outputMergeable) {}
+
+ // The unit we are being merged into
+ OutputMergeable& outputMergeable;
+
+ // mappings (after disambiguating with the other mergeable), old name => new name
+ std::map<Name, Name> ftNames; // function types
+ std::map<Name, Name> eNames; // exports
+ std::map<Name, Name> fNames; // functions
+ std::map<Name, Name> gNames; // globals
+
+ void visitCall(Call* curr) {
+ curr->target = fNames[curr->target];
+ assert(curr->target.is());
+ }
+
+ void visitCallImport(CallImport* curr) {
+ auto iter = implementedFunctionImports.find(curr->target);
+ if (iter != implementedFunctionImports.end()) {
+ // this import is now in the module - call it
+ replaceCurrent(Builder(*getModule()).makeCall(iter->second, curr->operands, curr->type));
+ return;
+ }
+ curr->target = fNames[curr->target];
+ assert(curr->target.is());
+ }
+
+ void visitCallIndirect(CallIndirect* curr) {
+ curr->fullType = ftNames[curr->fullType];
+ assert(curr->fullType.is());
+ }
+
+ void visitGetGlobal(GetGlobal* curr) {
+ auto iter = implementedGlobalImports.find(curr->name);
+ if (iter != implementedGlobalImports.end()) {
+ // this import is now in the module - use it
+ curr->name = iter->second;
+ return;
+ }
+ curr->name = gNames[curr->name];
+ assert(curr->name.is());
+ // if this is the memory or table base, add the bump
+ if (memoryBaseGlobals.count(curr->name)) {
+ addBump(outputMergeable.totalMemorySize);
+ } else if (tableBaseGlobals.count(curr->name)) {
+ addBump(outputMergeable.totalTableSize);
+ }
+ }
+
+ void visitSetGlobal(SetGlobal* curr) {
+ curr->name = gNames[curr->name];
+ assert(curr->name.is());
+ }
+
+ void merge() {
+ // find function imports in us that are implemented in the output
+ // TODO make maps, avoid N^2
+ for (auto& imp : wasm.imports) {
+ // per wasm dynamic library rules, we expect to see exports on 'env'
+ if ((imp->kind == ExternalKind::Function || imp->kind == ExternalKind::Global) && imp->module == ENV) {
+ // seek an export on the other side that matches
+ for (auto& exp : outputMergeable.wasm.exports) {
+ if (exp->kind == imp->kind && exp->name == imp->base) {
+ // fits!
+ if (imp->kind == ExternalKind::Function) {
+ implementedFunctionImports[imp->name] = exp->value;
+ } else {
+ implementedGlobalImports[imp->name] = exp->value;
+ }
+ break;
+ }
+ }
+ }
+ }
+ // remove the unneeded ones
+ for (auto& pair : implementedFunctionImports) {
+ wasm.removeImport(pair.first);
+ }
+ for (auto& pair : implementedGlobalImports) {
+ wasm.removeImport(pair.first);
+ }
+
+ // find new names
+ for (auto& curr : wasm.functionTypes) {
+ curr->name = ftNames[curr->name] = getNonColliding(curr->name, [&](Name name) -> bool {
+ return outputMergeable.wasm.getFunctionTypeOrNull(name);
+ });
+ }
+ for (auto& curr : wasm.imports) {
+ if (curr->kind == ExternalKind::Function) {
+ curr->name = fNames[curr->name] = getNonColliding(curr->name, [&](Name name) -> bool {
+ return !!outputMergeable.wasm.getImportOrNull(name) || !!outputMergeable.wasm.getFunctionOrNull(name);
+ });
+ } else if (curr->kind == ExternalKind::Global) {
+ curr->name = gNames[curr->name] = getNonColliding(curr->name, [&](Name name) -> bool {
+ return !!outputMergeable.wasm.getImportOrNull(name) || !!outputMergeable.wasm.getGlobalOrNull(name);
+ });
+ }
+ }
+ for (auto& curr : wasm.functions) {
+ curr->name = fNames[curr->name] = getNonColliding(curr->name, [&](Name name) -> bool {
+ return outputMergeable.wasm.getFunctionOrNull(name);
+ });
+ }
+ for (auto& curr : wasm.globals) {
+ curr->name = gNames[curr->name] = getNonColliding(curr->name, [&](Name name) -> bool {
+ return outputMergeable.wasm.getGlobalOrNull(name);
+ });
+ }
+
+ // update global names in input
+ {
+ auto temp = memoryBaseGlobals;
+ memoryBaseGlobals.clear();
+ for (auto x : temp) {
+ memoryBaseGlobals.insert(gNames[x]);
+ }
+ }
+ {
+ auto temp = tableBaseGlobals;
+ tableBaseGlobals.clear();
+ for (auto x : temp) {
+ tableBaseGlobals.insert(gNames[x]);
+ }
+ }
+
+ // find function imports in output that are implemented in the input
+ for (auto& imp : outputMergeable.wasm.imports) {
+ if ((imp->kind == ExternalKind::Function || imp->kind == ExternalKind::Global) && imp->module == ENV) {
+ for (auto& exp : wasm.exports) {
+ if (exp->kind == imp->kind && exp->name == imp->base) {
+ if (imp->kind == ExternalKind::Function) {
+ outputMergeable.implementedFunctionImports[imp->name] = fNames[exp->value];
+ } else {
+ outputMergeable.implementedGlobalImports[imp->name] = gNames[exp->value];
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ // update the output before bringing anything in. avoid doing so when possible, as in the
+ // common case the output module is very large.
+ if (outputMergeable.implementedFunctionImports.size() + outputMergeable.implementedGlobalImports.size() > 0) {
+ outputMergeable.walkModule(&outputMergeable.wasm);
+ }
+
+ // memory&table: we place the new memory segments at a higher position. after the existing ones.
+ copySegment(outputMergeable.wasm.memory, wasm.memory, [](char x) -> char { return x; });
+ copySegment(outputMergeable.wasm.table, wasm.table, [&](Name x) -> Name { return fNames[x]; });
+
+ // update the new contents about to be merged in
+ walkModule(&wasm);
+
+ // handle the dylink post-instantiate. this is special, as if it exists in both, we must in fact call both
+ Name POST_INSTANTIATE("__post_instantiate");
+ if (fNames.find(POST_INSTANTIATE) != fNames.end() &&
+ outputMergeable.wasm.getExportOrNull(POST_INSTANTIATE)) {
+ // indeed, both exist. add a call to the second (wasm spec does not give an order requirement)
+ auto* func = outputMergeable.wasm.getFunction(outputMergeable.wasm.getExport(POST_INSTANTIATE)->value);
+ Builder builder(outputMergeable.wasm);
+ func->body = builder.makeSequence(
+ builder.makeCall(fNames[POST_INSTANTIATE], {}, none),
+ func->body
+ );
+ }
+
+ // copy in the data
+ for (auto& curr : wasm.functionTypes) {
+ outputMergeable.wasm.addFunctionType(curr.release());
+ }
+ for (auto& curr : wasm.imports) {
+ if (curr->kind == ExternalKind::Memory || curr->kind == ExternalKind::Table) {
+ continue; // wasm has just 1 of each, they must match
+ }
+ // update and add
+ if (curr->functionType.is()) {
+ curr->functionType = ftNames[curr->functionType];
+ assert(curr->functionType.is());
+ }
+ outputMergeable.wasm.addImport(curr.release());
+ }
+ for (auto& curr : wasm.exports) {
+ if (curr->kind == ExternalKind::Memory || curr->kind == ExternalKind::Table) {
+ continue; // wasm has just 1 of each, they must match
+ }
+ // if an export would collide, do not add the new one, ignore it
+ // TODO: warning/error mode?
+ if (!outputMergeable.wasm.getExportOrNull(curr->name)) {
+ if (curr->kind == ExternalKind::Function) {
+ curr->value = fNames[curr->value];
+ outputMergeable.wasm.addExport(curr.release());
+ } else if (curr->kind == ExternalKind::Global) {
+ curr->value = gNames[curr->value];
+ outputMergeable.wasm.addExport(curr.release());
+ } else {
+ WASM_UNREACHABLE();
+ }
+ }
+ }
+ for (auto& curr : wasm.functions) {
+ curr->type = ftNames[curr->type];
+ assert(curr->type.is());
+ outputMergeable.wasm.addFunction(curr.release());
+ }
+ for (auto& curr : wasm.globals) {
+ outputMergeable.wasm.addGlobal(curr.release());
+ }
+ }
+
+private:
+ // add an offset to a get_global. we look above, and if there is already an add,
+ // we can add into it, avoiding creating a new node
+ void addBump(Index bump) {
+ if (expressionStack.size() >= 2) {
+ auto* parent = expressionStack[expressionStack.size() - 2];
+ if (auto* binary = parent->dynCast<Binary>()) {
+ if (binary->op == AddInt32) {
+ if (auto* num = binary->right->dynCast<Const>()) {
+ num->value = num->value.add(Literal(bump));
+ return;
+ }
+ }
+ }
+ }
+ Builder builder(*getModule());
+ replaceCurrent(
+ builder.makeBinary(
+ AddInt32,
+ expressionStack.back(),
+ builder.makeConst(Literal(int32_t(bump)))
+ )
+ );
+ }
+};
+
+// Finalize the memory/table bases, assinging concrete values into them
+void finalizeBases(Module& wasm, Index memory, Index table) {
+ struct FinalizableMergeable : public Mergeable, public PostWalker<FinalizableMergeable, Visitor<FinalizableMergeable>> {
+ FinalizableMergeable(Module& wasm, Index memory, Index table) : Mergeable(wasm), memory(memory), table(table) {
+ walkModule(&wasm);
+ // ensure memory and table sizes suffice, after finalization we have absolute locations now
+ for (auto& segment : wasm.memory.segments) {
+ ensureSize(wasm.memory, memory + segment.data.size());
+ }
+ for (auto& segment : wasm.table.segments) {
+ ensureSize(wasm.table, table + segment.data.size());
+ }
+ }
+
+ Index memory, table;
+
+ void visitGetGlobal(GetGlobal* curr) {
+ if (memory != Index(-1) && memoryBaseGlobals.count(curr->name)) {
+ finalize(memory);
+ } else if (table != Index(-1) && tableBaseGlobals.count(curr->name)) {
+ finalize(table);
+ }
+ }
+
+ private:
+ void finalize(Index value) {
+ replaceCurrent(Builder(*getModule()).makeConst(Literal(int32_t(value))));
+ }
+ };
+ FinalizableMergeable mergeable(wasm, memory, table);
+}
+
+//
+// main
+//
+
+int main(int argc, const char* argv[]) {
+ std::vector<std::string> filenames;
+ bool emitBinary = true;
+ Index finalizeMemoryBase = Index(-1),
+ finalizeTableBase = Index(-1);
+ bool optimize = false;
+ bool verbose = false;
+
+ Options options("wasm-merge", "Merge wasm files");
+ options
+ .add("--output", "-o", "Output file",
+ Options::Arguments::One,
+ [](Options* o, const std::string& argument) {
+ o->extra["output"] = argument;
+ Colors::disable();
+ })
+ .add("--emit-text", "-S", "Emit text instead of binary for the output file",
+ Options::Arguments::Zero,
+ [&](Options *o, const std::string &argument) { emitBinary = false; })
+ .add("--finalize-memory-base", "-fmb", "Finalize the env.memoryBase import",
+ Options::Arguments::One,
+ [&](Options* o, const std::string& argument) {
+ finalizeMemoryBase = atoi(argument.c_str());
+ })
+ .add("--finalize-table-base", "-fmb", "Finalize the env.tableBase import",
+ Options::Arguments::One,
+ [&](Options* o, const std::string& argument) {
+ finalizeTableBase = atoi(argument.c_str());
+ })
+ .add("-O", "-O", "Perform merge-time/finalize-time optimizations",
+ Options::Arguments::Zero,
+ [&](Options* o, const std::string& argument) {
+ optimize = true;
+ })
+ .add("--verbose", "-v", "Verbose output",
+ Options::Arguments::Zero,
+ [&](Options* o, const std::string& argument) {
+ verbose = true;
+ })
+ .add_positional("INFILES", Options::Arguments::N,
+ [&](Options *o, const std::string &argument) {
+ filenames.push_back(argument);
+ });
+ options.parse(argc, argv);
+
+ Module output;
+ std::vector<std::unique_ptr<Module>> otherModules; // keep all inputs alive, to save copies
+ bool first = true;
+ for (auto& filename : filenames) {
+ ModuleReader reader;
+ if (first) {
+ // read the first right into output, don't waste time merging into an empty module
+ try {
+ reader.read(filename, output);
+ } catch (ParseException& p) {
+ p.dump(std::cerr);
+ Fatal() << "error in parsing input";
+ }
+ first = false;
+ } else {
+ std::unique_ptr<Module> input = wasm::make_unique<Module>();
+ try {
+ reader.read(filename, *input);
+ } catch (ParseException& p) {
+ p.dump(std::cerr);
+ Fatal() << "error in parsing input";
+ }
+ // perform the merge
+ OutputMergeable outputMergeable(output);
+ InputMergeable inputMergeable(*input, outputMergeable);
+ inputMergeable.merge();
+ // retain the linked in module as we may depend on parts of it
+ otherModules.push_back(std::unique_ptr<Module>(input.release()));
+ }
+ }
+
+ if (verbose) {
+ // memory and table are standardized and merged, so it's easy to dump out some stats
+ std::cout << "merged total memory size: " << output.memory.segments[0].data.size() << '\n';
+ std::cout << "merged total table size: " << output.table.segments[0].data.size() << '\n';
+ std::cout << "merged functions: " << output.functions.size() << '\n';
+ }
+
+ if (finalizeMemoryBase != Index(-1) || finalizeTableBase != Index(-1)) {
+ finalizeBases(output, finalizeMemoryBase, finalizeTableBase);
+ }
+
+ if (optimize) {
+ // merge-time/finalize-time optimization
+ // it is beneficial to do global optimizations, as well as precomputing to get rid of finalized constants
+ PassRunner passRunner(&output);
+ passRunner.add("precompute");
+ passRunner.add("optimize-instructions"); // things now-constant may be further optimized
+ passRunner.addDefaultGlobalOptimizationPasses();
+ passRunner.run();
+ }
+
+ if (!WasmValidator().validate(output)) {
+ Fatal() << "error in validating output";
+ }
+
+ if (options.extra.count("output") > 0) {
+ ModuleWriter writer;
+ writer.setDebug(options.debug);
+ writer.setBinary(emitBinary);
+ writer.write(output, options.extra["output"]);
+ }
+}
diff --git a/src/wasm-validator.h b/src/wasm-validator.h
index 4d198ac34..4631a63b8 100644
--- a/src/wasm-validator.h
+++ b/src/wasm-validator.h
@@ -426,7 +426,9 @@ public:
if (!validateGlobally) return;
shouldBeTrue(curr->init != nullptr, curr->name, "global init must be non-null");
shouldBeTrue(curr->init->is<Const>() || curr->init->is<GetGlobal>(), curr->name, "global init must be valid");
- shouldBeEqual(curr->type, curr->init->type, nullptr, "global init must have correct type");
+ if (!shouldBeEqual(curr->type, curr->init->type, curr->init, "global init must have correct type")) {
+ std::cerr << "(on global " << curr->name << '\n';
+ }
}
void visitFunction(Function *curr) {
diff --git a/src/wasm.h b/src/wasm.h
index b27fe6acb..4804322b6 100644
--- a/src/wasm.h
+++ b/src/wasm.h
@@ -561,6 +561,7 @@ public:
class Table {
public:
+ static const Address::address_t kPageSize = 1;
static const Index kMaxSize = Index(-1);
struct Segment {
diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp
index 7e75d9178..a983fc943 100644
--- a/src/wasm/wasm.cpp
+++ b/src/wasm/wasm.cpp
@@ -32,6 +32,8 @@ const char* Name = "name";
}
Name GROW_WASM_MEMORY("__growWasmMemory"),
+ MEMORY_BASE("memoryBase"),
+ TABLE_BASE("tableBase"),
NEW_SIZE("newSize"),
MODULE("module"),
START("start"),
diff --git a/test/merge/basics.wast b/test/merge/basics.wast
new file mode 100644
index 000000000..7a234584b
--- /dev/null
+++ b/test/merge/basics.wast
@@ -0,0 +1,38 @@
+(module
+ (type $ii (func (param i32 i32)))
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table 0 anyfunc))
+ (import "env" "some-func" (func $some-func))
+ (import "env" "some-collide" (func $some-collide))
+ (data (get_global $memoryBase) "hello, A!\n")
+ (global $global-collide i32 (i32.const 0))
+ (global $global-collide-mut (mut i32) (i32.const 0))
+ (global $global-a i32 (i32.const 1))
+ (elem (get_global $tableBase) $only-a $willCollide $some-func $some-collide $only-a)
+ (export "exp-a" (func $only-a))
+ (export "exp-collide" (func $only-a))
+ (export "exp-collide2" (func $willCollide))
+ (func $only-a
+ (drop (i32.const 100))
+ (call $only-a)
+ (call_import $some-func)
+ (call_import $some-collide)
+ (call_indirect $ii
+ (i32.const 123)
+ (i32.const 456)
+ (i32.const 789)
+ )
+ (drop (get_global $global-collide))
+ (drop (get_global $global-a))
+ (drop (get_global $memoryBase))
+ (drop (get_global $tableBase))
+ (set_global $global-collide-mut (i32.const 1234))
+ )
+ (func $willCollide
+ (drop (i32.const 200))
+ (call $willCollide)
+ )
+)
+
diff --git a/test/merge/basics.wast.combined b/test/merge/basics.wast.combined
new file mode 100644
index 000000000..f0654ec7a
--- /dev/null
+++ b/test/merge/basics.wast.combined
@@ -0,0 +1,133 @@
+(module
+ (type $ii (func (param i32 i32)))
+ (type $FUNCSIG$v (func))
+ (type $ii$0 (func (param i32 i32)))
+ (type $FUNCSIG$v$0 (func))
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table 10 anyfunc))
+ (import "env" "some-func" (func $some-func))
+ (import "env" "some-collide" (func $some-collide))
+ (import "env" "memoryBase" (global $memoryBase$0 i32))
+ (import "env" "tableBase" (global $tableBase$0 i32))
+ (import "env" "some-func-b" (func $some-func-b))
+ (import "env" "some-collide" (func $some-collide$0))
+ (global $global-collide i32 (i32.const 0))
+ (global $global-collide-mut (mut i32) (i32.const 0))
+ (global $global-a i32 (i32.const 1))
+ (global $global-collide$0 i32 (i32.const 0))
+ (global $global-collide-mut$0 (mut i32) (i32.const 0))
+ (global $global-b i32 (i32.const 1))
+ (elem (get_global $tableBase) $only-a $willCollide $some-func $some-collide $only-a $only-a $only-b $willCollide$0 $some-func-b $some-collide$0)
+ (data (get_global $memoryBase) "hello, A!\n\00\00\00\00\00\00hello, B!\n\00\00\00\00\00\00")
+ (export "exp-a" (func $only-a))
+ (export "exp-collide" (func $only-a))
+ (export "exp-collide2" (func $willCollide))
+ (export "exp-b" (func $only-b))
+ (export "exp-b-nameCollided" (func $willCollide$0))
+ (func $only-a (type $FUNCSIG$v)
+ (drop
+ (i32.const 100)
+ )
+ (call $only-a)
+ (call $some-func)
+ (call $some-collide)
+ (call_indirect $ii
+ (i32.const 123)
+ (i32.const 456)
+ (i32.const 789)
+ )
+ (drop
+ (get_global $global-collide)
+ )
+ (drop
+ (get_global $global-a)
+ )
+ (drop
+ (get_global $memoryBase)
+ )
+ (drop
+ (get_global $tableBase)
+ )
+ (set_global $global-collide-mut
+ (i32.const 1234)
+ )
+ )
+ (func $willCollide (type $FUNCSIG$v)
+ (drop
+ (i32.const 200)
+ )
+ (call $willCollide)
+ )
+ (func $only-b (type $FUNCSIG$v$0)
+ (drop
+ (i32.const 111)
+ )
+ (call $only-b)
+ (call $some-func-b)
+ (call $some-collide$0)
+ (call_indirect $ii$0
+ (i32.const 12)
+ (i32.const 34)
+ (i32.const 56)
+ )
+ (drop
+ (get_global $global-collide$0)
+ )
+ (drop
+ (get_global $global-b)
+ )
+ (drop
+ (i32.add
+ (get_global $memoryBase$0)
+ (i32.const 16)
+ )
+ )
+ (drop
+ (i32.add
+ (get_global $tableBase$0)
+ (i32.const 6)
+ )
+ )
+ (drop
+ (i32.add
+ (get_global $memoryBase$0)
+ (i32.const 1016)
+ )
+ )
+ (drop
+ (i32.add
+ (get_global $tableBase$0)
+ (i32.const 1006)
+ )
+ )
+ (drop
+ (i32.add
+ (i32.add
+ (get_global $tableBase$0)
+ (i32.const 6)
+ )
+ (unreachable)
+ )
+ )
+ (drop
+ (i32.sub
+ (i32.add
+ (get_global $tableBase$0)
+ (i32.const 6)
+ )
+ (i32.const 1000)
+ )
+ )
+ (set_global $global-collide-mut$0
+ (i32.const 5678)
+ )
+ )
+ (func $willCollide$0 (type $FUNCSIG$v$0)
+ (drop
+ (i32.const 222)
+ )
+ (call $willCollide$0)
+ )
+)
diff --git a/test/merge/basics.wast.combined.finalized b/test/merge/basics.wast.combined.finalized
new file mode 100644
index 000000000..7637b787b
--- /dev/null
+++ b/test/merge/basics.wast.combined.finalized
@@ -0,0 +1,133 @@
+(module
+ (type $ii (func (param i32 i32)))
+ (type $FUNCSIG$v (func))
+ (type $ii$0 (func (param i32 i32)))
+ (type $FUNCSIG$v$0 (func))
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table 18 anyfunc))
+ (import "env" "some-func" (func $some-func))
+ (import "env" "some-collide" (func $some-collide))
+ (import "env" "memoryBase" (global $memoryBase$0 i32))
+ (import "env" "tableBase" (global $tableBase$0 i32))
+ (import "env" "some-func-b" (func $some-func-b))
+ (import "env" "some-collide" (func $some-collide$0))
+ (global $global-collide i32 (i32.const 0))
+ (global $global-collide-mut (mut i32) (i32.const 0))
+ (global $global-a i32 (i32.const 1))
+ (global $global-collide$0 i32 (i32.const 0))
+ (global $global-collide-mut$0 (mut i32) (i32.const 0))
+ (global $global-b i32 (i32.const 1))
+ (elem (i32.const 8) $only-a $willCollide $some-func $some-collide $only-a $only-a $only-b $willCollide$0 $some-func-b $some-collide$0)
+ (data (i32.const 1024) "hello, A!\n\00\00\00\00\00\00hello, B!\n\00\00\00\00\00\00")
+ (export "exp-a" (func $only-a))
+ (export "exp-collide" (func $only-a))
+ (export "exp-collide2" (func $willCollide))
+ (export "exp-b" (func $only-b))
+ (export "exp-b-nameCollided" (func $willCollide$0))
+ (func $only-a (type $FUNCSIG$v)
+ (drop
+ (i32.const 100)
+ )
+ (call $only-a)
+ (call $some-func)
+ (call $some-collide)
+ (call_indirect $ii
+ (i32.const 123)
+ (i32.const 456)
+ (i32.const 789)
+ )
+ (drop
+ (get_global $global-collide)
+ )
+ (drop
+ (get_global $global-a)
+ )
+ (drop
+ (i32.const 1024)
+ )
+ (drop
+ (i32.const 8)
+ )
+ (set_global $global-collide-mut
+ (i32.const 1234)
+ )
+ )
+ (func $willCollide (type $FUNCSIG$v)
+ (drop
+ (i32.const 200)
+ )
+ (call $willCollide)
+ )
+ (func $only-b (type $FUNCSIG$v$0)
+ (drop
+ (i32.const 111)
+ )
+ (call $only-b)
+ (call $some-func-b)
+ (call $some-collide$0)
+ (call_indirect $ii$0
+ (i32.const 12)
+ (i32.const 34)
+ (i32.const 56)
+ )
+ (drop
+ (get_global $global-collide$0)
+ )
+ (drop
+ (get_global $global-b)
+ )
+ (drop
+ (i32.add
+ (i32.const 1024)
+ (i32.const 16)
+ )
+ )
+ (drop
+ (i32.add
+ (i32.const 8)
+ (i32.const 6)
+ )
+ )
+ (drop
+ (i32.add
+ (i32.const 1024)
+ (i32.const 1016)
+ )
+ )
+ (drop
+ (i32.add
+ (i32.const 8)
+ (i32.const 1006)
+ )
+ )
+ (drop
+ (i32.add
+ (i32.add
+ (i32.const 8)
+ (i32.const 6)
+ )
+ (unreachable)
+ )
+ )
+ (drop
+ (i32.sub
+ (i32.add
+ (i32.const 8)
+ (i32.const 6)
+ )
+ (i32.const 1000)
+ )
+ )
+ (set_global $global-collide-mut$0
+ (i32.const 5678)
+ )
+ )
+ (func $willCollide$0 (type $FUNCSIG$v$0)
+ (drop
+ (i32.const 222)
+ )
+ (call $willCollide$0)
+ )
+)
diff --git a/test/merge/basics.wast.combined.finalized.opt b/test/merge/basics.wast.combined.finalized.opt
new file mode 100644
index 000000000..320ba8fa7
--- /dev/null
+++ b/test/merge/basics.wast.combined.finalized.opt
@@ -0,0 +1,86 @@
+(module
+ (type $ii (func (param i32 i32)))
+ (type $FUNCSIG$v (func))
+ (type $ii$0 (func (param i32 i32)))
+ (type $FUNCSIG$v$0 (func))
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table 18 anyfunc))
+ (import "env" "some-func" (func $some-func))
+ (import "env" "some-collide" (func $some-collide))
+ (import "env" "some-func-b" (func $some-func-b))
+ (import "env" "some-collide" (func $some-collide$0))
+ (global $global-collide i32 (i32.const 0))
+ (global $global-collide-mut (mut i32) (i32.const 0))
+ (global $global-a i32 (i32.const 1))
+ (global $global-collide$0 i32 (i32.const 0))
+ (global $global-collide-mut$0 (mut i32) (i32.const 0))
+ (global $global-b i32 (i32.const 1))
+ (elem (i32.const 8) $only-a $willCollide $some-func $some-collide $only-a $only-a $only-b $willCollide$0 $some-func-b $some-collide$0)
+ (data (i32.const 1024) "hello, A!\n\00\00\00\00\00\00hello, B!\n")
+ (export "exp-a" (func $only-a))
+ (export "exp-collide" (func $only-a))
+ (export "exp-collide2" (func $willCollide))
+ (export "exp-b" (func $only-b))
+ (export "exp-b-nameCollided" (func $willCollide$0))
+ (func $only-a (type $FUNCSIG$v)
+ (nop)
+ (call $only-a)
+ (call $some-func)
+ (call $some-collide)
+ (call_indirect $ii
+ (i32.const 123)
+ (i32.const 456)
+ (i32.const 789)
+ )
+ (drop
+ (get_global $global-collide)
+ )
+ (drop
+ (get_global $global-a)
+ )
+ (nop)
+ (nop)
+ (set_global $global-collide-mut
+ (i32.const 1234)
+ )
+ )
+ (func $willCollide (type $FUNCSIG$v)
+ (nop)
+ (call $willCollide)
+ )
+ (func $only-b (type $FUNCSIG$v$0)
+ (nop)
+ (call $only-b)
+ (call $some-func-b)
+ (call $some-collide$0)
+ (call_indirect $ii$0
+ (i32.const 12)
+ (i32.const 34)
+ (i32.const 56)
+ )
+ (drop
+ (get_global $global-collide$0)
+ )
+ (drop
+ (get_global $global-b)
+ )
+ (nop)
+ (nop)
+ (nop)
+ (nop)
+ (drop
+ (i32.add
+ (unreachable)
+ (i32.const 14)
+ )
+ )
+ (nop)
+ (set_global $global-collide-mut$0
+ (i32.const 5678)
+ )
+ )
+ (func $willCollide$0 (type $FUNCSIG$v$0)
+ (nop)
+ (call $willCollide$0)
+ )
+)
diff --git a/test/merge/basics.wast.combined.finalized.opt.stdout b/test/merge/basics.wast.combined.finalized.opt.stdout
new file mode 100644
index 000000000..18fbdb05e
--- /dev/null
+++ b/test/merge/basics.wast.combined.finalized.opt.stdout
@@ -0,0 +1,3 @@
+merged total memory size: 32
+merged total table size: 10
+merged functions: 4
diff --git a/test/merge/basics.wast.combined.finalized.stdout b/test/merge/basics.wast.combined.finalized.stdout
new file mode 100644
index 000000000..18fbdb05e
--- /dev/null
+++ b/test/merge/basics.wast.combined.finalized.stdout
@@ -0,0 +1,3 @@
+merged total memory size: 32
+merged total table size: 10
+merged functions: 4
diff --git a/test/merge/basics.wast.combined.opt b/test/merge/basics.wast.combined.opt
new file mode 100644
index 000000000..ba8ab6220
--- /dev/null
+++ b/test/merge/basics.wast.combined.opt
@@ -0,0 +1,122 @@
+(module
+ (type $ii (func (param i32 i32)))
+ (type $FUNCSIG$v (func))
+ (type $ii$0 (func (param i32 i32)))
+ (type $FUNCSIG$v$0 (func))
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table 10 anyfunc))
+ (import "env" "some-func" (func $some-func))
+ (import "env" "some-collide" (func $some-collide))
+ (import "env" "memoryBase" (global $memoryBase$0 i32))
+ (import "env" "tableBase" (global $tableBase$0 i32))
+ (import "env" "some-func-b" (func $some-func-b))
+ (import "env" "some-collide" (func $some-collide$0))
+ (global $global-collide i32 (i32.const 0))
+ (global $global-collide-mut (mut i32) (i32.const 0))
+ (global $global-a i32 (i32.const 1))
+ (global $global-collide$0 i32 (i32.const 0))
+ (global $global-collide-mut$0 (mut i32) (i32.const 0))
+ (global $global-b i32 (i32.const 1))
+ (elem (get_global $tableBase) $only-a $willCollide $some-func $some-collide $only-a $only-a $only-b $willCollide$0 $some-func-b $some-collide$0)
+ (data (get_global $memoryBase) "hello, A!\n\00\00\00\00\00\00hello, B!\n")
+ (export "exp-a" (func $only-a))
+ (export "exp-collide" (func $only-a))
+ (export "exp-collide2" (func $willCollide))
+ (export "exp-b" (func $only-b))
+ (export "exp-b-nameCollided" (func $willCollide$0))
+ (func $only-a (type $FUNCSIG$v)
+ (nop)
+ (call $only-a)
+ (call $some-func)
+ (call $some-collide)
+ (call_indirect $ii
+ (i32.const 123)
+ (i32.const 456)
+ (i32.const 789)
+ )
+ (drop
+ (get_global $global-collide)
+ )
+ (drop
+ (get_global $global-a)
+ )
+ (drop
+ (get_global $memoryBase)
+ )
+ (drop
+ (get_global $tableBase)
+ )
+ (set_global $global-collide-mut
+ (i32.const 1234)
+ )
+ )
+ (func $willCollide (type $FUNCSIG$v)
+ (nop)
+ (call $willCollide)
+ )
+ (func $only-b (type $FUNCSIG$v$0)
+ (nop)
+ (call $only-b)
+ (call $some-func-b)
+ (call $some-collide$0)
+ (call_indirect $ii$0
+ (i32.const 12)
+ (i32.const 34)
+ (i32.const 56)
+ )
+ (drop
+ (get_global $global-collide$0)
+ )
+ (drop
+ (get_global $global-b)
+ )
+ (drop
+ (i32.add
+ (get_global $memoryBase$0)
+ (i32.const 16)
+ )
+ )
+ (drop
+ (i32.add
+ (get_global $tableBase$0)
+ (i32.const 6)
+ )
+ )
+ (drop
+ (i32.add
+ (get_global $memoryBase$0)
+ (i32.const 1016)
+ )
+ )
+ (drop
+ (i32.add
+ (get_global $tableBase$0)
+ (i32.const 1006)
+ )
+ )
+ (drop
+ (i32.add
+ (i32.add
+ (get_global $tableBase$0)
+ (i32.const 6)
+ )
+ (unreachable)
+ )
+ )
+ (drop
+ (i32.add
+ (get_global $tableBase$0)
+ (i32.const -994)
+ )
+ )
+ (set_global $global-collide-mut$0
+ (i32.const 5678)
+ )
+ )
+ (func $willCollide$0 (type $FUNCSIG$v$0)
+ (nop)
+ (call $willCollide$0)
+ )
+)
diff --git a/test/merge/basics.wast.combined.opt.stdout b/test/merge/basics.wast.combined.opt.stdout
new file mode 100644
index 000000000..18fbdb05e
--- /dev/null
+++ b/test/merge/basics.wast.combined.opt.stdout
@@ -0,0 +1,3 @@
+merged total memory size: 32
+merged total table size: 10
+merged functions: 4
diff --git a/test/merge/basics.wast.combined.stdout b/test/merge/basics.wast.combined.stdout
new file mode 100644
index 000000000..18fbdb05e
--- /dev/null
+++ b/test/merge/basics.wast.combined.stdout
@@ -0,0 +1,3 @@
+merged total memory size: 32
+merged total table size: 10
+merged functions: 4
diff --git a/test/merge/basics.wast.toMerge b/test/merge/basics.wast.toMerge
new file mode 100644
index 000000000..5122afe31
--- /dev/null
+++ b/test/merge/basics.wast.toMerge
@@ -0,0 +1,63 @@
+(module
+ (type $ii (func (param i32 i32)))
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table 0 anyfunc))
+ (import "env" "some-func-b" (func $some-func-b))
+ (import "env" "some-collide" (func $some-collide))
+ (data (get_global $memoryBase) "hello, B!\n")
+ (global $global-collide i32 (i32.const 0))
+ (global $global-collide-mut (mut i32) (i32.const 0))
+ (global $global-b i32 (i32.const 1))
+ (elem (get_global $tableBase) $only-b $willCollide $some-func-b $some-collide)
+ (export "exp-b" (func $only-b))
+ (export "exp-collide" (func $only-b))
+ (export "exp-collide2" (func $willCollide))
+ (export "exp-b-nameCollided" (func $willCollide))
+ (func $only-b
+ (drop (i32.const 111))
+ (call $only-b)
+ (call $some-func-b)
+ (call_import $some-collide)
+ (call_indirect $ii
+ (i32.const 12)
+ (i32.const 34)
+ (i32.const 56)
+ )
+ (drop (get_global $global-collide))
+ (drop (get_global $global-b))
+ (drop (get_global $memoryBase))
+ (drop (get_global $tableBase))
+ (drop
+ (i32.add
+ (get_global $memoryBase)
+ (i32.const 1000)
+ )
+ )
+ (drop
+ (i32.add
+ (get_global $tableBase)
+ (i32.const 1000)
+ )
+ )
+ (drop
+ (i32.add
+ (get_global $tableBase)
+ (unreachable) ;; bad!
+ )
+ )
+ (drop
+ (i32.sub ;; bad!
+ (get_global $tableBase)
+ (i32.const 1000)
+ )
+ )
+ (set_global $global-collide-mut (i32.const 5678))
+ )
+ (func $willCollide
+ (drop (i32.const 222))
+ (call $willCollide)
+ )
+)
+
diff --git a/test/merge/dylib.wasm b/test/merge/dylib.wasm
new file mode 100644
index 000000000..4d86a9483
--- /dev/null
+++ b/test/merge/dylib.wasm
Binary files differ
diff --git a/test/merge/dylib.wasm.combined b/test/merge/dylib.wasm.combined
new file mode 100644
index 000000000..0133476a9
--- /dev/null
+++ b/test/merge/dylib.wasm.combined
@@ -0,0 +1,91 @@
+(module
+ (type $0 (func (param i32 i32)))
+ (type $1 (func (param i32) (result i32)))
+ (type $2 (func (result i32)))
+ (type $3 (func))
+ (type $0$0 (func (param i32 i32)))
+ (type $1$0 (func (result i32)))
+ (type $2$0 (func))
+ (import "env" "memoryBase" (global $import$0 i32))
+ (import "env" "_puts" (func $import$1 (param i32) (result i32)))
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table 0 anyfunc))
+ (import "env" "tableBase" (global $import$4 i32))
+ (import "env" "memoryBase" (global $import$0$0 i32))
+ (import "env" "tableBase" (global $import$4$0 i32))
+ (global $global$0 (mut i32) (i32.const 0))
+ (global $global$1 (mut i32) (i32.const 0))
+ (global $global$2 i32 (i32.const 0))
+ (global $global$0$0 (mut i32) (i32.const 0))
+ (global $global$1$0 (mut i32) (i32.const 0))
+
+ (data (get_global $import$0) "hello, world!\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00")
+ (export "__post_instantiate" (func $__post_instantiate))
+ (export "_main" (func $_main))
+ (export "runPostSets" (func $runPostSets))
+ (export "_str" (global $global$2))
+ (export "_foo" (func $_foo))
+ (func $_main (type $2) (result i32)
+ (block $label$0 i32
+ (drop
+ (call $import$1
+ (get_global $import$0)
+ )
+ )
+ (i32.const 0)
+ )
+ )
+ (func $runPostSets (type $3)
+ (nop)
+ )
+ (func $__post_instantiate (type $3)
+ (call $__post_instantiate$0)
+ (block
+ (block $label$0
+ (set_global $global$0
+ (i32.add
+ (get_global $import$0)
+ (i32.const 16)
+ )
+ )
+ (set_global $global$1
+ (i32.add
+ (get_global $global$0)
+ (i32.const 32)
+ )
+ )
+ (call $runPostSets)
+ )
+ )
+ )
+ (func $_foo (type $1$0) (result i32)
+ (local $var$0 i32)
+ (block $label$0 i32
+ (set_local $var$0
+ (call $_main)
+ )
+ (get_local $var$0)
+ )
+ )
+ (func $runPostSets$0 (type $2$0)
+ (nop)
+ )
+ (func $__post_instantiate$0 (type $2$0)
+ (block $label$0
+ (set_global $global$0$0
+ (i32.add
+ (get_global $import$0$0)
+ (i32.const 48)
+ )
+ )
+ (set_global $global$1$0
+ (i32.add
+ (get_global $global$0$0)
+ (i32.const 10)
+ )
+ )
+ (call $runPostSets$0)
+ )
+ )
+ ;; custom section "dylink", size 2
+)
diff --git a/test/merge/dylib.wasm.combined.finalized b/test/merge/dylib.wasm.combined.finalized
new file mode 100644
index 000000000..c3f64a0b5
--- /dev/null
+++ b/test/merge/dylib.wasm.combined.finalized
@@ -0,0 +1,91 @@
+(module
+ (type $0 (func (param i32 i32)))
+ (type $1 (func (param i32) (result i32)))
+ (type $2 (func (result i32)))
+ (type $3 (func))
+ (type $0$0 (func (param i32 i32)))
+ (type $1$0 (func (result i32)))
+ (type $2$0 (func))
+ (import "env" "memoryBase" (global $import$0 i32))
+ (import "env" "_puts" (func $import$1 (param i32) (result i32)))
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table 8 anyfunc))
+ (import "env" "tableBase" (global $import$4 i32))
+ (import "env" "memoryBase" (global $import$0$0 i32))
+ (import "env" "tableBase" (global $import$4$0 i32))
+ (global $global$0 (mut i32) (i32.const 0))
+ (global $global$1 (mut i32) (i32.const 0))
+ (global $global$2 i32 (i32.const 0))
+ (global $global$0$0 (mut i32) (i32.const 0))
+ (global $global$1$0 (mut i32) (i32.const 0))
+
+ (data (i32.const 1024) "hello, world!\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00")
+ (export "__post_instantiate" (func $__post_instantiate))
+ (export "_main" (func $_main))
+ (export "runPostSets" (func $runPostSets))
+ (export "_str" (global $global$2))
+ (export "_foo" (func $_foo))
+ (func $_main (type $2) (result i32)
+ (block $label$0 i32
+ (drop
+ (call $import$1
+ (i32.const 1024)
+ )
+ )
+ (i32.const 0)
+ )
+ )
+ (func $runPostSets (type $3)
+ (nop)
+ )
+ (func $__post_instantiate (type $3)
+ (call $__post_instantiate$0)
+ (block
+ (block $label$0
+ (set_global $global$0
+ (i32.add
+ (i32.const 1024)
+ (i32.const 16)
+ )
+ )
+ (set_global $global$1
+ (i32.add
+ (get_global $global$0)
+ (i32.const 32)
+ )
+ )
+ (call $runPostSets)
+ )
+ )
+ )
+ (func $_foo (type $1$0) (result i32)
+ (local $var$0 i32)
+ (block $label$0 i32
+ (set_local $var$0
+ (call $_main)
+ )
+ (get_local $var$0)
+ )
+ )
+ (func $runPostSets$0 (type $2$0)
+ (nop)
+ )
+ (func $__post_instantiate$0 (type $2$0)
+ (block $label$0
+ (set_global $global$0$0
+ (i32.add
+ (i32.const 1024)
+ (i32.const 48)
+ )
+ )
+ (set_global $global$1$0
+ (i32.add
+ (get_global $global$0$0)
+ (i32.const 10)
+ )
+ )
+ (call $runPostSets$0)
+ )
+ )
+ ;; custom section "dylink", size 2
+)
diff --git a/test/merge/dylib.wasm.combined.finalized.opt b/test/merge/dylib.wasm.combined.finalized.opt
new file mode 100644
index 000000000..2d40fb83c
--- /dev/null
+++ b/test/merge/dylib.wasm.combined.finalized.opt
@@ -0,0 +1,81 @@
+(module
+ (type $0 (func (param i32 i32)))
+ (type $1 (func (param i32) (result i32)))
+ (type $2 (func (result i32)))
+ (type $3 (func))
+ (type $0$0 (func (param i32 i32)))
+ (type $1$0 (func (result i32)))
+ (type $2$0 (func))
+ (import "env" "_puts" (func $import$1 (param i32) (result i32)))
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table 8 anyfunc))
+ (global $global$0 (mut i32) (i32.const 0))
+ (global $global$1 (mut i32) (i32.const 0))
+ (global $global$2 i32 (i32.const 0))
+ (global $global$0$0 (mut i32) (i32.const 0))
+ (global $global$1$0 (mut i32) (i32.const 0))
+
+ (data (i32.const 1024) "hello, world!")
+ (export "__post_instantiate" (func $__post_instantiate))
+ (export "_main" (func $_main))
+ (export "runPostSets" (func $runPostSets))
+ (export "_str" (global $global$2))
+ (export "_foo" (func $_foo))
+ (func $_main (type $2) (result i32)
+ (block $label$0 i32
+ (drop
+ (call $import$1
+ (i32.const 1024)
+ )
+ )
+ (i32.const 0)
+ )
+ )
+ (func $runPostSets (type $3)
+ (nop)
+ )
+ (func $__post_instantiate (type $3)
+ (call $__post_instantiate$0)
+ (block
+ (block $label$0
+ (set_global $global$0
+ (i32.const 1040)
+ )
+ (set_global $global$1
+ (i32.add
+ (get_global $global$0)
+ (i32.const 32)
+ )
+ )
+ (call $runPostSets)
+ )
+ )
+ )
+ (func $_foo (type $1$0) (result i32)
+ (local $var$0 i32)
+ (block $label$0 i32
+ (set_local $var$0
+ (call $_main)
+ )
+ (get_local $var$0)
+ )
+ )
+ (func $runPostSets$0 (type $2$0)
+ (nop)
+ )
+ (func $__post_instantiate$0 (type $2$0)
+ (block $label$0
+ (set_global $global$0$0
+ (i32.const 1072)
+ )
+ (set_global $global$1$0
+ (i32.add
+ (get_global $global$0$0)
+ (i32.const 10)
+ )
+ )
+ (call $runPostSets$0)
+ )
+ )
+ ;; custom section "dylink", size 2
+)
diff --git a/test/merge/dylib.wasm.combined.finalized.opt.stdout b/test/merge/dylib.wasm.combined.finalized.opt.stdout
new file mode 100644
index 000000000..fb480861a
--- /dev/null
+++ b/test/merge/dylib.wasm.combined.finalized.opt.stdout
@@ -0,0 +1,3 @@
+merged total memory size: 64
+merged total table size: 0
+merged functions: 6
diff --git a/test/merge/dylib.wasm.combined.finalized.stdout b/test/merge/dylib.wasm.combined.finalized.stdout
new file mode 100644
index 000000000..fb480861a
--- /dev/null
+++ b/test/merge/dylib.wasm.combined.finalized.stdout
@@ -0,0 +1,3 @@
+merged total memory size: 64
+merged total table size: 0
+merged functions: 6
diff --git a/test/merge/dylib.wasm.combined.opt b/test/merge/dylib.wasm.combined.opt
new file mode 100644
index 000000000..8c354e34d
--- /dev/null
+++ b/test/merge/dylib.wasm.combined.opt
@@ -0,0 +1,90 @@
+(module
+ (type $0 (func (param i32 i32)))
+ (type $1 (func (param i32) (result i32)))
+ (type $2 (func (result i32)))
+ (type $3 (func))
+ (type $0$0 (func (param i32 i32)))
+ (type $1$0 (func (result i32)))
+ (type $2$0 (func))
+ (import "env" "memoryBase" (global $import$0 i32))
+ (import "env" "_puts" (func $import$1 (param i32) (result i32)))
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table 0 anyfunc))
+ (import "env" "tableBase" (global $import$4 i32))
+ (import "env" "memoryBase" (global $import$0$0 i32))
+ (global $global$0 (mut i32) (i32.const 0))
+ (global $global$1 (mut i32) (i32.const 0))
+ (global $global$2 i32 (i32.const 0))
+ (global $global$0$0 (mut i32) (i32.const 0))
+ (global $global$1$0 (mut i32) (i32.const 0))
+
+ (data (get_global $import$0) "hello, world!")
+ (export "__post_instantiate" (func $__post_instantiate))
+ (export "_main" (func $_main))
+ (export "runPostSets" (func $runPostSets))
+ (export "_str" (global $global$2))
+ (export "_foo" (func $_foo))
+ (func $_main (type $2) (result i32)
+ (block $label$0 i32
+ (drop
+ (call $import$1
+ (get_global $import$0)
+ )
+ )
+ (i32.const 0)
+ )
+ )
+ (func $runPostSets (type $3)
+ (nop)
+ )
+ (func $__post_instantiate (type $3)
+ (call $__post_instantiate$0)
+ (block
+ (block $label$0
+ (set_global $global$0
+ (i32.add
+ (get_global $import$0)
+ (i32.const 16)
+ )
+ )
+ (set_global $global$1
+ (i32.add
+ (get_global $global$0)
+ (i32.const 32)
+ )
+ )
+ (call $runPostSets)
+ )
+ )
+ )
+ (func $_foo (type $1$0) (result i32)
+ (local $var$0 i32)
+ (block $label$0 i32
+ (set_local $var$0
+ (call $_main)
+ )
+ (get_local $var$0)
+ )
+ )
+ (func $runPostSets$0 (type $2$0)
+ (nop)
+ )
+ (func $__post_instantiate$0 (type $2$0)
+ (block $label$0
+ (set_global $global$0$0
+ (i32.add
+ (get_global $import$0$0)
+ (i32.const 48)
+ )
+ )
+ (set_global $global$1$0
+ (i32.add
+ (get_global $global$0$0)
+ (i32.const 10)
+ )
+ )
+ (call $runPostSets$0)
+ )
+ )
+ ;; custom section "dylink", size 2
+)
diff --git a/test/merge/dylib.wasm.combined.opt.stdout b/test/merge/dylib.wasm.combined.opt.stdout
new file mode 100644
index 000000000..fb480861a
--- /dev/null
+++ b/test/merge/dylib.wasm.combined.opt.stdout
@@ -0,0 +1,3 @@
+merged total memory size: 64
+merged total table size: 0
+merged functions: 6
diff --git a/test/merge/dylib.wasm.combined.stdout b/test/merge/dylib.wasm.combined.stdout
new file mode 100644
index 000000000..fb480861a
--- /dev/null
+++ b/test/merge/dylib.wasm.combined.stdout
@@ -0,0 +1,3 @@
+merged total memory size: 64
+merged total table size: 0
+merged functions: 6
diff --git a/test/merge/dylib.wasm.toMerge b/test/merge/dylib.wasm.toMerge
new file mode 100644
index 000000000..c9953956b
--- /dev/null
+++ b/test/merge/dylib.wasm.toMerge
Binary files differ
diff --git a/test/merge/fusing.wast b/test/merge/fusing.wast
new file mode 100644
index 000000000..588647e35
--- /dev/null
+++ b/test/merge/fusing.wast
@@ -0,0 +1,18 @@
+(module
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table 0 anyfunc))
+ (export "foo" (func $foo-func))
+ (import "env" "bar" (func $bar-func))
+ (global $a-global i32 (i32.const 0))
+ (export "aglobal" (global $a-global))
+ (import "env" "bglobal" (global $b-global f64))
+ (func $foo-func
+ (drop (i32.const 1337))
+ (call_import $bar-func)
+ (drop (get_global $a-global))
+ (drop (get_global $b-global))
+ )
+)
+
diff --git a/test/merge/fusing.wast.combined b/test/merge/fusing.wast.combined
new file mode 100644
index 000000000..2a7adf6e2
--- /dev/null
+++ b/test/merge/fusing.wast.combined
@@ -0,0 +1,44 @@
+(module
+ (type $FUNCSIG$v (func))
+ (type $FUNCSIG$v$0 (func))
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table 0 anyfunc))
+ (import "env" "memoryBase" (global $memoryBase$0 i32))
+ (import "env" "tableBase" (global $tableBase$0 i32))
+ (global $a-global i32 (i32.const 0))
+ (global $b-global f64 (f64.const 2.14281428))
+
+ (data (get_global $memoryBase) "")
+ (export "foo" (func $foo-func))
+ (export "aglobal" (global $a-global))
+ (export "bar" (func $bar-func))
+ (export "bglobal" (global $b-global))
+ (func $foo-func (type $FUNCSIG$v)
+ (drop
+ (i32.const 1337)
+ )
+ (call $bar-func)
+ (drop
+ (get_global $a-global)
+ )
+ (drop
+ (get_global $b-global)
+ )
+ )
+ (func $b (type $FUNCSIG$v$0)
+ (call $foo-func)
+ )
+ (func $bar-func (type $FUNCSIG$v$0)
+ (drop
+ (f64.const 3.14159)
+ )
+ (drop
+ (get_global $a-global)
+ )
+ (drop
+ (get_global $b-global)
+ )
+ )
+)
diff --git a/test/merge/fusing.wast.combined.finalized b/test/merge/fusing.wast.combined.finalized
new file mode 100644
index 000000000..7896e448d
--- /dev/null
+++ b/test/merge/fusing.wast.combined.finalized
@@ -0,0 +1,44 @@
+(module
+ (type $FUNCSIG$v (func))
+ (type $FUNCSIG$v$0 (func))
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table 8 anyfunc))
+ (import "env" "memoryBase" (global $memoryBase$0 i32))
+ (import "env" "tableBase" (global $tableBase$0 i32))
+ (global $a-global i32 (i32.const 0))
+ (global $b-global f64 (f64.const 2.14281428))
+
+ (data (i32.const 1024) "")
+ (export "foo" (func $foo-func))
+ (export "aglobal" (global $a-global))
+ (export "bar" (func $bar-func))
+ (export "bglobal" (global $b-global))
+ (func $foo-func (type $FUNCSIG$v)
+ (drop
+ (i32.const 1337)
+ )
+ (call $bar-func)
+ (drop
+ (get_global $a-global)
+ )
+ (drop
+ (get_global $b-global)
+ )
+ )
+ (func $b (type $FUNCSIG$v$0)
+ (call $foo-func)
+ )
+ (func $bar-func (type $FUNCSIG$v$0)
+ (drop
+ (f64.const 3.14159)
+ )
+ (drop
+ (get_global $a-global)
+ )
+ (drop
+ (get_global $b-global)
+ )
+ )
+)
diff --git a/test/merge/fusing.wast.combined.finalized.opt b/test/merge/fusing.wast.combined.finalized.opt
new file mode 100644
index 000000000..202c566e1
--- /dev/null
+++ b/test/merge/fusing.wast.combined.finalized.opt
@@ -0,0 +1,32 @@
+(module
+ (type $FUNCSIG$v (func))
+ (type $FUNCSIG$v$0 (func))
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table 8 anyfunc))
+ (global $a-global i32 (i32.const 0))
+ (global $b-global f64 (f64.const 2.14281428))
+
+ (export "foo" (func $foo-func))
+ (export "aglobal" (global $a-global))
+ (export "bar" (func $bar-func))
+ (export "bglobal" (global $b-global))
+ (func $foo-func (type $FUNCSIG$v)
+ (nop)
+ (call $bar-func)
+ (drop
+ (get_global $a-global)
+ )
+ (drop
+ (get_global $b-global)
+ )
+ )
+ (func $bar-func (type $FUNCSIG$v$0)
+ (nop)
+ (drop
+ (get_global $a-global)
+ )
+ (drop
+ (get_global $b-global)
+ )
+ )
+)
diff --git a/test/merge/fusing.wast.combined.finalized.opt.stdout b/test/merge/fusing.wast.combined.finalized.opt.stdout
new file mode 100644
index 000000000..80b514d22
--- /dev/null
+++ b/test/merge/fusing.wast.combined.finalized.opt.stdout
@@ -0,0 +1,3 @@
+merged total memory size: 0
+merged total table size: 0
+merged functions: 3
diff --git a/test/merge/fusing.wast.combined.finalized.stdout b/test/merge/fusing.wast.combined.finalized.stdout
new file mode 100644
index 000000000..80b514d22
--- /dev/null
+++ b/test/merge/fusing.wast.combined.finalized.stdout
@@ -0,0 +1,3 @@
+merged total memory size: 0
+merged total table size: 0
+merged functions: 3
diff --git a/test/merge/fusing.wast.combined.opt b/test/merge/fusing.wast.combined.opt
new file mode 100644
index 000000000..1a09fb784
--- /dev/null
+++ b/test/merge/fusing.wast.combined.opt
@@ -0,0 +1,35 @@
+(module
+ (type $FUNCSIG$v (func))
+ (type $FUNCSIG$v$0 (func))
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table 0 anyfunc))
+ (global $a-global i32 (i32.const 0))
+ (global $b-global f64 (f64.const 2.14281428))
+
+ (data (get_global $memoryBase) "")
+ (export "foo" (func $foo-func))
+ (export "aglobal" (global $a-global))
+ (export "bar" (func $bar-func))
+ (export "bglobal" (global $b-global))
+ (func $foo-func (type $FUNCSIG$v)
+ (nop)
+ (call $bar-func)
+ (drop
+ (get_global $a-global)
+ )
+ (drop
+ (get_global $b-global)
+ )
+ )
+ (func $bar-func (type $FUNCSIG$v$0)
+ (nop)
+ (drop
+ (get_global $a-global)
+ )
+ (drop
+ (get_global $b-global)
+ )
+ )
+)
diff --git a/test/merge/fusing.wast.combined.opt.stdout b/test/merge/fusing.wast.combined.opt.stdout
new file mode 100644
index 000000000..80b514d22
--- /dev/null
+++ b/test/merge/fusing.wast.combined.opt.stdout
@@ -0,0 +1,3 @@
+merged total memory size: 0
+merged total table size: 0
+merged functions: 3
diff --git a/test/merge/fusing.wast.combined.stdout b/test/merge/fusing.wast.combined.stdout
new file mode 100644
index 000000000..80b514d22
--- /dev/null
+++ b/test/merge/fusing.wast.combined.stdout
@@ -0,0 +1,3 @@
+merged total memory size: 0
+merged total table size: 0
+merged functions: 3
diff --git a/test/merge/fusing.wast.toMerge b/test/merge/fusing.wast.toMerge
new file mode 100644
index 000000000..4abd0a5e1
--- /dev/null
+++ b/test/merge/fusing.wast.toMerge
@@ -0,0 +1,20 @@
+(module
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table 0 anyfunc))
+ (import "env" "foo" (func $b-foo))
+ (export "bar" (func $bar-func))
+ (global $b-global f64 (f64.const 2.14281428))
+ (export "bglobal" (global $b-global))
+ (import "env" "aglobal" (global $a-global i32))
+ (func $b
+ (call $b-foo)
+ )
+ (func $bar-func
+ (drop (f64.const 3.14159))
+ (drop (get_global $a-global))
+ (drop (get_global $b-global))
+ )
+)
+
diff --git a/test/merge/global-init.wast b/test/merge/global-init.wast
new file mode 100644
index 000000000..ddf1a868f
--- /dev/null
+++ b/test/merge/global-init.wast
@@ -0,0 +1,10 @@
+(module
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table 0 anyfunc))
+ (import "env" "globally" (global $i-collide i32))
+ (global $a i32 (get_global $i-collide))
+ (global $g-collide i32 (get_global $i-collide))
+)
+
diff --git a/test/merge/global-init.wast.combined b/test/merge/global-init.wast.combined
new file mode 100644
index 000000000..95b339968
--- /dev/null
+++ b/test/merge/global-init.wast.combined
@@ -0,0 +1,16 @@
+(module
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table 0 anyfunc))
+ (import "env" "globally" (global $i-collide i32))
+ (import "env" "memoryBase" (global $memoryBase$0 i32))
+ (import "env" "tableBase" (global $tableBase$0 i32))
+ (import "env" "globally" (global $i-collide$0 f64))
+ (global $a i32 (get_global $i-collide))
+ (global $g-collide i32 (get_global $i-collide))
+ (global $b f64 (get_global $i-collide$0))
+ (global $g-collide$0 f64 (get_global $i-collide$0))
+
+ (data (get_global $memoryBase) "")
+)
diff --git a/test/merge/global-init.wast.combined.finalized b/test/merge/global-init.wast.combined.finalized
new file mode 100644
index 000000000..40a5066fa
--- /dev/null
+++ b/test/merge/global-init.wast.combined.finalized
@@ -0,0 +1,16 @@
+(module
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table 8 anyfunc))
+ (import "env" "globally" (global $i-collide i32))
+ (import "env" "memoryBase" (global $memoryBase$0 i32))
+ (import "env" "tableBase" (global $tableBase$0 i32))
+ (import "env" "globally" (global $i-collide$0 f64))
+ (global $a i32 (get_global $i-collide))
+ (global $g-collide i32 (get_global $i-collide))
+ (global $b f64 (get_global $i-collide$0))
+ (global $g-collide$0 f64 (get_global $i-collide$0))
+
+ (data (i32.const 1024) "")
+)
diff --git a/test/merge/global-init.wast.combined.finalized.opt b/test/merge/global-init.wast.combined.finalized.opt
new file mode 100644
index 000000000..02a0900f5
--- /dev/null
+++ b/test/merge/global-init.wast.combined.finalized.opt
@@ -0,0 +1,5 @@
+(module
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table 8 anyfunc))
+
+)
diff --git a/test/merge/global-init.wast.combined.finalized.opt.stdout b/test/merge/global-init.wast.combined.finalized.opt.stdout
new file mode 100644
index 000000000..361590ef0
--- /dev/null
+++ b/test/merge/global-init.wast.combined.finalized.opt.stdout
@@ -0,0 +1,3 @@
+merged total memory size: 0
+merged total table size: 0
+merged functions: 0
diff --git a/test/merge/global-init.wast.combined.finalized.stdout b/test/merge/global-init.wast.combined.finalized.stdout
new file mode 100644
index 000000000..361590ef0
--- /dev/null
+++ b/test/merge/global-init.wast.combined.finalized.stdout
@@ -0,0 +1,3 @@
+merged total memory size: 0
+merged total table size: 0
+merged functions: 0
diff --git a/test/merge/global-init.wast.combined.opt b/test/merge/global-init.wast.combined.opt
new file mode 100644
index 000000000..44c047693
--- /dev/null
+++ b/test/merge/global-init.wast.combined.opt
@@ -0,0 +1,8 @@
+(module
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table 0 anyfunc))
+
+ (data (get_global $memoryBase) "")
+)
diff --git a/test/merge/global-init.wast.combined.opt.stdout b/test/merge/global-init.wast.combined.opt.stdout
new file mode 100644
index 000000000..361590ef0
--- /dev/null
+++ b/test/merge/global-init.wast.combined.opt.stdout
@@ -0,0 +1,3 @@
+merged total memory size: 0
+merged total table size: 0
+merged functions: 0
diff --git a/test/merge/global-init.wast.combined.stdout b/test/merge/global-init.wast.combined.stdout
new file mode 100644
index 000000000..361590ef0
--- /dev/null
+++ b/test/merge/global-init.wast.combined.stdout
@@ -0,0 +1,3 @@
+merged total memory size: 0
+merged total table size: 0
+merged functions: 0
diff --git a/test/merge/global-init.wast.toMerge b/test/merge/global-init.wast.toMerge
new file mode 100644
index 000000000..6f5d5e6dd
--- /dev/null
+++ b/test/merge/global-init.wast.toMerge
@@ -0,0 +1,10 @@
+(module
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table 0 anyfunc))
+ (import "env" "globally" (global $i-collide f64))
+ (global $b f64 (get_global $i-collide))
+ (global $g-collide f64 (get_global $i-collide))
+)
+
diff --git a/test/merge/main-lacks-segments.wast b/test/merge/main-lacks-segments.wast
new file mode 100644
index 000000000..c18db2470
--- /dev/null
+++ b/test/merge/main-lacks-segments.wast
@@ -0,0 +1,7 @@
+(module
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table 0 anyfunc))
+)
+
diff --git a/test/merge/main-lacks-segments.wast.combined b/test/merge/main-lacks-segments.wast.combined
new file mode 100644
index 000000000..33eb89435
--- /dev/null
+++ b/test/merge/main-lacks-segments.wast.combined
@@ -0,0 +1,25 @@
+(module
+ (type $0 (func))
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table 2 anyfunc))
+ (import "env" "memoryBase" (global $memoryBase$0 i32))
+ (import "env" "tableBase" (global $tableBase$0 i32))
+ (elem (get_global $tableBase) $foo $foo)
+ (data (get_global $memoryBase) "hello, this is some data!\00\00\00\00\00\00\00")
+ (func $foo (type $0)
+ (drop
+ (i32.add
+ (get_global $tableBase$0)
+ (i32.const 0)
+ )
+ )
+ (drop
+ (i32.add
+ (get_global $memoryBase$0)
+ (i32.const 0)
+ )
+ )
+ )
+)
diff --git a/test/merge/main-lacks-segments.wast.combined.finalized b/test/merge/main-lacks-segments.wast.combined.finalized
new file mode 100644
index 000000000..923ffd34d
--- /dev/null
+++ b/test/merge/main-lacks-segments.wast.combined.finalized
@@ -0,0 +1,25 @@
+(module
+ (type $0 (func))
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table 10 anyfunc))
+ (import "env" "memoryBase" (global $memoryBase$0 i32))
+ (import "env" "tableBase" (global $tableBase$0 i32))
+ (elem (i32.const 8) $foo $foo)
+ (data (i32.const 1024) "hello, this is some data!\00\00\00\00\00\00\00")
+ (func $foo (type $0)
+ (drop
+ (i32.add
+ (i32.const 8)
+ (i32.const 0)
+ )
+ )
+ (drop
+ (i32.add
+ (i32.const 1024)
+ (i32.const 0)
+ )
+ )
+ )
+)
diff --git a/test/merge/main-lacks-segments.wast.combined.finalized.opt b/test/merge/main-lacks-segments.wast.combined.finalized.opt
new file mode 100644
index 000000000..0aeb4c62d
--- /dev/null
+++ b/test/merge/main-lacks-segments.wast.combined.finalized.opt
@@ -0,0 +1,10 @@
+(module
+ (type $0 (func))
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table 10 anyfunc))
+ (elem (i32.const 8) $foo $foo)
+ (data (i32.const 1024) "hello, this is some data!")
+ (func $foo (type $0)
+ (nop)
+ )
+)
diff --git a/test/merge/main-lacks-segments.wast.combined.finalized.opt.stdout b/test/merge/main-lacks-segments.wast.combined.finalized.opt.stdout
new file mode 100644
index 000000000..5e72852f9
--- /dev/null
+++ b/test/merge/main-lacks-segments.wast.combined.finalized.opt.stdout
@@ -0,0 +1,3 @@
+merged total memory size: 32
+merged total table size: 2
+merged functions: 1
diff --git a/test/merge/main-lacks-segments.wast.combined.finalized.stdout b/test/merge/main-lacks-segments.wast.combined.finalized.stdout
new file mode 100644
index 000000000..5e72852f9
--- /dev/null
+++ b/test/merge/main-lacks-segments.wast.combined.finalized.stdout
@@ -0,0 +1,3 @@
+merged total memory size: 32
+merged total table size: 2
+merged functions: 1
diff --git a/test/merge/main-lacks-segments.wast.combined.opt b/test/merge/main-lacks-segments.wast.combined.opt
new file mode 100644
index 000000000..4ea294a8e
--- /dev/null
+++ b/test/merge/main-lacks-segments.wast.combined.opt
@@ -0,0 +1,19 @@
+(module
+ (type $0 (func))
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table 2 anyfunc))
+ (import "env" "memoryBase" (global $memoryBase$0 i32))
+ (import "env" "tableBase" (global $tableBase$0 i32))
+ (elem (get_global $tableBase) $foo $foo)
+ (data (get_global $memoryBase) "hello, this is some data!")
+ (func $foo (type $0)
+ (drop
+ (get_global $tableBase$0)
+ )
+ (drop
+ (get_global $memoryBase$0)
+ )
+ )
+)
diff --git a/test/merge/main-lacks-segments.wast.combined.opt.stdout b/test/merge/main-lacks-segments.wast.combined.opt.stdout
new file mode 100644
index 000000000..5e72852f9
--- /dev/null
+++ b/test/merge/main-lacks-segments.wast.combined.opt.stdout
@@ -0,0 +1,3 @@
+merged total memory size: 32
+merged total table size: 2
+merged functions: 1
diff --git a/test/merge/main-lacks-segments.wast.combined.stdout b/test/merge/main-lacks-segments.wast.combined.stdout
new file mode 100644
index 000000000..5e72852f9
--- /dev/null
+++ b/test/merge/main-lacks-segments.wast.combined.stdout
@@ -0,0 +1,3 @@
+merged total memory size: 32
+merged total table size: 2
+merged functions: 1
diff --git a/test/merge/main-lacks-segments.wast.toMerge b/test/merge/main-lacks-segments.wast.toMerge
new file mode 100644
index 000000000..63c2c3a3a
--- /dev/null
+++ b/test/merge/main-lacks-segments.wast.toMerge
@@ -0,0 +1,13 @@
+(module
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table 0 anyfunc))
+ (elem (get_global $tableBase) $foo)
+ (data (get_global $memoryBase) "hello, this is some data!")
+ (func $foo
+ (drop (get_global $tableBase))
+ (drop (get_global $memoryBase))
+ )
+)
+
diff --git a/test/merge/post-instantiate-a.wast b/test/merge/post-instantiate-a.wast
new file mode 100644
index 000000000..5099df574
--- /dev/null
+++ b/test/merge/post-instantiate-a.wast
@@ -0,0 +1,9 @@
+(module
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (export "__post_instantiate" (func $0))
+ (func $0
+ (drop (i32.const 1000))
+ )
+)
+
diff --git a/test/merge/post-instantiate-a.wast.combined b/test/merge/post-instantiate-a.wast.combined
new file mode 100644
index 000000000..725e1df28
--- /dev/null
+++ b/test/merge/post-instantiate-a.wast.combined
@@ -0,0 +1,19 @@
+(module
+ (type $0 (func))
+ (type $0$0 (func))
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (import "env" "memoryBase" (global $memoryBase$0 i32))
+ (import "env" "tableBase" (global $tableBase$0 i32))
+ (memory $0 0)
+ (data (get_global $memoryBase) "")
+ (export "__post_instantiate" (func $0))
+ (func $0 (type $0)
+ (drop
+ (i32.const 1000)
+ )
+ )
+ (func $0$0 (type $0$0)
+ (nop)
+ )
+)
diff --git a/test/merge/post-instantiate-a.wast.combined.finalized b/test/merge/post-instantiate-a.wast.combined.finalized
new file mode 100644
index 000000000..e50f84e79
--- /dev/null
+++ b/test/merge/post-instantiate-a.wast.combined.finalized
@@ -0,0 +1,19 @@
+(module
+ (type $0 (func))
+ (type $0$0 (func))
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (import "env" "memoryBase" (global $memoryBase$0 i32))
+ (import "env" "tableBase" (global $tableBase$0 i32))
+ (memory $0 1)
+ (data (i32.const 1024) "")
+ (export "__post_instantiate" (func $0))
+ (func $0 (type $0)
+ (drop
+ (i32.const 1000)
+ )
+ )
+ (func $0$0 (type $0$0)
+ (nop)
+ )
+)
diff --git a/test/merge/post-instantiate-a.wast.combined.finalized.opt b/test/merge/post-instantiate-a.wast.combined.finalized.opt
new file mode 100644
index 000000000..2fc7dbdb3
--- /dev/null
+++ b/test/merge/post-instantiate-a.wast.combined.finalized.opt
@@ -0,0 +1,10 @@
+(module
+ (type $0 (func))
+ (type $0$0 (func))
+ (memory $0 1)
+ (data (i32.const 1024) "")
+ (export "__post_instantiate" (func $0))
+ (func $0 (type $0)
+ (nop)
+ )
+)
diff --git a/test/merge/post-instantiate-a.wast.combined.finalized.opt.stdout b/test/merge/post-instantiate-a.wast.combined.finalized.opt.stdout
new file mode 100644
index 000000000..3816869a7
--- /dev/null
+++ b/test/merge/post-instantiate-a.wast.combined.finalized.opt.stdout
@@ -0,0 +1,3 @@
+merged total memory size: 0
+merged total table size: 0
+merged functions: 2
diff --git a/test/merge/post-instantiate-a.wast.combined.finalized.stdout b/test/merge/post-instantiate-a.wast.combined.finalized.stdout
new file mode 100644
index 000000000..3816869a7
--- /dev/null
+++ b/test/merge/post-instantiate-a.wast.combined.finalized.stdout
@@ -0,0 +1,3 @@
+merged total memory size: 0
+merged total table size: 0
+merged functions: 2
diff --git a/test/merge/post-instantiate-a.wast.combined.opt b/test/merge/post-instantiate-a.wast.combined.opt
new file mode 100644
index 000000000..8f190f187
--- /dev/null
+++ b/test/merge/post-instantiate-a.wast.combined.opt
@@ -0,0 +1,12 @@
+(module
+ (type $0 (func))
+ (type $0$0 (func))
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (memory $0 0)
+ (data (get_global $memoryBase) "")
+ (export "__post_instantiate" (func $0))
+ (func $0 (type $0)
+ (nop)
+ )
+)
diff --git a/test/merge/post-instantiate-a.wast.combined.opt.stdout b/test/merge/post-instantiate-a.wast.combined.opt.stdout
new file mode 100644
index 000000000..3816869a7
--- /dev/null
+++ b/test/merge/post-instantiate-a.wast.combined.opt.stdout
@@ -0,0 +1,3 @@
+merged total memory size: 0
+merged total table size: 0
+merged functions: 2
diff --git a/test/merge/post-instantiate-a.wast.combined.stdout b/test/merge/post-instantiate-a.wast.combined.stdout
new file mode 100644
index 000000000..3816869a7
--- /dev/null
+++ b/test/merge/post-instantiate-a.wast.combined.stdout
@@ -0,0 +1,3 @@
+merged total memory size: 0
+merged total table size: 0
+merged functions: 2
diff --git a/test/merge/post-instantiate-a.wast.toMerge b/test/merge/post-instantiate-a.wast.toMerge
new file mode 100644
index 000000000..3b62ceb9e
--- /dev/null
+++ b/test/merge/post-instantiate-a.wast.toMerge
@@ -0,0 +1,6 @@
+(module
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (func $0)
+)
+
diff --git a/test/merge/post-instantiate-b.wast b/test/merge/post-instantiate-b.wast
new file mode 100644
index 000000000..3b62ceb9e
--- /dev/null
+++ b/test/merge/post-instantiate-b.wast
@@ -0,0 +1,6 @@
+(module
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (func $0)
+)
+
diff --git a/test/merge/post-instantiate-b.wast.combined b/test/merge/post-instantiate-b.wast.combined
new file mode 100644
index 000000000..df4bfe76d
--- /dev/null
+++ b/test/merge/post-instantiate-b.wast.combined
@@ -0,0 +1,19 @@
+(module
+ (type $0 (func))
+ (type $0$0 (func))
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (import "env" "memoryBase" (global $memoryBase$0 i32))
+ (import "env" "tableBase" (global $tableBase$0 i32))
+ (memory $0 0)
+ (data (get_global $memoryBase) "")
+ (export "__post_instantiate" (func $0$0))
+ (func $0 (type $0)
+ (nop)
+ )
+ (func $0$0 (type $0$0)
+ (drop
+ (i32.const 2000)
+ )
+ )
+)
diff --git a/test/merge/post-instantiate-b.wast.combined.finalized b/test/merge/post-instantiate-b.wast.combined.finalized
new file mode 100644
index 000000000..a6f2d309b
--- /dev/null
+++ b/test/merge/post-instantiate-b.wast.combined.finalized
@@ -0,0 +1,19 @@
+(module
+ (type $0 (func))
+ (type $0$0 (func))
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (import "env" "memoryBase" (global $memoryBase$0 i32))
+ (import "env" "tableBase" (global $tableBase$0 i32))
+ (memory $0 1)
+ (data (i32.const 1024) "")
+ (export "__post_instantiate" (func $0$0))
+ (func $0 (type $0)
+ (nop)
+ )
+ (func $0$0 (type $0$0)
+ (drop
+ (i32.const 2000)
+ )
+ )
+)
diff --git a/test/merge/post-instantiate-b.wast.combined.finalized.opt b/test/merge/post-instantiate-b.wast.combined.finalized.opt
new file mode 100644
index 000000000..f335f08d9
--- /dev/null
+++ b/test/merge/post-instantiate-b.wast.combined.finalized.opt
@@ -0,0 +1,10 @@
+(module
+ (type $0 (func))
+ (type $0$0 (func))
+ (memory $0 1)
+ (data (i32.const 1024) "")
+ (export "__post_instantiate" (func $0$0))
+ (func $0$0 (type $0$0)
+ (nop)
+ )
+)
diff --git a/test/merge/post-instantiate-b.wast.combined.finalized.opt.stdout b/test/merge/post-instantiate-b.wast.combined.finalized.opt.stdout
new file mode 100644
index 000000000..3816869a7
--- /dev/null
+++ b/test/merge/post-instantiate-b.wast.combined.finalized.opt.stdout
@@ -0,0 +1,3 @@
+merged total memory size: 0
+merged total table size: 0
+merged functions: 2
diff --git a/test/merge/post-instantiate-b.wast.combined.finalized.stdout b/test/merge/post-instantiate-b.wast.combined.finalized.stdout
new file mode 100644
index 000000000..3816869a7
--- /dev/null
+++ b/test/merge/post-instantiate-b.wast.combined.finalized.stdout
@@ -0,0 +1,3 @@
+merged total memory size: 0
+merged total table size: 0
+merged functions: 2
diff --git a/test/merge/post-instantiate-b.wast.combined.opt b/test/merge/post-instantiate-b.wast.combined.opt
new file mode 100644
index 000000000..1a85ff79d
--- /dev/null
+++ b/test/merge/post-instantiate-b.wast.combined.opt
@@ -0,0 +1,12 @@
+(module
+ (type $0 (func))
+ (type $0$0 (func))
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (memory $0 0)
+ (data (get_global $memoryBase) "")
+ (export "__post_instantiate" (func $0$0))
+ (func $0$0 (type $0$0)
+ (nop)
+ )
+)
diff --git a/test/merge/post-instantiate-b.wast.combined.opt.stdout b/test/merge/post-instantiate-b.wast.combined.opt.stdout
new file mode 100644
index 000000000..3816869a7
--- /dev/null
+++ b/test/merge/post-instantiate-b.wast.combined.opt.stdout
@@ -0,0 +1,3 @@
+merged total memory size: 0
+merged total table size: 0
+merged functions: 2
diff --git a/test/merge/post-instantiate-b.wast.combined.stdout b/test/merge/post-instantiate-b.wast.combined.stdout
new file mode 100644
index 000000000..3816869a7
--- /dev/null
+++ b/test/merge/post-instantiate-b.wast.combined.stdout
@@ -0,0 +1,3 @@
+merged total memory size: 0
+merged total table size: 0
+merged functions: 2
diff --git a/test/merge/post-instantiate-b.wast.toMerge b/test/merge/post-instantiate-b.wast.toMerge
new file mode 100644
index 000000000..0b3678389
--- /dev/null
+++ b/test/merge/post-instantiate-b.wast.toMerge
@@ -0,0 +1,9 @@
+(module
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (export "__post_instantiate" (func $0))
+ (func $0
+ (drop (i32.const 2000))
+ )
+)
+
diff --git a/test/merge/printf.wast b/test/merge/printf.wast
new file mode 100644
index 000000000..c984602bf
--- /dev/null
+++ b/test/merge/printf.wast
@@ -0,0 +1,13 @@
+(module
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table 0 anyfunc))
+ (import "env" "globally" (global $i-collide i32))
+ (import "env" "foobar" (func $import$8 (param i32 i32) (result i32)))
+ (export "_printf" (func $625))
+ (func $625 (param $var$0 i32) (param $var$1 i32) (result i32)
+ (i32.const 102030)
+ )
+)
+
diff --git a/test/merge/printf.wast.combined b/test/merge/printf.wast.combined
new file mode 100644
index 000000000..f8dcc3d0c
--- /dev/null
+++ b/test/merge/printf.wast.combined
@@ -0,0 +1,28 @@
+(module
+ (type $FUNCSIG$iii (func (param i32 i32) (result i32)))
+ (type $FUNCSIG$iii$0 (func (param i32 i32) (result i32)))
+ (type $1 (func))
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table 0 anyfunc))
+ (import "env" "globally" (global $i-collide i32))
+ (import "env" "foobar" (func $import$8 (param i32 i32) (result i32)))
+ (import "env" "memoryBase" (global $memoryBase$0 i32))
+ (import "env" "tableBase" (global $tableBase$0 i32))
+ (import "env" "globally" (global $i-collide$0 f64))
+
+ (data (get_global $memoryBase) "")
+ (export "_printf" (func $625))
+ (func $625 (type $FUNCSIG$iii) (param $var$0 i32) (param $var$1 i32) (result i32)
+ (i32.const 102030)
+ )
+ (func $b (type $1)
+ (drop
+ (call $625
+ (i32.const 11)
+ (i32.const 22)
+ )
+ )
+ )
+)
diff --git a/test/merge/printf.wast.combined.finalized b/test/merge/printf.wast.combined.finalized
new file mode 100644
index 000000000..c72f0d28f
--- /dev/null
+++ b/test/merge/printf.wast.combined.finalized
@@ -0,0 +1,28 @@
+(module
+ (type $FUNCSIG$iii (func (param i32 i32) (result i32)))
+ (type $FUNCSIG$iii$0 (func (param i32 i32) (result i32)))
+ (type $1 (func))
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table 8 anyfunc))
+ (import "env" "globally" (global $i-collide i32))
+ (import "env" "foobar" (func $import$8 (param i32 i32) (result i32)))
+ (import "env" "memoryBase" (global $memoryBase$0 i32))
+ (import "env" "tableBase" (global $tableBase$0 i32))
+ (import "env" "globally" (global $i-collide$0 f64))
+
+ (data (i32.const 1024) "")
+ (export "_printf" (func $625))
+ (func $625 (type $FUNCSIG$iii) (param $var$0 i32) (param $var$1 i32) (result i32)
+ (i32.const 102030)
+ )
+ (func $b (type $1)
+ (drop
+ (call $625
+ (i32.const 11)
+ (i32.const 22)
+ )
+ )
+ )
+)
diff --git a/test/merge/printf.wast.combined.finalized.opt b/test/merge/printf.wast.combined.finalized.opt
new file mode 100644
index 000000000..92e17f720
--- /dev/null
+++ b/test/merge/printf.wast.combined.finalized.opt
@@ -0,0 +1,12 @@
+(module
+ (type $FUNCSIG$iii (func (param i32 i32) (result i32)))
+ (type $FUNCSIG$iii$0 (func (param i32 i32) (result i32)))
+ (type $1 (func))
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table 8 anyfunc))
+
+ (export "_printf" (func $625))
+ (func $625 (type $FUNCSIG$iii) (param $var$0 i32) (param $var$1 i32) (result i32)
+ (i32.const 102030)
+ )
+)
diff --git a/test/merge/printf.wast.combined.finalized.opt.stdout b/test/merge/printf.wast.combined.finalized.opt.stdout
new file mode 100644
index 000000000..3816869a7
--- /dev/null
+++ b/test/merge/printf.wast.combined.finalized.opt.stdout
@@ -0,0 +1,3 @@
+merged total memory size: 0
+merged total table size: 0
+merged functions: 2
diff --git a/test/merge/printf.wast.combined.finalized.stdout b/test/merge/printf.wast.combined.finalized.stdout
new file mode 100644
index 000000000..3816869a7
--- /dev/null
+++ b/test/merge/printf.wast.combined.finalized.stdout
@@ -0,0 +1,3 @@
+merged total memory size: 0
+merged total table size: 0
+merged functions: 2
diff --git a/test/merge/printf.wast.combined.opt b/test/merge/printf.wast.combined.opt
new file mode 100644
index 000000000..e01710fd1
--- /dev/null
+++ b/test/merge/printf.wast.combined.opt
@@ -0,0 +1,15 @@
+(module
+ (type $FUNCSIG$iii (func (param i32 i32) (result i32)))
+ (type $FUNCSIG$iii$0 (func (param i32 i32) (result i32)))
+ (type $1 (func))
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table 0 anyfunc))
+
+ (data (get_global $memoryBase) "")
+ (export "_printf" (func $625))
+ (func $625 (type $FUNCSIG$iii) (param $var$0 i32) (param $var$1 i32) (result i32)
+ (i32.const 102030)
+ )
+)
diff --git a/test/merge/printf.wast.combined.opt.stdout b/test/merge/printf.wast.combined.opt.stdout
new file mode 100644
index 000000000..3816869a7
--- /dev/null
+++ b/test/merge/printf.wast.combined.opt.stdout
@@ -0,0 +1,3 @@
+merged total memory size: 0
+merged total table size: 0
+merged functions: 2
diff --git a/test/merge/printf.wast.combined.stdout b/test/merge/printf.wast.combined.stdout
new file mode 100644
index 000000000..3816869a7
--- /dev/null
+++ b/test/merge/printf.wast.combined.stdout
@@ -0,0 +1,3 @@
+merged total memory size: 0
+merged total table size: 0
+merged functions: 2
diff --git a/test/merge/printf.wast.toMerge b/test/merge/printf.wast.toMerge
new file mode 100644
index 000000000..d394abe34
--- /dev/null
+++ b/test/merge/printf.wast.toMerge
@@ -0,0 +1,14 @@
+(module
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table 0 anyfunc))
+ (import "env" "globally" (global $i-collide f64))
+ (import "env" "_printf" (func $import$8 (param i32 i32) (result i32)))
+ (func $b
+ (drop
+ (call $import$8 (i32.const 11) (i32.const 22))
+ )
+ )
+)
+