LCOV - code coverage report
Current view: top level - src/wasm - module-compiler.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 678 701 96.7 %
Date: 2019-04-17 Functions: 103 119 86.6 %

          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 <algorithm>
       8             : 
       9             : #include "src/api.h"
      10             : #include "src/asmjs/asm-js.h"
      11             : #include "src/base/enum-set.h"
      12             : #include "src/base/optional.h"
      13             : #include "src/base/platform/mutex.h"
      14             : #include "src/base/platform/semaphore.h"
      15             : #include "src/base/template-utils.h"
      16             : #include "src/base/utils/random-number-generator.h"
      17             : #include "src/compiler/wasm-compiler.h"
      18             : #include "src/counters.h"
      19             : #include "src/heap/heap-inl.h"  // For CodeSpaceMemoryModificationScope.
      20             : #include "src/identity-map.h"
      21             : #include "src/property-descriptor.h"
      22             : #include "src/task-utils.h"
      23             : #include "src/tracing/trace-event.h"
      24             : #include "src/trap-handler/trap-handler.h"
      25             : #include "src/wasm/js-to-wasm-wrapper-cache.h"
      26             : #include "src/wasm/module-decoder.h"
      27             : #include "src/wasm/streaming-decoder.h"
      28             : #include "src/wasm/wasm-code-manager.h"
      29             : #include "src/wasm/wasm-engine.h"
      30             : #include "src/wasm/wasm-import-wrapper-cache.h"
      31             : #include "src/wasm/wasm-js.h"
      32             : #include "src/wasm/wasm-limits.h"
      33             : #include "src/wasm/wasm-memory.h"
      34             : #include "src/wasm/wasm-objects-inl.h"
      35             : #include "src/wasm/wasm-result.h"
      36             : #include "src/wasm/wasm-serialization.h"
      37             : 
      38             : #define TRACE_COMPILE(...)                             \
      39             :   do {                                                 \
      40             :     if (FLAG_trace_wasm_compiler) PrintF(__VA_ARGS__); \
      41             :   } while (false)
      42             : 
      43             : #define TRACE_STREAMING(...)                            \
      44             :   do {                                                  \
      45             :     if (FLAG_trace_wasm_streaming) PrintF(__VA_ARGS__); \
      46             :   } while (false)
      47             : 
      48             : #define TRACE_LAZY(...)                                        \
      49             :   do {                                                         \
      50             :     if (FLAG_trace_wasm_lazy_compilation) PrintF(__VA_ARGS__); \
      51             :   } while (false)
      52             : 
      53             : namespace v8 {
      54             : namespace internal {
      55             : namespace wasm {
      56             : 
      57             : namespace {
      58             : 
      59             : enum class CompileMode : uint8_t { kRegular, kTiering };
      60             : 
      61             : // Background compile jobs hold a shared pointer to this token. The token is
      62             : // used to notify them that they should stop. As soon as they see this (after
      63             : // finishing their current compilation unit), they will stop.
      64             : // This allows to already remove the NativeModule without having to synchronize
      65             : // on background compile jobs.
      66     2485960 : class BackgroundCompileToken {
      67             :  public:
      68             :   explicit BackgroundCompileToken(
      69             :       const std::shared_ptr<NativeModule>& native_module)
      70     1242981 :       : native_module_(native_module) {}
      71             : 
      72     1251100 :   void Cancel() {
      73     1251100 :     base::SharedMutexGuard<base::kExclusive> mutex_guard(&mutex_);
      74             :     native_module_.reset();
      75     1251100 :   }
      76             : 
      77             :  private:
      78             :   friend class BackgroundCompileScope;
      79             :   base::SharedMutex mutex_;
      80             :   std::weak_ptr<NativeModule> native_module_;
      81             : 
      82             :   std::shared_ptr<NativeModule> StartScope() {
      83      812117 :     mutex_.LockShared();
      84             :     return native_module_.lock();
      85             :   }
      86             : 
      87      815985 :   void ExitScope() { mutex_.UnlockShared(); }
      88             : };
      89             : 
      90             : class CompilationStateImpl;
      91             : 
      92             : // Keep these scopes short, as they hold the mutex of the token, which
      93             : // sequentializes all these scopes. The mutex is also acquired from foreground
      94             : // tasks, which should not be blocked for a long time.
      95             : class BackgroundCompileScope {
      96             :  public:
      97      812117 :   explicit BackgroundCompileScope(
      98             :       const std::shared_ptr<BackgroundCompileToken>& token)
      99     1628250 :       : token_(token.get()), native_module_(token->StartScope()) {}
     100             : 
     101     1632059 :   ~BackgroundCompileScope() { token_->ExitScope(); }
     102             : 
     103             :   bool cancelled() const { return native_module_ == nullptr; }
     104             : 
     105             :   NativeModule* native_module() {
     106             :     DCHECK(!cancelled());
     107             :     return native_module_.get();
     108             :   }
     109             : 
     110             :   inline CompilationStateImpl* compilation_state();
     111             : 
     112             :  private:
     113             :   BackgroundCompileToken* const token_;
     114             :   // Keep the native module alive while in this scope.
     115             :   std::shared_ptr<NativeModule> const native_module_;
     116             : };
     117             : 
     118             : enum CompileBaselineOnly : bool {
     119             :   kBaselineOnly = true,
     120             :   kBaselineOrTopTier = false
     121             : };
     122             : 
     123             : // A set of work-stealing queues (vectors of units). Each background compile
     124             : // task owns one of the queues and steals from all others once its own queue
     125             : // runs empty.
     126     1242981 : class CompilationUnitQueues {
     127             :  public:
     128     1242981 :   explicit CompilationUnitQueues(int max_tasks) : queues_(max_tasks) {
     129             :     DCHECK_LT(0, max_tasks);
     130    18644619 :     for (int task_id = 0; task_id < max_tasks; ++task_id) {
     131    17401638 :       queues_[task_id].next_steal_task_id_ = next_task_id(task_id);
     132             :     }
     133     3728943 :     for (auto& atomic_counter : num_units_) {
     134             :       std::atomic_init(&atomic_counter, size_t{0});
     135             :     }
     136     1242981 :   }
     137             : 
     138      794575 :   std::unique_ptr<WasmCompilationUnit> GetNextUnit(
     139             :       int task_id, CompileBaselineOnly baseline_only) {
     140             :     DCHECK_LE(0, task_id);
     141             :     DCHECK_GT(queues_.size(), task_id);
     142             : 
     143             :     // As long as any lower-tier units are outstanding we need to steal them
     144             :     // before executing own higher-tier units.
     145      794575 :     int max_tier = baseline_only ? kBaseline : kTopTier;
     146      833661 :     for (int tier = GetLowestTierWithUnits(); tier <= max_tier; ++tier) {
     147      352611 :       Queue* queue = &queues_[task_id];
     148             :       // First, check whether our own queue has a unit of the wanted tier. If
     149             :       // so, return it, otherwise get the task id to steal from.
     150             :       int steal_task_id;
     151             :       {
     152      352611 :         base::MutexGuard mutex_guard(&queue->mutex_);
     153      352797 :         if (!queue->units_[tier].empty()) {
     154      314852 :           auto unit = std::move(queue->units_[tier].back());
     155             :           queue->units_[tier].pop_back();
     156             :           DecrementUnitCount(tier);
     157             :           return unit;
     158             :         }
     159       37888 :         steal_task_id = queue->next_steal_task_id_;
     160             :       }
     161             : 
     162             :       // Try to steal from all other queues. If none of this succeeds, the outer
     163             :       // loop increases the tier and retries.
     164             :       size_t steal_trials = queues_.size();
     165      609778 :       for (; steal_trials > 0;
     166             :            --steal_trials, steal_task_id = next_task_id(steal_task_id)) {
     167      208947 :         if (steal_task_id == task_id) continue;
     168      538212 :         if (auto unit = StealUnitsAndGetFirst(task_id, steal_task_id, tier)) {
     169             :           DecrementUnitCount(tier);
     170       18344 :           return unit;
     171             :         }
     172             :       }
     173             :     }
     174             :     return {};
     175             :   }
     176             : 
     177      138919 :   void AddUnits(Vector<std::unique_ptr<WasmCompilationUnit>> baseline_units,
     178             :                 Vector<std::unique_ptr<WasmCompilationUnit>> top_tier_units) {
     179             :     DCHECK_LT(0, baseline_units.size() + top_tier_units.size());
     180             :     // Add to the individual queues in a round-robin fashion. No special care is
     181             :     // taken to balance them; they will be balanced by work stealing.
     182      138919 :     int queue_to_add = next_queue_to_add.load(std::memory_order_relaxed);
     183      277838 :     while (!next_queue_to_add.compare_exchange_weak(
     184             :         queue_to_add, next_task_id(queue_to_add), std::memory_order_relaxed)) {
     185             :       // Retry with updated {queue_to_add}.
     186             :     }
     187             : 
     188      138919 :     Queue* queue = &queues_[queue_to_add];
     189      138919 :     base::MutexGuard guard(&queue->mutex_);
     190      138918 :     if (!baseline_units.empty()) {
     191             :       queue->units_[kBaseline].insert(
     192             :           queue->units_[kBaseline].end(),
     193             :           std::make_move_iterator(baseline_units.begin()),
     194      138851 :           std::make_move_iterator(baseline_units.end()));
     195             :       num_units_[kBaseline].fetch_add(baseline_units.size(),
     196             :                                       std::memory_order_relaxed);
     197             :     }
     198      138920 :     if (!top_tier_units.empty()) {
     199             :       queue->units_[kTopTier].insert(
     200             :           queue->units_[kTopTier].end(),
     201             :           std::make_move_iterator(top_tier_units.begin()),
     202       52073 :           std::make_move_iterator(top_tier_units.end()));
     203             :       num_units_[kTopTier].fetch_add(top_tier_units.size(),
     204             :                                      std::memory_order_relaxed);
     205             :     }
     206      138919 :   }
     207             : 
     208             :   // Get the current total number of units in all queues. This is only a
     209             :   // momentary snapshot, it's not guaranteed that {GetNextUnit} returns a unit
     210             :   // if this method returns non-zero.
     211             :   size_t GetTotalSize() const {
     212             :     size_t total = 0;
     213     1061245 :     for (auto& atomic_counter : num_units_) {
     214      707504 :       total += atomic_counter.load(std::memory_order_relaxed);
     215             :     }
     216             :     return total;
     217             :   }
     218             : 
     219             :  private:
     220             :   // Store tier in int so we can easily loop over it:
     221             :   static constexpr int kBaseline = 0;
     222             :   static constexpr int kTopTier = 1;
     223             :   static constexpr int kNumTiers = kTopTier + 1;
     224             : 
     225    34803276 :   struct Queue {
     226             :     base::Mutex mutex_;
     227             : 
     228             :     // Protected by {mutex_}:
     229             :     std::vector<std::unique_ptr<WasmCompilationUnit>> units_[kNumTiers];
     230             :     int next_steal_task_id_;
     231             :     // End of fields protected by {mutex_}.
     232             :   };
     233             : 
     234             :   std::vector<Queue> queues_;
     235             : 
     236             :   std::atomic<size_t> num_units_[kNumTiers];
     237             :   std::atomic<int> next_queue_to_add{0};
     238             : 
     239             :   int next_task_id(int task_id) const {
     240     9048720 :     int next = task_id + 1;
     241     9048720 :     return next == static_cast<int>(queues_.size()) ? 0 : next;
     242             :   }
     243             : 
     244             :   int GetLowestTierWithUnits() const {
     245     2743241 :     for (int tier = 0; tier < kNumTiers; ++tier) {
     246     1350922 :       if (num_units_[tier].load(std::memory_order_relaxed) > 0) return tier;
     247             :     }
     248             :     return kNumTiers;
     249             :   }
     250             : 
     251             :   void DecrementUnitCount(int tier) {
     252             :     size_t old_units_count = num_units_[tier].fetch_sub(1);
     253             :     DCHECK_LE(1, old_units_count);
     254             :     USE(old_units_count);
     255             :   }
     256             : 
     257             :   // Steal units of {wanted_tier} from {steal_from_task_id} to {task_id}. Return
     258             :   // first stolen unit (rest put in queue of {task_id}), or {nullptr} if
     259             :   // {steal_from_task_id} had no units of {wanted_tier}.
     260      185461 :   std::unique_ptr<WasmCompilationUnit> StealUnitsAndGetFirst(
     261             :       int task_id, int steal_from_task_id, int wanted_tier) {
     262             :     DCHECK_NE(task_id, steal_from_task_id);
     263      185555 :     std::vector<std::unique_ptr<WasmCompilationUnit>> stolen;
     264             :     {
     265      185461 :       Queue* steal_queue = &queues_[steal_from_task_id];
     266      185461 :       base::MutexGuard guard(&steal_queue->mutex_);
     267      185564 :       if (steal_queue->units_[wanted_tier].empty()) return {};
     268             :       auto* steal_from_vector = &steal_queue->units_[wanted_tier];
     269       18344 :       size_t remaining = steal_from_vector->size() / 2;
     270             :       stolen.assign(
     271             :           std::make_move_iterator(steal_from_vector->begin()) + remaining,
     272             :           std::make_move_iterator(steal_from_vector->end()));
     273       18343 :       steal_from_vector->resize(remaining);
     274             :     }
     275             :     DCHECK(!stolen.empty());
     276       18343 :     auto returned_unit = std::move(stolen.back());
     277             :     stolen.pop_back();
     278       18344 :     Queue* queue = &queues_[task_id];
     279       18344 :     base::MutexGuard guard(&queue->mutex_);
     280       18343 :     auto* target_queue = &queue->units_[wanted_tier];
     281             :     target_queue->insert(target_queue->end(),
     282             :                          std::make_move_iterator(stolen.begin()),
     283       18343 :                          std::make_move_iterator(stolen.end()));
     284       18338 :     queue->next_steal_task_id_ = next_task_id(steal_from_task_id);
     285             :     return returned_unit;
     286             :   }
     287             : };
     288             : 
     289             : // The {CompilationStateImpl} keeps track of the compilation state of the
     290             : // owning NativeModule, i.e. which functions are left to be compiled.
     291             : // It contains a task manager to allow parallel and asynchronous background
     292             : // compilation of functions.
     293             : // Its public interface {CompilationState} lives in compilation-environment.h.
     294     4971924 : class CompilationStateImpl {
     295             :  public:
     296             :   CompilationStateImpl(const std::shared_ptr<NativeModule>& native_module,
     297             :                        std::shared_ptr<Counters> async_counters);
     298             : 
     299             :   // Cancel all background compilation and wait for all tasks to finish. Call
     300             :   // this before destructing this object.
     301             :   void AbortCompilation();
     302             : 
     303             :   // Set the number of compilations unit expected to be executed. Needs to be
     304             :   // set before {AddCompilationUnits} is run, which triggers background
     305             :   // compilation.
     306             :   void SetNumberOfFunctionsToCompile(int num_functions, int num_lazy_functions);
     307             : 
     308             :   // Add the callback function to be called on compilation events. Needs to be
     309             :   // set before {AddCompilationUnits} is run to ensure that it receives all
     310             :   // events. The callback object must support being deleted from any thread.
     311             :   void AddCallback(CompilationState::callback_t);
     312             : 
     313             :   // Inserts new functions to compile and kicks off compilation.
     314             :   void AddCompilationUnits(
     315             :       Vector<std::unique_ptr<WasmCompilationUnit>> baseline_units,
     316             :       Vector<std::unique_ptr<WasmCompilationUnit>> top_tier_units);
     317             :   void AddTopTierCompilationUnit(std::unique_ptr<WasmCompilationUnit>);
     318             :   std::unique_ptr<WasmCompilationUnit> GetNextCompilationUnit(
     319             :       int task_id, CompileBaselineOnly baseline_only);
     320             : 
     321             :   void OnFinishedUnit(WasmCode*);
     322             :   void OnFinishedUnits(Vector<WasmCode*>);
     323             : 
     324             :   void OnBackgroundTaskStopped(int task_id, const WasmFeatures& detected);
     325             :   void UpdateDetectedFeatures(const WasmFeatures& detected);
     326             :   void PublishDetectedFeatures(Isolate*);
     327             :   void RestartBackgroundTasks();
     328             : 
     329             :   void SetError();
     330             : 
     331             :   bool failed() const {
     332             :     return compile_failed_.load(std::memory_order_relaxed);
     333             :   }
     334             : 
     335             :   bool baseline_compilation_finished() const {
     336      353743 :     base::MutexGuard guard(&callbacks_mutex_);
     337             :     DCHECK_LE(outstanding_baseline_functions_, outstanding_top_tier_functions_);
     338      353730 :     return outstanding_baseline_functions_ == 0;
     339             :   }
     340             : 
     341             :   CompileMode compile_mode() const { return compile_mode_; }
     342             :   Counters* counters() const { return async_counters_.get(); }
     343        8126 :   WasmFeatures* detected_features() { return &detected_features_; }
     344             : 
     345     2340784 :   void SetWireBytesStorage(
     346             :       std::shared_ptr<WireBytesStorage> wire_bytes_storage) {
     347     2340784 :     base::MutexGuard guard(&mutex_);
     348             :     wire_bytes_storage_ = wire_bytes_storage;
     349     2340784 :   }
     350             : 
     351             :   std::shared_ptr<WireBytesStorage> GetWireBytesStorage() const {
     352     1210755 :     base::MutexGuard guard(&mutex_);
     353             :     DCHECK_NOT_NULL(wire_bytes_storage_);
     354             :     return wire_bytes_storage_;
     355             :   }
     356             : 
     357             :   const std::shared_ptr<BackgroundCompileToken>& background_compile_token()
     358             :       const {
     359      258883 :     return background_compile_token_;
     360             :   }
     361             : 
     362             :  private:
     363             :   NativeModule* const native_module_;
     364             :   const std::shared_ptr<BackgroundCompileToken> background_compile_token_;
     365             :   const CompileMode compile_mode_;
     366             :   const std::shared_ptr<Counters> async_counters_;
     367             : 
     368             :   // Compilation error, atomically updated. This flag can be updated and read
     369             :   // using relaxed semantics.
     370             :   std::atomic<bool> compile_failed_{false};
     371             : 
     372             :   const int max_background_tasks_ = 0;
     373             : 
     374             :   CompilationUnitQueues compilation_unit_queues_;
     375             : 
     376             :   // This mutex protects all information of this {CompilationStateImpl} which is
     377             :   // being accessed concurrently.
     378             :   mutable base::Mutex mutex_;
     379             : 
     380             :   //////////////////////////////////////////////////////////////////////////////
     381             :   // Protected by {mutex_}:
     382             : 
     383             :   // Set of unused task ids; <= {max_background_tasks_} many.
     384             :   std::vector<int> available_task_ids_;
     385             : 
     386             :   // Features detected to be used in this module. Features can be detected
     387             :   // as a module is being compiled.
     388             :   WasmFeatures detected_features_ = kNoWasmFeatures;
     389             : 
     390             :   // Abstraction over the storage of the wire bytes. Held in a shared_ptr so
     391             :   // that background compilation jobs can keep the storage alive while
     392             :   // compiling.
     393             :   std::shared_ptr<WireBytesStorage> wire_bytes_storage_;
     394             : 
     395             :   // End of fields protected by {mutex_}.
     396             :   //////////////////////////////////////////////////////////////////////////////
     397             : 
     398             :   // This mutex protects the callbacks vector, and the counters used to
     399             :   // determine which callbacks to call. The counters plus the callbacks
     400             :   // themselves need to be synchronized to ensure correct order of events.
     401             :   mutable base::Mutex callbacks_mutex_;
     402             : 
     403             :   //////////////////////////////////////////////////////////////////////////////
     404             :   // Protected by {callbacks_mutex_}:
     405             : 
     406             :   // Callback functions to be called on compilation events.
     407             :   std::vector<CompilationState::callback_t> callbacks_;
     408             : 
     409             :   int outstanding_baseline_functions_ = 0;
     410             :   int outstanding_top_tier_functions_ = 0;
     411             :   std::vector<ExecutionTier> highest_execution_tier_;
     412             : 
     413             :   // End of fields protected by {callbacks_mutex_}.
     414             :   //////////////////////////////////////////////////////////////////////////////
     415             : };
     416             : 
     417             : CompilationStateImpl* Impl(CompilationState* compilation_state) {
     418             :   return reinterpret_cast<CompilationStateImpl*>(compilation_state);
     419             : }
     420             : const CompilationStateImpl* Impl(const CompilationState* compilation_state) {
     421             :   return reinterpret_cast<const CompilationStateImpl*>(compilation_state);
     422             : }
     423             : 
     424             : CompilationStateImpl* BackgroundCompileScope::compilation_state() {
     425             :   return Impl(native_module()->compilation_state());
     426             : }
     427             : 
     428             : void UpdateFeatureUseCounts(Isolate* isolate, const WasmFeatures& detected) {
     429      145004 :   if (detected.threads) {
     430        1436 :     isolate->CountUsage(v8::Isolate::UseCounterFeature::kWasmThreadOpcodes);
     431             :   }
     432             : }
     433             : 
     434             : }  // namespace
     435             : 
     436             : //////////////////////////////////////////////////////
     437             : // PIMPL implementation of {CompilationState}.
     438             : 
     439     1242981 : CompilationState::~CompilationState() { Impl(this)->~CompilationStateImpl(); }
     440             : 
     441     1242981 : void CompilationState::AbortCompilation() { Impl(this)->AbortCompilation(); }
     442             : 
     443           0 : void CompilationState::SetError() { Impl(this)->SetError(); }
     444             : 
     445     2340528 : void CompilationState::SetWireBytesStorage(
     446             :     std::shared_ptr<WireBytesStorage> wire_bytes_storage) {
     447     4681056 :   Impl(this)->SetWireBytesStorage(std::move(wire_bytes_storage));
     448     2340528 : }
     449             : 
     450      731780 : std::shared_ptr<WireBytesStorage> CompilationState::GetWireBytesStorage()
     451             :     const {
     452      731780 :   return Impl(this)->GetWireBytesStorage();
     453             : }
     454             : 
     455        2201 : void CompilationState::AddCallback(CompilationState::callback_t callback) {
     456        4402 :   return Impl(this)->AddCallback(std::move(callback));
     457             : }
     458             : 
     459          32 : bool CompilationState::failed() const { return Impl(this)->failed(); }
     460             : 
     461           0 : void CompilationState::OnFinishedUnit(WasmCode* code) {
     462             :   Impl(this)->OnFinishedUnit(code);
     463           0 : }
     464             : 
     465           0 : void CompilationState::OnFinishedUnits(Vector<WasmCode*> code_vector) {
     466           0 :   Impl(this)->OnFinishedUnits(code_vector);
     467           0 : }
     468             : 
     469             : // static
     470     1242981 : std::unique_ptr<CompilationState> CompilationState::New(
     471             :     const std::shared_ptr<NativeModule>& native_module,
     472             :     std::shared_ptr<Counters> async_counters) {
     473             :   return std::unique_ptr<CompilationState>(reinterpret_cast<CompilationState*>(
     474     2485962 :       new CompilationStateImpl(native_module, std::move(async_counters))));
     475             : }
     476             : 
     477             : // End of PIMPL implementation of {CompilationState}.
     478             : //////////////////////////////////////////////////////
     479             : 
     480             : namespace {
     481             : 
     482         198 : ExecutionTier ApplyHintToExecutionTier(WasmCompilationHintTier hint,
     483             :                                        ExecutionTier default_tier) {
     484         198 :   switch (hint) {
     485             :     case WasmCompilationHintTier::kDefault:
     486         144 :       return default_tier;
     487             :     case WasmCompilationHintTier::kInterpreter:
     488             :       return ExecutionTier::kInterpreter;
     489             :     case WasmCompilationHintTier::kBaseline:
     490           9 :       return ExecutionTier::kLiftoff;
     491             :     case WasmCompilationHintTier::kOptimized:
     492          33 :       return ExecutionTier::kTurbofan;
     493             :   }
     494           0 :   UNREACHABLE();
     495             : }
     496             : 
     497             : const WasmCompilationHint* GetCompilationHint(const WasmModule* module,
     498             :                                               uint32_t func_index) {
     499             :   DCHECK_LE(module->num_imported_functions, func_index);
     500        1268 :   uint32_t hint_index = func_index - module->num_imported_functions;
     501             :   const std::vector<WasmCompilationHint>& compilation_hints =
     502             :       module->compilation_hints;
     503        2536 :   if (hint_index < compilation_hints.size()) {
     504             :     return &compilation_hints[hint_index];
     505             :   }
     506             :   return nullptr;
     507             : }
     508             : 
     509             : bool IsLazyCompilation(const WasmModule* module,
     510             :                        const WasmFeatures& enabled_features,
     511             :                        uint32_t func_index) {
     512      559482 :   if (enabled_features.compilation_hints) {
     513             :     const WasmCompilationHint* hint = GetCompilationHint(module, func_index);
     514        1143 :     return hint != nullptr &&
     515         343 :            hint->strategy == WasmCompilationHintStrategy::kLazy;
     516             :   }
     517             :   return false;
     518             : }
     519             : 
     520             : bool IsLazyCompilation(const WasmModule* module,
     521             :                        const NativeModule* native_module,
     522             :                        const WasmFeatures& enabled_features,
     523             :                        uint32_t func_index) {
     524      559506 :   if (native_module->lazy_compilation()) return true;
     525             :   return IsLazyCompilation(module, enabled_features, func_index);
     526             : }
     527             : 
     528             : struct ExecutionTierPair {
     529             :   ExecutionTier baseline_tier;
     530             :   ExecutionTier top_tier;
     531             : };
     532             : 
     533      567450 : ExecutionTierPair GetRequestedExecutionTiers(
     534             :     const WasmModule* module, CompileMode compile_mode,
     535             :     const WasmFeatures& enabled_features, uint32_t func_index) {
     536             :   ExecutionTierPair result;
     537      567450 :   switch (compile_mode) {
     538             :     case CompileMode::kRegular:
     539             :       result.baseline_tier =
     540      275084 :           WasmCompilationUnit::GetDefaultExecutionTier(module);
     541             :       result.top_tier = result.baseline_tier;
     542      275085 :       return result;
     543             :     case CompileMode::kTiering:
     544             : 
     545             :       // Default tiering behaviour.
     546             :       result.baseline_tier = ExecutionTier::kLiftoff;
     547             :       result.top_tier = ExecutionTier::kTurbofan;
     548             : 
     549             :       // Check if compilation hints override default tiering behaviour.
     550      292366 :       if (enabled_features.compilation_hints) {
     551             :         const WasmCompilationHint* hint =
     552             :             GetCompilationHint(module, func_index);
     553         468 :         if (hint != nullptr) {
     554          99 :           result.baseline_tier = ApplyHintToExecutionTier(hint->baseline_tier,
     555             :                                                           result.baseline_tier);
     556             :           result.top_tier =
     557          99 :               ApplyHintToExecutionTier(hint->top_tier, result.top_tier);
     558             :         }
     559             :       }
     560             : 
     561             :       // Correct top tier if necessary.
     562             :       static_assert(ExecutionTier::kInterpreter < ExecutionTier::kLiftoff &&
     563             :                         ExecutionTier::kLiftoff < ExecutionTier::kTurbofan,
     564             :                     "Assume an order on execution tiers");
     565      292365 :       if (result.baseline_tier > result.top_tier) {
     566             :         result.top_tier = result.baseline_tier;
     567             :       }
     568      292365 :       return result;
     569             :   }
     570           0 :   UNREACHABLE();
     571             : }
     572             : 
     573             : // The {CompilationUnitBuilder} builds compilation units and stores them in an
     574             : // internal buffer. The buffer is moved into the working queue of the
     575             : // {CompilationStateImpl} when {Commit} is called.
     576      145145 : class CompilationUnitBuilder {
     577             :  public:
     578             :   explicit CompilationUnitBuilder(NativeModule* native_module)
     579             :       : native_module_(native_module),
     580      145145 :         default_tier_(WasmCompilationUnit::GetDefaultExecutionTier(
     581      290290 :             native_module->module())) {}
     582             : 
     583      235704 :   void AddUnits(uint32_t func_index) {
     584             :     ExecutionTierPair tiers = GetRequestedExecutionTiers(
     585             :         native_module_->module(), compilation_state()->compile_mode(),
     586      471408 :         native_module_->enabled_features(), func_index);
     587      235704 :     baseline_units_.emplace_back(CreateUnit(func_index, tiers.baseline_tier));
     588      235701 :     if (tiers.baseline_tier != tiers.top_tier) {
     589       99650 :       tiering_units_.emplace_back(CreateUnit(func_index, tiers.top_tier));
     590             :     }
     591      235702 :   }
     592             : 
     593      145211 :   bool Commit() {
     594      145211 :     if (baseline_units_.empty() && tiering_units_.empty()) return false;
     595             :     compilation_state()->AddCompilationUnits(VectorOf(baseline_units_),
     596             :                                              VectorOf(tiering_units_));
     597      138853 :     Clear();
     598      138853 :     return true;
     599             :   }
     600             : 
     601      138913 :   void Clear() {
     602             :     baseline_units_.clear();
     603             :     tiering_units_.clear();
     604      138913 :   }
     605             : 
     606             :  private:
     607             :   std::unique_ptr<WasmCompilationUnit> CreateUnit(uint32_t func_index,
     608             :                                                   ExecutionTier tier) {
     609      335353 :     return base::make_unique<WasmCompilationUnit>(func_index, tier);
     610             :   }
     611             : 
     612             :   CompilationStateImpl* compilation_state() const {
     613             :     return Impl(native_module_->compilation_state());
     614             :   }
     615             : 
     616             :   NativeModule* const native_module_;
     617             :   const ExecutionTier default_tier_;
     618             :   std::vector<std::unique_ptr<WasmCompilationUnit>> baseline_units_;
     619             :   std::vector<std::unique_ptr<WasmCompilationUnit>> tiering_units_;
     620             : };
     621             : 
     622             : }  // namespace
     623             : 
     624        8126 : void CompileLazy(Isolate* isolate, NativeModule* native_module,
     625             :                  uint32_t func_index) {
     626             :   Counters* counters = isolate->counters();
     627             :   HistogramTimerScope lazy_time_scope(counters->wasm_lazy_compilation_time());
     628             : 
     629             :   DCHECK(!native_module->lazy_compile_frozen());
     630             : 
     631             :   base::ElapsedTimer compilation_timer;
     632             : 
     633       16252 :   NativeModuleModificationScope native_module_modification_scope(native_module);
     634             : 
     635             :   DCHECK(!native_module->HasCode(static_cast<uint32_t>(func_index)));
     636             : 
     637             :   compilation_timer.Start();
     638             : 
     639             :   TRACE_LAZY("Compiling wasm-function#%d.\n", func_index);
     640             : 
     641             :   const uint8_t* module_start = native_module->wire_bytes().start();
     642             : 
     643        8126 :   const WasmFunction* func = &native_module->module()->functions[func_index];
     644             :   FunctionBody func_body{func->sig, func->code.offset(),
     645             :                          module_start + func->code.offset(),
     646             :                          module_start + func->code.end_offset()};
     647             : 
     648             :   CompilationStateImpl* compilation_state =
     649             :       Impl(native_module->compilation_state());
     650             :   ExecutionTierPair tiers = GetRequestedExecutionTiers(
     651             :       native_module->module(), compilation_state->compile_mode(),
     652        8126 :       native_module->enabled_features(), func_index);
     653             : 
     654       16252 :   WasmCompilationUnit baseline_unit(func_index, tiers.baseline_tier);
     655        8126 :   CompilationEnv env = native_module->CreateCompilationEnv();
     656             :   WasmCompilationResult result = baseline_unit.ExecuteCompilation(
     657        8126 :       isolate->wasm_engine(), &env, compilation_state->GetWireBytesStorage(),
     658       16252 :       isolate->counters(), compilation_state->detected_features());
     659       16252 :   WasmCodeRefScope code_ref_scope;
     660        8126 :   WasmCode* code = native_module->AddCompiledCode(std::move(result));
     661             : 
     662        8126 :   if (tiers.baseline_tier < tiers.top_tier) {
     663             :     auto tiering_unit =
     664         132 :         base::make_unique<WasmCompilationUnit>(func_index, tiers.top_tier);
     665          66 :     compilation_state->AddTopTierCompilationUnit(std::move(tiering_unit));
     666             :   }
     667             : 
     668             :   // During lazy compilation, we should never get compilation errors. The module
     669             :   // was verified before starting execution with lazy compilation.
     670             :   // This might be OOM, but then we cannot continue execution anyway.
     671             :   // TODO(clemensh): According to the spec, we can actually skip validation at
     672             :   // module creation time, and return a function that always traps here.
     673        8126 :   CHECK(!compilation_state->failed());
     674             : 
     675             :   // The code we just produced should be the one that was requested.
     676             :   DCHECK_EQ(func_index, code->index());
     677             : 
     678        8126 :   if (WasmCode::ShouldBeLogged(isolate)) code->LogCode(isolate);
     679             : 
     680        8126 :   double func_kb = 1e-3 * func->code.length();
     681        8126 :   double compilation_seconds = compilation_timer.Elapsed().InSecondsF();
     682             : 
     683        8126 :   counters->wasm_lazily_compiled_functions()->Increment();
     684             : 
     685        8126 :   int throughput_sample = static_cast<int>(func_kb / compilation_seconds);
     686        8126 :   counters->wasm_lazy_compilation_throughput()->AddSample(throughput_sample);
     687        8126 : }
     688             : 
     689             : namespace {
     690             : 
     691      221122 : void RecordStats(const Code code, Counters* counters) {
     692      442245 :   counters->wasm_generated_code_size()->Increment(code->body_size());
     693      221124 :   counters->wasm_reloc_size()->Increment(code->relocation_info()->length());
     694      221123 : }
     695             : 
     696             : constexpr int kMainThreadTaskId = -1;
     697             : 
     698             : // Run by the main thread and background tasks to take part in compilation.
     699             : // Returns whether any units were executed.
     700      482815 : bool ExecuteCompilationUnits(
     701             :     const std::shared_ptr<BackgroundCompileToken>& token, Counters* counters,
     702             :     int task_id, CompileBaselineOnly baseline_only) {
     703             :   TRACE_COMPILE("Compiling (task %d)...\n", task_id);
     704     1448583 :   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"), "ExecuteCompilationUnits");
     705             : 
     706      482819 :   const bool is_foreground = task_id == kMainThreadTaskId;
     707             :   // The main thread uses task id 0, which might collide with one of the
     708             :   // background tasks. This is fine, as it will only cause some contention on
     709             :   // the one queue, but work otherwise.
     710      482819 :   if (is_foreground) task_id = 0;
     711             : 
     712      482819 :   Platform* platform = V8::GetCurrentPlatform();
     713             :   // Deadline is in 50ms from now.
     714             :   static constexpr double kBackgroundCompileTimeLimit =
     715             :       50.0 / base::Time::kMillisecondsPerSecond;
     716             :   const double deadline =
     717      482729 :       platform->MonotonicallyIncreasingTime() + kBackgroundCompileTimeLimit;
     718             : 
     719             :   // These fields are initialized in a {BackgroundCompileScope} before
     720             :   // starting compilation.
     721      482849 :   base::Optional<CompilationEnv> env;
     722      482849 :   std::shared_ptr<WireBytesStorage> wire_bytes;
     723             :   std::shared_ptr<const WasmModule> module;
     724             :   WasmEngine* wasm_engine = nullptr;
     725      965835 :   std::unique_ptr<WasmCompilationUnit> unit;
     726      482849 :   WasmFeatures detected_features = kNoWasmFeatures;
     727             : 
     728             :   auto stop = [is_foreground, task_id,
     729      938922 :                &detected_features](BackgroundCompileScope& compile_scope) {
     730      469461 :     if (is_foreground) {
     731             :       compile_scope.compilation_state()->UpdateDetectedFeatures(
     732      250841 :           detected_features);
     733             :     } else {
     734             :       compile_scope.compilation_state()->OnBackgroundTaskStopped(
     735      218620 :           task_id, detected_features);
     736             :     }
     737      469491 :   };
     738             : 
     739             :   // Preparation (synchronized): Initialize the fields above and get the first
     740             :   // compilation unit.
     741             :   {
     742      671942 :     BackgroundCompileScope compile_scope(token);
     743      776838 :     if (compile_scope.cancelled()) return false;
     744      941842 :     env.emplace(compile_scope.native_module()->CreateCompilationEnv());
     745      471041 :     wire_bytes = compile_scope.compilation_state()->GetWireBytesStorage();
     746      471039 :     module = compile_scope.native_module()->shared_module();
     747             :     wasm_engine = compile_scope.native_module()->engine();
     748      470859 :     unit = compile_scope.compilation_state()->GetNextCompilationUnit(
     749             :         task_id, baseline_only);
     750      471021 :     if (unit == nullptr) {
     751      281928 :       stop(compile_scope);
     752      281939 :       return false;
     753             :     }
     754             :   }
     755             : 
     756      189079 :   std::vector<WasmCompilationResult> results_to_publish;
     757             : 
     758             :   auto publish_results = [&results_to_publish](
     759      942396 :                              BackgroundCompileScope* compile_scope) {
     760      541558 :     if (results_to_publish.empty()) return;
     761      537444 :     WasmCodeRefScope code_ref_scope;
     762             :     std::vector<WasmCode*> code_vector =
     763             :         compile_scope->native_module()->AddCompiledCode(
     764      268471 :             VectorOf(results_to_publish));
     765      268833 :     compile_scope->compilation_state()->OnFinishedUnits(VectorOf(code_vector));
     766             :     results_to_publish.clear();
     767      189067 :   };
     768             : 
     769             :   bool compilation_failed = false;
     770             :   while (true) {
     771             :     // (asynchronous): Execute the compilation.
     772             :     WasmCompilationResult result = unit->ExecuteCompilation(
     773      477178 :         wasm_engine, &env.value(), wire_bytes, counters, &detected_features);
     774      329793 :     results_to_publish.emplace_back(std::move(result));
     775             : 
     776             :     // (synchronized): Publish the compilation result and get the next unit.
     777             :     {
     778      473749 :       BackgroundCompileScope compile_scope(token);
     779      514353 :       if (compile_scope.cancelled()) return true;
     780      331710 :       if (!results_to_publish.back().succeeded()) {
     781             :         // Compile error.
     782        7880 :         compile_scope.compilation_state()->SetError();
     783        7876 :         stop(compile_scope);
     784             :         compilation_failed = true;
     785        7880 :         break;
     786             :       }
     787             :       // Publish TurboFan units immediately to reduce peak memory consumption.
     788      323830 :       if (result.requested_tier == ExecutionTier::kTurbofan) {
     789      225540 :         publish_results(&compile_scope);
     790             :       }
     791             : 
     792             :       // Get next unit.
     793      323941 :       if (deadline < platform->MonotonicallyIncreasingTime()) {
     794             :         unit = nullptr;
     795             :       } else {
     796      323639 :         unit = compile_scope.compilation_state()->GetNextCompilationUnit(
     797             :             task_id, baseline_only);
     798             :       }
     799             : 
     800      323725 :       if (unit == nullptr) {
     801      179671 :         publish_results(&compile_scope);
     802      179676 :         stop(compile_scope);
     803      179649 :         return true;
     804             :       }
     805             :     }
     806             :   }
     807             :   // We only get here if compilation failed. Other exits return directly.
     808             :   DCHECK(compilation_failed);
     809             :   USE(compilation_failed);
     810        7882 :   token->Cancel();
     811        7880 :   return true;
     812             : }
     813             : 
     814        8925 : DecodeResult ValidateSingleFunction(const WasmModule* module, int func_index,
     815             :                                     Vector<const uint8_t> code,
     816             :                                     Counters* counters,
     817             :                                     AccountingAllocator* allocator,
     818             :                                     WasmFeatures enabled_features) {
     819        8925 :   const WasmFunction* func = &module->functions[func_index];
     820        8925 :   FunctionBody body{func->sig, func->code.offset(), code.start(), code.end()};
     821             :   DecodeResult result;
     822             :   {
     823        8925 :     auto time_counter = SELECT_WASM_COUNTER(counters, module->origin,
     824             :                                             wasm_decode, function_time);
     825             :     TimedHistogramScope wasm_decode_function_time_scope(time_counter);
     826        8925 :     WasmFeatures detected;
     827             :     result =
     828       17850 :         VerifyWasmCode(allocator, enabled_features, module, &detected, body);
     829             :   }
     830        8925 :   return result;
     831             : }
     832             : 
     833             : enum class OnlyLazyFunctions : bool { kNo = false, kYes = true };
     834             : 
     835        7821 : void ValidateSequentially(
     836             :     const WasmModule* module, NativeModule* native_module, Counters* counters,
     837             :     AccountingAllocator* allocator, ErrorThrower* thrower,
     838             :     OnlyLazyFunctions only_lazy_functions = OnlyLazyFunctions ::kNo) {
     839             :   DCHECK(!thrower->error());
     840        7821 :   uint32_t start = module->num_imported_functions;
     841        7821 :   uint32_t end = start + module->num_declared_functions;
     842        7821 :   auto enabled_features = native_module->enabled_features();
     843       25735 :   for (uint32_t func_index = start; func_index < end; func_index++) {
     844             :     // Skip non-lazy functions if requested.
     845        9045 :     if (only_lazy_functions == OnlyLazyFunctions::kYes &&
     846             :         !IsLazyCompilation(module, native_module, enabled_features,
     847             :                            func_index)) {
     848          72 :       continue;
     849             :     }
     850             :     ModuleWireBytes wire_bytes{native_module->wire_bytes()};
     851        8885 :     const WasmFunction* func = &module->functions[func_index];
     852        8885 :     Vector<const uint8_t> code = wire_bytes.GetFunctionBytes(func);
     853       17770 :     DecodeResult result = ValidateSingleFunction(
     854             :         module, func_index, code, counters, allocator, enabled_features);
     855             : 
     856        8885 :     if (result.failed()) {
     857        7741 :       WasmName name = wire_bytes.GetNameOrNull(func, module);
     858        7741 :       if (name.start() == nullptr) {
     859             :         thrower->CompileError(
     860        7397 :             "Compiling function #%d failed: %s @+%u", func->func_index,
     861        7397 :             result.error().message().c_str(), result.error().offset());
     862             :       } else {
     863         344 :         TruncatedUserString<> name(wire_bytes.GetNameOrNull(func, module));
     864             :         thrower->CompileError("Compiling function #%d:\"%.*s\" failed: %s @+%u",
     865         344 :                               func->func_index, name.length(), name.start(),
     866             :                               result.error().message().c_str(),
     867         344 :                               result.error().offset());
     868             :       }
     869             :     }
     870             :   }
     871        7821 : }
     872             : 
     873      144887 : void InitializeCompilationUnits(NativeModule* native_module) {
     874             :   // Set number of functions that must be compiled to consider the module fully
     875             :   // compiled.
     876             :   auto wasm_module = native_module->module();
     877      144887 :   int num_functions = wasm_module->num_declared_functions;
     878             :   DCHECK_IMPLIES(!native_module->enabled_features().compilation_hints,
     879             :                  wasm_module->num_lazy_compilation_hints == 0);
     880      144887 :   int num_lazy_functions = wasm_module->num_lazy_compilation_hints;
     881             :   CompilationStateImpl* compilation_state =
     882             :       Impl(native_module->compilation_state());
     883             :   compilation_state->SetNumberOfFunctionsToCompile(num_functions,
     884      144887 :                                                    num_lazy_functions);
     885             : 
     886             :   ModuleWireBytes wire_bytes(native_module->wire_bytes());
     887             :   const WasmModule* module = native_module->module();
     888             :   CompilationUnitBuilder builder(native_module);
     889      144889 :   uint32_t start = module->num_imported_functions;
     890      144889 :   uint32_t end = start + module->num_declared_functions;
     891      615359 :   for (uint32_t func_index = start; func_index < end; func_index++) {
     892      235236 :     if (IsLazyCompilation(module, native_module,
     893             :                           native_module->enabled_features(), func_index)) {
     894          16 :       native_module->UseLazyStub(func_index);
     895             :     } else {
     896      235220 :       builder.AddUnits(func_index);
     897             :     }
     898             :   }
     899      144888 :   builder.Commit();
     900      144889 : }
     901             : 
     902             : bool NeedsDeterministicCompile() {
     903     1385718 :   return FLAG_trace_wasm_decoder || FLAG_wasm_num_compilation_tasks <= 1;
     904             : }
     905             : 
     906      145385 : void CompileNativeModule(Isolate* isolate, ErrorThrower* thrower,
     907             :                          const WasmModule* wasm_module,
     908             :                          NativeModule* native_module) {
     909             :   ModuleWireBytes wire_bytes(native_module->wire_bytes());
     910             : 
     911      145385 :   if (FLAG_wasm_lazy_compilation ||
     912      144082 :       (FLAG_asm_wasm_lazy_compilation && wasm_module->origin == kAsmJsOrigin)) {
     913        2641 :     if (wasm_module->origin == kWasmOrigin) {
     914             :       // Validate wasm modules for lazy compilation. Don't validate asm.js
     915             :       // modules, they are valid by construction (otherwise a CHECK will fail
     916             :       // during lazy compilation).
     917             :       // TODO(clemensh): According to the spec, we can actually skip validation
     918             :       // at module creation time, and return a function that always traps at
     919             :       // (lazy) compilation time.
     920             :       ValidateSequentially(wasm_module, native_module, isolate->counters(),
     921         176 :                            isolate->allocator(), thrower);
     922             :       // On error: Return and leave the module in an unexecutable state.
     923        2825 :       if (thrower->error()) return;
     924             :     }
     925             :     native_module->set_lazy_compilation(true);
     926        2633 :     native_module->UseLazyStubs();
     927        2633 :     return;
     928             :   }
     929             : 
     930      142744 :   if (native_module->enabled_features().compilation_hints) {
     931             :     ValidateSequentially(wasm_module, native_module, isolate->counters(),
     932             :                          isolate->allocator(), thrower,
     933          64 :                          OnlyLazyFunctions::kYes);
     934             :     // On error: Return and leave the module in an unexecutable state.
     935          64 :     if (thrower->error()) return;
     936             :   }
     937             : 
     938             :   // Turn on the {CanonicalHandleScope} so that the background threads can
     939             :   // use the node cache.
     940      285473 :   CanonicalHandleScope canonical(isolate);
     941             : 
     942             :   auto* compilation_state = Impl(native_module->compilation_state());
     943             :   DCHECK_GE(kMaxInt, native_module->module()->num_declared_functions);
     944             : 
     945             :   // Install a callback to notify us once background compilation finished, or
     946             :   // compilation failed.
     947      285474 :   auto baseline_finished_semaphore = std::make_shared<base::Semaphore>(0);
     948             :   // The callback captures a shared ptr to the semaphore.
     949      285472 :   compilation_state->AddCallback(
     950      285472 :       [baseline_finished_semaphore](CompilationEvent event) {
     951      555638 :         if (event == CompilationEvent::kFinishedBaselineCompilation ||
     952      277819 :             event == CompilationEvent::kFailedCompilation) {
     953      142737 :           baseline_finished_semaphore->Signal();
     954             :         }
     955      142737 :       });
     956             : 
     957             :   // Initialize the compilation units and kick off background compile tasks.
     958      142736 :   InitializeCompilationUnits(native_module);
     959             : 
     960             :   // If tiering is disabled, the main thread can execute any unit (all of them
     961             :   // are part of initial compilation). Otherwise, just execute baseline units.
     962             :   bool is_tiering = compilation_state->compile_mode() == CompileMode::kTiering;
     963      142737 :   auto baseline_only = is_tiering ? kBaselineOnly : kBaselineOrTopTier;
     964             :   // The main threads contributes to the compilation, except if we need
     965             :   // deterministic compilation; in that case, the single background task will
     966             :   // execute all compilation.
     967      142737 :   if (!NeedsDeterministicCompile()) {
     968      517766 :     while (ExecuteCompilationUnits(
     969             :         compilation_state->background_compile_token(), isolate->counters(),
     970             :         kMainThreadTaskId, baseline_only)) {
     971             :       // Continue executing compilation units.
     972             :     }
     973             :   }
     974             : 
     975             :   // Now wait until baseline compilation finished.
     976      142737 :   baseline_finished_semaphore->Wait();
     977             : 
     978      142737 :   compilation_state->PublishDetectedFeatures(isolate);
     979             : 
     980      142737 :   if (compilation_state->failed()) {
     981             :     ValidateSequentially(wasm_module, native_module, isolate->counters(),
     982        7505 :                          isolate->allocator(), thrower);
     983        7505 :     CHECK(thrower->error());
     984             :   }
     985             : }
     986             : 
     987             : // The runnable task that performs compilations in the background.
     988      672439 : class BackgroundCompileTask : public CancelableTask {
     989             :  public:
     990             :   explicit BackgroundCompileTask(CancelableTaskManager* manager,
     991             :                                  std::shared_ptr<BackgroundCompileToken> token,
     992             :                                  std::shared_ptr<Counters> async_counters,
     993             :                                  int task_id)
     994             :       : CancelableTask(manager),
     995             :         token_(std::move(token)),
     996             :         async_counters_(std::move(async_counters)),
     997      448452 :         task_id_(task_id) {}
     998             : 
     999      224092 :   void RunInternal() override {
    1000      224092 :     ExecuteCompilationUnits(token_, async_counters_.get(), task_id_,
    1001      224092 :                             kBaselineOrTopTier);
    1002      224094 :   }
    1003             : 
    1004             :  private:
    1005             :   const std::shared_ptr<BackgroundCompileToken> token_;
    1006             :   const std::shared_ptr<Counters> async_counters_;
    1007             :   const int task_id_;
    1008             : };
    1009             : 
    1010             : }  // namespace
    1011             : 
    1012      145341 : std::shared_ptr<NativeModule> CompileToNativeModule(
    1013             :     Isolate* isolate, const WasmFeatures& enabled, ErrorThrower* thrower,
    1014             :     std::shared_ptr<const WasmModule> module, const ModuleWireBytes& wire_bytes,
    1015             :     Handle<FixedArray>* export_wrappers_out) {
    1016             :   const WasmModule* wasm_module = module.get();
    1017      145341 :   TimedHistogramScope wasm_compile_module_time_scope(SELECT_WASM_COUNTER(
    1018      145341 :       isolate->counters(), wasm_module->origin, wasm_compile, module_time));
    1019             : 
    1020             :   // Embedder usage count for declared shared memories.
    1021      145344 :   if (wasm_module->has_shared_memory) {
    1022        1482 :     isolate->CountUsage(v8::Isolate::UseCounterFeature::kWasmSharedMemory);
    1023             :   }
    1024      145346 :   int export_wrapper_size = static_cast<int>(module->num_exported_functions);
    1025             : 
    1026             :   // TODO(wasm): only save the sections necessary to deserialize a
    1027             :   // {WasmModule}. E.g. function bodies could be omitted.
    1028             :   OwnedVector<uint8_t> wire_bytes_copy =
    1029      145346 :       OwnedVector<uint8_t>::Of(wire_bytes.module_bytes());
    1030             : 
    1031             :   // Create and compile the native module.
    1032             :   size_t code_size_estimate =
    1033      145347 :       wasm::WasmCodeManager::EstimateNativeModuleCodeSize(module.get());
    1034             : 
    1035             :   // Create a new {NativeModule} first.
    1036             :   auto native_module = isolate->wasm_engine()->NewNativeModule(
    1037             :       isolate, enabled, code_size_estimate,
    1038      290694 :       wasm::NativeModule::kCanAllocateMoreMemory, std::move(module));
    1039      290696 :   native_module->SetWireBytes(std::move(wire_bytes_copy));
    1040      145348 :   native_module->SetRuntimeStubs(isolate);
    1041             : 
    1042      145348 :   CompileNativeModule(isolate, thrower, wasm_module, native_module.get());
    1043      145347 :   if (thrower->error()) return {};
    1044             : 
    1045             :   // Compile JS->wasm wrappers for exported functions.
    1046             :   *export_wrappers_out = isolate->factory()->NewFixedArray(
    1047      137826 :       export_wrapper_size, AllocationType::kOld);
    1048             :   CompileJsToWasmWrappers(isolate, native_module->module(),
    1049      137827 :                           *export_wrappers_out);
    1050             : 
    1051             :   // Log the code within the generated module for profiling.
    1052      137827 :   native_module->LogWasmCodes(isolate);
    1053             : 
    1054             :   return native_module;
    1055             : }
    1056             : 
    1057          38 : void CompileNativeModuleWithExplicitBoundsChecks(Isolate* isolate,
    1058             :                                                  ErrorThrower* thrower,
    1059             :                                                  const WasmModule* wasm_module,
    1060             :                                                  NativeModule* native_module) {
    1061          38 :   native_module->DisableTrapHandler();
    1062          38 :   CompileNativeModule(isolate, thrower, wasm_module, native_module);
    1063          38 : }
    1064             : 
    1065        2647 : AsyncCompileJob::AsyncCompileJob(
    1066             :     Isolate* isolate, const WasmFeatures& enabled,
    1067             :     std::unique_ptr<byte[]> bytes_copy, size_t length, Handle<Context> context,
    1068             :     std::shared_ptr<CompilationResultResolver> resolver)
    1069             :     : isolate_(isolate),
    1070             :       enabled_features_(enabled),
    1071             :       bytes_copy_(std::move(bytes_copy)),
    1072             :       wire_bytes_(bytes_copy_.get(), bytes_copy_.get() + length),
    1073       10588 :       resolver_(std::move(resolver)) {
    1074             :   v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
    1075        2647 :   v8::Platform* platform = V8::GetCurrentPlatform();
    1076        5294 :   foreground_task_runner_ = platform->GetForegroundTaskRunner(v8_isolate);
    1077             :   native_context_ =
    1078        2647 :       isolate->global_handles()->Create(context->native_context());
    1079             :   DCHECK(native_context_->IsNativeContext());
    1080        2647 : }
    1081             : 
    1082        2195 : void AsyncCompileJob::Start() {
    1083        4390 :   DoAsync<DecodeModule>(isolate_->counters());  // --
    1084        2195 : }
    1085             : 
    1086          72 : void AsyncCompileJob::Abort() {
    1087             :   // Removing this job will trigger the destructor, which will cancel all
    1088             :   // compilation.
    1089          72 :   isolate_->wasm_engine()->RemoveCompileJob(this);
    1090          72 : }
    1091             : 
    1092        1808 : class AsyncStreamingProcessor final : public StreamingProcessor {
    1093             :  public:
    1094             :   explicit AsyncStreamingProcessor(AsyncCompileJob* job);
    1095             : 
    1096             :   bool ProcessModuleHeader(Vector<const uint8_t> bytes,
    1097             :                            uint32_t offset) override;
    1098             : 
    1099             :   bool ProcessSection(SectionCode section_code, Vector<const uint8_t> bytes,
    1100             :                       uint32_t offset) override;
    1101             : 
    1102             :   bool ProcessCodeSectionHeader(int functions_count, uint32_t offset,
    1103             :                                 std::shared_ptr<WireBytesStorage>) override;
    1104             : 
    1105             :   bool ProcessFunctionBody(Vector<const uint8_t> bytes,
    1106             :                            uint32_t offset) override;
    1107             : 
    1108             :   void OnFinishedChunk() override;
    1109             : 
    1110             :   void OnFinishedStream(OwnedVector<uint8_t> bytes) override;
    1111             : 
    1112             :   void OnError(const WasmError&) override;
    1113             : 
    1114             :   void OnAbort() override;
    1115             : 
    1116             :   bool Deserialize(Vector<const uint8_t> wire_bytes,
    1117             :                    Vector<const uint8_t> module_bytes) override;
    1118             : 
    1119             :  private:
    1120             :   // Finishes the AsyncCompileJob with an error.
    1121             :   void FinishAsyncCompileJobWithError(const WasmError&);
    1122             : 
    1123             :   void CommitCompilationUnits();
    1124             : 
    1125             :   ModuleDecoder decoder_;
    1126             :   AsyncCompileJob* job_;
    1127             :   std::unique_ptr<CompilationUnitBuilder> compilation_unit_builder_;
    1128             :   int num_functions_ = 0;
    1129             : };
    1130             : 
    1131         452 : std::shared_ptr<StreamingDecoder> AsyncCompileJob::CreateStreamingDecoder() {
    1132             :   DCHECK_NULL(stream_);
    1133        1356 :   stream_.reset(
    1134        1808 :       new StreamingDecoder(base::make_unique<AsyncStreamingProcessor>(this)));
    1135         452 :   return stream_;
    1136             : }
    1137             : 
    1138        7941 : AsyncCompileJob::~AsyncCompileJob() {
    1139             :   // Note: This destructor always runs on the foreground thread of the isolate.
    1140        2647 :   background_task_manager_.CancelAndWait();
    1141             :   // If the runtime objects were not created yet, then initial compilation did
    1142             :   // not finish yet. In this case we can abort compilation.
    1143        5087 :   if (native_module_ && module_object_.is_null()) {
    1144         173 :     Impl(native_module_->compilation_state())->AbortCompilation();
    1145             :   }
    1146             :   // Tell the streaming decoder that the AsyncCompileJob is not available
    1147             :   // anymore.
    1148             :   // TODO(ahaas): Is this notification really necessary? Check
    1149             :   // https://crbug.com/888170.
    1150        2647 :   if (stream_) stream_->NotifyCompilationEnded();
    1151             :   CancelPendingForegroundTask();
    1152        2647 :   isolate_->global_handles()->Destroy(native_context_.location());
    1153        2647 :   if (!module_object_.is_null()) {
    1154        2267 :     isolate_->global_handles()->Destroy(module_object_.location());
    1155             :   }
    1156        2647 : }
    1157             : 
    1158        2436 : void AsyncCompileJob::CreateNativeModule(
    1159             :     std::shared_ptr<const WasmModule> module) {
    1160             :   // Embedder usage count for declared shared memories.
    1161        2436 :   if (module->has_shared_memory) {
    1162           0 :     isolate_->CountUsage(v8::Isolate::UseCounterFeature::kWasmSharedMemory);
    1163             :   }
    1164             : 
    1165             :   // TODO(wasm): Improve efficiency of storing module wire bytes. Only store
    1166             :   // relevant sections, not function bodies
    1167             : 
    1168             :   // Create the module object and populate with compiled functions and
    1169             :   // information needed at instantiation time.
    1170             :   // TODO(clemensh): For the same module (same bytes / same hash), we should
    1171             :   // only have one {WasmModuleObject}. Otherwise, we might only set
    1172             :   // breakpoints on a (potentially empty) subset of the instances.
    1173             :   // Create the module object.
    1174             : 
    1175             :   size_t code_size_estimate =
    1176        2436 :       wasm::WasmCodeManager::EstimateNativeModuleCodeSize(module.get());
    1177        7308 :   native_module_ = isolate_->wasm_engine()->NewNativeModule(
    1178             :       isolate_, enabled_features_, code_size_estimate,
    1179             :       wasm::NativeModule::kCanAllocateMoreMemory, std::move(module));
    1180        4872 :   native_module_->SetWireBytes({std::move(bytes_copy_), wire_bytes_.length()});
    1181        2436 :   native_module_->SetRuntimeStubs(isolate_);
    1182             : 
    1183        2436 :   if (stream_) stream_->NotifyNativeModuleCreated(native_module_);
    1184        2436 : }
    1185             : 
    1186        2263 : void AsyncCompileJob::PrepareRuntimeObjects() {
    1187             :   // Create heap objects for script and module bytes to be stored in the
    1188             :   // module object. Asm.js is not compiled asynchronously.
    1189             :   const WasmModule* module = native_module_->module();
    1190             :   Handle<Script> script =
    1191        2263 :       CreateWasmScript(isolate_, wire_bytes_, module->source_map_url);
    1192             : 
    1193             :   size_t code_size_estimate =
    1194        2263 :       wasm::WasmCodeManager::EstimateNativeModuleCodeSize(module);
    1195             :   Handle<WasmModuleObject> module_object = WasmModuleObject::New(
    1196        4526 :       isolate_, native_module_, script, code_size_estimate);
    1197             : 
    1198        4526 :   module_object_ = isolate_->global_handles()->Create(*module_object);
    1199        2263 : }
    1200             : 
    1201             : // This function assumes that it is executed in a HandleScope, and that a
    1202             : // context is set on the isolate.
    1203        2267 : void AsyncCompileJob::FinishCompile() {
    1204             :   bool is_after_deserialization = !module_object_.is_null();
    1205        2267 :   if (!is_after_deserialization) {
    1206        2263 :     PrepareRuntimeObjects();
    1207             :   }
    1208             :   DCHECK(!isolate_->context().is_null());
    1209             :   // Finish the wasm script now and make it public to the debugger.
    1210        2267 :   Handle<Script> script(module_object_->script(), isolate_);
    1211        4534 :   if (script->type() == Script::TYPE_WASM &&
    1212             :       module_object_->module()->source_map_url.size() != 0) {
    1213           0 :     MaybeHandle<String> src_map_str = isolate_->factory()->NewStringFromUtf8(
    1214             :         CStrVector(module_object_->module()->source_map_url.c_str()),
    1215           0 :         AllocationType::kOld);
    1216           0 :     script->set_source_mapping_url(*src_map_str.ToHandleChecked());
    1217             :   }
    1218        2267 :   isolate_->debug()->OnAfterCompile(script);
    1219             : 
    1220             :   // We can only update the feature counts once the entire compile is done.
    1221             :   auto compilation_state =
    1222             :       Impl(module_object_->native_module()->compilation_state());
    1223        2267 :   compilation_state->PublishDetectedFeatures(isolate_);
    1224             : 
    1225             :   // TODO(bbudge) Allow deserialization without wrapper compilation, so we can
    1226             :   // just compile wrappers here.
    1227        2267 :   if (!is_after_deserialization) {
    1228             :     // TODO(wasm): compiling wrappers should be made async.
    1229        2263 :     CompileWrappers();
    1230             :   }
    1231        2267 :   FinishModule();
    1232        2267 : }
    1233             : 
    1234         221 : void AsyncCompileJob::DecodeFailed(const WasmError& error) {
    1235         442 :   ErrorThrower thrower(isolate_, "WebAssembly.compile()");
    1236             :   thrower.CompileFailed(error);
    1237             :   // {job} keeps the {this} pointer alive.
    1238             :   std::shared_ptr<AsyncCompileJob> job =
    1239         442 :       isolate_->wasm_engine()->RemoveCompileJob(this);
    1240         221 :   resolver_->OnCompilationFailed(thrower.Reify());
    1241         221 : }
    1242             : 
    1243          76 : void AsyncCompileJob::AsyncCompileFailed() {
    1244         152 :   ErrorThrower thrower(isolate_, "WebAssembly.compile()");
    1245             :   ValidateSequentially(native_module_->module(), native_module_.get(),
    1246          76 :                        isolate_->counters(), isolate_->allocator(), &thrower);
    1247             :   DCHECK(thrower.error());
    1248             :   // {job} keeps the {this} pointer alive.
    1249             :   std::shared_ptr<AsyncCompileJob> job =
    1250         152 :       isolate_->wasm_engine()->RemoveCompileJob(this);
    1251          76 :   resolver_->OnCompilationFailed(thrower.Reify());
    1252          76 : }
    1253             : 
    1254           0 : void AsyncCompileJob::AsyncCompileSucceeded(Handle<WasmModuleObject> result) {
    1255        2267 :   resolver_->OnCompilationSucceeded(result);
    1256           0 : }
    1257             : 
    1258             : class AsyncCompileJob::CompilationStateCallback {
    1259             :  public:
    1260             :   explicit CompilationStateCallback(AsyncCompileJob* job) : job_(job) {}
    1261             : 
    1262        4554 :   void operator()(CompilationEvent event) {
    1263             :     // This callback is only being called from a foreground task.
    1264        4554 :     switch (event) {
    1265             :       case CompilationEvent::kFinishedBaselineCompilation:
    1266             :         DCHECK(!last_event_.has_value());
    1267        4478 :         if (job_->DecrementAndCheckFinisherCount()) {
    1268        2197 :           job_->DoSync<CompileFinished>();
    1269             :         }
    1270             :         break;
    1271             :       case CompilationEvent::kFinishedTopTierCompilation:
    1272             :         DCHECK_EQ(CompilationEvent::kFinishedBaselineCompilation, last_event_);
    1273             :         // At this point, the job will already be gone, thus do not access it
    1274             :         // here.
    1275             :         break;
    1276             :       case CompilationEvent::kFailedCompilation: {
    1277             :         DCHECK(!last_event_.has_value());
    1278         160 :         if (job_->DecrementAndCheckFinisherCount()) {
    1279          62 :           job_->DoSync<CompileFailed>();
    1280             :         }
    1281             :         break;
    1282             :       }
    1283             :       default:
    1284           0 :         UNREACHABLE();
    1285             :     }
    1286             : #ifdef DEBUG
    1287             :     last_event_ = event;
    1288             : #endif
    1289        4554 :   }
    1290             : 
    1291             :  private:
    1292             :   AsyncCompileJob* job_;
    1293             : #ifdef DEBUG
    1294             :   // This will be modified by different threads, but they externally
    1295             :   // synchronize, so no explicit synchronization (currently) needed here.
    1296             :   base::Optional<CompilationEvent> last_event_;
    1297             : #endif
    1298             : };
    1299             : 
    1300             : // A closure to run a compilation step (either as foreground or background
    1301             : // task) and schedule the next step(s), if any.
    1302        7083 : class AsyncCompileJob::CompileStep {
    1303             :  public:
    1304        7082 :   virtual ~CompileStep() = default;
    1305             : 
    1306        7082 :   void Run(AsyncCompileJob* job, bool on_foreground) {
    1307        7082 :     if (on_foreground) {
    1308        4888 :       HandleScope scope(job->isolate_);
    1309        4888 :       SaveAndSwitchContext saved_context(job->isolate_, *job->native_context_);
    1310        4888 :       RunInForeground(job);
    1311             :     } else {
    1312        2194 :       RunInBackground(job);
    1313             :     }
    1314        7082 :   }
    1315             : 
    1316           0 :   virtual void RunInForeground(AsyncCompileJob*) { UNREACHABLE(); }
    1317           0 :   virtual void RunInBackground(AsyncCompileJob*) { UNREACHABLE(); }
    1318             : };
    1319             : 
    1320             : class AsyncCompileJob::CompileTask : public CancelableTask {
    1321             :  public:
    1322             :   CompileTask(AsyncCompileJob* job, bool on_foreground)
    1323             :       // We only manage the background tasks with the {CancelableTaskManager} of
    1324             :       // the {AsyncCompileJob}. Foreground tasks are managed by the system's
    1325             :       // {CancelableTaskManager}. Background tasks cannot spawn tasks managed by
    1326             :       // their own task manager.
    1327        4889 :       : CancelableTask(on_foreground ? job->isolate_->cancelable_task_manager()
    1328             :                                      : &job->background_task_manager_),
    1329             :         job_(job),
    1330        9279 :         on_foreground_(on_foreground) {}
    1331             : 
    1332       21252 :   ~CompileTask() override {
    1333        7084 :     if (job_ != nullptr && on_foreground_) ResetPendingForegroundTask();
    1334       14168 :   }
    1335             : 
    1336        7082 :   void RunInternal() final {
    1337        7082 :     if (!job_) return;
    1338        7082 :     if (on_foreground_) ResetPendingForegroundTask();
    1339       14164 :     job_->step_->Run(job_, on_foreground_);
    1340             :     // After execution, reset {job_} such that we don't try to reset the pending
    1341             :     // foreground task when the task is deleted.
    1342        7082 :     job_ = nullptr;
    1343             :   }
    1344             : 
    1345             :   void Cancel() {
    1346             :     DCHECK_NOT_NULL(job_);
    1347           1 :     job_ = nullptr;
    1348             :   }
    1349             : 
    1350             :  private:
    1351             :   // {job_} will be cleared to cancel a pending task.
    1352             :   AsyncCompileJob* job_;
    1353             :   bool on_foreground_;
    1354             : 
    1355             :   void ResetPendingForegroundTask() const {
    1356             :     DCHECK_EQ(this, job_->pending_foreground_task_);
    1357        4888 :     job_->pending_foreground_task_ = nullptr;
    1358             :   }
    1359             : };
    1360             : 
    1361        4633 : void AsyncCompileJob::StartForegroundTask() {
    1362             :   DCHECK_NULL(pending_foreground_task_);
    1363             : 
    1364        4633 :   auto new_task = base::make_unique<CompileTask>(this, true);
    1365        4633 :   pending_foreground_task_ = new_task.get();
    1366       13899 :   foreground_task_runner_->PostTask(std::move(new_task));
    1367        4633 : }
    1368             : 
    1369         256 : void AsyncCompileJob::ExecuteForegroundTaskImmediately() {
    1370             :   DCHECK_NULL(pending_foreground_task_);
    1371             : 
    1372         256 :   auto new_task = base::make_unique<CompileTask>(this, true);
    1373         256 :   pending_foreground_task_ = new_task.get();
    1374         256 :   new_task->Run();
    1375         256 : }
    1376             : 
    1377           0 : void AsyncCompileJob::CancelPendingForegroundTask() {
    1378        2647 :   if (!pending_foreground_task_) return;
    1379             :   pending_foreground_task_->Cancel();
    1380           1 :   pending_foreground_task_ = nullptr;
    1381             : }
    1382             : 
    1383        2195 : void AsyncCompileJob::StartBackgroundTask() {
    1384        2195 :   auto task = base::make_unique<CompileTask>(this, false);
    1385             : 
    1386             :   // If --wasm-num-compilation-tasks=0 is passed, do only spawn foreground
    1387             :   // tasks. This is used to make timing deterministic.
    1388        2195 :   if (FLAG_wasm_num_compilation_tasks > 0) {
    1389        6585 :     V8::GetCurrentPlatform()->CallOnWorkerThread(std::move(task));
    1390             :   } else {
    1391           0 :     foreground_task_runner_->PostTask(std::move(task));
    1392             :   }
    1393        2195 : }
    1394             : 
    1395             : template <typename Step,
    1396             :           AsyncCompileJob::UseExistingForegroundTask use_existing_fg_task,
    1397             :           typename... Args>
    1398          64 : void AsyncCompileJob::DoSync(Args&&... args) {
    1399        4631 :   NextStep<Step>(std::forward<Args>(args)...);
    1400          64 :   if (use_existing_fg_task && pending_foreground_task_ != nullptr) return;
    1401        4633 :   StartForegroundTask();
    1402             : }
    1403             : 
    1404             : template <typename Step, typename... Args>
    1405             : void AsyncCompileJob::DoImmediately(Args&&... args) {
    1406         256 :   NextStep<Step>(std::forward<Args>(args)...);
    1407         256 :   ExecuteForegroundTaskImmediately();
    1408             : }
    1409             : 
    1410             : template <typename Step, typename... Args>
    1411             : void AsyncCompileJob::DoAsync(Args&&... args) {
    1412        2195 :   NextStep<Step>(std::forward<Args>(args)...);
    1413        2195 :   StartBackgroundTask();
    1414             : }
    1415             : 
    1416             : template <typename Step, typename... Args>
    1417        7082 : void AsyncCompileJob::NextStep(Args&&... args) {
    1418        7559 :   step_.reset(new Step(std::forward<Args>(args)...));
    1419        7084 : }
    1420             : 
    1421             : //==========================================================================
    1422             : // Step 1: (async) Decode the module.
    1423             : //==========================================================================
    1424        4386 : class AsyncCompileJob::DecodeModule : public AsyncCompileJob::CompileStep {
    1425             :  public:
    1426        2195 :   explicit DecodeModule(Counters* counters) : counters_(counters) {}
    1427             : 
    1428        2194 :   void RunInBackground(AsyncCompileJob* job) override {
    1429        2194 :     ModuleResult result;
    1430             :     {
    1431             :       DisallowHandleAllocation no_handle;
    1432             :       DisallowHeapAllocation no_allocation;
    1433             :       // Decode the module bytes.
    1434             :       TRACE_COMPILE("(1) Decoding module...\n");
    1435        6580 :       TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"),
    1436             :                    "AsyncCompileJob::DecodeModule");
    1437        4386 :       result = DecodeWasmModule(
    1438             :           job->enabled_features_, job->wire_bytes_.start(),
    1439        2194 :           job->wire_bytes_.end(), false, kWasmOrigin, counters_,
    1440        2192 :           job->isolate()->wasm_engine()->allocator());
    1441             : 
    1442             :       // Validate lazy functions here.
    1443        2192 :       auto enabled_features = job->enabled_features_;
    1444        2192 :       if (enabled_features.compilation_hints && result.ok()) {
    1445             :         const WasmModule* module = result.value().get();
    1446             :         auto allocator = job->isolate()->wasm_engine()->allocator();
    1447          24 :         int start = module->num_imported_functions;
    1448          24 :         int end = start + module->num_declared_functions;
    1449             : 
    1450          40 :         for (int func_index = start; func_index < end; func_index++) {
    1451          16 :           const WasmFunction* func = &module->functions[func_index];
    1452          16 :           Vector<const uint8_t> code = job->wire_bytes_.GetFunctionBytes(func);
    1453             : 
    1454          32 :           if (IsLazyCompilation(module, enabled_features, func_index)) {
    1455             :             DecodeResult function_result =
    1456          32 :                 ValidateSingleFunction(module, func_index, code, counters_,
    1457             :                                        allocator, enabled_features);
    1458          16 :             if (function_result.failed()) {
    1459          16 :               result = ModuleResult(function_result.error());
    1460             :               break;
    1461             :             }
    1462             :           }
    1463             :         }
    1464             :       }
    1465             :     }
    1466        2192 :     if (result.failed()) {
    1467             :       // Decoding failure; reject the promise and clean up.
    1468             :       job->DoSync<DecodeFail>(std::move(result).error());
    1469             :     } else {
    1470             :       // Decode passed.
    1471        4304 :       job->DoSync<PrepareAndStartCompile>(std::move(result).value(), true);
    1472             :     }
    1473        2194 :   }
    1474             : 
    1475             :  private:
    1476             :   Counters* const counters_;
    1477             : };
    1478             : 
    1479             : //==========================================================================
    1480             : // Step 1b: (sync) Fail decoding the module.
    1481             : //==========================================================================
    1482         442 : class AsyncCompileJob::DecodeFail : public CompileStep {
    1483             :  public:
    1484         221 :   explicit DecodeFail(WasmError error) : error_(std::move(error)) {}
    1485             : 
    1486             :  private:
    1487             :   WasmError error_;
    1488             : 
    1489         221 :   void RunInForeground(AsyncCompileJob* job) override {
    1490             :     TRACE_COMPILE("(1b) Decoding failed.\n");
    1491             :     // {job_} is deleted in DecodeFailed, therefore the {return}.
    1492         221 :     return job->DecodeFailed(error_);
    1493             :   }
    1494             : };
    1495             : 
    1496             : //==========================================================================
    1497             : // Step 2 (sync): Create heap-allocated data and start compile.
    1498             : //==========================================================================
    1499        4818 : class AsyncCompileJob::PrepareAndStartCompile : public CompileStep {
    1500             :  public:
    1501             :   PrepareAndStartCompile(std::shared_ptr<const WasmModule> module,
    1502             :                          bool start_compilation)
    1503        4816 :       : module_(std::move(module)), start_compilation_(start_compilation) {}
    1504             : 
    1505             :  private:
    1506             :   std::shared_ptr<const WasmModule> module_;
    1507             :   bool start_compilation_;
    1508             : 
    1509        2408 :   void RunInForeground(AsyncCompileJob* job) override {
    1510             :     TRACE_COMPILE("(2) Prepare and start compile...\n");
    1511             : 
    1512             :     // Make sure all compilation tasks stopped running. Decoding (async step)
    1513             :     // is done.
    1514        2408 :     job->background_task_manager_.CancelAndWait();
    1515             : 
    1516        4816 :     job->CreateNativeModule(module_);
    1517             : 
    1518             :     CompilationStateImpl* compilation_state =
    1519             :         Impl(job->native_module_->compilation_state());
    1520        4816 :     compilation_state->AddCallback(CompilationStateCallback{job});
    1521        2408 :     if (start_compilation_) {
    1522             :       // TODO(ahaas): Try to remove the {start_compilation_} check when
    1523             :       // streaming decoding is done in the background. If
    1524             :       // InitializeCompilationUnits always returns 0 for streaming compilation,
    1525             :       // then DoAsync would do the same as NextStep already.
    1526             : 
    1527             :       // Add compilation units and kick off compilation.
    1528        2152 :       InitializeCompilationUnits(job->native_module_.get());
    1529             :     }
    1530        2408 :   }
    1531             : };
    1532             : 
    1533             : //==========================================================================
    1534             : // Step 3a (sync): Compilation failed.
    1535             : //==========================================================================
    1536         186 : class AsyncCompileJob::CompileFailed : public CompileStep {
    1537             :  private:
    1538          62 :   void RunInForeground(AsyncCompileJob* job) override {
    1539             :     TRACE_COMPILE("(3a) Compilation failed\n");
    1540             :     DCHECK(job->native_module_->compilation_state()->failed());
    1541             : 
    1542             :     // {job_} is deleted in AsyncCompileFailed, therefore the {return}.
    1543          62 :     return job->AsyncCompileFailed();
    1544             :   }
    1545             : };
    1546             : 
    1547             : namespace {
    1548        2197 : class SampleTopTierCodeSizeCallback {
    1549             :  public:
    1550             :   explicit SampleTopTierCodeSizeCallback(
    1551             :       std::weak_ptr<NativeModule> native_module)
    1552             :       : native_module_(std::move(native_module)) {}
    1553             : 
    1554         163 :   void operator()(CompilationEvent event) {
    1555             :     // This callback is registered after baseline compilation finished, so the
    1556             :     // only possible event to follow is {kFinishedTopTierCompilation}.
    1557             :     DCHECK_EQ(CompilationEvent::kFinishedTopTierCompilation, event);
    1558         163 :     if (std::shared_ptr<NativeModule> native_module = native_module_.lock()) {
    1559             :       native_module->engine()->SampleTopTierCodeSizeInAllIsolates(
    1560         163 :           native_module);
    1561             :     }
    1562         163 :   }
    1563             : 
    1564             :  private:
    1565             :   std::weak_ptr<NativeModule> native_module_;
    1566             : };
    1567             : }  // namespace
    1568             : 
    1569             : //==========================================================================
    1570             : // Step 3b (sync): Compilation finished.
    1571             : //==========================================================================
    1572        6591 : class AsyncCompileJob::CompileFinished : public CompileStep {
    1573             :  private:
    1574        2197 :   void RunInForeground(AsyncCompileJob* job) override {
    1575             :     TRACE_COMPILE("(3b) Compilation finished\n");
    1576             :     DCHECK(!job->native_module_->compilation_state()->failed());
    1577             :     // Sample the generated code size when baseline compilation finished.
    1578        2197 :     job->native_module_->SampleCodeSize(job->isolate_->counters(),
    1579        2197 :                                         NativeModule::kAfterBaseline);
    1580             :     // Also, set a callback to sample the code size after top-tier compilation
    1581             :     // finished. This callback will *not* keep the NativeModule alive.
    1582        4394 :     job->native_module_->compilation_state()->AddCallback(
    1583        2197 :         SampleTopTierCodeSizeCallback{job->native_module_});
    1584             :     // Then finalize and publish the generated module.
    1585        2197 :     job->FinishCompile();
    1586        2197 :   }
    1587             : };
    1588             : 
    1589        2263 : void AsyncCompileJob::CompileWrappers() {
    1590             :   // TODO(wasm): Compile all wrappers here, including the start function wrapper
    1591             :   // and the wrappers for the function table elements.
    1592             :   TRACE_COMPILE("(5) Compile wrappers...\n");
    1593             :   // Compile JS->wasm wrappers for exported functions.
    1594        2263 :   CompileJsToWasmWrappers(isolate_, module_object_->native_module()->module(),
    1595        4526 :                           handle(module_object_->export_wrappers(), isolate_));
    1596        2263 : }
    1597             : 
    1598        2267 : void AsyncCompileJob::FinishModule() {
    1599             :   TRACE_COMPILE("(6) Finish module...\n");
    1600             :   AsyncCompileSucceeded(module_object_);
    1601        2267 :   isolate_->wasm_engine()->RemoveCompileJob(this);
    1602        2267 : }
    1603             : 
    1604           0 : AsyncStreamingProcessor::AsyncStreamingProcessor(AsyncCompileJob* job)
    1605             :     : decoder_(job->enabled_features_),
    1606             :       job_(job),
    1607         904 :       compilation_unit_builder_(nullptr) {}
    1608             : 
    1609         180 : void AsyncStreamingProcessor::FinishAsyncCompileJobWithError(
    1610             :     const WasmError& error) {
    1611             :   DCHECK(error.has_error());
    1612             :   // Make sure all background tasks stopped executing before we change the state
    1613             :   // of the AsyncCompileJob to DecodeFail.
    1614         180 :   job_->background_task_manager_.CancelAndWait();
    1615             : 
    1616             :   // Check if there is already a CompiledModule, in which case we have to clean
    1617             :   // up the CompilationStateImpl as well.
    1618         180 :   if (job_->native_module_) {
    1619          64 :     Impl(job_->native_module_->compilation_state())->AbortCompilation();
    1620             : 
    1621          64 :     job_->DoSync<AsyncCompileJob::DecodeFail,
    1622          64 :                  AsyncCompileJob::kUseExistingForegroundTask>(error);
    1623             : 
    1624             :     // Clear the {compilation_unit_builder_} if it exists. This is needed
    1625             :     // because there is a check in the destructor of the
    1626             :     // {CompilationUnitBuilder} that it is empty.
    1627          64 :     if (compilation_unit_builder_) compilation_unit_builder_->Clear();
    1628             :   } else {
    1629             :     job_->DoSync<AsyncCompileJob::DecodeFail>(error);
    1630             :   }
    1631         180 : }
    1632             : 
    1633             : // Process the module header.
    1634         408 : bool AsyncStreamingProcessor::ProcessModuleHeader(Vector<const uint8_t> bytes,
    1635             :                                                   uint32_t offset) {
    1636             :   TRACE_STREAMING("Process module header...\n");
    1637         408 :   decoder_.StartDecoding(job_->isolate()->counters(),
    1638         816 :                          job_->isolate()->wasm_engine()->allocator());
    1639         408 :   decoder_.DecodeModuleHeader(bytes, offset);
    1640         408 :   if (!decoder_.ok()) {
    1641          16 :     FinishAsyncCompileJobWithError(decoder_.FinishDecoding(false).error());
    1642          16 :     return false;
    1643             :   }
    1644             :   return true;
    1645             : }
    1646             : 
    1647             : // Process all sections except for the code section.
    1648        1060 : bool AsyncStreamingProcessor::ProcessSection(SectionCode section_code,
    1649             :                                              Vector<const uint8_t> bytes,
    1650             :                                              uint32_t offset) {
    1651             :   TRACE_STREAMING("Process section %d ...\n", section_code);
    1652        1060 :   if (compilation_unit_builder_) {
    1653             :     // We reached a section after the code section, we do not need the
    1654             :     // compilation_unit_builder_ anymore.
    1655             :     CommitCompilationUnits();
    1656             :     compilation_unit_builder_.reset();
    1657             :   }
    1658        1060 :   if (section_code == SectionCode::kUnknownSectionCode) {
    1659             :     Decoder decoder(bytes, offset);
    1660             :     section_code = ModuleDecoder::IdentifyUnknownSection(
    1661         136 :         decoder, bytes.start() + bytes.length());
    1662         136 :     if (section_code == SectionCode::kUnknownSectionCode) {
    1663             :       // Skip unknown sections that we do not know how to handle.
    1664             :       return true;
    1665             :     }
    1666             :     // Remove the unknown section tag from the payload bytes.
    1667         136 :     offset += decoder.position();
    1668         136 :     bytes = bytes.SubVector(decoder.position(), bytes.size());
    1669             :   }
    1670             :   constexpr bool verify_functions = false;
    1671        1060 :   decoder_.DecodeSection(section_code, bytes, offset, verify_functions);
    1672        1060 :   if (!decoder_.ok()) {
    1673          28 :     FinishAsyncCompileJobWithError(decoder_.FinishDecoding(false).error());
    1674          28 :     return false;
    1675             :   }
    1676             :   return true;
    1677             : }
    1678             : 
    1679             : // Start the code section.
    1680         268 : bool AsyncStreamingProcessor::ProcessCodeSectionHeader(
    1681             :     int functions_count, uint32_t offset,
    1682             :     std::shared_ptr<WireBytesStorage> wire_bytes_storage) {
    1683             :   TRACE_STREAMING("Start the code section with %d functions...\n",
    1684             :                   functions_count);
    1685         268 :   if (!decoder_.CheckFunctionsCount(static_cast<uint32_t>(functions_count),
    1686             :                                     offset)) {
    1687          12 :     FinishAsyncCompileJobWithError(decoder_.FinishDecoding(false).error());
    1688          12 :     return false;
    1689             :   }
    1690             :   // Execute the PrepareAndStartCompile step immediately and not in a separate
    1691             :   // task.
    1692         768 :   job_->DoImmediately<AsyncCompileJob::PrepareAndStartCompile>(
    1693         256 :       decoder_.shared_module(), false);
    1694         256 :   auto* compilation_state = Impl(job_->native_module_->compilation_state());
    1695         512 :   compilation_state->SetWireBytesStorage(std::move(wire_bytes_storage));
    1696             : 
    1697             :   // Set number of functions that must be compiled to consider the module fully
    1698             :   // compiled.
    1699         256 :   auto wasm_module = job_->native_module_->module();
    1700         256 :   int num_functions = wasm_module->num_declared_functions;
    1701             :   DCHECK_IMPLIES(!job_->native_module_->enabled_features().compilation_hints,
    1702             :                  wasm_module->num_lazy_compilation_hints == 0);
    1703         256 :   int num_lazy_functions = wasm_module->num_lazy_compilation_hints;
    1704             :   compilation_state->SetNumberOfFunctionsToCompile(num_functions,
    1705         256 :                                                    num_lazy_functions);
    1706             : 
    1707             :   // Set outstanding_finishers_ to 2, because both the AsyncCompileJob and the
    1708             :   // AsyncStreamingProcessor have to finish.
    1709         256 :   job_->outstanding_finishers_.store(2);
    1710         256 :   compilation_unit_builder_.reset(
    1711         256 :       new CompilationUnitBuilder(job_->native_module_.get()));
    1712             :   return true;
    1713             : }
    1714             : 
    1715             : // Process a function body.
    1716         508 : bool AsyncStreamingProcessor::ProcessFunctionBody(Vector<const uint8_t> bytes,
    1717             :                                                   uint32_t offset) {
    1718             :   TRACE_STREAMING("Process function body %d ...\n", num_functions_);
    1719             : 
    1720        1016 :   decoder_.DecodeFunctionBody(
    1721        1016 :       num_functions_, static_cast<uint32_t>(bytes.length()), offset, false);
    1722             : 
    1723         508 :   NativeModule* native_module = job_->native_module_.get();
    1724             :   const WasmModule* module = native_module->module();
    1725         508 :   auto enabled_features = native_module->enabled_features();
    1726             :   uint32_t func_index =
    1727        1016 :       num_functions_ + decoder_.module()->num_imported_functions;
    1728             : 
    1729         508 :   if (IsLazyCompilation(module, native_module, enabled_features, func_index)) {
    1730             :     Counters* counters = Impl(native_module->compilation_state())->counters();
    1731             :     AccountingAllocator* allocator = native_module->engine()->allocator();
    1732             : 
    1733             :     // The native module does not own the wire bytes until {SetWireBytes} is
    1734             :     // called in {OnFinishedStream}. Validation must use {bytes} parameter.
    1735          48 :     DecodeResult result = ValidateSingleFunction(
    1736             :         module, func_index, bytes, counters, allocator, enabled_features);
    1737             : 
    1738          24 :     if (result.failed()) {
    1739           8 :       FinishAsyncCompileJobWithError(result.error());
    1740             :       return false;
    1741             :     }
    1742             : 
    1743          16 :     native_module->UseLazyStub(func_index);
    1744             :   } else {
    1745         484 :     compilation_unit_builder_->AddUnits(func_index);
    1746             :   }
    1747             : 
    1748         500 :   ++num_functions_;
    1749             : 
    1750         500 :   return true;
    1751             : }
    1752             : 
    1753           0 : void AsyncStreamingProcessor::CommitCompilationUnits() {
    1754             :   DCHECK(compilation_unit_builder_);
    1755         324 :   compilation_unit_builder_->Commit();
    1756           0 : }
    1757             : 
    1758         396 : void AsyncStreamingProcessor::OnFinishedChunk() {
    1759             :   TRACE_STREAMING("FinishChunk...\n");
    1760         396 :   if (compilation_unit_builder_) CommitCompilationUnits();
    1761         396 : }
    1762             : 
    1763             : // Finish the processing of the stream.
    1764         192 : void AsyncStreamingProcessor::OnFinishedStream(OwnedVector<uint8_t> bytes) {
    1765             :   TRACE_STREAMING("Finish stream...\n");
    1766         572 :   ModuleResult result = decoder_.FinishDecoding(false);
    1767         192 :   if (result.failed()) {
    1768           4 :     FinishAsyncCompileJobWithError(result.error());
    1769           4 :     return;
    1770             :   }
    1771             :   // We have to open a HandleScope and prepare the Context for
    1772             :   // CreateNativeModule, PrepareRuntimeObjects and FinishCompile as this is a
    1773             :   // callback from the embedder.
    1774         188 :   HandleScope scope(job_->isolate_);
    1775         376 :   SaveAndSwitchContext saved_context(job_->isolate_, *job_->native_context_);
    1776             : 
    1777         188 :   bool needs_finish = job_->DecrementAndCheckFinisherCount();
    1778         188 :   if (job_->native_module_ == nullptr) {
    1779             :     // We are processing a WebAssembly module without code section. Create the
    1780             :     // runtime objects now (would otherwise happen in {PrepareAndStartCompile}).
    1781          56 :     job_->CreateNativeModule(std::move(result).value());
    1782             :     DCHECK(needs_finish);
    1783             :   }
    1784         376 :   job_->wire_bytes_ = ModuleWireBytes(bytes.as_vector());
    1785         376 :   job_->native_module_->SetWireBytes(std::move(bytes));
    1786         188 :   if (needs_finish) {
    1787         160 :     if (job_->native_module_->compilation_state()->failed()) {
    1788          14 :       job_->AsyncCompileFailed();
    1789             :     } else {
    1790          66 :       job_->FinishCompile();
    1791             :     }
    1792             :   }
    1793             : }
    1794             : 
    1795             : // Report an error detected in the StreamingDecoder.
    1796         112 : void AsyncStreamingProcessor::OnError(const WasmError& error) {
    1797             :   TRACE_STREAMING("Stream error...\n");
    1798         112 :   FinishAsyncCompileJobWithError(error);
    1799         112 : }
    1800             : 
    1801          72 : void AsyncStreamingProcessor::OnAbort() {
    1802             :   TRACE_STREAMING("Abort stream...\n");
    1803          72 :   job_->Abort();
    1804          72 : }
    1805             : 
    1806           8 : bool AsyncStreamingProcessor::Deserialize(Vector<const uint8_t> module_bytes,
    1807             :                                           Vector<const uint8_t> wire_bytes) {
    1808             :   // DeserializeNativeModule and FinishCompile assume that they are executed in
    1809             :   // a HandleScope, and that a context is set on the isolate.
    1810           8 :   HandleScope scope(job_->isolate_);
    1811          16 :   SaveAndSwitchContext saved_context(job_->isolate_, *job_->native_context_);
    1812             : 
    1813             :   MaybeHandle<WasmModuleObject> result =
    1814           8 :       DeserializeNativeModule(job_->isolate_, module_bytes, wire_bytes);
    1815           8 :   if (result.is_null()) return false;
    1816             : 
    1817             :   job_->module_object_ =
    1818           8 :       job_->isolate_->global_handles()->Create(*result.ToHandleChecked());
    1819           8 :   job_->native_module_ = job_->module_object_->shared_native_module();
    1820           4 :   auto owned_wire_bytes = OwnedVector<uint8_t>::Of(wire_bytes);
    1821           8 :   job_->wire_bytes_ = ModuleWireBytes(owned_wire_bytes.as_vector());
    1822           8 :   job_->native_module_->SetWireBytes(std::move(owned_wire_bytes));
    1823           4 :   job_->FinishCompile();
    1824             :   return true;
    1825             : }
    1826             : 
    1827             : namespace {
    1828     1242981 : int GetMaxBackgroundTasks() {
    1829     1242981 :   if (NeedsDeterministicCompile()) return 1;
    1830     1242973 :   int num_worker_threads = V8::GetCurrentPlatform()->NumberOfWorkerThreads();
    1831             :   int num_compile_tasks =
    1832     1242973 :       std::min(FLAG_wasm_num_compilation_tasks, num_worker_threads);
    1833     2485946 :   return std::max(1, num_compile_tasks);
    1834             : }
    1835             : }  // namespace
    1836             : 
    1837     1242981 : CompilationStateImpl::CompilationStateImpl(
    1838             :     const std::shared_ptr<NativeModule>& native_module,
    1839             :     std::shared_ptr<Counters> async_counters)
    1840             :     : native_module_(native_module.get()),
    1841             :       background_compile_token_(
    1842             :           std::make_shared<BackgroundCompileToken>(native_module)),
    1843      877465 :       compile_mode_(FLAG_wasm_tier_up &&
    1844      877465 :                             native_module->module()->origin == kWasmOrigin
    1845             :                         ? CompileMode::kTiering
    1846             :                         : CompileMode::kRegular),
    1847             :       async_counters_(std::move(async_counters)),
    1848     1242981 :       max_background_tasks_(GetMaxBackgroundTasks()),
    1849             :       compilation_unit_queues_(max_background_tasks_),
    1850     7457886 :       available_task_ids_(max_background_tasks_) {
    1851    18644619 :   for (int i = 0; i < max_background_tasks_; ++i) {
    1852             :     // Ids are popped on task creation, so reverse this list. This ensures that
    1853             :     // the first background task gets id 0.
    1854    17401638 :     available_task_ids_[i] = max_background_tasks_ - 1 - i;
    1855             :   }
    1856     1242981 : }
    1857             : 
    1858     1243218 : void CompilationStateImpl::AbortCompilation() {
    1859     1243218 :   background_compile_token_->Cancel();
    1860             :   // No more callbacks after abort.
    1861     1243218 :   base::MutexGuard callbacks_guard(&callbacks_mutex_);
    1862             :   callbacks_.clear();
    1863     1243218 : }
    1864             : 
    1865      145141 : void CompilationStateImpl::SetNumberOfFunctionsToCompile(
    1866             :     int num_functions, int num_lazy_functions) {
    1867             :   DCHECK(!failed());
    1868      145141 :   base::MutexGuard guard(&callbacks_mutex_);
    1869             : 
    1870      145145 :   int num_functions_to_compile = num_functions - num_lazy_functions;
    1871      145145 :   outstanding_baseline_functions_ = num_functions_to_compile;
    1872      145145 :   outstanding_top_tier_functions_ = num_functions_to_compile;
    1873      290290 :   highest_execution_tier_.assign(num_functions, ExecutionTier::kNone);
    1874             : 
    1875             :   // Degenerate case of an empty module. Trigger callbacks immediately.
    1876      145145 :   if (num_functions_to_compile == 0) {
    1877       12592 :     for (auto& callback : callbacks_) {
    1878             :       callback(CompilationEvent::kFinishedBaselineCompilation);
    1879             :     }
    1880       12592 :     for (auto& callback : callbacks_) {
    1881             :       callback(CompilationEvent::kFinishedTopTierCompilation);
    1882             :     }
    1883             :     // Clear the callbacks because no more events will be delivered.
    1884             :     callbacks_.clear();
    1885             :   }
    1886      145144 : }
    1887             : 
    1888      147343 : void CompilationStateImpl::AddCallback(CompilationState::callback_t callback) {
    1889      147343 :   base::MutexGuard callbacks_guard(&callbacks_mutex_);
    1890      147345 :   callbacks_.emplace_back(std::move(callback));
    1891      147346 : }
    1892             : 
    1893             : void CompilationStateImpl::AddCompilationUnits(
    1894             :     Vector<std::unique_ptr<WasmCompilationUnit>> baseline_units,
    1895             :     Vector<std::unique_ptr<WasmCompilationUnit>> top_tier_units) {
    1896      138917 :   compilation_unit_queues_.AddUnits(baseline_units, top_tier_units);
    1897             : 
    1898      138919 :   RestartBackgroundTasks();
    1899             : }
    1900             : 
    1901          66 : void CompilationStateImpl::AddTopTierCompilationUnit(
    1902             :     std::unique_ptr<WasmCompilationUnit> unit) {
    1903             :   AddCompilationUnits({}, {&unit, 1});
    1904          66 : }
    1905             : 
    1906             : std::unique_ptr<WasmCompilationUnit>
    1907             : CompilationStateImpl::GetNextCompilationUnit(
    1908             :     int task_id, CompileBaselineOnly baseline_only) {
    1909      794714 :   return compilation_unit_queues_.GetNextUnit(task_id, baseline_only);
    1910             : }
    1911             : 
    1912             : void CompilationStateImpl::OnFinishedUnit(WasmCode* code) {
    1913           0 :   OnFinishedUnits({&code, 1});
    1914             : }
    1915             : 
    1916      268695 : void CompilationStateImpl::OnFinishedUnits(Vector<WasmCode*> code_vector) {
    1917      268695 :   base::MutexGuard guard(&callbacks_mutex_);
    1918             : 
    1919             :   // Assume an order of execution tiers that represents the quality of their
    1920             :   // generated code.
    1921             :   static_assert(ExecutionTier::kNone < ExecutionTier::kInterpreter &&
    1922             :                     ExecutionTier::kInterpreter < ExecutionTier::kLiftoff &&
    1923             :                     ExecutionTier::kLiftoff < ExecutionTier::kTurbofan,
    1924             :                 "Assume an order on execution tiers");
    1925             : 
    1926      268843 :   auto module = native_module_->module();
    1927      268843 :   auto enabled_features = native_module_->enabled_features();
    1928      916175 :   for (WasmCode* code : code_vector) {
    1929             :     DCHECK_NOT_NULL(code);
    1930             :     DCHECK_NE(code->tier(), ExecutionTier::kNone);
    1931      323654 :     native_module_->engine()->LogCode(code);
    1932             : 
    1933             :     // Skip lazily compiled code as we do not consider this for the completion
    1934             :     // of baseline respectively top tier compilation.
    1935             :     int func_index = code->index();
    1936      647348 :     if (IsLazyCompilation(module, native_module_, enabled_features,
    1937             :                           func_index)) {
    1938          47 :       continue;
    1939             :     }
    1940             : 
    1941             :     // Determine whether we are reaching baseline or top tier with the given
    1942             :     // code.
    1943      323627 :     uint32_t slot_index = code->index() - module->num_imported_functions;
    1944             :     ExecutionTierPair requested_tiers = GetRequestedExecutionTiers(
    1945      323627 :         module, compile_mode(), enabled_features, func_index);
    1946             :     DCHECK_EQ(highest_execution_tier_.size(), module->num_declared_functions);
    1947      647252 :     ExecutionTier prior_tier = highest_execution_tier_[slot_index];
    1948      323626 :     bool had_reached_baseline = prior_tier >= requested_tiers.baseline_tier;
    1949             :     bool had_reached_top_tier = prior_tier >= requested_tiers.top_tier;
    1950             :     DCHECK_IMPLIES(had_reached_baseline, prior_tier > ExecutionTier::kNone);
    1951             :     bool reaches_baseline = !had_reached_baseline;
    1952             :     bool reaches_top_tier =
    1953      323626 :         !had_reached_top_tier && code->tier() >= requested_tiers.top_tier;
    1954             :     DCHECK_IMPLIES(reaches_baseline,
    1955             :                    code->tier() >= requested_tiers.baseline_tier);
    1956             :     DCHECK_IMPLIES(reaches_top_tier, had_reached_baseline || reaches_baseline);
    1957             : 
    1958             :     // Remember compilation state before update.
    1959             :     bool had_completed_baseline_compilation =
    1960      323626 :         outstanding_baseline_functions_ == 0;
    1961             :     bool had_completed_top_tier_compilation =
    1962      323626 :         outstanding_top_tier_functions_ == 0;
    1963             : 
    1964             :     // Update compilation state.
    1965      323626 :     if (code->tier() > prior_tier) {
    1966      304016 :       highest_execution_tier_[slot_index] = code->tier();
    1967             :     }
    1968      323626 :     if (reaches_baseline) outstanding_baseline_functions_--;
    1969      323626 :     if (reaches_top_tier) outstanding_top_tier_functions_--;
    1970             :     DCHECK_LE(0, outstanding_baseline_functions_);
    1971             :     DCHECK_LE(outstanding_baseline_functions_, outstanding_top_tier_functions_);
    1972             : 
    1973             :     // Conclude if we are completing baseline or top tier compilation.
    1974      562464 :     bool completes_baseline_compilation = !had_completed_baseline_compilation &&
    1975      238838 :                                           outstanding_baseline_functions_ == 0;
    1976      634581 :     bool completes_top_tier_compilation = !had_completed_top_tier_compilation &&
    1977      310955 :                                           outstanding_top_tier_functions_ == 0;
    1978             :     DCHECK_IMPLIES(
    1979             :         completes_top_tier_compilation,
    1980             :         had_completed_baseline_compilation || completes_baseline_compilation);
    1981             : 
    1982             :     // Trigger callbacks.
    1983      323626 :     if (completes_baseline_compilation) {
    1984      262354 :       for (auto& callback : callbacks_) {
    1985             :         callback(CompilationEvent::kFinishedBaselineCompilation);
    1986             :       }
    1987             :     }
    1988      323626 :     if (completes_top_tier_compilation) {
    1989      262210 :       for (auto& callback : callbacks_) {
    1990             :         callback(CompilationEvent::kFinishedTopTierCompilation);
    1991             :       }
    1992             :       // Clear the callbacks because no more events will be delivered.
    1993             :       callbacks_.clear();
    1994             :     }
    1995             :   }
    1996      268858 : }
    1997             : 
    1998      218621 : void CompilationStateImpl::OnBackgroundTaskStopped(
    1999             :     int task_id, const WasmFeatures& detected) {
    2000             :   {
    2001      218621 :     base::MutexGuard guard(&mutex_);
    2002             :     DCHECK_EQ(0, std::count(available_task_ids_.begin(),
    2003             :                             available_task_ids_.end(), task_id));
    2004             :     DCHECK_GT(max_background_tasks_, available_task_ids_.size());
    2005      218680 :     available_task_ids_.push_back(task_id);
    2006      218672 :     UnionFeaturesInto(&detected_features_, detected);
    2007             :   }
    2008             : 
    2009             :   // The background task could have stopped while we were adding new units, or
    2010             :   // because it reached its deadline. In both cases we need to restart tasks to
    2011             :   // avoid a potential deadlock.
    2012      218676 :   RestartBackgroundTasks();
    2013      218649 : }
    2014             : 
    2015      250841 : void CompilationStateImpl::UpdateDetectedFeatures(
    2016             :     const WasmFeatures& detected) {
    2017      250841 :   base::MutexGuard guard(&mutex_);
    2018      250841 :   UnionFeaturesInto(&detected_features_, detected);
    2019      250842 : }
    2020             : 
    2021      145004 : void CompilationStateImpl::PublishDetectedFeatures(Isolate* isolate) {
    2022             :   // Notifying the isolate of the feature counts must take place under
    2023             :   // the mutex, because even if we have finished baseline compilation,
    2024             :   // tiering compilations may still occur in the background.
    2025      145004 :   base::MutexGuard guard(&mutex_);
    2026             :   UpdateFeatureUseCounts(isolate, detected_features_);
    2027      145004 : }
    2028             : 
    2029      357550 : void CompilationStateImpl::RestartBackgroundTasks() {
    2030             :   // Create new tasks, but only spawn them after releasing the mutex, because
    2031             :   // some platforms (e.g. the predictable platform) might execute tasks right
    2032             :   // away.
    2033      353759 :   std::vector<std::unique_ptr<Task>> new_tasks;
    2034             :   {
    2035      357550 :     base::MutexGuard guard(&mutex_);
    2036             :     // Explicit fast path (quite common): If no more task ids are available
    2037             :     // (i.e. {max_background_tasks_} tasks are already running), spawn nothing.
    2038      357592 :     if (available_task_ids_.empty()) return;
    2039             :     // No need to restart tasks if compilation already failed.
    2040      357589 :     if (failed()) return;
    2041             : 
    2042             :     size_t max_num_restart = compilation_unit_queues_.GetTotalSize();
    2043             : 
    2044      802191 :     while (!available_task_ids_.empty() && max_num_restart-- > 0) {
    2045      224224 :       int task_id = available_task_ids_.back();
    2046             :       available_task_ids_.pop_back();
    2047             :       new_tasks.emplace_back(
    2048      224224 :           native_module_->engine()
    2049      448449 :               ->NewBackgroundCompileTask<BackgroundCompileTask>(
    2050      224226 :                   background_compile_token_, async_counters_, task_id));
    2051             :     }
    2052             :   }
    2053             : 
    2054      353759 :   if (baseline_compilation_finished()) {
    2055      152539 :     for (auto& task : new_tasks) {
    2056       28894 :       V8::GetCurrentPlatform()->CallLowPriorityTaskOnWorkerThread(
    2057       28894 :           std::move(task));
    2058             :     }
    2059             :   } else {
    2060      425446 :     for (auto& task : new_tasks) {
    2061      629337 :       V8::GetCurrentPlatform()->CallOnWorkerThread(std::move(task));
    2062             :     }
    2063             :   }
    2064             : }
    2065             : 
    2066        7882 : void CompilationStateImpl::SetError() {
    2067        7882 :   bool expected = false;
    2068        7882 :   if (!compile_failed_.compare_exchange_strong(expected, true,
    2069             :                                                std::memory_order_relaxed)) {
    2070         297 :     return;  // Already failed before.
    2071             :   }
    2072             : 
    2073        7585 :   base::MutexGuard callbacks_guard(&callbacks_mutex_);
    2074       15170 :   for (auto& callback : callbacks_) {
    2075             :     callback(CompilationEvent::kFailedCompilation);
    2076             :   }
    2077             :   // No more callbacks after an error.
    2078             :   callbacks_.clear();
    2079             : }
    2080             : 
    2081      140434 : void CompileJsToWasmWrappers(Isolate* isolate, const WasmModule* module,
    2082             :                              Handle<FixedArray> export_wrappers) {
    2083             :   JSToWasmWrapperCache js_to_wasm_cache;
    2084             :   int wrapper_index = 0;
    2085             : 
    2086             :   // TODO(6792): Wrappers below are allocated with {Factory::NewCode}. As an
    2087             :   // optimization we keep the code space unlocked to avoid repeated unlocking
    2088             :   // because many such wrapper are allocated in sequence below.
    2089      280868 :   CodeSpaceMemoryModificationScope modification_scope(isolate->heap());
    2090      364435 :   for (auto exp : module->export_table) {
    2091      224001 :     if (exp.kind != kExternalFunction) continue;
    2092      221124 :     auto& function = module->functions[exp.index];
    2093             :     Handle<Code> wrapper_code = js_to_wasm_cache.GetOrCompileJSToWasmWrapper(
    2094      221124 :         isolate, function.sig, function.imported);
    2095      442244 :     export_wrappers->set(wrapper_index, *wrapper_code);
    2096      221123 :     RecordStats(*wrapper_code, isolate->counters());
    2097      221124 :     ++wrapper_index;
    2098             :   }
    2099      140434 : }
    2100             : 
    2101      137965 : Handle<Script> CreateWasmScript(Isolate* isolate,
    2102             :                                 const ModuleWireBytes& wire_bytes,
    2103             :                                 const std::string& source_map_url) {
    2104             :   Handle<Script> script =
    2105      137965 :       isolate->factory()->NewScript(isolate->factory()->empty_string());
    2106      413895 :   script->set_context_data(isolate->native_context()->debug_context_id());
    2107             :   script->set_type(Script::TYPE_WASM);
    2108             : 
    2109      137965 :   int hash = StringHasher::HashSequentialString(
    2110             :       reinterpret_cast<const char*>(wire_bytes.start()),
    2111      137965 :       static_cast<int>(wire_bytes.length()), kZeroHashSeed);
    2112             : 
    2113             :   const int kBufferSize = 32;
    2114             :   char buffer[kBufferSize];
    2115             : 
    2116      137965 :   int name_chars = SNPrintF(ArrayVector(buffer), "wasm-%08x", hash);
    2117             :   DCHECK(name_chars >= 0 && name_chars < kBufferSize);
    2118             :   MaybeHandle<String> name_str = isolate->factory()->NewStringFromOneByte(
    2119      137965 :       VectorOf(reinterpret_cast<uint8_t*>(buffer), name_chars),
    2120      137965 :       AllocationType::kOld);
    2121      275930 :   script->set_name(*name_str.ToHandleChecked());
    2122             : 
    2123      137965 :   if (source_map_url.size() != 0) {
    2124             :     MaybeHandle<String> src_map_str = isolate->factory()->NewStringFromUtf8(
    2125           4 :         CStrVector(source_map_url.c_str()), AllocationType::kOld);
    2126           8 :     script->set_source_mapping_url(*src_map_str.ToHandleChecked());
    2127             :   }
    2128      137965 :   return script;
    2129             : }
    2130             : 
    2131             : }  // namespace wasm
    2132             : }  // namespace internal
    2133      122004 : }  // namespace v8
    2134             : 
    2135             : #undef TRACE_COMPILE
    2136             : #undef TRACE_STREAMING
    2137             : #undef TRACE_LAZY

Generated by: LCOV version 1.10