LCOV - code coverage report
Current view: top level - src/wasm - module-compiler.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 599 619 96.8 %
Date: 2019-03-21 Functions: 101 115 87.8 %

          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     2483804 : class BackgroundCompileToken {
      63             :  public:
      64             :   explicit BackgroundCompileToken(
      65             :       const std::shared_ptr<NativeModule>& native_module)
      66     1241902 :       : native_module_(native_module) {}
      67             : 
      68     1242555 :   void Cancel() {
      69     1242555 :     base::SharedMutexGuard<base::kExclusive> mutex_guard(&mutex_);
      70             :     native_module_.reset();
      71     1242555 :   }
      72             : 
      73             :  private:
      74             :   friend class BackgroundCompileScope;
      75             :   base::SharedMutex mutex_;
      76             :   std::weak_ptr<NativeModule> native_module_;
      77             : 
      78             :   std::shared_ptr<NativeModule> StartScope() {
      79      226576 :     mutex_.LockShared();
      80             :     return native_module_.lock();
      81             :   }
      82             : 
      83      230797 :   void ExitScope() { mutex_.UnlockShared(); }
      84             : };
      85             : 
      86             : class CompilationStateImpl;
      87             : 
      88             : // Keep these scopes short, as they hold the mutex of the token, which
      89             : // sequentializes all these scopes. The mutex is also acquired from foreground
      90             : // tasks, which should not be blocked for a long time.
      91             : class BackgroundCompileScope {
      92             :  public:
      93      226576 :   explicit BackgroundCompileScope(
      94             :       const std::shared_ptr<BackgroundCompileToken>& token)
      95      457436 :       : token_(token.get()), native_module_(token->StartScope()) {}
      96             : 
      97      461551 :   ~BackgroundCompileScope() { token_->ExitScope(); }
      98             : 
      99             :   bool cancelled() const { return native_module_ == nullptr; }
     100             : 
     101             :   NativeModule* native_module() {
     102             :     DCHECK(!cancelled());
     103             :     return native_module_.get();
     104             :   }
     105             : 
     106             :   inline CompilationStateImpl* compilation_state();
     107             : 
     108             :  private:
     109             :   BackgroundCompileToken* const token_;
     110             :   // Keep the native module alive while in this scope.
     111             :   std::shared_ptr<NativeModule> const native_module_;
     112             : };
     113             : 
     114             : // The {CompilationStateImpl} keeps track of the compilation state of the
     115             : // owning NativeModule, i.e. which functions are left to be compiled.
     116             : // It contains a task manager to allow parallel and asynchronous background
     117             : // compilation of functions.
     118             : // Its public interface {CompilationState} lives in compilation-environment.h.
     119     3725706 : class CompilationStateImpl {
     120             :  public:
     121             :   CompilationStateImpl(const std::shared_ptr<NativeModule>& native_module,
     122             :                        std::shared_ptr<Counters> async_counters);
     123             : 
     124             :   // Cancel all background compilation and wait for all tasks to finish. Call
     125             :   // this before destructing this object.
     126             :   void AbortCompilation();
     127             : 
     128             :   // Set the number of compilations unit expected to be executed. Needs to be
     129             :   // set before {AddCompilationUnits} is run, which triggers background
     130             :   // compilation.
     131             :   void SetNumberOfFunctionsToCompile(int num_functions);
     132             : 
     133             :   // Add the callback function to be called on compilation events. Needs to be
     134             :   // set before {AddCompilationUnits} is run to ensure that it receives all
     135             :   // events. The callback object must support being deleted from any thread.
     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();
     153             : 
     154             :   bool failed() const {
     155             :     return compile_failed_.load(std::memory_order_relaxed);
     156             :   }
     157             : 
     158     5397613 :   bool baseline_compilation_finished() const {
     159     5397613 :     base::MutexGuard guard(&callbacks_mutex_);
     160    10780306 :     return outstanding_baseline_units_ == 0 ||
     161    10687399 :            (compile_mode_ == CompileMode::kTiering &&
     162    10702319 :             outstanding_tiering_units_ == 0);
     163             :   }
     164             : 
     165             :   CompileMode compile_mode() const { return compile_mode_; }
     166       10272 :   WasmFeatures* detected_features() { return &detected_features_; }
     167             : 
     168     2339109 :   void SetWireBytesStorage(
     169             :       std::shared_ptr<WireBytesStorage> wire_bytes_storage) {
     170     2339109 :     base::MutexGuard guard(&mutex_);
     171             :     wire_bytes_storage_ = wire_bytes_storage;
     172     2339109 :   }
     173             : 
     174             :   std::shared_ptr<WireBytesStorage> GetWireBytesStorage() const {
     175      909599 :     base::MutexGuard guard(&mutex_);
     176             :     DCHECK_NOT_NULL(wire_bytes_storage_);
     177             :     return wire_bytes_storage_;
     178             :   }
     179             : 
     180             :  private:
     181             :   NativeModule* const native_module_;
     182             :   const std::shared_ptr<BackgroundCompileToken> background_compile_token_;
     183             :   const CompileMode compile_mode_;
     184             :   const std::shared_ptr<Counters> async_counters_;
     185             : 
     186             :   // Compilation error, atomically updated. This flag can be updated and read
     187             :   // using relaxed semantics.
     188             :   std::atomic<bool> compile_failed_{false};
     189             : 
     190             :   // This mutex protects all information of this {CompilationStateImpl} which is
     191             :   // being accessed concurrently.
     192             :   mutable base::Mutex mutex_;
     193             : 
     194             :   //////////////////////////////////////////////////////////////////////////////
     195             :   // Protected by {mutex_}:
     196             : 
     197             :   std::vector<std::unique_ptr<WasmCompilationUnit>> baseline_compilation_units_;
     198             :   std::vector<std::unique_ptr<WasmCompilationUnit>> tiering_compilation_units_;
     199             : 
     200             :   int num_background_tasks_ = 0;
     201             : 
     202             :   // Features detected to be used in this module. Features can be detected
     203             :   // as a module is being compiled.
     204             :   WasmFeatures detected_features_ = kNoWasmFeatures;
     205             : 
     206             :   // Abstraction over the storage of the wire bytes. Held in a shared_ptr so
     207             :   // that background compilation jobs can keep the storage alive while
     208             :   // compiling.
     209             :   std::shared_ptr<WireBytesStorage> wire_bytes_storage_;
     210             : 
     211             :   // End of fields protected by {mutex_}.
     212             :   //////////////////////////////////////////////////////////////////////////////
     213             : 
     214             :   // This mutex protects the callbacks vector, and the counters used to
     215             :   // determine which callbacks to call. The counters plus the callbacks
     216             :   // themselves need to be synchronized to ensure correct order of events.
     217             :   mutable base::Mutex callbacks_mutex_;
     218             : 
     219             :   //////////////////////////////////////////////////////////////////////////////
     220             :   // Protected by {callbacks_mutex_}:
     221             : 
     222             :   // Callback functions to be called on compilation events.
     223             :   std::vector<CompilationState::callback_t> callbacks_;
     224             : 
     225             :   int outstanding_baseline_units_ = 0;
     226             :   int outstanding_tiering_units_ = 0;
     227             : 
     228             :   // End of fields protected by {callbacks_mutex_}.
     229             :   //////////////////////////////////////////////////////////////////////////////
     230             : 
     231             :   const int max_background_tasks_ = 0;
     232             : };
     233             : 
     234             : CompilationStateImpl* Impl(CompilationState* compilation_state) {
     235             :   return reinterpret_cast<CompilationStateImpl*>(compilation_state);
     236             : }
     237             : const CompilationStateImpl* Impl(const CompilationState* compilation_state) {
     238             :   return reinterpret_cast<const CompilationStateImpl*>(compilation_state);
     239             : }
     240             : 
     241             : CompilationStateImpl* BackgroundCompileScope::compilation_state() {
     242             :   return Impl(native_module()->compilation_state());
     243             : }
     244             : 
     245             : void UpdateFeatureUseCounts(Isolate* isolate, const WasmFeatures& detected) {
     246      144223 :   if (detected.threads) {
     247        1444 :     isolate->CountUsage(v8::Isolate::UseCounterFeature::kWasmThreadOpcodes);
     248             :   }
     249             : }
     250             : 
     251             : }  // namespace
     252             : 
     253             : //////////////////////////////////////////////////////
     254             : // PIMPL implementation of {CompilationState}.
     255             : 
     256     1241902 : CompilationState::~CompilationState() { Impl(this)->~CompilationStateImpl(); }
     257             : 
     258     1241901 : void CompilationState::AbortCompilation() { Impl(this)->AbortCompilation(); }
     259             : 
     260        7129 : void CompilationState::SetError() { Impl(this)->SetError(); }
     261             : 
     262     2339109 : void CompilationState::SetWireBytesStorage(
     263             :     std::shared_ptr<WireBytesStorage> wire_bytes_storage) {
     264     4678218 :   Impl(this)->SetWireBytesStorage(std::move(wire_bytes_storage));
     265     2339109 : }
     266             : 
     267      863017 : std::shared_ptr<WireBytesStorage> CompilationState::GetWireBytesStorage()
     268             :     const {
     269      863017 :   return Impl(this)->GetWireBytesStorage();
     270             : }
     271             : 
     272        1263 : void CompilationState::AddCallback(CompilationState::callback_t callback) {
     273        2526 :   return Impl(this)->AddCallback(std::move(callback));
     274             : }
     275             : 
     276          32 : bool CompilationState::failed() const { return Impl(this)->failed(); }
     277             : 
     278           0 : void CompilationState::OnFinishedUnit(ExecutionTier tier, WasmCode* code) {
     279           0 :   Impl(this)->OnFinishedUnit(tier, code);
     280           0 : }
     281             : 
     282             : // static
     283     1241902 : std::unique_ptr<CompilationState> CompilationState::New(
     284             :     const std::shared_ptr<NativeModule>& native_module,
     285             :     std::shared_ptr<Counters> async_counters) {
     286             :   return std::unique_ptr<CompilationState>(reinterpret_cast<CompilationState*>(
     287     2483804 :       new CompilationStateImpl(native_module, std::move(async_counters))));
     288             : }
     289             : 
     290             : // End of PIMPL implementation of {CompilationState}.
     291             : //////////////////////////////////////////////////////
     292             : 
     293        8062 : void CompileLazy(Isolate* isolate, NativeModule* native_module,
     294             :                  uint32_t func_index) {
     295             :   Counters* counters = isolate->counters();
     296             :   HistogramTimerScope lazy_time_scope(counters->wasm_lazy_compilation_time());
     297             : 
     298             :   DCHECK(!native_module->lazy_compile_frozen());
     299             : 
     300             :   base::ElapsedTimer compilation_timer;
     301             : 
     302       16124 :   NativeModuleModificationScope native_module_modification_scope(native_module);
     303             : 
     304             :   DCHECK(!native_module->has_code(static_cast<uint32_t>(func_index)));
     305             : 
     306             :   compilation_timer.Start();
     307             : 
     308             :   TRACE_LAZY("Compiling wasm-function#%d.\n", func_index);
     309             : 
     310             :   const uint8_t* module_start = native_module->wire_bytes().start();
     311             : 
     312        8062 :   const WasmFunction* func = &native_module->module()->functions[func_index];
     313             :   FunctionBody func_body{func->sig, func->code.offset(),
     314             :                          module_start + func->code.offset(),
     315             :                          module_start + func->code.end_offset()};
     316             : 
     317             :   ExecutionTier tier =
     318        8062 :       WasmCompilationUnit::GetDefaultExecutionTier(native_module->module());
     319       16124 :   WasmCompilationUnit unit(isolate->wasm_engine(), func_index, tier);
     320        8062 :   CompilationEnv env = native_module->CreateCompilationEnv();
     321             :   WasmCompilationResult result = unit.ExecuteCompilation(
     322        8062 :       &env, native_module->compilation_state()->GetWireBytesStorage(),
     323             :       isolate->counters(),
     324       16124 :       Impl(native_module->compilation_state())->detected_features());
     325        8062 :   WasmCode* code = native_module->AddCompiledCode(std::move(result));
     326             : 
     327             :   // During lazy compilation, we should never get compilation errors. The module
     328             :   // was verified before starting execution with lazy compilation.
     329             :   // This might be OOM, but then we cannot continue execution anyway.
     330             :   // TODO(clemensh): According to the spec, we can actually skip validation at
     331             :   // module creation time, and return a function that always traps here.
     332        8062 :   CHECK(!native_module->compilation_state()->failed());
     333             : 
     334             :   // The code we just produced should be the one that was requested.
     335             :   DCHECK_EQ(func_index, code->index());
     336             : 
     337        8062 :   if (WasmCode::ShouldBeLogged(isolate)) code->LogCode(isolate);
     338             : 
     339             :   int64_t func_size =
     340        8062 :       static_cast<int64_t>(func->code.end_offset() - func->code.offset());
     341        8062 :   int64_t compilation_time = compilation_timer.Elapsed().InMicroseconds();
     342             : 
     343        8062 :   counters->wasm_lazily_compiled_functions()->Increment();
     344             : 
     345       16124 :   counters->wasm_lazy_compilation_throughput()->AddSample(
     346        8062 :       compilation_time != 0 ? static_cast<int>(func_size / compilation_time)
     347        8062 :                             : 0);
     348        8062 : }
     349             : 
     350             : namespace {
     351             : 
     352          96 : ExecutionTier apply_hint_to_execution_tier(WasmCompilationHintTier hint,
     353             :                                            ExecutionTier default_tier) {
     354          96 :   switch (hint) {
     355             :     case WasmCompilationHintTier::kDefault:
     356          64 :       return default_tier;
     357             :     case WasmCompilationHintTier::kInterpreter:
     358             :       return ExecutionTier::kInterpreter;
     359             :     case WasmCompilationHintTier::kBaseline:
     360           8 :       return ExecutionTier::kBaseline;
     361             :     case WasmCompilationHintTier::kOptimized:
     362           8 :       return ExecutionTier::kOptimized;
     363             :   }
     364           0 :   UNREACHABLE();
     365             : }
     366             : 
     367             : // The {CompilationUnitBuilder} builds compilation units and stores them in an
     368             : // internal buffer. The buffer is moved into the working queue of the
     369             : // {CompilationStateImpl} when {Commit} is called.
     370        6617 : class CompilationUnitBuilder {
     371             :  public:
     372             :   explicit CompilationUnitBuilder(NativeModule* native_module,
     373             :                                   WasmEngine* wasm_engine)
     374             :       : native_module_(native_module),
     375             :         wasm_engine_(wasm_engine),
     376        6617 :         default_tier_(WasmCompilationUnit::GetDefaultExecutionTier(
     377       13234 :             native_module->module())) {}
     378             : 
     379      103513 :   void AddUnit(uint32_t func_index) {
     380      103513 :     switch (compilation_state()->compile_mode()) {
     381             :       case CompileMode::kRegular:
     382         744 :         baseline_units_.emplace_back(CreateUnit(func_index, default_tier_));
     383         372 :         return;
     384             :       case CompileMode::kTiering:
     385             : 
     386             :         // Default tiering behaviour.
     387             :         ExecutionTier first_tier = ExecutionTier::kBaseline;
     388             :         ExecutionTier second_tier = ExecutionTier::kOptimized;
     389             : 
     390             :         // Check if compilation hints override default tiering behaviour.
     391      103141 :         if (native_module_->enabled_features().compilation_hints) {
     392             :           // Find compilation hint.
     393         252 :           CHECK_LE(native_module_->num_imported_functions(), func_index);
     394             :           uint32_t hint_index =
     395         252 :               func_index - native_module_->num_imported_functions();
     396             :           const std::vector<WasmCompilationHint>& compilation_hints =
     397             :               native_module_->module()->compilation_hints;
     398         504 :           if (hint_index < compilation_hints.size()) {
     399          48 :             WasmCompilationHint hint = compilation_hints[hint_index];
     400             : 
     401             :             // Apply compilation hint.
     402             :             first_tier =
     403          48 :                 apply_hint_to_execution_tier(hint.first_tier, first_tier);
     404             :             second_tier =
     405          48 :                 apply_hint_to_execution_tier(hint.second_tier, second_tier);
     406             :           }
     407             :         }
     408             : 
     409             :         // Create compilation units and suppress duplicate compilation.
     410      103141 :         baseline_units_.emplace_back(
     411      103141 :             CreateUnit(func_index, std::move(first_tier)));
     412             :         static_assert(ExecutionTier::kInterpreter < ExecutionTier::kBaseline &&
     413             :                           ExecutionTier::kBaseline < ExecutionTier::kOptimized,
     414             :                       "Assume an order on execution tiers");
     415      103141 :         if (first_tier < second_tier) {
     416      103133 :           tiering_units_.emplace_back(
     417      103133 :               CreateUnit(func_index, std::move(second_tier)));
     418             :         }
     419             :         return;
     420             :     }
     421           0 :     UNREACHABLE();
     422             :   }
     423             : 
     424        6693 :   bool Commit() {
     425        6693 :     if (baseline_units_.empty() && tiering_units_.empty()) return false;
     426       13258 :     compilation_state()->AddCompilationUnits(baseline_units_, tiering_units_);
     427        6629 :     Clear();
     428        6629 :     return true;
     429             :   }
     430             : 
     431        6681 :   void Clear() {
     432             :     baseline_units_.clear();
     433             :     tiering_units_.clear();
     434        6681 :   }
     435             : 
     436             :  private:
     437             :   std::unique_ptr<WasmCompilationUnit> CreateUnit(uint32_t func_index,
     438             :                                                   ExecutionTier tier) {
     439             :     return base::make_unique<WasmCompilationUnit>(wasm_engine_, func_index,
     440      206646 :                                                   tier);
     441             :   }
     442             : 
     443             :   CompilationStateImpl* compilation_state() const {
     444             :     return Impl(native_module_->compilation_state());
     445             :   }
     446             : 
     447             :   NativeModule* const native_module_;
     448             :   WasmEngine* const wasm_engine_;
     449             :   const ExecutionTier default_tier_;
     450             :   std::vector<std::unique_ptr<WasmCompilationUnit>> baseline_units_;
     451             :   std::vector<std::unique_ptr<WasmCompilationUnit>> tiering_units_;
     452             : };
     453             : 
     454             : bool compile_lazy(const WasmModule* module) {
     455      144648 :   return FLAG_wasm_lazy_compilation ||
     456      144160 :          (FLAG_asm_wasm_lazy_compilation && module->origin == kAsmJsOrigin);
     457             : }
     458             : 
     459      220385 : void RecordStats(const Code code, Counters* counters) {
     460      440770 :   counters->wasm_generated_code_size()->Increment(code->body_size());
     461      220385 :   counters->wasm_reloc_size()->Increment(code->relocation_info()->length());
     462      220386 : }
     463             : 
     464      229988 : double MonotonicallyIncreasingTimeInMs() {
     465      229988 :   return V8::GetCurrentPlatform()->MonotonicallyIncreasingTime() *
     466      229920 :          base::Time::kMillisecondsPerSecond;
     467             : }
     468             : 
     469             : // Run by each compilation task and by the main thread (i.e. in both
     470             : // foreground and background threads).
     471     5359929 : bool FetchAndExecuteCompilationUnit(CompilationEnv* env,
     472             :                                     NativeModule* native_module,
     473             :                                     CompilationStateImpl* compilation_state,
     474             :                                     WasmFeatures* detected,
     475             :                                     Counters* counters) {
     476             :   DisallowHeapAccess no_heap_access;
     477             : 
     478             :   std::unique_ptr<WasmCompilationUnit> unit =
     479    10719858 :       compilation_state->GetNextCompilationUnit();
     480     5359929 :   if (unit == nullptr) return false;
     481             : 
     482             :   WasmCompilationResult result = unit->ExecuteCompilation(
     483       20718 :       env, compilation_state->GetWireBytesStorage(), counters, detected);
     484             : 
     485        6906 :   if (result.succeeded()) {
     486        6858 :     WasmCode* code = native_module->AddCompiledCode(std::move(result));
     487        6858 :     compilation_state->OnFinishedUnit(result.requested_tier, code);
     488             :   } else {
     489          48 :     compilation_state->SetError();
     490             :   }
     491             : 
     492             :   return true;
     493             : }
     494             : 
     495        6401 : void InitializeCompilationUnits(NativeModule* native_module,
     496             :                                 WasmEngine* wasm_engine) {
     497             :   ModuleWireBytes wire_bytes(native_module->wire_bytes());
     498             :   const WasmModule* module = native_module->module();
     499             :   CompilationUnitBuilder builder(native_module, wasm_engine);
     500        6401 :   uint32_t start = module->num_imported_functions;
     501        6401 :   uint32_t end = start + module->num_declared_functions;
     502      212523 :   for (uint32_t i = start; i < end; ++i) {
     503      103061 :     builder.AddUnit(i);
     504             :   }
     505        6401 :   builder.Commit();
     506        6401 : }
     507             : 
     508        5162 : void CompileInParallel(Isolate* isolate, NativeModule* native_module) {
     509             :   // Data structures for the parallel compilation.
     510             : 
     511             :   //-----------------------------------------------------------------------
     512             :   // For parallel compilation:
     513             :   // 1) The main thread allocates a compilation unit for each wasm function
     514             :   //    and stores them in the vector {compilation_units} within the
     515             :   //    {compilation_state}. By adding units to the {compilation_state}, new
     516             :   //    {BackgroundCompileTasks} instances are spawned which run on
     517             :   //    the background threads.
     518             :   // 2) The background threads and the main thread pick one compilation unit at
     519             :   //    a time and execute the parallel phase of the compilation unit.
     520             : 
     521             :   // Turn on the {CanonicalHandleScope} so that the background threads can
     522             :   // use the node cache.
     523       10324 :   CanonicalHandleScope canonical(isolate);
     524             : 
     525             :   CompilationStateImpl* compilation_state =
     526             :       Impl(native_module->compilation_state());
     527             :   DCHECK_GE(kMaxInt, native_module->module()->num_declared_functions);
     528             :   int num_wasm_functions =
     529        5162 :       static_cast<int>(native_module->module()->num_declared_functions);
     530        5162 :   compilation_state->SetNumberOfFunctionsToCompile(num_wasm_functions);
     531             : 
     532             :   // 1) The main thread allocates a compilation unit for each wasm function
     533             :   //    and stores them in the vector {compilation_units} within the
     534             :   //    {compilation_state}. By adding units to the {compilation_state}, new
     535             :   //    {BackgroundCompileTask} instances are spawned which run on
     536             :   //    background threads.
     537        5162 :   InitializeCompilationUnits(native_module, isolate->wasm_engine());
     538             : 
     539             :   // 2) The background threads and the main thread pick one compilation unit at
     540             :   //    a time and execute the parallel phase of the compilation unit.
     541        5162 :   WasmFeatures detected_features;
     542        5162 :   CompilationEnv env = native_module->CreateCompilationEnv();
     543             :   // TODO(wasm): This might already execute TurboFan units on the main thread,
     544             :   // while waiting for baseline compilation to finish. This can introduce
     545             :   // additional delay.
     546             :   // TODO(wasm): This is a busy-wait loop once all units have started executing
     547             :   // in background threads. Replace by a semaphore / barrier.
     548    16089735 :   while (!compilation_state->failed() &&
     549     5364715 :          !compilation_state->baseline_compilation_finished()) {
     550             :     FetchAndExecuteCompilationUnit(&env, native_module, compilation_state,
     551     5359929 :                                    &detected_features, isolate->counters());
     552             :   }
     553             : 
     554             :   // Publish features from the foreground and background tasks.
     555        5162 :   compilation_state->PublishDetectedFeatures(isolate, detected_features);
     556        5162 : }
     557             : 
     558      136857 : void CompileSequentially(Isolate* isolate, NativeModule* native_module) {
     559             :   ModuleWireBytes wire_bytes(native_module->wire_bytes());
     560             :   const WasmModule* module = native_module->module();
     561      136857 :   WasmFeatures detected = kNoWasmFeatures;
     562             :   auto* comp_state = Impl(native_module->compilation_state());
     563             :   ExecutionTier tier =
     564      136857 :       WasmCompilationUnit::GetDefaultExecutionTier(native_module->module());
     565      372554 :   for (const WasmFunction& func : module->functions) {
     566      242829 :     if (func.imported) continue;  // Imports are compiled at instantiation time.
     567             : 
     568             :     // Compile the function.
     569             :     WasmCompilationUnit::CompileWasmFunction(isolate, native_module, &detected,
     570      131469 :                                              &func, tier);
     571      131463 :     if (comp_state->failed()) break;
     572             :   }
     573             :   UpdateFeatureUseCounts(isolate, detected);
     574      136854 : }
     575             : 
     576        7757 : void ValidateSequentially(Isolate* isolate, NativeModule* native_module,
     577             :                           ErrorThrower* thrower) {
     578             :   DCHECK(!thrower->error());
     579             : 
     580             :   ModuleWireBytes wire_bytes{native_module->wire_bytes()};
     581             :   const WasmModule* module = native_module->module();
     582        7757 :   uint32_t start = module->num_imported_functions;
     583        7757 :   uint32_t end = start + module->num_declared_functions;
     584        9253 :   for (uint32_t i = start; i < end; ++i) {
     585        8337 :     const WasmFunction* func = &module->functions[i];
     586             : 
     587             :     Vector<const uint8_t> code = wire_bytes.GetFunctionBytes(func);
     588        8337 :     FunctionBody body{func->sig, func->code.offset(), code.start(), code.end()};
     589             :     DecodeResult result;
     590             :     {
     591        8337 :       auto time_counter = SELECT_WASM_COUNTER(
     592             :           isolate->counters(), module->origin, wasm_decode, function_time);
     593             : 
     594             :       TimedHistogramScope wasm_decode_function_time_scope(time_counter);
     595        8337 :       WasmFeatures detected;
     596       16674 :       result = VerifyWasmCode(isolate->allocator(),
     597             :                               native_module->enabled_features(), module,
     598             :                               &detected, body);
     599             :     }
     600        8337 :     if (result.failed()) {
     601        7589 :       WasmName name = wire_bytes.GetNameOrNull(func, module);
     602        7589 :       if (name.start() == nullptr) {
     603             :         thrower->CompileError("Compiling function #%d failed: %s @+%u", i,
     604             :                               result.error().message().c_str(),
     605        7397 :                               result.error().offset());
     606             :       } else {
     607         192 :         TruncatedUserString<> name(wire_bytes.GetNameOrNull(func, module));
     608             :         thrower->CompileError("Compiling function #%d:\"%.*s\" failed: %s @+%u",
     609             :                               i, name.length(), name.start(),
     610             :                               result.error().message().c_str(),
     611         192 :                               result.error().offset());
     612             :       }
     613             :       break;
     614             :     }
     615             :   }
     616        7757 : }
     617             : 
     618      144648 : void CompileNativeModule(Isolate* isolate, ErrorThrower* thrower,
     619             :                          const WasmModule* wasm_module,
     620             :                          NativeModule* native_module) {
     621             :   ModuleWireBytes wire_bytes(native_module->wire_bytes());
     622             : 
     623      144648 :   if (compile_lazy(wasm_module)) {
     624        2629 :     if (wasm_module->origin == kWasmOrigin) {
     625             :       // Validate wasm modules for lazy compilation. Don't validate asm.js
     626             :       // modules, they are valid by construction (otherwise a CHECK will fail
     627             :       // during lazy compilation).
     628             :       // TODO(clemensh): According to the spec, we can actually skip validation
     629             :       // at module creation time, and return a function that always traps at
     630             :       // (lazy) compilation time.
     631         176 :       ValidateSequentially(isolate, native_module, thrower);
     632         176 :       if (thrower->error()) return;
     633             :     }
     634             : 
     635        2621 :     native_module->SetLazyBuiltin();
     636             :   } else {
     637             :     size_t funcs_to_compile =
     638      142019 :         wasm_module->functions.size() - wasm_module->num_imported_functions;
     639             :     bool compile_parallel =
     640      284030 :         !FLAG_trace_wasm_decoder && FLAG_wasm_num_compilation_tasks > 0 &&
     641      147181 :         funcs_to_compile > 1 &&
     642        5162 :         V8::GetCurrentPlatform()->NumberOfWorkerThreads() > 0;
     643             : 
     644      142019 :     if (compile_parallel) {
     645        5162 :       CompileInParallel(isolate, native_module);
     646             :     } else {
     647      136857 :       CompileSequentially(isolate, native_module);
     648             :     }
     649             :     auto* compilation_state = Impl(native_module->compilation_state());
     650      142019 :     if (compilation_state->failed()) {
     651        7505 :       ValidateSequentially(isolate, native_module, thrower);
     652        7505 :       CHECK(thrower->error());
     653             :     }
     654             :   }
     655             : }
     656             : 
     657             : // The runnable task that performs compilations in the background.
     658       98617 : class BackgroundCompileTask : public CancelableTask {
     659             :  public:
     660             :   explicit BackgroundCompileTask(CancelableTaskManager* manager,
     661             :                                  std::shared_ptr<BackgroundCompileToken> token,
     662             :                                  std::shared_ptr<Counters> async_counters)
     663             :       : CancelableTask(manager),
     664             :         token_(std::move(token)),
     665       32898 :         async_counters_(std::move(async_counters)) {}
     666             : 
     667       32819 :   void RunInternal() override {
     668             :     TRACE_COMPILE("(3b) Compiling...\n");
     669       66075 :     TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"),
     670             :                  "BackgroundCompileTask::RunInternal");
     671             : 
     672       32823 :     double deadline = MonotonicallyIncreasingTimeInMs() + 50.0;
     673             : 
     674             :     // These fields are initialized in a {BackgroundCompileScope} before
     675             :     // starting compilation.
     676       32808 :     base::Optional<CompilationEnv> env;
     677       32808 :     std::shared_ptr<WireBytesStorage> wire_bytes;
     678             :     std::shared_ptr<const WasmModule> module;
     679       33240 :     std::unique_ptr<WasmCompilationUnit> unit;
     680       32808 :     WasmFeatures detected_features = kNoWasmFeatures;
     681             : 
     682             :     // Preparation (synchronized): Initialize the fields above and get the first
     683             :     // compilation unit.
     684             :     {
     685       47093 :       BackgroundCompileScope compile_scope(token_);
     686       51464 :       if (compile_scope.cancelled()) return;
     687       63289 :       env.emplace(compile_scope.native_module()->CreateCompilationEnv());
     688       31680 :       wire_bytes = compile_scope.compilation_state()->GetWireBytesStorage();
     689       31679 :       module = compile_scope.native_module()->shared_module();
     690       63351 :       unit = compile_scope.compilation_state()->GetNextCompilationUnit();
     691       31672 :       if (unit == nullptr) {
     692             :         compile_scope.compilation_state()->OnBackgroundTaskStopped(
     693       17387 :             detected_features);
     694       17391 :         return;
     695             :       }
     696             :     }
     697             : 
     698         433 :     std::vector<WasmCompilationResult> results_to_publish;
     699             : 
     700             :     auto publish_results =
     701      315375 :         [&results_to_publish](BackgroundCompileScope* compile_scope) {
     702      124767 :           if (results_to_publish.empty()) return;
     703             :           // TODO(clemensh): Refactor {OnFinishedUnit} and remove this.
     704             :           std::vector<ExecutionTier> requested_tiers;
     705      101045 :           requested_tiers.reserve(results_to_publish.size());
     706      398288 :           for (auto& result : results_to_publish) {
     707      195780 :             requested_tiers.push_back(result.requested_tier);
     708             :           }
     709             : 
     710             :           std::vector<WasmCode*> generated_code =
     711             :               compile_scope->native_module()->AddCompiledCode(
     712      101233 :                   VectorOf(results_to_publish));
     713             :           results_to_publish.clear();
     714             : 
     715             :           // Account for the finished compilation units.
     716             :           // TODO(clemensh): This takes a lock on each invokation. Only do this
     717             :           // once and pass accumulated counts.
     718             :           DCHECK_EQ(generated_code.size(), requested_tiers.size());
     719      494933 :           for (size_t i = 0; i < generated_code.size(); ++i) {
     720      393650 :             compile_scope->compilation_state()->OnFinishedUnit(
     721      196825 :                 requested_tiers[i], generated_code[i]);
     722             :           }
     723       14191 :         };
     724             : 
     725             :     bool compilation_failed = false;
     726             :     while (true) {
     727             :       // (asynchronous): Execute the compilation.
     728             : 
     729             :       WasmCompilationResult result = unit->ExecuteCompilation(
     730      381382 :           &env.value(), wire_bytes, async_counters_.get(), &detected_features);
     731      193855 :       results_to_publish.emplace_back(std::move(result));
     732             : 
     733             :       // (synchronized): Publish the compilation result and get the next unit.
     734             :       {
     735      377637 :         BackgroundCompileScope compile_scope(token_);
     736      211834 :         if (compile_scope.cancelled()) return;
     737      197692 :         if (!results_to_publish.back().succeeded()) {
     738             :           // Compile error.
     739         433 :           compile_scope.compilation_state()->SetError();
     740             :           compile_scope.compilation_state()->OnBackgroundTaskStopped(
     741         433 :               detected_features);
     742             :           compilation_failed = true;
     743         433 :           break;
     744             :         }
     745             :         // Publish TurboFan units immediately to reduce peak memory consumption.
     746      197259 :         if (result.requested_tier == ExecutionTier::kOptimized) {
     747       99487 :           publish_results(&compile_scope);
     748             :         }
     749             : 
     750      197330 :         if (deadline < MonotonicallyIncreasingTimeInMs()) {
     751          65 :           publish_results(&compile_scope);
     752             :           compile_scope.compilation_state()->ReportDetectedFeatures(
     753          65 :               detected_features);
     754          65 :           compile_scope.compilation_state()->RestartBackgroundCompileTask();
     755          65 :           return;
     756             :         }
     757             : 
     758             :         // Get next unit.
     759      394059 :         unit = compile_scope.compilation_state()->GetNextCompilationUnit();
     760      197156 :         if (unit == nullptr) {
     761       13496 :           publish_results(&compile_scope);
     762             :           compile_scope.compilation_state()->OnBackgroundTaskStopped(
     763       13497 :               detected_features);
     764       13501 :           return;
     765             :         }
     766             :       }
     767             :     }
     768             :     // We only get here if compilation failed. Other exits return directly.
     769             :     DCHECK(compilation_failed);
     770             :     USE(compilation_failed);
     771         433 :     token_->Cancel();
     772             :   }
     773             : 
     774             :  private:
     775             :   std::shared_ptr<BackgroundCompileToken> token_;
     776             :   std::shared_ptr<Counters> async_counters_;
     777             : };
     778             : 
     779             : }  // namespace
     780             : 
     781      144596 : std::shared_ptr<NativeModule> CompileToNativeModule(
     782             :     Isolate* isolate, const WasmFeatures& enabled, ErrorThrower* thrower,
     783             :     std::shared_ptr<const WasmModule> module, const ModuleWireBytes& wire_bytes,
     784             :     Handle<FixedArray>* export_wrappers_out) {
     785             :   const WasmModule* wasm_module = module.get();
     786      144596 :   TimedHistogramScope wasm_compile_module_time_scope(SELECT_WASM_COUNTER(
     787      144596 :       isolate->counters(), wasm_module->origin, wasm_compile, module_time));
     788             : 
     789             :   // Embedder usage count for declared shared memories.
     790      144605 :   if (wasm_module->has_shared_memory) {
     791        1484 :     isolate->CountUsage(v8::Isolate::UseCounterFeature::kWasmSharedMemory);
     792             :   }
     793      144607 :   int export_wrapper_size = static_cast<int>(module->num_exported_functions);
     794             : 
     795             :   // TODO(wasm): only save the sections necessary to deserialize a
     796             :   // {WasmModule}. E.g. function bodies could be omitted.
     797             :   OwnedVector<uint8_t> wire_bytes_copy =
     798      144607 :       OwnedVector<uint8_t>::Of(wire_bytes.module_bytes());
     799             : 
     800             :   // Create and compile the native module.
     801             :   size_t code_size_estimate =
     802      144610 :       wasm::WasmCodeManager::EstimateNativeModuleCodeSize(module.get());
     803             : 
     804             :   // Create a new {NativeModule} first.
     805             :   auto native_module = isolate->wasm_engine()->NewNativeModule(
     806             :       isolate, enabled, code_size_estimate,
     807      289215 :       wasm::NativeModule::kCanAllocateMoreMemory, std::move(module));
     808      289220 :   native_module->SetWireBytes(std::move(wire_bytes_copy));
     809      144610 :   native_module->SetRuntimeStubs(isolate);
     810             : 
     811      144610 :   CompileNativeModule(isolate, thrower, wasm_module, native_module.get());
     812      144608 :   if (thrower->error()) return {};
     813             : 
     814             :   // Compile JS->wasm wrappers for exported functions.
     815             :   *export_wrappers_out = isolate->factory()->NewFixedArray(
     816      137095 :       export_wrapper_size, AllocationType::kOld);
     817             :   CompileJsToWasmWrappers(isolate, native_module->module(),
     818      137097 :                           *export_wrappers_out);
     819             : 
     820             :   // Log the code within the generated module for profiling.
     821      137097 :   native_module->LogWasmCodes(isolate);
     822             : 
     823             :   return native_module;
     824             : }
     825             : 
     826          38 : void CompileNativeModuleWithExplicitBoundsChecks(Isolate* isolate,
     827             :                                                  ErrorThrower* thrower,
     828             :                                                  const WasmModule* wasm_module,
     829             :                                                  NativeModule* native_module) {
     830          38 :   native_module->DisableTrapHandler();
     831          38 :   CompileNativeModule(isolate, thrower, wasm_module, native_module);
     832          38 : }
     833             : 
     834        2543 : AsyncCompileJob::AsyncCompileJob(
     835             :     Isolate* isolate, const WasmFeatures& enabled,
     836             :     std::unique_ptr<byte[]> bytes_copy, size_t length, Handle<Context> context,
     837             :     std::shared_ptr<CompilationResultResolver> resolver)
     838             :     : isolate_(isolate),
     839             :       enabled_features_(enabled),
     840             :       bytes_copy_(std::move(bytes_copy)),
     841             :       wire_bytes_(bytes_copy_.get(), bytes_copy_.get() + length),
     842       10172 :       resolver_(std::move(resolver)) {
     843             :   v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
     844        2543 :   v8::Platform* platform = V8::GetCurrentPlatform();
     845        5086 :   foreground_task_runner_ = platform->GetForegroundTaskRunner(v8_isolate);
     846             :   native_context_ =
     847        5086 :       isolate->global_handles()->Create(context->native_context());
     848             :   DCHECK(native_context_->IsNativeContext());
     849        2543 : }
     850             : 
     851        2163 : void AsyncCompileJob::Start() {
     852        4326 :   DoAsync<DecodeModule>(isolate_->counters());  // --
     853        2163 : }
     854             : 
     855          56 : void AsyncCompileJob::Abort() {
     856             :   // Removing this job will trigger the destructor, which will cancel all
     857             :   // compilation.
     858          56 :   isolate_->wasm_engine()->RemoveCompileJob(this);
     859          56 : }
     860             : 
     861        1520 : class AsyncStreamingProcessor final : public StreamingProcessor {
     862             :  public:
     863             :   explicit AsyncStreamingProcessor(AsyncCompileJob* job);
     864             : 
     865             :   bool ProcessModuleHeader(Vector<const uint8_t> bytes,
     866             :                            uint32_t offset) override;
     867             : 
     868             :   bool ProcessSection(SectionCode section_code, Vector<const uint8_t> bytes,
     869             :                       uint32_t offset) override;
     870             : 
     871             :   bool ProcessCodeSectionHeader(int functions_count, uint32_t offset,
     872             :                                 std::shared_ptr<WireBytesStorage>) override;
     873             : 
     874             :   bool ProcessFunctionBody(Vector<const uint8_t> bytes,
     875             :                            uint32_t offset) override;
     876             : 
     877             :   void OnFinishedChunk() override;
     878             : 
     879             :   void OnFinishedStream(OwnedVector<uint8_t> bytes) override;
     880             : 
     881             :   void OnError(const WasmError&) override;
     882             : 
     883             :   void OnAbort() override;
     884             : 
     885             :   bool Deserialize(Vector<const uint8_t> wire_bytes,
     886             :                    Vector<const uint8_t> module_bytes) override;
     887             : 
     888             :  private:
     889             :   // Finishes the AsyncCompileJob with an error.
     890             :   void FinishAsyncCompileJobWithError(const WasmError&);
     891             : 
     892             :   void CommitCompilationUnits();
     893             : 
     894             :   ModuleDecoder decoder_;
     895             :   AsyncCompileJob* job_;
     896             :   std::unique_ptr<CompilationUnitBuilder> compilation_unit_builder_;
     897             :   int num_functions_ = 0;
     898             : };
     899             : 
     900         380 : std::shared_ptr<StreamingDecoder> AsyncCompileJob::CreateStreamingDecoder() {
     901             :   DCHECK_NULL(stream_);
     902        1140 :   stream_.reset(
     903        1520 :       new StreamingDecoder(base::make_unique<AsyncStreamingProcessor>(this)));
     904         380 :   return stream_;
     905             : }
     906             : 
     907        7629 : AsyncCompileJob::~AsyncCompileJob() {
     908             :   // Note: This destructor always runs on the foreground thread of the isolate.
     909        2543 :   background_task_manager_.CancelAndWait();
     910             :   // If the runtime objects were not created yet, then initial compilation did
     911             :   // not finish yet. In this case we can abort compilation.
     912        4918 :   if (native_module_ && module_object_.is_null()) {
     913         165 :     Impl(native_module_->compilation_state())->AbortCompilation();
     914             :   }
     915             :   // Tell the streaming decoder that the AsyncCompileJob is not available
     916             :   // anymore.
     917             :   // TODO(ahaas): Is this notification really necessary? Check
     918             :   // https://crbug.com/888170.
     919        2543 :   if (stream_) stream_->NotifyCompilationEnded();
     920             :   CancelPendingForegroundTask();
     921        2543 :   isolate_->global_handles()->Destroy(native_context_.location());
     922        2543 :   if (!module_object_.is_null()) {
     923        2210 :     isolate_->global_handles()->Destroy(module_object_.location());
     924             :   }
     925        2543 : }
     926             : 
     927        2371 : void AsyncCompileJob::CreateNativeModule(
     928             :     std::shared_ptr<const WasmModule> module) {
     929             :   // Embedder usage count for declared shared memories.
     930        2371 :   if (module->has_shared_memory) {
     931           0 :     isolate_->CountUsage(v8::Isolate::UseCounterFeature::kWasmSharedMemory);
     932             :   }
     933             : 
     934             :   // TODO(wasm): Improve efficiency of storing module wire bytes. Only store
     935             :   // relevant sections, not function bodies
     936             : 
     937             :   // Create the module object and populate with compiled functions and
     938             :   // information needed at instantiation time.
     939             :   // TODO(clemensh): For the same module (same bytes / same hash), we should
     940             :   // only have one {WasmModuleObject}. Otherwise, we might only set
     941             :   // breakpoints on a (potentially empty) subset of the instances.
     942             :   // Create the module object.
     943             : 
     944             :   size_t code_size_estimate =
     945        2371 :       wasm::WasmCodeManager::EstimateNativeModuleCodeSize(module.get());
     946        7113 :   native_module_ = isolate_->wasm_engine()->NewNativeModule(
     947             :       isolate_, enabled_features_, code_size_estimate,
     948             :       wasm::NativeModule::kCanAllocateMoreMemory, std::move(module));
     949        4742 :   native_module_->SetWireBytes({std::move(bytes_copy_), wire_bytes_.length()});
     950        2371 :   native_module_->SetRuntimeStubs(isolate_);
     951             : 
     952        2371 :   if (stream_) stream_->NotifyNativeModuleCreated(native_module_);
     953        2371 : }
     954             : 
     955        2206 : void AsyncCompileJob::PrepareRuntimeObjects() {
     956             :   // Create heap objects for script and module bytes to be stored in the
     957             :   // module object. Asm.js is not compiled asynchronously.
     958             :   const WasmModule* module = native_module_->module();
     959             :   Handle<Script> script =
     960        2206 :       CreateWasmScript(isolate_, wire_bytes_, module->source_map_url);
     961             : 
     962             :   size_t code_size_estimate =
     963        2206 :       wasm::WasmCodeManager::EstimateNativeModuleCodeSize(module);
     964             :   Handle<WasmModuleObject> module_object = WasmModuleObject::New(
     965        4412 :       isolate_, native_module_, script, code_size_estimate);
     966             : 
     967        4412 :   module_object_ = isolate_->global_handles()->Create(*module_object);
     968        2206 : }
     969             : 
     970             : // This function assumes that it is executed in a HandleScope, and that a
     971             : // context is set on the isolate.
     972        2210 : void AsyncCompileJob::FinishCompile() {
     973             :   bool is_after_deserialization = !module_object_.is_null();
     974        2210 :   if (!is_after_deserialization) {
     975        2206 :     PrepareRuntimeObjects();
     976             :   }
     977             :   DCHECK(!isolate_->context().is_null());
     978             :   // Finish the wasm script now and make it public to the debugger.
     979        2210 :   Handle<Script> script(module_object_->script(), isolate_);
     980        6630 :   if (script->type() == Script::TYPE_WASM &&
     981        4420 :       module_object_->module()->source_map_url.size() != 0) {
     982           0 :     MaybeHandle<String> src_map_str = isolate_->factory()->NewStringFromUtf8(
     983           0 :         CStrVector(module_object_->module()->source_map_url.c_str()),
     984           0 :         AllocationType::kOld);
     985           0 :     script->set_source_mapping_url(*src_map_str.ToHandleChecked());
     986             :   }
     987        2210 :   isolate_->debug()->OnAfterCompile(script);
     988             : 
     989             :   // We can only update the feature counts once the entire compile is done.
     990             :   auto compilation_state =
     991        4420 :       Impl(module_object_->native_module()->compilation_state());
     992             :   compilation_state->PublishDetectedFeatures(
     993        2210 :       isolate_, *compilation_state->detected_features());
     994             : 
     995             :   // TODO(bbudge) Allow deserialization without wrapper compilation, so we can
     996             :   // just compile wrappers here.
     997        2210 :   if (!is_after_deserialization) {
     998             :     // TODO(wasm): compiling wrappers should be made async.
     999        2206 :     CompileWrappers();
    1000             :   }
    1001        2210 :   FinishModule();
    1002        2210 : }
    1003             : 
    1004         189 : void AsyncCompileJob::DecodeFailed(const WasmError& error) {
    1005         378 :   ErrorThrower thrower(isolate_, "WebAssembly.compile()");
    1006             :   thrower.CompileFailed(error);
    1007             :   // {job} keeps the {this} pointer alive.
    1008             :   std::shared_ptr<AsyncCompileJob> job =
    1009         378 :       isolate_->wasm_engine()->RemoveCompileJob(this);
    1010         189 :   resolver_->OnCompilationFailed(thrower.Reify());
    1011         189 : }
    1012             : 
    1013          76 : void AsyncCompileJob::AsyncCompileFailed() {
    1014         152 :   ErrorThrower thrower(isolate_, "WebAssembly.compile()");
    1015          76 :   ValidateSequentially(isolate_, native_module_.get(), &thrower);
    1016             :   DCHECK(thrower.error());
    1017             :   // {job} keeps the {this} pointer alive.
    1018             :   std::shared_ptr<AsyncCompileJob> job =
    1019         152 :       isolate_->wasm_engine()->RemoveCompileJob(this);
    1020          76 :   resolver_->OnCompilationFailed(thrower.Reify());
    1021          76 : }
    1022             : 
    1023           0 : void AsyncCompileJob::AsyncCompileSucceeded(Handle<WasmModuleObject> result) {
    1024        2210 :   resolver_->OnCompilationSucceeded(result);
    1025           0 : }
    1026             : 
    1027             : class AsyncCompileJob::CompilationStateCallback {
    1028             :  public:
    1029             :   explicit CompilationStateCallback(AsyncCompileJob* job) : job_(job) {}
    1030             : 
    1031        2664 :   void operator()(CompilationEvent event) {
    1032             :     // This callback is only being called from a foreground task.
    1033        2664 :     switch (event) {
    1034             :       case CompilationEvent::kFinishedBaselineCompilation:
    1035             :         DCHECK(!last_event_.has_value());
    1036        2588 :         if (job_->DecrementAndCheckFinisherCount()) {
    1037        1259 :           job_->DoSync<CompileFinished>();
    1038             :         }
    1039             :         break;
    1040             :       case CompilationEvent::kFinishedTopTierCompilation:
    1041             :         DCHECK_EQ(CompilationEvent::kFinishedBaselineCompilation, last_event_);
    1042             :         // At this point, the job will already be gone, thus do not access it
    1043             :         // here.
    1044             :         break;
    1045             :       case CompilationEvent::kFailedCompilation: {
    1046             :         DCHECK(!last_event_.has_value());
    1047         160 :         if (job_->DecrementAndCheckFinisherCount()) {
    1048          59 :           job_->DoSync<CompileFailed>();
    1049             :         }
    1050             :         break;
    1051             :       }
    1052             :       default:
    1053           0 :         UNREACHABLE();
    1054             :     }
    1055             : #ifdef DEBUG
    1056             :     last_event_ = event;
    1057             : #endif
    1058        2664 :   }
    1059             : 
    1060             :  private:
    1061             :   AsyncCompileJob* job_;
    1062             : #ifdef DEBUG
    1063             :   // This will be modified by different threads, but they externally
    1064             :   // synchronize, so no explicit synchronization (currently) needed here.
    1065             :   base::Optional<CompilationEvent> last_event_;
    1066             : #endif
    1067             : };
    1068             : 
    1069             : // A closure to run a compilation step (either as foreground or background
    1070             : // task) and schedule the next step(s), if any.
    1071        6024 : class AsyncCompileJob::CompileStep {
    1072             :  public:
    1073        6024 :   virtual ~CompileStep() = default;
    1074             : 
    1075        6021 :   void Run(AsyncCompileJob* job, bool on_foreground) {
    1076        6021 :     if (on_foreground) {
    1077        3858 :       HandleScope scope(job->isolate_);
    1078        3858 :       SaveAndSwitchContext saved_context(job->isolate_, *job->native_context_);
    1079        3858 :       RunInForeground(job);
    1080             :     } else {
    1081        2163 :       RunInBackground(job);
    1082             :     }
    1083        6021 :   }
    1084             : 
    1085           0 :   virtual void RunInForeground(AsyncCompileJob*) { UNREACHABLE(); }
    1086           0 :   virtual void RunInBackground(AsyncCompileJob*) { UNREACHABLE(); }
    1087             : };
    1088             : 
    1089             : class AsyncCompileJob::CompileTask : public CancelableTask {
    1090             :  public:
    1091             :   CompileTask(AsyncCompileJob* job, bool on_foreground)
    1092             :       // We only manage the background tasks with the {CancelableTaskManager} of
    1093             :       // the {AsyncCompileJob}. Foreground tasks are managed by the system's
    1094             :       // {CancelableTaskManager}. Background tasks cannot spawn tasks managed by
    1095             :       // their own task manager.
    1096        3861 :       : CancelableTask(on_foreground ? job->isolate_->cancelable_task_manager()
    1097             :                                      : &job->background_task_manager_),
    1098             :         job_(job),
    1099        8187 :         on_foreground_(on_foreground) {}
    1100             : 
    1101       18072 :   ~CompileTask() override {
    1102        6024 :     if (job_ != nullptr && on_foreground_) ResetPendingForegroundTask();
    1103       12048 :   }
    1104             : 
    1105        6020 :   void RunInternal() final {
    1106        6020 :     if (!job_) return;
    1107        6021 :     if (on_foreground_) ResetPendingForegroundTask();
    1108       12042 :     job_->step_->Run(job_, on_foreground_);
    1109             :     // After execution, reset {job_} such that we don't try to reset the pending
    1110             :     // foreground task when the task is deleted.
    1111        6021 :     job_ = nullptr;
    1112             :   }
    1113             : 
    1114             :   void Cancel() {
    1115             :     DCHECK_NOT_NULL(job_);
    1116           3 :     job_ = nullptr;
    1117             :   }
    1118             : 
    1119             :  private:
    1120             :   // {job_} will be cleared to cancel a pending task.
    1121             :   AsyncCompileJob* job_;
    1122             :   bool on_foreground_;
    1123             : 
    1124             :   void ResetPendingForegroundTask() const {
    1125             :     DCHECK_EQ(this, job_->pending_foreground_task_);
    1126        3858 :     job_->pending_foreground_task_ = nullptr;
    1127             :   }
    1128             : };
    1129             : 
    1130        3645 : void AsyncCompileJob::StartForegroundTask() {
    1131             :   DCHECK_NULL(pending_foreground_task_);
    1132             : 
    1133        3645 :   auto new_task = base::make_unique<CompileTask>(this, true);
    1134        3645 :   pending_foreground_task_ = new_task.get();
    1135       10935 :   foreground_task_runner_->PostTask(std::move(new_task));
    1136        3645 : }
    1137             : 
    1138         216 : void AsyncCompileJob::ExecuteForegroundTaskImmediately() {
    1139             :   DCHECK_NULL(pending_foreground_task_);
    1140             : 
    1141         216 :   auto new_task = base::make_unique<CompileTask>(this, true);
    1142         216 :   pending_foreground_task_ = new_task.get();
    1143         216 :   new_task->Run();
    1144         216 : }
    1145             : 
    1146           0 : void AsyncCompileJob::CancelPendingForegroundTask() {
    1147        2543 :   if (!pending_foreground_task_) return;
    1148             :   pending_foreground_task_->Cancel();
    1149           3 :   pending_foreground_task_ = nullptr;
    1150             : }
    1151             : 
    1152        2163 : void AsyncCompileJob::StartBackgroundTask() {
    1153        2163 :   auto task = base::make_unique<CompileTask>(this, false);
    1154             : 
    1155             :   // If --wasm-num-compilation-tasks=0 is passed, do only spawn foreground
    1156             :   // tasks. This is used to make timing deterministic.
    1157        2163 :   if (FLAG_wasm_num_compilation_tasks > 0) {
    1158        6489 :     V8::GetCurrentPlatform()->CallOnWorkerThread(std::move(task));
    1159             :   } else {
    1160           0 :     foreground_task_runner_->PostTask(std::move(task));
    1161             :   }
    1162        2163 : }
    1163             : 
    1164             : template <typename Step,
    1165             :           AsyncCompileJob::UseExistingForegroundTask use_existing_fg_task,
    1166             :           typename... Args>
    1167          56 : void AsyncCompileJob::DoSync(Args&&... args) {
    1168        3645 :   NextStep<Step>(std::forward<Args>(args)...);
    1169          56 :   if (use_existing_fg_task && pending_foreground_task_ != nullptr) return;
    1170        3645 :   StartForegroundTask();
    1171             : }
    1172             : 
    1173             : template <typename Step, typename... Args>
    1174             : void AsyncCompileJob::DoImmediately(Args&&... args) {
    1175         216 :   NextStep<Step>(std::forward<Args>(args)...);
    1176         216 :   ExecuteForegroundTaskImmediately();
    1177             : }
    1178             : 
    1179             : template <typename Step, typename... Args>
    1180             : void AsyncCompileJob::DoAsync(Args&&... args) {
    1181        2163 :   NextStep<Step>(std::forward<Args>(args)...);
    1182        2163 :   StartBackgroundTask();
    1183             : }
    1184             : 
    1185             : template <typename Step, typename... Args>
    1186        6024 : void AsyncCompileJob::NextStep(Args&&... args) {
    1187        6429 :   step_.reset(new Step(std::forward<Args>(args)...));
    1188        6024 : }
    1189             : 
    1190             : //==========================================================================
    1191             : // Step 1: (async) Decode the module.
    1192             : //==========================================================================
    1193        4326 : class AsyncCompileJob::DecodeModule : public AsyncCompileJob::CompileStep {
    1194             :  public:
    1195        2163 :   explicit DecodeModule(Counters* counters) : counters_(counters) {}
    1196             : 
    1197        2163 :   void RunInBackground(AsyncCompileJob* job) override {
    1198        2163 :     ModuleResult result;
    1199             :     {
    1200             :       DisallowHandleAllocation no_handle;
    1201             :       DisallowHeapAllocation no_allocation;
    1202             :       // Decode the module bytes.
    1203             :       TRACE_COMPILE("(1) Decoding module...\n");
    1204        6489 :       TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"),
    1205             :                    "AsyncCompileJob::DecodeModule");
    1206        4326 :       result = DecodeWasmModule(
    1207             :           job->enabled_features_, job->wire_bytes_.start(),
    1208        2163 :           job->wire_bytes_.end(), false, kWasmOrigin, counters_,
    1209        2163 :           job->isolate()->wasm_engine()->allocator());
    1210             :     }
    1211        2163 :     if (result.failed()) {
    1212             :       // Decoding failure; reject the promise and clean up.
    1213             :       job->DoSync<DecodeFail>(std::move(result).error());
    1214             :     } else {
    1215             :       // Decode passed.
    1216        4276 :       job->DoSync<PrepareAndStartCompile>(std::move(result).value(), true);
    1217             :     }
    1218        2163 :   }
    1219             : 
    1220             :  private:
    1221             :   Counters* const counters_;
    1222             : };
    1223             : 
    1224             : //==========================================================================
    1225             : // Step 1b: (sync) Fail decoding the module.
    1226             : //==========================================================================
    1227         378 : class AsyncCompileJob::DecodeFail : public CompileStep {
    1228             :  public:
    1229         189 :   explicit DecodeFail(WasmError error) : error_(std::move(error)) {}
    1230             : 
    1231             :  private:
    1232             :   WasmError error_;
    1233             : 
    1234         189 :   void RunInForeground(AsyncCompileJob* job) override {
    1235             :     TRACE_COMPILE("(1b) Decoding failed.\n");
    1236             :     // {job_} is deleted in DecodeFailed, therefore the {return}.
    1237         189 :     return job->DecodeFailed(error_);
    1238             :   }
    1239             : };
    1240             : 
    1241             : //==========================================================================
    1242             : // Step 2 (sync): Create heap-allocated data and start compile.
    1243             : //==========================================================================
    1244        4708 : class AsyncCompileJob::PrepareAndStartCompile : public CompileStep {
    1245             :  public:
    1246             :   PrepareAndStartCompile(std::shared_ptr<const WasmModule> module,
    1247             :                          bool start_compilation)
    1248        4708 :       : module_(std::move(module)), start_compilation_(start_compilation) {}
    1249             : 
    1250             :  private:
    1251             :   std::shared_ptr<const WasmModule> module_;
    1252             :   bool start_compilation_;
    1253             : 
    1254        2351 :   void RunInForeground(AsyncCompileJob* job) override {
    1255             :     TRACE_COMPILE("(2) Prepare and start compile...\n");
    1256             : 
    1257             :     // Make sure all compilation tasks stopped running. Decoding (async step)
    1258             :     // is done.
    1259        2351 :     job->background_task_manager_.CancelAndWait();
    1260             : 
    1261        4702 :     job->CreateNativeModule(module_);
    1262             : 
    1263             :     size_t num_functions =
    1264        2351 :         module_->functions.size() - module_->num_imported_functions;
    1265             : 
    1266        2351 :     if (num_functions == 0) {
    1267             :       // Degenerate case of an empty module.
    1268         896 :       job->FinishCompile();
    1269         896 :       return;
    1270             :     }
    1271             : 
    1272             :     CompilationStateImpl* compilation_state =
    1273             :         Impl(job->native_module_->compilation_state());
    1274        2910 :     compilation_state->AddCallback(CompilationStateCallback{job});
    1275        1455 :     if (start_compilation_) {
    1276             :       // TODO(ahaas): Try to remove the {start_compilation_} check when
    1277             :       // streaming decoding is done in the background. If
    1278             :       // InitializeCompilationUnits always returns 0 for streaming compilation,
    1279             :       // then DoAsync would do the same as NextStep already.
    1280             : 
    1281        1239 :       compilation_state->SetNumberOfFunctionsToCompile(
    1282        2478 :           module_->num_declared_functions);
    1283             :       // Add compilation units and kick off compilation.
    1284             :       InitializeCompilationUnits(job->native_module_.get(),
    1285        1239 :                                  job->isolate()->wasm_engine());
    1286             :     }
    1287             :   }
    1288             : };
    1289             : 
    1290             : //==========================================================================
    1291             : // Step 3a (sync): Compilation failed.
    1292             : //==========================================================================
    1293         177 : class AsyncCompileJob::CompileFailed : public CompileStep {
    1294             :  private:
    1295          59 :   void RunInForeground(AsyncCompileJob* job) override {
    1296             :     TRACE_COMPILE("(3a) Compilation failed\n");
    1297             :     DCHECK(job->native_module_->compilation_state()->failed());
    1298             : 
    1299             :     // {job_} is deleted in AsyncCompileFailed, therefore the {return}.
    1300          59 :     return job->AsyncCompileFailed();
    1301             :   }
    1302             : };
    1303             : 
    1304             : namespace {
    1305        1259 : class SampleTopTierCodeSizeCallback {
    1306             :  public:
    1307             :   explicit SampleTopTierCodeSizeCallback(
    1308             :       std::weak_ptr<NativeModule> native_module)
    1309             :       : native_module_(std::move(native_module)) {}
    1310             : 
    1311         351 :   void operator()(CompilationEvent event) {
    1312             :     // This callback is registered after baseline compilation finished, so the
    1313             :     // only possible event to follow is {kFinishedTopTierCompilation}.
    1314             :     DCHECK_EQ(CompilationEvent::kFinishedTopTierCompilation, event);
    1315         351 :     if (std::shared_ptr<NativeModule> native_module = native_module_.lock()) {
    1316             :       native_module->engine()->SampleTopTierCodeSizeInAllIsolates(
    1317         351 :           native_module);
    1318             :     }
    1319         351 :   }
    1320             : 
    1321             :  private:
    1322             :   std::weak_ptr<NativeModule> native_module_;
    1323             : };
    1324             : }  // namespace
    1325             : 
    1326             : //==========================================================================
    1327             : // Step 3b (sync): Compilation finished.
    1328             : //==========================================================================
    1329        3777 : class AsyncCompileJob::CompileFinished : public CompileStep {
    1330             :  private:
    1331        1259 :   void RunInForeground(AsyncCompileJob* job) override {
    1332             :     TRACE_COMPILE("(3b) Compilation finished\n");
    1333             :     DCHECK(!job->native_module_->compilation_state()->failed());
    1334             :     // Sample the generated code size when baseline compilation finished.
    1335        1259 :     job->native_module_->SampleCodeSize(job->isolate_->counters(),
    1336        1259 :                                         NativeModule::kAfterBaseline);
    1337             :     // Also, set a callback to sample the code size after top-tier compilation
    1338             :     // finished. This callback will *not* keep the NativeModule alive.
    1339        2518 :     job->native_module_->compilation_state()->AddCallback(
    1340        1259 :         SampleTopTierCodeSizeCallback{job->native_module_});
    1341             :     // Then finalize and publish the generated module.
    1342        1259 :     job->FinishCompile();
    1343        1259 :   }
    1344             : };
    1345             : 
    1346        2206 : void AsyncCompileJob::CompileWrappers() {
    1347             :   // TODO(wasm): Compile all wrappers here, including the start function wrapper
    1348             :   // and the wrappers for the function table elements.
    1349             :   TRACE_COMPILE("(5) Compile wrappers...\n");
    1350             :   // Compile JS->wasm wrappers for exported functions.
    1351        4412 :   CompileJsToWasmWrappers(isolate_, module_object_->native_module()->module(),
    1352        4412 :                           handle(module_object_->export_wrappers(), isolate_));
    1353        2206 : }
    1354             : 
    1355        2210 : void AsyncCompileJob::FinishModule() {
    1356             :   TRACE_COMPILE("(6) Finish module...\n");
    1357             :   AsyncCompileSucceeded(module_object_);
    1358        2210 :   isolate_->wasm_engine()->RemoveCompileJob(this);
    1359        2210 : }
    1360             : 
    1361           0 : AsyncStreamingProcessor::AsyncStreamingProcessor(AsyncCompileJob* job)
    1362             :     : decoder_(job->enabled_features_),
    1363             :       job_(job),
    1364         760 :       compilation_unit_builder_(nullptr) {}
    1365             : 
    1366         164 : void AsyncStreamingProcessor::FinishAsyncCompileJobWithError(
    1367             :     const WasmError& error) {
    1368             :   DCHECK(error.has_error());
    1369             :   // Make sure all background tasks stopped executing before we change the state
    1370             :   // of the AsyncCompileJob to DecodeFail.
    1371         164 :   job_->background_task_manager_.CancelAndWait();
    1372             : 
    1373             :   // Check if there is already a CompiledModule, in which case we have to clean
    1374             :   // up the CompilationStateImpl as well.
    1375         164 :   if (job_->native_module_) {
    1376          56 :     Impl(job_->native_module_->compilation_state())->AbortCompilation();
    1377             : 
    1378          56 :     job_->DoSync<AsyncCompileJob::DecodeFail,
    1379          56 :                  AsyncCompileJob::kUseExistingForegroundTask>(error);
    1380             : 
    1381             :     // Clear the {compilation_unit_builder_} if it exists. This is needed
    1382             :     // because there is a check in the destructor of the
    1383             :     // {CompilationUnitBuilder} that it is empty.
    1384          56 :     if (compilation_unit_builder_) compilation_unit_builder_->Clear();
    1385             :   } else {
    1386             :     job_->DoSync<AsyncCompileJob::DecodeFail>(error);
    1387             :   }
    1388         164 : }
    1389             : 
    1390             : // Process the module header.
    1391         352 : bool AsyncStreamingProcessor::ProcessModuleHeader(Vector<const uint8_t> bytes,
    1392             :                                                   uint32_t offset) {
    1393             :   TRACE_STREAMING("Process module header...\n");
    1394         352 :   decoder_.StartDecoding(job_->isolate()->counters(),
    1395         704 :                          job_->isolate()->wasm_engine()->allocator());
    1396         352 :   decoder_.DecodeModuleHeader(bytes, offset);
    1397         352 :   if (!decoder_.ok()) {
    1398          16 :     FinishAsyncCompileJobWithError(decoder_.FinishDecoding(false).error());
    1399          16 :     return false;
    1400             :   }
    1401             :   return true;
    1402             : }
    1403             : 
    1404             : // Process all sections except for the code section.
    1405         804 : bool AsyncStreamingProcessor::ProcessSection(SectionCode section_code,
    1406             :                                              Vector<const uint8_t> bytes,
    1407             :                                              uint32_t offset) {
    1408             :   TRACE_STREAMING("Process section %d ...\n", section_code);
    1409         804 :   if (compilation_unit_builder_) {
    1410             :     // We reached a section after the code section, we do not need the
    1411             :     // compilation_unit_builder_ anymore.
    1412             :     CommitCompilationUnits();
    1413             :     compilation_unit_builder_.reset();
    1414             :   }
    1415         804 :   if (section_code == SectionCode::kUnknownSectionCode) {
    1416             :     Decoder decoder(bytes, offset);
    1417             :     section_code = ModuleDecoder::IdentifyUnknownSection(
    1418          72 :         decoder, bytes.start() + bytes.length());
    1419          72 :     if (section_code == SectionCode::kUnknownSectionCode) {
    1420             :       // Skip unknown sections that we do not know how to handle.
    1421             :       return true;
    1422             :     }
    1423             :     // Remove the unknown section tag from the payload bytes.
    1424          72 :     offset += decoder.position();
    1425          72 :     bytes = bytes.SubVector(decoder.position(), bytes.size());
    1426             :   }
    1427             :   constexpr bool verify_functions = false;
    1428         804 :   decoder_.DecodeSection(section_code, bytes, offset, verify_functions);
    1429         804 :   if (!decoder_.ok()) {
    1430          20 :     FinishAsyncCompileJobWithError(decoder_.FinishDecoding(false).error());
    1431          20 :     return false;
    1432             :   }
    1433             :   return true;
    1434             : }
    1435             : 
    1436             : // Start the code section.
    1437         228 : bool AsyncStreamingProcessor::ProcessCodeSectionHeader(
    1438             :     int functions_count, uint32_t offset,
    1439             :     std::shared_ptr<WireBytesStorage> wire_bytes_storage) {
    1440             :   TRACE_STREAMING("Start the code section with %d functions...\n",
    1441             :                   functions_count);
    1442         228 :   if (!decoder_.CheckFunctionsCount(static_cast<uint32_t>(functions_count),
    1443             :                                     offset)) {
    1444          12 :     FinishAsyncCompileJobWithError(decoder_.FinishDecoding(false).error());
    1445          12 :     return false;
    1446             :   }
    1447             :   // Execute the PrepareAndStartCompile step immediately and not in a separate
    1448             :   // task.
    1449         648 :   job_->DoImmediately<AsyncCompileJob::PrepareAndStartCompile>(
    1450         216 :       decoder_.shared_module(), false);
    1451         432 :   job_->native_module_->compilation_state()->SetWireBytesStorage(
    1452         216 :       std::move(wire_bytes_storage));
    1453             : 
    1454         216 :   auto* compilation_state = Impl(job_->native_module_->compilation_state());
    1455         216 :   compilation_state->SetNumberOfFunctionsToCompile(functions_count);
    1456             : 
    1457             :   // Set outstanding_finishers_ to 2, because both the AsyncCompileJob and the
    1458             :   // AsyncStreamingProcessor have to finish.
    1459         216 :   job_->outstanding_finishers_.store(2);
    1460         216 :   compilation_unit_builder_.reset(new CompilationUnitBuilder(
    1461         216 :       job_->native_module_.get(), job_->isolate()->wasm_engine()));
    1462             :   return true;
    1463             : }
    1464             : 
    1465             : // Process a function body.
    1466         452 : bool AsyncStreamingProcessor::ProcessFunctionBody(Vector<const uint8_t> bytes,
    1467             :                                                   uint32_t offset) {
    1468             :   TRACE_STREAMING("Process function body %d ...\n", num_functions_);
    1469             : 
    1470         904 :   decoder_.DecodeFunctionBody(
    1471         904 :       num_functions_, static_cast<uint32_t>(bytes.length()), offset, false);
    1472             : 
    1473         904 :   int index = num_functions_ + decoder_.module()->num_imported_functions;
    1474         452 :   compilation_unit_builder_->AddUnit(index);
    1475         452 :   ++num_functions_;
    1476             :   // This method always succeeds. The return value is necessary to comply with
    1477             :   // the StreamingProcessor interface.
    1478         452 :   return true;
    1479             : }
    1480             : 
    1481           0 : void AsyncStreamingProcessor::CommitCompilationUnits() {
    1482             :   DCHECK(compilation_unit_builder_);
    1483         292 :   compilation_unit_builder_->Commit();
    1484           0 : }
    1485             : 
    1486         356 : void AsyncStreamingProcessor::OnFinishedChunk() {
    1487             :   TRACE_STREAMING("FinishChunk...\n");
    1488         356 :   if (compilation_unit_builder_) CommitCompilationUnits();
    1489         356 : }
    1490             : 
    1491             : // Finish the processing of the stream.
    1492         152 : void AsyncStreamingProcessor::OnFinishedStream(OwnedVector<uint8_t> bytes) {
    1493             :   TRACE_STREAMING("Finish stream...\n");
    1494         452 :   ModuleResult result = decoder_.FinishDecoding(false);
    1495         152 :   if (result.failed()) {
    1496           4 :     FinishAsyncCompileJobWithError(result.error());
    1497           4 :     return;
    1498             :   }
    1499             :   // We have to open a HandleScope and prepare the Context for
    1500             :   // CreateNativeModule, PrepareRuntimeObjects and FinishCompile as this is a
    1501             :   // callback from the embedder.
    1502         148 :   HandleScope scope(job_->isolate_);
    1503         296 :   SaveAndSwitchContext saved_context(job_->isolate_, *job_->native_context_);
    1504             : 
    1505         148 :   bool needs_finish = job_->DecrementAndCheckFinisherCount();
    1506         148 :   if (job_->native_module_ == nullptr) {
    1507             :     // We are processing a WebAssembly module without code section. Create the
    1508             :     // runtime objects now (would otherwise happen in {PrepareAndStartCompile}).
    1509          40 :     job_->CreateNativeModule(std::move(result).value());
    1510             :     DCHECK(needs_finish);
    1511             :   }
    1512         296 :   job_->wire_bytes_ = ModuleWireBytes(bytes.as_vector());
    1513         296 :   job_->native_module_->SetWireBytes(std::move(bytes));
    1514         148 :   if (needs_finish) {
    1515         136 :     if (job_->native_module_->compilation_state()->failed()) {
    1516          17 :       job_->AsyncCompileFailed();
    1517             :     } else {
    1518          51 :       job_->FinishCompile();
    1519             :     }
    1520             :   }
    1521             : }
    1522             : 
    1523             : // Report an error detected in the StreamingDecoder.
    1524         112 : void AsyncStreamingProcessor::OnError(const WasmError& error) {
    1525             :   TRACE_STREAMING("Stream error...\n");
    1526         112 :   FinishAsyncCompileJobWithError(error);
    1527         112 : }
    1528             : 
    1529          56 : void AsyncStreamingProcessor::OnAbort() {
    1530             :   TRACE_STREAMING("Abort stream...\n");
    1531          56 :   job_->Abort();
    1532          56 : }
    1533             : 
    1534           8 : bool AsyncStreamingProcessor::Deserialize(Vector<const uint8_t> module_bytes,
    1535             :                                           Vector<const uint8_t> wire_bytes) {
    1536             :   // DeserializeNativeModule and FinishCompile assume that they are executed in
    1537             :   // a HandleScope, and that a context is set on the isolate.
    1538           8 :   HandleScope scope(job_->isolate_);
    1539          16 :   SaveAndSwitchContext saved_context(job_->isolate_, *job_->native_context_);
    1540             : 
    1541             :   MaybeHandle<WasmModuleObject> result =
    1542           8 :       DeserializeNativeModule(job_->isolate_, module_bytes, wire_bytes);
    1543           8 :   if (result.is_null()) return false;
    1544             : 
    1545             :   job_->module_object_ =
    1546           8 :       job_->isolate_->global_handles()->Create(*result.ToHandleChecked());
    1547          12 :   job_->native_module_ = job_->module_object_->shared_native_module();
    1548           4 :   auto owned_wire_bytes = OwnedVector<uint8_t>::Of(wire_bytes);
    1549           8 :   job_->wire_bytes_ = ModuleWireBytes(owned_wire_bytes.as_vector());
    1550           8 :   job_->native_module_->SetWireBytes(std::move(owned_wire_bytes));
    1551           4 :   job_->FinishCompile();
    1552             :   return true;
    1553             : }
    1554             : 
    1555     1241902 : CompilationStateImpl::CompilationStateImpl(
    1556             :     const std::shared_ptr<NativeModule>& native_module,
    1557             :     std::shared_ptr<Counters> async_counters)
    1558             :     : native_module_(native_module.get()),
    1559             :       background_compile_token_(
    1560             :           std::make_shared<BackgroundCompileToken>(native_module)),
    1561     1241492 :       compile_mode_(FLAG_wasm_tier_up &&
    1562     1241492 :                             native_module->module()->origin == kWasmOrigin
    1563             :                         ? CompileMode::kTiering
    1564             :                         : CompileMode::kRegular),
    1565             :       async_counters_(std::move(async_counters)),
    1566             :       max_background_tasks_(std::max(
    1567             :           1, std::min(FLAG_wasm_num_compilation_tasks,
    1568    11177118 :                       V8::GetCurrentPlatform()->NumberOfWorkerThreads()))) {}
    1569             : 
    1570     1242122 : void CompilationStateImpl::AbortCompilation() {
    1571     1242122 :   background_compile_token_->Cancel();
    1572             :   // No more callbacks after abort.
    1573     1242122 :   base::MutexGuard callbacks_guard(&callbacks_mutex_);
    1574             :   callbacks_.clear();
    1575     1242122 : }
    1576             : 
    1577        6617 : void CompilationStateImpl::SetNumberOfFunctionsToCompile(int num_functions) {
    1578             :   DCHECK(!failed());
    1579        6617 :   base::MutexGuard guard(&callbacks_mutex_);
    1580        6617 :   outstanding_baseline_units_ = num_functions;
    1581             : 
    1582        6617 :   if (compile_mode_ == CompileMode::kTiering) {
    1583        6505 :     outstanding_tiering_units_ = num_functions;
    1584             :   }
    1585        6617 : }
    1586             : 
    1587        2718 : void CompilationStateImpl::AddCallback(CompilationState::callback_t callback) {
    1588        2718 :   base::MutexGuard callbacks_guard(&callbacks_mutex_);
    1589        2718 :   callbacks_.emplace_back(std::move(callback));
    1590        2718 : }
    1591             : 
    1592        6629 : void CompilationStateImpl::AddCompilationUnits(
    1593             :     std::vector<std::unique_ptr<WasmCompilationUnit>>& baseline_units,
    1594             :     std::vector<std::unique_ptr<WasmCompilationUnit>>& tiering_units) {
    1595             :   {
    1596        6629 :     base::MutexGuard guard(&mutex_);
    1597             : 
    1598             :     DCHECK_LE(tiering_units.size(), baseline_units.size());
    1599             :     DCHECK_IMPLIES(compile_mode_ == CompileMode::kTiering &&
    1600             :                        !native_module_->enabled_features().compilation_hints,
    1601             :                    tiering_units.size() == baseline_units.size());
    1602             :     DCHECK_IMPLIES(compile_mode_ == CompileMode::kTiering &&
    1603             :                        !native_module_->enabled_features().compilation_hints,
    1604             :                    tiering_units.back()->tier() == ExecutionTier::kOptimized);
    1605             :     DCHECK_IMPLIES(compile_mode_ == CompileMode::kRegular,
    1606             :                    tiering_compilation_units_.empty());
    1607             : 
    1608             :     baseline_compilation_units_.insert(
    1609             :         baseline_compilation_units_.end(),
    1610             :         std::make_move_iterator(baseline_units.begin()),
    1611        6629 :         std::make_move_iterator(baseline_units.end()));
    1612        6629 :     if (!tiering_units.empty()) {
    1613             :       tiering_compilation_units_.insert(
    1614             :           tiering_compilation_units_.end(),
    1615             :           std::make_move_iterator(tiering_units.begin()),
    1616        6517 :           std::make_move_iterator(tiering_units.end()));
    1617             :     }
    1618             :   }
    1619             : 
    1620        6629 :   RestartBackgroundTasks();
    1621        6629 : }
    1622             : 
    1623             : std::unique_ptr<WasmCompilationUnit>
    1624     5587964 : CompilationStateImpl::GetNextCompilationUnit() {
    1625     5587964 :   base::MutexGuard guard(&mutex_);
    1626             : 
    1627             :   std::vector<std::unique_ptr<WasmCompilationUnit>>& units =
    1628             :       baseline_compilation_units_.empty() ? tiering_compilation_units_
    1629     5588880 :                                           : baseline_compilation_units_;
    1630             : 
    1631     5588880 :   if (!units.empty()) {
    1632      204965 :     std::unique_ptr<WasmCompilationUnit> unit = std::move(units.back());
    1633             :     units.pop_back();
    1634             :     return unit;
    1635             :   }
    1636             : 
    1637             :   return std::unique_ptr<WasmCompilationUnit>();
    1638             : }
    1639             : 
    1640      203560 : void CompilationStateImpl::OnFinishedUnit(ExecutionTier tier, WasmCode* code) {
    1641             :   // This mutex guarantees that events happen in the right order.
    1642      203560 :   base::MutexGuard guard(&callbacks_mutex_);
    1643             : 
    1644             :   // If we are *not* compiling in tiering mode, then all units are counted as
    1645             :   // baseline units.
    1646      203708 :   bool is_tiering_mode = compile_mode_ == CompileMode::kTiering;
    1647      203708 :   bool is_tiering_unit = is_tiering_mode && tier == ExecutionTier::kOptimized;
    1648             : 
    1649             :   // Sanity check: If we are not in tiering mode, there cannot be outstanding
    1650             :   // tiering units.
    1651             :   DCHECK_IMPLIES(!is_tiering_mode, outstanding_tiering_units_ == 0);
    1652             : 
    1653             :   bool baseline_finished = false;
    1654             :   bool tiering_finished = false;
    1655      203708 :   if (is_tiering_unit) {
    1656             :     DCHECK_LT(0, outstanding_tiering_units_);
    1657      101613 :     --outstanding_tiering_units_;
    1658      101613 :     tiering_finished = outstanding_tiering_units_ == 0;
    1659             :     // If baseline compilation has not finished yet, then also trigger
    1660             :     // {kFinishedBaselineCompilation}.
    1661      101613 :     baseline_finished = tiering_finished && outstanding_baseline_units_ > 0;
    1662             :   } else {
    1663             :     DCHECK_LT(0, outstanding_baseline_units_);
    1664      102095 :     --outstanding_baseline_units_;
    1665             :     // If we are in tiering mode and tiering finished before, then do not
    1666             :     // trigger baseline finished.
    1667      102095 :     baseline_finished = outstanding_baseline_units_ == 0 &&
    1668        5968 :                         (!is_tiering_mode || outstanding_tiering_units_ > 0);
    1669             :     // If we are not tiering, then we also trigger the "top tier finished"
    1670             :     // event when baseline compilation is finished.
    1671      102095 :     tiering_finished = baseline_finished && !is_tiering_mode;
    1672             :   }
    1673             : 
    1674      203708 :   if (baseline_finished) {
    1675        7378 :     for (auto& callback : callbacks_)
    1676             :       callback(CompilationEvent::kFinishedBaselineCompilation);
    1677             :   }
    1678      203708 :   if (tiering_finished) {
    1679        7698 :     for (auto& callback : callbacks_)
    1680             :       callback(CompilationEvent::kFinishedTopTierCompilation);
    1681             :     // Clear the callbacks because no more events will be delivered.
    1682             :     callbacks_.clear();
    1683             :   }
    1684             : 
    1685      203708 :   if (code != nullptr) native_module_->engine()->LogCode(code);
    1686      203705 : }
    1687             : 
    1688       32898 : void CompilationStateImpl::RestartBackgroundCompileTask() {
    1689             :   auto task =
    1690       32898 :       native_module_->engine()->NewBackgroundCompileTask<BackgroundCompileTask>(
    1691       65796 :           background_compile_token_, async_counters_);
    1692             : 
    1693       32898 :   if (baseline_compilation_finished()) {
    1694       20392 :     V8::GetCurrentPlatform()->CallLowPriorityTaskOnWorkerThread(
    1695       20392 :         std::move(task));
    1696             :   } else {
    1697       68106 :     V8::GetCurrentPlatform()->CallOnWorkerThread(std::move(task));
    1698             :   }
    1699       32898 : }
    1700             : 
    1701          65 : void CompilationStateImpl::ReportDetectedFeatures(
    1702             :     const WasmFeatures& detected) {
    1703          65 :   base::MutexGuard guard(&mutex_);
    1704          65 :   UnionFeaturesInto(&detected_features_, detected);
    1705          65 : }
    1706             : 
    1707       31305 : void CompilationStateImpl::OnBackgroundTaskStopped(
    1708             :     const WasmFeatures& detected) {
    1709       31305 :   base::MutexGuard guard(&mutex_);
    1710             :   DCHECK_LE(1, num_background_tasks_);
    1711       31325 :   --num_background_tasks_;
    1712       31325 :   UnionFeaturesInto(&detected_features_, detected);
    1713       31323 : }
    1714             : 
    1715        7372 : void CompilationStateImpl::PublishDetectedFeatures(
    1716             :     Isolate* isolate, const WasmFeatures& detected) {
    1717             :   // Notifying the isolate of the feature counts must take place under
    1718             :   // the mutex, because even if we have finished baseline compilation,
    1719             :   // tiering compilations may still occur in the background.
    1720        7372 :   base::MutexGuard guard(&mutex_);
    1721        7372 :   UnionFeaturesInto(&detected_features_, detected);
    1722             :   UpdateFeatureUseCounts(isolate, detected_features_);
    1723        7372 : }
    1724             : 
    1725        6629 : void CompilationStateImpl::RestartBackgroundTasks() {
    1726             :   int num_restart;
    1727             :   {
    1728        6629 :     base::MutexGuard guard(&mutex_);
    1729             :     // No need to restart tasks if compilation already failed.
    1730        6629 :     if (failed()) return;
    1731             : 
    1732             :     DCHECK_LE(num_background_tasks_, max_background_tasks_);
    1733        6625 :     if (num_background_tasks_ == max_background_tasks_) return;
    1734             :     size_t num_compilation_units =
    1735        6625 :         baseline_compilation_units_.size() + tiering_compilation_units_.size();
    1736        6625 :     num_restart = max_background_tasks_ - num_background_tasks_;
    1737             :     DCHECK_LE(0, num_restart);
    1738        6625 :     if (num_compilation_units < static_cast<size_t>(num_restart)) {
    1739        4414 :       num_restart = static_cast<int>(num_compilation_units);
    1740             :     }
    1741        6625 :     num_background_tasks_ += num_restart;
    1742             :   }
    1743             : 
    1744       72291 :   for (; num_restart > 0; --num_restart) {
    1745       32833 :     RestartBackgroundCompileTask();
    1746             :   }
    1747             : }
    1748             : 
    1749        7610 : void CompilationStateImpl::SetError() {
    1750        7610 :   bool expected = false;
    1751        7610 :   if (!compile_failed_.compare_exchange_strong(expected, true,
    1752             :                                                std::memory_order_relaxed)) {
    1753          25 :     return;  // Already failed before.
    1754             :   }
    1755             : 
    1756        7585 :   base::MutexGuard callbacks_guard(&callbacks_mutex_);
    1757        7665 :   for (auto& callback : callbacks_) {
    1758             :     callback(CompilationEvent::kFailedCompilation);
    1759             :   }
    1760             :   // No more callbacks after an error.
    1761             :   callbacks_.clear();
    1762             : }
    1763             : 
    1764      139645 : void CompileJsToWasmWrappers(Isolate* isolate, const WasmModule* module,
    1765             :                              Handle<FixedArray> export_wrappers) {
    1766             :   JSToWasmWrapperCache js_to_wasm_cache;
    1767             :   int wrapper_index = 0;
    1768             : 
    1769             :   // TODO(6792): Wrappers below are allocated with {Factory::NewCode}. As an
    1770             :   // optimization we keep the code space unlocked to avoid repeated unlocking
    1771             :   // because many such wrapper are allocated in sequence below.
    1772      279292 :   CodeSpaceMemoryModificationScope modification_scope(isolate->heap());
    1773      362785 :   for (auto exp : module->export_table) {
    1774      223138 :     if (exp.kind != kExternalFunction) continue;
    1775      220386 :     auto& function = module->functions[exp.index];
    1776             :     Handle<Code> wrapper_code = js_to_wasm_cache.GetOrCompileJSToWasmWrapper(
    1777      220386 :         isolate, function.sig, function.imported);
    1778      440768 :     export_wrappers->set(wrapper_index, *wrapper_code);
    1779      220385 :     RecordStats(*wrapper_code, isolate->counters());
    1780      220386 :     ++wrapper_index;
    1781             :   }
    1782      139647 : }
    1783             : 
    1784      137189 : Handle<Script> CreateWasmScript(Isolate* isolate,
    1785             :                                 const ModuleWireBytes& wire_bytes,
    1786             :                                 const std::string& source_map_url) {
    1787             :   Handle<Script> script =
    1788      137189 :       isolate->factory()->NewScript(isolate->factory()->empty_string());
    1789      411569 :   script->set_context_data(isolate->native_context()->debug_context_id());
    1790             :   script->set_type(Script::TYPE_WASM);
    1791             : 
    1792      137189 :   int hash = StringHasher::HashSequentialString(
    1793             :       reinterpret_cast<const char*>(wire_bytes.start()),
    1794      137189 :       static_cast<int>(wire_bytes.length()), kZeroHashSeed);
    1795             : 
    1796             :   const int kBufferSize = 32;
    1797             :   char buffer[kBufferSize];
    1798             : 
    1799      137189 :   int name_chars = SNPrintF(ArrayVector(buffer), "wasm-%08x", hash);
    1800             :   DCHECK(name_chars >= 0 && name_chars < kBufferSize);
    1801             :   MaybeHandle<String> name_str = isolate->factory()->NewStringFromOneByte(
    1802      137189 :       VectorOf(reinterpret_cast<uint8_t*>(buffer), name_chars),
    1803      137189 :       AllocationType::kOld);
    1804      274378 :   script->set_name(*name_str.ToHandleChecked());
    1805             : 
    1806      137189 :   if (source_map_url.size() != 0) {
    1807             :     MaybeHandle<String> src_map_str = isolate->factory()->NewStringFromUtf8(
    1808           4 :         CStrVector(source_map_url.c_str()), AllocationType::kOld);
    1809           8 :     script->set_source_mapping_url(*src_map_str.ToHandleChecked());
    1810             :   }
    1811      137189 :   return script;
    1812             : }
    1813             : 
    1814             : }  // namespace wasm
    1815             : }  // namespace internal
    1816      120216 : }  // namespace v8
    1817             : 
    1818             : #undef TRACE_COMPILE
    1819             : #undef TRACE_STREAMING
    1820             : #undef TRACE_LAZY

Generated by: LCOV version 1.10