LCOV - code coverage report
Current view: top level - src/wasm - module-compiler.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 568 585 97.1 %
Date: 2019-02-19 Functions: 94 106 88.7 %

          Line data    Source code
       1             : // Copyright 2017 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/wasm/module-compiler.h"
       6             : 
       7             : #include "src/api.h"
       8             : #include "src/asmjs/asm-js.h"
       9             : #include "src/base/enum-set.h"
      10             : #include "src/base/optional.h"
      11             : #include "src/base/template-utils.h"
      12             : #include "src/base/utils/random-number-generator.h"
      13             : #include "src/compiler/wasm-compiler.h"
      14             : #include "src/counters.h"
      15             : #include "src/heap/heap-inl.h"  // For CodeSpaceMemoryModificationScope.
      16             : #include "src/identity-map.h"
      17             : #include "src/property-descriptor.h"
      18             : #include "src/task-utils.h"
      19             : #include "src/tracing/trace-event.h"
      20             : #include "src/trap-handler/trap-handler.h"
      21             : #include "src/wasm/js-to-wasm-wrapper-cache-inl.h"
      22             : #include "src/wasm/module-decoder.h"
      23             : #include "src/wasm/streaming-decoder.h"
      24             : #include "src/wasm/wasm-code-manager.h"
      25             : #include "src/wasm/wasm-engine.h"
      26             : #include "src/wasm/wasm-import-wrapper-cache-inl.h"
      27             : #include "src/wasm/wasm-js.h"
      28             : #include "src/wasm/wasm-limits.h"
      29             : #include "src/wasm/wasm-memory.h"
      30             : #include "src/wasm/wasm-objects-inl.h"
      31             : #include "src/wasm/wasm-result.h"
      32             : #include "src/wasm/wasm-serialization.h"
      33             : 
      34             : #define TRACE_COMPILE(...)                             \
      35             :   do {                                                 \
      36             :     if (FLAG_trace_wasm_compiler) PrintF(__VA_ARGS__); \
      37             :   } while (false)
      38             : 
      39             : #define TRACE_STREAMING(...)                            \
      40             :   do {                                                  \
      41             :     if (FLAG_trace_wasm_streaming) PrintF(__VA_ARGS__); \
      42             :   } while (false)
      43             : 
      44             : #define TRACE_LAZY(...)                                        \
      45             :   do {                                                         \
      46             :     if (FLAG_trace_wasm_lazy_compilation) PrintF(__VA_ARGS__); \
      47             :   } while (false)
      48             : 
      49             : namespace v8 {
      50             : namespace internal {
      51             : namespace wasm {
      52             : 
      53             : namespace {
      54             : 
      55             : enum class CompileMode : uint8_t { kRegular, kTiering };
      56             : 
      57             : // Background compile jobs hold a shared pointer to this token. The token is
      58             : // used to notify them that they should stop. As soon as they see this (after
      59             : // finishing their current compilation unit), they will stop.
      60             : // This allows to already remove the NativeModule without having to synchronize
      61             : // on background compile jobs.
      62     1240023 : class BackgroundCompileToken {
      63             :  public:
      64             :   explicit BackgroundCompileToken(NativeModule* native_module)
      65     1240023 :       : native_module_(native_module) {}
      66             : 
      67             :   void Cancel() {
      68     1240212 :     base::MutexGuard mutex_guard(&mutex_);
      69     1240212 :     native_module_ = nullptr;
      70             :   }
      71             : 
      72             :   // Only call this while holding the {mutex_}.
      73         243 :   void CancelLocked() { native_module_ = nullptr; }
      74             : 
      75             :  private:
      76             :   friend class BackgroundCompileScope;
      77             :   base::Mutex mutex_;
      78             :   NativeModule* native_module_;
      79             : 
      80             :   NativeModule* StartScope() {
      81      426506 :     mutex_.Lock();
      82      426663 :     return native_module_;
      83             :   }
      84             : 
      85      426663 :   void ExitScope() { mutex_.Unlock(); }
      86             : };
      87             : 
      88             : class CompilationStateImpl;
      89             : 
      90             : // Keep these scopes short, as they hold the mutex of the token, which
      91             : // sequentializes all these scopes. The mutex is also acquired from foreground
      92             : // tasks, which should not be blocked for a long time.
      93             : class BackgroundCompileScope {
      94             :  public:
      95             :   explicit BackgroundCompileScope(
      96             :       const std::shared_ptr<BackgroundCompileToken>& token)
      97      426506 :       : token_(token.get()), native_module_(token->StartScope()) {}
      98             : 
      99             :   ~BackgroundCompileScope() { token_->ExitScope(); }
     100             : 
     101             :   bool cancelled() const { return native_module_ == nullptr; }
     102             : 
     103             :   NativeModule* native_module() {
     104             :     DCHECK(!cancelled());
     105             :     return native_module_;
     106             :   }
     107             : 
     108             :   inline CompilationStateImpl* compilation_state();
     109             : 
     110             :  private:
     111             :   BackgroundCompileToken* const token_;
     112             :   NativeModule* const native_module_;
     113             : };
     114             : 
     115             : // The {CompilationStateImpl} keeps track of the compilation state of the
     116             : // owning NativeModule, i.e. which functions are left to be compiled.
     117             : // It contains a task manager to allow parallel and asynchronous background
     118             : // compilation of functions.
     119             : // It's public interface {CompilationState} lives in compilation-environment.h.
     120             : class CompilationStateImpl {
     121             :  public:
     122             :   CompilationStateImpl(NativeModule*, std::shared_ptr<Counters> async_counters);
     123             :   ~CompilationStateImpl();
     124             : 
     125             :   // Cancel all background compilation and wait for all tasks to finish. Call
     126             :   // this before destructing this object.
     127             :   void AbortCompilation();
     128             : 
     129             :   // Set the number of compilations unit expected to be executed. Needs to be
     130             :   // set before {AddCompilationUnits} is run, which triggers background
     131             :   // compilation.
     132             :   void SetNumberOfFunctionsToCompile(size_t num_functions);
     133             : 
     134             :   // Add the callback function to be called on compilation events. Needs to be
     135             :   // set before {AddCompilationUnits} is run.
     136             :   void AddCallback(CompilationState::callback_t);
     137             : 
     138             :   // Inserts new functions to compile and kicks off compilation.
     139             :   void AddCompilationUnits(
     140             :       std::vector<std::unique_ptr<WasmCompilationUnit>>& baseline_units,
     141             :       std::vector<std::unique_ptr<WasmCompilationUnit>>& tiering_units);
     142             :   std::unique_ptr<WasmCompilationUnit> GetNextCompilationUnit();
     143             : 
     144             :   void OnFinishedUnit(ExecutionTier, WasmCode*);
     145             : 
     146             :   void ReportDetectedFeatures(const WasmFeatures& detected);
     147             :   void OnBackgroundTaskStopped(const WasmFeatures& detected);
     148             :   void PublishDetectedFeatures(Isolate* isolate, const WasmFeatures& detected);
     149             :   void RestartBackgroundCompileTask();
     150             :   void RestartBackgroundTasks();
     151             : 
     152             :   void SetError(uint32_t func_index, const WasmError& error);
     153             : 
     154             :   bool failed() const {
     155        8056 :     return compile_error_.load(std::memory_order_relaxed) != nullptr;
     156             :   }
     157             : 
     158      919861 :   bool baseline_compilation_finished() const {
     159      919861 :     base::MutexGuard guard(&mutex_);
     160     1819725 :     return outstanding_baseline_units_ == 0 ||
     161     1797184 :            (compile_mode_ == CompileMode::kTiering &&
     162     1817181 :             outstanding_tiering_units_ == 0);
     163             :   }
     164             : 
     165             :   CompileMode compile_mode() const { return compile_mode_; }
     166             :   WasmFeatures* detected_features() { return &detected_features_; }
     167             : 
     168             :   // Call {GetCompileError} from foreground threads only, since we access
     169             :   // NativeModule::wire_bytes, which is set from the foreground thread once the
     170             :   // stream has finished.
     171       13018 :   WasmError GetCompileError() {
     172             :     CompilationError* error = compile_error_.load(std::memory_order_acquire);
     173             :     DCHECK_NOT_NULL(error);
     174       13018 :     std::ostringstream error_msg;
     175       13018 :     error_msg << "Compiling wasm function \"";
     176       13018 :     wasm::ModuleWireBytes wire_bytes(native_module_->wire_bytes());
     177             :     wasm::WireBytesRef name_ref = native_module_->module()->LookupFunctionName(
     178       26036 :         wire_bytes, error->func_index);
     179       13018 :     if (name_ref.is_set()) {
     180         272 :       wasm::WasmName name = wire_bytes.GetNameOrNull(name_ref);
     181         544 :       error_msg.write(name.start(), name.length());
     182             :     } else {
     183       25492 :       error_msg << "wasm-function[" << error->func_index << "]";
     184             :     }
     185       26036 :     error_msg << "\" failed: " << error->error.message();
     186       13018 :     return WasmError{error->error.offset(), error_msg.str()};
     187             :   }
     188             : 
     189     2336214 :   void SetWireBytesStorage(
     190             :       std::shared_ptr<WireBytesStorage> wire_bytes_storage) {
     191     2336214 :     base::MutexGuard guard(&mutex_);
     192             :     wire_bytes_storage_ = wire_bytes_storage;
     193     2336214 :   }
     194             : 
     195      906332 :   std::shared_ptr<WireBytesStorage> GetWireBytesStorage() const {
     196      906332 :     base::MutexGuard guard(&mutex_);
     197             :     DCHECK_NOT_NULL(wire_bytes_storage_);
     198      906339 :     return wire_bytes_storage_;
     199             :   }
     200             : 
     201             :  private:
     202             :   struct CompilationError {
     203             :     uint32_t const func_index;
     204             :     WasmError const error;
     205             :     CompilationError(uint32_t func_index, WasmError error)
     206        6646 :         : func_index(func_index), error(std::move(error)) {}
     207             :   };
     208             : 
     209             :   void NotifyOnEvent(CompilationEvent event);
     210             : 
     211             :   NativeModule* const native_module_;
     212             :   const std::shared_ptr<BackgroundCompileToken> background_compile_token_;
     213             :   const CompileMode compile_mode_;
     214             :   const std::shared_ptr<Counters> async_counters_;
     215             : 
     216             :   // Compilation error, atomically updated, but at most once (nullptr -> error).
     217             :   // Uses acquire-release semantics (acquire on load, release on update).
     218             :   // For checking whether an error is set, relaxed semantics can be used.
     219             :   std::atomic<CompilationError*> compile_error_{nullptr};
     220             : 
     221             :   // This mutex protects all information of this {CompilationStateImpl} which is
     222             :   // being accessed concurrently.
     223             :   mutable base::Mutex mutex_;
     224             : 
     225             :   //////////////////////////////////////////////////////////////////////////////
     226             :   // Protected by {mutex_}:
     227             : 
     228             :   std::vector<std::unique_ptr<WasmCompilationUnit>> baseline_compilation_units_;
     229             :   std::vector<std::unique_ptr<WasmCompilationUnit>> tiering_compilation_units_;
     230             : 
     231             :   int num_background_tasks_ = 0;
     232             : 
     233             :   // Features detected to be used in this module. Features can be detected
     234             :   // as a module is being compiled.
     235             :   WasmFeatures detected_features_ = kNoWasmFeatures;
     236             : 
     237             :   // Abstraction over the storage of the wire bytes. Held in a shared_ptr so
     238             :   // that background compilation jobs can keep the storage alive while
     239             :   // compiling.
     240             :   std::shared_ptr<WireBytesStorage> wire_bytes_storage_;
     241             : 
     242             :   size_t outstanding_baseline_units_ = 0;
     243             :   size_t outstanding_tiering_units_ = 0;
     244             : 
     245             :   // End of fields protected by {mutex_}.
     246             :   //////////////////////////////////////////////////////////////////////////////
     247             : 
     248             :   // Callback functions to be called on compilation events. Only accessible from
     249             :   // the foreground thread.
     250             :   std::vector<CompilationState::callback_t> callbacks_;
     251             : 
     252             :   const int max_background_tasks_ = 0;
     253             : };
     254             : 
     255             : CompilationStateImpl* Impl(CompilationState* compilation_state) {
     256             :   return reinterpret_cast<CompilationStateImpl*>(compilation_state);
     257             : }
     258             : const CompilationStateImpl* Impl(const CompilationState* compilation_state) {
     259             :   return reinterpret_cast<const CompilationStateImpl*>(compilation_state);
     260             : }
     261             : 
     262             : CompilationStateImpl* BackgroundCompileScope::compilation_state() {
     263             :   return Impl(native_module()->compilation_state());
     264             : }
     265             : 
     266             : void UpdateFeatureUseCounts(Isolate* isolate, const WasmFeatures& detected) {
     267      142733 :   if (detected.threads) {
     268        1232 :     isolate->CountUsage(v8::Isolate::UseCounterFeature::kWasmThreadOpcodes);
     269             :   }
     270             : }
     271             : 
     272             : }  // namespace
     273             : 
     274             : //////////////////////////////////////////////////////
     275             : // PIMPL implementation of {CompilationState}.
     276             : 
     277     1240023 : CompilationState::~CompilationState() { Impl(this)->~CompilationStateImpl(); }
     278             : 
     279     1240023 : void CompilationState::AbortCompilation() { Impl(this)->AbortCompilation(); }
     280             : 
     281        6646 : void CompilationState::SetError(uint32_t func_index, const WasmError& error) {
     282        6646 :   Impl(this)->SetError(func_index, error);
     283        6646 : }
     284             : 
     285     2336214 : void CompilationState::SetWireBytesStorage(
     286             :     std::shared_ptr<WireBytesStorage> wire_bytes_storage) {
     287     4672428 :   Impl(this)->SetWireBytesStorage(std::move(wire_bytes_storage));
     288     2336214 : }
     289             : 
     290      861489 : std::shared_ptr<WireBytesStorage> CompilationState::GetWireBytesStorage()
     291             :     const {
     292      869529 :   return Impl(this)->GetWireBytesStorage();
     293             : }
     294             : 
     295           4 : void CompilationState::AddCallback(CompilationState::callback_t callback) {
     296           8 :   return Impl(this)->AddCallback(std::move(callback));
     297             : }
     298             : 
     299          32 : bool CompilationState::failed() const { return Impl(this)->failed(); }
     300             : 
     301           0 : void CompilationState::OnFinishedUnit(ExecutionTier tier, WasmCode* code) {
     302           0 :   Impl(this)->OnFinishedUnit(tier, code);
     303           0 : }
     304             : 
     305             : // static
     306     1240023 : std::unique_ptr<CompilationState> CompilationState::New(
     307             :     NativeModule* native_module, std::shared_ptr<Counters> async_counters) {
     308             :   return std::unique_ptr<CompilationState>(reinterpret_cast<CompilationState*>(
     309     2480046 :       new CompilationStateImpl(native_module, std::move(async_counters))));
     310             : }
     311             : 
     312             : // End of PIMPL implementation of {CompilationState}.
     313             : //////////////////////////////////////////////////////
     314             : 
     315        8040 : WasmCode* LazyCompileFunction(Isolate* isolate, NativeModule* native_module,
     316             :                               int func_index) {
     317             :   base::ElapsedTimer compilation_timer;
     318             :   DCHECK(!native_module->has_code(static_cast<uint32_t>(func_index)));
     319             : 
     320             :   compilation_timer.Start();
     321             : 
     322             :   TRACE_LAZY("Compiling wasm-function#%d.\n", func_index);
     323             : 
     324             :   const uint8_t* module_start = native_module->wire_bytes().start();
     325             : 
     326       16080 :   const WasmFunction* func = &native_module->module()->functions[func_index];
     327             :   FunctionBody func_body{func->sig, func->code.offset(),
     328             :                          module_start + func->code.offset(),
     329             :                          module_start + func->code.end_offset()};
     330             : 
     331             :   ExecutionTier tier =
     332        8040 :       WasmCompilationUnit::GetDefaultExecutionTier(native_module->module());
     333        8040 :   WasmCompilationUnit unit(isolate->wasm_engine(), func_index, tier);
     334        8040 :   CompilationEnv env = native_module->CreateCompilationEnv();
     335             :   WasmCompilationResult result = unit.ExecuteCompilation(
     336             :       &env, native_module->compilation_state()->GetWireBytesStorage(),
     337             :       isolate->counters(),
     338       32160 :       Impl(native_module->compilation_state())->detected_features());
     339        8040 :   WasmCode* code = unit.Publish(std::move(result), native_module);
     340             : 
     341             :   // During lazy compilation, we should never get compilation errors. The module
     342             :   // was verified before starting execution with lazy compilation.
     343             :   // This might be OOM, but then we cannot continue execution anyway.
     344             :   // TODO(clemensh): According to the spec, we can actually skip validation at
     345             :   // module creation time, and return a function that always traps here.
     346        8040 :   CHECK(!native_module->compilation_state()->failed());
     347             : 
     348        8040 :   if (WasmCode::ShouldBeLogged(isolate)) code->LogCode(isolate);
     349             : 
     350             :   int64_t func_size =
     351        8040 :       static_cast<int64_t>(func->code.end_offset() - func->code.offset());
     352        8040 :   int64_t compilation_time = compilation_timer.Elapsed().InMicroseconds();
     353             : 
     354             :   auto counters = isolate->counters();
     355        8040 :   counters->wasm_lazily_compiled_functions()->Increment();
     356             : 
     357             :   counters->wasm_lazy_compilation_throughput()->AddSample(
     358        8040 :       compilation_time != 0 ? static_cast<int>(func_size / compilation_time)
     359       16080 :                             : 0);
     360             : 
     361        8040 :   return code;
     362             : }
     363             : 
     364        8040 : Address CompileLazy(Isolate* isolate, NativeModule* native_module,
     365             :                     uint32_t func_index) {
     366             :   HistogramTimerScope lazy_time_scope(
     367        8040 :       isolate->counters()->wasm_lazy_compilation_time());
     368             : 
     369             :   DCHECK(!native_module->lazy_compile_frozen());
     370             : 
     371       16080 :   NativeModuleModificationScope native_module_modification_scope(native_module);
     372             : 
     373        8040 :   WasmCode* result = LazyCompileFunction(isolate, native_module, func_index);
     374             :   DCHECK_NOT_NULL(result);
     375             :   DCHECK_EQ(func_index, result->index());
     376             : 
     377        8040 :   return result->instruction_start();
     378             : }
     379             : 
     380             : namespace {
     381             : 
     382             : // The {CompilationUnitBuilder} builds compilation units and stores them in an
     383             : // internal buffer. The buffer is moved into the working queue of the
     384             : // {CompilationStateImpl} when {Commit} is called.
     385        6243 : class CompilationUnitBuilder {
     386             :  public:
     387             :   explicit CompilationUnitBuilder(NativeModule* native_module,
     388             :                                   WasmEngine* wasm_engine)
     389             :       : native_module_(native_module),
     390             :         wasm_engine_(wasm_engine),
     391             :         default_tier_(WasmCompilationUnit::GetDefaultExecutionTier(
     392        6435 :             native_module->module())) {}
     393             : 
     394      102713 :   void AddUnit(uint32_t func_index) {
     395      102713 :     switch (compilation_state()->compile_mode()) {
     396             :       case CompileMode::kTiering:
     397             :         tiering_units_.emplace_back(
     398      205106 :             CreateUnit(func_index, ExecutionTier::kOptimized));
     399             :         baseline_units_.emplace_back(
     400      205106 :             CreateUnit(func_index, ExecutionTier::kBaseline));
     401      102553 :         return;
     402             :       case CompileMode::kRegular:
     403         480 :         baseline_units_.emplace_back(CreateUnit(func_index, default_tier_));
     404         160 :         return;
     405             :     }
     406           0 :     UNREACHABLE();
     407             :   }
     408             : 
     409       12574 :   bool Commit() {
     410        6371 :     if (baseline_units_.empty() && tiering_units_.empty()) return false;
     411       12518 :     compilation_state()->AddCompilationUnits(baseline_units_, tiering_units_);
     412        6259 :     Clear();
     413        6259 :     return true;
     414             :   }
     415             : 
     416        6303 :   void Clear() {
     417             :     baseline_units_.clear();
     418             :     tiering_units_.clear();
     419        6303 :   }
     420             : 
     421             :  private:
     422             :   std::unique_ptr<WasmCompilationUnit> CreateUnit(uint32_t func_index,
     423             :                                                   ExecutionTier tier) {
     424             :     return base::make_unique<WasmCompilationUnit>(wasm_engine_, func_index,
     425      205266 :                                                   tier);
     426             :   }
     427             : 
     428             :   CompilationStateImpl* compilation_state() const {
     429             :     return Impl(native_module_->compilation_state());
     430             :   }
     431             : 
     432             :   NativeModule* const native_module_;
     433             :   WasmEngine* const wasm_engine_;
     434             :   const ExecutionTier default_tier_;
     435             :   std::vector<std::unique_ptr<WasmCompilationUnit>> baseline_units_;
     436             :   std::vector<std::unique_ptr<WasmCompilationUnit>> tiering_units_;
     437             : };
     438             : 
     439             : bool compile_lazy(const WasmModule* module) {
     440      143151 :   return FLAG_wasm_lazy_compilation ||
     441      142663 :          (FLAG_asm_wasm_lazy_compilation && module->origin == kAsmJsOrigin);
     442             : }
     443             : 
     444      219835 : void RecordStats(const Code code, Counters* counters) {
     445      219835 :   counters->wasm_generated_code_size()->Increment(code->body_size());
     446      439673 :   counters->wasm_reloc_size()->Increment(code->relocation_info()->length());
     447      219836 : }
     448             : 
     449      228803 : double MonotonicallyIncreasingTimeInMs() {
     450      228803 :   return V8::GetCurrentPlatform()->MonotonicallyIncreasingTime() *
     451      228802 :          base::Time::kMillisecondsPerSecond;
     452             : }
     453             : 
     454             : // Run by each compilation task and by the main thread (i.e. in both
     455             : // foreground and background threads).
     456      882554 : bool FetchAndExecuteCompilationUnit(CompilationEnv* env,
     457             :                                     NativeModule* native_module,
     458             :                                     CompilationStateImpl* compilation_state,
     459             :                                     WasmFeatures* detected,
     460             :                                     Counters* counters) {
     461             :   DisallowHeapAccess no_heap_access;
     462             : 
     463             :   std::unique_ptr<WasmCompilationUnit> unit =
     464      882554 :       compilation_state->GetNextCompilationUnit();
     465      882554 :   if (unit == nullptr) return false;
     466             : 
     467             :   WasmCompilationResult result = unit->ExecuteCompilation(
     468       24576 :       env, compilation_state->GetWireBytesStorage(), counters, detected);
     469             : 
     470       12288 :   WasmCode* code = unit->Publish(std::move(result), native_module);
     471        6144 :   compilation_state->OnFinishedUnit(unit->requested_tier(), code);
     472             : 
     473             :   return true;
     474             : }
     475             : 
     476        6051 : void InitializeCompilationUnits(NativeModule* native_module,
     477             :                                 WasmEngine* wasm_engine) {
     478             :   ModuleWireBytes wire_bytes(native_module->wire_bytes());
     479             :   const WasmModule* module = native_module->module();
     480             :   CompilationUnitBuilder builder(native_module, wasm_engine);
     481        6051 :   uint32_t start = module->num_imported_functions;
     482        6051 :   uint32_t end = start + module->num_declared_functions;
     483      108340 :   for (uint32_t i = start; i < end; ++i) {
     484      102289 :     builder.AddUnit(i);
     485             :   }
     486        6051 :   builder.Commit();
     487        6051 : }
     488             : 
     489        4818 : void CompileInParallel(Isolate* isolate, NativeModule* native_module) {
     490             :   // Data structures for the parallel compilation.
     491             : 
     492             :   //-----------------------------------------------------------------------
     493             :   // For parallel compilation:
     494             :   // 1) The main thread allocates a compilation unit for each wasm function
     495             :   //    and stores them in the vector {compilation_units} within the
     496             :   //    {compilation_state}. By adding units to the {compilation_state}, new
     497             :   //    {BackgroundCompileTasks} instances are spawned which run on
     498             :   //    the background threads.
     499             :   // 2) The background threads and the main thread pick one compilation unit at
     500             :   //    a time and execute the parallel phase of the compilation unit.
     501             : 
     502             :   // Turn on the {CanonicalHandleScope} so that the background threads can
     503             :   // use the node cache.
     504        4818 :   CanonicalHandleScope canonical(isolate);
     505             : 
     506             :   CompilationStateImpl* compilation_state =
     507             :       Impl(native_module->compilation_state());
     508             :   uint32_t num_wasm_functions =
     509        4818 :       native_module->num_functions() - native_module->num_imported_functions();
     510        4818 :   compilation_state->SetNumberOfFunctionsToCompile(num_wasm_functions);
     511             : 
     512             :   // 1) The main thread allocates a compilation unit for each wasm function
     513             :   //    and stores them in the vector {compilation_units} within the
     514             :   //    {compilation_state}. By adding units to the {compilation_state}, new
     515             :   //    {BackgroundCompileTask} instances are spawned which run on
     516             :   //    background threads.
     517        4818 :   InitializeCompilationUnits(native_module, isolate->wasm_engine());
     518             : 
     519             :   // 2) The background threads and the main thread pick one compilation unit at
     520             :   //    a time and execute the parallel phase of the compilation unit.
     521        4818 :   WasmFeatures detected_features;
     522        4818 :   CompilationEnv env = native_module->CreateCompilationEnv();
     523             :   // TODO(wasm): This might already execute TurboFan units on the main thread,
     524             :   // while waiting for baseline compilation to finish. This can introduce
     525             :   // additional delay.
     526             :   // TODO(wasm): This is a busy-wait loop once all units have started executing
     527             :   // in background threads. Replace by a semaphore / barrier.
     528     1779362 :   while (!compilation_state->failed() &&
     529      887172 :          !compilation_state->baseline_compilation_finished()) {
     530             :     FetchAndExecuteCompilationUnit(&env, native_module, compilation_state,
     531      882554 :                                    &detected_features, isolate->counters());
     532             :   }
     533             : 
     534             :   // Publish features from the foreground and background tasks.
     535        4818 :   compilation_state->PublishDetectedFeatures(isolate, detected_features);
     536        4818 : }
     537             : 
     538      135722 : void CompileSequentially(Isolate* isolate, NativeModule* native_module,
     539             :                          ErrorThrower* thrower) {
     540             :   DCHECK(!thrower->error());
     541             : 
     542             :   ModuleWireBytes wire_bytes(native_module->wire_bytes());
     543             :   const WasmModule* module = native_module->module();
     544      135722 :   WasmFeatures detected = kNoWasmFeatures;
     545             :   auto* comp_state = Impl(native_module->compilation_state());
     546             :   ExecutionTier tier =
     547      135722 :       WasmCompilationUnit::GetDefaultExecutionTier(native_module->module());
     548      506718 :   for (const WasmFunction& func : module->functions) {
     549      241654 :     if (func.imported) continue;  // Imports are compiled at instantiation time.
     550             : 
     551             :     // Compile the function.
     552             :     WasmCompilationUnit::CompileWasmFunction(isolate, native_module, &detected,
     553      130366 :                                              &func, tier);
     554      130363 :     if (comp_state->failed()) {
     555       12754 :       thrower->CompileFailed(comp_state->GetCompileError());
     556        6377 :       break;
     557             :     }
     558             :   }
     559             :   UpdateFeatureUseCounts(isolate, detected);
     560      135719 : }
     561             : 
     562         624 : void ValidateSequentially(Isolate* isolate, NativeModule* native_module,
     563             :                           ErrorThrower* thrower) {
     564             :   DCHECK(!thrower->error());
     565             : 
     566             :   ModuleWireBytes wire_bytes(native_module->wire_bytes());
     567             :   const WasmModule* module = native_module->module();
     568         176 :   uint32_t start = module->num_imported_functions;
     569         176 :   uint32_t end = start + module->num_declared_functions;
     570         616 :   for (uint32_t i = start; i < end; ++i) {
     571         448 :     const WasmFunction& func = module->functions[i];
     572             : 
     573             :     const byte* base = wire_bytes.start();
     574             :     FunctionBody body{func.sig, func.code.offset(), base + func.code.offset(),
     575         448 :                       base + func.code.end_offset()};
     576             :     DecodeResult result;
     577             :     {
     578         896 :       auto time_counter = SELECT_WASM_COUNTER(
     579             :           isolate->counters(), module->origin, wasm_decode, function_time);
     580             : 
     581             :       TimedHistogramScope wasm_decode_function_time_scope(time_counter);
     582         448 :       WasmFeatures detected;
     583         896 :       result = VerifyWasmCode(isolate->allocator(),
     584         448 :                               native_module->enabled_features(), module,
     585             :                               &detected, body);
     586             :     }
     587         448 :     if (result.failed()) {
     588           8 :       TruncatedUserString<> name(wire_bytes.GetNameOrNull(&func, module));
     589             :       thrower->CompileError("Compiling function #%d:%.*s failed: %s @+%u", i,
     590             :                             name.length(), name.start(),
     591             :                             result.error().message().c_str(),
     592          16 :                             result.error().offset());
     593             :       break;
     594             :     }
     595             :   }
     596         176 : }
     597             : 
     598      143327 : void CompileNativeModule(Isolate* isolate, ErrorThrower* thrower,
     599             :                          const WasmModule* wasm_module,
     600             :                          NativeModule* native_module) {
     601             :   ModuleWireBytes wire_bytes(native_module->wire_bytes());
     602             : 
     603      143151 :   if (compile_lazy(wasm_module)) {
     604        2611 :     if (wasm_module->origin == kWasmOrigin) {
     605             :       // Validate wasm modules for lazy compilation. Don't validate asm.js
     606             :       // modules, they are valid by construction (otherwise a CHECK will fail
     607             :       // during lazy compilation).
     608             :       // TODO(clemensh): According to the spec, we can actually skip validation
     609             :       // at module creation time, and return a function that always traps at
     610             :       // (lazy) compilation time.
     611         176 :       ValidateSequentially(isolate, native_module, thrower);
     612      143325 :       if (thrower->error()) return;
     613             :     }
     614             : 
     615        2603 :     native_module->SetLazyBuiltin(BUILTIN_CODE(isolate, WasmCompileLazy));
     616             :   } else {
     617             :     size_t funcs_to_compile =
     618      281080 :         wasm_module->functions.size() - wasm_module->num_imported_functions;
     619             :     bool compile_parallel =
     620      281072 :         !FLAG_trace_wasm_decoder && FLAG_wasm_num_compilation_tasks > 0 &&
     621      145358 :         funcs_to_compile > 1 &&
     622        4818 :         V8::GetCurrentPlatform()->NumberOfWorkerThreads() > 0;
     623             : 
     624      140540 :     if (compile_parallel) {
     625        4818 :       CompileInParallel(isolate, native_module);
     626             :     } else {
     627      135722 :       CompileSequentially(isolate, native_module, thrower);
     628             :     }
     629             :     auto* compilation_state = Impl(native_module->compilation_state());
     630      140539 :     if (compilation_state->failed()) {
     631       13154 :       thrower->CompileFailed(compilation_state->GetCompileError());
     632             :     }
     633             :   }
     634             : }
     635             : 
     636             : // The runnable task that performs compilations in the background.
     637       94232 : class BackgroundCompileTask : public CancelableTask {
     638             :  public:
     639       31417 :   explicit BackgroundCompileTask(CancelableTaskManager* manager,
     640             :                                  std::shared_ptr<BackgroundCompileToken> token,
     641             :                                  std::shared_ptr<Counters> async_counters)
     642             :       : CancelableTask(manager),
     643             :         token_(std::move(token)),
     644       62834 :         async_counters_(std::move(async_counters)) {}
     645             : 
     646       31386 :   void RunInternal() override {
     647             :     TRACE_COMPILE("(3b) Compiling...\n");
     648       62773 :     TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"),
     649             :                  "BackgroundCompileTask::RunInternal");
     650             : 
     651             :     // These fields are initialized before getting the first unit of work.
     652       31387 :     base::Optional<CompilationEnv> env;
     653       31387 :     std::shared_ptr<WireBytesStorage> wire_bytes;
     654             :     std::shared_ptr<const WasmModule> module;
     655             : 
     656       31387 :     WasmFeatures detected_features = kNoWasmFeatures;
     657       31387 :     double deadline = MonotonicallyIncreasingTimeInMs() + 50.0;
     658             :     while (true) {
     659             :       // Step 1 (synchronized): Get a WasmCompilationUnit, and initialize some
     660             :       // fields if this is the first unit executed by this task.
     661             :       std::unique_ptr<WasmCompilationUnit> unit;
     662             :       {
     663             :         BackgroundCompileScope compile_scope(token_);
     664      228821 :         if (compile_scope.cancelled()) return;
     665      228075 :         if (!env.has_value()) {
     666       61332 :           env.emplace(compile_scope.native_module()->CreateCompilationEnv());
     667       61332 :           wire_bytes = compile_scope.compilation_state()->GetWireBytesStorage();
     668             :           module = compile_scope.native_module()->shared_module();
     669             :         }
     670      456149 :         unit = compile_scope.compilation_state()->GetNextCompilationUnit();
     671      228074 :         if (unit == nullptr) {
     672             :           compile_scope.compilation_state()->OnBackgroundTaskStopped(
     673       30232 :               detected_features);
     674       30233 :           return;
     675             :         }
     676             :       }
     677             : 
     678             :       // Step 2: Execute the compilation.
     679             : 
     680             :       WasmCompilationResult result = unit->ExecuteCompilation(
     681      395257 :           &env.value(), wire_bytes, async_counters_.get(), &detected_features);
     682             : 
     683             :       // Step 3 (synchronized): Publish the compilation result.
     684             :       {
     685             :         BackgroundCompileScope compile_scope(token_);
     686      197842 :         if (compile_scope.cancelled()) return;
     687             :         WasmCode* code =
     688      197689 :             unit->Publish(std::move(result), compile_scope.native_module());
     689      197689 :         if (code == nullptr) {
     690             :           compile_scope.compilation_state()->OnBackgroundTaskStopped(
     691         243 :               detected_features);
     692             :           // Also, cancel all remaining compilation.
     693         243 :           token_->CancelLocked();
     694             :           return;
     695             :         }
     696             :         compile_scope.compilation_state()->OnFinishedUnit(
     697      394892 :             unit->requested_tier(), code);
     698      197446 :         if (deadline < MonotonicallyIncreasingTimeInMs()) {
     699             :           compile_scope.compilation_state()->ReportDetectedFeatures(
     700          26 :               detected_features);
     701          26 :           compile_scope.compilation_state()->RestartBackgroundCompileTask();
     702          26 :           return;
     703             :         }
     704             :       }
     705             :     }
     706       31399 :     UNREACHABLE();  // Loop exits via explicit return.
     707             :   }
     708             : 
     709             :  private:
     710             :   std::shared_ptr<BackgroundCompileToken> token_;
     711             :   std::shared_ptr<Counters> async_counters_;
     712             : };
     713             : 
     714             : }  // namespace
     715             : 
     716      143110 : std::unique_ptr<NativeModule> CompileToNativeModule(
     717      143111 :     Isolate* isolate, const WasmFeatures& enabled, ErrorThrower* thrower,
     718             :     std::shared_ptr<const WasmModule> module, const ModuleWireBytes& wire_bytes,
     719             :     Handle<FixedArray>* export_wrappers_out) {
     720      429335 :   const WasmModule* wasm_module = module.get();
     721      143110 :   TimedHistogramScope wasm_compile_module_time_scope(SELECT_WASM_COUNTER(
     722      286220 :       isolate->counters(), wasm_module->origin, wasm_compile, module_time));
     723             : 
     724             :   // Embedder usage count for declared shared memories.
     725      143113 :   if (wasm_module->has_shared_memory) {
     726        1259 :     isolate->CountUsage(v8::Isolate::UseCounterFeature::kWasmSharedMemory);
     727             :   }
     728      143112 :   int export_wrapper_size = static_cast<int>(module->num_exported_functions);
     729             : 
     730             :   // TODO(wasm): only save the sections necessary to deserialize a
     731             :   // {WasmModule}. E.g. function bodies could be omitted.
     732             :   OwnedVector<uint8_t> wire_bytes_copy =
     733      143112 :       OwnedVector<uint8_t>::Of(wire_bytes.module_bytes());
     734             : 
     735             :   // Create and compile the native module.
     736             :   size_t code_size_estimate =
     737      143113 :       wasm::WasmCodeManager::EstimateNativeModuleCodeSize(module.get());
     738             : 
     739             :   // Create a new {NativeModule} first.
     740             :   auto native_module = isolate->wasm_engine()->NewNativeModule(
     741             :       isolate, enabled, code_size_estimate,
     742      286224 :       wasm::NativeModule::kCanAllocateMoreMemory, std::move(module));
     743      286226 :   native_module->SetWireBytes(std::move(wire_bytes_copy));
     744      143113 :   native_module->SetRuntimeStubs(isolate);
     745             : 
     746      143113 :   CompileNativeModule(isolate, thrower, wasm_module, native_module.get());
     747      143111 :   if (thrower->error()) return {};
     748             : 
     749             :   // Compile JS->wasm wrappers for exported functions.
     750             :   *export_wrappers_out =
     751      136526 :       isolate->factory()->NewFixedArray(export_wrapper_size, TENURED);
     752             :   CompileJsToWasmWrappers(isolate, native_module->module(),
     753      136528 :                           *export_wrappers_out);
     754             : 
     755             :   // Log the code within the generated module for profiling.
     756      136528 :   native_module->LogWasmCodes(isolate);
     757             : 
     758             :   return native_module;
     759             : }
     760             : 
     761          38 : void CompileNativeModuleWithExplicitBoundsChecks(Isolate* isolate,
     762             :                                                  ErrorThrower* thrower,
     763             :                                                  const WasmModule* wasm_module,
     764             :                                                  NativeModule* native_module) {
     765          38 :   native_module->DisableTrapHandler();
     766          38 :   CompileNativeModule(isolate, thrower, wasm_module, native_module);
     767          38 : }
     768             : 
     769        2503 : AsyncCompileJob::AsyncCompileJob(
     770        2503 :     Isolate* isolate, const WasmFeatures& enabled,
     771             :     std::unique_ptr<byte[]> bytes_copy, size_t length, Handle<Context> context,
     772             :     std::shared_ptr<CompilationResultResolver> resolver)
     773             :     : isolate_(isolate),
     774             :       enabled_features_(enabled),
     775             :       bytes_copy_(std::move(bytes_copy)),
     776             :       wire_bytes_(bytes_copy_.get(), bytes_copy_.get() + length),
     777       10012 :       resolver_(std::move(resolver)) {
     778             :   v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
     779        2503 :   v8::Platform* platform = V8::GetCurrentPlatform();
     780        5006 :   foreground_task_runner_ = platform->GetForegroundTaskRunner(v8_isolate);
     781             :   native_context_ =
     782        5006 :       isolate->global_handles()->Create(context->native_context());
     783             :   DCHECK(native_context_->IsNativeContext());
     784        2503 : }
     785             : 
     786        2147 : void AsyncCompileJob::Start() {
     787        6441 :   DoAsync<DecodeModule>(isolate_->counters());  // --
     788        2147 : }
     789             : 
     790          52 : void AsyncCompileJob::Abort() {
     791             :   // Removing this job will trigger the destructor, which will cancel all
     792             :   // compilation.
     793         156 :   isolate_->wasm_engine()->RemoveCompileJob(this);
     794          52 : }
     795             : 
     796        1424 : class AsyncStreamingProcessor final : public StreamingProcessor {
     797             :  public:
     798             :   explicit AsyncStreamingProcessor(AsyncCompileJob* job);
     799             : 
     800             :   bool ProcessModuleHeader(Vector<const uint8_t> bytes,
     801             :                            uint32_t offset) override;
     802             : 
     803             :   bool ProcessSection(SectionCode section_code, Vector<const uint8_t> bytes,
     804             :                       uint32_t offset) override;
     805             : 
     806             :   bool ProcessCodeSectionHeader(size_t functions_count, uint32_t offset,
     807             :                                 std::shared_ptr<WireBytesStorage>) override;
     808             : 
     809             :   bool ProcessFunctionBody(Vector<const uint8_t> bytes,
     810             :                            uint32_t offset) override;
     811             : 
     812             :   void OnFinishedChunk() override;
     813             : 
     814             :   void OnFinishedStream(OwnedVector<uint8_t> bytes) override;
     815             : 
     816             :   void OnError(const WasmError&) override;
     817             : 
     818             :   void OnAbort() override;
     819             : 
     820             :   bool Deserialize(Vector<const uint8_t> wire_bytes,
     821             :                    Vector<const uint8_t> module_bytes) override;
     822             : 
     823             :  private:
     824             :   // Finishes the AsyncCompileJob with an error.
     825             :   void FinishAsyncCompileJobWithError(const WasmError&);
     826             : 
     827             :   void CommitCompilationUnits();
     828             : 
     829             :   ModuleDecoder decoder_;
     830             :   AsyncCompileJob* job_;
     831             :   std::unique_ptr<CompilationUnitBuilder> compilation_unit_builder_;
     832             :   uint32_t next_function_ = 0;
     833             : };
     834             : 
     835         356 : std::shared_ptr<StreamingDecoder> AsyncCompileJob::CreateStreamingDecoder() {
     836             :   DCHECK_NULL(stream_);
     837             :   stream_.reset(
     838        1424 :       new StreamingDecoder(base::make_unique<AsyncStreamingProcessor>(this)));
     839         356 :   return stream_;
     840             : }
     841             : 
     842        5006 : AsyncCompileJob::~AsyncCompileJob() {
     843        2503 :   background_task_manager_.CancelAndWait();
     844             :   // If the runtime objects were not created yet, then initial compilation did
     845             :   // not finish yet. In this case we can abort compilation.
     846        4840 :   if (native_module_ && module_object_.is_null()) {
     847         141 :     Impl(native_module_->compilation_state())->AbortCompilation();
     848             :   }
     849             :   // Tell the streaming decoder that the AsyncCompileJob is not available
     850             :   // anymore.
     851             :   // TODO(ahaas): Is this notification really necessary? Check
     852             :   // https://crbug.com/888170.
     853        2503 :   if (stream_) stream_->NotifyCompilationEnded();
     854             :   CancelPendingForegroundTask();
     855        2503 :   isolate_->global_handles()->Destroy(native_context_.location());
     856        2503 :   if (!module_object_.is_null()) {
     857        2196 :     isolate_->global_handles()->Destroy(module_object_.location());
     858             :   }
     859        2503 : }
     860             : 
     861        2333 : void AsyncCompileJob::CreateNativeModule(
     862             :     std::shared_ptr<const WasmModule> module) {
     863             :   // Embedder usage count for declared shared memories.
     864        4666 :   if (module->has_shared_memory) {
     865           0 :     isolate_->CountUsage(v8::Isolate::UseCounterFeature::kWasmSharedMemory);
     866             :   }
     867             : 
     868             :   // TODO(wasm): Improve efficiency of storing module wire bytes. Only store
     869             :   // relevant sections, not function bodies
     870             : 
     871             :   // Create the module object and populate with compiled functions and
     872             :   // information needed at instantiation time.
     873             :   // TODO(clemensh): For the same module (same bytes / same hash), we should
     874             :   // only have one {WasmModuleObject}. Otherwise, we might only set
     875             :   // breakpoints on a (potentially empty) subset of the instances.
     876             :   // Create the module object.
     877             : 
     878             :   size_t code_size_estimate =
     879        2333 :       wasm::WasmCodeManager::EstimateNativeModuleCodeSize(module.get());
     880        9332 :   native_module_ = isolate_->wasm_engine()->NewNativeModule(
     881             :       isolate_, enabled_features_, code_size_estimate,
     882             :       wasm::NativeModule::kCanAllocateMoreMemory, std::move(module));
     883        6999 :   native_module_->SetWireBytes({std::move(bytes_copy_), wire_bytes_.length()});
     884        4666 :   native_module_->SetRuntimeStubs(isolate_);
     885             : 
     886        2333 :   if (stream_) stream_->NotifyNativeModuleCreated(native_module_);
     887        2333 : }
     888             : 
     889        2192 : void AsyncCompileJob::PrepareRuntimeObjects() {
     890             :   // Create heap objects for script and module bytes to be stored in the
     891             :   // module object. Asm.js is not compiled asynchronously.
     892        2192 :   const WasmModule* module = native_module_->module();
     893             :   Handle<Script> script =
     894        4384 :       CreateWasmScript(isolate_, wire_bytes_, module->source_map_url);
     895             : 
     896             :   size_t code_size_estimate =
     897        2192 :       wasm::WasmCodeManager::EstimateNativeModuleCodeSize(module);
     898             :   Handle<WasmModuleObject> module_object = WasmModuleObject::New(
     899        4384 :       isolate_, native_module_, script, code_size_estimate);
     900             : 
     901        4384 :   module_object_ = isolate_->global_handles()->Create(*module_object);
     902        2192 : }
     903             : 
     904             : // This function assumes that it is executed in a HandleScope, and that a
     905             : // context is set on the isolate.
     906        2196 : void AsyncCompileJob::FinishCompile() {
     907        2196 :   bool is_after_deserialization = !module_object_.is_null();
     908        2196 :   if (!is_after_deserialization) {
     909        2192 :     PrepareRuntimeObjects();
     910             :   }
     911             :   DCHECK(!isolate_->context().is_null());
     912             :   // Finish the wasm script now and make it public to the debugger.
     913        8784 :   Handle<Script> script(module_object_->script(), isolate_);
     914        6588 :   if (script->type() == Script::TYPE_WASM &&
     915        4392 :       module_object_->module()->source_map_url.size() != 0) {
     916             :     MaybeHandle<String> src_map_str = isolate_->factory()->NewStringFromUtf8(
     917           0 :         CStrVector(module_object_->module()->source_map_url.c_str()), TENURED);
     918           0 :     script->set_source_mapping_url(*src_map_str.ToHandleChecked());
     919             :   }
     920        4392 :   isolate_->debug()->OnAfterCompile(script);
     921             : 
     922             :   // We can only update the feature counts once the entire compile is done.
     923             :   auto compilation_state =
     924        4392 :       Impl(module_object_->native_module()->compilation_state());
     925             :   compilation_state->PublishDetectedFeatures(
     926        2196 :       isolate_, *compilation_state->detected_features());
     927             : 
     928             :   // TODO(bbudge) Allow deserialization without wrapper compilation, so we can
     929             :   // just compile wrappers here.
     930        2196 :   if (!is_after_deserialization) {
     931             :     // TODO(wasm): compiling wrappers should be made async.
     932        2192 :     CompileWrappers();
     933             :   }
     934        2196 :   FinishModule();
     935        2196 : }
     936             : 
     937         245 : void AsyncCompileJob::AsyncCompileFailed(const WasmError& error) {
     938         245 :   ErrorThrower thrower(isolate_, "WebAssembly.compile()");
     939             :   thrower.CompileFailed(error);
     940             :   // {job} keeps the {this} pointer alive.
     941             :   std::shared_ptr<AsyncCompileJob> job =
     942         735 :       isolate_->wasm_engine()->RemoveCompileJob(this);
     943         490 :   resolver_->OnCompilationFailed(thrower.Reify());
     944         245 : }
     945             : 
     946           0 : void AsyncCompileJob::AsyncCompileSucceeded(Handle<WasmModuleObject> result) {
     947        2196 :   resolver_->OnCompilationSucceeded(result);
     948           0 : }
     949             : 
     950             : class AsyncCompileJob::CompilationStateCallback {
     951             :  public:
     952             :   explicit CompilationStateCallback(AsyncCompileJob* job) : job_(job) {}
     953             : 
     954        2635 :   void operator()(CompilationEvent event) {
     955             :     // This callback is only being called from a foreground task.
     956        2635 :     switch (event) {
     957             :       case CompilationEvent::kFinishedBaselineCompilation:
     958             :         DCHECK(!last_event_.has_value());
     959        2576 :         if (job_->DecrementAndCheckFinisherCount()) {
     960        1239 :           AsyncCompileJob* job = job_;
     961        1239 :           job->foreground_task_runner_->PostTask(
     962        1240 :               MakeCancelableTask(job->isolate_, [job] {
     963        1240 :                 HandleScope scope(job->isolate_);
     964             :                 SaveAndSwitchContext saved_context(job->isolate_,
     965        2480 :                                                    *job->native_context_);
     966        1240 :                 job->FinishCompile();
     967        8679 :               }));
     968             :         }
     969             :         break;
     970             :       case CompilationEvent::kFinishedTopTierCompilation:
     971             :         DCHECK_EQ(CompilationEvent::kFinishedBaselineCompilation, last_event_);
     972             :         // This callback should not react to top tier finished callbacks, since
     973             :         // the job might already be gone then.
     974             :         break;
     975             :       case CompilationEvent::kFailedCompilation: {
     976             :         DCHECK(!last_event_.has_value());
     977             :         // Tier-up compilation should not fail if baseline compilation
     978             :         // did not fail.
     979             :         DCHECK(!Impl(job_->native_module_->compilation_state())
     980             :                     ->baseline_compilation_finished());
     981             : 
     982          64 :         AsyncCompileJob* job = job_;
     983          64 :         job->foreground_task_runner_->PostTask(
     984          64 :             MakeCancelableTask(job->isolate_, [job] {
     985          64 :               HandleScope scope(job->isolate_);
     986             :               SaveAndSwitchContext saved_context(job->isolate_,
     987         128 :                                                  *job->native_context_);
     988             :               WasmError error = Impl(job->native_module_->compilation_state())
     989         128 :                                     ->GetCompileError();
     990         128 :               return job->AsyncCompileFailed(error);
     991         384 :             }));
     992             : 
     993          64 :         break;
     994             :       }
     995             :       default:
     996           0 :         UNREACHABLE();
     997             :     }
     998             : #ifdef DEBUG
     999             :     last_event_ = event;
    1000             : #endif
    1001        2636 :   }
    1002             : 
    1003             :  private:
    1004             :   AsyncCompileJob* job_;
    1005             : #ifdef DEBUG
    1006             :   // This will be modified by different threads, but they externally
    1007             :   // synchronize, so no explicit synchronization (currently) needed here.
    1008             :   base::Optional<CompilationEvent> last_event_;
    1009             : #endif
    1010             : };
    1011             : 
    1012             : // A closure to run a compilation step (either as foreground or background
    1013             : // task) and schedule the next step(s), if any.
    1014        4642 : class AsyncCompileJob::CompileStep {
    1015             :  public:
    1016        4642 :   virtual ~CompileStep() = default;
    1017             : 
    1018        4641 :   void Run(AsyncCompileJob* job, bool on_foreground) {
    1019        4641 :     if (on_foreground) {
    1020        2494 :       HandleScope scope(job->isolate_);
    1021        2494 :       SaveAndSwitchContext saved_context(job->isolate_, *job->native_context_);
    1022        2494 :       RunInForeground(job);
    1023             :     } else {
    1024        2147 :       RunInBackground(job);
    1025             :     }
    1026        4641 :   }
    1027             : 
    1028           0 :   virtual void RunInForeground(AsyncCompileJob*) { UNREACHABLE(); }
    1029           0 :   virtual void RunInBackground(AsyncCompileJob*) { UNREACHABLE(); }
    1030             : };
    1031             : 
    1032             : class AsyncCompileJob::CompileTask : public CancelableTask {
    1033             :  public:
    1034             :   CompileTask(AsyncCompileJob* job, bool on_foreground)
    1035             :       // We only manage the background tasks with the {CancelableTaskManager} of
    1036             :       // the {AsyncCompileJob}. Foreground tasks are managed by the system's
    1037             :       // {CancelableTaskManager}. Background tasks cannot spawn tasks managed by
    1038             :       // their own task manager.
    1039        2494 :       : CancelableTask(on_foreground ? job->isolate_->cancelable_task_manager()
    1040             :                                      : &job->background_task_manager_),
    1041             :         job_(job),
    1042        6788 :         on_foreground_(on_foreground) {}
    1043             : 
    1044        9284 :   ~CompileTask() override {
    1045        4642 :     if (job_ != nullptr && on_foreground_) ResetPendingForegroundTask();
    1046        9284 :   }
    1047             : 
    1048        4641 :   void RunInternal() final {
    1049        9282 :     if (!job_) return;
    1050        4641 :     if (on_foreground_) ResetPendingForegroundTask();
    1051        9282 :     job_->step_->Run(job_, on_foreground_);
    1052             :     // After execution, reset {job_} such that we don't try to reset the pending
    1053             :     // foreground task when the task is deleted.
    1054        4641 :     job_ = nullptr;
    1055             :   }
    1056             : 
    1057             :   void Cancel() {
    1058             :     DCHECK_NOT_NULL(job_);
    1059           1 :     job_ = nullptr;
    1060             :   }
    1061             : 
    1062             :  private:
    1063             :   // {job_} will be cleared to cancel a pending task.
    1064             :   AsyncCompileJob* job_;
    1065             :   bool on_foreground_;
    1066             : 
    1067             :   void ResetPendingForegroundTask() const {
    1068             :     DCHECK_EQ(this, job_->pending_foreground_task_);
    1069        2494 :     job_->pending_foreground_task_ = nullptr;
    1070             :   }
    1071             : };
    1072             : 
    1073        2302 : void AsyncCompileJob::StartForegroundTask() {
    1074             :   DCHECK_NULL(pending_foreground_task_);
    1075             : 
    1076        2302 :   auto new_task = base::make_unique<CompileTask>(this, true);
    1077        2303 :   pending_foreground_task_ = new_task.get();
    1078        6909 :   foreground_task_runner_->PostTask(std::move(new_task));
    1079        2303 : }
    1080             : 
    1081         192 : void AsyncCompileJob::ExecuteForegroundTaskImmediately() {
    1082             :   DCHECK_NULL(pending_foreground_task_);
    1083             : 
    1084         192 :   auto new_task = base::make_unique<CompileTask>(this, true);
    1085         192 :   pending_foreground_task_ = new_task.get();
    1086         192 :   new_task->Run();
    1087         192 : }
    1088             : 
    1089           0 : void AsyncCompileJob::CancelPendingForegroundTask() {
    1090        2503 :   if (!pending_foreground_task_) return;
    1091             :   pending_foreground_task_->Cancel();
    1092           1 :   pending_foreground_task_ = nullptr;
    1093             : }
    1094             : 
    1095        2147 : void AsyncCompileJob::StartBackgroundTask() {
    1096        2147 :   auto task = base::make_unique<CompileTask>(this, false);
    1097             : 
    1098             :   // If --wasm-num-compilation-tasks=0 is passed, do only spawn foreground
    1099             :   // tasks. This is used to make timing deterministic.
    1100        2147 :   if (FLAG_wasm_num_compilation_tasks > 0) {
    1101        6441 :     V8::GetCurrentPlatform()->CallOnWorkerThread(std::move(task));
    1102             :   } else {
    1103           0 :     foreground_task_runner_->PostTask(std::move(task));
    1104             :   }
    1105        2147 : }
    1106             : 
    1107             : template <typename Step,
    1108             :           AsyncCompileJob::UseExistingForegroundTask use_existing_fg_task,
    1109             :           typename... Args>
    1110          48 : void AsyncCompileJob::DoSync(Args&&... args) {
    1111        2303 :   NextStep<Step>(std::forward<Args>(args)...);
    1112          96 :   if (use_existing_fg_task && pending_foreground_task_ != nullptr) return;
    1113        2302 :   StartForegroundTask();
    1114             : }
    1115             : 
    1116             : template <typename Step, typename... Args>
    1117             : void AsyncCompileJob::DoImmediately(Args&&... args) {
    1118         192 :   NextStep<Step>(std::forward<Args>(args)...);
    1119         192 :   ExecuteForegroundTaskImmediately();
    1120             : }
    1121             : 
    1122             : template <typename Step, typename... Args>
    1123             : void AsyncCompileJob::DoAsync(Args&&... args) {
    1124        2147 :   NextStep<Step>(std::forward<Args>(args)...);
    1125        2147 :   StartBackgroundTask();
    1126             : }
    1127             : 
    1128             : template <typename Step, typename... Args>
    1129        4642 : void AsyncCompileJob::NextStep(Args&&... args) {
    1130        4798 :   step_.reset(new Step(std::forward<Args>(args)...));
    1131        4641 : }
    1132             : 
    1133             : //==========================================================================
    1134             : // Step 1: (async) Decode the module.
    1135             : //==========================================================================
    1136        4294 : class AsyncCompileJob::DecodeModule : public AsyncCompileJob::CompileStep {
    1137             :  public:
    1138        2147 :   explicit DecodeModule(Counters* counters) : counters_(counters) {}
    1139             : 
    1140        4294 :   void RunInBackground(AsyncCompileJob* job) override {
    1141             :     ModuleResult result;
    1142             :     {
    1143             :       DisallowHandleAllocation no_handle;
    1144             :       DisallowHeapAllocation no_allocation;
    1145             :       // Decode the module bytes.
    1146             :       TRACE_COMPILE("(1) Decoding module...\n");
    1147        4294 :       TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"),
    1148             :                    "AsyncCompileJob::DecodeModule");
    1149        6441 :       result = DecodeWasmModule(
    1150             :           job->enabled_features_, job->wire_bytes_.start(),
    1151             :           job->wire_bytes_.end(), false, kWasmOrigin, counters_,
    1152        4294 :           job->isolate()->wasm_engine()->allocator());
    1153             :     }
    1154        2147 :     if (result.failed()) {
    1155             :       // Decoding failure; reject the promise and clean up.
    1156             :       job->DoSync<DecodeFail>(std::move(result).error());
    1157             :     } else {
    1158             :       // Decode passed.
    1159        4244 :       job->DoSync<PrepareAndStartCompile>(std::move(result).value(), true);
    1160        2147 :     }
    1161        2147 :   }
    1162             : 
    1163             :  private:
    1164             :   Counters* const counters_;
    1165             : };
    1166             : 
    1167             : //==========================================================================
    1168             : // Step 1b: (sync) Fail decoding the module.
    1169             : //==========================================================================
    1170         362 : class AsyncCompileJob::DecodeFail : public CompileStep {
    1171             :  public:
    1172         181 :   explicit DecodeFail(WasmError error) : error_(std::move(error)) {}
    1173             : 
    1174             :  private:
    1175             :   WasmError error_;
    1176             : 
    1177         181 :   void RunInForeground(AsyncCompileJob* job) override {
    1178             :     TRACE_COMPILE("(1b) Decoding failed.\n");
    1179             :     // {job_} is deleted in AsyncCompileFailed, therefore the {return}.
    1180         181 :     return job->AsyncCompileFailed(error_);
    1181             :   }
    1182             : };
    1183             : 
    1184             : //==========================================================================
    1185             : // Step 2 (sync): Create heap-allocated data and start compile.
    1186             : //==========================================================================
    1187        4628 : class AsyncCompileJob::PrepareAndStartCompile : public CompileStep {
    1188             :  public:
    1189             :   PrepareAndStartCompile(std::shared_ptr<const WasmModule> module,
    1190             :                          bool start_compilation)
    1191        4628 :       : module_(std::move(module)), start_compilation_(start_compilation) {}
    1192             : 
    1193             :  private:
    1194             :   std::shared_ptr<const WasmModule> module_;
    1195             :   bool start_compilation_;
    1196             : 
    1197        3546 :   void RunInForeground(AsyncCompileJob* job) override {
    1198             :     TRACE_COMPILE("(2) Prepare and start compile...\n");
    1199             : 
    1200             :     // Make sure all compilation tasks stopped running. Decoding (async step)
    1201             :     // is done.
    1202        2313 :     job->background_task_manager_.CancelAndWait();
    1203             : 
    1204        4626 :     job->CreateNativeModule(module_);
    1205             : 
    1206             :     size_t num_functions =
    1207        5859 :         module_->functions.size() - module_->num_imported_functions;
    1208             : 
    1209        2313 :     if (num_functions == 0) {
    1210             :       // Degenerate case of an empty module.
    1211         888 :       job->FinishCompile();
    1212        3201 :       return;
    1213             :     }
    1214             : 
    1215             :     CompilationStateImpl* compilation_state =
    1216        2658 :         Impl(job->native_module_->compilation_state());
    1217        1425 :     compilation_state->AddCallback(CompilationStateCallback{job});
    1218        1425 :     if (start_compilation_) {
    1219             :       // TODO(ahaas): Try to remove the {start_compilation_} check when
    1220             :       // streaming decoding is done in the background. If
    1221             :       // InitializeCompilationUnits always returns 0 for streaming compilation,
    1222             :       // then DoAsync would do the same as NextStep already.
    1223             : 
    1224             :       compilation_state->SetNumberOfFunctionsToCompile(
    1225        1233 :           module_->num_declared_functions);
    1226             :       // Add compilation units and kick off compilation.
    1227             :       InitializeCompilationUnits(job->native_module_.get(),
    1228        1233 :                                  job->isolate()->wasm_engine());
    1229             :     }
    1230             :   }
    1231             : };
    1232             : 
    1233        2192 : void AsyncCompileJob::CompileWrappers() {
    1234             :   // TODO(wasm): Compile all wrappers here, including the start function wrapper
    1235             :   // and the wrappers for the function table elements.
    1236             :   TRACE_COMPILE("(5) Compile wrappers...\n");
    1237             :   // Compile JS->wasm wrappers for exported functions.
    1238             :   CompileJsToWasmWrappers(isolate_, module_object_->native_module()->module(),
    1239        8768 :                           handle(module_object_->export_wrappers(), isolate_));
    1240        2192 : }
    1241             : 
    1242        2196 : void AsyncCompileJob::FinishModule() {
    1243             :   TRACE_COMPILE("(6) Finish module...\n");
    1244             :   AsyncCompileSucceeded(module_object_);
    1245             : 
    1246        2196 :   size_t num_functions = native_module_->num_functions() -
    1247             :                          native_module_->num_imported_functions();
    1248        2196 :   auto* compilation_state = Impl(native_module_->compilation_state());
    1249        2196 :   if (compilation_state->compile_mode() == CompileMode::kRegular ||
    1250             :       num_functions == 0) {
    1251             :     // If we do not tier up, the async compile job is done here and
    1252             :     // can be deleted.
    1253        2772 :     isolate_->wasm_engine()->RemoveCompileJob(this);
    1254        3120 :     return;
    1255             :   }
    1256             :   DCHECK_EQ(CompileMode::kTiering, compilation_state->compile_mode());
    1257        1272 :   if (compilation_state->baseline_compilation_finished()) {
    1258        3816 :     isolate_->wasm_engine()->RemoveCompileJob(this);
    1259             :   }
    1260             : }
    1261             : 
    1262           0 : AsyncStreamingProcessor::AsyncStreamingProcessor(AsyncCompileJob* job)
    1263             :     : decoder_(job->enabled_features_),
    1264             :       job_(job),
    1265         356 :       compilation_unit_builder_(nullptr) {}
    1266             : 
    1267         156 : void AsyncStreamingProcessor::FinishAsyncCompileJobWithError(
    1268             :     const WasmError& error) {
    1269             :   DCHECK(error.has_error());
    1270             :   // Make sure all background tasks stopped executing before we change the state
    1271             :   // of the AsyncCompileJob to DecodeFail.
    1272         156 :   job_->background_task_manager_.CancelAndWait();
    1273             : 
    1274             :   // Check if there is already a CompiledModule, in which case we have to clean
    1275             :   // up the CompilationStateImpl as well.
    1276         156 :   if (job_->native_module_) {
    1277          48 :     Impl(job_->native_module_->compilation_state())->AbortCompilation();
    1278             : 
    1279             :     job_->DoSync<AsyncCompileJob::DecodeFail,
    1280          48 :                  AsyncCompileJob::kUseExistingForegroundTask>(error);
    1281             : 
    1282             :     // Clear the {compilation_unit_builder_} if it exists. This is needed
    1283             :     // because there is a check in the destructor of the
    1284             :     // {CompilationUnitBuilder} that it is empty.
    1285          48 :     if (compilation_unit_builder_) compilation_unit_builder_->Clear();
    1286             :   } else {
    1287             :     job_->DoSync<AsyncCompileJob::DecodeFail>(error);
    1288             :   }
    1289         156 : }
    1290             : 
    1291             : // Process the module header.
    1292         328 : bool AsyncStreamingProcessor::ProcessModuleHeader(Vector<const uint8_t> bytes,
    1293             :                                                   uint32_t offset) {
    1294             :   TRACE_STREAMING("Process module header...\n");
    1295             :   decoder_.StartDecoding(job_->isolate()->counters(),
    1296         984 :                          job_->isolate()->wasm_engine()->allocator());
    1297         328 :   decoder_.DecodeModuleHeader(bytes, offset);
    1298         328 :   if (!decoder_.ok()) {
    1299          16 :     FinishAsyncCompileJobWithError(decoder_.FinishDecoding(false).error());
    1300          16 :     return false;
    1301             :   }
    1302             :   return true;
    1303             : }
    1304             : 
    1305             : // Process all sections except for the code section.
    1306         724 : bool AsyncStreamingProcessor::ProcessSection(SectionCode section_code,
    1307             :                                              Vector<const uint8_t> bytes,
    1308             :                                              uint32_t offset) {
    1309             :   TRACE_STREAMING("Process section %d ...\n", section_code);
    1310         724 :   if (compilation_unit_builder_) {
    1311             :     // We reached a section after the code section, we do not need the
    1312             :     // compilation_unit_builder_ anymore.
    1313             :     CommitCompilationUnits();
    1314             :     compilation_unit_builder_.reset();
    1315             :   }
    1316         724 :   if (section_code == SectionCode::kUnknownSectionCode) {
    1317             :     Decoder decoder(bytes, offset);
    1318             :     section_code = ModuleDecoder::IdentifyUnknownSection(
    1319          56 :         decoder, bytes.start() + bytes.length());
    1320          56 :     if (section_code == SectionCode::kUnknownSectionCode) {
    1321             :       // Skip unknown sections that we do not know how to handle.
    1322             :       return true;
    1323             :     }
    1324             :     // Remove the unknown section tag from the payload bytes.
    1325         112 :     offset += decoder.position();
    1326          56 :     bytes = bytes.SubVector(decoder.position(), bytes.size());
    1327             :   }
    1328             :   constexpr bool verify_functions = false;
    1329         724 :   decoder_.DecodeSection(section_code, bytes, offset, verify_functions);
    1330         724 :   if (!decoder_.ok()) {
    1331          20 :     FinishAsyncCompileJobWithError(decoder_.FinishDecoding(false).error());
    1332          20 :     return false;
    1333             :   }
    1334             :   return true;
    1335             : }
    1336             : 
    1337             : // Start the code section.
    1338         204 : bool AsyncStreamingProcessor::ProcessCodeSectionHeader(
    1339             :     size_t functions_count, uint32_t offset,
    1340             :     std::shared_ptr<WireBytesStorage> wire_bytes_storage) {
    1341             :   TRACE_STREAMING("Start the code section with %zu functions...\n",
    1342             :                   functions_count);
    1343         204 :   if (!decoder_.CheckFunctionsCount(static_cast<uint32_t>(functions_count),
    1344         204 :                                     offset)) {
    1345          12 :     FinishAsyncCompileJobWithError(decoder_.FinishDecoding(false).error());
    1346          12 :     return false;
    1347             :   }
    1348             :   // Execute the PrepareAndStartCompile step immediately and not in a separate
    1349             :   // task.
    1350             :   job_->DoImmediately<AsyncCompileJob::PrepareAndStartCompile>(
    1351         576 :       decoder_.shared_module(), false);
    1352             :   job_->native_module_->compilation_state()->SetWireBytesStorage(
    1353         960 :       std::move(wire_bytes_storage));
    1354             : 
    1355         192 :   auto* compilation_state = Impl(job_->native_module_->compilation_state());
    1356         192 :   compilation_state->SetNumberOfFunctionsToCompile(functions_count);
    1357             : 
    1358             :   // Set outstanding_finishers_ to 2, because both the AsyncCompileJob and the
    1359             :   // AsyncStreamingProcessor have to finish.
    1360         192 :   job_->outstanding_finishers_.store(2);
    1361             :   compilation_unit_builder_.reset(new CompilationUnitBuilder(
    1362         384 :       job_->native_module_.get(), job_->isolate()->wasm_engine()));
    1363             :   return true;
    1364             : }
    1365             : 
    1366             : // Process a function body.
    1367         424 : bool AsyncStreamingProcessor::ProcessFunctionBody(Vector<const uint8_t> bytes,
    1368             :                                                   uint32_t offset) {
    1369             :   TRACE_STREAMING("Process function body %d ...\n", next_function_);
    1370             : 
    1371             :   decoder_.DecodeFunctionBody(
    1372         848 :       next_function_, static_cast<uint32_t>(bytes.length()), offset, false);
    1373             : 
    1374         848 :   uint32_t index = next_function_ + decoder_.module()->num_imported_functions;
    1375         424 :   compilation_unit_builder_->AddUnit(index);
    1376         424 :   ++next_function_;
    1377             :   // This method always succeeds. The return value is necessary to comply with
    1378             :   // the StreamingProcessor interface.
    1379         424 :   return true;
    1380             : }
    1381             : 
    1382           0 : void AsyncStreamingProcessor::CommitCompilationUnits() {
    1383             :   DCHECK(compilation_unit_builder_);
    1384         264 :   compilation_unit_builder_->Commit();
    1385           0 : }
    1386             : 
    1387         328 : void AsyncStreamingProcessor::OnFinishedChunk() {
    1388             :   TRACE_STREAMING("FinishChunk...\n");
    1389         328 :   if (compilation_unit_builder_) CommitCompilationUnits();
    1390         328 : }
    1391             : 
    1392             : // Finish the processing of the stream.
    1393         132 : void AsyncStreamingProcessor::OnFinishedStream(OwnedVector<uint8_t> bytes) {
    1394             :   TRACE_STREAMING("Finish stream...\n");
    1395         264 :   ModuleResult result = decoder_.FinishDecoding(false);
    1396         132 :   if (result.failed()) {
    1397           4 :     FinishAsyncCompileJobWithError(result.error());
    1398         136 :     return;
    1399             :   }
    1400             :   // We have to open a HandleScope and prepare the Context for
    1401             :   // CreateNativeModule, PrepareRuntimeObjects and FinishCompile as this is a
    1402             :   // callback from the embedder.
    1403         128 :   HandleScope scope(job_->isolate_);
    1404         256 :   SaveAndSwitchContext saved_context(job_->isolate_, *job_->native_context_);
    1405             : 
    1406         128 :   bool needs_finish = job_->DecrementAndCheckFinisherCount();
    1407         256 :   if (job_->native_module_ == nullptr) {
    1408             :     // We are processing a WebAssembly module without code section. Create the
    1409             :     // runtime objects now (would otherwise happen in {PrepareAndStartCompile}).
    1410          40 :     job_->CreateNativeModule(std::move(result).value());
    1411             :     DCHECK(needs_finish);
    1412             :   }
    1413         256 :   job_->wire_bytes_ = ModuleWireBytes(bytes.as_vector());
    1414         256 :   job_->native_module_->SetWireBytes(std::move(bytes));
    1415         128 :   if (needs_finish) {
    1416          64 :     job_->FinishCompile();
    1417         128 :   }
    1418             : }
    1419             : 
    1420             : // Report an error detected in the StreamingDecoder.
    1421         104 : void AsyncStreamingProcessor::OnError(const WasmError& error) {
    1422             :   TRACE_STREAMING("Stream error...\n");
    1423         104 :   FinishAsyncCompileJobWithError(error);
    1424         104 : }
    1425             : 
    1426          52 : void AsyncStreamingProcessor::OnAbort() {
    1427             :   TRACE_STREAMING("Abort stream...\n");
    1428          52 :   job_->Abort();
    1429          52 : }
    1430             : 
    1431           8 : bool AsyncStreamingProcessor::Deserialize(Vector<const uint8_t> module_bytes,
    1432             :                                           Vector<const uint8_t> wire_bytes) {
    1433             :   // DeserializeNativeModule and FinishCompile assume that they are executed in
    1434             :   // a HandleScope, and that a context is set on the isolate.
    1435          12 :   HandleScope scope(job_->isolate_);
    1436          16 :   SaveAndSwitchContext saved_context(job_->isolate_, *job_->native_context_);
    1437             : 
    1438             :   MaybeHandle<WasmModuleObject> result =
    1439           8 :       DeserializeNativeModule(job_->isolate_, module_bytes, wire_bytes);
    1440           8 :   if (result.is_null()) return false;
    1441             : 
    1442             :   job_->module_object_ =
    1443           8 :       job_->isolate_->global_handles()->Create(*result.ToHandleChecked());
    1444          12 :   job_->native_module_ = job_->module_object_->shared_native_module();
    1445           4 :   auto owned_wire_bytes = OwnedVector<uint8_t>::Of(wire_bytes);
    1446           8 :   job_->wire_bytes_ = ModuleWireBytes(owned_wire_bytes.as_vector());
    1447           8 :   job_->native_module_->SetWireBytes(std::move(owned_wire_bytes));
    1448           4 :   job_->FinishCompile();
    1449             :   return true;
    1450             : }
    1451             : 
    1452     1240023 : CompilationStateImpl::CompilationStateImpl(
    1453             :     NativeModule* native_module, std::shared_ptr<Counters> async_counters)
    1454             :     : native_module_(native_module),
    1455             :       background_compile_token_(
    1456             :           std::make_shared<BackgroundCompileToken>(native_module)),
    1457     1239933 :       compile_mode_(FLAG_wasm_tier_up &&
    1458     2479866 :                             native_module->module()->origin == kWasmOrigin
    1459             :                         ? CompileMode::kTiering
    1460             :                         : CompileMode::kRegular),
    1461             :       async_counters_(std::move(async_counters)),
    1462             :       max_background_tasks_(std::max(
    1463             :           1, std::min(FLAG_wasm_num_compilation_tasks,
    1464     9920184 :                       V8::GetCurrentPlatform()->NumberOfWorkerThreads()))) {}
    1465             : 
    1466     3720069 : CompilationStateImpl::~CompilationStateImpl() {
    1467             :   CompilationError* error = compile_error_.load(std::memory_order_acquire);
    1468     1246664 :   if (error != nullptr) delete error;
    1469     1240023 : }
    1470             : 
    1471     1240212 : void CompilationStateImpl::AbortCompilation() {
    1472     1240212 :   background_compile_token_->Cancel();
    1473             :   // No more callbacks after abort.
    1474     1240212 :   callbacks_.clear();
    1475     1240211 : }
    1476             : 
    1477        6243 : void CompilationStateImpl::SetNumberOfFunctionsToCompile(size_t num_functions) {
    1478             :   DCHECK(!failed());
    1479        6243 :   base::MutexGuard guard(&mutex_);
    1480        6243 :   outstanding_baseline_units_ = num_functions;
    1481             : 
    1482        6243 :   if (compile_mode_ == CompileMode::kTiering) {
    1483        6199 :     outstanding_tiering_units_ = num_functions;
    1484             :   }
    1485        6243 : }
    1486             : 
    1487             : void CompilationStateImpl::AddCallback(CompilationState::callback_t callback) {
    1488        1429 :   callbacks_.emplace_back(std::move(callback));
    1489             : }
    1490             : 
    1491        6259 : void CompilationStateImpl::AddCompilationUnits(
    1492             :     std::vector<std::unique_ptr<WasmCompilationUnit>>& baseline_units,
    1493             :     std::vector<std::unique_ptr<WasmCompilationUnit>>& tiering_units) {
    1494             :   {
    1495        6259 :     base::MutexGuard guard(&mutex_);
    1496             : 
    1497        6259 :     if (compile_mode_ == CompileMode::kTiering) {
    1498             :       DCHECK_EQ(baseline_units.size(), tiering_units.size());
    1499             :       DCHECK_EQ(tiering_units.back()->requested_tier(),
    1500             :                 ExecutionTier::kOptimized);
    1501             :       tiering_compilation_units_.insert(
    1502             :           tiering_compilation_units_.end(),
    1503             :           std::make_move_iterator(tiering_units.begin()),
    1504        6215 :           std::make_move_iterator(tiering_units.end()));
    1505             :     } else {
    1506             :       DCHECK(tiering_compilation_units_.empty());
    1507             :     }
    1508             : 
    1509             :     baseline_compilation_units_.insert(
    1510             :         baseline_compilation_units_.end(),
    1511             :         std::make_move_iterator(baseline_units.begin()),
    1512        6259 :         std::make_move_iterator(baseline_units.end()));
    1513             :   }
    1514             : 
    1515        6259 :   RestartBackgroundTasks();
    1516        6259 : }
    1517             : 
    1518             : std::unique_ptr<WasmCompilationUnit>
    1519     1110615 : CompilationStateImpl::GetNextCompilationUnit() {
    1520     1110615 :   base::MutexGuard guard(&mutex_);
    1521             : 
    1522             :   std::vector<std::unique_ptr<WasmCompilationUnit>>& units =
    1523             :       baseline_compilation_units_.empty() ? tiering_compilation_units_
    1524     1110629 :                                           : baseline_compilation_units_;
    1525             : 
    1526     1110629 :   if (!units.empty()) {
    1527             :     std::unique_ptr<WasmCompilationUnit> unit = std::move(units.back());
    1528      203986 :     units.pop_back();
    1529             :     return unit;
    1530             :   }
    1531             : 
    1532             :   return std::unique_ptr<WasmCompilationUnit>();
    1533             : }
    1534             : 
    1535      203587 : void CompilationStateImpl::OnFinishedUnit(ExecutionTier tier, WasmCode* code) {
    1536             :   // This mutex guarantees that events happen in the right order.
    1537      203587 :   base::MutexGuard guard(&mutex_);
    1538             : 
    1539             :   // If we are *not* compiling in tiering mode, then all units are counted as
    1540             :   // baseline units.
    1541      203589 :   bool is_tiering_mode = compile_mode_ == CompileMode::kTiering;
    1542      203589 :   bool is_tiering_unit = is_tiering_mode && tier == ExecutionTier::kOptimized;
    1543             : 
    1544             :   // Sanity check: If we are not in tiering mode, there cannot be outstanding
    1545             :   // tiering units.
    1546             :   DCHECK_IMPLIES(!is_tiering_mode, outstanding_tiering_units_ == 0);
    1547             : 
    1548      203589 :   if (is_tiering_unit) {
    1549             :     DCHECK_LT(0, outstanding_tiering_units_);
    1550      101468 :     --outstanding_tiering_units_;
    1551      101468 :     if (outstanding_tiering_units_ == 0) {
    1552             :       // If baseline compilation has not finished yet, then also trigger
    1553             :       // {kFinishedBaselineCompilation}.
    1554        5839 :       if (outstanding_baseline_units_ > 0) {
    1555         442 :         NotifyOnEvent(CompilationEvent::kFinishedBaselineCompilation);
    1556             :       }
    1557        5839 :       NotifyOnEvent(CompilationEvent::kFinishedTopTierCompilation);
    1558             :     }
    1559             :   } else {
    1560             :     DCHECK_LT(0, outstanding_baseline_units_);
    1561      102121 :     --outstanding_baseline_units_;
    1562      102121 :     if (outstanding_baseline_units_ == 0) {
    1563        5928 :       NotifyOnEvent(CompilationEvent::kFinishedBaselineCompilation);
    1564             :       // If we are not tiering, then we also trigger the "top tier finished"
    1565             :       // event when baseline compilation is finished.
    1566        5928 :       if (!is_tiering_mode) {
    1567          44 :         NotifyOnEvent(CompilationEvent::kFinishedTopTierCompilation);
    1568             :       }
    1569             :     }
    1570             :   }
    1571             : 
    1572      203590 :   if (code != nullptr) native_module_->engine()->LogCode(code);
    1573      203590 : }
    1574             : 
    1575       31417 : void CompilationStateImpl::RestartBackgroundCompileTask() {
    1576             :   auto task =
    1577             :       native_module_->engine()->NewBackgroundCompileTask<BackgroundCompileTask>(
    1578       31417 :           background_compile_token_, async_counters_);
    1579             : 
    1580       31417 :   if (baseline_compilation_finished()) {
    1581       14226 :     V8::GetCurrentPlatform()->CallLowPriorityTaskOnWorkerThread(
    1582       42678 :         std::move(task));
    1583             :   } else {
    1584       51573 :     V8::GetCurrentPlatform()->CallOnWorkerThread(std::move(task));
    1585             :   }
    1586       31417 : }
    1587             : 
    1588          26 : void CompilationStateImpl::ReportDetectedFeatures(
    1589             :     const WasmFeatures& detected) {
    1590          26 :   base::MutexGuard guard(&mutex_);
    1591          26 :   UnionFeaturesInto(&detected_features_, detected);
    1592          26 : }
    1593             : 
    1594       30474 : void CompilationStateImpl::OnBackgroundTaskStopped(
    1595             :     const WasmFeatures& detected) {
    1596       30474 :   base::MutexGuard guard(&mutex_);
    1597             :   DCHECK_LE(1, num_background_tasks_);
    1598       30475 :   --num_background_tasks_;
    1599       30475 :   UnionFeaturesInto(&detected_features_, detected);
    1600       30476 : }
    1601             : 
    1602        7014 : void CompilationStateImpl::PublishDetectedFeatures(
    1603             :     Isolate* isolate, const WasmFeatures& detected) {
    1604             :   // Notifying the isolate of the feature counts must take place under
    1605             :   // the mutex, because even if we have finished baseline compilation,
    1606             :   // tiering compilations may still occur in the background.
    1607        7014 :   base::MutexGuard guard(&mutex_);
    1608        7014 :   UnionFeaturesInto(&detected_features_, detected);
    1609             :   UpdateFeatureUseCounts(isolate, detected_features_);
    1610        7014 : }
    1611             : 
    1612        6259 : void CompilationStateImpl::RestartBackgroundTasks() {
    1613             :   int num_restart;
    1614             :   {
    1615        6259 :     base::MutexGuard guard(&mutex_);
    1616             :     // No need to restart tasks if compilation already failed.
    1617        6259 :     if (failed()) return;
    1618             : 
    1619             :     DCHECK_LE(num_background_tasks_, max_background_tasks_);
    1620        6259 :     if (num_background_tasks_ == max_background_tasks_) return;
    1621             :     size_t num_compilation_units =
    1622       18777 :         baseline_compilation_units_.size() + tiering_compilation_units_.size();
    1623        6259 :     num_restart = max_background_tasks_ - num_background_tasks_;
    1624             :     DCHECK_LE(0, num_restart);
    1625        6259 :     if (num_compilation_units < static_cast<size_t>(num_restart)) {
    1626        4066 :       num_restart = static_cast<int>(num_compilation_units);
    1627             :     }
    1628        6259 :     num_background_tasks_ += num_restart;
    1629             :   }
    1630             : 
    1631       31391 :   for (; num_restart > 0; --num_restart) {
    1632       31391 :     RestartBackgroundCompileTask();
    1633             :   }
    1634             : }
    1635             : 
    1636        6646 : void CompilationStateImpl::SetError(uint32_t func_index,
    1637             :                                     const WasmError& error) {
    1638             :   DCHECK(error.has_error());
    1639             :   std::unique_ptr<CompilationError> compile_error =
    1640        6646 :       base::make_unique<CompilationError>(func_index, error);
    1641        6646 :   CompilationError* expected = nullptr;
    1642             :   bool set = compile_error_.compare_exchange_strong(
    1643        6646 :       expected, compile_error.get(), std::memory_order_acq_rel);
    1644             :   // Ignore all but the first error. If the previous value is not nullptr, just
    1645             :   // return (and free the allocated error).
    1646       13292 :   if (!set) return;
    1647             :   // If set successfully, give up ownership.
    1648             :   compile_error.release();
    1649             :   // Schedule a foreground task to call the callback and notify users about the
    1650             :   // compile error.
    1651        6641 :   NotifyOnEvent(CompilationEvent::kFailedCompilation);
    1652             : }
    1653             : 
    1654       18893 : void CompilationStateImpl::NotifyOnEvent(CompilationEvent event) {
    1655       40431 :   for (auto& callback : callbacks_) callback(event);
    1656             :   // If no more events are expected after this one, clear the callbacks to free
    1657             :   // memory. We can safely do this here, as this method is only called from
    1658             :   // foreground tasks.
    1659       18894 :   if (event >= CompilationEvent::kFirstFinalEvent) callbacks_.clear();
    1660       18895 : }
    1661             : 
    1662      139036 : void CompileJsToWasmWrappers(Isolate* isolate, const WasmModule* module,
    1663             :                              Handle<FixedArray> export_wrappers) {
    1664             :   JSToWasmWrapperCache js_to_wasm_cache;
    1665             :   int wrapper_index = 0;
    1666             : 
    1667             :   // TODO(6792): Wrappers below are allocated with {Factory::NewCode}. As an
    1668             :   // optimization we keep the code space unlocked to avoid repeated unlocking
    1669             :   // because many such wrapper are allocated in sequence below.
    1670      278068 :   CodeSpaceMemoryModificationScope modification_scope(isolate->heap());
    1671      500470 :   for (auto exp : module->export_table) {
    1672      222399 :     if (exp.kind != kExternalFunction) continue;
    1673      219837 :     auto& function = module->functions[exp.index];
    1674             :     Handle<Code> wrapper_code = js_to_wasm_cache.GetOrCompileJSToWasmWrapper(
    1675      219837 :         isolate, function.sig, function.imported);
    1676      439674 :     export_wrappers->set(wrapper_index, *wrapper_code);
    1677      219837 :     RecordStats(*wrapper_code, isolate->counters());
    1678      219836 :     ++wrapper_index;
    1679             :   }
    1680      139036 : }
    1681             : 
    1682      136597 : Handle<Script> CreateWasmScript(Isolate* isolate,
    1683             :                                 const ModuleWireBytes& wire_bytes,
    1684             :                                 const std::string& source_map_url) {
    1685             :   Handle<Script> script =
    1686      136597 :       isolate->factory()->NewScript(isolate->factory()->empty_string());
    1687      409791 :   script->set_context_data(isolate->native_context()->debug_context_id());
    1688             :   script->set_type(Script::TYPE_WASM);
    1689             : 
    1690             :   int hash = StringHasher::HashSequentialString(
    1691             :       reinterpret_cast<const char*>(wire_bytes.start()),
    1692      136597 :       static_cast<int>(wire_bytes.length()), kZeroHashSeed);
    1693             : 
    1694             :   const int kBufferSize = 32;
    1695             :   char buffer[kBufferSize];
    1696             : 
    1697      136597 :   int name_chars = SNPrintF(ArrayVector(buffer), "wasm-%08x", hash);
    1698             :   DCHECK(name_chars >= 0 && name_chars < kBufferSize);
    1699             :   MaybeHandle<String> name_str = isolate->factory()->NewStringFromOneByte(
    1700      136597 :       VectorOf(reinterpret_cast<uint8_t*>(buffer), name_chars), TENURED);
    1701      273194 :   script->set_name(*name_str.ToHandleChecked());
    1702             : 
    1703      136597 :   if (source_map_url.size() != 0) {
    1704             :     MaybeHandle<String> src_map_str = isolate->factory()->NewStringFromUtf8(
    1705           4 :         CStrVector(source_map_url.c_str()), TENURED);
    1706           8 :     script->set_source_mapping_url(*src_map_str.ToHandleChecked());
    1707             :   }
    1708      136597 :   return script;
    1709             : }
    1710             : 
    1711             : }  // namespace wasm
    1712             : }  // namespace internal
    1713      178779 : }  // namespace v8
    1714             : 
    1715             : #undef TRACE_COMPILE
    1716             : #undef TRACE_STREAMING
    1717             : #undef TRACE_LAZY

Generated by: LCOV version 1.10