Merge pull request #695 from WebAssembly/opts

Get optimizer on par with emscripten asm.js optimizer
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 38b2df7..0d7b274 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -133,6 +133,7 @@
 
 SET(asm2wasm_SOURCES
   src/tools/asm2wasm.cpp
+  src/wasm-emscripten.cpp
   src/wasm.cpp
 )
 ADD_EXECUTABLE(asm2wasm
@@ -144,6 +145,7 @@
 
 SET(s2wasm_SOURCES
   src/tools/s2wasm.cpp
+  src/wasm-emscripten.cpp
   src/wasm-linker.cpp
   src/wasm.cpp
 )
diff --git a/check.py b/check.py
index 3da8946..28bdb43 100755
--- a/check.py
+++ b/check.py
@@ -521,6 +521,12 @@
   # bar should be linked from the archive
   fail_if_not_contained(output, '(func $bar')
 
+  # Test exporting memory growth function
+  cmd = [s2wasm, os.path.join('test', 'linker', 'main.s'), '--emscripten-glue', '--allow-memory-growth']
+  output = run_command(cmd)
+  fail_if_not_contained(output, '(export "__growWasmMemory" $__growWasmMemory)')
+  fail_if_not_contained(output, '(func $__growWasmMemory (param $newSize i32)')
+
   print '\n[ running validation tests... ]\n'
   wasm_as = os.path.join('bin', 'wasm-as')
   # Ensure the tests validate by default
diff --git a/src/asm2wasm.h b/src/asm2wasm.h
index 478a0dd..eb5413e 100644
--- a/src/asm2wasm.h
+++ b/src/asm2wasm.h
@@ -32,6 +32,7 @@
 #include "pass.h"
 #include "ast_utils.h"
 #include "wasm-builder.h"
+#include "wasm-emscripten.h"
 #include "wasm-validator.h"
 #include "wasm-module-building.h"
 
@@ -819,23 +820,7 @@
 
   // apply memory growth, if relevant
   if (memoryGrowth) {
-    // create and export a function that just calls memory growth
-    Builder builder(wasm);
-    wasm.addFunction(builder.makeFunction(
-      GROW_WASM_MEMORY,
-      { { NEW_SIZE, i32 } },
-      i32,
-      {},
-      builder.makeHost(
-        GrowMemory,
-        Name(),
-        { builder.makeGetLocal(0, i32) }
-      )
-    ));
-    auto export_ = new Export;
-    export_->name = export_->value = GROW_WASM_MEMORY;
-    export_->kind = Export::Function;
-    wasm.addExport(export_);
+    emscripten::generateMemoryGrowthFunction(wasm);
   }
 
 #if 0
diff --git a/src/tools/s2wasm.cpp b/src/tools/s2wasm.cpp
index 2ee094a..8c36a0d 100644
--- a/src/tools/s2wasm.cpp
+++ b/src/tools/s2wasm.cpp
@@ -22,6 +22,7 @@
 #include "support/command-line.h"
 #include "support/file.h"
 #include "s2wasm.h"
+#include "wasm-emscripten.h"
 #include "wasm-linker.h"
 #include "wasm-printing.h"
 #include "wasm-validator.h"
@@ -32,6 +33,7 @@
 int main(int argc, const char *argv[]) {
   bool ignoreUnknownSymbols = false;
   bool generateEmscriptenGlue = false;
+  bool allowMemoryGrowth = false;
   std::string startFunction;
   std::vector<std::string> archiveLibraries;
   Options options("s2wasm", "Link .s file into .wast");
@@ -73,6 +75,11 @@
            [](Options *o, const std::string &argument) {
              o->extra["max-memory"] = argument;
            })
+      .add("--allow-memory-growth", "", "Allow linear memory to grow at runtime",
+           Options::Arguments::Zero,
+           [&allowMemoryGrowth](Options *, const std::string &) {
+             allowMemoryGrowth = true;
+           })
       .add("--emscripten-glue", "-e", "Generate emscripten glue",
            Options::Arguments::Zero,
            [&generateEmscriptenGlue](Options *, const std::string &) {
@@ -98,6 +105,11 @@
                       });
   options.parse(argc, argv);
 
+  if (allowMemoryGrowth && !generateEmscriptenGlue) {
+    Fatal() << "Error: adding memory growth code without Emscripten glue. "
+      "This doesn't do anything.\n";
+  }
+
   auto debugFlag = options.debug ? Flags::Debug : Flags::Release;
   auto input(read_file<std::string>(options.extra["infile"], Flags::Text, debugFlag));
 
@@ -138,6 +150,10 @@
   std::stringstream meta;
   if (generateEmscriptenGlue) {
     if (options.debug) std::cerr << "Emscripten gluing..." << std::endl;
+    if (allowMemoryGrowth) {
+      emscripten::generateMemoryGrowthFunction(linker.getOutput().wasm);
+    }
+
     // dyncall thunks
     linker.emscriptenGlue(meta);
   }
diff --git a/src/wasm-emscripten.cpp b/src/wasm-emscripten.cpp
new file mode 100644
index 0000000..f1e544a
--- /dev/null
+++ b/src/wasm-emscripten.cpp
@@ -0,0 +1,216 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#include "wasm-emscripten.h"
+
+#include "asm_v_wasm.h"
+#include "asmjs/shared-constants.h"
+#include "shared-constants.h"
+#include "wasm-builder.h"
+#include "wasm-traversal.h"
+#include "wasm.h"
+
+namespace wasm {
+
+namespace emscripten {
+
+cashew::IString EMSCRIPTEN_ASM_CONST("emscripten_asm_const");
+
+void generateMemoryGrowthFunction(Module& wasm) {
+  Builder wasmBuilder(wasm);
+  Name name(GROW_WASM_MEMORY);
+  std::vector<NameType> params { { NEW_SIZE, i32 } };
+  Function* growFunction = wasmBuilder.makeFunction(
+    name, std::move(params), i32, {}
+  );
+  growFunction->body = wasmBuilder.makeHost(
+    GrowMemory,
+    Name(),
+    { wasmBuilder.makeGetLocal(0, i32) }
+  );
+
+  wasm.addFunction(growFunction);
+  auto export_ = new Export;
+  export_->name = export_->value = name;
+  export_->kind = Export::Function;
+  wasm.addExport(export_);
+}
+
+static bool hasI64ResultOrParam(FunctionType* ft) {
+  if (ft->result == i64) return true;
+  for (auto ty : ft->params) {
+    if (ty == i64) return true;
+  }
+  return false;
+}
+
+std::vector<Function*> makeDynCallThunks(Module& wasm, std::vector<Name> const& tableSegmentData) {
+  wasm.removeImport(EMSCRIPTEN_ASM_CONST); // we create _sig versions
+
+  std::vector<Function*> generatedFunctions;
+  std::unordered_set<std::string> sigs;
+  Builder wasmBuilder(wasm);
+  for (const auto& indirectFunc : tableSegmentData) {
+    std::string sig(getSig(wasm.getFunction(indirectFunc)));
+    auto* funcType = ensureFunctionType(sig, &wasm);
+    if (hasI64ResultOrParam(funcType)) continue; // Can't export i64s on the web.
+    if (!sigs.insert(sig).second) continue; // Sig is already in the set
+    std::vector<NameType> params;
+    params.emplace_back("fptr", i32); // function pointer param
+    int p = 0;
+    for (const auto& ty : funcType->params) params.emplace_back(std::to_string(p++), ty);
+    Function* f = wasmBuilder.makeFunction(std::string("dynCall_") + sig, std::move(params), funcType->result, {});
+    Expression* fptr = wasmBuilder.makeGetLocal(0, i32);
+    std::vector<Expression*> args;
+    for (unsigned i = 0; i < funcType->params.size(); ++i) {
+      args.push_back(wasmBuilder.makeGetLocal(i + 1, funcType->params[i]));
+    }
+    Expression* call = wasmBuilder.makeCallIndirect(funcType, fptr, args);
+    f->body = call;
+    wasm.addFunction(f);
+    generatedFunctions.push_back(f);
+  }
+  return generatedFunctions;
+}
+
+struct AsmConstWalker : public PostWalker<AsmConstWalker, Visitor<AsmConstWalker>> {
+  Module& wasm;
+  std::unordered_map<Address, Address> segmentsByAddress; // address => segment index
+
+  std::map<std::string, std::set<std::string>> sigsForCode;
+  std::map<std::string, Address> ids;
+  std::set<std::string> allSigs;
+
+  AsmConstWalker(Module& _wasm, std::unordered_map<Address, Address> _segmentsByAddress) :
+    wasm(_wasm), segmentsByAddress(_segmentsByAddress) { }
+
+  void visitCallImport(CallImport* curr);
+
+  std::string escape(const char *input);
+};
+
+void AsmConstWalker::visitCallImport(CallImport* curr) {
+  if (curr->target == EMSCRIPTEN_ASM_CONST) {
+    auto arg = curr->operands[0]->cast<Const>();
+    auto address = arg->value.geti32();
+    auto segmentIterator = segmentsByAddress.find(address);
+    std::string code;
+    if (segmentIterator != segmentsByAddress.end()) {
+      Address segmentIndex = segmentsByAddress[address];
+      code = escape(&wasm.memory.segments[segmentIndex].data[0]);
+    } else {
+      // If we can't find the segment corresponding with the address, then we omitted the segment and the address points to an empty string.
+      code = escape("");
+    }
+    int32_t id;
+    if (ids.count(code) == 0) {
+      id = ids.size();
+      ids[code] = id;
+    } else {
+      id = ids[code];
+    }
+    std::string sig = getSig(curr);
+    sigsForCode[code].insert(sig);
+    std::string fixedTarget = EMSCRIPTEN_ASM_CONST.str + std::string("_") + sig;
+    curr->target = cashew::IString(fixedTarget.c_str(), false);
+    arg->value = Literal(id);
+    // add import, if necessary
+    if (allSigs.count(sig) == 0) {
+      allSigs.insert(sig);
+      auto import = new Import;
+      import->name = import->base = curr->target;
+      import->module = ENV;
+      import->functionType = ensureFunctionType(getSig(curr), &wasm);
+      import->kind = Import::Function;
+      wasm.addImport(import);
+    }
+  }
+}
+
+std::string AsmConstWalker::escape(const char *input) {
+  std::string code = input;
+  // replace newlines quotes with escaped newlines
+  size_t curr = 0;
+  while ((curr = code.find("\\n", curr)) != std::string::npos) {
+    code = code.replace(curr, 2, "\\\\n");
+    curr += 3; // skip this one
+  }
+  // replace double quotes with escaped single quotes
+  curr = 0;
+  while ((curr = code.find('"', curr)) != std::string::npos) {
+    if (curr == 0 || code[curr-1] != '\\') {
+      code = code.replace(curr, 1, "\\" "\"");
+      curr += 2; // skip this one
+    } else { // already escaped, escape the slash as well
+      code = code.replace(curr, 1, "\\" "\\" "\"");
+      curr += 3; // skip this one
+    }
+  }
+  return code;
+}
+
+template<class C>
+void printSet(std::ostream& o, C& c) {
+  o << "[";
+  bool first = true;
+  for (auto& item : c) {
+    if (first) first = false;
+    else o << ",";
+    o << '"' << item << '"';
+  }
+  o << "]";
+}
+
+void generateEmscriptenMetadata(std::ostream& o,
+                                Module& wasm,
+                                std::unordered_map<Address, Address> segmentsByAddress,
+                                Address staticBump,
+                                std::vector<Name> const& initializerFunctions) {
+  o << ";; METADATA: { ";
+  // find asmConst calls, and emit their metadata
+  AsmConstWalker walker(wasm, segmentsByAddress);
+  walker.walkModule(&wasm);
+  // print
+  o << "\"asmConsts\": {";
+  bool first = true;
+  for (auto& pair : walker.sigsForCode) {
+    auto& code = pair.first;
+    auto& sigs = pair.second;
+    if (first) first = false;
+    else o << ",";
+    o << '"' << walker.ids[code] << "\": [\"" << code << "\", ";
+    printSet(o, sigs);
+    o << "]";
+  }
+  o << "}";
+  o << ",";
+  o << "\"staticBump\": " << staticBump << ", ";
+
+  o << "\"initializers\": [";
+  first = true;
+  for (const auto& func : initializerFunctions) {
+    if (first) first = false;
+    else o << ", ";
+    o << "\"" << func.c_str() << "\"";
+  }
+  o << "]";
+
+  o << " }\n";
+}
+
+} // namespace emscripten
+
+} // namespace wasm
diff --git a/src/wasm-emscripten.h b/src/wasm-emscripten.h
new file mode 100644
index 0000000..07c4708
--- /dev/null
+++ b/src/wasm-emscripten.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#ifndef wasm_emscripten_h
+#define wasm_emscripten_h
+
+#include "wasm.h"
+
+namespace wasm {
+
+namespace emscripten {
+
+void generateMemoryGrowthFunction(Module&);
+
+// Create thunks for use with emscripten Runtime.dynCall. Creates one for each
+// signature in the indirect function table.
+std::vector<Function*> makeDynCallThunks(Module& wasm, std::vector<Name> const& tableSegmentData);
+
+void generateEmscriptenMetadata(std::ostream& o,
+                                Module& wasm,
+                                std::unordered_map<Address, Address> segmentsByAddress,
+                                Address staticBump,
+                                std::vector<Name> const& initializerFunctions);
+
+} // namespace emscripten
+
+} // namespace wasm
+
+#endif // wasm_emscripten_h
diff --git a/src/wasm-linker.cpp b/src/wasm-linker.cpp
index 04deddf..527ff80 100644
--- a/src/wasm-linker.cpp
+++ b/src/wasm-linker.cpp
@@ -20,11 +20,13 @@
 #include "s2wasm.h"
 #include "support/utilities.h"
 #include "wasm-builder.h"
+#include "wasm-emscripten.h"
 #include "wasm-printing.h"
 
 using namespace wasm;
 
-cashew::IString EMSCRIPTEN_ASM_CONST("emscripten_asm_const");
+// Name of the dummy function to prevent erroneous nullptr comparisons.
+static constexpr const char* dummyFunction = "__wasm_nullptr";
 
 void Linker::placeStackPointer(Address stackAllocation) {
   // ensure this is the first allocation
@@ -138,7 +140,8 @@
 
   // Emit the pre-assigned function names in sorted order
   for (const auto& P : functionNames) {
-    getTableSegment().data.push_back(P.second);
+    ensureTableIsPopulated();
+    getTableDataRef().push_back(P.second);
   }
 
   for (auto& relocation : out.relocations) {
@@ -236,8 +239,9 @@
   }
 
   // finalize function table
-  if (out.wasm.table.segments.size() > 0) {
-    out.wasm.table.initial = out.wasm.table.max = getTableSegment().data.size();
+  unsigned int tableSize = getTableData().size();
+  if (tableSize > 0) {
+    out.wasm.table.initial = out.wasm.table.max = tableSize;
   }
 }
 
@@ -303,115 +307,40 @@
     WasmPrinter::printModule(&out.wasm, std::cerr);
   }
 
-  out.wasm.removeImport(EMSCRIPTEN_ASM_CONST); // we create _sig versions
-
-  makeDynCallThunks();
-
-  o << ";; METADATA: { ";
-  // find asmConst calls, and emit their metadata
-  struct AsmConstWalker : public PostWalker<AsmConstWalker, Visitor<AsmConstWalker>> {
-    Linker* parent;
-
-    std::map<std::string, std::set<std::string>> sigsForCode;
-    std::map<std::string, Address> ids;
-    std::set<std::string> allSigs;
-
-    void visitCallImport(CallImport* curr) {
-      if (curr->target == EMSCRIPTEN_ASM_CONST) {
-        auto arg = curr->operands[0]->cast<Const>();
-        Address segmentIndex = parent->segmentsByAddress[arg->value.geti32()];
-        std::string code = escape(&parent->out.wasm.memory.segments[segmentIndex].data[0]);
-        int32_t id;
-        if (ids.count(code) == 0) {
-          id = ids.size();
-          ids[code] = id;
-        } else {
-          id = ids[code];
-        }
-        std::string sig = getSig(curr);
-        sigsForCode[code].insert(sig);
-        std::string fixedTarget = EMSCRIPTEN_ASM_CONST.str + std::string("_") + sig;
-        curr->target = cashew::IString(fixedTarget.c_str(), false);
-        arg->value = Literal(id);
-        // add import, if necessary
-        if (allSigs.count(sig) == 0) {
-          allSigs.insert(sig);
-          auto import = new Import;
-          import->name = import->base = curr->target;
-          import->module = ENV;
-          import->functionType = ensureFunctionType(getSig(curr), &parent->out.wasm);
-          import->kind = Import::Function;
-          parent->out.wasm.addImport(import);
-        }
-      }
-    }
-
-    std::string escape(const char *input) {
-      std::string code = input;
-      // replace newlines quotes with escaped newlines
-      size_t curr = 0;
-      while ((curr = code.find("\\n", curr)) != std::string::npos) {
-        code = code.replace(curr, 2, "\\\\n");
-        curr += 3; // skip this one
-      }
-      // replace double quotes with escaped single quotes
-      curr = 0;
-      while ((curr = code.find('"', curr)) != std::string::npos) {
-        if (curr == 0 || code[curr-1] != '\\') {
-          code = code.replace(curr, 1, "\\" "\"");
-          curr += 2; // skip this one
-        } else { // already escaped, escape the slash as well
-          code = code.replace(curr, 1, "\\" "\\" "\"");
-          curr += 3; // skip this one
-        }
-      }
-      return code;
-    }
-  };
-  AsmConstWalker walker;
-  walker.parent = this;
-  walker.walkModule(&out.wasm);
-  // print
-  o << "\"asmConsts\": {";
-  bool first = true;
-  for (auto& pair : walker.sigsForCode) {
-    auto& code = pair.first;
-    auto& sigs = pair.second;
-    if (first) first = false;
-    else o << ",";
-    o << '"' << walker.ids[code] << "\": [\"" << code << "\", ";
-    printSet(o, sigs);
-    o << "]";
+  auto functionsToThunk = getTableData();
+  std::remove(functionsToThunk.begin(), functionsToThunk.end(), dummyFunction);
+  for (auto f : emscripten::makeDynCallThunks(out.wasm, functionsToThunk)) {
+    exportFunction(f->name, true);
   }
-  o << "}";
-  o << ",";
-  o << "\"staticBump\": " << (nextStatic - globalBase) << ", ";
 
-  o << "\"initializers\": [";
-  first = true;
-  for (const auto& func : out.initializerFunctions) {
-    if (first) first = false;
-    else o << ", ";
-    o << "\"" << func.c_str() << "\"";
-  }
-  o << "]";
-
-  o << " }\n";
+  auto staticBump = nextStatic - globalBase;
+  emscripten::generateEmscriptenMetadata(o, out.wasm, segmentsByAddress, staticBump, out.initializerFunctions);
 }
 
-Table::Segment& Linker::getTableSegment() {
+void Linker::ensureTableIsPopulated() {
   if (out.wasm.table.segments.size() == 0) {
-    out.wasm.table.segments.emplace_back(out.wasm.allocator.alloc<Const>()->set(Literal(uint32_t(0))));
-  } else {
-    assert(out.wasm.table.segments.size() == 1);
+    auto emptySegment = out.wasm.allocator.alloc<Const>()->set(Literal(uint32_t(0)));
+    out.wasm.table.segments.emplace_back(emptySegment);
   }
-  return out.wasm.table.segments[0];
+}
+
+std::vector<Name>& Linker::getTableDataRef() {
+  assert(out.wasm.table.segments.size() == 1);
+  return out.wasm.table.segments[0].data;
+}
+
+std::vector<Name> Linker::getTableData() {
+  if (out.wasm.table.segments.size() > 0) {
+    return getTableDataRef();
+  }
+  return {};
 }
 
 Index Linker::getFunctionIndex(Name name) {
   if (!functionIndexes.count(name)) {
-    functionIndexes[name] = getTableSegment().data.size();
-    getTableSegment().data.push_back(name);
+    ensureTableIsPopulated();
+    functionIndexes[name] = getTableData().size();
+    getTableDataRef().push_back(name);
     if (debug) {
       std::cerr << "function index: " << name << ": "
                 << functionIndexes[name] << '\n';
@@ -420,14 +349,6 @@
   return functionIndexes[name];
 }
 
-bool hasI64ResultOrParam(FunctionType* ft) {
-  if (ft->result == i64) return true;
-  for (auto ty : ft->params) {
-    if (ty == i64) return true;
-  }
-  return false;
-}
-
 void Linker::makeDummyFunction() {
   bool create = false;
   // Check if there are address-taken functions
@@ -445,34 +366,6 @@
   getFunctionIndex(dummy->name);
 }
 
-void Linker::makeDynCallThunks() {
-  if (out.wasm.table.segments.size() == 0) return;
-  std::unordered_set<std::string> sigs;
-  wasm::Builder wasmBuilder(out.wasm);
-  for (const auto& indirectFunc : getTableSegment().data) {
-    // Skip generating thunks for the dummy function
-    if (indirectFunc == dummyFunction) continue;
-    std::string sig(getSig(out.wasm.getFunction(indirectFunc)));
-    auto* funcType = ensureFunctionType(sig, &out.wasm);
-    if (hasI64ResultOrParam(funcType)) continue; // Can't export i64s on the web.
-    if (!sigs.insert(sig).second) continue; // Sig is already in the set
-    std::vector<NameType> params;
-    params.emplace_back("fptr", i32); // function pointer param
-    int p = 0;
-    for (const auto& ty : funcType->params) params.emplace_back(std::to_string(p++), ty);
-    Function* f = wasmBuilder.makeFunction(std::string("dynCall_") + sig, std::move(params), funcType->result, {});
-    Expression* fptr = wasmBuilder.makeGetLocal(0, i32);
-    std::vector<Expression*> args;
-    for (unsigned i = 0; i < funcType->params.size(); ++i) {
-      args.push_back(wasmBuilder.makeGetLocal(i + 1, funcType->params[i]));
-    }
-    Expression* call = wasmBuilder.makeCallIndirect(funcType, fptr, args);
-    f->body = call;
-    out.wasm.addFunction(f);
-    exportFunction(f->name, true);
-  }
-}
-
 Function* Linker::getImportThunk(Name name, const FunctionType* funcType) {
   Name thunkName = std::string("__importThunk_") + name.c_str();
   if (Function* thunk = out.wasm.checkFunction(thunkName)) return thunk;
diff --git a/src/wasm-linker.h b/src/wasm-linker.h
index 21d3362..015e3a0 100644
--- a/src/wasm-linker.h
+++ b/src/wasm-linker.h
@@ -252,9 +252,6 @@
   // Returns false if an error occurred.
   bool linkArchive(Archive& archive);
 
-  // Name of the dummy function to prevent erroneous nullptr comparisons.
-  static constexpr const char* dummyFunction = "__wasm_nullptr";
-
  private:
   // Allocate a static variable and return its address in linear memory
   Address allocateStatic(Address allocSize, Address alignment, Name name) {
@@ -268,23 +265,14 @@
   // relocation for it to point to the top of the stack.
   void placeStackPointer(Address stackAllocation);
 
-  template<class C>
-  void printSet(std::ostream& o, C& c) {
-    o << "[";
-    bool first = true;
-    for (auto& item : c) {
-      if (first) first = false;
-      else o << ",";
-      o << '"' << item << '"';
-    }
-    o << "]";
-  }
-
   void ensureImport(Name target, std::string signature);
 
   // Makes sure the table has a single segment, with offset 0,
   // to which we can add content.
-  Table::Segment& getTableSegment();
+  void ensureTableIsPopulated();
+
+  std::vector<Name>& getTableDataRef();
+  std::vector<Name> getTableData();
 
   // Retrieves (and assigns) an entry index in the indirect function table for
   // a given function.
@@ -294,10 +282,6 @@
   // pointer miscomparisons.
   void makeDummyFunction();
 
-  // Create thunks for use with emscripten Runtime.dynCall. Creates one for each
-  // signature in the indirect function table.
-  void makeDynCallThunks();
-
   static Address roundUpToPageSize(Address size) {
     return (size + Memory::kPageSize - 1) & Memory::kPageMask;
   }