Home | History | Annotate | Download | only in wasm
      1 // Copyright 2015 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "src/base/atomic-utils.h"
      6 #include "src/macro-assembler.h"
      7 #include "src/objects.h"
      8 #include "src/property-descriptor.h"
      9 #include "src/v8.h"
     10 
     11 #include "src/simulator.h"
     12 
     13 #include "src/wasm/ast-decoder.h"
     14 #include "src/wasm/module-decoder.h"
     15 #include "src/wasm/wasm-debug.h"
     16 #include "src/wasm/wasm-function-name-table.h"
     17 #include "src/wasm/wasm-module.h"
     18 #include "src/wasm/wasm-result.h"
     19 
     20 #include "src/compiler/wasm-compiler.h"
     21 
     22 namespace v8 {
     23 namespace internal {
     24 namespace wasm {
     25 
     26 static const int kPlaceholderMarker = 1000000000;
     27 
     28 static const char* wasmSections[] = {
     29 #define F(enumerator, order, string) string,
     30     FOR_EACH_WASM_SECTION_TYPE(F)
     31 #undef F
     32         "<unknown>"  // entry for "Max"
     33 };
     34 
     35 static uint8_t wasmSectionsLengths[]{
     36 #define F(enumerator, order, string) sizeof(string) - 1,
     37     FOR_EACH_WASM_SECTION_TYPE(F)
     38 #undef F
     39         9  // entry for "Max"
     40 };
     41 
     42 static uint8_t wasmSectionsOrders[]{
     43 #define F(enumerator, order, string) order,
     44     FOR_EACH_WASM_SECTION_TYPE(F)
     45 #undef F
     46         0  // entry for "Max"
     47 };
     48 
     49 static_assert(sizeof(wasmSections) / sizeof(wasmSections[0]) ==
     50                   (size_t)WasmSection::Code::Max + 1,
     51               "expected enum WasmSection::Code to be monotonic from 0");
     52 
     53 WasmSection::Code WasmSection::begin() { return (WasmSection::Code)0; }
     54 WasmSection::Code WasmSection::end() { return WasmSection::Code::Max; }
     55 WasmSection::Code WasmSection::next(WasmSection::Code code) {
     56   return (WasmSection::Code)(1 + (uint32_t)code);
     57 }
     58 
     59 const char* WasmSection::getName(WasmSection::Code code) {
     60   return wasmSections[(size_t)code];
     61 }
     62 
     63 size_t WasmSection::getNameLength(WasmSection::Code code) {
     64   return wasmSectionsLengths[(size_t)code];
     65 }
     66 
     67 int WasmSection::getOrder(WasmSection::Code code) {
     68   return wasmSectionsOrders[(size_t)code];
     69 }
     70 
     71 WasmSection::Code WasmSection::lookup(const byte* string, uint32_t length) {
     72   // TODO(jfb) Linear search, it may be better to do a common-prefix search.
     73   for (Code i = begin(); i != end(); i = next(i)) {
     74     if (getNameLength(i) == length && 0 == memcmp(getName(i), string, length)) {
     75       return i;
     76     }
     77   }
     78   return Code::Max;
     79 }
     80 
     81 std::ostream& operator<<(std::ostream& os, const WasmModule& module) {
     82   os << "WASM module with ";
     83   os << (module.min_mem_pages * module.kPageSize) << " min mem";
     84   os << (module.max_mem_pages * module.kPageSize) << " max mem";
     85   os << module.functions.size() << " functions";
     86   os << module.functions.size() << " globals";
     87   os << module.functions.size() << " data segments";
     88   return os;
     89 }
     90 
     91 std::ostream& operator<<(std::ostream& os, const WasmFunction& function) {
     92   os << "WASM function with signature " << *function.sig;
     93 
     94   os << " code bytes: "
     95      << (function.code_end_offset - function.code_start_offset);
     96   return os;
     97 }
     98 
     99 std::ostream& operator<<(std::ostream& os, const WasmFunctionName& pair) {
    100   os << "#" << pair.function_->func_index << ":";
    101   if (pair.function_->name_offset > 0) {
    102     if (pair.module_) {
    103       WasmName name = pair.module_->GetName(pair.function_->name_offset,
    104                                             pair.function_->name_length);
    105       os.write(name.start(), name.length());
    106     } else {
    107       os << "+" << pair.function_->func_index;
    108     }
    109   } else {
    110     os << "?";
    111   }
    112   return os;
    113 }
    114 
    115 namespace {
    116 // Internal constants for the layout of the module object.
    117 const int kWasmModuleFunctionTable = 0;
    118 const int kWasmModuleCodeTable = 1;
    119 const int kWasmMemArrayBuffer = 2;
    120 const int kWasmGlobalsArrayBuffer = 3;
    121 // TODO(clemensh): Remove function name array, extract names from module bytes.
    122 const int kWasmFunctionNamesArray = 4;
    123 const int kWasmModuleBytesString = 5;
    124 const int kWasmDebugInfo = 6;
    125 const int kWasmModuleInternalFieldCount = 7;
    126 
    127 uint32_t GetMinModuleMemSize(const WasmModule* module) {
    128   return WasmModule::kPageSize * module->min_mem_pages;
    129 }
    130 
    131 void LoadDataSegments(const WasmModule* module, byte* mem_addr,
    132                       size_t mem_size) {
    133   for (const WasmDataSegment& segment : module->data_segments) {
    134     if (!segment.init) continue;
    135     if (!segment.source_size) continue;
    136     CHECK_LT(segment.dest_addr, mem_size);
    137     CHECK_LE(segment.source_size, mem_size);
    138     CHECK_LE(segment.dest_addr + segment.source_size, mem_size);
    139     byte* addr = mem_addr + segment.dest_addr;
    140     memcpy(addr, module->module_start + segment.source_offset,
    141            segment.source_size);
    142   }
    143 }
    144 
    145 Handle<FixedArray> BuildFunctionTable(Isolate* isolate,
    146                                       const WasmModule* module) {
    147   // Compute the size of the indirect function table
    148   uint32_t table_size = module->FunctionTableSize();
    149   if (table_size == 0) {
    150     return Handle<FixedArray>::null();
    151   }
    152 
    153   Handle<FixedArray> fixed = isolate->factory()->NewFixedArray(2 * table_size);
    154   for (uint32_t i = 0;
    155        i < static_cast<uint32_t>(module->function_table.size());
    156        ++i) {
    157     const WasmFunction* function =
    158         &module->functions[module->function_table[i]];
    159     fixed->set(i, Smi::FromInt(function->sig_index));
    160   }
    161   return fixed;
    162 }
    163 
    164 Handle<JSArrayBuffer> NewArrayBuffer(Isolate* isolate, size_t size,
    165                                      byte** backing_store) {
    166   *backing_store = nullptr;
    167   if (size > (WasmModule::kMaxMemPages * WasmModule::kPageSize)) {
    168     // TODO(titzer): lift restriction on maximum memory allocated here.
    169     return Handle<JSArrayBuffer>::null();
    170   }
    171   void* memory = isolate->array_buffer_allocator()->Allocate(size);
    172   if (memory == nullptr) {
    173     return Handle<JSArrayBuffer>::null();
    174   }
    175 
    176   *backing_store = reinterpret_cast<byte*>(memory);
    177 
    178 #if DEBUG
    179   // Double check the API allocator actually zero-initialized the memory.
    180   byte* bytes = reinterpret_cast<byte*>(*backing_store);
    181   for (size_t i = 0; i < size; ++i) {
    182     DCHECK_EQ(0, bytes[i]);
    183   }
    184 #endif
    185 
    186   Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
    187   JSArrayBuffer::Setup(buffer, isolate, false, memory, static_cast<int>(size));
    188   buffer->set_is_neuterable(false);
    189   return buffer;
    190 }
    191 
    192 void RelocateInstanceCode(WasmModuleInstance* instance) {
    193   for (uint32_t i = 0; i < instance->function_code.size(); ++i) {
    194     Handle<Code> function = instance->function_code[i];
    195     AllowDeferredHandleDereference embedding_raw_address;
    196     int mask = (1 << RelocInfo::WASM_MEMORY_REFERENCE) |
    197                (1 << RelocInfo::WASM_MEMORY_SIZE_REFERENCE);
    198     for (RelocIterator it(*function, mask); !it.done(); it.next()) {
    199       it.rinfo()->update_wasm_memory_reference(
    200           nullptr, instance->mem_start, GetMinModuleMemSize(instance->module),
    201           static_cast<uint32_t>(instance->mem_size));
    202     }
    203   }
    204 }
    205 
    206 // Set the memory for a module instance to be the {memory} array buffer.
    207 void SetMemory(WasmModuleInstance* instance, Handle<JSArrayBuffer> memory) {
    208   memory->set_is_neuterable(false);
    209   instance->mem_start = reinterpret_cast<byte*>(memory->backing_store());
    210   instance->mem_size = memory->byte_length()->Number();
    211   instance->mem_buffer = memory;
    212   RelocateInstanceCode(instance);
    213 }
    214 
    215 // Allocate memory for a module instance as a new JSArrayBuffer.
    216 bool AllocateMemory(ErrorThrower* thrower, Isolate* isolate,
    217                     WasmModuleInstance* instance) {
    218   DCHECK(instance->module);
    219   DCHECK(instance->mem_buffer.is_null());
    220 
    221   if (instance->module->min_mem_pages > WasmModule::kMaxMemPages) {
    222     thrower->Error("Out of memory: wasm memory too large");
    223     return false;
    224   }
    225   instance->mem_size = GetMinModuleMemSize(instance->module);
    226   instance->mem_buffer =
    227       NewArrayBuffer(isolate, instance->mem_size, &instance->mem_start);
    228   if (instance->mem_start == nullptr) {
    229     thrower->Error("Out of memory: wasm memory");
    230     instance->mem_size = 0;
    231     return false;
    232   }
    233   RelocateInstanceCode(instance);
    234   return true;
    235 }
    236 
    237 bool AllocateGlobals(ErrorThrower* thrower, Isolate* isolate,
    238                      WasmModuleInstance* instance) {
    239   uint32_t globals_size = instance->module->globals_size;
    240   if (globals_size > 0) {
    241     instance->globals_buffer =
    242         NewArrayBuffer(isolate, globals_size, &instance->globals_start);
    243     if (!instance->globals_start) {
    244       // Not enough space for backing store of globals.
    245       thrower->Error("Out of memory: wasm globals");
    246       return false;
    247     }
    248 
    249     for (uint32_t i = 0; i < instance->function_code.size(); ++i) {
    250       Handle<Code> function = instance->function_code[i];
    251       AllowDeferredHandleDereference embedding_raw_address;
    252       int mask = 1 << RelocInfo::WASM_GLOBAL_REFERENCE;
    253       for (RelocIterator it(*function, mask); !it.done(); it.next()) {
    254         it.rinfo()->update_wasm_global_reference(nullptr,
    255                                                  instance->globals_start);
    256       }
    257     }
    258   }
    259   return true;
    260 }
    261 
    262 Handle<Code> CreatePlaceholder(Factory* factory, uint32_t index,
    263                                Code::Kind kind) {
    264   // Create a placeholder code object and encode the corresponding index in
    265   // the {constant_pool_offset} field of the code object.
    266   // TODO(titzer): placeholder code objects are somewhat dangerous.
    267   static byte buffer[] = {0, 0, 0, 0, 0, 0, 0, 0};  // fake instructions.
    268   static CodeDesc desc = {buffer, 8, 8, 0, 0, nullptr, 0, nullptr};
    269   Handle<Code> code = factory->NewCode(desc, Code::KindField::encode(kind),
    270                                        Handle<Object>::null());
    271   code->set_constant_pool_offset(static_cast<int>(index) + kPlaceholderMarker);
    272   return code;
    273 }
    274 
    275 // TODO(mtrofin): remove when we stop relying on placeholders.
    276 void InitializePlaceholders(Factory* factory,
    277                             std::vector<Handle<Code>>* placeholders,
    278                             size_t size) {
    279   DCHECK(placeholders->empty());
    280   placeholders->reserve(size);
    281 
    282   for (uint32_t i = 0; i < size; ++i) {
    283     placeholders->push_back(CreatePlaceholder(factory, i, Code::WASM_FUNCTION));
    284   }
    285 }
    286 
    287 bool LinkFunction(Handle<Code> unlinked,
    288                   const std::vector<Handle<Code>>& code_targets,
    289                   Code::Kind kind) {
    290   bool modified = false;
    291   int mode_mask = RelocInfo::kCodeTargetMask;
    292   AllowDeferredHandleDereference embedding_raw_address;
    293   for (RelocIterator it(*unlinked, mode_mask); !it.done(); it.next()) {
    294     RelocInfo::Mode mode = it.rinfo()->rmode();
    295     if (RelocInfo::IsCodeTarget(mode)) {
    296       Code* target =
    297           Code::GetCodeFromTargetAddress(it.rinfo()->target_address());
    298       if (target->kind() == kind &&
    299           target->constant_pool_offset() >= kPlaceholderMarker) {
    300         // Patch direct calls to placeholder code objects.
    301         uint32_t index = target->constant_pool_offset() - kPlaceholderMarker;
    302         CHECK(index < code_targets.size());
    303         Handle<Code> new_target = code_targets[index];
    304         if (target != *new_target) {
    305           it.rinfo()->set_target_address(new_target->instruction_start(),
    306                                          SKIP_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
    307           modified = true;
    308         }
    309       }
    310     }
    311   }
    312   return modified;
    313 }
    314 
    315 void LinkModuleFunctions(Isolate* isolate,
    316                          std::vector<Handle<Code>>& functions) {
    317   for (size_t i = 0; i < functions.size(); ++i) {
    318     Handle<Code> code = functions[i];
    319     bool modified = LinkFunction(code, functions, Code::WASM_FUNCTION);
    320     if (modified) {
    321       Assembler::FlushICache(isolate, code->instruction_start(),
    322                              code->instruction_size());
    323     }
    324   }
    325 }
    326 
    327 void LinkImports(Isolate* isolate, std::vector<Handle<Code>>& functions,
    328                  const std::vector<Handle<Code>>& imports) {
    329   for (uint32_t i = 0; i < functions.size(); ++i) {
    330     Handle<Code> code = functions[i];
    331     bool modified = LinkFunction(code, imports, Code::WASM_TO_JS_FUNCTION);
    332     if (modified) {
    333       Assembler::FlushICache(isolate, code->instruction_start(),
    334                              code->instruction_size());
    335     }
    336   }
    337 }
    338 
    339 }  // namespace
    340 
    341 WasmModule::WasmModule()
    342     : module_start(nullptr),
    343       module_end(nullptr),
    344       min_mem_pages(0),
    345       max_mem_pages(0),
    346       mem_export(false),
    347       mem_external(false),
    348       start_function_index(-1),
    349       origin(kWasmOrigin),
    350       globals_size(0),
    351       indirect_table_size(0),
    352       pending_tasks(new base::Semaphore(0)) {}
    353 
    354 static MaybeHandle<JSFunction> ReportFFIError(ErrorThrower& thrower,
    355                                               const char* error, uint32_t index,
    356                                               wasm::WasmName module_name,
    357                                               wasm::WasmName function_name) {
    358   if (!function_name.is_empty()) {
    359     thrower.Error("Import #%d module=\"%.*s\" function=\"%.*s\" error: %s",
    360                   index, module_name.length(), module_name.start(),
    361                   function_name.length(), function_name.start(), error);
    362   } else {
    363     thrower.Error("Import #%d module=\"%.*s\" error: %s", index,
    364                   module_name.length(), module_name.start(), error);
    365   }
    366   thrower.Error("Import ");
    367   return MaybeHandle<JSFunction>();
    368 }
    369 
    370 static MaybeHandle<JSFunction> LookupFunction(
    371     ErrorThrower& thrower, Factory* factory, Handle<JSReceiver> ffi,
    372     uint32_t index, wasm::WasmName module_name, wasm::WasmName function_name) {
    373   if (ffi.is_null()) {
    374     return ReportFFIError(thrower, "FFI is not an object", index, module_name,
    375                           function_name);
    376   }
    377 
    378   // Look up the module first.
    379   Handle<String> name = factory->InternalizeUtf8String(module_name);
    380   MaybeHandle<Object> result = Object::GetProperty(ffi, name);
    381   if (result.is_null()) {
    382     return ReportFFIError(thrower, "module not found", index, module_name,
    383                           function_name);
    384   }
    385 
    386   Handle<Object> module = result.ToHandleChecked();
    387 
    388   if (!module->IsJSReceiver()) {
    389     return ReportFFIError(thrower, "module is not an object or function", index,
    390                           module_name, function_name);
    391   }
    392 
    393   Handle<Object> function;
    394   if (!function_name.is_empty()) {
    395     // Look up the function in the module.
    396     Handle<String> name = factory->InternalizeUtf8String(function_name);
    397     MaybeHandle<Object> result = Object::GetProperty(module, name);
    398     if (result.is_null()) {
    399       return ReportFFIError(thrower, "function not found", index, module_name,
    400                             function_name);
    401     }
    402     function = result.ToHandleChecked();
    403   } else {
    404     // No function specified. Use the "default export".
    405     function = module;
    406   }
    407 
    408   if (!function->IsJSFunction()) {
    409     return ReportFFIError(thrower, "not a function", index, module_name,
    410                           function_name);
    411   }
    412 
    413   return Handle<JSFunction>::cast(function);
    414 }
    415 
    416 namespace {
    417 // Fetches the compilation unit of a wasm function and executes its parallel
    418 // phase.
    419 bool FetchAndExecuteCompilationUnit(
    420     Isolate* isolate,
    421     std::vector<compiler::WasmCompilationUnit*>* compilation_units,
    422     std::queue<compiler::WasmCompilationUnit*>* executed_units,
    423     base::Mutex* result_mutex, base::AtomicNumber<size_t>* next_unit) {
    424   DisallowHeapAllocation no_allocation;
    425   DisallowHandleAllocation no_handles;
    426   DisallowHandleDereference no_deref;
    427   DisallowCodeDependencyChange no_dependency_change;
    428 
    429   // - 1 because AtomicIntrement returns the value after the atomic increment.
    430   size_t index = next_unit->Increment(1) - 1;
    431   if (index >= compilation_units->size()) {
    432     return false;
    433   }
    434 
    435   compiler::WasmCompilationUnit* unit = compilation_units->at(index);
    436   if (unit != nullptr) {
    437     unit->ExecuteCompilation();
    438     {
    439       base::LockGuard<base::Mutex> guard(result_mutex);
    440       executed_units->push(unit);
    441     }
    442   }
    443   return true;
    444 }
    445 
    446 class WasmCompilationTask : public CancelableTask {
    447  public:
    448   WasmCompilationTask(
    449       Isolate* isolate,
    450       std::vector<compiler::WasmCompilationUnit*>* compilation_units,
    451       std::queue<compiler::WasmCompilationUnit*>* executed_units,
    452       base::Semaphore* on_finished, base::Mutex* result_mutex,
    453       base::AtomicNumber<size_t>* next_unit)
    454       : CancelableTask(isolate),
    455         isolate_(isolate),
    456         compilation_units_(compilation_units),
    457         executed_units_(executed_units),
    458         on_finished_(on_finished),
    459         result_mutex_(result_mutex),
    460         next_unit_(next_unit) {}
    461 
    462   void RunInternal() override {
    463     while (FetchAndExecuteCompilationUnit(isolate_, compilation_units_,
    464                                           executed_units_, result_mutex_,
    465                                           next_unit_)) {
    466     }
    467     on_finished_->Signal();
    468   }
    469 
    470   Isolate* isolate_;
    471   std::vector<compiler::WasmCompilationUnit*>* compilation_units_;
    472   std::queue<compiler::WasmCompilationUnit*>* executed_units_;
    473   base::Semaphore* on_finished_;
    474   base::Mutex* result_mutex_;
    475   base::AtomicNumber<size_t>* next_unit_;
    476 };
    477 
    478 // Records statistics on the code generated by compiling WASM functions.
    479 struct CodeStats {
    480   size_t code_size;
    481   size_t reloc_size;
    482 
    483   inline CodeStats() : code_size(0), reloc_size(0) {}
    484 
    485   inline void Record(Code* code) {
    486     code_size += code->body_size();
    487     reloc_size += code->relocation_info()->length();
    488   }
    489 
    490   inline void Report() {
    491     PrintF("Total generated wasm code: %zu bytes\n", code_size);
    492     PrintF("Total generated wasm reloc: %zu bytes\n", reloc_size);
    493   }
    494 };
    495 
    496 bool CompileWrappersToImportedFunctions(
    497     Isolate* isolate, const WasmModule* module, const Handle<JSReceiver> ffi,
    498     WasmModuleInstance* instance, ErrorThrower* thrower, Factory* factory) {
    499   if (module->import_table.size() > 0) {
    500     instance->import_code.reserve(module->import_table.size());
    501     for (uint32_t index = 0; index < module->import_table.size(); ++index) {
    502       const WasmImport& import = module->import_table[index];
    503       WasmName module_name = module->GetNameOrNull(import.module_name_offset,
    504                                                    import.module_name_length);
    505       WasmName function_name = module->GetNameOrNull(
    506           import.function_name_offset, import.function_name_length);
    507       MaybeHandle<JSFunction> function = LookupFunction(
    508           *thrower, factory, ffi, index, module_name, function_name);
    509       if (function.is_null()) return false;
    510 
    511       Handle<Code> code = compiler::CompileWasmToJSWrapper(
    512           isolate, function.ToHandleChecked(), import.sig, module_name,
    513           function_name);
    514       instance->import_code[index] = code;
    515     }
    516   }
    517   return true;
    518 }
    519 
    520 void InitializeParallelCompilation(
    521     Isolate* isolate, const std::vector<WasmFunction>& functions,
    522     std::vector<compiler::WasmCompilationUnit*>& compilation_units,
    523     ModuleEnv& module_env, ErrorThrower& thrower) {
    524   for (uint32_t i = FLAG_skip_compiling_wasm_funcs; i < functions.size(); ++i) {
    525     compilation_units[i] = new compiler::WasmCompilationUnit(
    526         &thrower, isolate, &module_env, &functions[i], i);
    527   }
    528 }
    529 
    530 uint32_t* StartCompilationTasks(
    531     Isolate* isolate,
    532     std::vector<compiler::WasmCompilationUnit*>& compilation_units,
    533     std::queue<compiler::WasmCompilationUnit*>& executed_units,
    534     base::Semaphore* pending_tasks, base::Mutex& result_mutex,
    535     base::AtomicNumber<size_t>& next_unit) {
    536   const size_t num_tasks =
    537       Min(static_cast<size_t>(FLAG_wasm_num_compilation_tasks),
    538           V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads());
    539   uint32_t* task_ids = new uint32_t[num_tasks];
    540   for (size_t i = 0; i < num_tasks; ++i) {
    541     WasmCompilationTask* task =
    542         new WasmCompilationTask(isolate, &compilation_units, &executed_units,
    543                                 pending_tasks, &result_mutex, &next_unit);
    544     task_ids[i] = task->id();
    545     V8::GetCurrentPlatform()->CallOnBackgroundThread(
    546         task, v8::Platform::kShortRunningTask);
    547   }
    548   return task_ids;
    549 }
    550 
    551 void WaitForCompilationTasks(Isolate* isolate, uint32_t* task_ids,
    552                              base::Semaphore* pending_tasks) {
    553   const size_t num_tasks =
    554       Min(static_cast<size_t>(FLAG_wasm_num_compilation_tasks),
    555           V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads());
    556   for (size_t i = 0; i < num_tasks; ++i) {
    557     // If the task has not started yet, then we abort it. Otherwise we wait for
    558     // it to finish.
    559     if (!isolate->cancelable_task_manager()->TryAbort(task_ids[i])) {
    560       pending_tasks->Wait();
    561     }
    562   }
    563 }
    564 
    565 void FinishCompilationUnits(
    566     std::queue<compiler::WasmCompilationUnit*>& executed_units,
    567     std::vector<Handle<Code>>& results, base::Mutex& result_mutex) {
    568   while (true) {
    569     compiler::WasmCompilationUnit* unit = nullptr;
    570     {
    571       base::LockGuard<base::Mutex> guard(&result_mutex);
    572       if (executed_units.empty()) {
    573         break;
    574       }
    575       unit = executed_units.front();
    576       executed_units.pop();
    577     }
    578     int j = unit->index();
    579     results[j] = unit->FinishCompilation();
    580     delete unit;
    581   }
    582 }
    583 
    584 void CompileInParallel(Isolate* isolate, const WasmModule* module,
    585                        std::vector<Handle<Code>>& functions,
    586                        ErrorThrower* thrower, ModuleEnv* module_env) {
    587   // Data structures for the parallel compilation.
    588   std::vector<compiler::WasmCompilationUnit*> compilation_units(
    589       module->functions.size());
    590   std::queue<compiler::WasmCompilationUnit*> executed_units;
    591 
    592   //-----------------------------------------------------------------------
    593   // For parallel compilation:
    594   // 1) The main thread allocates a compilation unit for each wasm function
    595   //    and stores them in the vector {compilation_units}.
    596   // 2) The main thread spawns {WasmCompilationTask} instances which run on
    597   //    the background threads.
    598   // 3.a) The background threads and the main thread pick one compilation
    599   //      unit at a time and execute the parallel phase of the compilation
    600   //      unit. After finishing the execution of the parallel phase, the
    601   //      result is enqueued in {executed_units}.
    602   // 3.b) If {executed_units} contains a compilation unit, the main thread
    603   //      dequeues it and finishes the compilation.
    604   // 4) After the parallel phase of all compilation units has started, the
    605   //    main thread waits for all {WasmCompilationTask} instances to finish.
    606   // 5) The main thread finishes the compilation.
    607 
    608   // Turn on the {CanonicalHandleScope} so that the background threads can
    609   // use the node cache.
    610   CanonicalHandleScope canonical(isolate);
    611 
    612   // 1) The main thread allocates a compilation unit for each wasm function
    613   //    and stores them in the vector {compilation_units}.
    614   InitializeParallelCompilation(isolate, module->functions, compilation_units,
    615                                 *module_env, *thrower);
    616 
    617   // Objects for the synchronization with the background threads.
    618   base::Mutex result_mutex;
    619   base::AtomicNumber<size_t> next_unit(
    620       static_cast<size_t>(FLAG_skip_compiling_wasm_funcs));
    621 
    622   // 2) The main thread spawns {WasmCompilationTask} instances which run on
    623   //    the background threads.
    624   base::SmartArrayPointer<uint32_t> task_ids(StartCompilationTasks(
    625       isolate, compilation_units, executed_units, module->pending_tasks.get(),
    626       result_mutex, next_unit));
    627 
    628   // 3.a) The background threads and the main thread pick one compilation
    629   //      unit at a time and execute the parallel phase of the compilation
    630   //      unit. After finishing the execution of the parallel phase, the
    631   //      result is enqueued in {executed_units}.
    632   while (FetchAndExecuteCompilationUnit(isolate, &compilation_units,
    633                                         &executed_units, &result_mutex,
    634                                         &next_unit)) {
    635     // 3.b) If {executed_units} contains a compilation unit, the main thread
    636     //      dequeues it and finishes the compilation unit. Compilation units
    637     //      are finished concurrently to the background threads to save
    638     //      memory.
    639     FinishCompilationUnits(executed_units, functions, result_mutex);
    640   }
    641   // 4) After the parallel phase of all compilation units has started, the
    642   //    main thread waits for all {WasmCompilationTask} instances to finish.
    643   WaitForCompilationTasks(isolate, task_ids.get(), module->pending_tasks.get());
    644   // Finish the compilation of the remaining compilation units.
    645   FinishCompilationUnits(executed_units, functions, result_mutex);
    646 }
    647 
    648 void CompileSequentially(Isolate* isolate, const WasmModule* module,
    649                          std::vector<Handle<Code>>& functions,
    650                          ErrorThrower* thrower, ModuleEnv* module_env) {
    651   DCHECK(!thrower->error());
    652 
    653   for (uint32_t i = FLAG_skip_compiling_wasm_funcs;
    654        i < module->functions.size(); ++i) {
    655     const WasmFunction& func = module->functions[i];
    656 
    657     DCHECK_EQ(i, func.func_index);
    658     WasmName str = module->GetName(func.name_offset, func.name_length);
    659     Handle<Code> code = Handle<Code>::null();
    660     // Compile the function.
    661     code = compiler::WasmCompilationUnit::CompileWasmFunction(
    662         thrower, isolate, module_env, &func);
    663     if (code.is_null()) {
    664       thrower->Error("Compilation of #%d:%.*s failed.", i, str.length(),
    665                      str.start());
    666       break;
    667     }
    668       // Install the code into the linker table.
    669     functions[i] = code;
    670   }
    671 }
    672 
    673 void PopulateFunctionTable(WasmModuleInstance* instance) {
    674   if (!instance->function_table.is_null()) {
    675     uint32_t table_size = instance->module->FunctionTableSize();
    676     DCHECK_EQ(table_size * 2, instance->function_table->length());
    677     uint32_t populated_table_size =
    678         static_cast<uint32_t>(instance->module->function_table.size());
    679     for (uint32_t i = 0; i < populated_table_size; ++i) {
    680     instance->function_table->set(
    681         i + table_size,
    682         *instance->function_code[instance->module->function_table[i]]);
    683     }
    684   }
    685 }
    686 }  // namespace
    687 
    688 void SetDeoptimizationData(Factory* factory, Handle<JSObject> js_object,
    689                            std::vector<Handle<Code>>& functions) {
    690   for (size_t i = FLAG_skip_compiling_wasm_funcs; i < functions.size(); ++i) {
    691     Handle<Code> code = functions[i];
    692     DCHECK(code->deoptimization_data() == nullptr ||
    693            code->deoptimization_data()->length() == 0);
    694     Handle<FixedArray> deopt_data = factory->NewFixedArray(2, TENURED);
    695     if (!js_object.is_null()) {
    696       deopt_data->set(0, *js_object);
    697     }
    698     deopt_data->set(1, Smi::FromInt(static_cast<int>(i)));
    699     deopt_data->set_length(2);
    700     code->set_deoptimization_data(*deopt_data);
    701   }
    702 }
    703 
    704 Handle<FixedArray> WasmModule::CompileFunctions(Isolate* isolate) const {
    705   Factory* factory = isolate->factory();
    706   ErrorThrower thrower(isolate, "WasmModule::CompileFunctions()");
    707 
    708   WasmModuleInstance temp_instance_for_compilation(this);
    709   temp_instance_for_compilation.function_table =
    710       BuildFunctionTable(isolate, this);
    711   temp_instance_for_compilation.context = isolate->native_context();
    712   temp_instance_for_compilation.mem_size = GetMinModuleMemSize(this);
    713   temp_instance_for_compilation.mem_start = nullptr;
    714   temp_instance_for_compilation.globals_start = nullptr;
    715 
    716   ModuleEnv module_env;
    717   module_env.module = this;
    718   module_env.instance = &temp_instance_for_compilation;
    719   module_env.origin = origin;
    720   InitializePlaceholders(factory, &module_env.placeholders, functions.size());
    721 
    722   Handle<FixedArray> ret =
    723       factory->NewFixedArray(static_cast<int>(functions.size()), TENURED);
    724 
    725   temp_instance_for_compilation.import_code.resize(import_table.size());
    726   for (uint32_t i = 0; i < import_table.size(); ++i) {
    727     temp_instance_for_compilation.import_code[i] =
    728         CreatePlaceholder(factory, i, Code::WASM_TO_JS_FUNCTION);
    729   }
    730   isolate->counters()->wasm_functions_per_module()->AddSample(
    731       static_cast<int>(functions.size()));
    732   if (FLAG_wasm_num_compilation_tasks != 0) {
    733     CompileInParallel(isolate, this,
    734                       temp_instance_for_compilation.function_code, &thrower,
    735                       &module_env);
    736   } else {
    737     CompileSequentially(isolate, this,
    738                         temp_instance_for_compilation.function_code, &thrower,
    739                         &module_env);
    740   }
    741   if (thrower.error()) {
    742     return Handle<FixedArray>::null();
    743   }
    744 
    745   LinkModuleFunctions(isolate, temp_instance_for_compilation.function_code);
    746 
    747   // At this point, compilation has completed. Update the code table
    748   // and record sizes.
    749   for (size_t i = FLAG_skip_compiling_wasm_funcs;
    750        i < temp_instance_for_compilation.function_code.size(); ++i) {
    751     Code* code = *temp_instance_for_compilation.function_code[i];
    752     ret->set(static_cast<int>(i), code);
    753   }
    754 
    755   PopulateFunctionTable(&temp_instance_for_compilation);
    756 
    757   return ret;
    758 }
    759 
    760 // Instantiates a wasm module as a JSObject.
    761 //  * allocates a backing store of {mem_size} bytes.
    762 //  * installs a named property "memory" for that buffer if exported
    763 //  * installs named properties on the object for exported functions
    764 //  * compiles wasm code to machine code
    765 MaybeHandle<JSObject> WasmModule::Instantiate(
    766     Isolate* isolate, Handle<JSReceiver> ffi,
    767     Handle<JSArrayBuffer> memory) const {
    768   HistogramTimerScope wasm_instantiate_module_time_scope(
    769       isolate->counters()->wasm_instantiate_module_time());
    770   ErrorThrower thrower(isolate, "WasmModule::Instantiate()");
    771   Factory* factory = isolate->factory();
    772 
    773   //-------------------------------------------------------------------------
    774   // Allocate the instance and its JS counterpart.
    775   //-------------------------------------------------------------------------
    776   Handle<Map> map = factory->NewMap(
    777       JS_OBJECT_TYPE,
    778       JSObject::kHeaderSize + kWasmModuleInternalFieldCount * kPointerSize);
    779   WasmModuleInstance instance(this);
    780   instance.context = isolate->native_context();
    781   instance.js_object = factory->NewJSObjectFromMap(map, TENURED);
    782 
    783   Handle<FixedArray> code_table = CompileFunctions(isolate);
    784   if (code_table.is_null()) return Handle<JSObject>::null();
    785 
    786   instance.js_object->SetInternalField(kWasmModuleCodeTable, *code_table);
    787   size_t module_bytes_len =
    788       instance.module->module_end - instance.module->module_start;
    789   DCHECK_LE(module_bytes_len, static_cast<size_t>(kMaxInt));
    790   Vector<const uint8_t> module_bytes_vec(instance.module->module_start,
    791                                          static_cast<int>(module_bytes_len));
    792   Handle<String> module_bytes_string =
    793       factory->NewStringFromOneByte(module_bytes_vec, TENURED)
    794           .ToHandleChecked();
    795   instance.js_object->SetInternalField(kWasmModuleBytesString,
    796                                        *module_bytes_string);
    797 
    798   for (uint32_t i = 0; i < functions.size(); ++i) {
    799     Handle<Code> code = Handle<Code>(Code::cast(code_table->get(i)));
    800     instance.function_code[i] = code;
    801   }
    802 
    803   //-------------------------------------------------------------------------
    804   // Allocate and initialize the linear memory.
    805   //-------------------------------------------------------------------------
    806   isolate->counters()->wasm_min_mem_pages_count()->AddSample(
    807       instance.module->min_mem_pages);
    808   isolate->counters()->wasm_max_mem_pages_count()->AddSample(
    809       instance.module->max_mem_pages);
    810   if (memory.is_null()) {
    811     if (!AllocateMemory(&thrower, isolate, &instance)) {
    812       return MaybeHandle<JSObject>();
    813     }
    814   } else {
    815     SetMemory(&instance, memory);
    816   }
    817   instance.js_object->SetInternalField(kWasmMemArrayBuffer,
    818                                        *instance.mem_buffer);
    819   LoadDataSegments(this, instance.mem_start, instance.mem_size);
    820 
    821   //-------------------------------------------------------------------------
    822   // Allocate the globals area if necessary.
    823   //-------------------------------------------------------------------------
    824   if (!AllocateGlobals(&thrower, isolate, &instance)) {
    825     return MaybeHandle<JSObject>();
    826   }
    827   if (!instance.globals_buffer.is_null()) {
    828     instance.js_object->SetInternalField(kWasmGlobalsArrayBuffer,
    829                                          *instance.globals_buffer);
    830   }
    831 
    832   HistogramTimerScope wasm_compile_module_time_scope(
    833       isolate->counters()->wasm_compile_module_time());
    834 
    835   ModuleEnv module_env;
    836   module_env.module = this;
    837   module_env.instance = &instance;
    838   module_env.origin = origin;
    839 
    840   //-------------------------------------------------------------------------
    841   // Compile wrappers to imported functions.
    842   //-------------------------------------------------------------------------
    843   if (!CompileWrappersToImportedFunctions(isolate, this, ffi, &instance,
    844                                           &thrower, factory)) {
    845     return MaybeHandle<JSObject>();
    846   }
    847 
    848   // If FLAG_print_wasm_code_size is set, this aggregates the sum of all code
    849   // objects created for this module.
    850   // TODO(titzer): switch this to TRACE_EVENT
    851   CodeStats code_stats;
    852   if (FLAG_print_wasm_code_size) {
    853     for (Handle<Code> c : instance.function_code) code_stats.Record(*c);
    854     for (Handle<Code> c : instance.import_code) code_stats.Record(*c);
    855   }
    856 
    857   {
    858     instance.js_object->SetInternalField(kWasmModuleFunctionTable,
    859                                          Smi::FromInt(0));
    860     LinkImports(isolate, instance.function_code, instance.import_code);
    861 
    862     SetDeoptimizationData(factory, instance.js_object, instance.function_code);
    863 
    864     //-------------------------------------------------------------------------
    865     // Create and populate the exports object.
    866     //-------------------------------------------------------------------------
    867     if (export_table.size() > 0 || mem_export) {
    868       Handle<JSObject> exports_object;
    869       if (origin == kWasmOrigin) {
    870         // Create the "exports" object.
    871         Handle<JSFunction> object_function = Handle<JSFunction>(
    872             isolate->native_context()->object_function(), isolate);
    873         exports_object = factory->NewJSObject(object_function, TENURED);
    874         Handle<String> exports_name = factory->InternalizeUtf8String("exports");
    875         JSObject::AddProperty(instance.js_object, exports_name, exports_object,
    876                               READ_ONLY);
    877       } else {
    878         // Just export the functions directly on the object returned.
    879         exports_object = instance.js_object;
    880       }
    881 
    882       PropertyDescriptor desc;
    883       desc.set_writable(false);
    884 
    885       // Compile wrappers and add them to the exports object.
    886       for (const WasmExport& exp : export_table) {
    887         if (thrower.error()) break;
    888         WasmName str = GetName(exp.name_offset, exp.name_length);
    889         Handle<String> name = factory->InternalizeUtf8String(str);
    890         Handle<Code> code = instance.function_code[exp.func_index];
    891         Handle<JSFunction> function = compiler::CompileJSToWasmWrapper(
    892             isolate, &module_env, name, code, instance.js_object,
    893             exp.func_index);
    894         if (FLAG_print_wasm_code_size) {
    895           code_stats.Record(function->code());
    896         }
    897         desc.set_value(function);
    898         Maybe<bool> status = JSReceiver::DefineOwnProperty(
    899             isolate, exports_object, name, &desc, Object::THROW_ON_ERROR);
    900         if (!status.IsJust()) {
    901           thrower.Error("export of %.*s failed.", str.length(), str.start());
    902           break;
    903         }
    904       }
    905 
    906       if (mem_export) {
    907         // Export the memory as a named property.
    908         Handle<String> name = factory->InternalizeUtf8String("memory");
    909         JSObject::AddProperty(exports_object, name, instance.mem_buffer,
    910                               READ_ONLY);
    911       }
    912     }
    913   }
    914 
    915   if (FLAG_print_wasm_code_size) {
    916     code_stats.Report();
    917   }
    918   //-------------------------------------------------------------------------
    919   // Attach the function name table.
    920   //-------------------------------------------------------------------------
    921   Handle<ByteArray> function_name_table =
    922       BuildFunctionNamesTable(isolate, module_env.module);
    923   instance.js_object->SetInternalField(kWasmFunctionNamesArray,
    924                                        *function_name_table);
    925 
    926   // Run the start function if one was specified.
    927   if (this->start_function_index >= 0) {
    928     HandleScope scope(isolate);
    929     uint32_t index = static_cast<uint32_t>(this->start_function_index);
    930     Handle<String> name = isolate->factory()->NewStringFromStaticChars("start");
    931     Handle<Code> code = instance.function_code[index];
    932     Handle<JSFunction> jsfunc = compiler::CompileJSToWasmWrapper(
    933         isolate, &module_env, name, code, instance.js_object, index);
    934 
    935     // Call the JS function.
    936     Handle<Object> undefined = isolate->factory()->undefined_value();
    937     MaybeHandle<Object> retval =
    938         Execution::Call(isolate, jsfunc, undefined, 0, nullptr);
    939 
    940     if (retval.is_null()) {
    941       thrower.Error("WASM.instantiateModule(): start function failed");
    942     }
    943   }
    944   return instance.js_object;
    945 }
    946 
    947 // TODO(mtrofin): remove this once we move to WASM_DIRECT_CALL
    948 Handle<Code> ModuleEnv::GetCodeOrPlaceholder(uint32_t index) const {
    949   DCHECK(IsValidFunction(index));
    950   if (!placeholders.empty()) return placeholders[index];
    951   DCHECK_NOT_NULL(instance);
    952   return instance->function_code[index];
    953 }
    954 
    955 Handle<Code> ModuleEnv::GetImportCode(uint32_t index) {
    956   DCHECK(IsValidImport(index));
    957   return instance ? instance->import_code[index] : Handle<Code>::null();
    958 }
    959 
    960 compiler::CallDescriptor* ModuleEnv::GetCallDescriptor(Zone* zone,
    961                                                        uint32_t index) {
    962   DCHECK(IsValidFunction(index));
    963   // Always make a direct call to whatever is in the table at that location.
    964   // A wrapper will be generated for FFI calls.
    965   const WasmFunction* function = &module->functions[index];
    966   return GetWasmCallDescriptor(zone, function->sig);
    967 }
    968 
    969 Handle<Object> GetWasmFunctionNameOrNull(Isolate* isolate, Handle<Object> wasm,
    970                                          uint32_t func_index) {
    971   if (!wasm->IsUndefined(isolate)) {
    972     Handle<ByteArray> func_names_arr_obj(
    973         ByteArray::cast(Handle<JSObject>::cast(wasm)->GetInternalField(
    974             kWasmFunctionNamesArray)),
    975         isolate);
    976     // TODO(clemens): Extract this from the module bytes; skip whole function
    977     // name table.
    978     Handle<Object> name;
    979     if (GetWasmFunctionNameFromTable(func_names_arr_obj, func_index)
    980             .ToHandle(&name)) {
    981       return name;
    982     }
    983   }
    984   return isolate->factory()->null_value();
    985 }
    986 
    987 Handle<String> GetWasmFunctionName(Isolate* isolate, Handle<Object> wasm,
    988                                    uint32_t func_index) {
    989   Handle<Object> name_or_null =
    990       GetWasmFunctionNameOrNull(isolate, wasm, func_index);
    991   if (!name_or_null->IsNull(isolate)) {
    992     return Handle<String>::cast(name_or_null);
    993   }
    994   return isolate->factory()->NewStringFromStaticChars("<WASM UNNAMED>");
    995 }
    996 
    997 bool IsWasmObject(Object* object) {
    998   if (!object->IsJSObject()) return false;
    999   JSObject* obj = JSObject::cast(object);
   1000   if (obj->GetInternalFieldCount() != kWasmModuleInternalFieldCount ||
   1001       !obj->GetInternalField(kWasmModuleCodeTable)->IsFixedArray() ||
   1002       !obj->GetInternalField(kWasmMemArrayBuffer)->IsJSArrayBuffer() ||
   1003       !obj->GetInternalField(kWasmFunctionNamesArray)->IsByteArray() ||
   1004       !obj->GetInternalField(kWasmModuleBytesString)->IsSeqOneByteString()) {
   1005     return false;
   1006   }
   1007   DisallowHeapAllocation no_gc;
   1008   SeqOneByteString* bytes =
   1009       SeqOneByteString::cast(obj->GetInternalField(kWasmModuleBytesString));
   1010   if (bytes->length() < 4) return false;
   1011   if (memcmp(bytes->GetChars(), "\0asm", 4)) return false;
   1012 
   1013   // All checks passed.
   1014   return true;
   1015 }
   1016 
   1017 SeqOneByteString* GetWasmBytes(JSObject* wasm) {
   1018   return SeqOneByteString::cast(wasm->GetInternalField(kWasmModuleBytesString));
   1019 }
   1020 
   1021 WasmDebugInfo* GetDebugInfo(JSObject* wasm) {
   1022   Object* info = wasm->GetInternalField(kWasmDebugInfo);
   1023   if (!info->IsUndefined(wasm->GetIsolate())) return WasmDebugInfo::cast(info);
   1024   Handle<WasmDebugInfo> new_info = WasmDebugInfo::New(handle(wasm));
   1025   wasm->SetInternalField(kWasmDebugInfo, *new_info);
   1026   return *new_info;
   1027 }
   1028 
   1029 namespace testing {
   1030 
   1031 int32_t CompileAndRunWasmModule(Isolate* isolate, const byte* module_start,
   1032                                 const byte* module_end, bool asm_js) {
   1033   HandleScope scope(isolate);
   1034   Zone zone(isolate->allocator());
   1035   ErrorThrower thrower(isolate, "CompileAndRunWasmModule");
   1036 
   1037   // Decode the module, but don't verify function bodies, since we'll
   1038   // be compiling them anyway.
   1039   ModuleResult decoding_result =
   1040       DecodeWasmModule(isolate, &zone, module_start, module_end, false,
   1041                        asm_js ? kAsmJsOrigin : kWasmOrigin);
   1042 
   1043   std::unique_ptr<const WasmModule> module(decoding_result.val);
   1044   if (decoding_result.failed()) {
   1045     // Module verification failed. throw.
   1046     thrower.Error("WASM.compileRun() failed: %s",
   1047                   decoding_result.error_msg.get());
   1048     return -1;
   1049   }
   1050 
   1051   if (module->import_table.size() > 0) {
   1052     thrower.Error("Not supported: module has imports.");
   1053   }
   1054   if (module->export_table.size() == 0) {
   1055     thrower.Error("Not supported: module has no exports.");
   1056   }
   1057 
   1058   if (thrower.error()) return -1;
   1059 
   1060   Handle<JSObject> instance =
   1061       module
   1062           ->Instantiate(isolate, Handle<JSReceiver>::null(),
   1063                         Handle<JSArrayBuffer>::null())
   1064           .ToHandleChecked();
   1065 
   1066   Handle<Name> exports = isolate->factory()->InternalizeUtf8String("exports");
   1067   Handle<JSObject> exports_object = Handle<JSObject>::cast(
   1068       JSObject::GetProperty(instance, exports).ToHandleChecked());
   1069   Handle<Name> main_name = isolate->factory()->NewStringFromStaticChars("main");
   1070   PropertyDescriptor desc;
   1071   Maybe<bool> property_found = JSReceiver::GetOwnPropertyDescriptor(
   1072       isolate, exports_object, main_name, &desc);
   1073   if (!property_found.FromMaybe(false)) return -1;
   1074 
   1075   Handle<JSFunction> main_export = Handle<JSFunction>::cast(desc.value());
   1076 
   1077   // Call the JS function.
   1078   Handle<Object> undefined = isolate->factory()->undefined_value();
   1079   MaybeHandle<Object> retval =
   1080       Execution::Call(isolate, main_export, undefined, 0, nullptr);
   1081 
   1082   // The result should be a number.
   1083   if (retval.is_null()) {
   1084     thrower.Error("WASM.compileRun() failed: Invocation was null");
   1085     return -1;
   1086   }
   1087   Handle<Object> result = retval.ToHandleChecked();
   1088   if (result->IsSmi()) {
   1089     return Smi::cast(*result)->value();
   1090   }
   1091   if (result->IsHeapNumber()) {
   1092     return static_cast<int32_t>(HeapNumber::cast(*result)->value());
   1093   }
   1094   thrower.Error("WASM.compileRun() failed: Return value should be number");
   1095   return -1;
   1096 }
   1097 
   1098 }  // namespace testing
   1099 }  // namespace wasm
   1100 }  // namespace internal
   1101 }  // namespace v8
   1102