Merge V8 5.3.332.45.  DO NOT MERGE

Test: Manual

FPIIM-449

Change-Id: Id3254828b068abdea3cb10442e0172a8c9a98e03
(cherry picked from commit 13e2dadd00298019ed862f2b2fc5068bba730bcf)
diff --git a/src/wasm/wasm-module.cc b/src/wasm/wasm-module.cc
index c9a4279..ca0a9b9 100644
--- a/src/wasm/wasm-module.cc
+++ b/src/wasm/wasm-module.cc
@@ -12,6 +12,7 @@
 
 #include "src/wasm/ast-decoder.h"
 #include "src/wasm/module-decoder.h"
+#include "src/wasm/wasm-debug.h"
 #include "src/wasm/wasm-function-name-table.h"
 #include "src/wasm/wasm-module.h"
 #include "src/wasm/wasm-result.h"
@@ -22,6 +23,8 @@
 namespace internal {
 namespace wasm {
 
+static const int kPlaceholderMarker = 1000000000;
+
 static const char* wasmSections[] = {
 #define F(enumerator, order, string) string,
     FOR_EACH_WASM_SECTION_TYPE(F)
@@ -109,113 +112,24 @@
   return os;
 }
 
-// A helper class for compiling multiple wasm functions that offers
-// placeholder code objects for calling functions that are not yet compiled.
-class WasmLinker {
- public:
-  WasmLinker(Isolate* isolate, size_t size)
-      : isolate_(isolate), placeholder_code_(size), function_code_(size) {}
-
-  // Get the code object for a function, allocating a placeholder if it has
-  // not yet been compiled.
-  Handle<Code> GetFunctionCode(uint32_t index) {
-    DCHECK(index < function_code_.size());
-    if (function_code_[index].is_null()) {
-      // Create a placeholder code object and encode the corresponding index in
-      // the {constant_pool_offset} field of the code object.
-      // TODO(titzer): placeholder code objects are somewhat dangerous.
-      byte buffer[] = {0, 0, 0, 0, 0, 0, 0, 0};  // fake instructions.
-      CodeDesc desc = {buffer, 8, 8, 0, 0, nullptr};
-      Handle<Code> code = isolate_->factory()->NewCode(
-          desc, Code::KindField::encode(Code::WASM_FUNCTION),
-          Handle<Object>::null());
-      code->set_constant_pool_offset(index + kPlaceholderMarker);
-      placeholder_code_[index] = code;
-      function_code_[index] = code;
-    }
-    return function_code_[index];
-  }
-
-  void Finish(uint32_t index, Handle<Code> code) {
-    DCHECK(index < function_code_.size());
-    function_code_[index] = code;
-  }
-
-  void Link(Handle<FixedArray> function_table,
-            std::vector<uint16_t>& functions) {
-    for (size_t i = 0; i < function_code_.size(); i++) {
-      LinkFunction(function_code_[i]);
-    }
-    if (!function_table.is_null()) {
-      int table_size = static_cast<int>(functions.size());
-      DCHECK_EQ(function_table->length(), table_size * 2);
-      for (int i = 0; i < table_size; i++) {
-        function_table->set(i + table_size, *function_code_[functions[i]]);
-      }
-    }
-  }
-
- private:
-  static const int kPlaceholderMarker = 1000000000;
-
-  Isolate* isolate_;
-  std::vector<Handle<Code>> placeholder_code_;
-  std::vector<Handle<Code>> function_code_;
-
-  void LinkFunction(Handle<Code> code) {
-    bool modified = false;
-    int mode_mask = RelocInfo::kCodeTargetMask;
-    AllowDeferredHandleDereference embedding_raw_address;
-    for (RelocIterator it(*code, mode_mask); !it.done(); it.next()) {
-      RelocInfo::Mode mode = it.rinfo()->rmode();
-      if (RelocInfo::IsCodeTarget(mode)) {
-        Code* target =
-            Code::GetCodeFromTargetAddress(it.rinfo()->target_address());
-        if (target->kind() == Code::WASM_FUNCTION &&
-            target->constant_pool_offset() >= kPlaceholderMarker) {
-          // Patch direct calls to placeholder code objects.
-          uint32_t index = target->constant_pool_offset() - kPlaceholderMarker;
-          CHECK(index < function_code_.size());
-          Handle<Code> new_target = function_code_[index];
-          if (target != *new_target) {
-            CHECK_EQ(*placeholder_code_[index], target);
-            it.rinfo()->set_target_address(new_target->instruction_start(),
-                                           SKIP_WRITE_BARRIER,
-                                           SKIP_ICACHE_FLUSH);
-            modified = true;
-          }
-        }
-      }
-    }
-    if (modified) {
-      Assembler::FlushICache(isolate_, code->instruction_start(),
-                             code->instruction_size());
-    }
-  }
-};
-
 namespace {
 // Internal constants for the layout of the module object.
-const int kWasmModuleInternalFieldCount = 5;
 const int kWasmModuleFunctionTable = 0;
 const int kWasmModuleCodeTable = 1;
 const int kWasmMemArrayBuffer = 2;
 const int kWasmGlobalsArrayBuffer = 3;
+// TODO(clemensh): Remove function name array, extract names from module bytes.
 const int kWasmFunctionNamesArray = 4;
+const int kWasmModuleBytesString = 5;
+const int kWasmDebugInfo = 6;
+const int kWasmModuleInternalFieldCount = 7;
 
-size_t AllocateGlobalsOffsets(std::vector<WasmGlobal>& globals) {
-  uint32_t offset = 0;
-  if (globals.size() == 0) return 0;
-  for (WasmGlobal& global : globals) {
-    byte size = WasmOpcodes::MemSize(global.type);
-    offset = (offset + size - 1) & ~(size - 1);  // align
-    global.offset = offset;
-    offset += size;
-  }
-  return offset;
+uint32_t GetMinModuleMemSize(const WasmModule* module) {
+  return WasmModule::kPageSize * module->min_mem_pages;
 }
 
-void LoadDataSegments(WasmModule* module, byte* mem_addr, size_t mem_size) {
+void LoadDataSegments(const WasmModule* module, byte* mem_addr,
+                      size_t mem_size) {
   for (const WasmDataSegment& segment : module->data_segments) {
     if (!segment.init) continue;
     if (!segment.source_size) continue;
@@ -228,14 +142,20 @@
   }
 }
 
-Handle<FixedArray> BuildFunctionTable(Isolate* isolate, WasmModule* module) {
-  if (module->function_table.size() == 0) {
+Handle<FixedArray> BuildFunctionTable(Isolate* isolate,
+                                      const WasmModule* module) {
+  // Compute the size of the indirect function table
+  uint32_t table_size = module->FunctionTableSize();
+  if (table_size == 0) {
     return Handle<FixedArray>::null();
   }
-  int table_size = static_cast<int>(module->function_table.size());
+
   Handle<FixedArray> fixed = isolate->factory()->NewFixedArray(2 * table_size);
-  for (int i = 0; i < table_size; i++) {
-    WasmFunction* function = &module->functions[module->function_table[i]];
+  for (uint32_t i = 0;
+       i < static_cast<uint32_t>(module->function_table.size());
+       ++i) {
+    const WasmFunction* function =
+        &module->functions[module->function_table[i]];
     fixed->set(i, Smi::FromInt(function->sig_index));
   }
   return fixed;
@@ -243,15 +163,13 @@
 
 Handle<JSArrayBuffer> NewArrayBuffer(Isolate* isolate, size_t size,
                                      byte** backing_store) {
+  *backing_store = nullptr;
   if (size > (WasmModule::kMaxMemPages * WasmModule::kPageSize)) {
     // TODO(titzer): lift restriction on maximum memory allocated here.
-    *backing_store = nullptr;
     return Handle<JSArrayBuffer>::null();
   }
-  void* memory =
-      isolate->array_buffer_allocator()->Allocate(static_cast<int>(size));
-  if (!memory) {
-    *backing_store = nullptr;
+  void* memory = isolate->array_buffer_allocator()->Allocate(size);
+  if (memory == nullptr) {
     return Handle<JSArrayBuffer>::null();
   }
 
@@ -260,7 +178,7 @@
 #if DEBUG
   // Double check the API allocator actually zero-initialized the memory.
   byte* bytes = reinterpret_cast<byte*>(*backing_store);
-  for (size_t i = 0; i < size; i++) {
+  for (size_t i = 0; i < size; ++i) {
     DCHECK_EQ(0, bytes[i]);
   }
 #endif
@@ -271,12 +189,27 @@
   return buffer;
 }
 
+void RelocateInstanceCode(WasmModuleInstance* instance) {
+  for (uint32_t i = 0; i < instance->function_code.size(); ++i) {
+    Handle<Code> function = instance->function_code[i];
+    AllowDeferredHandleDereference embedding_raw_address;
+    int mask = (1 << RelocInfo::WASM_MEMORY_REFERENCE) |
+               (1 << RelocInfo::WASM_MEMORY_SIZE_REFERENCE);
+    for (RelocIterator it(*function, mask); !it.done(); it.next()) {
+      it.rinfo()->update_wasm_memory_reference(
+          nullptr, instance->mem_start, GetMinModuleMemSize(instance->module),
+          static_cast<uint32_t>(instance->mem_size));
+    }
+  }
+}
+
 // Set the memory for a module instance to be the {memory} array buffer.
 void SetMemory(WasmModuleInstance* instance, Handle<JSArrayBuffer> memory) {
   memory->set_is_neuterable(false);
   instance->mem_start = reinterpret_cast<byte*>(memory->backing_store());
   instance->mem_size = memory->byte_length()->Number();
   instance->mem_buffer = memory;
+  RelocateInstanceCode(instance);
 }
 
 // Allocate memory for a module instance as a new JSArrayBuffer.
@@ -289,50 +222,140 @@
     thrower->Error("Out of memory: wasm memory too large");
     return false;
   }
-  instance->mem_size = WasmModule::kPageSize * instance->module->min_mem_pages;
+  instance->mem_size = GetMinModuleMemSize(instance->module);
   instance->mem_buffer =
       NewArrayBuffer(isolate, instance->mem_size, &instance->mem_start);
-  if (!instance->mem_start) {
+  if (instance->mem_start == nullptr) {
     thrower->Error("Out of memory: wasm memory");
     instance->mem_size = 0;
     return false;
   }
+  RelocateInstanceCode(instance);
   return true;
 }
 
 bool AllocateGlobals(ErrorThrower* thrower, Isolate* isolate,
                      WasmModuleInstance* instance) {
-  instance->globals_size = AllocateGlobalsOffsets(instance->module->globals);
-
-  if (instance->globals_size > 0) {
-    instance->globals_buffer = NewArrayBuffer(isolate, instance->globals_size,
-                                              &instance->globals_start);
+  uint32_t globals_size = instance->module->globals_size;
+  if (globals_size > 0) {
+    instance->globals_buffer =
+        NewArrayBuffer(isolate, globals_size, &instance->globals_start);
     if (!instance->globals_start) {
       // Not enough space for backing store of globals.
       thrower->Error("Out of memory: wasm globals");
       return false;
     }
+
+    for (uint32_t i = 0; i < instance->function_code.size(); ++i) {
+      Handle<Code> function = instance->function_code[i];
+      AllowDeferredHandleDereference embedding_raw_address;
+      int mask = 1 << RelocInfo::WASM_GLOBAL_REFERENCE;
+      for (RelocIterator it(*function, mask); !it.done(); it.next()) {
+        it.rinfo()->update_wasm_global_reference(nullptr,
+                                                 instance->globals_start);
+      }
+    }
   }
   return true;
 }
+
+Handle<Code> CreatePlaceholder(Factory* factory, uint32_t index,
+                               Code::Kind kind) {
+  // Create a placeholder code object and encode the corresponding index in
+  // the {constant_pool_offset} field of the code object.
+  // TODO(titzer): placeholder code objects are somewhat dangerous.
+  static byte buffer[] = {0, 0, 0, 0, 0, 0, 0, 0};  // fake instructions.
+  static CodeDesc desc = {buffer, 8, 8, 0, 0, nullptr, 0, nullptr};
+  Handle<Code> code = factory->NewCode(desc, Code::KindField::encode(kind),
+                                       Handle<Object>::null());
+  code->set_constant_pool_offset(static_cast<int>(index) + kPlaceholderMarker);
+  return code;
+}
+
+// TODO(mtrofin): remove when we stop relying on placeholders.
+void InitializePlaceholders(Factory* factory,
+                            std::vector<Handle<Code>>* placeholders,
+                            size_t size) {
+  DCHECK(placeholders->empty());
+  placeholders->reserve(size);
+
+  for (uint32_t i = 0; i < size; ++i) {
+    placeholders->push_back(CreatePlaceholder(factory, i, Code::WASM_FUNCTION));
+  }
+}
+
+bool LinkFunction(Handle<Code> unlinked,
+                  const std::vector<Handle<Code>>& code_targets,
+                  Code::Kind kind) {
+  bool modified = false;
+  int mode_mask = RelocInfo::kCodeTargetMask;
+  AllowDeferredHandleDereference embedding_raw_address;
+  for (RelocIterator it(*unlinked, mode_mask); !it.done(); it.next()) {
+    RelocInfo::Mode mode = it.rinfo()->rmode();
+    if (RelocInfo::IsCodeTarget(mode)) {
+      Code* target =
+          Code::GetCodeFromTargetAddress(it.rinfo()->target_address());
+      if (target->kind() == kind &&
+          target->constant_pool_offset() >= kPlaceholderMarker) {
+        // Patch direct calls to placeholder code objects.
+        uint32_t index = target->constant_pool_offset() - kPlaceholderMarker;
+        CHECK(index < code_targets.size());
+        Handle<Code> new_target = code_targets[index];
+        if (target != *new_target) {
+          it.rinfo()->set_target_address(new_target->instruction_start(),
+                                         SKIP_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
+          modified = true;
+        }
+      }
+    }
+  }
+  return modified;
+}
+
+void LinkModuleFunctions(Isolate* isolate,
+                         std::vector<Handle<Code>>& functions) {
+  for (size_t i = 0; i < functions.size(); ++i) {
+    Handle<Code> code = functions[i];
+    bool modified = LinkFunction(code, functions, Code::WASM_FUNCTION);
+    if (modified) {
+      Assembler::FlushICache(isolate, code->instruction_start(),
+                             code->instruction_size());
+    }
+  }
+}
+
+void LinkImports(Isolate* isolate, std::vector<Handle<Code>>& functions,
+                 const std::vector<Handle<Code>>& imports) {
+  for (uint32_t i = 0; i < functions.size(); ++i) {
+    Handle<Code> code = functions[i];
+    bool modified = LinkFunction(code, imports, Code::WASM_TO_JS_FUNCTION);
+    if (modified) {
+      Assembler::FlushICache(isolate, code->instruction_start(),
+                             code->instruction_size());
+    }
+  }
+}
+
 }  // namespace
 
 WasmModule::WasmModule()
-    : shared_isolate(nullptr),
-      module_start(nullptr),
+    : module_start(nullptr),
       module_end(nullptr),
       min_mem_pages(0),
       max_mem_pages(0),
       mem_export(false),
       mem_external(false),
       start_function_index(-1),
-      origin(kWasmOrigin) {}
+      origin(kWasmOrigin),
+      globals_size(0),
+      indirect_table_size(0),
+      pending_tasks(new base::Semaphore(0)) {}
 
 static MaybeHandle<JSFunction> ReportFFIError(ErrorThrower& thrower,
                                               const char* error, uint32_t index,
                                               wasm::WasmName module_name,
                                               wasm::WasmName function_name) {
-  if (function_name.start()) {
+  if (!function_name.is_empty()) {
     thrower.Error("Import #%d module=\"%.*s\" function=\"%.*s\" error: %s",
                   index, module_name.length(), module_name.start(),
                   function_name.length(), function_name.start(), error);
@@ -368,7 +391,7 @@
   }
 
   Handle<Object> function;
-  if (function_name.start()) {
+  if (!function_name.is_empty()) {
     // Look up the function in the module.
     Handle<String> name = factory->InternalizeUtf8String(function_name);
     MaybeHandle<Object> result = Object::GetProperty(module, name);
@@ -411,7 +434,7 @@
 
   compiler::WasmCompilationUnit* unit = compilation_units->at(index);
   if (unit != nullptr) {
-    compiler::ExecuteCompilation(unit);
+    unit->ExecuteCompilation();
     {
       base::LockGuard<base::Mutex> guard(result_mutex);
       executed_units->push(unit);
@@ -452,22 +475,31 @@
   base::AtomicNumber<size_t>* next_unit_;
 };
 
-void record_code_size(uint32_t& total_code_size, Code* code) {
-  if (FLAG_print_wasm_code_size) {
-    total_code_size += code->body_size() + code->relocation_info()->length();
-  }
-}
+// Records statistics on the code generated by compiling WASM functions.
+struct CodeStats {
+  size_t code_size;
+  size_t reloc_size;
 
-bool CompileWrappersToImportedFunctions(Isolate* isolate, WasmModule* module,
-                                        const Handle<JSReceiver> ffi,
-                                        WasmModuleInstance* instance,
-                                        ErrorThrower* thrower, Factory* factory,
-                                        ModuleEnv* module_env,
-                                        uint32_t& total_code_size) {
-  uint32_t index = 0;
+  inline CodeStats() : code_size(0), reloc_size(0) {}
+
+  inline void Record(Code* code) {
+    code_size += code->body_size();
+    reloc_size += code->relocation_info()->length();
+  }
+
+  inline void Report() {
+    PrintF("Total generated wasm code: %zu bytes\n", code_size);
+    PrintF("Total generated wasm reloc: %zu bytes\n", reloc_size);
+  }
+};
+
+bool CompileWrappersToImportedFunctions(
+    Isolate* isolate, const WasmModule* module, const Handle<JSReceiver> ffi,
+    WasmModuleInstance* instance, ErrorThrower* thrower, Factory* factory) {
   if (module->import_table.size() > 0) {
     instance->import_code.reserve(module->import_table.size());
-    for (const WasmImport& import : module->import_table) {
+    for (uint32_t index = 0; index < module->import_table.size(); ++index) {
+      const WasmImport& import = module->import_table[index];
       WasmName module_name = module->GetNameOrNull(import.module_name_offset,
                                                    import.module_name_length);
       WasmName function_name = module->GetNameOrNull(
@@ -477,28 +509,20 @@
       if (function.is_null()) return false;
 
       Handle<Code> code = compiler::CompileWasmToJSWrapper(
-          isolate, module_env, function.ToHandleChecked(), import.sig,
-          module_name, function_name);
-      instance->import_code.push_back(code);
-      record_code_size(total_code_size, *code);
-      index++;
+          isolate, function.ToHandleChecked(), import.sig, module_name,
+          function_name);
+      instance->import_code[index] = code;
     }
   }
   return true;
 }
 
 void InitializeParallelCompilation(
-    Isolate* isolate, std::vector<WasmFunction>& functions,
+    Isolate* isolate, const std::vector<WasmFunction>& functions,
     std::vector<compiler::WasmCompilationUnit*>& compilation_units,
     ModuleEnv& module_env, ErrorThrower& thrower) {
-  // Create a placeholder code object for all functions.
-  // TODO(ahaas): Maybe we could skip this for external functions.
-  for (uint32_t i = 0; i < functions.size(); i++) {
-    module_env.linker->GetFunctionCode(i);
-  }
-
-  for (uint32_t i = FLAG_skip_compiling_wasm_funcs; i < functions.size(); i++) {
-    compilation_units[i] = compiler::CreateWasmCompilationUnit(
+  for (uint32_t i = FLAG_skip_compiling_wasm_funcs; i < functions.size(); ++i) {
+    compilation_units[i] = new compiler::WasmCompilationUnit(
         &thrower, isolate, &module_env, &functions[i], i);
   }
 }
@@ -507,16 +531,16 @@
     Isolate* isolate,
     std::vector<compiler::WasmCompilationUnit*>& compilation_units,
     std::queue<compiler::WasmCompilationUnit*>& executed_units,
-    const base::SmartPointer<base::Semaphore>& pending_tasks,
-    base::Mutex& result_mutex, base::AtomicNumber<size_t>& next_unit) {
+    base::Semaphore* pending_tasks, base::Mutex& result_mutex,
+    base::AtomicNumber<size_t>& next_unit) {
   const size_t num_tasks =
       Min(static_cast<size_t>(FLAG_wasm_num_compilation_tasks),
           V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads());
   uint32_t* task_ids = new uint32_t[num_tasks];
-  for (size_t i = 0; i < num_tasks; i++) {
+  for (size_t i = 0; i < num_tasks; ++i) {
     WasmCompilationTask* task =
         new WasmCompilationTask(isolate, &compilation_units, &executed_units,
-                                pending_tasks.get(), &result_mutex, &next_unit);
+                                pending_tasks, &result_mutex, &next_unit);
     task_ids[i] = task->id();
     V8::GetCurrentPlatform()->CallOnBackgroundThread(
         task, v8::Platform::kShortRunningTask);
@@ -524,13 +548,12 @@
   return task_ids;
 }
 
-void WaitForCompilationTasks(
-    Isolate* isolate, uint32_t* task_ids,
-    const base::SmartPointer<base::Semaphore>& pending_tasks) {
+void WaitForCompilationTasks(Isolate* isolate, uint32_t* task_ids,
+                             base::Semaphore* pending_tasks) {
   const size_t num_tasks =
       Min(static_cast<size_t>(FLAG_wasm_num_compilation_tasks),
           V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads());
-  for (size_t i = 0; i < num_tasks; i++) {
+  for (size_t i = 0; i < num_tasks; ++i) {
     // If the task has not started yet, then we abort it. Otherwise we wait for
     // it to finish.
     if (!isolate->cancelable_task_manager()->TryAbort(task_ids[i])) {
@@ -540,7 +563,6 @@
 }
 
 void FinishCompilationUnits(
-    WasmModule* module,
     std::queue<compiler::WasmCompilationUnit*>& executed_units,
     std::vector<Handle<Code>>& results, base::Mutex& result_mutex) {
   while (true) {
@@ -553,90 +575,201 @@
       unit = executed_units.front();
       executed_units.pop();
     }
-    int j = compiler::GetIndexOfWasmCompilationUnit(unit);
-    results[j] = compiler::FinishCompilation(unit);
+    int j = unit->index();
+    results[j] = unit->FinishCompilation();
+    delete unit;
   }
 }
 
-bool FinishCompilation(Isolate* isolate, WasmModule* module,
-                       const Handle<JSReceiver> ffi,
-                       const std::vector<Handle<Code>>& results,
-                       const WasmModuleInstance& instance,
-                       const Handle<FixedArray>& code_table,
-                       ErrorThrower& thrower, Factory* factory,
-                       ModuleEnv& module_env, uint32_t& total_code_size,
-                       PropertyDescriptor& desc) {
+void CompileInParallel(Isolate* isolate, const WasmModule* module,
+                       std::vector<Handle<Code>>& functions,
+                       ErrorThrower* thrower, ModuleEnv* module_env) {
+  // Data structures for the parallel compilation.
+  std::vector<compiler::WasmCompilationUnit*> compilation_units(
+      module->functions.size());
+  std::queue<compiler::WasmCompilationUnit*> executed_units;
+
+  //-----------------------------------------------------------------------
+  // For parallel compilation:
+  // 1) The main thread allocates a compilation unit for each wasm function
+  //    and stores them in the vector {compilation_units}.
+  // 2) The main thread spawns {WasmCompilationTask} instances which run on
+  //    the background threads.
+  // 3.a) The background threads and the main thread pick one compilation
+  //      unit at a time and execute the parallel phase of the compilation
+  //      unit. After finishing the execution of the parallel phase, the
+  //      result is enqueued in {executed_units}.
+  // 3.b) If {executed_units} contains a compilation unit, the main thread
+  //      dequeues it and finishes the compilation.
+  // 4) After the parallel phase of all compilation units has started, the
+  //    main thread waits for all {WasmCompilationTask} instances to finish.
+  // 5) The main thread finishes the compilation.
+
+  // Turn on the {CanonicalHandleScope} so that the background threads can
+  // use the node cache.
+  CanonicalHandleScope canonical(isolate);
+
+  // 1) The main thread allocates a compilation unit for each wasm function
+  //    and stores them in the vector {compilation_units}.
+  InitializeParallelCompilation(isolate, module->functions, compilation_units,
+                                *module_env, *thrower);
+
+  // Objects for the synchronization with the background threads.
+  base::Mutex result_mutex;
+  base::AtomicNumber<size_t> next_unit(
+      static_cast<size_t>(FLAG_skip_compiling_wasm_funcs));
+
+  // 2) The main thread spawns {WasmCompilationTask} instances which run on
+  //    the background threads.
+  base::SmartArrayPointer<uint32_t> task_ids(StartCompilationTasks(
+      isolate, compilation_units, executed_units, module->pending_tasks.get(),
+      result_mutex, next_unit));
+
+  // 3.a) The background threads and the main thread pick one compilation
+  //      unit at a time and execute the parallel phase of the compilation
+  //      unit. After finishing the execution of the parallel phase, the
+  //      result is enqueued in {executed_units}.
+  while (FetchAndExecuteCompilationUnit(isolate, &compilation_units,
+                                        &executed_units, &result_mutex,
+                                        &next_unit)) {
+    // 3.b) If {executed_units} contains a compilation unit, the main thread
+    //      dequeues it and finishes the compilation unit. Compilation units
+    //      are finished concurrently to the background threads to save
+    //      memory.
+    FinishCompilationUnits(executed_units, functions, result_mutex);
+  }
+  // 4) After the parallel phase of all compilation units has started, the
+  //    main thread waits for all {WasmCompilationTask} instances to finish.
+  WaitForCompilationTasks(isolate, task_ids.get(), module->pending_tasks.get());
+  // Finish the compilation of the remaining compilation units.
+  FinishCompilationUnits(executed_units, functions, result_mutex);
+}
+
+void CompileSequentially(Isolate* isolate, const WasmModule* module,
+                         std::vector<Handle<Code>>& functions,
+                         ErrorThrower* thrower, ModuleEnv* module_env) {
+  DCHECK(!thrower->error());
+
   for (uint32_t i = FLAG_skip_compiling_wasm_funcs;
-       i < module->functions.size(); i++) {
+       i < module->functions.size(); ++i) {
     const WasmFunction& func = module->functions[i];
-    if (thrower.error()) break;
 
     DCHECK_EQ(i, func.func_index);
     WasmName str = module->GetName(func.name_offset, func.name_length);
     Handle<Code> code = Handle<Code>::null();
-    Handle<JSFunction> function = Handle<JSFunction>::null();
-    Handle<String> function_name = Handle<String>::null();
-    if (FLAG_wasm_num_compilation_tasks != 0) {
-      code = results[i];
-    } else {
-      // Compile the function.
-      code =
-          compiler::CompileWasmFunction(&thrower, isolate, &module_env, &func);
-    }
+    // Compile the function.
+    code = compiler::WasmCompilationUnit::CompileWasmFunction(
+        thrower, isolate, module_env, &func);
     if (code.is_null()) {
-      thrower.Error("Compilation of #%d:%.*s failed.", i, str.length(),
-                    str.start());
-      return false;
+      thrower->Error("Compilation of #%d:%.*s failed.", i, str.length(),
+                     str.start());
+      break;
     }
-    if (func.exported) {
-      function_name = factory->InternalizeUtf8String(str);
-      function = compiler::CompileJSToWasmWrapper(
-          isolate, &module_env, function_name, code, instance.js_object, i);
-      record_code_size(total_code_size, function->code());
-    }
-    if (!code.is_null()) {
       // Install the code into the linker table.
-      module_env.linker->Finish(i, code);
-      code_table->set(i, *code);
-      record_code_size(total_code_size, *code);
-    }
-    if (func.exported) {
-      // Exported functions are installed as read-only properties on the
-      // module.
-      desc.set_value(function);
-      Maybe<bool> status = JSReceiver::DefineOwnProperty(
-          isolate, instance.js_object, function_name, &desc,
-          Object::THROW_ON_ERROR);
-      if (!status.IsJust())
-        thrower.Error("export of %.*s failed.", str.length(), str.start());
+    functions[i] = code;
+  }
+}
+
+void PopulateFunctionTable(WasmModuleInstance* instance) {
+  if (!instance->function_table.is_null()) {
+    uint32_t table_size = instance->module->FunctionTableSize();
+    DCHECK_EQ(table_size * 2, instance->function_table->length());
+    uint32_t populated_table_size =
+        static_cast<uint32_t>(instance->module->function_table.size());
+    for (uint32_t i = 0; i < populated_table_size; ++i) {
+    instance->function_table->set(
+        i + table_size,
+        *instance->function_code[instance->module->function_table[i]]);
     }
   }
-  return true;
 }
 }  // namespace
 
+void SetDeoptimizationData(Factory* factory, Handle<JSObject> js_object,
+                           std::vector<Handle<Code>>& functions) {
+  for (size_t i = FLAG_skip_compiling_wasm_funcs; i < functions.size(); ++i) {
+    Handle<Code> code = functions[i];
+    DCHECK(code->deoptimization_data() == nullptr ||
+           code->deoptimization_data()->length() == 0);
+    Handle<FixedArray> deopt_data = factory->NewFixedArray(2, TENURED);
+    if (!js_object.is_null()) {
+      deopt_data->set(0, *js_object);
+    }
+    deopt_data->set(1, Smi::FromInt(static_cast<int>(i)));
+    deopt_data->set_length(2);
+    code->set_deoptimization_data(*deopt_data);
+  }
+}
+
+Handle<FixedArray> WasmModule::CompileFunctions(Isolate* isolate) const {
+  Factory* factory = isolate->factory();
+  ErrorThrower thrower(isolate, "WasmModule::CompileFunctions()");
+
+  WasmModuleInstance temp_instance_for_compilation(this);
+  temp_instance_for_compilation.function_table =
+      BuildFunctionTable(isolate, this);
+  temp_instance_for_compilation.context = isolate->native_context();
+  temp_instance_for_compilation.mem_size = GetMinModuleMemSize(this);
+  temp_instance_for_compilation.mem_start = nullptr;
+  temp_instance_for_compilation.globals_start = nullptr;
+
+  ModuleEnv module_env;
+  module_env.module = this;
+  module_env.instance = &temp_instance_for_compilation;
+  module_env.origin = origin;
+  InitializePlaceholders(factory, &module_env.placeholders, functions.size());
+
+  Handle<FixedArray> ret =
+      factory->NewFixedArray(static_cast<int>(functions.size()), TENURED);
+
+  temp_instance_for_compilation.import_code.resize(import_table.size());
+  for (uint32_t i = 0; i < import_table.size(); ++i) {
+    temp_instance_for_compilation.import_code[i] =
+        CreatePlaceholder(factory, i, Code::WASM_TO_JS_FUNCTION);
+  }
+  isolate->counters()->wasm_functions_per_module()->AddSample(
+      static_cast<int>(functions.size()));
+  if (FLAG_wasm_num_compilation_tasks != 0) {
+    CompileInParallel(isolate, this,
+                      temp_instance_for_compilation.function_code, &thrower,
+                      &module_env);
+  } else {
+    CompileSequentially(isolate, this,
+                        temp_instance_for_compilation.function_code, &thrower,
+                        &module_env);
+  }
+  if (thrower.error()) {
+    return Handle<FixedArray>::null();
+  }
+
+  LinkModuleFunctions(isolate, temp_instance_for_compilation.function_code);
+
+  // At this point, compilation has completed. Update the code table
+  // and record sizes.
+  for (size_t i = FLAG_skip_compiling_wasm_funcs;
+       i < temp_instance_for_compilation.function_code.size(); ++i) {
+    Code* code = *temp_instance_for_compilation.function_code[i];
+    ret->set(static_cast<int>(i), code);
+  }
+
+  PopulateFunctionTable(&temp_instance_for_compilation);
+
+  return ret;
+}
+
 // Instantiates a wasm module as a JSObject.
 //  * allocates a backing store of {mem_size} bytes.
 //  * installs a named property "memory" for that buffer if exported
 //  * installs named properties on the object for exported functions
 //  * compiles wasm code to machine code
-MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
-                                              Handle<JSReceiver> ffi,
-                                              Handle<JSArrayBuffer> memory) {
+MaybeHandle<JSObject> WasmModule::Instantiate(
+    Isolate* isolate, Handle<JSReceiver> ffi,
+    Handle<JSArrayBuffer> memory) const {
   HistogramTimerScope wasm_instantiate_module_time_scope(
       isolate->counters()->wasm_instantiate_module_time());
-  this->shared_isolate = isolate;  // TODO(titzer): have a real shared isolate.
   ErrorThrower thrower(isolate, "WasmModule::Instantiate()");
   Factory* factory = isolate->factory();
 
-  PropertyDescriptor desc;
-  desc.set_writable(false);
-
-  // If FLAG_print_wasm_code_size is set, this aggregates the sum of all code
-  // objects created for this module.
-  // TODO(titzer): switch this to TRACE_EVENT
-  uint32_t total_code_size = 0;
-
   //-------------------------------------------------------------------------
   // Allocate the instance and its JS counterpart.
   //-------------------------------------------------------------------------
@@ -646,9 +779,26 @@
   WasmModuleInstance instance(this);
   instance.context = isolate->native_context();
   instance.js_object = factory->NewJSObjectFromMap(map, TENURED);
-  Handle<FixedArray> code_table =
-      factory->NewFixedArray(static_cast<int>(functions.size()), TENURED);
+
+  Handle<FixedArray> code_table = CompileFunctions(isolate);
+  if (code_table.is_null()) return Handle<JSObject>::null();
+
   instance.js_object->SetInternalField(kWasmModuleCodeTable, *code_table);
+  size_t module_bytes_len =
+      instance.module->module_end - instance.module->module_start;
+  DCHECK_LE(module_bytes_len, static_cast<size_t>(kMaxInt));
+  Vector<const uint8_t> module_bytes_vec(instance.module->module_start,
+                                         static_cast<int>(module_bytes_len));
+  Handle<String> module_bytes_string =
+      factory->NewStringFromOneByte(module_bytes_vec, TENURED)
+          .ToHandleChecked();
+  instance.js_object->SetInternalField(kWasmModuleBytesString,
+                                       *module_bytes_string);
+
+  for (uint32_t i = 0; i < functions.size(); ++i) {
+    Handle<Code> code = Handle<Code>(Code::cast(code_table->get(i)));
+    instance.function_code[i] = code;
+  }
 
   //-------------------------------------------------------------------------
   // Allocate and initialize the linear memory.
@@ -682,132 +832,75 @@
   HistogramTimerScope wasm_compile_module_time_scope(
       isolate->counters()->wasm_compile_module_time());
 
-  instance.function_table = BuildFunctionTable(isolate, this);
-  WasmLinker linker(isolate, functions.size());
   ModuleEnv module_env;
   module_env.module = this;
   module_env.instance = &instance;
-  module_env.linker = &linker;
   module_env.origin = origin;
 
   //-------------------------------------------------------------------------
   // Compile wrappers to imported functions.
   //-------------------------------------------------------------------------
   if (!CompileWrappersToImportedFunctions(isolate, this, ffi, &instance,
-                                          &thrower, factory, &module_env,
-                                          total_code_size)) {
+                                          &thrower, factory)) {
     return MaybeHandle<JSObject>();
   }
-  //-------------------------------------------------------------------------
-  // Compile all functions in the module.
-  //-------------------------------------------------------------------------
+
+  // If FLAG_print_wasm_code_size is set, this aggregates the sum of all code
+  // objects created for this module.
+  // TODO(titzer): switch this to TRACE_EVENT
+  CodeStats code_stats;
+  if (FLAG_print_wasm_code_size) {
+    for (Handle<Code> c : instance.function_code) code_stats.Record(*c);
+    for (Handle<Code> c : instance.import_code) code_stats.Record(*c);
+  }
+
   {
-    isolate->counters()->wasm_functions_per_module()->AddSample(
-        static_cast<int>(functions.size()));
-
-    // Data structures for the parallel compilation.
-    std::vector<compiler::WasmCompilationUnit*> compilation_units(
-        functions.size());
-    std::queue<compiler::WasmCompilationUnit*> executed_units;
-    std::vector<Handle<Code>> results(functions.size());
-
-    if (FLAG_wasm_num_compilation_tasks != 0) {
-      //-----------------------------------------------------------------------
-      // For parallel compilation:
-      // 1) The main thread allocates a compilation unit for each wasm function
-      //    and stores them in the vector {compilation_units}.
-      // 2) The main thread spawns {WasmCompilationTask} instances which run on
-      //    the background threads.
-      // 3.a) The background threads and the main thread pick one compilation
-      //      unit at a time and execute the parallel phase of the compilation
-      //      unit. After finishing the execution of the parallel phase, the
-      //      result is enqueued in {executed_units}.
-      // 3.b) If {executed_units} contains a compilation unit, the main thread
-      //      dequeues it and finishes the compilation.
-      // 4) After the parallel phase of all compilation units has started, the
-      //    main thread waits for all {WasmCompilationTask} instances to finish.
-      // 5) The main thread finishes the compilation.
-
-      // Turn on the {CanonicalHandleScope} so that the background threads can
-      // use the node cache.
-      CanonicalHandleScope canonical(isolate);
-
-      // 1) The main thread allocates a compilation unit for each wasm function
-      //    and stores them in the vector {compilation_units}.
-      InitializeParallelCompilation(isolate, functions, compilation_units,
-                                    module_env, thrower);
-
-      // Objects for the synchronization with the background threads.
-      base::SmartPointer<base::Semaphore> pending_tasks(new base::Semaphore(0));
-      base::Mutex result_mutex;
-      base::AtomicNumber<size_t> next_unit(
-          static_cast<size_t>(FLAG_skip_compiling_wasm_funcs));
-
-      // 2) The main thread spawns {WasmCompilationTask} instances which run on
-      //    the background threads.
-      base::SmartArrayPointer<uint32_t> task_ids(
-          StartCompilationTasks(isolate, compilation_units, executed_units,
-                                pending_tasks, result_mutex, next_unit));
-
-      // 3.a) The background threads and the main thread pick one compilation
-      //      unit at a time and execute the parallel phase of the compilation
-      //      unit. After finishing the execution of the parallel phase, the
-      //      result is enqueued in {executed_units}.
-      while (FetchAndExecuteCompilationUnit(isolate, &compilation_units,
-                                            &executed_units, &result_mutex,
-                                            &next_unit)) {
-        // 3.b) If {executed_units} contains a compilation unit, the main thread
-        //      dequeues it and finishes the compilation unit. Compilation units
-        //      are finished concurrently to the background threads to save
-        //      memory.
-        FinishCompilationUnits(this, executed_units, results, result_mutex);
-      }
-      // 4) After the parallel phase of all compilation units has started, the
-      //    main thread waits for all {WasmCompilationTask} instances to finish.
-      WaitForCompilationTasks(isolate, task_ids.get(), pending_tasks);
-      // Finish the compilation of the remaining compilation units.
-      FinishCompilationUnits(this, executed_units, results, result_mutex);
-    }
-    // 5) The main thread finishes the compilation.
-    if (!FinishCompilation(isolate, this, ffi, results, instance, code_table,
-                           thrower, factory, module_env, total_code_size,
-                           desc)) {
-      return MaybeHandle<JSObject>();
-    }
-
-    // Patch all direct call sites.
-    linker.Link(instance.function_table, this->function_table);
     instance.js_object->SetInternalField(kWasmModuleFunctionTable,
                                          Smi::FromInt(0));
+    LinkImports(isolate, instance.function_code, instance.import_code);
+
+    SetDeoptimizationData(factory, instance.js_object, instance.function_code);
 
     //-------------------------------------------------------------------------
     // Create and populate the exports object.
     //-------------------------------------------------------------------------
     if (export_table.size() > 0 || mem_export) {
-      // Create the "exports" object.
-      Handle<JSFunction> object_function = Handle<JSFunction>(
-          isolate->native_context()->object_function(), isolate);
-      Handle<JSObject> exports_object =
-          factory->NewJSObject(object_function, TENURED);
-      Handle<String> exports_name = factory->InternalizeUtf8String("exports");
-      JSObject::AddProperty(instance.js_object, exports_name, exports_object,
-                            READ_ONLY);
+      Handle<JSObject> exports_object;
+      if (origin == kWasmOrigin) {
+        // Create the "exports" object.
+        Handle<JSFunction> object_function = Handle<JSFunction>(
+            isolate->native_context()->object_function(), isolate);
+        exports_object = factory->NewJSObject(object_function, TENURED);
+        Handle<String> exports_name = factory->InternalizeUtf8String("exports");
+        JSObject::AddProperty(instance.js_object, exports_name, exports_object,
+                              READ_ONLY);
+      } else {
+        // Just export the functions directly on the object returned.
+        exports_object = instance.js_object;
+      }
+
+      PropertyDescriptor desc;
+      desc.set_writable(false);
 
       // Compile wrappers and add them to the exports object.
       for (const WasmExport& exp : export_table) {
         if (thrower.error()) break;
         WasmName str = GetName(exp.name_offset, exp.name_length);
         Handle<String> name = factory->InternalizeUtf8String(str);
-        Handle<Code> code = linker.GetFunctionCode(exp.func_index);
+        Handle<Code> code = instance.function_code[exp.func_index];
         Handle<JSFunction> function = compiler::CompileJSToWasmWrapper(
             isolate, &module_env, name, code, instance.js_object,
             exp.func_index);
-        record_code_size(total_code_size, function->code());
+        if (FLAG_print_wasm_code_size) {
+          code_stats.Record(function->code());
+        }
         desc.set_value(function);
         Maybe<bool> status = JSReceiver::DefineOwnProperty(
             isolate, exports_object, name, &desc, Object::THROW_ON_ERROR);
-        if (!status.IsJust())
+        if (!status.IsJust()) {
           thrower.Error("export of %.*s failed.", str.length(), str.start());
+          break;
+        }
       }
 
       if (mem_export) {
@@ -819,29 +912,28 @@
     }
   }
 
-  //-------------------------------------------------------------------------
-  // Attach an array with function names and an array with offsets into that
-  // first array.
-  //-------------------------------------------------------------------------
-  {
-    Handle<Object> arr = BuildFunctionNamesTable(isolate, module_env.module);
-    instance.js_object->SetInternalField(kWasmFunctionNamesArray, *arr);
+  if (FLAG_print_wasm_code_size) {
+    code_stats.Report();
   }
-
-  if (FLAG_print_wasm_code_size)
-    printf("Total generated wasm code: %u bytes\n", total_code_size);
+  //-------------------------------------------------------------------------
+  // Attach the function name table.
+  //-------------------------------------------------------------------------
+  Handle<ByteArray> function_name_table =
+      BuildFunctionNamesTable(isolate, module_env.module);
+  instance.js_object->SetInternalField(kWasmFunctionNamesArray,
+                                       *function_name_table);
 
   // Run the start function if one was specified.
   if (this->start_function_index >= 0) {
     HandleScope scope(isolate);
     uint32_t index = static_cast<uint32_t>(this->start_function_index);
     Handle<String> name = isolate->factory()->NewStringFromStaticChars("start");
-    Handle<Code> code = linker.GetFunctionCode(index);
+    Handle<Code> code = instance.function_code[index];
     Handle<JSFunction> jsfunc = compiler::CompileJSToWasmWrapper(
         isolate, &module_env, name, code, instance.js_object, index);
 
     // Call the JS function.
-    Handle<Object> undefined(isolate->heap()->undefined_value(), isolate);
+    Handle<Object> undefined = isolate->factory()->undefined_value();
     MaybeHandle<Object> retval =
         Execution::Call(isolate, jsfunc, undefined, 0, nullptr);
 
@@ -852,10 +944,12 @@
   return instance.js_object;
 }
 
-Handle<Code> ModuleEnv::GetFunctionCode(uint32_t index) {
+// TODO(mtrofin): remove this once we move to WASM_DIRECT_CALL
+Handle<Code> ModuleEnv::GetCodeOrPlaceholder(uint32_t index) const {
   DCHECK(IsValidFunction(index));
-  if (linker) return linker->GetFunctionCode(index);
-  return instance ? instance->function_code[index] : Handle<Code>::null();
+  if (!placeholders.empty()) return placeholders[index];
+  DCHECK_NOT_NULL(instance);
+  return instance->function_code[index];
 }
 
 Handle<Code> ModuleEnv::GetImportCode(uint32_t index) {
@@ -868,98 +962,122 @@
   DCHECK(IsValidFunction(index));
   // Always make a direct call to whatever is in the table at that location.
   // A wrapper will be generated for FFI calls.
-  WasmFunction* function = &module->functions[index];
+  const WasmFunction* function = &module->functions[index];
   return GetWasmCallDescriptor(zone, function->sig);
 }
 
+Handle<Object> GetWasmFunctionNameOrNull(Isolate* isolate, Handle<Object> wasm,
+                                         uint32_t func_index) {
+  if (!wasm->IsUndefined(isolate)) {
+    Handle<ByteArray> func_names_arr_obj(
+        ByteArray::cast(Handle<JSObject>::cast(wasm)->GetInternalField(
+            kWasmFunctionNamesArray)),
+        isolate);
+    // TODO(clemens): Extract this from the module bytes; skip whole function
+    // name table.
+    Handle<Object> name;
+    if (GetWasmFunctionNameFromTable(func_names_arr_obj, func_index)
+            .ToHandle(&name)) {
+      return name;
+    }
+  }
+  return isolate->factory()->null_value();
+}
+
+Handle<String> GetWasmFunctionName(Isolate* isolate, Handle<Object> wasm,
+                                   uint32_t func_index) {
+  Handle<Object> name_or_null =
+      GetWasmFunctionNameOrNull(isolate, wasm, func_index);
+  if (!name_or_null->IsNull(isolate)) {
+    return Handle<String>::cast(name_or_null);
+  }
+  return isolate->factory()->NewStringFromStaticChars("<WASM UNNAMED>");
+}
+
+bool IsWasmObject(Object* object) {
+  if (!object->IsJSObject()) return false;
+  JSObject* obj = JSObject::cast(object);
+  if (obj->GetInternalFieldCount() != kWasmModuleInternalFieldCount ||
+      !obj->GetInternalField(kWasmModuleCodeTable)->IsFixedArray() ||
+      !obj->GetInternalField(kWasmMemArrayBuffer)->IsJSArrayBuffer() ||
+      !obj->GetInternalField(kWasmFunctionNamesArray)->IsByteArray() ||
+      !obj->GetInternalField(kWasmModuleBytesString)->IsSeqOneByteString()) {
+    return false;
+  }
+  DisallowHeapAllocation no_gc;
+  SeqOneByteString* bytes =
+      SeqOneByteString::cast(obj->GetInternalField(kWasmModuleBytesString));
+  if (bytes->length() < 4) return false;
+  if (memcmp(bytes->GetChars(), "\0asm", 4)) return false;
+
+  // All checks passed.
+  return true;
+}
+
+SeqOneByteString* GetWasmBytes(JSObject* wasm) {
+  return SeqOneByteString::cast(wasm->GetInternalField(kWasmModuleBytesString));
+}
+
+WasmDebugInfo* GetDebugInfo(JSObject* wasm) {
+  Object* info = wasm->GetInternalField(kWasmDebugInfo);
+  if (!info->IsUndefined(wasm->GetIsolate())) return WasmDebugInfo::cast(info);
+  Handle<WasmDebugInfo> new_info = WasmDebugInfo::New(handle(wasm));
+  wasm->SetInternalField(kWasmDebugInfo, *new_info);
+  return *new_info;
+}
+
+namespace testing {
+
 int32_t CompileAndRunWasmModule(Isolate* isolate, const byte* module_start,
                                 const byte* module_end, bool asm_js) {
   HandleScope scope(isolate);
   Zone zone(isolate->allocator());
+  ErrorThrower thrower(isolate, "CompileAndRunWasmModule");
+
   // Decode the module, but don't verify function bodies, since we'll
   // be compiling them anyway.
-  ModuleResult result = DecodeWasmModule(isolate, &zone, module_start,
-                                         module_end, false, kWasmOrigin);
-  if (result.failed()) {
-    if (result.val) {
-      delete result.val;
-    }
+  ModuleResult decoding_result =
+      DecodeWasmModule(isolate, &zone, module_start, module_end, false,
+                       asm_js ? kAsmJsOrigin : kWasmOrigin);
+
+  std::unique_ptr<const WasmModule> module(decoding_result.val);
+  if (decoding_result.failed()) {
     // Module verification failed. throw.
-    std::ostringstream str;
-    str << "WASM.compileRun() failed: " << result;
-    isolate->Throw(
-        *isolate->factory()->NewStringFromAsciiChecked(str.str().c_str()));
+    thrower.Error("WASM.compileRun() failed: %s",
+                  decoding_result.error_msg.get());
     return -1;
   }
 
-  int32_t retval = CompileAndRunWasmModule(isolate, result.val);
-  delete result.val;
-  return retval;
-}
-
-int32_t CompileAndRunWasmModule(Isolate* isolate, WasmModule* module) {
-  ErrorThrower thrower(isolate, "CompileAndRunWasmModule");
-  WasmModuleInstance instance(module);
-
-  // Allocate and initialize the linear memory.
-  if (!AllocateMemory(&thrower, isolate, &instance)) {
-    return -1;
+  if (module->import_table.size() > 0) {
+    thrower.Error("Not supported: module has imports.");
   }
-  LoadDataSegments(module, instance.mem_start, instance.mem_size);
-
-  // Allocate the globals area if necessary.
-  if (!AllocateGlobals(&thrower, isolate, &instance)) {
-    return -1;
+  if (module->export_table.size() == 0) {
+    thrower.Error("Not supported: module has no exports.");
   }
 
-  // Build the function table.
-  instance.function_table = BuildFunctionTable(isolate, module);
+  if (thrower.error()) return -1;
 
-  // Create module environment.
-  WasmLinker linker(isolate, module->functions.size());
-  ModuleEnv module_env;
-  module_env.module = module;
-  module_env.instance = &instance;
-  module_env.linker = &linker;
-  module_env.origin = module->origin;
+  Handle<JSObject> instance =
+      module
+          ->Instantiate(isolate, Handle<JSReceiver>::null(),
+                        Handle<JSArrayBuffer>::null())
+          .ToHandleChecked();
 
-  // Compile all functions.
-  Handle<Code> main_code = Handle<Code>::null();  // record last code.
-  uint32_t index = 0;
-  int main_index = 0;
-  for (const WasmFunction& func : module->functions) {
-    DCHECK_EQ(index, func.func_index);
-    // Compile the function and install it in the code table.
-    Handle<Code> code =
-        compiler::CompileWasmFunction(&thrower, isolate, &module_env, &func);
-    if (!code.is_null()) {
-      if (func.exported) {
-        main_code = code;
-        main_index = index;
-      }
-      linker.Finish(index, code);
-    }
-    if (thrower.error()) return -1;
-    index++;
-  }
+  Handle<Name> exports = isolate->factory()->InternalizeUtf8String("exports");
+  Handle<JSObject> exports_object = Handle<JSObject>::cast(
+      JSObject::GetProperty(instance, exports).ToHandleChecked());
+  Handle<Name> main_name = isolate->factory()->NewStringFromStaticChars("main");
+  PropertyDescriptor desc;
+  Maybe<bool> property_found = JSReceiver::GetOwnPropertyDescriptor(
+      isolate, exports_object, main_name, &desc);
+  if (!property_found.FromMaybe(false)) return -1;
 
-  if (main_code.is_null()) {
-    thrower.Error("WASM.compileRun() failed: no main code found");
-    return -1;
-  }
-
-  linker.Link(instance.function_table, instance.module->function_table);
-
-  // Wrap the main code so it can be called as a JS function.
-  Handle<String> name = isolate->factory()->NewStringFromStaticChars("main");
-  Handle<JSObject> module_object = Handle<JSObject>(0, isolate);
-  Handle<JSFunction> jsfunc = compiler::CompileJSToWasmWrapper(
-      isolate, &module_env, name, main_code, module_object, main_index);
+  Handle<JSFunction> main_export = Handle<JSFunction>::cast(desc.value());
 
   // Call the JS function.
-  Handle<Object> undefined(isolate->heap()->undefined_value(), isolate);
+  Handle<Object> undefined = isolate->factory()->undefined_value();
   MaybeHandle<Object> retval =
-      Execution::Call(isolate, jsfunc, undefined, 0, nullptr);
+      Execution::Call(isolate, main_export, undefined, 0, nullptr);
 
   // The result should be a number.
   if (retval.is_null()) {
@@ -977,15 +1095,7 @@
   return -1;
 }
 
-Handle<Object> GetWasmFunctionName(Handle<JSObject> wasm, uint32_t func_index) {
-  Handle<Object> func_names_arr_obj = handle(
-      wasm->GetInternalField(kWasmFunctionNamesArray), wasm->GetIsolate());
-  if (func_names_arr_obj->IsUndefined())
-    return func_names_arr_obj;  // Return undefined.
-  return GetWasmFunctionNameFromTable(
-      Handle<ByteArray>::cast(func_names_arr_obj), func_index);
-}
-
+}  // namespace testing
 }  // namespace wasm
 }  // namespace internal
 }  // namespace v8