LCOV - code coverage report
Current view: top level - src/wasm - module-compiler.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 603 633 95.3 %
Date: 2019-01-20 Functions: 101 118 85.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 "src/api.h"
       8             : #include "src/asmjs/asm-js.h"
       9             : #include "src/base/enum-set.h"
      10             : #include "src/base/template-utils.h"
      11             : #include "src/base/utils/random-number-generator.h"
      12             : #include "src/compiler/wasm-compiler.h"
      13             : #include "src/counters.h"
      14             : #include "src/identity-map.h"
      15             : #include "src/property-descriptor.h"
      16             : #include "src/task-utils.h"
      17             : #include "src/tracing/trace-event.h"
      18             : #include "src/trap-handler/trap-handler.h"
      19             : #include "src/wasm/js-to-wasm-wrapper-cache-inl.h"
      20             : #include "src/wasm/module-decoder.h"
      21             : #include "src/wasm/streaming-decoder.h"
      22             : #include "src/wasm/wasm-code-manager.h"
      23             : #include "src/wasm/wasm-engine.h"
      24             : #include "src/wasm/wasm-import-wrapper-cache-inl.h"
      25             : #include "src/wasm/wasm-js.h"
      26             : #include "src/wasm/wasm-limits.h"
      27             : #include "src/wasm/wasm-memory.h"
      28             : #include "src/wasm/wasm-objects-inl.h"
      29             : #include "src/wasm/wasm-result.h"
      30             : #include "src/wasm/wasm-serialization.h"
      31             : 
      32             : #define TRACE_COMPILE(...)                             \
      33             :   do {                                                 \
      34             :     if (FLAG_trace_wasm_compiler) PrintF(__VA_ARGS__); \
      35             :   } while (false)
      36             : 
      37             : #define TRACE_STREAMING(...)                            \
      38             :   do {                                                  \
      39             :     if (FLAG_trace_wasm_streaming) PrintF(__VA_ARGS__); \
      40             :   } while (false)
      41             : 
      42             : #define TRACE_LAZY(...)                                        \
      43             :   do {                                                         \
      44             :     if (FLAG_trace_wasm_lazy_compilation) PrintF(__VA_ARGS__); \
      45             :   } while (false)
      46             : 
      47             : namespace v8 {
      48             : namespace internal {
      49             : namespace wasm {
      50             : 
      51             : namespace {
      52             : 
      53             : enum class CompileMode : uint8_t { kRegular, kTiering };
      54             : 
      55             : // The {CompilationStateImpl} keeps track of the compilation state of the
      56             : // owning NativeModule, i.e. which functions are left to be compiled.
      57             : // It contains a task manager to allow parallel and asynchronous background
      58             : // compilation of functions.
      59             : // It's public interface {CompilationState} lives in compilation-environment.h.
      60             : class CompilationStateImpl {
      61             :  public:
      62             :   CompilationStateImpl(internal::Isolate*, NativeModule*);
      63             :   ~CompilationStateImpl();
      64             : 
      65             :   // Cancel all background compilation and wait for all tasks to finish. Call
      66             :   // this before destructing this object.
      67             :   void CancelAndWait();
      68             : 
      69             :   // Set the number of compilations unit expected to be executed. Needs to be
      70             :   // set before {AddCompilationUnits} is run, which triggers background
      71             :   // compilation.
      72             :   void SetNumberOfFunctionsToCompile(size_t num_functions);
      73             : 
      74             :   // Add the callback function to be called on compilation events. Needs to be
      75             :   // set before {AddCompilationUnits} is run.
      76             :   void AddCallback(CompilationState::callback_t);
      77             : 
      78             :   // Inserts new functions to compile and kicks off compilation.
      79             :   void AddCompilationUnits(
      80             :       std::vector<std::unique_ptr<WasmCompilationUnit>>& baseline_units,
      81             :       std::vector<std::unique_ptr<WasmCompilationUnit>>& tiering_units);
      82             :   std::unique_ptr<WasmCompilationUnit> GetNextCompilationUnit();
      83             :   std::unique_ptr<WasmCompilationUnit> GetNextExecutedUnit();
      84             : 
      85             :   bool HasCompilationUnitToFinish();
      86             : 
      87             :   void OnFinishedUnit(ExecutionTier, WasmCode*);
      88             : 
      89             :   void ReportDetectedFeatures(const WasmFeatures& detected);
      90             :   void OnBackgroundTaskStopped(const WasmFeatures& detected);
      91             :   void PublishDetectedFeatures(Isolate* isolate, const WasmFeatures& detected);
      92             :   void RestartBackgroundCompileTask();
      93             :   void RestartBackgroundTasks(size_t max = std::numeric_limits<size_t>::max());
      94             :   // Only one foreground thread (finisher) is allowed to run at a time.
      95             :   // {SetFinisherIsRunning} returns whether the flag changed its state.
      96             :   bool SetFinisherIsRunning(bool value);
      97             :   void ScheduleFinisherTask();
      98             : 
      99             :   void Abort();
     100             : 
     101             :   void SetError(uint32_t func_index, const WasmError& error);
     102             : 
     103             :   Isolate* isolate() const { return isolate_; }
     104             : 
     105             :   bool failed() const {
     106        9679 :     return compile_error_.load(std::memory_order_relaxed) != nullptr;
     107             :   }
     108             : 
     109      686702 :   bool baseline_compilation_finished() const {
     110      686702 :     base::MutexGuard guard(&mutex_);
     111     1342886 :     return outstanding_baseline_units_ == 0 ||
     112     1281896 :            (compile_mode_ == CompileMode::kTiering &&
     113     1312414 :             outstanding_tiering_units_ == 0);
     114             :   }
     115             : 
     116             :   CompileMode compile_mode() const { return compile_mode_; }
     117             :   WasmFeatures* detected_features() { return &detected_features_; }
     118             : 
     119             :   // Call {GetCompileError} from foreground threads only, since we access
     120             :   // NativeModule::wire_bytes, which is set from the foreground thread once the
     121             :   // stream has finished.
     122       13342 :   WasmError GetCompileError() {
     123             :     CompilationError* error = compile_error_.load(std::memory_order_acquire);
     124             :     DCHECK_NOT_NULL(error);
     125       13342 :     std::ostringstream error_msg;
     126       13342 :     error_msg << "Compiling wasm function \"";
     127       13342 :     wasm::ModuleWireBytes wire_bytes(native_module_->wire_bytes());
     128             :     wasm::WireBytesRef name_ref = native_module_->module()->LookupFunctionName(
     129       26684 :         wire_bytes, error->func_index);
     130       13342 :     if (name_ref.is_set()) {
     131         279 :       wasm::WasmName name = wire_bytes.GetNameOrNull(name_ref);
     132         558 :       error_msg.write(name.start(), name.length());
     133             :     } else {
     134       26126 :       error_msg << "wasm-function[" << error->func_index << "]";
     135             :     }
     136       26684 :     error_msg << "\" failed: " << error->error.message();
     137       13342 :     return WasmError{error->error.offset(), error_msg.str()};
     138             :   }
     139             : 
     140     2900482 :   void SetWireBytesStorage(
     141             :       std::shared_ptr<WireBytesStorage> wire_bytes_storage) {
     142     2900482 :     base::MutexGuard guard(&mutex_);
     143             :     wire_bytes_storage_ = wire_bytes_storage;
     144     2900482 :   }
     145             : 
     146     1754498 :   std::shared_ptr<WireBytesStorage> GetWireBytesStorage() const {
     147     1754498 :     base::MutexGuard guard(&mutex_);
     148             :     DCHECK_NOT_NULL(wire_bytes_storage_);
     149     1754499 :     return wire_bytes_storage_;
     150             :   }
     151             : 
     152             :  private:
     153             :   struct CompilationError {
     154             :     uint32_t const func_index;
     155             :     WasmError const error;
     156             :     CompilationError(uint32_t func_index, WasmError error)
     157        6930 :         : func_index(func_index), error(std::move(error)) {}
     158             :   };
     159             : 
     160           0 :   class LogCodesTask : public CancelableTask {
     161             :    public:
     162             :     LogCodesTask(CancelableTaskManager* manager,
     163             :                  CompilationStateImpl* compilation_state, Isolate* isolate)
     164             :         : CancelableTask(manager),
     165             :           compilation_state_(compilation_state),
     166           0 :           isolate_(isolate) {
     167             :       // This task should only be created if we should actually log code.
     168             :       DCHECK(WasmCode::ShouldBeLogged(isolate));
     169             :     }
     170             : 
     171             :     // Hold the compilation state {mutex_} when calling this method.
     172           0 :     void AddCode(WasmCode* code) { code_to_log_.push_back(code); }
     173             : 
     174           0 :     void RunInternal() override {
     175             :       // Remove this task from the {CompilationStateImpl}. The next compilation
     176             :       // that finishes will allocate and schedule a new task.
     177             :       {
     178           0 :         base::MutexGuard guard(&compilation_state_->mutex_);
     179             :         DCHECK_EQ(this, compilation_state_->log_codes_task_);
     180           0 :         compilation_state_->log_codes_task_ = nullptr;
     181             :       }
     182             :       // If by now we shouldn't log code any more, don't log it.
     183           0 :       if (!WasmCode::ShouldBeLogged(isolate_)) return;
     184           0 :       for (WasmCode* code : code_to_log_) {
     185           0 :         code->LogCode(isolate_);
     186             :       }
     187             :     }
     188             : 
     189             :    private:
     190             :     CompilationStateImpl* const compilation_state_;
     191             :     Isolate* const isolate_;
     192             :     std::vector<WasmCode*> code_to_log_;
     193             :   };
     194             : 
     195         170 :   class FreeCallbacksTask : public CancelableTask {
     196             :    public:
     197             :     explicit FreeCallbacksTask(CompilationStateImpl* comp_state)
     198             :         : CancelableTask(&comp_state->foreground_task_manager_),
     199          85 :           compilation_state_(comp_state) {}
     200             : 
     201          55 :     void RunInternal() override { compilation_state_->callbacks_.clear(); }
     202             : 
     203             :    private:
     204             :     CompilationStateImpl* const compilation_state_;
     205             :   };
     206             : 
     207             :   void NotifyOnEvent(CompilationEvent event, const WasmError* error);
     208             : 
     209             :   std::vector<std::unique_ptr<WasmCompilationUnit>>& finish_units() {
     210      324591 :     return baseline_compilation_finished() ? tiering_finish_units_
     211      324591 :                                            : baseline_finish_units_;
     212             :   }
     213             : 
     214             :   // TODO(mstarzinger): Get rid of the Isolate field to make sure the
     215             :   // {CompilationStateImpl} can be shared across multiple Isolates.
     216             :   Isolate* const isolate_;
     217             :   NativeModule* const native_module_;
     218             :   const CompileMode compile_mode_;
     219             :   // Store the value of {WasmCode::ShouldBeLogged()} at creation time of the
     220             :   // compilation state.
     221             :   // TODO(wasm): We might lose log events if logging is enabled while
     222             :   // compilation is running.
     223             :   bool const should_log_code_;
     224             : 
     225             :   // Compilation error, atomically updated, but at most once (nullptr -> error).
     226             :   // Uses acquire-release semantics (acquire on load, release on update).
     227             :   // For checking whether an error is set, relaxed semantics can be used.
     228             :   std::atomic<CompilationError*> compile_error_{nullptr};
     229             : 
     230             :   // This mutex protects all information of this {CompilationStateImpl} which is
     231             :   // being accessed concurrently.
     232             :   mutable base::Mutex mutex_;
     233             : 
     234             :   //////////////////////////////////////////////////////////////////////////////
     235             :   // Protected by {mutex_}:
     236             : 
     237             :   std::vector<std::unique_ptr<WasmCompilationUnit>> baseline_compilation_units_;
     238             :   std::vector<std::unique_ptr<WasmCompilationUnit>> tiering_compilation_units_;
     239             : 
     240             :   bool finisher_is_running_ = false;
     241             :   size_t num_background_tasks_ = 0;
     242             : 
     243             :   std::vector<std::unique_ptr<WasmCompilationUnit>> baseline_finish_units_;
     244             :   std::vector<std::unique_ptr<WasmCompilationUnit>> tiering_finish_units_;
     245             : 
     246             :   // Features detected to be used in this module. Features can be detected
     247             :   // as a module is being compiled.
     248             :   WasmFeatures detected_features_ = kNoWasmFeatures;
     249             : 
     250             :   // The foreground task to log finished wasm code. Is {nullptr} if no such task
     251             :   // is currently scheduled.
     252             :   LogCodesTask* log_codes_task_ = nullptr;
     253             : 
     254             :   // Abstraction over the storage of the wire bytes. Held in a shared_ptr so
     255             :   // that background compilation jobs can keep the storage alive while
     256             :   // compiling.
     257             :   std::shared_ptr<WireBytesStorage> wire_bytes_storage_;
     258             : 
     259             :   size_t outstanding_baseline_units_ = 0;
     260             :   size_t outstanding_tiering_units_ = 0;
     261             : 
     262             :   // End of fields protected by {mutex_}.
     263             :   //////////////////////////////////////////////////////////////////////////////
     264             : 
     265             :   // Callback functions to be called on compilation events. Only accessible from
     266             :   // the foreground thread.
     267             :   std::vector<CompilationState::callback_t> callbacks_;
     268             : 
     269             :   // Remember whether {Abort()} was called. When set from the foreground this
     270             :   // ensures no more callbacks will be called afterwards. No guarantees when set
     271             :   // from the background. Only needs to be atomic so that it can be set from
     272             :   // foreground and background.
     273             :   std::atomic<bool> aborted_{false};
     274             : 
     275             :   CancelableTaskManager background_task_manager_;
     276             :   CancelableTaskManager foreground_task_manager_;
     277             :   std::shared_ptr<v8::TaskRunner> foreground_task_runner_;
     278             : 
     279             :   const size_t max_background_tasks_ = 0;
     280             : };
     281             : 
     282             : void UpdateFeatureUseCounts(Isolate* isolate, const WasmFeatures& detected) {
     283      159412 :   if (detected.threads) {
     284        1367 :     isolate->CountUsage(v8::Isolate::UseCounterFeature::kWasmThreadOpcodes);
     285             :   }
     286             : }
     287             : 
     288             : CompilationStateImpl* Impl(CompilationState* compilation_state) {
     289             :   return reinterpret_cast<CompilationStateImpl*>(compilation_state);
     290             : }
     291             : const CompilationStateImpl* Impl(const CompilationState* compilation_state) {
     292             :   return reinterpret_cast<const CompilationStateImpl*>(compilation_state);
     293             : }
     294             : 
     295             : }  // namespace
     296             : 
     297             : //////////////////////////////////////////////////////
     298             : // PIMPL implementation of {CompilationState}.
     299             : 
     300     1530590 : CompilationState::~CompilationState() { Impl(this)->~CompilationStateImpl(); }
     301             : 
     302     3061180 : void CompilationState::CancelAndWait() { Impl(this)->CancelAndWait(); }
     303             : 
     304        6739 : void CompilationState::SetError(uint32_t func_index, const WasmError& error) {
     305        6739 :   Impl(this)->SetError(func_index, error);
     306        6739 : }
     307             : 
     308     2900482 : void CompilationState::SetWireBytesStorage(
     309             :     std::shared_ptr<WireBytesStorage> wire_bytes_storage) {
     310     5800964 :   Impl(this)->SetWireBytesStorage(std::move(wire_bytes_storage));
     311     2900482 : }
     312             : 
     313     1516483 : std::shared_ptr<WireBytesStorage> CompilationState::GetWireBytesStorage()
     314             :     const {
     315     1526144 :   return Impl(this)->GetWireBytesStorage();
     316             : }
     317             : 
     318           5 : void CompilationState::AddCallback(CompilationState::callback_t callback) {
     319          10 :   return Impl(this)->AddCallback(std::move(callback));
     320             : }
     321             : 
     322          36 : bool CompilationState::failed() const { return Impl(this)->failed(); }
     323             : 
     324             : // static
     325     1530590 : std::unique_ptr<CompilationState> CompilationState::New(
     326             :     Isolate* isolate, NativeModule* native_module) {
     327             :   return std::unique_ptr<CompilationState>(reinterpret_cast<CompilationState*>(
     328     3061180 :       new CompilationStateImpl(isolate, native_module)));
     329             : }
     330             : 
     331             : // End of PIMPL implementation of {CompilationState}.
     332             : //////////////////////////////////////////////////////
     333             : 
     334        9661 : WasmCode* LazyCompileFunction(Isolate* isolate, NativeModule* native_module,
     335             :                               int func_index) {
     336             :   base::ElapsedTimer compilation_timer;
     337             :   DCHECK(!native_module->has_code(static_cast<uint32_t>(func_index)));
     338             : 
     339             :   compilation_timer.Start();
     340             : 
     341             :   TRACE_LAZY("Compiling wasm-function#%d.\n", func_index);
     342             : 
     343             :   const uint8_t* module_start = native_module->wire_bytes().start();
     344             : 
     345       19322 :   const WasmFunction* func = &native_module->module()->functions[func_index];
     346             :   FunctionBody func_body{func->sig, func->code.offset(),
     347             :                          module_start + func->code.offset(),
     348             :                          module_start + func->code.end_offset()};
     349             : 
     350             :   WasmCompilationUnit unit(
     351             :       isolate->wasm_engine(), func_index,
     352       19322 :       WasmCompilationUnit::GetDefaultExecutionTier(native_module->module()));
     353        9661 :   CompilationEnv env = native_module->CreateCompilationEnv();
     354             :   unit.ExecuteCompilation(
     355             :       &env, native_module,
     356             :       native_module->compilation_state()->GetWireBytesStorage(),
     357             :       isolate->counters(),
     358       28983 :       Impl(native_module->compilation_state())->detected_features());
     359             : 
     360             :   // During lazy compilation, we should never get compilation errors. The module
     361             :   // was verified before starting execution with lazy compilation.
     362             :   // This might be OOM, but then we cannot continue execution anyway.
     363             :   // TODO(clemensh): According to the spec, we can actually skip validation at
     364             :   // module creation time, and return a function that always traps here.
     365        9661 :   CHECK(!native_module->compilation_state()->failed());
     366             : 
     367        9661 :   WasmCode* code = unit.result();
     368             : 
     369        9661 :   if (WasmCode::ShouldBeLogged(isolate)) code->LogCode(isolate);
     370             : 
     371             :   int64_t func_size =
     372        9661 :       static_cast<int64_t>(func->code.end_offset() - func->code.offset());
     373        9661 :   int64_t compilation_time = compilation_timer.Elapsed().InMicroseconds();
     374             : 
     375             :   auto counters = isolate->counters();
     376        9661 :   counters->wasm_lazily_compiled_functions()->Increment();
     377             : 
     378             :   counters->wasm_lazy_compilation_throughput()->AddSample(
     379        9661 :       compilation_time != 0 ? static_cast<int>(func_size / compilation_time)
     380       19322 :                             : 0);
     381             : 
     382        9661 :   return code;
     383             : }
     384             : 
     385        9661 : Address CompileLazy(Isolate* isolate, NativeModule* native_module,
     386             :                     uint32_t func_index) {
     387             :   HistogramTimerScope lazy_time_scope(
     388        9661 :       isolate->counters()->wasm_lazy_compilation_time());
     389             : 
     390             :   DCHECK(!native_module->lazy_compile_frozen());
     391             : 
     392       19322 :   NativeModuleModificationScope native_module_modification_scope(native_module);
     393             : 
     394        9661 :   WasmCode* result = LazyCompileFunction(isolate, native_module, func_index);
     395             :   DCHECK_NOT_NULL(result);
     396             :   DCHECK_EQ(func_index, result->index());
     397             : 
     398        9661 :   return result->instruction_start();
     399             : }
     400             : 
     401             : namespace {
     402             : 
     403             : // The {CompilationUnitBuilder} builds compilation units and stores them in an
     404             : // internal buffer. The buffer is moved into the working queue of the
     405             : // {CompilationStateImpl} when {Commit} is called.
     406        6852 : class CompilationUnitBuilder {
     407             :  public:
     408             :   explicit CompilationUnitBuilder(NativeModule* native_module,
     409             :                                   WasmEngine* wasm_engine)
     410             :       : native_module_(native_module),
     411             :         wasm_engine_(wasm_engine),
     412             :         default_tier_(WasmCompilationUnit::GetDefaultExecutionTier(
     413        7081 :             native_module->module())) {}
     414             : 
     415      114696 :   void AddUnit(uint32_t func_index) {
     416      114696 :     switch (compilation_state()->compile_mode()) {
     417             :       case CompileMode::kTiering:
     418             :         tiering_units_.emplace_back(
     419      229020 :             CreateUnit(func_index, ExecutionTier::kOptimized));
     420             :         baseline_units_.emplace_back(
     421      229020 :             CreateUnit(func_index, ExecutionTier::kBaseline));
     422      114510 :         return;
     423             :       case CompileMode::kRegular:
     424         558 :         baseline_units_.emplace_back(CreateUnit(func_index, default_tier_));
     425         186 :         return;
     426             :     }
     427           0 :     UNREACHABLE();
     428             :   }
     429             : 
     430       13824 :   bool Commit() {
     431        7017 :     if (baseline_units_.empty() && tiering_units_.empty()) return false;
     432       13754 :     compilation_state()->AddCompilationUnits(baseline_units_, tiering_units_);
     433        6877 :     Clear();
     434        6877 :     return true;
     435             :   }
     436             : 
     437        6927 :   void Clear() {
     438             :     baseline_units_.clear();
     439             :     tiering_units_.clear();
     440        6927 :   }
     441             : 
     442             :  private:
     443             :   std::unique_ptr<WasmCompilationUnit> CreateUnit(uint32_t func_index,
     444             :                                                   ExecutionTier tier) {
     445             :     return base::make_unique<WasmCompilationUnit>(wasm_engine_, func_index,
     446      229206 :                                                   tier);
     447             :   }
     448             : 
     449             :   CompilationStateImpl* compilation_state() const {
     450             :     return Impl(native_module_->compilation_state());
     451             :   }
     452             : 
     453             :   NativeModule* const native_module_;
     454             :   WasmEngine* const wasm_engine_;
     455             :   const ExecutionTier default_tier_;
     456             :   std::vector<std::unique_ptr<WasmCompilationUnit>> baseline_units_;
     457             :   std::vector<std::unique_ptr<WasmCompilationUnit>> tiering_units_;
     458             : };
     459             : 
     460             : bool compile_lazy(const WasmModule* module) {
     461      160209 :   return FLAG_wasm_lazy_compilation ||
     462      159660 :          (FLAG_asm_wasm_lazy_compilation && module->origin == kAsmJsOrigin);
     463             : }
     464             : 
     465      247021 : void RecordStats(const Code code, Counters* counters) {
     466      247021 :   counters->wasm_generated_code_size()->Increment(code->body_size());
     467      494039 :   counters->wasm_reloc_size()->Increment(code->relocation_info()->length());
     468      247022 : }
     469             : 
     470      257612 : double MonotonicallyIncreasingTimeInMs() {
     471      257612 :   return V8::GetCurrentPlatform()->MonotonicallyIncreasingTime() *
     472      257611 :          base::Time::kMillisecondsPerSecond;
     473             : }
     474             : 
     475             : // Run by each compilation task and by the main thread (i.e. in both
     476             : // foreground and background threads). The no_finisher_callback is called
     477             : // within the result_mutex_ lock when no finishing task is running, i.e. when
     478             : // the finisher_is_running_ flag is not set.
     479      265807 : bool FetchAndExecuteCompilationUnit(CompilationEnv* env,
     480             :                                     NativeModule* native_module,
     481             :                                     CompilationStateImpl* compilation_state,
     482             :                                     WasmFeatures* detected,
     483             :                                     Counters* counters) {
     484             :   DisallowHeapAccess no_heap_access;
     485             : 
     486             :   std::unique_ptr<WasmCompilationUnit> unit =
     487      265807 :       compilation_state->GetNextCompilationUnit();
     488      265918 :   if (unit == nullptr) return false;
     489             : 
     490             :   // Get the tier before starting compilation, as compilation can switch tiers
     491             :   // if baseline bails out.
     492      228354 :   ExecutionTier tier = unit->tier();
     493             :   unit->ExecuteCompilation(env, native_module,
     494             :                            compilation_state->GetWireBytesStorage(), counters,
     495      685066 :                            detected);
     496      228356 :   compilation_state->OnFinishedUnit(tier, unit->result());
     497             : 
     498      228360 :   return true;
     499             : }
     500             : 
     501        6623 : void InitializeCompilationUnits(NativeModule* native_module,
     502             :                                 WasmEngine* wasm_engine) {
     503             :   ModuleWireBytes wire_bytes(native_module->wire_bytes());
     504             :   const WasmModule* module = native_module->module();
     505             :   CompilationUnitBuilder builder(native_module, wasm_engine);
     506        6623 :   uint32_t start = module->num_imported_functions;
     507        6623 :   uint32_t end = start + module->num_declared_functions;
     508      120816 :   for (uint32_t i = start; i < end; ++i) {
     509      114193 :     builder.AddUnit(i);
     510             :   }
     511        6623 :   builder.Commit();
     512        6623 : }
     513             : 
     514      324707 : void FinishCompilationUnits(CompilationStateImpl* compilation_state) {
     515      649414 :   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"), "FinishCompilationUnits");
     516      324707 :   while (!compilation_state->failed()) {
     517             :     std::unique_ptr<WasmCompilationUnit> unit =
     518      324591 :         compilation_state->GetNextExecutedUnit();
     519      324591 :     if (unit == nullptr) break;
     520      324707 :   }
     521      324707 : }
     522             : 
     523        5273 : void CompileInParallel(Isolate* isolate, NativeModule* native_module) {
     524             :   // Data structures for the parallel compilation.
     525             : 
     526             :   //-----------------------------------------------------------------------
     527             :   // For parallel compilation:
     528             :   // 1) The main thread allocates a compilation unit for each wasm function
     529             :   //    and stores them in the vector {compilation_units} within the
     530             :   //    {compilation_state}. By adding units to the {compilation_state}, new
     531             :   //    {BackgroundCompileTasks} instances are spawned which run on
     532             :   //    the background threads.
     533             :   // 2) The background threads and the main thread pick one compilation unit at
     534             :   //    a time and execute the parallel phase of the compilation unit.
     535             :   // 3) After the parallel phase of all compilation units has started, the
     536             :   //    main thread continues to finish all compilation units as long as
     537             :   //    baseline-compilation units are left to be processed.
     538             :   // 4) If tier-up is enabled, the main thread restarts background tasks
     539             :   //    that take care of compiling and finishing the top-tier compilation
     540             :   //    units.
     541             : 
     542             :   // Turn on the {CanonicalHandleScope} so that the background threads can
     543             :   // use the node cache.
     544        5273 :   CanonicalHandleScope canonical(isolate);
     545             : 
     546        5156 :   CompilationStateImpl* compilation_state =
     547             :       Impl(native_module->compilation_state());
     548             :   // Make sure that no foreground task is spawned for finishing
     549             :   // the compilation units. This foreground thread will be
     550             :   // responsible for finishing compilation.
     551        5273 :   compilation_state->SetFinisherIsRunning(true);
     552             :   uint32_t num_wasm_functions =
     553        5273 :       native_module->num_functions() - native_module->num_imported_functions();
     554        5273 :   compilation_state->SetNumberOfFunctionsToCompile(num_wasm_functions);
     555             : 
     556             :   // 1) The main thread allocates a compilation unit for each wasm function
     557             :   //    and stores them in the vector {compilation_units} within the
     558             :   //    {compilation_state}. By adding units to the {compilation_state}, new
     559             :   //    {BackgroundCompileTask} instances are spawned which run on
     560             :   //    background threads.
     561        5273 :   InitializeCompilationUnits(native_module, isolate->wasm_engine());
     562             : 
     563             :   // 2) The background threads and the main thread pick one compilation unit at
     564             :   //    a time and execute the parallel phase of the compilation unit.
     565        5273 :   WasmFeatures detected_features;
     566        5273 :   CompilationEnv env = native_module->CreateCompilationEnv();
     567       14240 :   while (FetchAndExecuteCompilationUnit(&env, native_module, compilation_state,
     568             :                                         &detected_features,
     569       14116 :                                         isolate->counters()) &&
     570        5149 :          !compilation_state->baseline_compilation_finished()) {
     571             :     // TODO(clemensh): Refactor ownership of the AsyncCompileJob and remove
     572             :     // this.
     573        3810 :     FinishCompilationUnits(compilation_state);
     574             : 
     575        3810 :     if (compilation_state->failed()) break;
     576             :   }
     577             : 
     578      321014 :   while (!compilation_state->failed()) {
     579             :     // 3) After the parallel phase of all compilation units has started, the
     580             :     //    main thread continues to finish compilation units as long as
     581             :     //    baseline compilation units are left to be processed. If compilation
     582             :     //    already failed, all background tasks have already been canceled
     583             :     //    in {FinishCompilationUnits}, and there are no units to finish.
     584      320897 :     FinishCompilationUnits(compilation_state);
     585             : 
     586      320897 :     if (compilation_state->baseline_compilation_finished()) break;
     587             :   }
     588             : 
     589             :   // Publish features from the foreground and background tasks.
     590        5273 :   compilation_state->PublishDetectedFeatures(isolate, detected_features);
     591             : 
     592             :   // 4) If tiering-compilation is enabled, we need to set the finisher
     593             :   //    to false, such that the background threads will spawn a foreground
     594             :   //    thread to finish the top-tier compilation units.
     595       10429 :   if (!compilation_state->failed() &&
     596             :       compilation_state->compile_mode() == CompileMode::kTiering) {
     597        5123 :     compilation_state->SetFinisherIsRunning(false);
     598        5273 :   }
     599        5273 : }
     600             : 
     601      151758 : void CompileSequentially(Isolate* isolate, NativeModule* native_module,
     602             :                          ErrorThrower* thrower) {
     603             :   DCHECK(!thrower->error());
     604             : 
     605             :   ModuleWireBytes wire_bytes(native_module->wire_bytes());
     606             :   const WasmModule* module = native_module->module();
     607      151758 :   WasmFeatures detected = kNoWasmFeatures;
     608             :   auto* comp_state = Impl(native_module->compilation_state());
     609             :   ExecutionTier tier =
     610      151758 :       WasmCompilationUnit::GetDefaultExecutionTier(native_module->module());
     611      567657 :   for (const WasmFunction& func : module->functions) {
     612      270702 :     if (func.imported) continue;  // Imports are compiled at instantiation time.
     613             : 
     614             :     // Compile the function.
     615             :     WasmCompilationUnit::CompileWasmFunction(isolate, native_module, &detected,
     616      145808 :                                              &func, tier);
     617      145807 :     if (comp_state->failed()) {
     618       13124 :       thrower->CompileFailed(comp_state->GetCompileError());
     619        6562 :       break;
     620             :     }
     621             :   }
     622             :   UpdateFeatureUseCounts(isolate, detected);
     623      151760 : }
     624             : 
     625         702 : void ValidateSequentially(Isolate* isolate, NativeModule* native_module,
     626             :                           ErrorThrower* thrower) {
     627             :   DCHECK(!thrower->error());
     628             : 
     629             :   ModuleWireBytes wire_bytes(native_module->wire_bytes());
     630             :   const WasmModule* module = native_module->module();
     631         198 :   uint32_t start = module->num_imported_functions;
     632         198 :   uint32_t end = start + module->num_declared_functions;
     633         693 :   for (uint32_t i = start; i < end; ++i) {
     634         504 :     const WasmFunction& func = module->functions[i];
     635             : 
     636             :     const byte* base = wire_bytes.start();
     637             :     FunctionBody body{func.sig, func.code.offset(), base + func.code.offset(),
     638         504 :                       base + func.code.end_offset()};
     639             :     DecodeResult result;
     640             :     {
     641        1008 :       auto time_counter = SELECT_WASM_COUNTER(
     642             :           isolate->counters(), module->origin, wasm_decode, function_time);
     643             : 
     644             :       TimedHistogramScope wasm_decode_function_time_scope(time_counter);
     645         504 :       WasmFeatures detected;
     646        1008 :       result = VerifyWasmCode(isolate->allocator(),
     647         504 :                               native_module->enabled_features(), module,
     648             :                               &detected, body);
     649             :     }
     650         504 :     if (result.failed()) {
     651           9 :       TruncatedUserString<> name(wire_bytes.GetNameOrNull(&func, module));
     652             :       thrower->CompileError("Compiling function #%d:%.*s failed: %s @+%u", i,
     653             :                             name.length(), name.start(),
     654             :                             result.error().message().c_str(),
     655          18 :                             result.error().offset());
     656             :       break;
     657             :     }
     658             :   }
     659         198 : }
     660             : 
     661      160407 : void CompileNativeModule(Isolate* isolate, ErrorThrower* thrower,
     662             :                          const WasmModule* wasm_module,
     663             :                          NativeModule* native_module) {
     664             :   ModuleWireBytes wire_bytes(native_module->wire_bytes());
     665             : 
     666      160209 :   if (compile_lazy(wasm_module)) {
     667        3178 :     if (wasm_module->origin == kWasmOrigin) {
     668             :       // Validate wasm modules for lazy compilation. Don't validate asm.js
     669             :       // modules, they are valid by construction (otherwise a CHECK will fail
     670             :       // during lazy compilation).
     671             :       // TODO(clemensh): According to the spec, we can actually skip validation
     672             :       // at module creation time, and return a function that always traps at
     673             :       // (lazy) compilation time.
     674         198 :       ValidateSequentially(isolate, native_module, thrower);
     675      160407 :       if (thrower->error()) return;
     676             :     }
     677             : 
     678        3169 :     native_module->SetLazyBuiltin(BUILTIN_CODE(isolate, WasmCompileLazy));
     679             :   } else {
     680             :     size_t funcs_to_compile =
     681      314062 :         wasm_module->functions.size() - wasm_module->num_imported_functions;
     682             :     bool compile_parallel =
     683      314053 :         !FLAG_trace_wasm_decoder && FLAG_wasm_num_compilation_tasks > 0 &&
     684      162304 :         funcs_to_compile > 1 &&
     685        5273 :         V8::GetCurrentPlatform()->NumberOfWorkerThreads() > 0;
     686             : 
     687      157031 :     if (compile_parallel) {
     688        5273 :       CompileInParallel(isolate, native_module);
     689             :     } else {
     690      151758 :       CompileSequentially(isolate, native_module, thrower);
     691             :     }
     692             :     auto* compilation_state = Impl(native_module->compilation_state());
     693      157032 :     if (compilation_state->failed()) {
     694       13358 :       thrower->CompileFailed(compilation_state->GetCompileError());
     695             :     }
     696             :   }
     697             : }
     698             : 
     699             : // The runnable task that finishes compilation in foreground (e.g. updating
     700             : // the NativeModule, the code table, etc.).
     701             : class FinishCompileTask : public CancelableTask {
     702             :  public:
     703             :   explicit FinishCompileTask(CompilationStateImpl* compilation_state,
     704             :                              CancelableTaskManager* task_manager)
     705             :       : CancelableTask(task_manager), compilation_state_(compilation_state) {}
     706             : 
     707             :   void RunInternal() override {
     708             :     Isolate* isolate = compilation_state_->isolate();
     709             :     HandleScope scope(isolate);
     710             :     SaveContext saved_context(isolate);
     711             :     isolate->set_context(Context());
     712             : 
     713             :     TRACE_COMPILE("(4a) Finishing compilation units...\n");
     714             :     if (compilation_state_->failed()) {
     715             :       compilation_state_->SetFinisherIsRunning(false);
     716             :       return;
     717             :     }
     718             : 
     719             :     // We execute for 1 ms and then reschedule the task, same as the GC.
     720             :     double deadline = MonotonicallyIncreasingTimeInMs() + 1.0;
     721             :     while (true) {
     722             :       compilation_state_->RestartBackgroundTasks();
     723             : 
     724             :       std::unique_ptr<WasmCompilationUnit> unit =
     725             :           compilation_state_->GetNextExecutedUnit();
     726             : 
     727             :       if (unit == nullptr) {
     728             :         // It might happen that a background task just scheduled a unit to be
     729             :         // finished, but did not start a finisher task since the flag was still
     730             :         // set. Check for this case, and continue if there is more work.
     731             :         compilation_state_->SetFinisherIsRunning(false);
     732             :         if (compilation_state_->HasCompilationUnitToFinish() &&
     733             :             compilation_state_->SetFinisherIsRunning(true)) {
     734             :           continue;
     735             :         }
     736             :         break;
     737             :       }
     738             : 
     739             :       if (compilation_state_->failed()) break;
     740             : 
     741             :       if (deadline < MonotonicallyIncreasingTimeInMs()) {
     742             :         // We reached the deadline. We reschedule this task and return
     743             :         // immediately. Since we rescheduled this task already, we do not set
     744             :         // the FinisherIsRunning flag to false.
     745             :         compilation_state_->ScheduleFinisherTask();
     746             :         return;
     747             :       }
     748             :     }
     749             :   }
     750             : 
     751             :  private:
     752             :   CompilationStateImpl* compilation_state_;
     753             : };
     754             : 
     755             : // The runnable task that performs compilations in the background.
     756       69258 : class BackgroundCompileTask : public CancelableTask {
     757             :  public:
     758             :   explicit BackgroundCompileTask(CancelableTaskManager* task_manager,
     759             :                                  NativeModule* native_module,
     760             :                                  Counters* counters)
     761             :       : CancelableTask(task_manager),
     762             :         native_module_(native_module),
     763       34635 :         counters_(counters) {}
     764             : 
     765       34416 :   void RunInternal() override {
     766             :     TRACE_COMPILE("(3b) Compiling...\n");
     767       68835 :     TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"),
     768             :                  "BackgroundCompileTask::RunInternal");
     769             :     // The number of currently running background tasks is reduced in
     770             :     // {OnBackgroundTaskStopped}.
     771       34419 :     CompilationEnv env = native_module_->CreateCompilationEnv();
     772       34410 :     auto* compilation_state = Impl(native_module_->compilation_state());
     773       34410 :     WasmFeatures detected_features = kNoWasmFeatures;
     774       34410 :     double deadline = MonotonicallyIncreasingTimeInMs() + 50.0;
     775      291979 :     while (!compilation_state->failed()) {
     776      256954 :       if (!FetchAndExecuteCompilationUnit(&env, native_module_,
     777             :                                           compilation_state, &detected_features,
     778      256901 :                                           counters_)) {
     779             :         break;
     780             :       }
     781      223208 :       if (deadline < MonotonicallyIncreasingTimeInMs()) {
     782          59 :         compilation_state->ReportDetectedFeatures(detected_features);
     783          59 :         compilation_state->RestartBackgroundCompileTask();
     784       34499 :         return;
     785             :       }
     786             :     }
     787       34407 :     compilation_state->OnBackgroundTaskStopped(detected_features);
     788             :   }
     789             : 
     790             :  private:
     791             :   NativeModule* const native_module_;
     792             :   Counters* const counters_;
     793             : };
     794             : 
     795             : }  // namespace
     796             : 
     797      160153 : std::unique_ptr<NativeModule> CompileToNativeModule(
     798      160165 :     Isolate* isolate, const WasmFeatures& enabled, ErrorThrower* thrower,
     799             :     std::shared_ptr<const WasmModule> module, const ModuleWireBytes& wire_bytes,
     800             :     Handle<FixedArray>* export_wrappers_out) {
     801      480473 :   const WasmModule* wasm_module = module.get();
     802      160153 :   TimedHistogramScope wasm_compile_module_time_scope(SELECT_WASM_COUNTER(
     803      320306 :       isolate->counters(), wasm_module->origin, wasm_compile, module_time));
     804             : 
     805             :   // Embedder usage count for declared shared memories.
     806      160163 :   if (wasm_module->has_shared_memory) {
     807        1386 :     isolate->CountUsage(v8::Isolate::UseCounterFeature::kWasmSharedMemory);
     808             :   }
     809      160159 :   int export_wrapper_size = static_cast<int>(module->num_exported_functions);
     810             : 
     811             :   // TODO(wasm): only save the sections necessary to deserialize a
     812             :   // {WasmModule}. E.g. function bodies could be omitted.
     813             :   OwnedVector<uint8_t> wire_bytes_copy =
     814      160159 :       OwnedVector<uint8_t>::Of(wire_bytes.module_bytes());
     815             : 
     816             :   // Create and compile the native module.
     817             :   size_t code_size_estimate =
     818      160161 :       wasm::WasmCodeManager::EstimateNativeModuleCodeSize(module.get());
     819             : 
     820             :   // Create a new {NativeModule} first.
     821             :   auto native_module = isolate->wasm_engine()->code_manager()->NewNativeModule(
     822             :       isolate, enabled, code_size_estimate,
     823      320322 :       wasm::NativeModule::kCanAllocateMoreMemory, std::move(module));
     824      320334 :   native_module->SetWireBytes(std::move(wire_bytes_copy));
     825      160167 :   native_module->SetRuntimeStubs(isolate);
     826             : 
     827      160167 :   CompileNativeModule(isolate, thrower, wasm_module, native_module.get());
     828      160165 :   if (thrower->error()) return {};
     829             : 
     830             :   // Compile JS->wasm wrappers for exported functions.
     831             :   *export_wrappers_out =
     832      153477 :       isolate->factory()->NewFixedArray(export_wrapper_size, TENURED);
     833             :   CompileJsToWasmWrappers(isolate, native_module->module(),
     834      153478 :                           *export_wrappers_out);
     835             : 
     836             :   // Log the code within the generated module for profiling.
     837      153479 :   native_module->LogWasmCodes(isolate);
     838             : 
     839             :   return native_module;
     840             : }
     841             : 
     842          43 : void CompileNativeModuleWithExplicitBoundsChecks(Isolate* isolate,
     843             :                                                  ErrorThrower* thrower,
     844             :                                                  const WasmModule* wasm_module,
     845             :                                                  NativeModule* native_module) {
     846          43 :   native_module->DisableTrapHandler();
     847          43 :   CompileNativeModule(isolate, thrower, wasm_module, native_module);
     848          43 : }
     849             : 
     850        2685 : AsyncCompileJob::AsyncCompileJob(
     851             :     Isolate* isolate, const WasmFeatures& enabled,
     852             :     std::unique_ptr<byte[]> bytes_copy, size_t length, Handle<Context> context,
     853             :     std::shared_ptr<CompilationResultResolver> resolver)
     854             :     : isolate_(isolate),
     855             :       enabled_features_(enabled),
     856             :       bytes_copy_(std::move(bytes_copy)),
     857             :       wire_bytes_(bytes_copy_.get(), bytes_copy_.get() + length),
     858       10740 :       resolver_(std::move(resolver)) {
     859             :   v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
     860        2685 :   v8::Platform* platform = V8::GetCurrentPlatform();
     861        5370 :   foreground_task_runner_ = platform->GetForegroundTaskRunner(v8_isolate);
     862             :   // The handle for the context must be deferred.
     863        2685 :   DeferredHandleScope deferred(isolate);
     864        5370 :   native_context_ = Handle<Context>(context->native_context(), isolate);
     865             :   DCHECK(native_context_->IsNativeContext());
     866        5370 :   deferred_handles_.push_back(deferred.Detach());
     867        2685 : }
     868             : 
     869        2261 : void AsyncCompileJob::Start() {
     870        6783 :   DoAsync<DecodeModule>(isolate_->counters());  // --
     871        2261 : }
     872             : 
     873          65 : void AsyncCompileJob::Abort() {
     874             :   // Removing this job will trigger the destructor, which will cancel all
     875             :   // compilation.
     876         195 :   isolate_->wasm_engine()->RemoveCompileJob(this);
     877          65 : }
     878             : 
     879        1696 : class AsyncStreamingProcessor final : public StreamingProcessor {
     880             :  public:
     881             :   explicit AsyncStreamingProcessor(AsyncCompileJob* job);
     882             : 
     883             :   bool ProcessModuleHeader(Vector<const uint8_t> bytes,
     884             :                            uint32_t offset) override;
     885             : 
     886             :   bool ProcessSection(SectionCode section_code, Vector<const uint8_t> bytes,
     887             :                       uint32_t offset) override;
     888             : 
     889             :   bool ProcessCodeSectionHeader(size_t functions_count, uint32_t offset,
     890             :                                 std::shared_ptr<WireBytesStorage>) override;
     891             : 
     892             :   bool ProcessFunctionBody(Vector<const uint8_t> bytes,
     893             :                            uint32_t offset) override;
     894             : 
     895             :   void OnFinishedChunk() override;
     896             : 
     897             :   void OnFinishedStream(OwnedVector<uint8_t> bytes) override;
     898             : 
     899             :   void OnError(const WasmError&) override;
     900             : 
     901             :   void OnAbort() override;
     902             : 
     903             :   bool Deserialize(Vector<const uint8_t> wire_bytes,
     904             :                    Vector<const uint8_t> module_bytes) override;
     905             : 
     906             :  private:
     907             :   // Finishes the AsyncCompileJob with an error.
     908             :   void FinishAsyncCompileJobWithError(const WasmError&);
     909             : 
     910             :   void CommitCompilationUnits();
     911             : 
     912             :   ModuleDecoder decoder_;
     913             :   AsyncCompileJob* job_;
     914             :   std::unique_ptr<CompilationUnitBuilder> compilation_unit_builder_;
     915             :   uint32_t next_function_ = 0;
     916             : };
     917             : 
     918         424 : std::shared_ptr<StreamingDecoder> AsyncCompileJob::CreateStreamingDecoder() {
     919             :   DCHECK_NULL(stream_);
     920             :   stream_.reset(
     921        1696 :       new StreamingDecoder(base::make_unique<AsyncStreamingProcessor>(this)));
     922         424 :   return stream_;
     923             : }
     924             : 
     925        5370 : AsyncCompileJob::~AsyncCompileJob() {
     926        2685 :   background_task_manager_.CancelAndWait();
     927             :   // If the runtime objects were not created yet, then initial compilation did
     928             :   // not finish yet. In this case we can abort compilation.
     929        5202 :   if (native_module_ && module_object_.is_null()) {
     930         136 :     Impl(native_module_->compilation_state())->Abort();
     931             :   }
     932             :   // Tell the streaming decoder that the AsyncCompileJob is not available
     933             :   // anymore.
     934             :   // TODO(ahaas): Is this notification really necessary? Check
     935             :   // https://crbug.com/888170.
     936        2685 :   if (stream_) stream_->NotifyCompilationEnded();
     937             :   CancelPendingForegroundTask();
     938       10482 :   for (auto d : deferred_handles_) delete d;
     939        2685 : }
     940             : 
     941        2512 : void AsyncCompileJob::CreateNativeModule(
     942             :     std::shared_ptr<const WasmModule> module) {
     943             :   // Embedder usage count for declared shared memories.
     944        5024 :   if (module->has_shared_memory) {
     945           0 :     isolate_->CountUsage(v8::Isolate::UseCounterFeature::kWasmSharedMemory);
     946             :   }
     947             : 
     948             :   // TODO(wasm): Improve efficiency of storing module wire bytes. Only store
     949             :   // relevant sections, not function bodies
     950             : 
     951             :   // Create the module object and populate with compiled functions and
     952             :   // information needed at instantiation time.
     953             :   // TODO(clemensh): For the same module (same bytes / same hash), we should
     954             :   // only have one {WasmModuleObject}. Otherwise, we might only set
     955             :   // breakpoints on a (potentially empty) subset of the instances.
     956             :   // Create the module object.
     957             : 
     958             :   size_t code_size_estimate =
     959        2512 :       wasm::WasmCodeManager::EstimateNativeModuleCodeSize(module.get());
     960       10048 :   native_module_ = isolate_->wasm_engine()->code_manager()->NewNativeModule(
     961             :       isolate_, enabled_features_, code_size_estimate,
     962             :       wasm::NativeModule::kCanAllocateMoreMemory, std::move(module));
     963        7536 :   native_module_->SetWireBytes({std::move(bytes_copy_), wire_bytes_.length()});
     964        5024 :   native_module_->SetRuntimeStubs(isolate_);
     965             : 
     966        2512 :   if (stream_) stream_->NotifyNativeModuleCreated(native_module_);
     967        2512 : }
     968             : 
     969        2376 : void AsyncCompileJob::PrepareRuntimeObjects() {
     970             :   // Create heap objects for script and module bytes to be stored in the
     971             :   // module object. Asm.js is not compiled asynchronously.
     972        2376 :   const WasmModule* module = native_module_->module();
     973             :   Handle<Script> script =
     974        2376 :       CreateWasmScript(isolate_, wire_bytes_, module->source_map_url);
     975             : 
     976             :   size_t code_size_estimate =
     977        2376 :       wasm::WasmCodeManager::EstimateNativeModuleCodeSize(module);
     978             :   module_object_ = WasmModuleObject::New(isolate_, native_module_, script,
     979        4752 :                                          code_size_estimate);
     980             : 
     981             :   {
     982        2376 :     DeferredHandleScope deferred(isolate_);
     983        4752 :     module_object_ = handle(*module_object_, isolate_);
     984        4752 :     deferred_handles_.push_back(deferred.Detach());
     985             :   }
     986        2376 : }
     987             : 
     988             : // This function assumes that it is executed in a HandleScope, and that a
     989             : // context is set on the isolate.
     990        2381 : void AsyncCompileJob::FinishCompile() {
     991        2381 :   bool is_after_deserialization = !module_object_.is_null();
     992        2381 :   if (!is_after_deserialization) {
     993        2376 :     PrepareRuntimeObjects();
     994             :   }
     995             :   DCHECK(!isolate_->context().is_null());
     996             :   // Finish the wasm script now and make it public to the debugger.
     997        9524 :   Handle<Script> script(module_object_->script(), isolate_);
     998        7143 :   if (script->type() == Script::TYPE_WASM &&
     999        4762 :       module_object_->module()->source_map_url.size() != 0) {
    1000             :     MaybeHandle<String> src_map_str = isolate_->factory()->NewStringFromUtf8(
    1001           0 :         CStrVector(module_object_->module()->source_map_url.c_str()), TENURED);
    1002           0 :     script->set_source_mapping_url(*src_map_str.ToHandleChecked());
    1003             :   }
    1004        4762 :   isolate_->debug()->OnAfterCompile(script);
    1005             : 
    1006             :   // We can only update the feature counts once the entire compile is done.
    1007             :   auto compilation_state =
    1008        4762 :       Impl(module_object_->native_module()->compilation_state());
    1009             :   compilation_state->PublishDetectedFeatures(
    1010        2381 :       isolate_, *compilation_state->detected_features());
    1011             : 
    1012             :   // TODO(bbudge) Allow deserialization without wrapper compilation, so we can
    1013             :   // just compile wrappers here.
    1014        2381 :   if (!is_after_deserialization) {
    1015             :     // TODO(wasm): compiling wrappers should be made async.
    1016        2376 :     CompileWrappers();
    1017             :   }
    1018        2381 :   FinishModule();
    1019        2381 : }
    1020             : 
    1021         228 : void AsyncCompileJob::AsyncCompileFailed(Handle<Object> error_reason) {
    1022             :   // {job} keeps the {this} pointer alive.
    1023             :   std::shared_ptr<AsyncCompileJob> job =
    1024         684 :       isolate_->wasm_engine()->RemoveCompileJob(this);
    1025         228 :   resolver_->OnCompilationFailed(error_reason);
    1026         228 : }
    1027             : 
    1028           0 : void AsyncCompileJob::AsyncCompileSucceeded(Handle<WasmModuleObject> result) {
    1029        2381 :   resolver_->OnCompilationSucceeded(result);
    1030           0 : }
    1031             : 
    1032             : class AsyncCompileJob::CompilationStateCallback {
    1033             :  public:
    1034             :   explicit CompilationStateCallback(AsyncCompileJob* job) : job_(job) {}
    1035             : 
    1036        2921 :   void operator()(CompilationEvent event, const WasmError* error) {
    1037             :     // This callback is only being called from a foreground task.
    1038        2921 :     switch (event) {
    1039             :       case CompilationEvent::kFinishedBaselineCompilation:
    1040             :         DCHECK(!last_event_.has_value());
    1041        5982 :         if (job_->DecrementAndCheckFinisherCount()) {
    1042        2856 :           SaveContext saved_context(job_->isolate());
    1043        2856 :           job_->isolate()->set_context(*job_->native_context_);
    1044        1428 :           job_->FinishCompile();
    1045             :         }
    1046             :         break;
    1047             :       case CompilationEvent::kFinishedTopTierCompilation:
    1048             :         DCHECK_EQ(CompilationEvent::kFinishedBaselineCompilation, last_event_);
    1049             :         // This callback should not react to top tier finished callbacks, since
    1050             :         // the job might already be gone then.
    1051             :         break;
    1052             :       case CompilationEvent::kFailedCompilation:
    1053             :         DCHECK(!last_event_.has_value());
    1054             :         DCHECK_NOT_NULL(error);
    1055             :         // Tier-up compilation should not fail if baseline compilation
    1056             :         // did not fail.
    1057             :         DCHECK(!Impl(job_->native_module_->compilation_state())
    1058             :                     ->baseline_compilation_finished());
    1059             : 
    1060             :         {
    1061          92 :           SaveContext saved_context(job_->isolate());
    1062          92 :           job_->isolate()->set_context(*job_->native_context_);
    1063          92 :           ErrorThrower thrower(job_->isolate(), "AsyncCompilation");
    1064             :           thrower.CompileFailed(nullptr, *error);
    1065          46 :           Handle<Object> error = thrower.Reify();
    1066             : 
    1067         138 :           DeferredHandleScope deferred(job_->isolate());
    1068          92 :           error = handle(*error, job_->isolate());
    1069          92 :           job_->deferred_handles_.push_back(deferred.Detach());
    1070             : 
    1071          92 :           job_->DoSync<CompileFailed, kUseExistingForegroundTask>(error);
    1072             :         }
    1073             : 
    1074          46 :         break;
    1075             :       default:
    1076           0 :         UNREACHABLE();
    1077             :     }
    1078             : #ifdef DEBUG
    1079             :     last_event_ = event;
    1080             : #endif
    1081        2921 :   }
    1082             : 
    1083             :  private:
    1084             :   AsyncCompileJob* job_;
    1085             : #ifdef DEBUG
    1086             :   base::Optional<CompilationEvent> last_event_;
    1087             : #endif
    1088             : };
    1089             : 
    1090             : // A closure to run a compilation step (either as foreground or background
    1091             : // task) and schedule the next step(s), if any.
    1092        4978 : class AsyncCompileJob::CompileStep {
    1093             :  public:
    1094        4977 :   virtual ~CompileStep() = default;
    1095             : 
    1096        4977 :   void Run(AsyncCompileJob* job, bool on_foreground) {
    1097        4977 :     if (on_foreground) {
    1098        2716 :       HandleScope scope(job->isolate_);
    1099        5432 :       SaveContext saved_context(job->isolate_);
    1100        2716 :       job->isolate_->set_context(*job->native_context_);
    1101        2716 :       RunInForeground(job);
    1102             :     } else {
    1103        2261 :       RunInBackground(job);
    1104             :     }
    1105        4977 :   }
    1106             : 
    1107           0 :   virtual void RunInForeground(AsyncCompileJob*) { UNREACHABLE(); }
    1108           0 :   virtual void RunInBackground(AsyncCompileJob*) { UNREACHABLE(); }
    1109             : };
    1110             : 
    1111             : class AsyncCompileJob::CompileTask : public CancelableTask {
    1112             :  public:
    1113             :   CompileTask(AsyncCompileJob* job, bool on_foreground)
    1114             :       // We only manage the background tasks with the {CancelableTaskManager} of
    1115             :       // the {AsyncCompileJob}. Foreground tasks are managed by the system's
    1116             :       // {CancelableTaskManager}. Background tasks cannot spawn tasks managed by
    1117             :       // their own task manager.
    1118        2717 :       : CancelableTask(on_foreground ? job->isolate_->cancelable_task_manager()
    1119             :                                      : &job->background_task_manager_),
    1120             :         job_(job),
    1121        7239 :         on_foreground_(on_foreground) {}
    1122             : 
    1123        9956 :   ~CompileTask() override {
    1124        4978 :     if (job_ != nullptr && on_foreground_) ResetPendingForegroundTask();
    1125        9956 :   }
    1126             : 
    1127        4977 :   void RunInternal() final {
    1128        9954 :     if (!job_) return;
    1129        4977 :     if (on_foreground_) ResetPendingForegroundTask();
    1130        9954 :     job_->step_->Run(job_, on_foreground_);
    1131             :     // After execution, reset {job_} such that we don't try to reset the pending
    1132             :     // foreground task when the task is deleted.
    1133        4977 :     job_ = nullptr;
    1134             :   }
    1135             : 
    1136             :   void Cancel() {
    1137             :     DCHECK_NOT_NULL(job_);
    1138           1 :     job_ = nullptr;
    1139             :   }
    1140             : 
    1141             :  private:
    1142             :   // {job_} will be cleared to cancel a pending task.
    1143             :   AsyncCompileJob* job_;
    1144             :   bool on_foreground_;
    1145             : 
    1146             :   void ResetPendingForegroundTask() const {
    1147             :     DCHECK_EQ(this, job_->pending_foreground_task_);
    1148        2716 :     job_->pending_foreground_task_ = nullptr;
    1149             :   }
    1150             : };
    1151             : 
    1152        2488 : void AsyncCompileJob::StartForegroundTask() {
    1153             :   DCHECK_NULL(pending_foreground_task_);
    1154             : 
    1155        2488 :   auto new_task = base::make_unique<CompileTask>(this, true);
    1156        2488 :   pending_foreground_task_ = new_task.get();
    1157        7464 :   foreground_task_runner_->PostTask(std::move(new_task));
    1158        2488 : }
    1159             : 
    1160         229 : void AsyncCompileJob::ExecuteForegroundTaskImmediately() {
    1161             :   DCHECK_NULL(pending_foreground_task_);
    1162             : 
    1163         229 :   auto new_task = base::make_unique<CompileTask>(this, true);
    1164         229 :   pending_foreground_task_ = new_task.get();
    1165         229 :   new_task->Run();
    1166         229 : }
    1167             : 
    1168           0 : void AsyncCompileJob::CancelPendingForegroundTask() {
    1169        2685 :   if (!pending_foreground_task_) return;
    1170             :   pending_foreground_task_->Cancel();
    1171           1 :   pending_foreground_task_ = nullptr;
    1172             : }
    1173             : 
    1174        2261 : void AsyncCompileJob::StartBackgroundTask() {
    1175        2261 :   auto task = base::make_unique<CompileTask>(this, false);
    1176             : 
    1177             :   // If --wasm-num-compilation-tasks=0 is passed, do only spawn foreground
    1178             :   // tasks. This is used to make timing deterministic.
    1179        2261 :   if (FLAG_wasm_num_compilation_tasks > 0) {
    1180        6783 :     V8::GetCurrentPlatform()->CallOnWorkerThread(std::move(task));
    1181             :   } else {
    1182           0 :     foreground_task_runner_->PostTask(std::move(task));
    1183             :   }
    1184        2261 : }
    1185             : 
    1186             : template <typename Step,
    1187             :           AsyncCompileJob::UseExistingForegroundTask use_existing_fg_task,
    1188             :           typename... Args>
    1189         101 : void AsyncCompileJob::DoSync(Args&&... args) {
    1190        2486 :   NextStep<Step>(std::forward<Args>(args)...);
    1191         202 :   if (use_existing_fg_task && pending_foreground_task_ != nullptr) return;
    1192        2488 :   StartForegroundTask();
    1193             : }
    1194             : 
    1195             : template <typename Step, typename... Args>
    1196             : void AsyncCompileJob::DoImmediately(Args&&... args) {
    1197         229 :   NextStep<Step>(std::forward<Args>(args)...);
    1198         229 :   ExecuteForegroundTaskImmediately();
    1199             : }
    1200             : 
    1201             : template <typename Step, typename... Args>
    1202             : void AsyncCompileJob::DoAsync(Args&&... args) {
    1203        2261 :   NextStep<Step>(std::forward<Args>(args)...);
    1204        2261 :   StartBackgroundTask();
    1205             : }
    1206             : 
    1207             : template <typename Step, typename... Args>
    1208        4976 : void AsyncCompileJob::NextStep(Args&&... args) {
    1209        5157 :   step_.reset(new Step(std::forward<Args>(args)...));
    1210        4979 : }
    1211             : 
    1212             : //==========================================================================
    1213             : // Step 1: (async) Decode the module.
    1214             : //==========================================================================
    1215        4520 : class AsyncCompileJob::DecodeModule : public AsyncCompileJob::CompileStep {
    1216             :  public:
    1217        2261 :   explicit DecodeModule(Counters* counters) : counters_(counters) {}
    1218             : 
    1219        4522 :   void RunInBackground(AsyncCompileJob* job) override {
    1220             :     ModuleResult result;
    1221             :     {
    1222             :       DisallowHandleAllocation no_handle;
    1223             :       DisallowHeapAllocation no_allocation;
    1224             :       // Decode the module bytes.
    1225             :       TRACE_COMPILE("(1) Decoding module...\n");
    1226        4522 :       TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"),
    1227             :                    "AsyncCompileJob::DecodeModule");
    1228        6781 :       result = DecodeWasmModule(
    1229             :           job->enabled_features_, job->wire_bytes_.start(),
    1230             :           job->wire_bytes_.end(), false, kWasmOrigin, counters_,
    1231        4518 :           job->isolate()->wasm_engine()->allocator());
    1232             :     }
    1233        2259 :     if (result.failed()) {
    1234             :       // Decoding failure; reject the promise and clean up.
    1235             :       job->DoSync<DecodeFail>(std::move(result).error());
    1236             :     } else {
    1237             :       // Decode passed.
    1238        4518 :       job->DoSync<PrepareAndStartCompile>(std::move(result).value(), true);
    1239        2261 :     }
    1240        2261 :   }
    1241             : 
    1242             :  private:
    1243             :   Counters* const counters_;
    1244             : };
    1245             : 
    1246             : //==========================================================================
    1247             : // Step 1b: (sync) Fail decoding the module.
    1248             : //==========================================================================
    1249         364 : class AsyncCompileJob::DecodeFail : public CompileStep {
    1250             :  public:
    1251         182 :   explicit DecodeFail(WasmError error) : error_(std::move(error)) {}
    1252             : 
    1253             :  private:
    1254             :   WasmError error_;
    1255             : 
    1256         182 :   void RunInForeground(AsyncCompileJob* job) override {
    1257             :     TRACE_COMPILE("(1b) Decoding failed.\n");
    1258         182 :     ErrorThrower thrower(job->isolate_, "AsyncCompile");
    1259             :     thrower.CompileFailed("Wasm decoding failed", error_);
    1260             :     // {job_} is deleted in AsyncCompileFailed, therefore the {return}.
    1261         182 :     return job->AsyncCompileFailed(thrower.Reify());
    1262             :   }
    1263             : };
    1264             : 
    1265             : //==========================================================================
    1266             : // Step 2 (sync): Create heap-allocated data and start compile.
    1267             : //==========================================================================
    1268        4978 : class AsyncCompileJob::PrepareAndStartCompile : public CompileStep {
    1269             :  public:
    1270             :   PrepareAndStartCompile(std::shared_ptr<const WasmModule> module,
    1271             :                          bool start_compilation)
    1272        4978 :       : module_(std::move(module)), start_compilation_(start_compilation) {}
    1273             : 
    1274             :  private:
    1275             :   std::shared_ptr<const WasmModule> module_;
    1276             :   bool start_compilation_;
    1277             : 
    1278        3838 :   void RunInForeground(AsyncCompileJob* job) override {
    1279             :     TRACE_COMPILE("(2) Prepare and start compile...\n");
    1280             : 
    1281             :     // Make sure all compilation tasks stopped running. Decoding (async step)
    1282             :     // is done.
    1283        2488 :     job->background_task_manager_.CancelAndWait();
    1284             : 
    1285        4976 :     job->CreateNativeModule(module_);
    1286             : 
    1287             :     size_t num_functions =
    1288        6326 :         module_->functions.size() - module_->num_imported_functions;
    1289             : 
    1290        2488 :     if (num_functions == 0) {
    1291             :       // Degenerate case of an empty module.
    1292         909 :       job->FinishCompile();
    1293        3397 :       return;
    1294             :     }
    1295             : 
    1296             :     CompilationStateImpl* compilation_state =
    1297        2929 :         Impl(job->native_module_->compilation_state());
    1298        1579 :     compilation_state->AddCallback(CompilationStateCallback{job});
    1299        1579 :     if (start_compilation_) {
    1300             :       // TODO(ahaas): Try to remove the {start_compilation_} check when
    1301             :       // streaming decoding is done in the background. If
    1302             :       // InitializeCompilationUnits always returns 0 for streaming compilation,
    1303             :       // then DoAsync would do the same as NextStep already.
    1304             : 
    1305             :       compilation_state->SetNumberOfFunctionsToCompile(
    1306        1350 :           module_->num_declared_functions);
    1307             :       // Add compilation units and kick off compilation.
    1308             :       InitializeCompilationUnits(job->native_module_.get(),
    1309        1350 :                                  job->isolate()->wasm_engine());
    1310             :     }
    1311             :   }
    1312             : };
    1313             : 
    1314             : //==========================================================================
    1315             : // Step 4b (sync): Compilation failed. Reject Promise.
    1316             : //==========================================================================
    1317          92 : class AsyncCompileJob::CompileFailed : public CompileStep {
    1318             :  public:
    1319             :   explicit CompileFailed(Handle<Object> error_reason)
    1320          46 :       : error_reason_(error_reason) {}
    1321             : 
    1322          46 :   void RunInForeground(AsyncCompileJob* job) override {
    1323             :     TRACE_COMPILE("(4b) Compilation Failed...\n");
    1324          46 :     return job->AsyncCompileFailed(error_reason_);
    1325             :   }
    1326             : 
    1327             :  private:
    1328             :   Handle<Object> error_reason_;
    1329             : };
    1330             : 
    1331        2376 : void AsyncCompileJob::CompileWrappers() {
    1332             :   // TODO(wasm): Compile all wrappers here, including the start function wrapper
    1333             :   // and the wrappers for the function table elements.
    1334             :   TRACE_COMPILE("(5) Compile wrappers...\n");
    1335             :   // Compile JS->wasm wrappers for exported functions.
    1336             :   CompileJsToWasmWrappers(isolate_, module_object_->native_module()->module(),
    1337        9504 :                           handle(module_object_->export_wrappers(), isolate_));
    1338        2376 : }
    1339             : 
    1340        2381 : void AsyncCompileJob::FinishModule() {
    1341             :   TRACE_COMPILE("(6) Finish module...\n");
    1342             :   AsyncCompileSucceeded(module_object_);
    1343             : 
    1344        2381 :   size_t num_functions = native_module_->num_functions() -
    1345             :                          native_module_->num_imported_functions();
    1346        2381 :   auto* compilation_state = Impl(native_module_->compilation_state());
    1347        2381 :   if (compilation_state->compile_mode() == CompileMode::kRegular ||
    1348             :       num_functions == 0) {
    1349             :     // If we do not tier up, the async compile job is done here and
    1350             :     // can be deleted.
    1351        2853 :     isolate_->wasm_engine()->RemoveCompileJob(this);
    1352        3332 :     return;
    1353             :   }
    1354             :   DCHECK_EQ(CompileMode::kTiering, compilation_state->compile_mode());
    1355        1430 :   if (compilation_state->baseline_compilation_finished()) {
    1356        4290 :     isolate_->wasm_engine()->RemoveCompileJob(this);
    1357             :   }
    1358             : }
    1359             : 
    1360           0 : AsyncStreamingProcessor::AsyncStreamingProcessor(AsyncCompileJob* job)
    1361             :     : decoder_(job->enabled_features_),
    1362             :       job_(job),
    1363         424 :       compilation_unit_builder_(nullptr) {}
    1364             : 
    1365         181 : void AsyncStreamingProcessor::FinishAsyncCompileJobWithError(
    1366             :     const WasmError& error) {
    1367             :   DCHECK(error.has_error());
    1368             :   // Make sure all background tasks stopped executing before we change the state
    1369             :   // of the AsyncCompileJob to DecodeFail.
    1370         181 :   job_->background_task_manager_.CancelAndWait();
    1371             : 
    1372             :   // Check if there is already a CompiledModule, in which case we have to clean
    1373             :   // up the CompilationStateImpl as well.
    1374         181 :   if (job_->native_module_) {
    1375          55 :     Impl(job_->native_module_->compilation_state())->Abort();
    1376             : 
    1377             :     job_->DoSync<AsyncCompileJob::DecodeFail,
    1378          55 :                  AsyncCompileJob::kUseExistingForegroundTask>(error);
    1379             : 
    1380             :     // Clear the {compilation_unit_builder_} if it exists. This is needed
    1381             :     // because there is a check in the destructor of the
    1382             :     // {CompilationUnitBuilder} that it is empty.
    1383          55 :     if (compilation_unit_builder_) compilation_unit_builder_->Clear();
    1384             :   } else {
    1385             :     job_->DoSync<AsyncCompileJob::DecodeFail>(error);
    1386             :   }
    1387         181 : }
    1388             : 
    1389             : // Process the module header.
    1390         389 : bool AsyncStreamingProcessor::ProcessModuleHeader(Vector<const uint8_t> bytes,
    1391             :                                                   uint32_t offset) {
    1392             :   TRACE_STREAMING("Process module header...\n");
    1393             :   decoder_.StartDecoding(job_->isolate()->counters(),
    1394        1167 :                          job_->isolate()->wasm_engine()->allocator());
    1395         389 :   decoder_.DecodeModuleHeader(bytes, offset);
    1396         389 :   if (!decoder_.ok()) {
    1397          18 :     FinishAsyncCompileJobWithError(decoder_.FinishDecoding(false).error());
    1398          18 :     return false;
    1399             :   }
    1400             :   return true;
    1401             : }
    1402             : 
    1403             : // Process all sections except for the code section.
    1404         860 : bool AsyncStreamingProcessor::ProcessSection(SectionCode section_code,
    1405             :                                              Vector<const uint8_t> bytes,
    1406             :                                              uint32_t offset) {
    1407             :   TRACE_STREAMING("Process section %d ...\n", section_code);
    1408         860 :   if (compilation_unit_builder_) {
    1409             :     // We reached a section after the code section, we do not need the
    1410             :     // compilation_unit_builder_ anymore.
    1411             :     CommitCompilationUnits();
    1412             :     compilation_unit_builder_.reset();
    1413             :   }
    1414         860 :   if (section_code == SectionCode::kUnknownSectionCode) {
    1415             :     Decoder decoder(bytes, offset);
    1416             :     section_code = ModuleDecoder::IdentifyUnknownSection(
    1417          65 :         decoder, bytes.start() + bytes.length());
    1418          65 :     if (section_code == SectionCode::kUnknownSectionCode) {
    1419             :       // Skip unknown sections that we do not know how to handle.
    1420             :       return true;
    1421             :     }
    1422             :     // Remove the unknown section tag from the payload bytes.
    1423         130 :     offset += decoder.position();
    1424          65 :     bytes = bytes.SubVector(decoder.position(), bytes.size());
    1425             :   }
    1426             :   constexpr bool verify_functions = false;
    1427         860 :   decoder_.DecodeSection(section_code, bytes, offset, verify_functions);
    1428         860 :   if (!decoder_.ok()) {
    1429          24 :     FinishAsyncCompileJobWithError(decoder_.FinishDecoding(false).error());
    1430          24 :     return false;
    1431             :   }
    1432             :   return true;
    1433             : }
    1434             : 
    1435             : // Start the code section.
    1436         243 : bool AsyncStreamingProcessor::ProcessCodeSectionHeader(
    1437             :     size_t functions_count, uint32_t offset,
    1438             :     std::shared_ptr<WireBytesStorage> wire_bytes_storage) {
    1439             :   TRACE_STREAMING("Start the code section with %zu functions...\n",
    1440             :                   functions_count);
    1441         243 :   if (!decoder_.CheckFunctionsCount(static_cast<uint32_t>(functions_count),
    1442         243 :                                     offset)) {
    1443          14 :     FinishAsyncCompileJobWithError(decoder_.FinishDecoding(false).error());
    1444          14 :     return false;
    1445             :   }
    1446             :   // Execute the PrepareAndStartCompile step immediately and not in a separate
    1447             :   // task.
    1448             :   job_->DoImmediately<AsyncCompileJob::PrepareAndStartCompile>(
    1449         687 :       decoder_.shared_module(), false);
    1450             :   job_->native_module_->compilation_state()->SetWireBytesStorage(
    1451        1145 :       std::move(wire_bytes_storage));
    1452             : 
    1453         229 :   auto* compilation_state = Impl(job_->native_module_->compilation_state());
    1454         229 :   compilation_state->SetNumberOfFunctionsToCompile(functions_count);
    1455             : 
    1456             :   // Set outstanding_finishers_ to 2, because both the AsyncCompileJob and the
    1457             :   // AsyncStreamingProcessor have to finish.
    1458         229 :   job_->outstanding_finishers_.store(2);
    1459             :   compilation_unit_builder_.reset(new CompilationUnitBuilder(
    1460         458 :       job_->native_module_.get(), job_->isolate()->wasm_engine()));
    1461             :   return true;
    1462             : }
    1463             : 
    1464             : // Process a function body.
    1465         503 : bool AsyncStreamingProcessor::ProcessFunctionBody(Vector<const uint8_t> bytes,
    1466             :                                                   uint32_t offset) {
    1467             :   TRACE_STREAMING("Process function body %d ...\n", next_function_);
    1468             : 
    1469             :   decoder_.DecodeFunctionBody(
    1470        1006 :       next_function_, static_cast<uint32_t>(bytes.length()), offset, false);
    1471             : 
    1472        1006 :   uint32_t index = next_function_ + decoder_.module()->num_imported_functions;
    1473         503 :   compilation_unit_builder_->AddUnit(index);
    1474         503 :   ++next_function_;
    1475             :   // This method always succeeds. The return value is necessary to comply with
    1476             :   // the StreamingProcessor interface.
    1477         503 :   return true;
    1478             : }
    1479             : 
    1480           0 : void AsyncStreamingProcessor::CommitCompilationUnits() {
    1481             :   DCHECK(compilation_unit_builder_);
    1482         324 :   compilation_unit_builder_->Commit();
    1483           0 : }
    1484             : 
    1485         403 : void AsyncStreamingProcessor::OnFinishedChunk() {
    1486             :   TRACE_STREAMING("FinishChunk...\n");
    1487         403 :   if (compilation_unit_builder_) CommitCompilationUnits();
    1488         403 : }
    1489             : 
    1490             : // Finish the processing of the stream.
    1491         158 : void AsyncStreamingProcessor::OnFinishedStream(OwnedVector<uint8_t> bytes) {
    1492             :   TRACE_STREAMING("Finish stream...\n");
    1493         316 :   ModuleResult result = decoder_.FinishDecoding(false);
    1494         158 :   if (result.failed()) {
    1495           5 :     FinishAsyncCompileJobWithError(result.error());
    1496         163 :     return;
    1497             :   }
    1498             :   // We have to open a HandleScope and prepare the Context for
    1499             :   // CreateNativeModule, PrepareRuntimeObjects and FinishCompile as this is a
    1500             :   // callback from the embedder.
    1501         153 :   HandleScope scope(job_->isolate_);
    1502         306 :   SaveContext saved_context(job_->isolate_);
    1503         306 :   job_->isolate_->set_context(*job_->native_context_);
    1504             : 
    1505         153 :   bool needs_finish = job_->DecrementAndCheckFinisherCount();
    1506         306 :   if (job_->native_module_ == nullptr) {
    1507             :     // We are processing a WebAssembly module without code section. Create the
    1508             :     // runtime objects now (would otherwise happen in {PrepareAndStartCompile}).
    1509          48 :     job_->CreateNativeModule(std::move(result).value());
    1510             :     DCHECK(needs_finish);
    1511             :   }
    1512         306 :   job_->wire_bytes_ = ModuleWireBytes(bytes.as_vector());
    1513         306 :   job_->native_module_->SetWireBytes(std::move(bytes));
    1514         153 :   if (needs_finish) {
    1515          39 :     job_->FinishCompile();
    1516         153 :   }
    1517             : }
    1518             : 
    1519             : // Report an error detected in the StreamingDecoder.
    1520         120 : void AsyncStreamingProcessor::OnError(const WasmError& error) {
    1521             :   TRACE_STREAMING("Stream error...\n");
    1522         120 :   FinishAsyncCompileJobWithError(error);
    1523         120 : }
    1524             : 
    1525          65 : void AsyncStreamingProcessor::OnAbort() {
    1526             :   TRACE_STREAMING("Abort stream...\n");
    1527          65 :   job_->Abort();
    1528          65 : }
    1529             : 
    1530          10 : bool AsyncStreamingProcessor::Deserialize(Vector<const uint8_t> module_bytes,
    1531             :                                           Vector<const uint8_t> wire_bytes) {
    1532             :   // DeserializeNativeModule and FinishCompile assume that they are executed in
    1533             :   // a HandleScope, and that a context is set on the isolate.
    1534          10 :   HandleScope scope(job_->isolate_);
    1535          20 :   SaveContext saved_context(job_->isolate_);
    1536          20 :   job_->isolate_->set_context(*job_->native_context_);
    1537             : 
    1538             :   MaybeHandle<WasmModuleObject> result =
    1539          10 :       DeserializeNativeModule(job_->isolate_, module_bytes, wire_bytes);
    1540          10 :   if (result.is_null()) return false;
    1541             : 
    1542          10 :   job_->module_object_ = result.ToHandleChecked();
    1543             :   {
    1544           5 :     DeferredHandleScope deferred(job_->isolate_);
    1545          10 :     job_->module_object_ = handle(*job_->module_object_, job_->isolate_);
    1546          10 :     job_->deferred_handles_.push_back(deferred.Detach());
    1547             :   }
    1548          15 :   job_->native_module_ = job_->module_object_->shared_native_module();
    1549           5 :   auto owned_wire_bytes = OwnedVector<uint8_t>::Of(wire_bytes);
    1550          10 :   job_->wire_bytes_ = ModuleWireBytes(owned_wire_bytes.as_vector());
    1551          10 :   job_->native_module_->SetWireBytes(std::move(owned_wire_bytes));
    1552           5 :   job_->FinishCompile();
    1553             :   return true;
    1554             : }
    1555             : 
    1556     1530590 : CompilationStateImpl::CompilationStateImpl(internal::Isolate* isolate,
    1557             :                                            NativeModule* native_module)
    1558             :     : isolate_(isolate),
    1559             :       native_module_(native_module),
    1560     1530488 :       compile_mode_(FLAG_wasm_tier_up &&
    1561     1530488 :                             native_module->module()->origin == kWasmOrigin
    1562             :                         ? CompileMode::kTiering
    1563             :                         : CompileMode::kRegular),
    1564     1530590 :       should_log_code_(WasmCode::ShouldBeLogged(isolate)),
    1565             :       max_background_tasks_(std::max(
    1566             :           1, std::min(FLAG_wasm_num_compilation_tasks,
    1567    13775306 :                       V8::GetCurrentPlatform()->NumberOfWorkerThreads()))) {
    1568     1530588 :   v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_);
    1569     1530588 :   v8::Platform* platform = V8::GetCurrentPlatform();
    1570     3061179 :   foreground_task_runner_ = platform->GetForegroundTaskRunner(v8_isolate);
    1571     1530590 : }
    1572             : 
    1573     4591770 : CompilationStateImpl::~CompilationStateImpl() {
    1574             :   DCHECK(background_task_manager_.canceled());
    1575             :   DCHECK(foreground_task_manager_.canceled());
    1576             :   CompilationError* error = compile_error_.load(std::memory_order_acquire);
    1577     1537405 :   if (error != nullptr) delete error;
    1578     1530590 : }
    1579             : 
    1580             : void CompilationStateImpl::CancelAndWait() {
    1581     1530590 :   background_task_manager_.CancelAndWait();
    1582     1530590 :   foreground_task_manager_.CancelAndWait();
    1583             : }
    1584             : 
    1585        6852 : void CompilationStateImpl::SetNumberOfFunctionsToCompile(size_t num_functions) {
    1586             :   DCHECK(!failed());
    1587        6852 :   base::MutexGuard guard(&mutex_);
    1588        6852 :   outstanding_baseline_units_ = num_functions;
    1589             : 
    1590        6852 :   if (compile_mode_ == CompileMode::kTiering) {
    1591        6801 :     outstanding_tiering_units_ = num_functions;
    1592             :   }
    1593        6852 : }
    1594             : 
    1595             : void CompilationStateImpl::AddCallback(CompilationState::callback_t callback) {
    1596        1584 :   callbacks_.emplace_back(std::move(callback));
    1597             : }
    1598             : 
    1599        6877 : void CompilationStateImpl::AddCompilationUnits(
    1600             :     std::vector<std::unique_ptr<WasmCompilationUnit>>& baseline_units,
    1601             :     std::vector<std::unique_ptr<WasmCompilationUnit>>& tiering_units) {
    1602             :   {
    1603        6877 :     base::MutexGuard guard(&mutex_);
    1604             : 
    1605        6877 :     if (compile_mode_ == CompileMode::kTiering) {
    1606             :       DCHECK_EQ(baseline_units.size(), tiering_units.size());
    1607             :       DCHECK_EQ(tiering_units.back()->tier(), ExecutionTier::kOptimized);
    1608             :       tiering_compilation_units_.insert(
    1609             :           tiering_compilation_units_.end(),
    1610             :           std::make_move_iterator(tiering_units.begin()),
    1611        6826 :           std::make_move_iterator(tiering_units.end()));
    1612             :     } else {
    1613             :       DCHECK(tiering_compilation_units_.empty());
    1614             :     }
    1615             : 
    1616             :     baseline_compilation_units_.insert(
    1617             :         baseline_compilation_units_.end(),
    1618             :         std::make_move_iterator(baseline_units.begin()),
    1619        6877 :         std::make_move_iterator(baseline_units.end()));
    1620             :   }
    1621             : 
    1622        6877 :   RestartBackgroundTasks();
    1623        6877 : }
    1624             : 
    1625             : std::unique_ptr<WasmCompilationUnit>
    1626      265798 : CompilationStateImpl::GetNextCompilationUnit() {
    1627      265798 :   base::MutexGuard guard(&mutex_);
    1628             : 
    1629             :   std::vector<std::unique_ptr<WasmCompilationUnit>>& units =
    1630             :       baseline_compilation_units_.empty() ? tiering_compilation_units_
    1631      265928 :                                           : baseline_compilation_units_;
    1632             : 
    1633      265928 :   if (!units.empty()) {
    1634             :     std::unique_ptr<WasmCompilationUnit> unit = std::move(units.back());
    1635      228363 :     units.pop_back();
    1636             :     return unit;
    1637             :   }
    1638             : 
    1639             :   return std::unique_ptr<WasmCompilationUnit>();
    1640             : }
    1641             : 
    1642             : std::unique_ptr<WasmCompilationUnit>
    1643      324591 : CompilationStateImpl::GetNextExecutedUnit() {
    1644             :   std::vector<std::unique_ptr<WasmCompilationUnit>>& units = finish_units();
    1645      324591 :   base::MutexGuard guard(&mutex_);
    1646      324591 :   if (units.empty()) return {};
    1647             :   std::unique_ptr<WasmCompilationUnit> ret = std::move(units.back());
    1648           0 :   units.pop_back();
    1649             :   return ret;
    1650             : }
    1651             : 
    1652             : bool CompilationStateImpl::HasCompilationUnitToFinish() {
    1653             :   return !finish_units().empty();
    1654             : }
    1655             : 
    1656      228357 : void CompilationStateImpl::OnFinishedUnit(ExecutionTier tier, WasmCode* code) {
    1657             :   // This mutex guarantees that events happen in the right order.
    1658      228357 :   base::MutexGuard guard(&mutex_);
    1659             : 
    1660      456724 :   if (failed()) return;
    1661             : 
    1662             :   // If we are *not* compiling in tiering mode, then all units are counted as
    1663             :   // baseline units.
    1664      228063 :   bool is_tiering_mode = compile_mode_ == CompileMode::kTiering;
    1665      228063 :   bool is_tiering_unit = is_tiering_mode && tier == ExecutionTier::kOptimized;
    1666             : 
    1667             :   // Sanity check: If we are not in tiering mode, there cannot be outstanding
    1668             :   // tiering units.
    1669             :   DCHECK_IMPLIES(!is_tiering_mode, outstanding_tiering_units_ == 0);
    1670             : 
    1671             :   // Bitset of events to deliver.
    1672             :   base::EnumSet<CompilationEvent> events;
    1673             : 
    1674      228063 :   if (is_tiering_unit) {
    1675             :     DCHECK_LT(0, outstanding_tiering_units_);
    1676      113799 :     --outstanding_tiering_units_;
    1677      113799 :     if (outstanding_tiering_units_ == 0) {
    1678             :       // If baseline compilation has not finished yet, then also trigger
    1679             :       // {kFinishedBaselineCompilation}.
    1680        6547 :       if (outstanding_baseline_units_ > 0) {
    1681             :         events.Add(CompilationEvent::kFinishedBaselineCompilation);
    1682             :       }
    1683             :       events.Add(CompilationEvent::kFinishedTopTierCompilation);
    1684             :     }
    1685             :   } else {
    1686             :     DCHECK_LT(0, outstanding_baseline_units_);
    1687      114264 :     --outstanding_baseline_units_;
    1688      114264 :     if (outstanding_baseline_units_ == 0) {
    1689             :       events.Add(CompilationEvent::kFinishedBaselineCompilation);
    1690             :       // If we are not tiering, then we also trigger the "top tier finished"
    1691             :       // event when baseline compilation is finished.
    1692        6604 :       if (!is_tiering_mode) {
    1693             :         events.Add(CompilationEvent::kFinishedTopTierCompilation);
    1694             :       }
    1695             :     }
    1696             :   }
    1697             : 
    1698      228063 :   if (!events.empty()) {
    1699       11398 :     auto notify_events = [this, events] {
    1700       34194 :       for (auto event : {CompilationEvent::kFinishedBaselineCompilation,
    1701       22796 :                          CompilationEvent::kFinishedTopTierCompilation}) {
    1702       22796 :         if (!events.contains(event)) continue;
    1703       11727 :         NotifyOnEvent(event, nullptr);
    1704             :       }
    1705       11398 :     };
    1706       13151 :     foreground_task_runner_->PostTask(
    1707       78906 :         MakeCancelableTask(&foreground_task_manager_, notify_events));
    1708             :   }
    1709             : 
    1710      228063 :   if (should_log_code_ && code != nullptr) {
    1711           0 :     if (log_codes_task_ == nullptr) {
    1712             :       auto new_task = base::make_unique<LogCodesTask>(&foreground_task_manager_,
    1713           0 :                                                       this, isolate_);
    1714           0 :       log_codes_task_ = new_task.get();
    1715           0 :       foreground_task_runner_->PostTask(std::move(new_task));
    1716             :     }
    1717           0 :     log_codes_task_->AddCode(code);
    1718             :   }
    1719             : }
    1720             : 
    1721       34635 : void CompilationStateImpl::RestartBackgroundCompileTask() {
    1722             :   auto task = base::make_unique<BackgroundCompileTask>(
    1723       69270 :       &background_task_manager_, native_module_, isolate_->counters());
    1724             : 
    1725             :   // If --wasm-num-compilation-tasks=0 is passed, do only spawn foreground
    1726             :   // tasks. This is used to make timing deterministic.
    1727       34635 :   if (FLAG_wasm_num_compilation_tasks == 0) {
    1728           0 :     foreground_task_runner_->PostTask(std::move(task));
    1729       34635 :     return;
    1730             :   }
    1731             : 
    1732       34635 :   if (baseline_compilation_finished()) {
    1733       17844 :     V8::GetCurrentPlatform()->CallLowPriorityTaskOnWorkerThread(
    1734       53532 :         std::move(task));
    1735             :   } else {
    1736       50373 :     V8::GetCurrentPlatform()->CallOnWorkerThread(std::move(task));
    1737             :   }
    1738             : }
    1739             : 
    1740          59 : void CompilationStateImpl::ReportDetectedFeatures(
    1741             :     const WasmFeatures& detected) {
    1742          59 :   base::MutexGuard guard(&mutex_);
    1743          59 :   UnionFeaturesInto(&detected_features_, detected);
    1744          59 : }
    1745             : 
    1746       34383 : void CompilationStateImpl::OnBackgroundTaskStopped(
    1747             :     const WasmFeatures& detected) {
    1748       34383 :   base::MutexGuard guard(&mutex_);
    1749             :   DCHECK_LE(1, num_background_tasks_);
    1750       34384 :   --num_background_tasks_;
    1751       34384 :   UnionFeaturesInto(&detected_features_, detected);
    1752       34383 : }
    1753             : 
    1754        7654 : void CompilationStateImpl::PublishDetectedFeatures(
    1755             :     Isolate* isolate, const WasmFeatures& detected) {
    1756             :   // Notifying the isolate of the feature counts must take place under
    1757             :   // the mutex, because even if we have finished baseline compilation,
    1758             :   // tiering compilations may still occur in the background.
    1759        7654 :   base::MutexGuard guard(&mutex_);
    1760        7654 :   UnionFeaturesInto(&detected_features_, detected);
    1761             :   UpdateFeatureUseCounts(isolate, detected_features_);
    1762        7654 : }
    1763             : 
    1764        6877 : void CompilationStateImpl::RestartBackgroundTasks(size_t max) {
    1765             :   size_t num_restart;
    1766             :   {
    1767        6877 :     base::MutexGuard guard(&mutex_);
    1768             :     // No need to restart tasks if compilation already failed.
    1769        6877 :     if (failed()) return;
    1770             : 
    1771             :     DCHECK_LE(num_background_tasks_, max_background_tasks_);
    1772        6877 :     if (num_background_tasks_ == max_background_tasks_) return;
    1773             :     size_t num_compilation_units =
    1774       20631 :         baseline_compilation_units_.size() + tiering_compilation_units_.size();
    1775        6877 :     size_t stopped_tasks = max_background_tasks_ - num_background_tasks_;
    1776        6877 :     num_restart = std::min(max, std::min(num_compilation_units, stopped_tasks));
    1777        6877 :     num_background_tasks_ += num_restart;
    1778             :   }
    1779             : 
    1780       34576 :   for (; num_restart > 0; --num_restart) {
    1781       34576 :     RestartBackgroundCompileTask();
    1782             :   }
    1783             : }
    1784             : 
    1785       10396 : bool CompilationStateImpl::SetFinisherIsRunning(bool value) {
    1786       10396 :   base::MutexGuard guard(&mutex_);
    1787       10396 :   if (finisher_is_running_ == value) return false;
    1788       10396 :   finisher_is_running_ = value;
    1789       10396 :   return true;
    1790             : }
    1791             : 
    1792             : void CompilationStateImpl::ScheduleFinisherTask() {
    1793             :   foreground_task_runner_->PostTask(
    1794             :       base::make_unique<FinishCompileTask>(this, &foreground_task_manager_));
    1795             : }
    1796             : 
    1797         191 : void CompilationStateImpl::Abort() {
    1798         382 :   SetError(0, WasmError{0, "Compilation aborted"});
    1799         191 :   background_task_manager_.CancelAndWait();
    1800             :   // No more callbacks after abort. Don't free the std::function objects here,
    1801             :   // since this might clear references in the embedder, which is only allowed on
    1802             :   // the main thread.
    1803             :   aborted_.store(true);
    1804         191 :   if (!callbacks_.empty()) {
    1805          85 :     foreground_task_runner_->PostTask(
    1806         340 :         base::make_unique<FreeCallbacksTask>(this));
    1807             :   }
    1808         191 : }
    1809             : 
    1810        6930 : void CompilationStateImpl::SetError(uint32_t func_index,
    1811             :                                     const WasmError& error) {
    1812             :   DCHECK(error.has_error());
    1813             :   std::unique_ptr<CompilationError> compile_error =
    1814        6930 :       base::make_unique<CompilationError>(func_index, error);
    1815        6930 :   CompilationError* expected = nullptr;
    1816             :   bool set = compile_error_.compare_exchange_strong(
    1817        6930 :       expected, compile_error.get(), std::memory_order_acq_rel);
    1818             :   // Ignore all but the first error. If the previous value is not nullptr, just
    1819             :   // return (and free the allocated error).
    1820       13860 :   if (!set) return;
    1821             :   // If set successfully, give up ownership.
    1822             :   compile_error.release();
    1823             :   // Schedule a foreground task to call the callback and notify users about the
    1824             :   // compile error.
    1825        6815 :   foreground_task_runner_->PostTask(
    1826         101 :       MakeCancelableTask(&foreground_task_manager_, [this] {
    1827         101 :         WasmError error = GetCompileError();
    1828         101 :         NotifyOnEvent(CompilationEvent::kFailedCompilation, &error);
    1829       40991 :       }));
    1830             : }
    1831             : 
    1832       11828 : void CompilationStateImpl::NotifyOnEvent(CompilationEvent event,
    1833             :                                          const WasmError* error) {
    1834       23656 :   if (aborted_.load()) return;
    1835       11773 :   HandleScope scope(isolate_);
    1836       26477 :   for (auto& callback : callbacks_) callback(event, error);
    1837             :   // If no more events are expected after this one, clear the callbacks to free
    1838             :   // memory. We can safely do this here, as this method is only called from
    1839             :   // foreground tasks.
    1840       11773 :   if (event >= CompilationEvent::kFirstFinalEvent) callbacks_.clear();
    1841             : }
    1842             : 
    1843      156206 : void CompileJsToWasmWrappers(Isolate* isolate, const WasmModule* module,
    1844             :                              Handle<FixedArray> export_wrappers) {
    1845             :   JSToWasmWrapperCache js_to_wasm_cache;
    1846             :   int wrapper_index = 0;
    1847             : 
    1848             :   // TODO(6792): Wrappers below are allocated with {Factory::NewCode}. As an
    1849             :   // optimization we keep the code space unlocked to avoid repeated unlocking
    1850             :   // because many such wrapper are allocated in sequence below.
    1851      312414 :   CodeSpaceMemoryModificationScope modification_scope(isolate->heap());
    1852      562246 :   for (auto exp : module->export_table) {
    1853      249832 :     if (exp.kind != kExternalFunction) continue;
    1854      247022 :     auto& function = module->functions[exp.index];
    1855             :     Handle<Code> wrapper_code = js_to_wasm_cache.GetOrCompileJSToWasmWrapper(
    1856      247022 :         isolate, function.sig, function.imported);
    1857      494038 :     export_wrappers->set(wrapper_index, *wrapper_code);
    1858      247022 :     RecordStats(*wrapper_code, isolate->counters());
    1859      247022 :     ++wrapper_index;
    1860             :   }
    1861      156207 : }
    1862             : 
    1863      153227 : Handle<Script> CreateWasmScript(Isolate* isolate,
    1864             :                                 const ModuleWireBytes& wire_bytes,
    1865             :                                 const std::string& source_map_url) {
    1866             :   Handle<Script> script =
    1867      153227 :       isolate->factory()->NewScript(isolate->factory()->empty_string());
    1868      459681 :   script->set_context_data(isolate->native_context()->debug_context_id());
    1869             :   script->set_type(Script::TYPE_WASM);
    1870             : 
    1871             :   int hash = StringHasher::HashSequentialString(
    1872             :       reinterpret_cast<const char*>(wire_bytes.start()),
    1873      153227 :       static_cast<int>(wire_bytes.length()), kZeroHashSeed);
    1874             : 
    1875             :   const int kBufferSize = 32;
    1876             :   char buffer[kBufferSize];
    1877             : 
    1878      153227 :   int name_chars = SNPrintF(ArrayVector(buffer), "wasm-%08x", hash);
    1879             :   DCHECK(name_chars >= 0 && name_chars < kBufferSize);
    1880             :   MaybeHandle<String> name_str = isolate->factory()->NewStringFromOneByte(
    1881      153224 :       VectorOf(reinterpret_cast<uint8_t*>(buffer), name_chars), TENURED);
    1882      306452 :   script->set_name(*name_str.ToHandleChecked());
    1883             : 
    1884      153227 :   if (source_map_url.size() != 0) {
    1885             :     MaybeHandle<String> src_map_str = isolate->factory()->NewStringFromUtf8(
    1886           5 :         CStrVector(source_map_url.c_str()), TENURED);
    1887          10 :     script->set_source_mapping_url(*src_map_str.ToHandleChecked());
    1888             :   }
    1889      153227 :   return script;
    1890             : }
    1891             : 
    1892             : }  // namespace wasm
    1893             : }  // namespace internal
    1894      183867 : }  // namespace v8
    1895             : 
    1896             : #undef TRACE_COMPILE
    1897             : #undef TRACE_STREAMING
    1898             : #undef TRACE_LAZY

Generated by: LCOV version 1.10