11cb0ef41Sopenharmony_ci// Copyright 2017 the V8 project authors. All rights reserved. 21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 31cb0ef41Sopenharmony_ci// found in the LICENSE file. 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ci#include "src/wasm/module-compiler.h" 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ci#include <algorithm> 81cb0ef41Sopenharmony_ci#include <queue> 91cb0ef41Sopenharmony_ci 101cb0ef41Sopenharmony_ci#include "src/api/api-inl.h" 111cb0ef41Sopenharmony_ci#include "src/asmjs/asm-js.h" 121cb0ef41Sopenharmony_ci#include "src/base/enum-set.h" 131cb0ef41Sopenharmony_ci#include "src/base/optional.h" 141cb0ef41Sopenharmony_ci#include "src/base/platform/mutex.h" 151cb0ef41Sopenharmony_ci#include "src/base/platform/semaphore.h" 161cb0ef41Sopenharmony_ci#include "src/base/platform/time.h" 171cb0ef41Sopenharmony_ci#include "src/base/utils/random-number-generator.h" 181cb0ef41Sopenharmony_ci#include "src/compiler/wasm-compiler.h" 191cb0ef41Sopenharmony_ci#include "src/handles/global-handles-inl.h" 201cb0ef41Sopenharmony_ci#include "src/heap/heap-inl.h" // For CodePageCollectionMemoryModificationScope. 211cb0ef41Sopenharmony_ci#include "src/logging/counters-scopes.h" 221cb0ef41Sopenharmony_ci#include "src/logging/metrics.h" 231cb0ef41Sopenharmony_ci#include "src/objects/property-descriptor.h" 241cb0ef41Sopenharmony_ci#include "src/tasks/task-utils.h" 251cb0ef41Sopenharmony_ci#include "src/tracing/trace-event.h" 261cb0ef41Sopenharmony_ci#include "src/trap-handler/trap-handler.h" 271cb0ef41Sopenharmony_ci#include "src/utils/identity-map.h" 281cb0ef41Sopenharmony_ci#include "src/wasm/code-space-access.h" 291cb0ef41Sopenharmony_ci#include "src/wasm/module-decoder.h" 301cb0ef41Sopenharmony_ci#include "src/wasm/streaming-decoder.h" 311cb0ef41Sopenharmony_ci#include "src/wasm/wasm-code-manager.h" 321cb0ef41Sopenharmony_ci#include "src/wasm/wasm-engine.h" 331cb0ef41Sopenharmony_ci#include "src/wasm/wasm-import-wrapper-cache.h" 341cb0ef41Sopenharmony_ci#include "src/wasm/wasm-js.h" 351cb0ef41Sopenharmony_ci#include "src/wasm/wasm-limits.h" 361cb0ef41Sopenharmony_ci#include "src/wasm/wasm-objects-inl.h" 371cb0ef41Sopenharmony_ci#include "src/wasm/wasm-result.h" 381cb0ef41Sopenharmony_ci#include "src/wasm/wasm-serialization.h" 391cb0ef41Sopenharmony_ci 401cb0ef41Sopenharmony_ci#define TRACE_COMPILE(...) \ 411cb0ef41Sopenharmony_ci do { \ 421cb0ef41Sopenharmony_ci if (FLAG_trace_wasm_compiler) PrintF(__VA_ARGS__); \ 431cb0ef41Sopenharmony_ci } while (false) 441cb0ef41Sopenharmony_ci 451cb0ef41Sopenharmony_ci#define TRACE_STREAMING(...) \ 461cb0ef41Sopenharmony_ci do { \ 471cb0ef41Sopenharmony_ci if (FLAG_trace_wasm_streaming) PrintF(__VA_ARGS__); \ 481cb0ef41Sopenharmony_ci } while (false) 491cb0ef41Sopenharmony_ci 501cb0ef41Sopenharmony_ci#define TRACE_LAZY(...) \ 511cb0ef41Sopenharmony_ci do { \ 521cb0ef41Sopenharmony_ci if (FLAG_trace_wasm_lazy_compilation) PrintF(__VA_ARGS__); \ 531cb0ef41Sopenharmony_ci } while (false) 541cb0ef41Sopenharmony_ci 551cb0ef41Sopenharmony_cinamespace v8 { 561cb0ef41Sopenharmony_cinamespace internal { 571cb0ef41Sopenharmony_cinamespace wasm { 581cb0ef41Sopenharmony_ci 591cb0ef41Sopenharmony_cinamespace { 601cb0ef41Sopenharmony_ci 611cb0ef41Sopenharmony_cienum class CompileStrategy : uint8_t { 621cb0ef41Sopenharmony_ci // Compiles functions on first use. In this case, execution will block until 631cb0ef41Sopenharmony_ci // the function's baseline is reached and top tier compilation starts in 641cb0ef41Sopenharmony_ci // background (if applicable). 651cb0ef41Sopenharmony_ci // Lazy compilation can help to reduce startup time and code size at the risk 661cb0ef41Sopenharmony_ci // of blocking execution. 671cb0ef41Sopenharmony_ci kLazy, 681cb0ef41Sopenharmony_ci // Compiles baseline ahead of execution and starts top tier compilation in 691cb0ef41Sopenharmony_ci // background (if applicable). 701cb0ef41Sopenharmony_ci kEager, 711cb0ef41Sopenharmony_ci // Triggers baseline compilation on first use (just like {kLazy}) with the 721cb0ef41Sopenharmony_ci // difference that top tier compilation is started eagerly. 731cb0ef41Sopenharmony_ci // This strategy can help to reduce startup time at the risk of blocking 741cb0ef41Sopenharmony_ci // execution, but only in its early phase (until top tier compilation 751cb0ef41Sopenharmony_ci // finishes). 761cb0ef41Sopenharmony_ci kLazyBaselineEagerTopTier, 771cb0ef41Sopenharmony_ci // Marker for default strategy. 781cb0ef41Sopenharmony_ci kDefault = kEager, 791cb0ef41Sopenharmony_ci}; 801cb0ef41Sopenharmony_ci 811cb0ef41Sopenharmony_ciclass CompilationStateImpl; 821cb0ef41Sopenharmony_ciclass CompilationUnitBuilder; 831cb0ef41Sopenharmony_ci 841cb0ef41Sopenharmony_ciclass V8_NODISCARD BackgroundCompileScope { 851cb0ef41Sopenharmony_ci public: 861cb0ef41Sopenharmony_ci explicit BackgroundCompileScope(std::weak_ptr<NativeModule> native_module) 871cb0ef41Sopenharmony_ci : native_module_(native_module.lock()) {} 881cb0ef41Sopenharmony_ci 891cb0ef41Sopenharmony_ci NativeModule* native_module() const { 901cb0ef41Sopenharmony_ci DCHECK(native_module_); 911cb0ef41Sopenharmony_ci return native_module_.get(); 921cb0ef41Sopenharmony_ci } 931cb0ef41Sopenharmony_ci inline CompilationStateImpl* compilation_state() const; 941cb0ef41Sopenharmony_ci 951cb0ef41Sopenharmony_ci bool cancelled() const; 961cb0ef41Sopenharmony_ci 971cb0ef41Sopenharmony_ci private: 981cb0ef41Sopenharmony_ci // Keep the native module alive while in this scope. 991cb0ef41Sopenharmony_ci std::shared_ptr<NativeModule> native_module_; 1001cb0ef41Sopenharmony_ci}; 1011cb0ef41Sopenharmony_ci 1021cb0ef41Sopenharmony_cienum CompileBaselineOnly : bool { 1031cb0ef41Sopenharmony_ci kBaselineOnly = true, 1041cb0ef41Sopenharmony_ci kBaselineOrTopTier = false 1051cb0ef41Sopenharmony_ci}; 1061cb0ef41Sopenharmony_ci 1071cb0ef41Sopenharmony_ci// A set of work-stealing queues (vectors of units). Each background compile 1081cb0ef41Sopenharmony_ci// task owns one of the queues and steals from all others once its own queue 1091cb0ef41Sopenharmony_ci// runs empty. 1101cb0ef41Sopenharmony_ciclass CompilationUnitQueues { 1111cb0ef41Sopenharmony_ci public: 1121cb0ef41Sopenharmony_ci // Public API for QueueImpl. 1131cb0ef41Sopenharmony_ci struct Queue { 1141cb0ef41Sopenharmony_ci bool ShouldPublish(int num_processed_units) const; 1151cb0ef41Sopenharmony_ci }; 1161cb0ef41Sopenharmony_ci 1171cb0ef41Sopenharmony_ci explicit CompilationUnitQueues(int num_declared_functions) 1181cb0ef41Sopenharmony_ci : num_declared_functions_(num_declared_functions) { 1191cb0ef41Sopenharmony_ci // Add one first queue, to add units to. 1201cb0ef41Sopenharmony_ci queues_.emplace_back(std::make_unique<QueueImpl>(0)); 1211cb0ef41Sopenharmony_ci 1221cb0ef41Sopenharmony_ci for (auto& atomic_counter : num_units_) { 1231cb0ef41Sopenharmony_ci std::atomic_init(&atomic_counter, size_t{0}); 1241cb0ef41Sopenharmony_ci } 1251cb0ef41Sopenharmony_ci 1261cb0ef41Sopenharmony_ci top_tier_compiled_ = 1271cb0ef41Sopenharmony_ci std::make_unique<std::atomic<bool>[]>(num_declared_functions); 1281cb0ef41Sopenharmony_ci 1291cb0ef41Sopenharmony_ci for (int i = 0; i < num_declared_functions; i++) { 1301cb0ef41Sopenharmony_ci std::atomic_init(&top_tier_compiled_.get()[i], false); 1311cb0ef41Sopenharmony_ci } 1321cb0ef41Sopenharmony_ci } 1331cb0ef41Sopenharmony_ci 1341cb0ef41Sopenharmony_ci Queue* GetQueueForTask(int task_id) { 1351cb0ef41Sopenharmony_ci int required_queues = task_id + 1; 1361cb0ef41Sopenharmony_ci { 1371cb0ef41Sopenharmony_ci base::SharedMutexGuard<base::kShared> queues_guard(&queues_mutex_); 1381cb0ef41Sopenharmony_ci if (V8_LIKELY(static_cast<int>(queues_.size()) >= required_queues)) { 1391cb0ef41Sopenharmony_ci return queues_[task_id].get(); 1401cb0ef41Sopenharmony_ci } 1411cb0ef41Sopenharmony_ci } 1421cb0ef41Sopenharmony_ci 1431cb0ef41Sopenharmony_ci // Otherwise increase the number of queues. 1441cb0ef41Sopenharmony_ci base::SharedMutexGuard<base::kExclusive> queues_guard(&queues_mutex_); 1451cb0ef41Sopenharmony_ci int num_queues = static_cast<int>(queues_.size()); 1461cb0ef41Sopenharmony_ci while (num_queues < required_queues) { 1471cb0ef41Sopenharmony_ci int steal_from = num_queues + 1; 1481cb0ef41Sopenharmony_ci queues_.emplace_back(std::make_unique<QueueImpl>(steal_from)); 1491cb0ef41Sopenharmony_ci ++num_queues; 1501cb0ef41Sopenharmony_ci } 1511cb0ef41Sopenharmony_ci 1521cb0ef41Sopenharmony_ci // Update the {publish_limit}s of all queues. 1531cb0ef41Sopenharmony_ci 1541cb0ef41Sopenharmony_ci // We want background threads to publish regularly (to avoid contention when 1551cb0ef41Sopenharmony_ci // they are all publishing at the end). On the other side, each publishing 1561cb0ef41Sopenharmony_ci // has some overhead (part of it for synchronizing between threads), so it 1571cb0ef41Sopenharmony_ci // should not happen *too* often. Thus aim for 4-8 publishes per thread, but 1581cb0ef41Sopenharmony_ci // distribute it such that publishing is likely to happen at different 1591cb0ef41Sopenharmony_ci // times. 1601cb0ef41Sopenharmony_ci int units_per_thread = num_declared_functions_ / num_queues; 1611cb0ef41Sopenharmony_ci int min = std::max(10, units_per_thread / 8); 1621cb0ef41Sopenharmony_ci int queue_id = 0; 1631cb0ef41Sopenharmony_ci for (auto& queue : queues_) { 1641cb0ef41Sopenharmony_ci // Set a limit between {min} and {2*min}, but not smaller than {10}. 1651cb0ef41Sopenharmony_ci int limit = min + (min * queue_id / num_queues); 1661cb0ef41Sopenharmony_ci queue->publish_limit.store(limit, std::memory_order_relaxed); 1671cb0ef41Sopenharmony_ci ++queue_id; 1681cb0ef41Sopenharmony_ci } 1691cb0ef41Sopenharmony_ci 1701cb0ef41Sopenharmony_ci return queues_[task_id].get(); 1711cb0ef41Sopenharmony_ci } 1721cb0ef41Sopenharmony_ci 1731cb0ef41Sopenharmony_ci base::Optional<WasmCompilationUnit> GetNextUnit( 1741cb0ef41Sopenharmony_ci Queue* queue, CompileBaselineOnly baseline_only) { 1751cb0ef41Sopenharmony_ci // As long as any lower-tier units are outstanding we need to steal them 1761cb0ef41Sopenharmony_ci // before executing own higher-tier units. 1771cb0ef41Sopenharmony_ci int max_tier = baseline_only ? kBaseline : kTopTier; 1781cb0ef41Sopenharmony_ci for (int tier = GetLowestTierWithUnits(); tier <= max_tier; ++tier) { 1791cb0ef41Sopenharmony_ci if (auto unit = GetNextUnitOfTier(queue, tier)) { 1801cb0ef41Sopenharmony_ci size_t old_units_count = 1811cb0ef41Sopenharmony_ci num_units_[tier].fetch_sub(1, std::memory_order_relaxed); 1821cb0ef41Sopenharmony_ci DCHECK_LE(1, old_units_count); 1831cb0ef41Sopenharmony_ci USE(old_units_count); 1841cb0ef41Sopenharmony_ci return unit; 1851cb0ef41Sopenharmony_ci } 1861cb0ef41Sopenharmony_ci } 1871cb0ef41Sopenharmony_ci return {}; 1881cb0ef41Sopenharmony_ci } 1891cb0ef41Sopenharmony_ci 1901cb0ef41Sopenharmony_ci void AddUnits(base::Vector<WasmCompilationUnit> baseline_units, 1911cb0ef41Sopenharmony_ci base::Vector<WasmCompilationUnit> top_tier_units, 1921cb0ef41Sopenharmony_ci const WasmModule* module) { 1931cb0ef41Sopenharmony_ci DCHECK_LT(0, baseline_units.size() + top_tier_units.size()); 1941cb0ef41Sopenharmony_ci // Add to the individual queues in a round-robin fashion. No special care is 1951cb0ef41Sopenharmony_ci // taken to balance them; they will be balanced by work stealing. 1961cb0ef41Sopenharmony_ci QueueImpl* queue; 1971cb0ef41Sopenharmony_ci { 1981cb0ef41Sopenharmony_ci int queue_to_add = next_queue_to_add.load(std::memory_order_relaxed); 1991cb0ef41Sopenharmony_ci base::SharedMutexGuard<base::kShared> queues_guard(&queues_mutex_); 2001cb0ef41Sopenharmony_ci while (!next_queue_to_add.compare_exchange_weak( 2011cb0ef41Sopenharmony_ci queue_to_add, next_task_id(queue_to_add, queues_.size()), 2021cb0ef41Sopenharmony_ci std::memory_order_relaxed)) { 2031cb0ef41Sopenharmony_ci // Retry with updated {queue_to_add}. 2041cb0ef41Sopenharmony_ci } 2051cb0ef41Sopenharmony_ci queue = queues_[queue_to_add].get(); 2061cb0ef41Sopenharmony_ci } 2071cb0ef41Sopenharmony_ci 2081cb0ef41Sopenharmony_ci base::MutexGuard guard(&queue->mutex); 2091cb0ef41Sopenharmony_ci base::Optional<base::MutexGuard> big_units_guard; 2101cb0ef41Sopenharmony_ci for (auto pair : {std::make_pair(int{kBaseline}, baseline_units), 2111cb0ef41Sopenharmony_ci std::make_pair(int{kTopTier}, top_tier_units)}) { 2121cb0ef41Sopenharmony_ci int tier = pair.first; 2131cb0ef41Sopenharmony_ci base::Vector<WasmCompilationUnit> units = pair.second; 2141cb0ef41Sopenharmony_ci if (units.empty()) continue; 2151cb0ef41Sopenharmony_ci num_units_[tier].fetch_add(units.size(), std::memory_order_relaxed); 2161cb0ef41Sopenharmony_ci for (WasmCompilationUnit unit : units) { 2171cb0ef41Sopenharmony_ci size_t func_size = module->functions[unit.func_index()].code.length(); 2181cb0ef41Sopenharmony_ci if (func_size <= kBigUnitsLimit) { 2191cb0ef41Sopenharmony_ci queue->units[tier].push_back(unit); 2201cb0ef41Sopenharmony_ci } else { 2211cb0ef41Sopenharmony_ci if (!big_units_guard) { 2221cb0ef41Sopenharmony_ci big_units_guard.emplace(&big_units_queue_.mutex); 2231cb0ef41Sopenharmony_ci } 2241cb0ef41Sopenharmony_ci big_units_queue_.has_units[tier].store(true, 2251cb0ef41Sopenharmony_ci std::memory_order_relaxed); 2261cb0ef41Sopenharmony_ci big_units_queue_.units[tier].emplace(func_size, unit); 2271cb0ef41Sopenharmony_ci } 2281cb0ef41Sopenharmony_ci } 2291cb0ef41Sopenharmony_ci } 2301cb0ef41Sopenharmony_ci } 2311cb0ef41Sopenharmony_ci 2321cb0ef41Sopenharmony_ci void AddTopTierPriorityUnit(WasmCompilationUnit unit, size_t priority) { 2331cb0ef41Sopenharmony_ci base::SharedMutexGuard<base::kShared> queues_guard(&queues_mutex_); 2341cb0ef41Sopenharmony_ci // Add to the individual queues in a round-robin fashion. No special care is 2351cb0ef41Sopenharmony_ci // taken to balance them; they will be balanced by work stealing. We use 2361cb0ef41Sopenharmony_ci // the same counter for this reason. 2371cb0ef41Sopenharmony_ci int queue_to_add = next_queue_to_add.load(std::memory_order_relaxed); 2381cb0ef41Sopenharmony_ci while (!next_queue_to_add.compare_exchange_weak( 2391cb0ef41Sopenharmony_ci queue_to_add, next_task_id(queue_to_add, queues_.size()), 2401cb0ef41Sopenharmony_ci std::memory_order_relaxed)) { 2411cb0ef41Sopenharmony_ci // Retry with updated {queue_to_add}. 2421cb0ef41Sopenharmony_ci } 2431cb0ef41Sopenharmony_ci 2441cb0ef41Sopenharmony_ci { 2451cb0ef41Sopenharmony_ci auto* queue = queues_[queue_to_add].get(); 2461cb0ef41Sopenharmony_ci base::MutexGuard guard(&queue->mutex); 2471cb0ef41Sopenharmony_ci queue->top_tier_priority_units.emplace(priority, unit); 2481cb0ef41Sopenharmony_ci } 2491cb0ef41Sopenharmony_ci num_priority_units_.fetch_add(1, std::memory_order_relaxed); 2501cb0ef41Sopenharmony_ci num_units_[kTopTier].fetch_add(1, std::memory_order_relaxed); 2511cb0ef41Sopenharmony_ci } 2521cb0ef41Sopenharmony_ci 2531cb0ef41Sopenharmony_ci // Get the current total number of units in all queues. This is only a 2541cb0ef41Sopenharmony_ci // momentary snapshot, it's not guaranteed that {GetNextUnit} returns a unit 2551cb0ef41Sopenharmony_ci // if this method returns non-zero. 2561cb0ef41Sopenharmony_ci size_t GetTotalSize() const { 2571cb0ef41Sopenharmony_ci size_t total = 0; 2581cb0ef41Sopenharmony_ci for (auto& atomic_counter : num_units_) { 2591cb0ef41Sopenharmony_ci total += atomic_counter.load(std::memory_order_relaxed); 2601cb0ef41Sopenharmony_ci } 2611cb0ef41Sopenharmony_ci return total; 2621cb0ef41Sopenharmony_ci } 2631cb0ef41Sopenharmony_ci 2641cb0ef41Sopenharmony_ci private: 2651cb0ef41Sopenharmony_ci // Store tier in int so we can easily loop over it: 2661cb0ef41Sopenharmony_ci static constexpr int kBaseline = 0; 2671cb0ef41Sopenharmony_ci static constexpr int kTopTier = 1; 2681cb0ef41Sopenharmony_ci static constexpr int kNumTiers = kTopTier + 1; 2691cb0ef41Sopenharmony_ci 2701cb0ef41Sopenharmony_ci // Functions bigger than {kBigUnitsLimit} will be compiled first, in ascending 2711cb0ef41Sopenharmony_ci // order of their function body size. 2721cb0ef41Sopenharmony_ci static constexpr size_t kBigUnitsLimit = 4096; 2731cb0ef41Sopenharmony_ci 2741cb0ef41Sopenharmony_ci struct BigUnit { 2751cb0ef41Sopenharmony_ci BigUnit(size_t func_size, WasmCompilationUnit unit) 2761cb0ef41Sopenharmony_ci : func_size{func_size}, unit(unit) {} 2771cb0ef41Sopenharmony_ci 2781cb0ef41Sopenharmony_ci size_t func_size; 2791cb0ef41Sopenharmony_ci WasmCompilationUnit unit; 2801cb0ef41Sopenharmony_ci 2811cb0ef41Sopenharmony_ci bool operator<(const BigUnit& other) const { 2821cb0ef41Sopenharmony_ci return func_size < other.func_size; 2831cb0ef41Sopenharmony_ci } 2841cb0ef41Sopenharmony_ci }; 2851cb0ef41Sopenharmony_ci 2861cb0ef41Sopenharmony_ci struct TopTierPriorityUnit { 2871cb0ef41Sopenharmony_ci TopTierPriorityUnit(int priority, WasmCompilationUnit unit) 2881cb0ef41Sopenharmony_ci : priority(priority), unit(unit) {} 2891cb0ef41Sopenharmony_ci 2901cb0ef41Sopenharmony_ci size_t priority; 2911cb0ef41Sopenharmony_ci WasmCompilationUnit unit; 2921cb0ef41Sopenharmony_ci 2931cb0ef41Sopenharmony_ci bool operator<(const TopTierPriorityUnit& other) const { 2941cb0ef41Sopenharmony_ci return priority < other.priority; 2951cb0ef41Sopenharmony_ci } 2961cb0ef41Sopenharmony_ci }; 2971cb0ef41Sopenharmony_ci 2981cb0ef41Sopenharmony_ci struct BigUnitsQueue { 2991cb0ef41Sopenharmony_ci BigUnitsQueue() { 3001cb0ef41Sopenharmony_ci for (auto& atomic : has_units) std::atomic_init(&atomic, false); 3011cb0ef41Sopenharmony_ci } 3021cb0ef41Sopenharmony_ci 3031cb0ef41Sopenharmony_ci base::Mutex mutex; 3041cb0ef41Sopenharmony_ci 3051cb0ef41Sopenharmony_ci // Can be read concurrently to check whether any elements are in the queue. 3061cb0ef41Sopenharmony_ci std::atomic<bool> has_units[kNumTiers]; 3071cb0ef41Sopenharmony_ci 3081cb0ef41Sopenharmony_ci // Protected by {mutex}: 3091cb0ef41Sopenharmony_ci std::priority_queue<BigUnit> units[kNumTiers]; 3101cb0ef41Sopenharmony_ci }; 3111cb0ef41Sopenharmony_ci 3121cb0ef41Sopenharmony_ci struct QueueImpl : public Queue { 3131cb0ef41Sopenharmony_ci explicit QueueImpl(int next_steal_task_id) 3141cb0ef41Sopenharmony_ci : next_steal_task_id(next_steal_task_id) {} 3151cb0ef41Sopenharmony_ci 3161cb0ef41Sopenharmony_ci // Number of units after which the task processing this queue should publish 3171cb0ef41Sopenharmony_ci // compilation results. Updated (reduced, using relaxed ordering) when new 3181cb0ef41Sopenharmony_ci // queues are allocated. If there is only one thread running, we can delay 3191cb0ef41Sopenharmony_ci // publishing arbitrarily. 3201cb0ef41Sopenharmony_ci std::atomic<int> publish_limit{kMaxInt}; 3211cb0ef41Sopenharmony_ci 3221cb0ef41Sopenharmony_ci base::Mutex mutex; 3231cb0ef41Sopenharmony_ci 3241cb0ef41Sopenharmony_ci // All fields below are protected by {mutex}. 3251cb0ef41Sopenharmony_ci std::vector<WasmCompilationUnit> units[kNumTiers]; 3261cb0ef41Sopenharmony_ci std::priority_queue<TopTierPriorityUnit> top_tier_priority_units; 3271cb0ef41Sopenharmony_ci int next_steal_task_id; 3281cb0ef41Sopenharmony_ci }; 3291cb0ef41Sopenharmony_ci 3301cb0ef41Sopenharmony_ci int next_task_id(int task_id, size_t num_queues) const { 3311cb0ef41Sopenharmony_ci int next = task_id + 1; 3321cb0ef41Sopenharmony_ci return next == static_cast<int>(num_queues) ? 0 : next; 3331cb0ef41Sopenharmony_ci } 3341cb0ef41Sopenharmony_ci 3351cb0ef41Sopenharmony_ci int GetLowestTierWithUnits() const { 3361cb0ef41Sopenharmony_ci for (int tier = 0; tier < kNumTiers; ++tier) { 3371cb0ef41Sopenharmony_ci if (num_units_[tier].load(std::memory_order_relaxed) > 0) return tier; 3381cb0ef41Sopenharmony_ci } 3391cb0ef41Sopenharmony_ci return kNumTiers; 3401cb0ef41Sopenharmony_ci } 3411cb0ef41Sopenharmony_ci 3421cb0ef41Sopenharmony_ci base::Optional<WasmCompilationUnit> GetNextUnitOfTier(Queue* public_queue, 3431cb0ef41Sopenharmony_ci int tier) { 3441cb0ef41Sopenharmony_ci QueueImpl* queue = static_cast<QueueImpl*>(public_queue); 3451cb0ef41Sopenharmony_ci 3461cb0ef41Sopenharmony_ci // First check whether there is a priority unit. Execute that first. 3471cb0ef41Sopenharmony_ci if (tier == kTopTier) { 3481cb0ef41Sopenharmony_ci if (auto unit = GetTopTierPriorityUnit(queue)) { 3491cb0ef41Sopenharmony_ci return unit; 3501cb0ef41Sopenharmony_ci } 3511cb0ef41Sopenharmony_ci } 3521cb0ef41Sopenharmony_ci 3531cb0ef41Sopenharmony_ci // Then check whether there is a big unit of that tier. 3541cb0ef41Sopenharmony_ci if (auto unit = GetBigUnitOfTier(tier)) return unit; 3551cb0ef41Sopenharmony_ci 3561cb0ef41Sopenharmony_ci // Finally check whether our own queue has a unit of the wanted tier. If 3571cb0ef41Sopenharmony_ci // so, return it, otherwise get the task id to steal from. 3581cb0ef41Sopenharmony_ci int steal_task_id; 3591cb0ef41Sopenharmony_ci { 3601cb0ef41Sopenharmony_ci base::MutexGuard mutex_guard(&queue->mutex); 3611cb0ef41Sopenharmony_ci if (!queue->units[tier].empty()) { 3621cb0ef41Sopenharmony_ci auto unit = queue->units[tier].back(); 3631cb0ef41Sopenharmony_ci queue->units[tier].pop_back(); 3641cb0ef41Sopenharmony_ci return unit; 3651cb0ef41Sopenharmony_ci } 3661cb0ef41Sopenharmony_ci steal_task_id = queue->next_steal_task_id; 3671cb0ef41Sopenharmony_ci } 3681cb0ef41Sopenharmony_ci 3691cb0ef41Sopenharmony_ci // Try to steal from all other queues. If this succeeds, return one of the 3701cb0ef41Sopenharmony_ci // stolen units. 3711cb0ef41Sopenharmony_ci { 3721cb0ef41Sopenharmony_ci base::SharedMutexGuard<base::kShared> guard(&queues_mutex_); 3731cb0ef41Sopenharmony_ci for (size_t steal_trials = 0; steal_trials < queues_.size(); 3741cb0ef41Sopenharmony_ci ++steal_trials, ++steal_task_id) { 3751cb0ef41Sopenharmony_ci if (steal_task_id >= static_cast<int>(queues_.size())) { 3761cb0ef41Sopenharmony_ci steal_task_id = 0; 3771cb0ef41Sopenharmony_ci } 3781cb0ef41Sopenharmony_ci if (auto unit = StealUnitsAndGetFirst(queue, steal_task_id, tier)) { 3791cb0ef41Sopenharmony_ci return unit; 3801cb0ef41Sopenharmony_ci } 3811cb0ef41Sopenharmony_ci } 3821cb0ef41Sopenharmony_ci } 3831cb0ef41Sopenharmony_ci 3841cb0ef41Sopenharmony_ci // If we reach here, we didn't find any unit of the requested tier. 3851cb0ef41Sopenharmony_ci return {}; 3861cb0ef41Sopenharmony_ci } 3871cb0ef41Sopenharmony_ci 3881cb0ef41Sopenharmony_ci base::Optional<WasmCompilationUnit> GetBigUnitOfTier(int tier) { 3891cb0ef41Sopenharmony_ci // Fast path without locking. 3901cb0ef41Sopenharmony_ci if (!big_units_queue_.has_units[tier].load(std::memory_order_relaxed)) { 3911cb0ef41Sopenharmony_ci return {}; 3921cb0ef41Sopenharmony_ci } 3931cb0ef41Sopenharmony_ci base::MutexGuard guard(&big_units_queue_.mutex); 3941cb0ef41Sopenharmony_ci if (big_units_queue_.units[tier].empty()) return {}; 3951cb0ef41Sopenharmony_ci WasmCompilationUnit unit = big_units_queue_.units[tier].top().unit; 3961cb0ef41Sopenharmony_ci big_units_queue_.units[tier].pop(); 3971cb0ef41Sopenharmony_ci if (big_units_queue_.units[tier].empty()) { 3981cb0ef41Sopenharmony_ci big_units_queue_.has_units[tier].store(false, std::memory_order_relaxed); 3991cb0ef41Sopenharmony_ci } 4001cb0ef41Sopenharmony_ci return unit; 4011cb0ef41Sopenharmony_ci } 4021cb0ef41Sopenharmony_ci 4031cb0ef41Sopenharmony_ci base::Optional<WasmCompilationUnit> GetTopTierPriorityUnit(QueueImpl* queue) { 4041cb0ef41Sopenharmony_ci // Fast path without locking. 4051cb0ef41Sopenharmony_ci if (num_priority_units_.load(std::memory_order_relaxed) == 0) { 4061cb0ef41Sopenharmony_ci return {}; 4071cb0ef41Sopenharmony_ci } 4081cb0ef41Sopenharmony_ci 4091cb0ef41Sopenharmony_ci int steal_task_id; 4101cb0ef41Sopenharmony_ci { 4111cb0ef41Sopenharmony_ci base::MutexGuard mutex_guard(&queue->mutex); 4121cb0ef41Sopenharmony_ci while (!queue->top_tier_priority_units.empty()) { 4131cb0ef41Sopenharmony_ci auto unit = queue->top_tier_priority_units.top().unit; 4141cb0ef41Sopenharmony_ci queue->top_tier_priority_units.pop(); 4151cb0ef41Sopenharmony_ci num_priority_units_.fetch_sub(1, std::memory_order_relaxed); 4161cb0ef41Sopenharmony_ci 4171cb0ef41Sopenharmony_ci if (!top_tier_compiled_[unit.func_index()].exchange( 4181cb0ef41Sopenharmony_ci true, std::memory_order_relaxed)) { 4191cb0ef41Sopenharmony_ci return unit; 4201cb0ef41Sopenharmony_ci } 4211cb0ef41Sopenharmony_ci num_units_[kTopTier].fetch_sub(1, std::memory_order_relaxed); 4221cb0ef41Sopenharmony_ci } 4231cb0ef41Sopenharmony_ci steal_task_id = queue->next_steal_task_id; 4241cb0ef41Sopenharmony_ci } 4251cb0ef41Sopenharmony_ci 4261cb0ef41Sopenharmony_ci // Try to steal from all other queues. If this succeeds, return one of the 4271cb0ef41Sopenharmony_ci // stolen units. 4281cb0ef41Sopenharmony_ci { 4291cb0ef41Sopenharmony_ci base::SharedMutexGuard<base::kShared> guard(&queues_mutex_); 4301cb0ef41Sopenharmony_ci for (size_t steal_trials = 0; steal_trials < queues_.size(); 4311cb0ef41Sopenharmony_ci ++steal_trials, ++steal_task_id) { 4321cb0ef41Sopenharmony_ci if (steal_task_id >= static_cast<int>(queues_.size())) { 4331cb0ef41Sopenharmony_ci steal_task_id = 0; 4341cb0ef41Sopenharmony_ci } 4351cb0ef41Sopenharmony_ci if (auto unit = StealTopTierPriorityUnit(queue, steal_task_id)) { 4361cb0ef41Sopenharmony_ci return unit; 4371cb0ef41Sopenharmony_ci } 4381cb0ef41Sopenharmony_ci } 4391cb0ef41Sopenharmony_ci } 4401cb0ef41Sopenharmony_ci 4411cb0ef41Sopenharmony_ci return {}; 4421cb0ef41Sopenharmony_ci } 4431cb0ef41Sopenharmony_ci 4441cb0ef41Sopenharmony_ci // Steal units of {wanted_tier} from {steal_from_task_id} to {queue}. Return 4451cb0ef41Sopenharmony_ci // first stolen unit (rest put in queue of {task_id}), or {nullopt} if 4461cb0ef41Sopenharmony_ci // {steal_from_task_id} had no units of {wanted_tier}. 4471cb0ef41Sopenharmony_ci // Hold a shared lock on {queues_mutex_} when calling this method. 4481cb0ef41Sopenharmony_ci base::Optional<WasmCompilationUnit> StealUnitsAndGetFirst( 4491cb0ef41Sopenharmony_ci QueueImpl* queue, int steal_from_task_id, int wanted_tier) { 4501cb0ef41Sopenharmony_ci auto* steal_queue = queues_[steal_from_task_id].get(); 4511cb0ef41Sopenharmony_ci // Cannot steal from own queue. 4521cb0ef41Sopenharmony_ci if (steal_queue == queue) return {}; 4531cb0ef41Sopenharmony_ci std::vector<WasmCompilationUnit> stolen; 4541cb0ef41Sopenharmony_ci base::Optional<WasmCompilationUnit> returned_unit; 4551cb0ef41Sopenharmony_ci { 4561cb0ef41Sopenharmony_ci base::MutexGuard guard(&steal_queue->mutex); 4571cb0ef41Sopenharmony_ci auto* steal_from_vector = &steal_queue->units[wanted_tier]; 4581cb0ef41Sopenharmony_ci if (steal_from_vector->empty()) return {}; 4591cb0ef41Sopenharmony_ci size_t remaining = steal_from_vector->size() / 2; 4601cb0ef41Sopenharmony_ci auto steal_begin = steal_from_vector->begin() + remaining; 4611cb0ef41Sopenharmony_ci returned_unit = *steal_begin; 4621cb0ef41Sopenharmony_ci stolen.assign(steal_begin + 1, steal_from_vector->end()); 4631cb0ef41Sopenharmony_ci steal_from_vector->erase(steal_begin, steal_from_vector->end()); 4641cb0ef41Sopenharmony_ci } 4651cb0ef41Sopenharmony_ci base::MutexGuard guard(&queue->mutex); 4661cb0ef41Sopenharmony_ci auto* target_queue = &queue->units[wanted_tier]; 4671cb0ef41Sopenharmony_ci target_queue->insert(target_queue->end(), stolen.begin(), stolen.end()); 4681cb0ef41Sopenharmony_ci queue->next_steal_task_id = steal_from_task_id + 1; 4691cb0ef41Sopenharmony_ci return returned_unit; 4701cb0ef41Sopenharmony_ci } 4711cb0ef41Sopenharmony_ci 4721cb0ef41Sopenharmony_ci // Steal one priority unit from {steal_from_task_id} to {task_id}. Return 4731cb0ef41Sopenharmony_ci // stolen unit, or {nullopt} if {steal_from_task_id} had no priority units. 4741cb0ef41Sopenharmony_ci // Hold a shared lock on {queues_mutex_} when calling this method. 4751cb0ef41Sopenharmony_ci base::Optional<WasmCompilationUnit> StealTopTierPriorityUnit( 4761cb0ef41Sopenharmony_ci QueueImpl* queue, int steal_from_task_id) { 4771cb0ef41Sopenharmony_ci auto* steal_queue = queues_[steal_from_task_id].get(); 4781cb0ef41Sopenharmony_ci // Cannot steal from own queue. 4791cb0ef41Sopenharmony_ci if (steal_queue == queue) return {}; 4801cb0ef41Sopenharmony_ci base::Optional<WasmCompilationUnit> returned_unit; 4811cb0ef41Sopenharmony_ci { 4821cb0ef41Sopenharmony_ci base::MutexGuard guard(&steal_queue->mutex); 4831cb0ef41Sopenharmony_ci while (true) { 4841cb0ef41Sopenharmony_ci if (steal_queue->top_tier_priority_units.empty()) return {}; 4851cb0ef41Sopenharmony_ci 4861cb0ef41Sopenharmony_ci auto unit = steal_queue->top_tier_priority_units.top().unit; 4871cb0ef41Sopenharmony_ci steal_queue->top_tier_priority_units.pop(); 4881cb0ef41Sopenharmony_ci num_priority_units_.fetch_sub(1, std::memory_order_relaxed); 4891cb0ef41Sopenharmony_ci 4901cb0ef41Sopenharmony_ci if (!top_tier_compiled_[unit.func_index()].exchange( 4911cb0ef41Sopenharmony_ci true, std::memory_order_relaxed)) { 4921cb0ef41Sopenharmony_ci returned_unit = unit; 4931cb0ef41Sopenharmony_ci break; 4941cb0ef41Sopenharmony_ci } 4951cb0ef41Sopenharmony_ci num_units_[kTopTier].fetch_sub(1, std::memory_order_relaxed); 4961cb0ef41Sopenharmony_ci } 4971cb0ef41Sopenharmony_ci } 4981cb0ef41Sopenharmony_ci base::MutexGuard guard(&queue->mutex); 4991cb0ef41Sopenharmony_ci queue->next_steal_task_id = steal_from_task_id + 1; 5001cb0ef41Sopenharmony_ci return returned_unit; 5011cb0ef41Sopenharmony_ci } 5021cb0ef41Sopenharmony_ci 5031cb0ef41Sopenharmony_ci // {queues_mutex_} protectes {queues_}; 5041cb0ef41Sopenharmony_ci base::SharedMutex queues_mutex_; 5051cb0ef41Sopenharmony_ci std::vector<std::unique_ptr<QueueImpl>> queues_; 5061cb0ef41Sopenharmony_ci 5071cb0ef41Sopenharmony_ci const int num_declared_functions_; 5081cb0ef41Sopenharmony_ci 5091cb0ef41Sopenharmony_ci BigUnitsQueue big_units_queue_; 5101cb0ef41Sopenharmony_ci 5111cb0ef41Sopenharmony_ci std::atomic<size_t> num_units_[kNumTiers]; 5121cb0ef41Sopenharmony_ci std::atomic<size_t> num_priority_units_{0}; 5131cb0ef41Sopenharmony_ci std::unique_ptr<std::atomic<bool>[]> top_tier_compiled_; 5141cb0ef41Sopenharmony_ci std::atomic<int> next_queue_to_add{0}; 5151cb0ef41Sopenharmony_ci}; 5161cb0ef41Sopenharmony_ci 5171cb0ef41Sopenharmony_cibool CompilationUnitQueues::Queue::ShouldPublish( 5181cb0ef41Sopenharmony_ci int num_processed_units) const { 5191cb0ef41Sopenharmony_ci auto* queue = static_cast<const QueueImpl*>(this); 5201cb0ef41Sopenharmony_ci return num_processed_units >= 5211cb0ef41Sopenharmony_ci queue->publish_limit.load(std::memory_order_relaxed); 5221cb0ef41Sopenharmony_ci} 5231cb0ef41Sopenharmony_ci 5241cb0ef41Sopenharmony_ci// The {CompilationStateImpl} keeps track of the compilation state of the 5251cb0ef41Sopenharmony_ci// owning NativeModule, i.e. which functions are left to be compiled. 5261cb0ef41Sopenharmony_ci// It contains a task manager to allow parallel and asynchronous background 5271cb0ef41Sopenharmony_ci// compilation of functions. 5281cb0ef41Sopenharmony_ci// Its public interface {CompilationState} lives in compilation-environment.h. 5291cb0ef41Sopenharmony_ciclass CompilationStateImpl { 5301cb0ef41Sopenharmony_ci public: 5311cb0ef41Sopenharmony_ci CompilationStateImpl(const std::shared_ptr<NativeModule>& native_module, 5321cb0ef41Sopenharmony_ci std::shared_ptr<Counters> async_counters, 5331cb0ef41Sopenharmony_ci DynamicTiering dynamic_tiering); 5341cb0ef41Sopenharmony_ci ~CompilationStateImpl() { 5351cb0ef41Sopenharmony_ci if (compile_job_->IsValid()) compile_job_->CancelAndDetach(); 5361cb0ef41Sopenharmony_ci } 5371cb0ef41Sopenharmony_ci 5381cb0ef41Sopenharmony_ci // Call right after the constructor, after the {compilation_state_} field in 5391cb0ef41Sopenharmony_ci // the {NativeModule} has been initialized. 5401cb0ef41Sopenharmony_ci void InitCompileJob(); 5411cb0ef41Sopenharmony_ci 5421cb0ef41Sopenharmony_ci // {kCancelUnconditionally}: Cancel all compilation. 5431cb0ef41Sopenharmony_ci // {kCancelInitialCompilation}: Cancel all compilation if initial (baseline) 5441cb0ef41Sopenharmony_ci // compilation is not finished yet. 5451cb0ef41Sopenharmony_ci enum CancellationPolicy { kCancelUnconditionally, kCancelInitialCompilation }; 5461cb0ef41Sopenharmony_ci void CancelCompilation(CancellationPolicy); 5471cb0ef41Sopenharmony_ci 5481cb0ef41Sopenharmony_ci bool cancelled() const; 5491cb0ef41Sopenharmony_ci 5501cb0ef41Sopenharmony_ci // Initialize compilation progress. Set compilation tiers to expect for 5511cb0ef41Sopenharmony_ci // baseline and top tier compilation. Must be set before 5521cb0ef41Sopenharmony_ci // {CommitCompilationUnits} is invoked which triggers background compilation. 5531cb0ef41Sopenharmony_ci void InitializeCompilationProgress(bool lazy_module, int num_import_wrappers, 5541cb0ef41Sopenharmony_ci int num_export_wrappers); 5551cb0ef41Sopenharmony_ci 5561cb0ef41Sopenharmony_ci // Initialize the compilation progress after deserialization. This is needed 5571cb0ef41Sopenharmony_ci // for recompilation (e.g. for tier down) to work later. 5581cb0ef41Sopenharmony_ci void InitializeCompilationProgressAfterDeserialization( 5591cb0ef41Sopenharmony_ci base::Vector<const int> lazy_functions, 5601cb0ef41Sopenharmony_ci base::Vector<const int> liftoff_functions); 5611cb0ef41Sopenharmony_ci 5621cb0ef41Sopenharmony_ci // Initializes compilation units based on the information encoded in the 5631cb0ef41Sopenharmony_ci // {compilation_progress_}. 5641cb0ef41Sopenharmony_ci void InitializeCompilationUnits( 5651cb0ef41Sopenharmony_ci std::unique_ptr<CompilationUnitBuilder> builder); 5661cb0ef41Sopenharmony_ci 5671cb0ef41Sopenharmony_ci // Adds compilation units for another function to the 5681cb0ef41Sopenharmony_ci // {CompilationUnitBuilder}. This function is the streaming compilation 5691cb0ef41Sopenharmony_ci // equivalent to {InitializeCompilationUnits}. 5701cb0ef41Sopenharmony_ci void AddCompilationUnit(CompilationUnitBuilder* builder, int func_index); 5711cb0ef41Sopenharmony_ci 5721cb0ef41Sopenharmony_ci // Initialize recompilation of the whole module: Setup compilation progress 5731cb0ef41Sopenharmony_ci // for recompilation and add the respective compilation units. The callback is 5741cb0ef41Sopenharmony_ci // called immediately if no recompilation is needed, or called later 5751cb0ef41Sopenharmony_ci // otherwise. 5761cb0ef41Sopenharmony_ci void InitializeRecompilation(TieringState new_tiering_state, 5771cb0ef41Sopenharmony_ci std::unique_ptr<CompilationEventCallback> 5781cb0ef41Sopenharmony_ci recompilation_finished_callback); 5791cb0ef41Sopenharmony_ci 5801cb0ef41Sopenharmony_ci // Add the callback to be called on compilation events. Needs to be 5811cb0ef41Sopenharmony_ci // set before {CommitCompilationUnits} is run to ensure that it receives all 5821cb0ef41Sopenharmony_ci // events. The callback object must support being deleted from any thread. 5831cb0ef41Sopenharmony_ci void AddCallback(std::unique_ptr<CompilationEventCallback> callback); 5841cb0ef41Sopenharmony_ci 5851cb0ef41Sopenharmony_ci // Inserts new functions to compile and kicks off compilation. 5861cb0ef41Sopenharmony_ci void CommitCompilationUnits( 5871cb0ef41Sopenharmony_ci base::Vector<WasmCompilationUnit> baseline_units, 5881cb0ef41Sopenharmony_ci base::Vector<WasmCompilationUnit> top_tier_units, 5891cb0ef41Sopenharmony_ci base::Vector<std::shared_ptr<JSToWasmWrapperCompilationUnit>> 5901cb0ef41Sopenharmony_ci js_to_wasm_wrapper_units); 5911cb0ef41Sopenharmony_ci void CommitTopTierCompilationUnit(WasmCompilationUnit); 5921cb0ef41Sopenharmony_ci void AddTopTierPriorityCompilationUnit(WasmCompilationUnit, size_t); 5931cb0ef41Sopenharmony_ci 5941cb0ef41Sopenharmony_ci CompilationUnitQueues::Queue* GetQueueForCompileTask(int task_id); 5951cb0ef41Sopenharmony_ci 5961cb0ef41Sopenharmony_ci base::Optional<WasmCompilationUnit> GetNextCompilationUnit( 5971cb0ef41Sopenharmony_ci CompilationUnitQueues::Queue*, CompileBaselineOnly); 5981cb0ef41Sopenharmony_ci 5991cb0ef41Sopenharmony_ci std::shared_ptr<JSToWasmWrapperCompilationUnit> 6001cb0ef41Sopenharmony_ci GetNextJSToWasmWrapperCompilationUnit(); 6011cb0ef41Sopenharmony_ci void FinalizeJSToWasmWrappers(Isolate* isolate, const WasmModule* module, 6021cb0ef41Sopenharmony_ci Handle<FixedArray>* export_wrappers_out); 6031cb0ef41Sopenharmony_ci 6041cb0ef41Sopenharmony_ci void OnFinishedUnits(base::Vector<WasmCode*>); 6051cb0ef41Sopenharmony_ci void OnFinishedJSToWasmWrapperUnits(int num); 6061cb0ef41Sopenharmony_ci 6071cb0ef41Sopenharmony_ci void OnCompilationStopped(WasmFeatures detected); 6081cb0ef41Sopenharmony_ci void PublishDetectedFeatures(Isolate*); 6091cb0ef41Sopenharmony_ci void SchedulePublishCompilationResults( 6101cb0ef41Sopenharmony_ci std::vector<std::unique_ptr<WasmCode>> unpublished_code); 6111cb0ef41Sopenharmony_ci 6121cb0ef41Sopenharmony_ci size_t NumOutstandingCompilations() const; 6131cb0ef41Sopenharmony_ci 6141cb0ef41Sopenharmony_ci void SetError(); 6151cb0ef41Sopenharmony_ci 6161cb0ef41Sopenharmony_ci void WaitForCompilationEvent(CompilationEvent event); 6171cb0ef41Sopenharmony_ci 6181cb0ef41Sopenharmony_ci void SetHighPriority() { 6191cb0ef41Sopenharmony_ci // TODO(wasm): Keep a lower priority for TurboFan-only jobs. 6201cb0ef41Sopenharmony_ci compile_job_->UpdatePriority(TaskPriority::kUserBlocking); 6211cb0ef41Sopenharmony_ci } 6221cb0ef41Sopenharmony_ci 6231cb0ef41Sopenharmony_ci bool failed() const { 6241cb0ef41Sopenharmony_ci return compile_failed_.load(std::memory_order_relaxed); 6251cb0ef41Sopenharmony_ci } 6261cb0ef41Sopenharmony_ci 6271cb0ef41Sopenharmony_ci bool baseline_compilation_finished() const { 6281cb0ef41Sopenharmony_ci base::MutexGuard guard(&callbacks_mutex_); 6291cb0ef41Sopenharmony_ci return outstanding_baseline_units_ == 0 && 6301cb0ef41Sopenharmony_ci outstanding_export_wrappers_ == 0; 6311cb0ef41Sopenharmony_ci } 6321cb0ef41Sopenharmony_ci 6331cb0ef41Sopenharmony_ci bool top_tier_compilation_finished() const { 6341cb0ef41Sopenharmony_ci base::MutexGuard guard(&callbacks_mutex_); 6351cb0ef41Sopenharmony_ci return outstanding_top_tier_functions_ == 0; 6361cb0ef41Sopenharmony_ci } 6371cb0ef41Sopenharmony_ci 6381cb0ef41Sopenharmony_ci bool recompilation_finished() const { 6391cb0ef41Sopenharmony_ci base::MutexGuard guard(&callbacks_mutex_); 6401cb0ef41Sopenharmony_ci return outstanding_recompilation_functions_ == 0; 6411cb0ef41Sopenharmony_ci } 6421cb0ef41Sopenharmony_ci 6431cb0ef41Sopenharmony_ci DynamicTiering dynamic_tiering() const { return dynamic_tiering_; } 6441cb0ef41Sopenharmony_ci 6451cb0ef41Sopenharmony_ci Counters* counters() const { return async_counters_.get(); } 6461cb0ef41Sopenharmony_ci 6471cb0ef41Sopenharmony_ci void SetWireBytesStorage( 6481cb0ef41Sopenharmony_ci std::shared_ptr<WireBytesStorage> wire_bytes_storage) { 6491cb0ef41Sopenharmony_ci base::MutexGuard guard(&mutex_); 6501cb0ef41Sopenharmony_ci wire_bytes_storage_ = std::move(wire_bytes_storage); 6511cb0ef41Sopenharmony_ci } 6521cb0ef41Sopenharmony_ci 6531cb0ef41Sopenharmony_ci std::shared_ptr<WireBytesStorage> GetWireBytesStorage() const { 6541cb0ef41Sopenharmony_ci base::MutexGuard guard(&mutex_); 6551cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(wire_bytes_storage_); 6561cb0ef41Sopenharmony_ci return wire_bytes_storage_; 6571cb0ef41Sopenharmony_ci } 6581cb0ef41Sopenharmony_ci 6591cb0ef41Sopenharmony_ci void set_compilation_id(int compilation_id) { 6601cb0ef41Sopenharmony_ci DCHECK_EQ(compilation_id_, kInvalidCompilationID); 6611cb0ef41Sopenharmony_ci compilation_id_ = compilation_id; 6621cb0ef41Sopenharmony_ci } 6631cb0ef41Sopenharmony_ci 6641cb0ef41Sopenharmony_ci std::weak_ptr<NativeModule> const native_module_weak() const { 6651cb0ef41Sopenharmony_ci return native_module_weak_; 6661cb0ef41Sopenharmony_ci } 6671cb0ef41Sopenharmony_ci 6681cb0ef41Sopenharmony_ci private: 6691cb0ef41Sopenharmony_ci uint8_t SetupCompilationProgressForFunction( 6701cb0ef41Sopenharmony_ci bool lazy_function, NativeModule* module, 6711cb0ef41Sopenharmony_ci const WasmFeatures& enabled_features, int func_index); 6721cb0ef41Sopenharmony_ci 6731cb0ef41Sopenharmony_ci // Returns the potentially-updated {function_progress}. 6741cb0ef41Sopenharmony_ci uint8_t AddCompilationUnitInternal(CompilationUnitBuilder* builder, 6751cb0ef41Sopenharmony_ci int function_index, 6761cb0ef41Sopenharmony_ci uint8_t function_progress); 6771cb0ef41Sopenharmony_ci 6781cb0ef41Sopenharmony_ci // Trigger callbacks according to the internal counters below 6791cb0ef41Sopenharmony_ci // (outstanding_...), plus the given events. 6801cb0ef41Sopenharmony_ci // Hold the {callbacks_mutex_} when calling this method. 6811cb0ef41Sopenharmony_ci void TriggerCallbacks(base::EnumSet<CompilationEvent> additional_events = {}); 6821cb0ef41Sopenharmony_ci 6831cb0ef41Sopenharmony_ci void PublishCompilationResults( 6841cb0ef41Sopenharmony_ci std::vector<std::unique_ptr<WasmCode>> unpublished_code); 6851cb0ef41Sopenharmony_ci void PublishCode(base::Vector<std::unique_ptr<WasmCode>> codes); 6861cb0ef41Sopenharmony_ci 6871cb0ef41Sopenharmony_ci NativeModule* const native_module_; 6881cb0ef41Sopenharmony_ci std::weak_ptr<NativeModule> const native_module_weak_; 6891cb0ef41Sopenharmony_ci const std::shared_ptr<Counters> async_counters_; 6901cb0ef41Sopenharmony_ci 6911cb0ef41Sopenharmony_ci // Compilation error, atomically updated. This flag can be updated and read 6921cb0ef41Sopenharmony_ci // using relaxed semantics. 6931cb0ef41Sopenharmony_ci std::atomic<bool> compile_failed_{false}; 6941cb0ef41Sopenharmony_ci 6951cb0ef41Sopenharmony_ci // True if compilation was cancelled and worker threads should return. This 6961cb0ef41Sopenharmony_ci // flag can be updated and read using relaxed semantics. 6971cb0ef41Sopenharmony_ci std::atomic<bool> compile_cancelled_{false}; 6981cb0ef41Sopenharmony_ci 6991cb0ef41Sopenharmony_ci CompilationUnitQueues compilation_unit_queues_; 7001cb0ef41Sopenharmony_ci 7011cb0ef41Sopenharmony_ci // Number of wrappers to be compiled. Initialized once, counted down in 7021cb0ef41Sopenharmony_ci // {GetNextJSToWasmWrapperCompilationUnit}. 7031cb0ef41Sopenharmony_ci std::atomic<size_t> outstanding_js_to_wasm_wrappers_{0}; 7041cb0ef41Sopenharmony_ci // Wrapper compilation units are stored in shared_ptrs so that they are kept 7051cb0ef41Sopenharmony_ci // alive by the tasks even if the NativeModule dies. 7061cb0ef41Sopenharmony_ci std::vector<std::shared_ptr<JSToWasmWrapperCompilationUnit>> 7071cb0ef41Sopenharmony_ci js_to_wasm_wrapper_units_; 7081cb0ef41Sopenharmony_ci 7091cb0ef41Sopenharmony_ci // Cache the dynamic tiering configuration to be consistent for the whole 7101cb0ef41Sopenharmony_ci // compilation. 7111cb0ef41Sopenharmony_ci const DynamicTiering dynamic_tiering_; 7121cb0ef41Sopenharmony_ci 7131cb0ef41Sopenharmony_ci // This mutex protects all information of this {CompilationStateImpl} which is 7141cb0ef41Sopenharmony_ci // being accessed concurrently. 7151cb0ef41Sopenharmony_ci mutable base::Mutex mutex_; 7161cb0ef41Sopenharmony_ci 7171cb0ef41Sopenharmony_ci // The compile job handle, initialized right after construction of 7181cb0ef41Sopenharmony_ci // {CompilationStateImpl}. 7191cb0ef41Sopenharmony_ci std::unique_ptr<JobHandle> compile_job_; 7201cb0ef41Sopenharmony_ci 7211cb0ef41Sopenharmony_ci // The compilation id to identify trace events linked to this compilation. 7221cb0ef41Sopenharmony_ci static constexpr int kInvalidCompilationID = -1; 7231cb0ef41Sopenharmony_ci int compilation_id_ = kInvalidCompilationID; 7241cb0ef41Sopenharmony_ci 7251cb0ef41Sopenharmony_ci ////////////////////////////////////////////////////////////////////////////// 7261cb0ef41Sopenharmony_ci // Protected by {mutex_}: 7271cb0ef41Sopenharmony_ci 7281cb0ef41Sopenharmony_ci // Features detected to be used in this module. Features can be detected 7291cb0ef41Sopenharmony_ci // as a module is being compiled. 7301cb0ef41Sopenharmony_ci WasmFeatures detected_features_ = WasmFeatures::None(); 7311cb0ef41Sopenharmony_ci 7321cb0ef41Sopenharmony_ci // Abstraction over the storage of the wire bytes. Held in a shared_ptr so 7331cb0ef41Sopenharmony_ci // that background compilation jobs can keep the storage alive while 7341cb0ef41Sopenharmony_ci // compiling. 7351cb0ef41Sopenharmony_ci std::shared_ptr<WireBytesStorage> wire_bytes_storage_; 7361cb0ef41Sopenharmony_ci 7371cb0ef41Sopenharmony_ci // End of fields protected by {mutex_}. 7381cb0ef41Sopenharmony_ci ////////////////////////////////////////////////////////////////////////////// 7391cb0ef41Sopenharmony_ci 7401cb0ef41Sopenharmony_ci // This mutex protects the callbacks vector, and the counters used to 7411cb0ef41Sopenharmony_ci // determine which callbacks to call. The counters plus the callbacks 7421cb0ef41Sopenharmony_ci // themselves need to be synchronized to ensure correct order of events. 7431cb0ef41Sopenharmony_ci mutable base::Mutex callbacks_mutex_; 7441cb0ef41Sopenharmony_ci 7451cb0ef41Sopenharmony_ci ////////////////////////////////////////////////////////////////////////////// 7461cb0ef41Sopenharmony_ci // Protected by {callbacks_mutex_}: 7471cb0ef41Sopenharmony_ci 7481cb0ef41Sopenharmony_ci // Callbacks to be called on compilation events. 7491cb0ef41Sopenharmony_ci std::vector<std::unique_ptr<CompilationEventCallback>> callbacks_; 7501cb0ef41Sopenharmony_ci 7511cb0ef41Sopenharmony_ci // Events that already happened. 7521cb0ef41Sopenharmony_ci base::EnumSet<CompilationEvent> finished_events_; 7531cb0ef41Sopenharmony_ci 7541cb0ef41Sopenharmony_ci int outstanding_baseline_units_ = 0; 7551cb0ef41Sopenharmony_ci int outstanding_export_wrappers_ = 0; 7561cb0ef41Sopenharmony_ci int outstanding_top_tier_functions_ = 0; 7571cb0ef41Sopenharmony_ci // The amount of generated top tier code since the last 7581cb0ef41Sopenharmony_ci // {kFinishedCompilationChunk} event. 7591cb0ef41Sopenharmony_ci size_t bytes_since_last_chunk_ = 0; 7601cb0ef41Sopenharmony_ci std::vector<uint8_t> compilation_progress_; 7611cb0ef41Sopenharmony_ci 7621cb0ef41Sopenharmony_ci int outstanding_recompilation_functions_ = 0; 7631cb0ef41Sopenharmony_ci TieringState tiering_state_ = kTieredUp; 7641cb0ef41Sopenharmony_ci 7651cb0ef41Sopenharmony_ci // End of fields protected by {callbacks_mutex_}. 7661cb0ef41Sopenharmony_ci ////////////////////////////////////////////////////////////////////////////// 7671cb0ef41Sopenharmony_ci 7681cb0ef41Sopenharmony_ci // {publish_mutex_} protects {publish_queue_} and {publisher_running_}. 7691cb0ef41Sopenharmony_ci base::Mutex publish_mutex_; 7701cb0ef41Sopenharmony_ci std::vector<std::unique_ptr<WasmCode>> publish_queue_; 7711cb0ef41Sopenharmony_ci bool publisher_running_ = false; 7721cb0ef41Sopenharmony_ci 7731cb0ef41Sopenharmony_ci // Encoding of fields in the {compilation_progress_} vector. 7741cb0ef41Sopenharmony_ci using RequiredBaselineTierField = base::BitField8<ExecutionTier, 0, 2>; 7751cb0ef41Sopenharmony_ci using RequiredTopTierField = base::BitField8<ExecutionTier, 2, 2>; 7761cb0ef41Sopenharmony_ci using ReachedTierField = base::BitField8<ExecutionTier, 4, 2>; 7771cb0ef41Sopenharmony_ci using MissingRecompilationField = base::BitField8<bool, 6, 1>; 7781cb0ef41Sopenharmony_ci}; 7791cb0ef41Sopenharmony_ci 7801cb0ef41Sopenharmony_ciCompilationStateImpl* Impl(CompilationState* compilation_state) { 7811cb0ef41Sopenharmony_ci return reinterpret_cast<CompilationStateImpl*>(compilation_state); 7821cb0ef41Sopenharmony_ci} 7831cb0ef41Sopenharmony_ciconst CompilationStateImpl* Impl(const CompilationState* compilation_state) { 7841cb0ef41Sopenharmony_ci return reinterpret_cast<const CompilationStateImpl*>(compilation_state); 7851cb0ef41Sopenharmony_ci} 7861cb0ef41Sopenharmony_ci 7871cb0ef41Sopenharmony_ciCompilationStateImpl* BackgroundCompileScope::compilation_state() const { 7881cb0ef41Sopenharmony_ci DCHECK(native_module_); 7891cb0ef41Sopenharmony_ci return Impl(native_module_->compilation_state()); 7901cb0ef41Sopenharmony_ci} 7911cb0ef41Sopenharmony_ci 7921cb0ef41Sopenharmony_cibool BackgroundCompileScope::cancelled() const { 7931cb0ef41Sopenharmony_ci return native_module_ == nullptr || 7941cb0ef41Sopenharmony_ci Impl(native_module_->compilation_state())->cancelled(); 7951cb0ef41Sopenharmony_ci} 7961cb0ef41Sopenharmony_ci 7971cb0ef41Sopenharmony_civoid UpdateFeatureUseCounts(Isolate* isolate, const WasmFeatures& detected) { 7981cb0ef41Sopenharmony_ci using Feature = v8::Isolate::UseCounterFeature; 7991cb0ef41Sopenharmony_ci constexpr static std::pair<WasmFeature, Feature> kUseCounters[] = { 8001cb0ef41Sopenharmony_ci {kFeature_reftypes, Feature::kWasmRefTypes}, 8011cb0ef41Sopenharmony_ci {kFeature_simd, Feature::kWasmSimdOpcodes}, 8021cb0ef41Sopenharmony_ci {kFeature_threads, Feature::kWasmThreadOpcodes}, 8031cb0ef41Sopenharmony_ci {kFeature_eh, Feature::kWasmExceptionHandling}}; 8041cb0ef41Sopenharmony_ci 8051cb0ef41Sopenharmony_ci for (auto& feature : kUseCounters) { 8061cb0ef41Sopenharmony_ci if (detected.contains(feature.first)) isolate->CountUsage(feature.second); 8071cb0ef41Sopenharmony_ci } 8081cb0ef41Sopenharmony_ci} 8091cb0ef41Sopenharmony_ci 8101cb0ef41Sopenharmony_ci} // namespace 8111cb0ef41Sopenharmony_ci 8121cb0ef41Sopenharmony_ci////////////////////////////////////////////////////// 8131cb0ef41Sopenharmony_ci// PIMPL implementation of {CompilationState}. 8141cb0ef41Sopenharmony_ci 8151cb0ef41Sopenharmony_ciCompilationState::~CompilationState() { Impl(this)->~CompilationStateImpl(); } 8161cb0ef41Sopenharmony_ci 8171cb0ef41Sopenharmony_civoid CompilationState::InitCompileJob() { Impl(this)->InitCompileJob(); } 8181cb0ef41Sopenharmony_ci 8191cb0ef41Sopenharmony_civoid CompilationState::CancelCompilation() { 8201cb0ef41Sopenharmony_ci Impl(this)->CancelCompilation(CompilationStateImpl::kCancelUnconditionally); 8211cb0ef41Sopenharmony_ci} 8221cb0ef41Sopenharmony_ci 8231cb0ef41Sopenharmony_civoid CompilationState::CancelInitialCompilation() { 8241cb0ef41Sopenharmony_ci Impl(this)->CancelCompilation( 8251cb0ef41Sopenharmony_ci CompilationStateImpl::kCancelInitialCompilation); 8261cb0ef41Sopenharmony_ci} 8271cb0ef41Sopenharmony_ci 8281cb0ef41Sopenharmony_civoid CompilationState::SetError() { Impl(this)->SetError(); } 8291cb0ef41Sopenharmony_ci 8301cb0ef41Sopenharmony_civoid CompilationState::SetWireBytesStorage( 8311cb0ef41Sopenharmony_ci std::shared_ptr<WireBytesStorage> wire_bytes_storage) { 8321cb0ef41Sopenharmony_ci Impl(this)->SetWireBytesStorage(std::move(wire_bytes_storage)); 8331cb0ef41Sopenharmony_ci} 8341cb0ef41Sopenharmony_ci 8351cb0ef41Sopenharmony_cistd::shared_ptr<WireBytesStorage> CompilationState::GetWireBytesStorage() 8361cb0ef41Sopenharmony_ci const { 8371cb0ef41Sopenharmony_ci return Impl(this)->GetWireBytesStorage(); 8381cb0ef41Sopenharmony_ci} 8391cb0ef41Sopenharmony_ci 8401cb0ef41Sopenharmony_civoid CompilationState::AddCallback( 8411cb0ef41Sopenharmony_ci std::unique_ptr<CompilationEventCallback> callback) { 8421cb0ef41Sopenharmony_ci return Impl(this)->AddCallback(std::move(callback)); 8431cb0ef41Sopenharmony_ci} 8441cb0ef41Sopenharmony_ci 8451cb0ef41Sopenharmony_civoid CompilationState::WaitForTopTierFinished() { 8461cb0ef41Sopenharmony_ci Impl(this)->WaitForCompilationEvent( 8471cb0ef41Sopenharmony_ci CompilationEvent::kFinishedTopTierCompilation); 8481cb0ef41Sopenharmony_ci} 8491cb0ef41Sopenharmony_ci 8501cb0ef41Sopenharmony_civoid CompilationState::SetHighPriority() { Impl(this)->SetHighPriority(); } 8511cb0ef41Sopenharmony_ci 8521cb0ef41Sopenharmony_civoid CompilationState::InitializeAfterDeserialization( 8531cb0ef41Sopenharmony_ci base::Vector<const int> lazy_functions, 8541cb0ef41Sopenharmony_ci base::Vector<const int> liftoff_functions) { 8551cb0ef41Sopenharmony_ci Impl(this)->InitializeCompilationProgressAfterDeserialization( 8561cb0ef41Sopenharmony_ci lazy_functions, liftoff_functions); 8571cb0ef41Sopenharmony_ci} 8581cb0ef41Sopenharmony_ci 8591cb0ef41Sopenharmony_cibool CompilationState::failed() const { return Impl(this)->failed(); } 8601cb0ef41Sopenharmony_ci 8611cb0ef41Sopenharmony_cibool CompilationState::baseline_compilation_finished() const { 8621cb0ef41Sopenharmony_ci return Impl(this)->baseline_compilation_finished(); 8631cb0ef41Sopenharmony_ci} 8641cb0ef41Sopenharmony_ci 8651cb0ef41Sopenharmony_cibool CompilationState::top_tier_compilation_finished() const { 8661cb0ef41Sopenharmony_ci return Impl(this)->top_tier_compilation_finished(); 8671cb0ef41Sopenharmony_ci} 8681cb0ef41Sopenharmony_ci 8691cb0ef41Sopenharmony_cibool CompilationState::recompilation_finished() const { 8701cb0ef41Sopenharmony_ci return Impl(this)->recompilation_finished(); 8711cb0ef41Sopenharmony_ci} 8721cb0ef41Sopenharmony_ci 8731cb0ef41Sopenharmony_civoid CompilationState::set_compilation_id(int compilation_id) { 8741cb0ef41Sopenharmony_ci Impl(this)->set_compilation_id(compilation_id); 8751cb0ef41Sopenharmony_ci} 8761cb0ef41Sopenharmony_ci 8771cb0ef41Sopenharmony_ciDynamicTiering CompilationState::dynamic_tiering() const { 8781cb0ef41Sopenharmony_ci return Impl(this)->dynamic_tiering(); 8791cb0ef41Sopenharmony_ci} 8801cb0ef41Sopenharmony_ci 8811cb0ef41Sopenharmony_ci// static 8821cb0ef41Sopenharmony_cistd::unique_ptr<CompilationState> CompilationState::New( 8831cb0ef41Sopenharmony_ci const std::shared_ptr<NativeModule>& native_module, 8841cb0ef41Sopenharmony_ci std::shared_ptr<Counters> async_counters, DynamicTiering dynamic_tiering) { 8851cb0ef41Sopenharmony_ci return std::unique_ptr<CompilationState>(reinterpret_cast<CompilationState*>( 8861cb0ef41Sopenharmony_ci new CompilationStateImpl(std::move(native_module), 8871cb0ef41Sopenharmony_ci std::move(async_counters), dynamic_tiering))); 8881cb0ef41Sopenharmony_ci} 8891cb0ef41Sopenharmony_ci 8901cb0ef41Sopenharmony_ci// End of PIMPL implementation of {CompilationState}. 8911cb0ef41Sopenharmony_ci////////////////////////////////////////////////////// 8921cb0ef41Sopenharmony_ci 8931cb0ef41Sopenharmony_cinamespace { 8941cb0ef41Sopenharmony_ci 8951cb0ef41Sopenharmony_ciExecutionTier ApplyHintToExecutionTier(WasmCompilationHintTier hint, 8961cb0ef41Sopenharmony_ci ExecutionTier default_tier) { 8971cb0ef41Sopenharmony_ci switch (hint) { 8981cb0ef41Sopenharmony_ci case WasmCompilationHintTier::kDefault: 8991cb0ef41Sopenharmony_ci return default_tier; 9001cb0ef41Sopenharmony_ci case WasmCompilationHintTier::kBaseline: 9011cb0ef41Sopenharmony_ci return ExecutionTier::kLiftoff; 9021cb0ef41Sopenharmony_ci case WasmCompilationHintTier::kOptimized: 9031cb0ef41Sopenharmony_ci return ExecutionTier::kTurbofan; 9041cb0ef41Sopenharmony_ci } 9051cb0ef41Sopenharmony_ci UNREACHABLE(); 9061cb0ef41Sopenharmony_ci} 9071cb0ef41Sopenharmony_ci 9081cb0ef41Sopenharmony_ciconst WasmCompilationHint* GetCompilationHint(const WasmModule* module, 9091cb0ef41Sopenharmony_ci uint32_t func_index) { 9101cb0ef41Sopenharmony_ci DCHECK_LE(module->num_imported_functions, func_index); 9111cb0ef41Sopenharmony_ci uint32_t hint_index = declared_function_index(module, func_index); 9121cb0ef41Sopenharmony_ci const std::vector<WasmCompilationHint>& compilation_hints = 9131cb0ef41Sopenharmony_ci module->compilation_hints; 9141cb0ef41Sopenharmony_ci if (hint_index < compilation_hints.size()) { 9151cb0ef41Sopenharmony_ci return &compilation_hints[hint_index]; 9161cb0ef41Sopenharmony_ci } 9171cb0ef41Sopenharmony_ci return nullptr; 9181cb0ef41Sopenharmony_ci} 9191cb0ef41Sopenharmony_ci 9201cb0ef41Sopenharmony_ciCompileStrategy GetCompileStrategy(const WasmModule* module, 9211cb0ef41Sopenharmony_ci const WasmFeatures& enabled_features, 9221cb0ef41Sopenharmony_ci uint32_t func_index, bool lazy_module) { 9231cb0ef41Sopenharmony_ci if (lazy_module) return CompileStrategy::kLazy; 9241cb0ef41Sopenharmony_ci if (!enabled_features.has_compilation_hints()) { 9251cb0ef41Sopenharmony_ci return CompileStrategy::kDefault; 9261cb0ef41Sopenharmony_ci } 9271cb0ef41Sopenharmony_ci auto* hint = GetCompilationHint(module, func_index); 9281cb0ef41Sopenharmony_ci if (hint == nullptr) return CompileStrategy::kDefault; 9291cb0ef41Sopenharmony_ci switch (hint->strategy) { 9301cb0ef41Sopenharmony_ci case WasmCompilationHintStrategy::kLazy: 9311cb0ef41Sopenharmony_ci return CompileStrategy::kLazy; 9321cb0ef41Sopenharmony_ci case WasmCompilationHintStrategy::kEager: 9331cb0ef41Sopenharmony_ci return CompileStrategy::kEager; 9341cb0ef41Sopenharmony_ci case WasmCompilationHintStrategy::kLazyBaselineEagerTopTier: 9351cb0ef41Sopenharmony_ci return CompileStrategy::kLazyBaselineEagerTopTier; 9361cb0ef41Sopenharmony_ci case WasmCompilationHintStrategy::kDefault: 9371cb0ef41Sopenharmony_ci return CompileStrategy::kDefault; 9381cb0ef41Sopenharmony_ci } 9391cb0ef41Sopenharmony_ci} 9401cb0ef41Sopenharmony_ci 9411cb0ef41Sopenharmony_cistruct ExecutionTierPair { 9421cb0ef41Sopenharmony_ci ExecutionTier baseline_tier; 9431cb0ef41Sopenharmony_ci ExecutionTier top_tier; 9441cb0ef41Sopenharmony_ci}; 9451cb0ef41Sopenharmony_ci 9461cb0ef41Sopenharmony_ciExecutionTierPair GetRequestedExecutionTiers( 9471cb0ef41Sopenharmony_ci NativeModule* native_module, const WasmFeatures& enabled_features, 9481cb0ef41Sopenharmony_ci uint32_t func_index) { 9491cb0ef41Sopenharmony_ci const WasmModule* module = native_module->module(); 9501cb0ef41Sopenharmony_ci ExecutionTierPair result; 9511cb0ef41Sopenharmony_ci 9521cb0ef41Sopenharmony_ci result.baseline_tier = WasmCompilationUnit::GetBaselineExecutionTier(module); 9531cb0ef41Sopenharmony_ci 9541cb0ef41Sopenharmony_ci bool dynamic_tiering = 9551cb0ef41Sopenharmony_ci Impl(native_module->compilation_state())->dynamic_tiering() == 9561cb0ef41Sopenharmony_ci DynamicTiering::kEnabled; 9571cb0ef41Sopenharmony_ci bool tier_up_enabled = !dynamic_tiering && FLAG_wasm_tier_up; 9581cb0ef41Sopenharmony_ci if (module->origin != kWasmOrigin || !tier_up_enabled || 9591cb0ef41Sopenharmony_ci V8_UNLIKELY(FLAG_wasm_tier_up_filter >= 0 && 9601cb0ef41Sopenharmony_ci func_index != 9611cb0ef41Sopenharmony_ci static_cast<uint32_t>(FLAG_wasm_tier_up_filter))) { 9621cb0ef41Sopenharmony_ci result.top_tier = result.baseline_tier; 9631cb0ef41Sopenharmony_ci return result; 9641cb0ef41Sopenharmony_ci } 9651cb0ef41Sopenharmony_ci 9661cb0ef41Sopenharmony_ci // Default tiering behaviour. 9671cb0ef41Sopenharmony_ci result.top_tier = ExecutionTier::kTurbofan; 9681cb0ef41Sopenharmony_ci 9691cb0ef41Sopenharmony_ci // Check if compilation hints override default tiering behaviour. 9701cb0ef41Sopenharmony_ci if (enabled_features.has_compilation_hints()) { 9711cb0ef41Sopenharmony_ci const WasmCompilationHint* hint = GetCompilationHint(module, func_index); 9721cb0ef41Sopenharmony_ci if (hint != nullptr) { 9731cb0ef41Sopenharmony_ci result.baseline_tier = 9741cb0ef41Sopenharmony_ci ApplyHintToExecutionTier(hint->baseline_tier, result.baseline_tier); 9751cb0ef41Sopenharmony_ci result.top_tier = 9761cb0ef41Sopenharmony_ci ApplyHintToExecutionTier(hint->top_tier, result.top_tier); 9771cb0ef41Sopenharmony_ci } 9781cb0ef41Sopenharmony_ci } 9791cb0ef41Sopenharmony_ci 9801cb0ef41Sopenharmony_ci // Correct top tier if necessary. 9811cb0ef41Sopenharmony_ci static_assert(ExecutionTier::kLiftoff < ExecutionTier::kTurbofan, 9821cb0ef41Sopenharmony_ci "Assume an order on execution tiers"); 9831cb0ef41Sopenharmony_ci if (result.baseline_tier > result.top_tier) { 9841cb0ef41Sopenharmony_ci result.top_tier = result.baseline_tier; 9851cb0ef41Sopenharmony_ci } 9861cb0ef41Sopenharmony_ci return result; 9871cb0ef41Sopenharmony_ci} 9881cb0ef41Sopenharmony_ci 9891cb0ef41Sopenharmony_ci// The {CompilationUnitBuilder} builds compilation units and stores them in an 9901cb0ef41Sopenharmony_ci// internal buffer. The buffer is moved into the working queue of the 9911cb0ef41Sopenharmony_ci// {CompilationStateImpl} when {Commit} is called. 9921cb0ef41Sopenharmony_ciclass CompilationUnitBuilder { 9931cb0ef41Sopenharmony_ci public: 9941cb0ef41Sopenharmony_ci explicit CompilationUnitBuilder(NativeModule* native_module) 9951cb0ef41Sopenharmony_ci : native_module_(native_module) {} 9961cb0ef41Sopenharmony_ci 9971cb0ef41Sopenharmony_ci void AddUnits(uint32_t func_index) { 9981cb0ef41Sopenharmony_ci if (func_index < native_module_->module()->num_imported_functions) { 9991cb0ef41Sopenharmony_ci baseline_units_.emplace_back(func_index, ExecutionTier::kNone, 10001cb0ef41Sopenharmony_ci kNoDebugging); 10011cb0ef41Sopenharmony_ci return; 10021cb0ef41Sopenharmony_ci } 10031cb0ef41Sopenharmony_ci ExecutionTierPair tiers = GetRequestedExecutionTiers( 10041cb0ef41Sopenharmony_ci native_module_, native_module_->enabled_features(), func_index); 10051cb0ef41Sopenharmony_ci // Compile everything for non-debugging initially. If needed, we will tier 10061cb0ef41Sopenharmony_ci // down when the module is fully compiled. Synchronization would be pretty 10071cb0ef41Sopenharmony_ci // difficult otherwise. 10081cb0ef41Sopenharmony_ci baseline_units_.emplace_back(func_index, tiers.baseline_tier, kNoDebugging); 10091cb0ef41Sopenharmony_ci if (tiers.baseline_tier != tiers.top_tier) { 10101cb0ef41Sopenharmony_ci tiering_units_.emplace_back(func_index, tiers.top_tier, kNoDebugging); 10111cb0ef41Sopenharmony_ci } 10121cb0ef41Sopenharmony_ci } 10131cb0ef41Sopenharmony_ci 10141cb0ef41Sopenharmony_ci void AddJSToWasmWrapperUnit( 10151cb0ef41Sopenharmony_ci std::shared_ptr<JSToWasmWrapperCompilationUnit> unit) { 10161cb0ef41Sopenharmony_ci js_to_wasm_wrapper_units_.emplace_back(std::move(unit)); 10171cb0ef41Sopenharmony_ci } 10181cb0ef41Sopenharmony_ci 10191cb0ef41Sopenharmony_ci void AddBaselineUnit(int func_index, ExecutionTier tier) { 10201cb0ef41Sopenharmony_ci baseline_units_.emplace_back(func_index, tier, kNoDebugging); 10211cb0ef41Sopenharmony_ci } 10221cb0ef41Sopenharmony_ci 10231cb0ef41Sopenharmony_ci void AddTopTierUnit(int func_index, ExecutionTier tier) { 10241cb0ef41Sopenharmony_ci tiering_units_.emplace_back(func_index, tier, kNoDebugging); 10251cb0ef41Sopenharmony_ci } 10261cb0ef41Sopenharmony_ci 10271cb0ef41Sopenharmony_ci void AddDebugUnit(int func_index) { 10281cb0ef41Sopenharmony_ci baseline_units_.emplace_back(func_index, ExecutionTier::kLiftoff, 10291cb0ef41Sopenharmony_ci kForDebugging); 10301cb0ef41Sopenharmony_ci } 10311cb0ef41Sopenharmony_ci 10321cb0ef41Sopenharmony_ci void AddRecompilationUnit(int func_index, ExecutionTier tier) { 10331cb0ef41Sopenharmony_ci // For recompilation, just treat all units like baseline units. 10341cb0ef41Sopenharmony_ci baseline_units_.emplace_back( 10351cb0ef41Sopenharmony_ci func_index, tier, 10361cb0ef41Sopenharmony_ci tier == ExecutionTier::kLiftoff ? kForDebugging : kNoDebugging); 10371cb0ef41Sopenharmony_ci } 10381cb0ef41Sopenharmony_ci 10391cb0ef41Sopenharmony_ci bool Commit() { 10401cb0ef41Sopenharmony_ci if (baseline_units_.empty() && tiering_units_.empty() && 10411cb0ef41Sopenharmony_ci js_to_wasm_wrapper_units_.empty()) { 10421cb0ef41Sopenharmony_ci return false; 10431cb0ef41Sopenharmony_ci } 10441cb0ef41Sopenharmony_ci compilation_state()->CommitCompilationUnits( 10451cb0ef41Sopenharmony_ci base::VectorOf(baseline_units_), base::VectorOf(tiering_units_), 10461cb0ef41Sopenharmony_ci base::VectorOf(js_to_wasm_wrapper_units_)); 10471cb0ef41Sopenharmony_ci Clear(); 10481cb0ef41Sopenharmony_ci return true; 10491cb0ef41Sopenharmony_ci } 10501cb0ef41Sopenharmony_ci 10511cb0ef41Sopenharmony_ci void Clear() { 10521cb0ef41Sopenharmony_ci baseline_units_.clear(); 10531cb0ef41Sopenharmony_ci tiering_units_.clear(); 10541cb0ef41Sopenharmony_ci js_to_wasm_wrapper_units_.clear(); 10551cb0ef41Sopenharmony_ci } 10561cb0ef41Sopenharmony_ci 10571cb0ef41Sopenharmony_ci const WasmModule* module() { return native_module_->module(); } 10581cb0ef41Sopenharmony_ci 10591cb0ef41Sopenharmony_ci private: 10601cb0ef41Sopenharmony_ci CompilationStateImpl* compilation_state() const { 10611cb0ef41Sopenharmony_ci return Impl(native_module_->compilation_state()); 10621cb0ef41Sopenharmony_ci } 10631cb0ef41Sopenharmony_ci 10641cb0ef41Sopenharmony_ci NativeModule* const native_module_; 10651cb0ef41Sopenharmony_ci std::vector<WasmCompilationUnit> baseline_units_; 10661cb0ef41Sopenharmony_ci std::vector<WasmCompilationUnit> tiering_units_; 10671cb0ef41Sopenharmony_ci std::vector<std::shared_ptr<JSToWasmWrapperCompilationUnit>> 10681cb0ef41Sopenharmony_ci js_to_wasm_wrapper_units_; 10691cb0ef41Sopenharmony_ci}; 10701cb0ef41Sopenharmony_ci 10711cb0ef41Sopenharmony_civoid SetCompileError(ErrorThrower* thrower, ModuleWireBytes wire_bytes, 10721cb0ef41Sopenharmony_ci const WasmFunction* func, const WasmModule* module, 10731cb0ef41Sopenharmony_ci WasmError error) { 10741cb0ef41Sopenharmony_ci WasmName name = wire_bytes.GetNameOrNull(func, module); 10751cb0ef41Sopenharmony_ci if (name.begin() == nullptr) { 10761cb0ef41Sopenharmony_ci thrower->CompileError("Compiling function #%d failed: %s @+%u", 10771cb0ef41Sopenharmony_ci func->func_index, error.message().c_str(), 10781cb0ef41Sopenharmony_ci error.offset()); 10791cb0ef41Sopenharmony_ci } else { 10801cb0ef41Sopenharmony_ci TruncatedUserString<> truncated_name(name); 10811cb0ef41Sopenharmony_ci thrower->CompileError("Compiling function #%d:\"%.*s\" failed: %s @+%u", 10821cb0ef41Sopenharmony_ci func->func_index, truncated_name.length(), 10831cb0ef41Sopenharmony_ci truncated_name.start(), error.message().c_str(), 10841cb0ef41Sopenharmony_ci error.offset()); 10851cb0ef41Sopenharmony_ci } 10861cb0ef41Sopenharmony_ci} 10871cb0ef41Sopenharmony_ci 10881cb0ef41Sopenharmony_ciDecodeResult ValidateSingleFunction(const WasmModule* module, int func_index, 10891cb0ef41Sopenharmony_ci base::Vector<const uint8_t> code, 10901cb0ef41Sopenharmony_ci Counters* counters, 10911cb0ef41Sopenharmony_ci AccountingAllocator* allocator, 10921cb0ef41Sopenharmony_ci WasmFeatures enabled_features) { 10931cb0ef41Sopenharmony_ci const WasmFunction* func = &module->functions[func_index]; 10941cb0ef41Sopenharmony_ci FunctionBody body{func->sig, func->code.offset(), code.begin(), code.end()}; 10951cb0ef41Sopenharmony_ci DecodeResult result; 10961cb0ef41Sopenharmony_ci 10971cb0ef41Sopenharmony_ci WasmFeatures detected; 10981cb0ef41Sopenharmony_ci return VerifyWasmCode(allocator, enabled_features, module, &detected, body); 10991cb0ef41Sopenharmony_ci} 11001cb0ef41Sopenharmony_ci 11011cb0ef41Sopenharmony_cienum OnlyLazyFunctions : bool { 11021cb0ef41Sopenharmony_ci kAllFunctions = false, 11031cb0ef41Sopenharmony_ci kOnlyLazyFunctions = true, 11041cb0ef41Sopenharmony_ci}; 11051cb0ef41Sopenharmony_ci 11061cb0ef41Sopenharmony_civoid ValidateSequentially( 11071cb0ef41Sopenharmony_ci const WasmModule* module, NativeModule* native_module, Counters* counters, 11081cb0ef41Sopenharmony_ci AccountingAllocator* allocator, ErrorThrower* thrower, bool lazy_module, 11091cb0ef41Sopenharmony_ci OnlyLazyFunctions only_lazy_functions = kAllFunctions) { 11101cb0ef41Sopenharmony_ci DCHECK(!thrower->error()); 11111cb0ef41Sopenharmony_ci uint32_t start = module->num_imported_functions; 11121cb0ef41Sopenharmony_ci uint32_t end = start + module->num_declared_functions; 11131cb0ef41Sopenharmony_ci auto enabled_features = native_module->enabled_features(); 11141cb0ef41Sopenharmony_ci for (uint32_t func_index = start; func_index < end; func_index++) { 11151cb0ef41Sopenharmony_ci // Skip non-lazy functions if requested. 11161cb0ef41Sopenharmony_ci if (only_lazy_functions) { 11171cb0ef41Sopenharmony_ci CompileStrategy strategy = 11181cb0ef41Sopenharmony_ci GetCompileStrategy(module, enabled_features, func_index, lazy_module); 11191cb0ef41Sopenharmony_ci if (strategy != CompileStrategy::kLazy && 11201cb0ef41Sopenharmony_ci strategy != CompileStrategy::kLazyBaselineEagerTopTier) { 11211cb0ef41Sopenharmony_ci continue; 11221cb0ef41Sopenharmony_ci } 11231cb0ef41Sopenharmony_ci } 11241cb0ef41Sopenharmony_ci 11251cb0ef41Sopenharmony_ci ModuleWireBytes wire_bytes{native_module->wire_bytes()}; 11261cb0ef41Sopenharmony_ci const WasmFunction* func = &module->functions[func_index]; 11271cb0ef41Sopenharmony_ci base::Vector<const uint8_t> code = wire_bytes.GetFunctionBytes(func); 11281cb0ef41Sopenharmony_ci DecodeResult result = ValidateSingleFunction( 11291cb0ef41Sopenharmony_ci module, func_index, code, counters, allocator, enabled_features); 11301cb0ef41Sopenharmony_ci if (result.failed()) { 11311cb0ef41Sopenharmony_ci SetCompileError(thrower, wire_bytes, func, module, result.error()); 11321cb0ef41Sopenharmony_ci } 11331cb0ef41Sopenharmony_ci } 11341cb0ef41Sopenharmony_ci} 11351cb0ef41Sopenharmony_ci 11361cb0ef41Sopenharmony_cibool IsLazyModule(const WasmModule* module) { 11371cb0ef41Sopenharmony_ci return FLAG_wasm_lazy_compilation || 11381cb0ef41Sopenharmony_ci (FLAG_asm_wasm_lazy_compilation && is_asmjs_module(module)); 11391cb0ef41Sopenharmony_ci} 11401cb0ef41Sopenharmony_ci 11411cb0ef41Sopenharmony_ci} // namespace 11421cb0ef41Sopenharmony_ci 11431cb0ef41Sopenharmony_cibool CompileLazy(Isolate* isolate, Handle<WasmInstanceObject> instance, 11441cb0ef41Sopenharmony_ci int func_index) { 11451cb0ef41Sopenharmony_ci Handle<WasmModuleObject> module_object(instance->module_object(), isolate); 11461cb0ef41Sopenharmony_ci NativeModule* native_module = module_object->native_module(); 11471cb0ef41Sopenharmony_ci const WasmModule* module = native_module->module(); 11481cb0ef41Sopenharmony_ci auto enabled_features = native_module->enabled_features(); 11491cb0ef41Sopenharmony_ci Counters* counters = isolate->counters(); 11501cb0ef41Sopenharmony_ci 11511cb0ef41Sopenharmony_ci // Put the timer scope around everything, including the {CodeSpaceWriteScope} 11521cb0ef41Sopenharmony_ci // and its destruction, to measure complete overhead (apart from the runtime 11531cb0ef41Sopenharmony_ci // function itself, which has constant overhead). 11541cb0ef41Sopenharmony_ci base::Optional<TimedHistogramScope> lazy_compile_time_scope; 11551cb0ef41Sopenharmony_ci if (base::TimeTicks::IsHighResolution()) { 11561cb0ef41Sopenharmony_ci lazy_compile_time_scope.emplace(counters->wasm_lazy_compile_time()); 11571cb0ef41Sopenharmony_ci } 11581cb0ef41Sopenharmony_ci 11591cb0ef41Sopenharmony_ci DCHECK(!native_module->lazy_compile_frozen()); 11601cb0ef41Sopenharmony_ci 11611cb0ef41Sopenharmony_ci TRACE_LAZY("Compiling wasm-function#%d.\n", func_index); 11621cb0ef41Sopenharmony_ci 11631cb0ef41Sopenharmony_ci base::ThreadTicks thread_ticks = base::ThreadTicks::IsSupported() 11641cb0ef41Sopenharmony_ci ? base::ThreadTicks::Now() 11651cb0ef41Sopenharmony_ci : base::ThreadTicks(); 11661cb0ef41Sopenharmony_ci 11671cb0ef41Sopenharmony_ci CompilationStateImpl* compilation_state = 11681cb0ef41Sopenharmony_ci Impl(native_module->compilation_state()); 11691cb0ef41Sopenharmony_ci ExecutionTierPair tiers = 11701cb0ef41Sopenharmony_ci GetRequestedExecutionTiers(native_module, enabled_features, func_index); 11711cb0ef41Sopenharmony_ci 11721cb0ef41Sopenharmony_ci DCHECK_LE(native_module->num_imported_functions(), func_index); 11731cb0ef41Sopenharmony_ci DCHECK_LT(func_index, native_module->num_functions()); 11741cb0ef41Sopenharmony_ci WasmCompilationUnit baseline_unit{func_index, tiers.baseline_tier, 11751cb0ef41Sopenharmony_ci kNoDebugging}; 11761cb0ef41Sopenharmony_ci CompilationEnv env = native_module->CreateCompilationEnv(); 11771cb0ef41Sopenharmony_ci WasmEngine* engine = GetWasmEngine(); 11781cb0ef41Sopenharmony_ci WasmFeatures detected_features; 11791cb0ef41Sopenharmony_ci WasmCompilationResult result = baseline_unit.ExecuteCompilation( 11801cb0ef41Sopenharmony_ci &env, compilation_state->GetWireBytesStorage().get(), counters, 11811cb0ef41Sopenharmony_ci &detected_features); 11821cb0ef41Sopenharmony_ci compilation_state->OnCompilationStopped(detected_features); 11831cb0ef41Sopenharmony_ci if (!thread_ticks.IsNull()) { 11841cb0ef41Sopenharmony_ci native_module->UpdateCPUDuration( 11851cb0ef41Sopenharmony_ci (base::ThreadTicks::Now() - thread_ticks).InMicroseconds(), 11861cb0ef41Sopenharmony_ci tiers.baseline_tier); 11871cb0ef41Sopenharmony_ci } 11881cb0ef41Sopenharmony_ci 11891cb0ef41Sopenharmony_ci // During lazy compilation, we can only get compilation errors when 11901cb0ef41Sopenharmony_ci // {--wasm-lazy-validation} is enabled. Otherwise, the module was fully 11911cb0ef41Sopenharmony_ci // verified before starting its execution. 11921cb0ef41Sopenharmony_ci CHECK_IMPLIES(result.failed(), FLAG_wasm_lazy_validation); 11931cb0ef41Sopenharmony_ci const WasmFunction* func = &module->functions[func_index]; 11941cb0ef41Sopenharmony_ci if (result.failed()) { 11951cb0ef41Sopenharmony_ci ErrorThrower thrower(isolate, nullptr); 11961cb0ef41Sopenharmony_ci base::Vector<const uint8_t> code = 11971cb0ef41Sopenharmony_ci compilation_state->GetWireBytesStorage()->GetCode(func->code); 11981cb0ef41Sopenharmony_ci DecodeResult decode_result = 11991cb0ef41Sopenharmony_ci ValidateSingleFunction(module, func_index, code, counters, 12001cb0ef41Sopenharmony_ci engine->allocator(), enabled_features); 12011cb0ef41Sopenharmony_ci CHECK(decode_result.failed()); 12021cb0ef41Sopenharmony_ci SetCompileError(&thrower, ModuleWireBytes(native_module->wire_bytes()), 12031cb0ef41Sopenharmony_ci func, module, decode_result.error()); 12041cb0ef41Sopenharmony_ci return false; 12051cb0ef41Sopenharmony_ci } 12061cb0ef41Sopenharmony_ci 12071cb0ef41Sopenharmony_ci // Allocate feedback vector if needed. 12081cb0ef41Sopenharmony_ci if (result.feedback_vector_slots > 0) { 12091cb0ef41Sopenharmony_ci DCHECK(FLAG_wasm_speculative_inlining); 12101cb0ef41Sopenharmony_ci Handle<FixedArray> vector = isolate->factory()->NewFixedArrayWithZeroes( 12111cb0ef41Sopenharmony_ci result.feedback_vector_slots); 12121cb0ef41Sopenharmony_ci instance->feedback_vectors().set( 12131cb0ef41Sopenharmony_ci declared_function_index(module, func_index), *vector); 12141cb0ef41Sopenharmony_ci } 12151cb0ef41Sopenharmony_ci 12161cb0ef41Sopenharmony_ci WasmCodeRefScope code_ref_scope; 12171cb0ef41Sopenharmony_ci WasmCode* code; 12181cb0ef41Sopenharmony_ci { 12191cb0ef41Sopenharmony_ci CodeSpaceWriteScope code_space_write_scope(native_module); 12201cb0ef41Sopenharmony_ci code = native_module->PublishCode( 12211cb0ef41Sopenharmony_ci native_module->AddCompiledCode(std::move(result))); 12221cb0ef41Sopenharmony_ci } 12231cb0ef41Sopenharmony_ci DCHECK_EQ(func_index, code->index()); 12241cb0ef41Sopenharmony_ci 12251cb0ef41Sopenharmony_ci if (WasmCode::ShouldBeLogged(isolate)) { 12261cb0ef41Sopenharmony_ci DisallowGarbageCollection no_gc; 12271cb0ef41Sopenharmony_ci Object url_obj = module_object->script().name(); 12281cb0ef41Sopenharmony_ci DCHECK(url_obj.IsString() || url_obj.IsUndefined()); 12291cb0ef41Sopenharmony_ci std::unique_ptr<char[]> url = 12301cb0ef41Sopenharmony_ci url_obj.IsString() ? String::cast(url_obj).ToCString() : nullptr; 12311cb0ef41Sopenharmony_ci code->LogCode(isolate, url.get(), module_object->script().id()); 12321cb0ef41Sopenharmony_ci } 12331cb0ef41Sopenharmony_ci 12341cb0ef41Sopenharmony_ci counters->wasm_lazily_compiled_functions()->Increment(); 12351cb0ef41Sopenharmony_ci 12361cb0ef41Sopenharmony_ci const bool lazy_module = IsLazyModule(module); 12371cb0ef41Sopenharmony_ci if (GetCompileStrategy(module, enabled_features, func_index, lazy_module) == 12381cb0ef41Sopenharmony_ci CompileStrategy::kLazy && 12391cb0ef41Sopenharmony_ci tiers.baseline_tier < tiers.top_tier) { 12401cb0ef41Sopenharmony_ci WasmCompilationUnit tiering_unit{func_index, tiers.top_tier, kNoDebugging}; 12411cb0ef41Sopenharmony_ci compilation_state->CommitTopTierCompilationUnit(tiering_unit); 12421cb0ef41Sopenharmony_ci } 12431cb0ef41Sopenharmony_ci 12441cb0ef41Sopenharmony_ci return true; 12451cb0ef41Sopenharmony_ci} 12461cb0ef41Sopenharmony_ci 12471cb0ef41Sopenharmony_ciclass TransitiveTypeFeedbackProcessor { 12481cb0ef41Sopenharmony_ci public: 12491cb0ef41Sopenharmony_ci TransitiveTypeFeedbackProcessor(const WasmModule* module, 12501cb0ef41Sopenharmony_ci Handle<WasmInstanceObject> instance, 12511cb0ef41Sopenharmony_ci int func_index) 12521cb0ef41Sopenharmony_ci : instance_(instance), 12531cb0ef41Sopenharmony_ci feedback_for_function_(module->type_feedback.feedback_for_function) { 12541cb0ef41Sopenharmony_ci base::MutexGuard mutex_guard(&module->type_feedback.mutex); 12551cb0ef41Sopenharmony_ci queue_.insert(func_index); 12561cb0ef41Sopenharmony_ci while (!queue_.empty()) { 12571cb0ef41Sopenharmony_ci auto next = queue_.cbegin(); 12581cb0ef41Sopenharmony_ci Process(*next); 12591cb0ef41Sopenharmony_ci queue_.erase(next); 12601cb0ef41Sopenharmony_ci } 12611cb0ef41Sopenharmony_ci } 12621cb0ef41Sopenharmony_ci 12631cb0ef41Sopenharmony_ci private: 12641cb0ef41Sopenharmony_ci void Process(int func_index); 12651cb0ef41Sopenharmony_ci 12661cb0ef41Sopenharmony_ci void EnqueueCallees(std::vector<CallSiteFeedback> feedback) { 12671cb0ef41Sopenharmony_ci for (size_t i = 0; i < feedback.size(); i++) { 12681cb0ef41Sopenharmony_ci int func = feedback[i].function_index; 12691cb0ef41Sopenharmony_ci // TODO(jkummerow): Find a way to get the target function ID for 12701cb0ef41Sopenharmony_ci // direct calls (which currently requires decoding the function). 12711cb0ef41Sopenharmony_ci if (func == -1) continue; 12721cb0ef41Sopenharmony_ci // Don't spend time on calls that have never been executed. 12731cb0ef41Sopenharmony_ci if (feedback[i].absolute_call_frequency == 0) continue; 12741cb0ef41Sopenharmony_ci // Don't recompute feedback that has already been processed. 12751cb0ef41Sopenharmony_ci auto existing = feedback_for_function_.find(func); 12761cb0ef41Sopenharmony_ci if (existing != feedback_for_function_.end() && 12771cb0ef41Sopenharmony_ci existing->second.feedback_vector.size() > 0) { 12781cb0ef41Sopenharmony_ci continue; 12791cb0ef41Sopenharmony_ci } 12801cb0ef41Sopenharmony_ci queue_.insert(func); 12811cb0ef41Sopenharmony_ci } 12821cb0ef41Sopenharmony_ci } 12831cb0ef41Sopenharmony_ci 12841cb0ef41Sopenharmony_ci Handle<WasmInstanceObject> instance_; 12851cb0ef41Sopenharmony_ci std::map<uint32_t, FunctionTypeFeedback>& feedback_for_function_; 12861cb0ef41Sopenharmony_ci std::unordered_set<int> queue_; 12871cb0ef41Sopenharmony_ci}; 12881cb0ef41Sopenharmony_ci 12891cb0ef41Sopenharmony_civoid TransitiveTypeFeedbackProcessor::Process(int func_index) { 12901cb0ef41Sopenharmony_ci int which_vector = declared_function_index(instance_->module(), func_index); 12911cb0ef41Sopenharmony_ci Object maybe_feedback = instance_->feedback_vectors().get(which_vector); 12921cb0ef41Sopenharmony_ci if (!maybe_feedback.IsFixedArray()) return; 12931cb0ef41Sopenharmony_ci FixedArray feedback = FixedArray::cast(maybe_feedback); 12941cb0ef41Sopenharmony_ci std::vector<CallSiteFeedback> result(feedback.length() / 2); 12951cb0ef41Sopenharmony_ci int imported_functions = 12961cb0ef41Sopenharmony_ci static_cast<int>(instance_->module()->num_imported_functions); 12971cb0ef41Sopenharmony_ci for (int i = 0; i < feedback.length(); i += 2) { 12981cb0ef41Sopenharmony_ci Object value = feedback.get(i); 12991cb0ef41Sopenharmony_ci if (value.IsWasmInternalFunction() && 13001cb0ef41Sopenharmony_ci WasmExportedFunction::IsWasmExportedFunction( 13011cb0ef41Sopenharmony_ci WasmInternalFunction::cast(value).external())) { 13021cb0ef41Sopenharmony_ci // Monomorphic, and the internal function points to a wasm-generated 13031cb0ef41Sopenharmony_ci // external function (WasmExportedFunction). Mark the target for inlining 13041cb0ef41Sopenharmony_ci // if it's defined in the same module. 13051cb0ef41Sopenharmony_ci WasmExportedFunction target = WasmExportedFunction::cast( 13061cb0ef41Sopenharmony_ci WasmInternalFunction::cast(value).external()); 13071cb0ef41Sopenharmony_ci if (target.instance() == *instance_ && 13081cb0ef41Sopenharmony_ci target.function_index() >= imported_functions) { 13091cb0ef41Sopenharmony_ci if (FLAG_trace_wasm_speculative_inlining) { 13101cb0ef41Sopenharmony_ci PrintF("[Function #%d call_ref #%d inlineable (monomorphic)]\n", 13111cb0ef41Sopenharmony_ci func_index, i / 2); 13121cb0ef41Sopenharmony_ci } 13131cb0ef41Sopenharmony_ci int32_t count = Smi::cast(feedback.get(i + 1)).value(); 13141cb0ef41Sopenharmony_ci result[i / 2] = {target.function_index(), count}; 13151cb0ef41Sopenharmony_ci continue; 13161cb0ef41Sopenharmony_ci } 13171cb0ef41Sopenharmony_ci } else if (value.IsFixedArray()) { 13181cb0ef41Sopenharmony_ci // Polymorphic. Pick a target for inlining if there is one that was 13191cb0ef41Sopenharmony_ci // seen for most calls, and matches the requirements of the monomorphic 13201cb0ef41Sopenharmony_ci // case. 13211cb0ef41Sopenharmony_ci FixedArray polymorphic = FixedArray::cast(value); 13221cb0ef41Sopenharmony_ci size_t total_count = 0; 13231cb0ef41Sopenharmony_ci for (int j = 0; j < polymorphic.length(); j += 2) { 13241cb0ef41Sopenharmony_ci total_count += Smi::cast(polymorphic.get(j + 1)).value(); 13251cb0ef41Sopenharmony_ci } 13261cb0ef41Sopenharmony_ci int found_target = -1; 13271cb0ef41Sopenharmony_ci int found_count = -1; 13281cb0ef41Sopenharmony_ci double best_frequency = 0; 13291cb0ef41Sopenharmony_ci for (int j = 0; j < polymorphic.length(); j += 2) { 13301cb0ef41Sopenharmony_ci int32_t this_count = Smi::cast(polymorphic.get(j + 1)).value(); 13311cb0ef41Sopenharmony_ci double frequency = static_cast<double>(this_count) / total_count; 13321cb0ef41Sopenharmony_ci if (frequency > best_frequency) best_frequency = frequency; 13331cb0ef41Sopenharmony_ci if (frequency < 0.8) continue; 13341cb0ef41Sopenharmony_ci 13351cb0ef41Sopenharmony_ci // We reject this polymorphic entry if: 13361cb0ef41Sopenharmony_ci // - it is not defined, 13371cb0ef41Sopenharmony_ci // - it is not a wasm-defined function (WasmExportedFunction) 13381cb0ef41Sopenharmony_ci // - it was not defined in this module. 13391cb0ef41Sopenharmony_ci if (!polymorphic.get(j).IsWasmInternalFunction()) continue; 13401cb0ef41Sopenharmony_ci WasmInternalFunction internal = 13411cb0ef41Sopenharmony_ci WasmInternalFunction::cast(polymorphic.get(j)); 13421cb0ef41Sopenharmony_ci if (!WasmExportedFunction::IsWasmExportedFunction( 13431cb0ef41Sopenharmony_ci internal.external())) { 13441cb0ef41Sopenharmony_ci continue; 13451cb0ef41Sopenharmony_ci } 13461cb0ef41Sopenharmony_ci WasmExportedFunction target = 13471cb0ef41Sopenharmony_ci WasmExportedFunction::cast(internal.external()); 13481cb0ef41Sopenharmony_ci if (target.instance() != *instance_ || 13491cb0ef41Sopenharmony_ci target.function_index() < imported_functions) { 13501cb0ef41Sopenharmony_ci continue; 13511cb0ef41Sopenharmony_ci } 13521cb0ef41Sopenharmony_ci 13531cb0ef41Sopenharmony_ci found_target = target.function_index(); 13541cb0ef41Sopenharmony_ci found_count = static_cast<int>(this_count); 13551cb0ef41Sopenharmony_ci if (FLAG_trace_wasm_speculative_inlining) { 13561cb0ef41Sopenharmony_ci PrintF("[Function #%d call_ref #%d inlineable (polymorphic %f)]\n", 13571cb0ef41Sopenharmony_ci func_index, i / 2, frequency); 13581cb0ef41Sopenharmony_ci } 13591cb0ef41Sopenharmony_ci break; 13601cb0ef41Sopenharmony_ci } 13611cb0ef41Sopenharmony_ci if (found_target >= 0) { 13621cb0ef41Sopenharmony_ci result[i / 2] = {found_target, found_count}; 13631cb0ef41Sopenharmony_ci continue; 13641cb0ef41Sopenharmony_ci } else if (FLAG_trace_wasm_speculative_inlining) { 13651cb0ef41Sopenharmony_ci PrintF("[Function #%d call_ref #%d: best frequency %f]\n", func_index, 13661cb0ef41Sopenharmony_ci i / 2, best_frequency); 13671cb0ef41Sopenharmony_ci } 13681cb0ef41Sopenharmony_ci } else if (value.IsSmi()) { 13691cb0ef41Sopenharmony_ci // Direct call, just collecting call count. 13701cb0ef41Sopenharmony_ci int count = Smi::cast(value).value(); 13711cb0ef41Sopenharmony_ci if (FLAG_trace_wasm_speculative_inlining) { 13721cb0ef41Sopenharmony_ci PrintF("[Function #%d call_direct #%d: frequency %d]\n", func_index, 13731cb0ef41Sopenharmony_ci i / 2, count); 13741cb0ef41Sopenharmony_ci } 13751cb0ef41Sopenharmony_ci result[i / 2] = {-1, count}; 13761cb0ef41Sopenharmony_ci continue; 13771cb0ef41Sopenharmony_ci } 13781cb0ef41Sopenharmony_ci // If we fall through to here, then this call isn't eligible for inlining. 13791cb0ef41Sopenharmony_ci // Possible reasons: uninitialized or megamorphic feedback; or monomorphic 13801cb0ef41Sopenharmony_ci // or polymorphic that didn't meet our requirements. 13811cb0ef41Sopenharmony_ci if (FLAG_trace_wasm_speculative_inlining) { 13821cb0ef41Sopenharmony_ci PrintF("[Function #%d call_ref #%d *not* inlineable]\n", func_index, 13831cb0ef41Sopenharmony_ci i / 2); 13841cb0ef41Sopenharmony_ci } 13851cb0ef41Sopenharmony_ci result[i / 2] = {-1, -1}; 13861cb0ef41Sopenharmony_ci } 13871cb0ef41Sopenharmony_ci EnqueueCallees(result); 13881cb0ef41Sopenharmony_ci feedback_for_function_[func_index].feedback_vector = std::move(result); 13891cb0ef41Sopenharmony_ci} 13901cb0ef41Sopenharmony_ci 13911cb0ef41Sopenharmony_civoid TriggerTierUp(Isolate* isolate, NativeModule* native_module, 13921cb0ef41Sopenharmony_ci int func_index, Handle<WasmInstanceObject> instance) { 13931cb0ef41Sopenharmony_ci CompilationStateImpl* compilation_state = 13941cb0ef41Sopenharmony_ci Impl(native_module->compilation_state()); 13951cb0ef41Sopenharmony_ci WasmCompilationUnit tiering_unit{func_index, ExecutionTier::kTurbofan, 13961cb0ef41Sopenharmony_ci kNoDebugging}; 13971cb0ef41Sopenharmony_ci 13981cb0ef41Sopenharmony_ci const WasmModule* module = native_module->module(); 13991cb0ef41Sopenharmony_ci size_t priority; 14001cb0ef41Sopenharmony_ci { 14011cb0ef41Sopenharmony_ci base::MutexGuard mutex_guard(&module->type_feedback.mutex); 14021cb0ef41Sopenharmony_ci int saved_priority = 14031cb0ef41Sopenharmony_ci module->type_feedback.feedback_for_function[func_index].tierup_priority; 14041cb0ef41Sopenharmony_ci saved_priority++; 14051cb0ef41Sopenharmony_ci module->type_feedback.feedback_for_function[func_index].tierup_priority = 14061cb0ef41Sopenharmony_ci saved_priority; 14071cb0ef41Sopenharmony_ci // Continue to creating a compilation unit if this is the first time 14081cb0ef41Sopenharmony_ci // we detect this function as hot, and create a new higher-priority unit 14091cb0ef41Sopenharmony_ci // if the number of tierup checks is a power of two (at least 4). 14101cb0ef41Sopenharmony_ci if (saved_priority > 1 && 14111cb0ef41Sopenharmony_ci (saved_priority < 4 || (saved_priority & (saved_priority - 1)) != 0)) { 14121cb0ef41Sopenharmony_ci return; 14131cb0ef41Sopenharmony_ci } 14141cb0ef41Sopenharmony_ci priority = saved_priority; 14151cb0ef41Sopenharmony_ci } 14161cb0ef41Sopenharmony_ci if (FLAG_wasm_speculative_inlining) { 14171cb0ef41Sopenharmony_ci // TODO(jkummerow): we could have collisions here if different instances 14181cb0ef41Sopenharmony_ci // of the same module have collected different feedback. If that ever 14191cb0ef41Sopenharmony_ci // becomes a problem, figure out a solution. 14201cb0ef41Sopenharmony_ci TransitiveTypeFeedbackProcessor process(module, instance, func_index); 14211cb0ef41Sopenharmony_ci } 14221cb0ef41Sopenharmony_ci 14231cb0ef41Sopenharmony_ci compilation_state->AddTopTierPriorityCompilationUnit(tiering_unit, priority); 14241cb0ef41Sopenharmony_ci} 14251cb0ef41Sopenharmony_ci 14261cb0ef41Sopenharmony_cinamespace { 14271cb0ef41Sopenharmony_ci 14281cb0ef41Sopenharmony_civoid RecordStats(const Code code, Counters* counters) { 14291cb0ef41Sopenharmony_ci counters->wasm_generated_code_size()->Increment(code.raw_body_size()); 14301cb0ef41Sopenharmony_ci counters->wasm_reloc_size()->Increment(code.relocation_info().length()); 14311cb0ef41Sopenharmony_ci} 14321cb0ef41Sopenharmony_ci 14331cb0ef41Sopenharmony_cienum CompilationExecutionResult : int8_t { kNoMoreUnits, kYield }; 14341cb0ef41Sopenharmony_ci 14351cb0ef41Sopenharmony_ciCompilationExecutionResult ExecuteJSToWasmWrapperCompilationUnits( 14361cb0ef41Sopenharmony_ci std::weak_ptr<NativeModule> native_module, JobDelegate* delegate) { 14371cb0ef41Sopenharmony_ci std::shared_ptr<JSToWasmWrapperCompilationUnit> wrapper_unit = nullptr; 14381cb0ef41Sopenharmony_ci int num_processed_wrappers = 0; 14391cb0ef41Sopenharmony_ci 14401cb0ef41Sopenharmony_ci OperationsBarrier::Token wrapper_compilation_token; 14411cb0ef41Sopenharmony_ci Isolate* isolate; 14421cb0ef41Sopenharmony_ci 14431cb0ef41Sopenharmony_ci { 14441cb0ef41Sopenharmony_ci BackgroundCompileScope compile_scope(native_module); 14451cb0ef41Sopenharmony_ci if (compile_scope.cancelled()) return kYield; 14461cb0ef41Sopenharmony_ci wrapper_unit = compile_scope.compilation_state() 14471cb0ef41Sopenharmony_ci ->GetNextJSToWasmWrapperCompilationUnit(); 14481cb0ef41Sopenharmony_ci if (!wrapper_unit) return kNoMoreUnits; 14491cb0ef41Sopenharmony_ci isolate = wrapper_unit->isolate(); 14501cb0ef41Sopenharmony_ci wrapper_compilation_token = 14511cb0ef41Sopenharmony_ci wasm::GetWasmEngine()->StartWrapperCompilation(isolate); 14521cb0ef41Sopenharmony_ci if (!wrapper_compilation_token) return kNoMoreUnits; 14531cb0ef41Sopenharmony_ci } 14541cb0ef41Sopenharmony_ci 14551cb0ef41Sopenharmony_ci TRACE_EVENT0("v8.wasm", "wasm.JSToWasmWrapperCompilation"); 14561cb0ef41Sopenharmony_ci while (true) { 14571cb0ef41Sopenharmony_ci DCHECK_EQ(isolate, wrapper_unit->isolate()); 14581cb0ef41Sopenharmony_ci wrapper_unit->Execute(); 14591cb0ef41Sopenharmony_ci ++num_processed_wrappers; 14601cb0ef41Sopenharmony_ci bool yield = delegate && delegate->ShouldYield(); 14611cb0ef41Sopenharmony_ci BackgroundCompileScope compile_scope(native_module); 14621cb0ef41Sopenharmony_ci if (compile_scope.cancelled()) return kYield; 14631cb0ef41Sopenharmony_ci if (yield || 14641cb0ef41Sopenharmony_ci !(wrapper_unit = compile_scope.compilation_state() 14651cb0ef41Sopenharmony_ci ->GetNextJSToWasmWrapperCompilationUnit())) { 14661cb0ef41Sopenharmony_ci compile_scope.compilation_state()->OnFinishedJSToWasmWrapperUnits( 14671cb0ef41Sopenharmony_ci num_processed_wrappers); 14681cb0ef41Sopenharmony_ci return yield ? kYield : kNoMoreUnits; 14691cb0ef41Sopenharmony_ci } 14701cb0ef41Sopenharmony_ci } 14711cb0ef41Sopenharmony_ci} 14721cb0ef41Sopenharmony_ci 14731cb0ef41Sopenharmony_cinamespace { 14741cb0ef41Sopenharmony_ciconst char* GetCompilationEventName(const WasmCompilationUnit& unit, 14751cb0ef41Sopenharmony_ci const CompilationEnv& env) { 14761cb0ef41Sopenharmony_ci ExecutionTier tier = unit.tier(); 14771cb0ef41Sopenharmony_ci if (tier == ExecutionTier::kLiftoff) { 14781cb0ef41Sopenharmony_ci return "wasm.BaselineCompilation"; 14791cb0ef41Sopenharmony_ci } 14801cb0ef41Sopenharmony_ci if (tier == ExecutionTier::kTurbofan) { 14811cb0ef41Sopenharmony_ci return "wasm.TopTierCompilation"; 14821cb0ef41Sopenharmony_ci } 14831cb0ef41Sopenharmony_ci if (unit.func_index() < 14841cb0ef41Sopenharmony_ci static_cast<int>(env.module->num_imported_functions)) { 14851cb0ef41Sopenharmony_ci return "wasm.WasmToJSWrapperCompilation"; 14861cb0ef41Sopenharmony_ci } 14871cb0ef41Sopenharmony_ci return "wasm.OtherCompilation"; 14881cb0ef41Sopenharmony_ci} 14891cb0ef41Sopenharmony_ci} // namespace 14901cb0ef41Sopenharmony_ci 14911cb0ef41Sopenharmony_ciconstexpr uint8_t kMainTaskId = 0; 14921cb0ef41Sopenharmony_ci 14931cb0ef41Sopenharmony_ci// Run by the {BackgroundCompileJob} (on any thread). 14941cb0ef41Sopenharmony_ciCompilationExecutionResult ExecuteCompilationUnits( 14951cb0ef41Sopenharmony_ci std::weak_ptr<NativeModule> native_module, Counters* counters, 14961cb0ef41Sopenharmony_ci JobDelegate* delegate, CompileBaselineOnly baseline_only) { 14971cb0ef41Sopenharmony_ci TRACE_EVENT0("v8.wasm", "wasm.ExecuteCompilationUnits"); 14981cb0ef41Sopenharmony_ci 14991cb0ef41Sopenharmony_ci // Execute JS to Wasm wrapper units first, so that they are ready to be 15001cb0ef41Sopenharmony_ci // finalized by the main thread when the kFinishedBaselineCompilation event is 15011cb0ef41Sopenharmony_ci // triggered. 15021cb0ef41Sopenharmony_ci if (ExecuteJSToWasmWrapperCompilationUnits(native_module, delegate) == 15031cb0ef41Sopenharmony_ci kYield) { 15041cb0ef41Sopenharmony_ci return kYield; 15051cb0ef41Sopenharmony_ci } 15061cb0ef41Sopenharmony_ci 15071cb0ef41Sopenharmony_ci // These fields are initialized in a {BackgroundCompileScope} before 15081cb0ef41Sopenharmony_ci // starting compilation. 15091cb0ef41Sopenharmony_ci base::Optional<CompilationEnv> env; 15101cb0ef41Sopenharmony_ci std::shared_ptr<WireBytesStorage> wire_bytes; 15111cb0ef41Sopenharmony_ci std::shared_ptr<const WasmModule> module; 15121cb0ef41Sopenharmony_ci // Task 0 is any main thread (there might be multiple from multiple isolates), 15131cb0ef41Sopenharmony_ci // worker threads start at 1 (thus the "+ 1"). 15141cb0ef41Sopenharmony_ci STATIC_ASSERT(kMainTaskId == 0); 15151cb0ef41Sopenharmony_ci int task_id = delegate ? (int{delegate->GetTaskId()} + 1) : kMainTaskId; 15161cb0ef41Sopenharmony_ci DCHECK_LE(0, task_id); 15171cb0ef41Sopenharmony_ci CompilationUnitQueues::Queue* queue; 15181cb0ef41Sopenharmony_ci base::Optional<WasmCompilationUnit> unit; 15191cb0ef41Sopenharmony_ci 15201cb0ef41Sopenharmony_ci WasmFeatures detected_features = WasmFeatures::None(); 15211cb0ef41Sopenharmony_ci 15221cb0ef41Sopenharmony_ci base::ThreadTicks thread_ticks = base::ThreadTicks::IsSupported() 15231cb0ef41Sopenharmony_ci ? base::ThreadTicks::Now() 15241cb0ef41Sopenharmony_ci : base::ThreadTicks(); 15251cb0ef41Sopenharmony_ci 15261cb0ef41Sopenharmony_ci // Preparation (synchronized): Initialize the fields above and get the first 15271cb0ef41Sopenharmony_ci // compilation unit. 15281cb0ef41Sopenharmony_ci { 15291cb0ef41Sopenharmony_ci BackgroundCompileScope compile_scope(native_module); 15301cb0ef41Sopenharmony_ci if (compile_scope.cancelled()) return kYield; 15311cb0ef41Sopenharmony_ci env.emplace(compile_scope.native_module()->CreateCompilationEnv()); 15321cb0ef41Sopenharmony_ci wire_bytes = compile_scope.compilation_state()->GetWireBytesStorage(); 15331cb0ef41Sopenharmony_ci module = compile_scope.native_module()->shared_module(); 15341cb0ef41Sopenharmony_ci queue = compile_scope.compilation_state()->GetQueueForCompileTask(task_id); 15351cb0ef41Sopenharmony_ci unit = compile_scope.compilation_state()->GetNextCompilationUnit( 15361cb0ef41Sopenharmony_ci queue, baseline_only); 15371cb0ef41Sopenharmony_ci if (!unit) return kNoMoreUnits; 15381cb0ef41Sopenharmony_ci } 15391cb0ef41Sopenharmony_ci TRACE_COMPILE("ExecuteCompilationUnits (task id %d)\n", task_id); 15401cb0ef41Sopenharmony_ci 15411cb0ef41Sopenharmony_ci std::vector<WasmCompilationResult> results_to_publish; 15421cb0ef41Sopenharmony_ci while (true) { 15431cb0ef41Sopenharmony_ci ExecutionTier current_tier = unit->tier(); 15441cb0ef41Sopenharmony_ci const char* event_name = GetCompilationEventName(unit.value(), env.value()); 15451cb0ef41Sopenharmony_ci TRACE_EVENT0("v8.wasm", event_name); 15461cb0ef41Sopenharmony_ci while (unit->tier() == current_tier) { 15471cb0ef41Sopenharmony_ci // (asynchronous): Execute the compilation. 15481cb0ef41Sopenharmony_ci WasmCompilationResult result = unit->ExecuteCompilation( 15491cb0ef41Sopenharmony_ci &env.value(), wire_bytes.get(), counters, &detected_features); 15501cb0ef41Sopenharmony_ci results_to_publish.emplace_back(std::move(result)); 15511cb0ef41Sopenharmony_ci 15521cb0ef41Sopenharmony_ci bool yield = delegate && delegate->ShouldYield(); 15531cb0ef41Sopenharmony_ci 15541cb0ef41Sopenharmony_ci // (synchronized): Publish the compilation result and get the next unit. 15551cb0ef41Sopenharmony_ci BackgroundCompileScope compile_scope(native_module); 15561cb0ef41Sopenharmony_ci if (compile_scope.cancelled()) return kYield; 15571cb0ef41Sopenharmony_ci 15581cb0ef41Sopenharmony_ci if (!results_to_publish.back().succeeded()) { 15591cb0ef41Sopenharmony_ci compile_scope.compilation_state()->SetError(); 15601cb0ef41Sopenharmony_ci return kNoMoreUnits; 15611cb0ef41Sopenharmony_ci } 15621cb0ef41Sopenharmony_ci 15631cb0ef41Sopenharmony_ci if (!unit->for_debugging() && result.result_tier != current_tier) { 15641cb0ef41Sopenharmony_ci compile_scope.native_module()->AddLiftoffBailout(); 15651cb0ef41Sopenharmony_ci } 15661cb0ef41Sopenharmony_ci 15671cb0ef41Sopenharmony_ci // Yield or get next unit. 15681cb0ef41Sopenharmony_ci if (yield || 15691cb0ef41Sopenharmony_ci !(unit = compile_scope.compilation_state()->GetNextCompilationUnit( 15701cb0ef41Sopenharmony_ci queue, baseline_only))) { 15711cb0ef41Sopenharmony_ci if (!thread_ticks.IsNull()) { 15721cb0ef41Sopenharmony_ci compile_scope.native_module()->UpdateCPUDuration( 15731cb0ef41Sopenharmony_ci (base::ThreadTicks::Now() - thread_ticks).InMicroseconds(), 15741cb0ef41Sopenharmony_ci current_tier); 15751cb0ef41Sopenharmony_ci } 15761cb0ef41Sopenharmony_ci std::vector<std::unique_ptr<WasmCode>> unpublished_code = 15771cb0ef41Sopenharmony_ci compile_scope.native_module()->AddCompiledCode( 15781cb0ef41Sopenharmony_ci base::VectorOf(std::move(results_to_publish))); 15791cb0ef41Sopenharmony_ci results_to_publish.clear(); 15801cb0ef41Sopenharmony_ci compile_scope.compilation_state()->SchedulePublishCompilationResults( 15811cb0ef41Sopenharmony_ci std::move(unpublished_code)); 15821cb0ef41Sopenharmony_ci compile_scope.compilation_state()->OnCompilationStopped( 15831cb0ef41Sopenharmony_ci detected_features); 15841cb0ef41Sopenharmony_ci return yield ? kYield : kNoMoreUnits; 15851cb0ef41Sopenharmony_ci } 15861cb0ef41Sopenharmony_ci 15871cb0ef41Sopenharmony_ci // Publish after finishing a certain amount of units, to avoid contention 15881cb0ef41Sopenharmony_ci // when all threads publish at the end. 15891cb0ef41Sopenharmony_ci bool batch_full = 15901cb0ef41Sopenharmony_ci queue->ShouldPublish(static_cast<int>(results_to_publish.size())); 15911cb0ef41Sopenharmony_ci // Also publish each time the compilation tier changes from Liftoff to 15921cb0ef41Sopenharmony_ci // TurboFan, such that we immediately publish the baseline compilation 15931cb0ef41Sopenharmony_ci // results to start execution, and do not wait for a batch to fill up. 15941cb0ef41Sopenharmony_ci bool liftoff_finished = unit->tier() != current_tier && 15951cb0ef41Sopenharmony_ci unit->tier() == ExecutionTier::kTurbofan; 15961cb0ef41Sopenharmony_ci if (batch_full || liftoff_finished) { 15971cb0ef41Sopenharmony_ci if (!thread_ticks.IsNull()) { 15981cb0ef41Sopenharmony_ci base::ThreadTicks thread_ticks_now = base::ThreadTicks::Now(); 15991cb0ef41Sopenharmony_ci compile_scope.native_module()->UpdateCPUDuration( 16001cb0ef41Sopenharmony_ci (thread_ticks_now - thread_ticks).InMicroseconds(), current_tier); 16011cb0ef41Sopenharmony_ci thread_ticks = thread_ticks_now; 16021cb0ef41Sopenharmony_ci } 16031cb0ef41Sopenharmony_ci std::vector<std::unique_ptr<WasmCode>> unpublished_code = 16041cb0ef41Sopenharmony_ci compile_scope.native_module()->AddCompiledCode( 16051cb0ef41Sopenharmony_ci base::VectorOf(std::move(results_to_publish))); 16061cb0ef41Sopenharmony_ci results_to_publish.clear(); 16071cb0ef41Sopenharmony_ci compile_scope.compilation_state()->SchedulePublishCompilationResults( 16081cb0ef41Sopenharmony_ci std::move(unpublished_code)); 16091cb0ef41Sopenharmony_ci } 16101cb0ef41Sopenharmony_ci } 16111cb0ef41Sopenharmony_ci } 16121cb0ef41Sopenharmony_ci UNREACHABLE(); 16131cb0ef41Sopenharmony_ci} 16141cb0ef41Sopenharmony_ci 16151cb0ef41Sopenharmony_ciusing JSToWasmWrapperKey = std::pair<bool, FunctionSig>; 16161cb0ef41Sopenharmony_ci 16171cb0ef41Sopenharmony_ci// Returns the number of units added. 16181cb0ef41Sopenharmony_ciint AddExportWrapperUnits(Isolate* isolate, NativeModule* native_module, 16191cb0ef41Sopenharmony_ci CompilationUnitBuilder* builder) { 16201cb0ef41Sopenharmony_ci std::unordered_set<JSToWasmWrapperKey, base::hash<JSToWasmWrapperKey>> keys; 16211cb0ef41Sopenharmony_ci for (auto exp : native_module->module()->export_table) { 16221cb0ef41Sopenharmony_ci if (exp.kind != kExternalFunction) continue; 16231cb0ef41Sopenharmony_ci auto& function = native_module->module()->functions[exp.index]; 16241cb0ef41Sopenharmony_ci JSToWasmWrapperKey key(function.imported, *function.sig); 16251cb0ef41Sopenharmony_ci if (keys.insert(key).second) { 16261cb0ef41Sopenharmony_ci auto unit = std::make_shared<JSToWasmWrapperCompilationUnit>( 16271cb0ef41Sopenharmony_ci isolate, function.sig, native_module->module(), function.imported, 16281cb0ef41Sopenharmony_ci native_module->enabled_features(), 16291cb0ef41Sopenharmony_ci JSToWasmWrapperCompilationUnit::kAllowGeneric); 16301cb0ef41Sopenharmony_ci builder->AddJSToWasmWrapperUnit(std::move(unit)); 16311cb0ef41Sopenharmony_ci } 16321cb0ef41Sopenharmony_ci } 16331cb0ef41Sopenharmony_ci 16341cb0ef41Sopenharmony_ci return static_cast<int>(keys.size()); 16351cb0ef41Sopenharmony_ci} 16361cb0ef41Sopenharmony_ci 16371cb0ef41Sopenharmony_ci// Returns the number of units added. 16381cb0ef41Sopenharmony_ciint AddImportWrapperUnits(NativeModule* native_module, 16391cb0ef41Sopenharmony_ci CompilationUnitBuilder* builder) { 16401cb0ef41Sopenharmony_ci std::unordered_set<WasmImportWrapperCache::CacheKey, 16411cb0ef41Sopenharmony_ci WasmImportWrapperCache::CacheKeyHash> 16421cb0ef41Sopenharmony_ci keys; 16431cb0ef41Sopenharmony_ci int num_imported_functions = native_module->num_imported_functions(); 16441cb0ef41Sopenharmony_ci for (int func_index = 0; func_index < num_imported_functions; func_index++) { 16451cb0ef41Sopenharmony_ci const FunctionSig* sig = native_module->module()->functions[func_index].sig; 16461cb0ef41Sopenharmony_ci if (!IsJSCompatibleSignature(sig, native_module->module(), 16471cb0ef41Sopenharmony_ci native_module->enabled_features())) { 16481cb0ef41Sopenharmony_ci continue; 16491cb0ef41Sopenharmony_ci } 16501cb0ef41Sopenharmony_ci WasmImportWrapperCache::CacheKey key( 16511cb0ef41Sopenharmony_ci compiler::kDefaultImportCallKind, sig, 16521cb0ef41Sopenharmony_ci static_cast<int>(sig->parameter_count()), kNoSuspend); 16531cb0ef41Sopenharmony_ci auto it = keys.insert(key); 16541cb0ef41Sopenharmony_ci if (it.second) { 16551cb0ef41Sopenharmony_ci // Ensure that all keys exist in the cache, so that we can populate the 16561cb0ef41Sopenharmony_ci // cache later without locking. 16571cb0ef41Sopenharmony_ci (*native_module->import_wrapper_cache())[key] = nullptr; 16581cb0ef41Sopenharmony_ci builder->AddUnits(func_index); 16591cb0ef41Sopenharmony_ci } 16601cb0ef41Sopenharmony_ci } 16611cb0ef41Sopenharmony_ci return static_cast<int>(keys.size()); 16621cb0ef41Sopenharmony_ci} 16631cb0ef41Sopenharmony_ci 16641cb0ef41Sopenharmony_civoid InitializeLazyCompilation(NativeModule* native_module) { 16651cb0ef41Sopenharmony_ci const bool lazy_module = IsLazyModule(native_module->module()); 16661cb0ef41Sopenharmony_ci auto* module = native_module->module(); 16671cb0ef41Sopenharmony_ci 16681cb0ef41Sopenharmony_ci uint32_t start = module->num_imported_functions; 16691cb0ef41Sopenharmony_ci uint32_t end = start + module->num_declared_functions; 16701cb0ef41Sopenharmony_ci base::Optional<CodeSpaceWriteScope> lazy_code_space_write_scope; 16711cb0ef41Sopenharmony_ci for (uint32_t func_index = start; func_index < end; func_index++) { 16721cb0ef41Sopenharmony_ci CompileStrategy strategy = GetCompileStrategy( 16731cb0ef41Sopenharmony_ci module, native_module->enabled_features(), func_index, lazy_module); 16741cb0ef41Sopenharmony_ci if (strategy == CompileStrategy::kLazy || 16751cb0ef41Sopenharmony_ci strategy == CompileStrategy::kLazyBaselineEagerTopTier) { 16761cb0ef41Sopenharmony_ci // Open a single scope for all following calls to {UseLazyStub()}, instead 16771cb0ef41Sopenharmony_ci // of flipping page permissions for each {func_index} individually. 16781cb0ef41Sopenharmony_ci if (!lazy_code_space_write_scope.has_value()) { 16791cb0ef41Sopenharmony_ci lazy_code_space_write_scope.emplace(native_module); 16801cb0ef41Sopenharmony_ci } 16811cb0ef41Sopenharmony_ci native_module->UseLazyStub(func_index); 16821cb0ef41Sopenharmony_ci } 16831cb0ef41Sopenharmony_ci } 16841cb0ef41Sopenharmony_ci} 16851cb0ef41Sopenharmony_ci 16861cb0ef41Sopenharmony_cistd::unique_ptr<CompilationUnitBuilder> InitializeCompilation( 16871cb0ef41Sopenharmony_ci Isolate* isolate, NativeModule* native_module) { 16881cb0ef41Sopenharmony_ci InitializeLazyCompilation(native_module); 16891cb0ef41Sopenharmony_ci CompilationStateImpl* compilation_state = 16901cb0ef41Sopenharmony_ci Impl(native_module->compilation_state()); 16911cb0ef41Sopenharmony_ci const bool lazy_module = IsLazyModule(native_module->module()); 16921cb0ef41Sopenharmony_ci auto builder = std::make_unique<CompilationUnitBuilder>(native_module); 16931cb0ef41Sopenharmony_ci int num_import_wrappers = AddImportWrapperUnits(native_module, builder.get()); 16941cb0ef41Sopenharmony_ci int num_export_wrappers = 16951cb0ef41Sopenharmony_ci AddExportWrapperUnits(isolate, native_module, builder.get()); 16961cb0ef41Sopenharmony_ci compilation_state->InitializeCompilationProgress( 16971cb0ef41Sopenharmony_ci lazy_module, num_import_wrappers, num_export_wrappers); 16981cb0ef41Sopenharmony_ci return builder; 16991cb0ef41Sopenharmony_ci} 17001cb0ef41Sopenharmony_ci 17011cb0ef41Sopenharmony_cibool MayCompriseLazyFunctions(const WasmModule* module, 17021cb0ef41Sopenharmony_ci const WasmFeatures& enabled_features, 17031cb0ef41Sopenharmony_ci bool lazy_module) { 17041cb0ef41Sopenharmony_ci if (lazy_module || enabled_features.has_compilation_hints()) return true; 17051cb0ef41Sopenharmony_ci#ifdef ENABLE_SLOW_DCHECKS 17061cb0ef41Sopenharmony_ci int start = module->num_imported_functions; 17071cb0ef41Sopenharmony_ci int end = start + module->num_declared_functions; 17081cb0ef41Sopenharmony_ci for (int func_index = start; func_index < end; func_index++) { 17091cb0ef41Sopenharmony_ci SLOW_DCHECK(GetCompileStrategy(module, enabled_features, func_index, 17101cb0ef41Sopenharmony_ci lazy_module) != CompileStrategy::kLazy); 17111cb0ef41Sopenharmony_ci } 17121cb0ef41Sopenharmony_ci#endif 17131cb0ef41Sopenharmony_ci return false; 17141cb0ef41Sopenharmony_ci} 17151cb0ef41Sopenharmony_ci 17161cb0ef41Sopenharmony_ciclass CompilationTimeCallback : public CompilationEventCallback { 17171cb0ef41Sopenharmony_ci public: 17181cb0ef41Sopenharmony_ci enum CompileMode { kSynchronous, kAsync, kStreaming }; 17191cb0ef41Sopenharmony_ci explicit CompilationTimeCallback( 17201cb0ef41Sopenharmony_ci std::shared_ptr<Counters> async_counters, 17211cb0ef41Sopenharmony_ci std::shared_ptr<metrics::Recorder> metrics_recorder, 17221cb0ef41Sopenharmony_ci v8::metrics::Recorder::ContextId context_id, 17231cb0ef41Sopenharmony_ci std::weak_ptr<NativeModule> native_module, CompileMode compile_mode) 17241cb0ef41Sopenharmony_ci : start_time_(base::TimeTicks::Now()), 17251cb0ef41Sopenharmony_ci async_counters_(std::move(async_counters)), 17261cb0ef41Sopenharmony_ci metrics_recorder_(std::move(metrics_recorder)), 17271cb0ef41Sopenharmony_ci context_id_(context_id), 17281cb0ef41Sopenharmony_ci native_module_(std::move(native_module)), 17291cb0ef41Sopenharmony_ci compile_mode_(compile_mode) {} 17301cb0ef41Sopenharmony_ci 17311cb0ef41Sopenharmony_ci // Keep this callback alive to be able to record caching metrics. 17321cb0ef41Sopenharmony_ci ReleaseAfterFinalEvent release_after_final_event() override { 17331cb0ef41Sopenharmony_ci return CompilationEventCallback::ReleaseAfterFinalEvent::kKeep; 17341cb0ef41Sopenharmony_ci } 17351cb0ef41Sopenharmony_ci 17361cb0ef41Sopenharmony_ci void call(CompilationEvent compilation_event) override { 17371cb0ef41Sopenharmony_ci DCHECK(base::TimeTicks::IsHighResolution()); 17381cb0ef41Sopenharmony_ci std::shared_ptr<NativeModule> native_module = native_module_.lock(); 17391cb0ef41Sopenharmony_ci if (!native_module) return; 17401cb0ef41Sopenharmony_ci auto now = base::TimeTicks::Now(); 17411cb0ef41Sopenharmony_ci auto duration = now - start_time_; 17421cb0ef41Sopenharmony_ci if (compilation_event == CompilationEvent::kFinishedBaselineCompilation) { 17431cb0ef41Sopenharmony_ci // Reset {start_time_} to measure tier-up time. 17441cb0ef41Sopenharmony_ci start_time_ = now; 17451cb0ef41Sopenharmony_ci if (compile_mode_ != kSynchronous) { 17461cb0ef41Sopenharmony_ci TimedHistogram* histogram = 17471cb0ef41Sopenharmony_ci compile_mode_ == kAsync 17481cb0ef41Sopenharmony_ci ? async_counters_->wasm_async_compile_wasm_module_time() 17491cb0ef41Sopenharmony_ci : async_counters_->wasm_streaming_compile_wasm_module_time(); 17501cb0ef41Sopenharmony_ci histogram->AddSample(static_cast<int>(duration.InMicroseconds())); 17511cb0ef41Sopenharmony_ci } 17521cb0ef41Sopenharmony_ci 17531cb0ef41Sopenharmony_ci v8::metrics::WasmModuleCompiled event{ 17541cb0ef41Sopenharmony_ci (compile_mode_ != kSynchronous), // async 17551cb0ef41Sopenharmony_ci (compile_mode_ == kStreaming), // streamed 17561cb0ef41Sopenharmony_ci false, // cached 17571cb0ef41Sopenharmony_ci false, // deserialized 17581cb0ef41Sopenharmony_ci FLAG_wasm_lazy_compilation, // lazy 17591cb0ef41Sopenharmony_ci true, // success 17601cb0ef41Sopenharmony_ci native_module->liftoff_code_size(), // code_size_in_bytes 17611cb0ef41Sopenharmony_ci native_module->liftoff_bailout_count(), // liftoff_bailout_count 17621cb0ef41Sopenharmony_ci duration.InMicroseconds(), // wall_clock_duration_in_us 17631cb0ef41Sopenharmony_ci static_cast<int64_t>( // cpu_time_duration_in_us 17641cb0ef41Sopenharmony_ci native_module->baseline_compilation_cpu_duration())}; 17651cb0ef41Sopenharmony_ci metrics_recorder_->DelayMainThreadEvent(event, context_id_); 17661cb0ef41Sopenharmony_ci } 17671cb0ef41Sopenharmony_ci if (compilation_event == CompilationEvent::kFinishedTopTierCompilation) { 17681cb0ef41Sopenharmony_ci TimedHistogram* histogram = async_counters_->wasm_tier_up_module_time(); 17691cb0ef41Sopenharmony_ci histogram->AddSample(static_cast<int>(duration.InMicroseconds())); 17701cb0ef41Sopenharmony_ci 17711cb0ef41Sopenharmony_ci v8::metrics::WasmModuleTieredUp event{ 17721cb0ef41Sopenharmony_ci FLAG_wasm_lazy_compilation, // lazy 17731cb0ef41Sopenharmony_ci native_module->turbofan_code_size(), // code_size_in_bytes 17741cb0ef41Sopenharmony_ci duration.InMicroseconds(), // wall_clock_duration_in_us 17751cb0ef41Sopenharmony_ci static_cast<int64_t>( // cpu_time_duration_in_us 17761cb0ef41Sopenharmony_ci native_module->tier_up_cpu_duration())}; 17771cb0ef41Sopenharmony_ci metrics_recorder_->DelayMainThreadEvent(event, context_id_); 17781cb0ef41Sopenharmony_ci } 17791cb0ef41Sopenharmony_ci if (compilation_event == CompilationEvent::kFailedCompilation) { 17801cb0ef41Sopenharmony_ci v8::metrics::WasmModuleCompiled event{ 17811cb0ef41Sopenharmony_ci (compile_mode_ != kSynchronous), // async 17821cb0ef41Sopenharmony_ci (compile_mode_ == kStreaming), // streamed 17831cb0ef41Sopenharmony_ci false, // cached 17841cb0ef41Sopenharmony_ci false, // deserialized 17851cb0ef41Sopenharmony_ci FLAG_wasm_lazy_compilation, // lazy 17861cb0ef41Sopenharmony_ci false, // success 17871cb0ef41Sopenharmony_ci native_module->liftoff_code_size(), // code_size_in_bytes 17881cb0ef41Sopenharmony_ci native_module->liftoff_bailout_count(), // liftoff_bailout_count 17891cb0ef41Sopenharmony_ci duration.InMicroseconds(), // wall_clock_duration_in_us 17901cb0ef41Sopenharmony_ci static_cast<int64_t>( // cpu_time_duration_in_us 17911cb0ef41Sopenharmony_ci native_module->baseline_compilation_cpu_duration())}; 17921cb0ef41Sopenharmony_ci metrics_recorder_->DelayMainThreadEvent(event, context_id_); 17931cb0ef41Sopenharmony_ci } 17941cb0ef41Sopenharmony_ci } 17951cb0ef41Sopenharmony_ci 17961cb0ef41Sopenharmony_ci private: 17971cb0ef41Sopenharmony_ci base::TimeTicks start_time_; 17981cb0ef41Sopenharmony_ci const std::shared_ptr<Counters> async_counters_; 17991cb0ef41Sopenharmony_ci std::shared_ptr<metrics::Recorder> metrics_recorder_; 18001cb0ef41Sopenharmony_ci v8::metrics::Recorder::ContextId context_id_; 18011cb0ef41Sopenharmony_ci std::weak_ptr<NativeModule> native_module_; 18021cb0ef41Sopenharmony_ci const CompileMode compile_mode_; 18031cb0ef41Sopenharmony_ci}; 18041cb0ef41Sopenharmony_ci 18051cb0ef41Sopenharmony_civoid CompileNativeModule(Isolate* isolate, 18061cb0ef41Sopenharmony_ci v8::metrics::Recorder::ContextId context_id, 18071cb0ef41Sopenharmony_ci ErrorThrower* thrower, const WasmModule* wasm_module, 18081cb0ef41Sopenharmony_ci std::shared_ptr<NativeModule> native_module, 18091cb0ef41Sopenharmony_ci Handle<FixedArray>* export_wrappers_out) { 18101cb0ef41Sopenharmony_ci CHECK(!FLAG_jitless); 18111cb0ef41Sopenharmony_ci ModuleWireBytes wire_bytes(native_module->wire_bytes()); 18121cb0ef41Sopenharmony_ci const bool lazy_module = IsLazyModule(wasm_module); 18131cb0ef41Sopenharmony_ci if (!FLAG_wasm_lazy_validation && wasm_module->origin == kWasmOrigin && 18141cb0ef41Sopenharmony_ci MayCompriseLazyFunctions(wasm_module, native_module->enabled_features(), 18151cb0ef41Sopenharmony_ci lazy_module)) { 18161cb0ef41Sopenharmony_ci // Validate wasm modules for lazy compilation if requested. Never validate 18171cb0ef41Sopenharmony_ci // asm.js modules as these are valid by construction (additionally a CHECK 18181cb0ef41Sopenharmony_ci // will catch this during lazy compilation). 18191cb0ef41Sopenharmony_ci ValidateSequentially(wasm_module, native_module.get(), isolate->counters(), 18201cb0ef41Sopenharmony_ci isolate->allocator(), thrower, lazy_module, 18211cb0ef41Sopenharmony_ci kOnlyLazyFunctions); 18221cb0ef41Sopenharmony_ci // On error: Return and leave the module in an unexecutable state. 18231cb0ef41Sopenharmony_ci if (thrower->error()) return; 18241cb0ef41Sopenharmony_ci } 18251cb0ef41Sopenharmony_ci 18261cb0ef41Sopenharmony_ci DCHECK_GE(kMaxInt, native_module->module()->num_declared_functions); 18271cb0ef41Sopenharmony_ci 18281cb0ef41Sopenharmony_ci // The callback captures a shared ptr to the semaphore. 18291cb0ef41Sopenharmony_ci auto* compilation_state = Impl(native_module->compilation_state()); 18301cb0ef41Sopenharmony_ci if (base::TimeTicks::IsHighResolution()) { 18311cb0ef41Sopenharmony_ci compilation_state->AddCallback(std::make_unique<CompilationTimeCallback>( 18321cb0ef41Sopenharmony_ci isolate->async_counters(), isolate->metrics_recorder(), context_id, 18331cb0ef41Sopenharmony_ci native_module, CompilationTimeCallback::kSynchronous)); 18341cb0ef41Sopenharmony_ci } 18351cb0ef41Sopenharmony_ci 18361cb0ef41Sopenharmony_ci // Initialize the compilation units and kick off background compile tasks. 18371cb0ef41Sopenharmony_ci std::unique_ptr<CompilationUnitBuilder> builder = 18381cb0ef41Sopenharmony_ci InitializeCompilation(isolate, native_module.get()); 18391cb0ef41Sopenharmony_ci compilation_state->InitializeCompilationUnits(std::move(builder)); 18401cb0ef41Sopenharmony_ci 18411cb0ef41Sopenharmony_ci compilation_state->WaitForCompilationEvent( 18421cb0ef41Sopenharmony_ci CompilationEvent::kFinishedExportWrappers); 18431cb0ef41Sopenharmony_ci 18441cb0ef41Sopenharmony_ci if (compilation_state->failed()) { 18451cb0ef41Sopenharmony_ci DCHECK_IMPLIES(lazy_module, !FLAG_wasm_lazy_validation); 18461cb0ef41Sopenharmony_ci ValidateSequentially(wasm_module, native_module.get(), isolate->counters(), 18471cb0ef41Sopenharmony_ci isolate->allocator(), thrower, lazy_module); 18481cb0ef41Sopenharmony_ci CHECK(thrower->error()); 18491cb0ef41Sopenharmony_ci return; 18501cb0ef41Sopenharmony_ci } 18511cb0ef41Sopenharmony_ci 18521cb0ef41Sopenharmony_ci compilation_state->FinalizeJSToWasmWrappers(isolate, native_module->module(), 18531cb0ef41Sopenharmony_ci export_wrappers_out); 18541cb0ef41Sopenharmony_ci 18551cb0ef41Sopenharmony_ci compilation_state->WaitForCompilationEvent( 18561cb0ef41Sopenharmony_ci CompilationEvent::kFinishedBaselineCompilation); 18571cb0ef41Sopenharmony_ci 18581cb0ef41Sopenharmony_ci compilation_state->PublishDetectedFeatures(isolate); 18591cb0ef41Sopenharmony_ci 18601cb0ef41Sopenharmony_ci if (compilation_state->failed()) { 18611cb0ef41Sopenharmony_ci DCHECK_IMPLIES(lazy_module, !FLAG_wasm_lazy_validation); 18621cb0ef41Sopenharmony_ci ValidateSequentially(wasm_module, native_module.get(), isolate->counters(), 18631cb0ef41Sopenharmony_ci isolate->allocator(), thrower, lazy_module); 18641cb0ef41Sopenharmony_ci CHECK(thrower->error()); 18651cb0ef41Sopenharmony_ci } 18661cb0ef41Sopenharmony_ci} 18671cb0ef41Sopenharmony_ci 18681cb0ef41Sopenharmony_ciclass BackgroundCompileJob final : public JobTask { 18691cb0ef41Sopenharmony_ci public: 18701cb0ef41Sopenharmony_ci explicit BackgroundCompileJob(std::weak_ptr<NativeModule> native_module, 18711cb0ef41Sopenharmony_ci std::shared_ptr<Counters> async_counters) 18721cb0ef41Sopenharmony_ci : native_module_(std::move(native_module)), 18731cb0ef41Sopenharmony_ci engine_barrier_(GetWasmEngine()->GetBarrierForBackgroundCompile()), 18741cb0ef41Sopenharmony_ci async_counters_(std::move(async_counters)) {} 18751cb0ef41Sopenharmony_ci 18761cb0ef41Sopenharmony_ci void Run(JobDelegate* delegate) override { 18771cb0ef41Sopenharmony_ci auto engine_scope = engine_barrier_->TryLock(); 18781cb0ef41Sopenharmony_ci if (!engine_scope) return; 18791cb0ef41Sopenharmony_ci ExecuteCompilationUnits(native_module_, async_counters_.get(), delegate, 18801cb0ef41Sopenharmony_ci kBaselineOrTopTier); 18811cb0ef41Sopenharmony_ci } 18821cb0ef41Sopenharmony_ci 18831cb0ef41Sopenharmony_ci size_t GetMaxConcurrency(size_t worker_count) const override { 18841cb0ef41Sopenharmony_ci BackgroundCompileScope compile_scope(native_module_); 18851cb0ef41Sopenharmony_ci if (compile_scope.cancelled()) return 0; 18861cb0ef41Sopenharmony_ci // NumOutstandingCompilations() does not reflect the units that running 18871cb0ef41Sopenharmony_ci // workers are processing, thus add the current worker count to that number. 18881cb0ef41Sopenharmony_ci return std::min( 18891cb0ef41Sopenharmony_ci static_cast<size_t>(FLAG_wasm_num_compilation_tasks), 18901cb0ef41Sopenharmony_ci worker_count + 18911cb0ef41Sopenharmony_ci compile_scope.compilation_state()->NumOutstandingCompilations()); 18921cb0ef41Sopenharmony_ci } 18931cb0ef41Sopenharmony_ci 18941cb0ef41Sopenharmony_ci private: 18951cb0ef41Sopenharmony_ci std::weak_ptr<NativeModule> native_module_; 18961cb0ef41Sopenharmony_ci std::shared_ptr<OperationsBarrier> engine_barrier_; 18971cb0ef41Sopenharmony_ci const std::shared_ptr<Counters> async_counters_; 18981cb0ef41Sopenharmony_ci}; 18991cb0ef41Sopenharmony_ci 19001cb0ef41Sopenharmony_ci} // namespace 19011cb0ef41Sopenharmony_ci 19021cb0ef41Sopenharmony_cistd::shared_ptr<NativeModule> CompileToNativeModule( 19031cb0ef41Sopenharmony_ci Isolate* isolate, const WasmFeatures& enabled, ErrorThrower* thrower, 19041cb0ef41Sopenharmony_ci std::shared_ptr<const WasmModule> module, const ModuleWireBytes& wire_bytes, 19051cb0ef41Sopenharmony_ci Handle<FixedArray>* export_wrappers_out, int compilation_id, 19061cb0ef41Sopenharmony_ci v8::metrics::Recorder::ContextId context_id) { 19071cb0ef41Sopenharmony_ci const WasmModule* wasm_module = module.get(); 19081cb0ef41Sopenharmony_ci WasmEngine* engine = GetWasmEngine(); 19091cb0ef41Sopenharmony_ci base::OwnedVector<uint8_t> wire_bytes_copy = 19101cb0ef41Sopenharmony_ci base::OwnedVector<uint8_t>::Of(wire_bytes.module_bytes()); 19111cb0ef41Sopenharmony_ci // Prefer {wire_bytes_copy} to {wire_bytes.module_bytes()} for the temporary 19121cb0ef41Sopenharmony_ci // cache key. When we eventually install the module in the cache, the wire 19131cb0ef41Sopenharmony_ci // bytes of the temporary key and the new key have the same base pointer and 19141cb0ef41Sopenharmony_ci // we can skip the full bytes comparison. 19151cb0ef41Sopenharmony_ci std::shared_ptr<NativeModule> native_module = engine->MaybeGetNativeModule( 19161cb0ef41Sopenharmony_ci wasm_module->origin, wire_bytes_copy.as_vector(), isolate); 19171cb0ef41Sopenharmony_ci if (native_module) { 19181cb0ef41Sopenharmony_ci // TODO(thibaudm): Look into sharing export wrappers. 19191cb0ef41Sopenharmony_ci CompileJsToWasmWrappers(isolate, wasm_module, export_wrappers_out); 19201cb0ef41Sopenharmony_ci return native_module; 19211cb0ef41Sopenharmony_ci } 19221cb0ef41Sopenharmony_ci 19231cb0ef41Sopenharmony_ci TimedHistogramScope wasm_compile_module_time_scope(SELECT_WASM_COUNTER( 19241cb0ef41Sopenharmony_ci isolate->counters(), wasm_module->origin, wasm_compile, module_time)); 19251cb0ef41Sopenharmony_ci 19261cb0ef41Sopenharmony_ci // Embedder usage count for declared shared memories. 19271cb0ef41Sopenharmony_ci if (wasm_module->has_shared_memory) { 19281cb0ef41Sopenharmony_ci isolate->CountUsage(v8::Isolate::UseCounterFeature::kWasmSharedMemory); 19291cb0ef41Sopenharmony_ci } 19301cb0ef41Sopenharmony_ci 19311cb0ef41Sopenharmony_ci // Create a new {NativeModule} first. 19321cb0ef41Sopenharmony_ci const bool include_liftoff = module->origin == kWasmOrigin && FLAG_liftoff; 19331cb0ef41Sopenharmony_ci DynamicTiering dynamic_tiering = isolate->IsWasmDynamicTieringEnabled() 19341cb0ef41Sopenharmony_ci ? DynamicTiering::kEnabled 19351cb0ef41Sopenharmony_ci : DynamicTiering::kDisabled; 19361cb0ef41Sopenharmony_ci size_t code_size_estimate = 19371cb0ef41Sopenharmony_ci wasm::WasmCodeManager::EstimateNativeModuleCodeSize( 19381cb0ef41Sopenharmony_ci module.get(), include_liftoff, dynamic_tiering); 19391cb0ef41Sopenharmony_ci native_module = 19401cb0ef41Sopenharmony_ci engine->NewNativeModule(isolate, enabled, module, code_size_estimate); 19411cb0ef41Sopenharmony_ci native_module->SetWireBytes(std::move(wire_bytes_copy)); 19421cb0ef41Sopenharmony_ci native_module->compilation_state()->set_compilation_id(compilation_id); 19431cb0ef41Sopenharmony_ci // Sync compilation is user blocking, so we increase the priority. 19441cb0ef41Sopenharmony_ci native_module->compilation_state()->SetHighPriority(); 19451cb0ef41Sopenharmony_ci 19461cb0ef41Sopenharmony_ci CompileNativeModule(isolate, context_id, thrower, wasm_module, native_module, 19471cb0ef41Sopenharmony_ci export_wrappers_out); 19481cb0ef41Sopenharmony_ci bool cache_hit = !engine->UpdateNativeModuleCache(thrower->error(), 19491cb0ef41Sopenharmony_ci &native_module, isolate); 19501cb0ef41Sopenharmony_ci if (thrower->error()) return {}; 19511cb0ef41Sopenharmony_ci 19521cb0ef41Sopenharmony_ci if (cache_hit) { 19531cb0ef41Sopenharmony_ci CompileJsToWasmWrappers(isolate, wasm_module, export_wrappers_out); 19541cb0ef41Sopenharmony_ci return native_module; 19551cb0ef41Sopenharmony_ci } 19561cb0ef41Sopenharmony_ci 19571cb0ef41Sopenharmony_ci // Ensure that the code objects are logged before returning. 19581cb0ef41Sopenharmony_ci engine->LogOutstandingCodesForIsolate(isolate); 19591cb0ef41Sopenharmony_ci 19601cb0ef41Sopenharmony_ci return native_module; 19611cb0ef41Sopenharmony_ci} 19621cb0ef41Sopenharmony_ci 19631cb0ef41Sopenharmony_civoid RecompileNativeModule(NativeModule* native_module, 19641cb0ef41Sopenharmony_ci TieringState tiering_state) { 19651cb0ef41Sopenharmony_ci // Install a callback to notify us once background recompilation finished. 19661cb0ef41Sopenharmony_ci auto recompilation_finished_semaphore = std::make_shared<base::Semaphore>(0); 19671cb0ef41Sopenharmony_ci auto* compilation_state = Impl(native_module->compilation_state()); 19681cb0ef41Sopenharmony_ci 19691cb0ef41Sopenharmony_ci class RecompilationFinishedCallback : public CompilationEventCallback { 19701cb0ef41Sopenharmony_ci public: 19711cb0ef41Sopenharmony_ci explicit RecompilationFinishedCallback( 19721cb0ef41Sopenharmony_ci std::shared_ptr<base::Semaphore> recompilation_finished_semaphore) 19731cb0ef41Sopenharmony_ci : recompilation_finished_semaphore_( 19741cb0ef41Sopenharmony_ci std::move(recompilation_finished_semaphore)) {} 19751cb0ef41Sopenharmony_ci 19761cb0ef41Sopenharmony_ci void call(CompilationEvent event) override { 19771cb0ef41Sopenharmony_ci DCHECK_NE(CompilationEvent::kFailedCompilation, event); 19781cb0ef41Sopenharmony_ci if (event == CompilationEvent::kFinishedRecompilation) { 19791cb0ef41Sopenharmony_ci recompilation_finished_semaphore_->Signal(); 19801cb0ef41Sopenharmony_ci } 19811cb0ef41Sopenharmony_ci } 19821cb0ef41Sopenharmony_ci 19831cb0ef41Sopenharmony_ci private: 19841cb0ef41Sopenharmony_ci std::shared_ptr<base::Semaphore> recompilation_finished_semaphore_; 19851cb0ef41Sopenharmony_ci }; 19861cb0ef41Sopenharmony_ci 19871cb0ef41Sopenharmony_ci // The callback captures a shared ptr to the semaphore. 19881cb0ef41Sopenharmony_ci // Initialize the compilation units and kick off background compile tasks. 19891cb0ef41Sopenharmony_ci compilation_state->InitializeRecompilation( 19901cb0ef41Sopenharmony_ci tiering_state, std::make_unique<RecompilationFinishedCallback>( 19911cb0ef41Sopenharmony_ci recompilation_finished_semaphore)); 19921cb0ef41Sopenharmony_ci 19931cb0ef41Sopenharmony_ci constexpr JobDelegate* kNoDelegate = nullptr; 19941cb0ef41Sopenharmony_ci ExecuteCompilationUnits(compilation_state->native_module_weak(), 19951cb0ef41Sopenharmony_ci compilation_state->counters(), kNoDelegate, 19961cb0ef41Sopenharmony_ci kBaselineOnly); 19971cb0ef41Sopenharmony_ci recompilation_finished_semaphore->Wait(); 19981cb0ef41Sopenharmony_ci DCHECK(!compilation_state->failed()); 19991cb0ef41Sopenharmony_ci} 20001cb0ef41Sopenharmony_ci 20011cb0ef41Sopenharmony_ciAsyncCompileJob::AsyncCompileJob( 20021cb0ef41Sopenharmony_ci Isolate* isolate, const WasmFeatures& enabled, 20031cb0ef41Sopenharmony_ci std::unique_ptr<byte[]> bytes_copy, size_t length, Handle<Context> context, 20041cb0ef41Sopenharmony_ci Handle<Context> incumbent_context, const char* api_method_name, 20051cb0ef41Sopenharmony_ci std::shared_ptr<CompilationResultResolver> resolver, int compilation_id) 20061cb0ef41Sopenharmony_ci : isolate_(isolate), 20071cb0ef41Sopenharmony_ci api_method_name_(api_method_name), 20081cb0ef41Sopenharmony_ci enabled_features_(enabled), 20091cb0ef41Sopenharmony_ci dynamic_tiering_(isolate_->IsWasmDynamicTieringEnabled() 20101cb0ef41Sopenharmony_ci ? DynamicTiering::kEnabled 20111cb0ef41Sopenharmony_ci : DynamicTiering::kDisabled), 20121cb0ef41Sopenharmony_ci wasm_lazy_compilation_(FLAG_wasm_lazy_compilation), 20131cb0ef41Sopenharmony_ci start_time_(base::TimeTicks::Now()), 20141cb0ef41Sopenharmony_ci bytes_copy_(std::move(bytes_copy)), 20151cb0ef41Sopenharmony_ci wire_bytes_(bytes_copy_.get(), bytes_copy_.get() + length), 20161cb0ef41Sopenharmony_ci resolver_(std::move(resolver)), 20171cb0ef41Sopenharmony_ci compilation_id_(compilation_id) { 20181cb0ef41Sopenharmony_ci TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm.detailed"), 20191cb0ef41Sopenharmony_ci "wasm.AsyncCompileJob"); 20201cb0ef41Sopenharmony_ci CHECK(FLAG_wasm_async_compilation); 20211cb0ef41Sopenharmony_ci CHECK(!FLAG_jitless); 20221cb0ef41Sopenharmony_ci v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate); 20231cb0ef41Sopenharmony_ci v8::Platform* platform = V8::GetCurrentPlatform(); 20241cb0ef41Sopenharmony_ci foreground_task_runner_ = platform->GetForegroundTaskRunner(v8_isolate); 20251cb0ef41Sopenharmony_ci native_context_ = 20261cb0ef41Sopenharmony_ci isolate->global_handles()->Create(context->native_context()); 20271cb0ef41Sopenharmony_ci incumbent_context_ = isolate->global_handles()->Create(*incumbent_context); 20281cb0ef41Sopenharmony_ci DCHECK(native_context_->IsNativeContext()); 20291cb0ef41Sopenharmony_ci context_id_ = isolate->GetOrRegisterRecorderContextId(native_context_); 20301cb0ef41Sopenharmony_ci metrics_event_.async = true; 20311cb0ef41Sopenharmony_ci} 20321cb0ef41Sopenharmony_ci 20331cb0ef41Sopenharmony_civoid AsyncCompileJob::Start() { 20341cb0ef41Sopenharmony_ci DoAsync<DecodeModule>(isolate_->counters(), 20351cb0ef41Sopenharmony_ci isolate_->metrics_recorder()); // -- 20361cb0ef41Sopenharmony_ci} 20371cb0ef41Sopenharmony_ci 20381cb0ef41Sopenharmony_civoid AsyncCompileJob::Abort() { 20391cb0ef41Sopenharmony_ci // Removing this job will trigger the destructor, which will cancel all 20401cb0ef41Sopenharmony_ci // compilation. 20411cb0ef41Sopenharmony_ci GetWasmEngine()->RemoveCompileJob(this); 20421cb0ef41Sopenharmony_ci} 20431cb0ef41Sopenharmony_ci 20441cb0ef41Sopenharmony_ciclass AsyncStreamingProcessor final : public StreamingProcessor { 20451cb0ef41Sopenharmony_ci public: 20461cb0ef41Sopenharmony_ci explicit AsyncStreamingProcessor(AsyncCompileJob* job, 20471cb0ef41Sopenharmony_ci std::shared_ptr<Counters> counters, 20481cb0ef41Sopenharmony_ci AccountingAllocator* allocator); 20491cb0ef41Sopenharmony_ci 20501cb0ef41Sopenharmony_ci ~AsyncStreamingProcessor() override; 20511cb0ef41Sopenharmony_ci 20521cb0ef41Sopenharmony_ci bool ProcessModuleHeader(base::Vector<const uint8_t> bytes, 20531cb0ef41Sopenharmony_ci uint32_t offset) override; 20541cb0ef41Sopenharmony_ci 20551cb0ef41Sopenharmony_ci bool ProcessSection(SectionCode section_code, 20561cb0ef41Sopenharmony_ci base::Vector<const uint8_t> bytes, 20571cb0ef41Sopenharmony_ci uint32_t offset) override; 20581cb0ef41Sopenharmony_ci 20591cb0ef41Sopenharmony_ci bool ProcessCodeSectionHeader(int num_functions, 20601cb0ef41Sopenharmony_ci uint32_t functions_mismatch_error_offset, 20611cb0ef41Sopenharmony_ci std::shared_ptr<WireBytesStorage>, 20621cb0ef41Sopenharmony_ci int code_section_start, 20631cb0ef41Sopenharmony_ci int code_section_length) override; 20641cb0ef41Sopenharmony_ci 20651cb0ef41Sopenharmony_ci bool ProcessFunctionBody(base::Vector<const uint8_t> bytes, 20661cb0ef41Sopenharmony_ci uint32_t offset) override; 20671cb0ef41Sopenharmony_ci 20681cb0ef41Sopenharmony_ci void OnFinishedChunk() override; 20691cb0ef41Sopenharmony_ci 20701cb0ef41Sopenharmony_ci void OnFinishedStream(base::OwnedVector<uint8_t> bytes) override; 20711cb0ef41Sopenharmony_ci 20721cb0ef41Sopenharmony_ci void OnError(const WasmError&) override; 20731cb0ef41Sopenharmony_ci 20741cb0ef41Sopenharmony_ci void OnAbort() override; 20751cb0ef41Sopenharmony_ci 20761cb0ef41Sopenharmony_ci bool Deserialize(base::Vector<const uint8_t> wire_bytes, 20771cb0ef41Sopenharmony_ci base::Vector<const uint8_t> module_bytes) override; 20781cb0ef41Sopenharmony_ci 20791cb0ef41Sopenharmony_ci private: 20801cb0ef41Sopenharmony_ci // Finishes the AsyncCompileJob with an error. 20811cb0ef41Sopenharmony_ci void FinishAsyncCompileJobWithError(const WasmError&); 20821cb0ef41Sopenharmony_ci 20831cb0ef41Sopenharmony_ci void CommitCompilationUnits(); 20841cb0ef41Sopenharmony_ci 20851cb0ef41Sopenharmony_ci ModuleDecoder decoder_; 20861cb0ef41Sopenharmony_ci AsyncCompileJob* job_; 20871cb0ef41Sopenharmony_ci std::unique_ptr<CompilationUnitBuilder> compilation_unit_builder_; 20881cb0ef41Sopenharmony_ci int num_functions_ = 0; 20891cb0ef41Sopenharmony_ci bool prefix_cache_hit_ = false; 20901cb0ef41Sopenharmony_ci bool before_code_section_ = true; 20911cb0ef41Sopenharmony_ci std::shared_ptr<Counters> async_counters_; 20921cb0ef41Sopenharmony_ci AccountingAllocator* allocator_; 20931cb0ef41Sopenharmony_ci 20941cb0ef41Sopenharmony_ci // Running hash of the wire bytes up to code section size, but excluding the 20951cb0ef41Sopenharmony_ci // code section itself. Used by the {NativeModuleCache} to detect potential 20961cb0ef41Sopenharmony_ci // duplicate modules. 20971cb0ef41Sopenharmony_ci size_t prefix_hash_; 20981cb0ef41Sopenharmony_ci}; 20991cb0ef41Sopenharmony_ci 21001cb0ef41Sopenharmony_cistd::shared_ptr<StreamingDecoder> AsyncCompileJob::CreateStreamingDecoder() { 21011cb0ef41Sopenharmony_ci DCHECK_NULL(stream_); 21021cb0ef41Sopenharmony_ci stream_ = StreamingDecoder::CreateAsyncStreamingDecoder( 21031cb0ef41Sopenharmony_ci std::make_unique<AsyncStreamingProcessor>( 21041cb0ef41Sopenharmony_ci this, isolate_->async_counters(), isolate_->allocator())); 21051cb0ef41Sopenharmony_ci return stream_; 21061cb0ef41Sopenharmony_ci} 21071cb0ef41Sopenharmony_ci 21081cb0ef41Sopenharmony_ciAsyncCompileJob::~AsyncCompileJob() { 21091cb0ef41Sopenharmony_ci // Note: This destructor always runs on the foreground thread of the isolate. 21101cb0ef41Sopenharmony_ci background_task_manager_.CancelAndWait(); 21111cb0ef41Sopenharmony_ci // If initial compilation did not finish yet we can abort it. 21121cb0ef41Sopenharmony_ci if (native_module_) { 21131cb0ef41Sopenharmony_ci Impl(native_module_->compilation_state()) 21141cb0ef41Sopenharmony_ci ->CancelCompilation(CompilationStateImpl::kCancelInitialCompilation); 21151cb0ef41Sopenharmony_ci } 21161cb0ef41Sopenharmony_ci // Tell the streaming decoder that the AsyncCompileJob is not available 21171cb0ef41Sopenharmony_ci // anymore. 21181cb0ef41Sopenharmony_ci // TODO(ahaas): Is this notification really necessary? Check 21191cb0ef41Sopenharmony_ci // https://crbug.com/888170. 21201cb0ef41Sopenharmony_ci if (stream_) stream_->NotifyCompilationEnded(); 21211cb0ef41Sopenharmony_ci CancelPendingForegroundTask(); 21221cb0ef41Sopenharmony_ci isolate_->global_handles()->Destroy(native_context_.location()); 21231cb0ef41Sopenharmony_ci isolate_->global_handles()->Destroy(incumbent_context_.location()); 21241cb0ef41Sopenharmony_ci if (!module_object_.is_null()) { 21251cb0ef41Sopenharmony_ci isolate_->global_handles()->Destroy(module_object_.location()); 21261cb0ef41Sopenharmony_ci } 21271cb0ef41Sopenharmony_ci} 21281cb0ef41Sopenharmony_ci 21291cb0ef41Sopenharmony_civoid AsyncCompileJob::CreateNativeModule( 21301cb0ef41Sopenharmony_ci std::shared_ptr<const WasmModule> module, size_t code_size_estimate) { 21311cb0ef41Sopenharmony_ci // Embedder usage count for declared shared memories. 21321cb0ef41Sopenharmony_ci if (module->has_shared_memory) { 21331cb0ef41Sopenharmony_ci isolate_->CountUsage(v8::Isolate::UseCounterFeature::kWasmSharedMemory); 21341cb0ef41Sopenharmony_ci } 21351cb0ef41Sopenharmony_ci 21361cb0ef41Sopenharmony_ci // TODO(wasm): Improve efficiency of storing module wire bytes. Only store 21371cb0ef41Sopenharmony_ci // relevant sections, not function bodies 21381cb0ef41Sopenharmony_ci 21391cb0ef41Sopenharmony_ci // Create the module object and populate with compiled functions and 21401cb0ef41Sopenharmony_ci // information needed at instantiation time. 21411cb0ef41Sopenharmony_ci 21421cb0ef41Sopenharmony_ci native_module_ = GetWasmEngine()->NewNativeModule( 21431cb0ef41Sopenharmony_ci isolate_, enabled_features_, std::move(module), code_size_estimate); 21441cb0ef41Sopenharmony_ci native_module_->SetWireBytes({std::move(bytes_copy_), wire_bytes_.length()}); 21451cb0ef41Sopenharmony_ci native_module_->compilation_state()->set_compilation_id(compilation_id_); 21461cb0ef41Sopenharmony_ci} 21471cb0ef41Sopenharmony_ci 21481cb0ef41Sopenharmony_cibool AsyncCompileJob::GetOrCreateNativeModule( 21491cb0ef41Sopenharmony_ci std::shared_ptr<const WasmModule> module, size_t code_size_estimate) { 21501cb0ef41Sopenharmony_ci native_module_ = GetWasmEngine()->MaybeGetNativeModule( 21511cb0ef41Sopenharmony_ci module->origin, wire_bytes_.module_bytes(), isolate_); 21521cb0ef41Sopenharmony_ci if (native_module_ == nullptr) { 21531cb0ef41Sopenharmony_ci CreateNativeModule(std::move(module), code_size_estimate); 21541cb0ef41Sopenharmony_ci return false; 21551cb0ef41Sopenharmony_ci } 21561cb0ef41Sopenharmony_ci return true; 21571cb0ef41Sopenharmony_ci} 21581cb0ef41Sopenharmony_ci 21591cb0ef41Sopenharmony_civoid AsyncCompileJob::PrepareRuntimeObjects() { 21601cb0ef41Sopenharmony_ci // Create heap objects for script and module bytes to be stored in the 21611cb0ef41Sopenharmony_ci // module object. Asm.js is not compiled asynchronously. 21621cb0ef41Sopenharmony_ci DCHECK(module_object_.is_null()); 21631cb0ef41Sopenharmony_ci auto source_url = stream_ ? stream_->url() : base::Vector<const char>(); 21641cb0ef41Sopenharmony_ci auto script = 21651cb0ef41Sopenharmony_ci GetWasmEngine()->GetOrCreateScript(isolate_, native_module_, source_url); 21661cb0ef41Sopenharmony_ci Handle<WasmModuleObject> module_object = 21671cb0ef41Sopenharmony_ci WasmModuleObject::New(isolate_, native_module_, script); 21681cb0ef41Sopenharmony_ci 21691cb0ef41Sopenharmony_ci module_object_ = isolate_->global_handles()->Create(*module_object); 21701cb0ef41Sopenharmony_ci} 21711cb0ef41Sopenharmony_ci 21721cb0ef41Sopenharmony_ci// This function assumes that it is executed in a HandleScope, and that a 21731cb0ef41Sopenharmony_ci// context is set on the isolate. 21741cb0ef41Sopenharmony_civoid AsyncCompileJob::FinishCompile(bool is_after_cache_hit) { 21751cb0ef41Sopenharmony_ci TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm.detailed"), 21761cb0ef41Sopenharmony_ci "wasm.FinishAsyncCompile"); 21771cb0ef41Sopenharmony_ci bool is_after_deserialization = !module_object_.is_null(); 21781cb0ef41Sopenharmony_ci auto compilation_state = Impl(native_module_->compilation_state()); 21791cb0ef41Sopenharmony_ci if (!is_after_deserialization) { 21801cb0ef41Sopenharmony_ci if (stream_) { 21811cb0ef41Sopenharmony_ci stream_->NotifyNativeModuleCreated(native_module_); 21821cb0ef41Sopenharmony_ci } 21831cb0ef41Sopenharmony_ci PrepareRuntimeObjects(); 21841cb0ef41Sopenharmony_ci } 21851cb0ef41Sopenharmony_ci 21861cb0ef41Sopenharmony_ci // Measure duration of baseline compilation or deserialization from cache. 21871cb0ef41Sopenharmony_ci if (base::TimeTicks::IsHighResolution()) { 21881cb0ef41Sopenharmony_ci base::TimeDelta duration = base::TimeTicks::Now() - start_time_; 21891cb0ef41Sopenharmony_ci int duration_usecs = static_cast<int>(duration.InMicroseconds()); 21901cb0ef41Sopenharmony_ci isolate_->counters()->wasm_streaming_finish_wasm_module_time()->AddSample( 21911cb0ef41Sopenharmony_ci duration_usecs); 21921cb0ef41Sopenharmony_ci 21931cb0ef41Sopenharmony_ci if (is_after_cache_hit || is_after_deserialization) { 21941cb0ef41Sopenharmony_ci v8::metrics::WasmModuleCompiled event{ 21951cb0ef41Sopenharmony_ci true, // async 21961cb0ef41Sopenharmony_ci true, // streamed 21971cb0ef41Sopenharmony_ci is_after_cache_hit, // cached 21981cb0ef41Sopenharmony_ci is_after_deserialization, // deserialized 21991cb0ef41Sopenharmony_ci wasm_lazy_compilation_, // lazy 22001cb0ef41Sopenharmony_ci !compilation_state->failed(), // success 22011cb0ef41Sopenharmony_ci native_module_->turbofan_code_size(), // code_size_in_bytes 22021cb0ef41Sopenharmony_ci native_module_->liftoff_bailout_count(), // liftoff_bailout_count 22031cb0ef41Sopenharmony_ci duration.InMicroseconds(), // wall_clock_duration_in_us 22041cb0ef41Sopenharmony_ci static_cast<int64_t>( // cpu_time_duration_in_us 22051cb0ef41Sopenharmony_ci native_module_->baseline_compilation_cpu_duration())}; 22061cb0ef41Sopenharmony_ci isolate_->metrics_recorder()->DelayMainThreadEvent(event, context_id_); 22071cb0ef41Sopenharmony_ci } 22081cb0ef41Sopenharmony_ci } 22091cb0ef41Sopenharmony_ci 22101cb0ef41Sopenharmony_ci DCHECK(!isolate_->context().is_null()); 22111cb0ef41Sopenharmony_ci // Finish the wasm script now and make it public to the debugger. 22121cb0ef41Sopenharmony_ci Handle<Script> script(module_object_->script(), isolate_); 22131cb0ef41Sopenharmony_ci const WasmModule* module = module_object_->module(); 22141cb0ef41Sopenharmony_ci if (script->type() == Script::TYPE_WASM && 22151cb0ef41Sopenharmony_ci module->debug_symbols.type == WasmDebugSymbols::Type::SourceMap && 22161cb0ef41Sopenharmony_ci !module->debug_symbols.external_url.is_empty()) { 22171cb0ef41Sopenharmony_ci ModuleWireBytes wire_bytes(module_object_->native_module()->wire_bytes()); 22181cb0ef41Sopenharmony_ci MaybeHandle<String> src_map_str = isolate_->factory()->NewStringFromUtf8( 22191cb0ef41Sopenharmony_ci wire_bytes.GetNameOrNull(module->debug_symbols.external_url), 22201cb0ef41Sopenharmony_ci AllocationType::kOld); 22211cb0ef41Sopenharmony_ci script->set_source_mapping_url(*src_map_str.ToHandleChecked()); 22221cb0ef41Sopenharmony_ci } 22231cb0ef41Sopenharmony_ci { 22241cb0ef41Sopenharmony_ci TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm.detailed"), 22251cb0ef41Sopenharmony_ci "wasm.Debug.OnAfterCompile"); 22261cb0ef41Sopenharmony_ci isolate_->debug()->OnAfterCompile(script); 22271cb0ef41Sopenharmony_ci } 22281cb0ef41Sopenharmony_ci 22291cb0ef41Sopenharmony_ci // TODO(bbudge) Allow deserialization without wrapper compilation, so we can 22301cb0ef41Sopenharmony_ci // just compile wrappers here. 22311cb0ef41Sopenharmony_ci if (!is_after_deserialization) { 22321cb0ef41Sopenharmony_ci Handle<FixedArray> export_wrappers; 22331cb0ef41Sopenharmony_ci if (is_after_cache_hit) { 22341cb0ef41Sopenharmony_ci // TODO(thibaudm): Look into sharing wrappers. 22351cb0ef41Sopenharmony_ci CompileJsToWasmWrappers(isolate_, module, &export_wrappers); 22361cb0ef41Sopenharmony_ci } else { 22371cb0ef41Sopenharmony_ci compilation_state->FinalizeJSToWasmWrappers(isolate_, module, 22381cb0ef41Sopenharmony_ci &export_wrappers); 22391cb0ef41Sopenharmony_ci } 22401cb0ef41Sopenharmony_ci module_object_->set_export_wrappers(*export_wrappers); 22411cb0ef41Sopenharmony_ci } 22421cb0ef41Sopenharmony_ci // We can only update the feature counts once the entire compile is done. 22431cb0ef41Sopenharmony_ci compilation_state->PublishDetectedFeatures(isolate_); 22441cb0ef41Sopenharmony_ci 22451cb0ef41Sopenharmony_ci // We might need to recompile the module for debugging, if the debugger was 22461cb0ef41Sopenharmony_ci // enabled while streaming compilation was running. Since handling this while 22471cb0ef41Sopenharmony_ci // compiling via streaming is tricky, we just tier down now, before publishing 22481cb0ef41Sopenharmony_ci // the module. 22491cb0ef41Sopenharmony_ci if (native_module_->IsTieredDown()) native_module_->RecompileForTiering(); 22501cb0ef41Sopenharmony_ci 22511cb0ef41Sopenharmony_ci // Finally, log all generated code (it does not matter if this happens 22521cb0ef41Sopenharmony_ci // repeatedly in case the script is shared). 22531cb0ef41Sopenharmony_ci native_module_->LogWasmCodes(isolate_, module_object_->script()); 22541cb0ef41Sopenharmony_ci 22551cb0ef41Sopenharmony_ci FinishModule(); 22561cb0ef41Sopenharmony_ci} 22571cb0ef41Sopenharmony_ci 22581cb0ef41Sopenharmony_civoid AsyncCompileJob::DecodeFailed(const WasmError& error) { 22591cb0ef41Sopenharmony_ci ErrorThrower thrower(isolate_, api_method_name_); 22601cb0ef41Sopenharmony_ci thrower.CompileFailed(error); 22611cb0ef41Sopenharmony_ci // {job} keeps the {this} pointer alive. 22621cb0ef41Sopenharmony_ci std::shared_ptr<AsyncCompileJob> job = 22631cb0ef41Sopenharmony_ci GetWasmEngine()->RemoveCompileJob(this); 22641cb0ef41Sopenharmony_ci resolver_->OnCompilationFailed(thrower.Reify()); 22651cb0ef41Sopenharmony_ci} 22661cb0ef41Sopenharmony_ci 22671cb0ef41Sopenharmony_civoid AsyncCompileJob::AsyncCompileFailed() { 22681cb0ef41Sopenharmony_ci ErrorThrower thrower(isolate_, api_method_name_); 22691cb0ef41Sopenharmony_ci DCHECK_EQ(native_module_->module()->origin, kWasmOrigin); 22701cb0ef41Sopenharmony_ci const bool lazy_module = wasm_lazy_compilation_; 22711cb0ef41Sopenharmony_ci ValidateSequentially(native_module_->module(), native_module_.get(), 22721cb0ef41Sopenharmony_ci isolate_->counters(), isolate_->allocator(), &thrower, 22731cb0ef41Sopenharmony_ci lazy_module); 22741cb0ef41Sopenharmony_ci DCHECK(thrower.error()); 22751cb0ef41Sopenharmony_ci // {job} keeps the {this} pointer alive. 22761cb0ef41Sopenharmony_ci std::shared_ptr<AsyncCompileJob> job = 22771cb0ef41Sopenharmony_ci GetWasmEngine()->RemoveCompileJob(this); 22781cb0ef41Sopenharmony_ci resolver_->OnCompilationFailed(thrower.Reify()); 22791cb0ef41Sopenharmony_ci} 22801cb0ef41Sopenharmony_ci 22811cb0ef41Sopenharmony_civoid AsyncCompileJob::AsyncCompileSucceeded(Handle<WasmModuleObject> result) { 22821cb0ef41Sopenharmony_ci TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm.detailed"), 22831cb0ef41Sopenharmony_ci "wasm.OnCompilationSucceeded"); 22841cb0ef41Sopenharmony_ci // We have to make sure that an "incumbent context" is available in case 22851cb0ef41Sopenharmony_ci // the module's start function calls out to Blink. 22861cb0ef41Sopenharmony_ci Local<v8::Context> backup_incumbent_context = 22871cb0ef41Sopenharmony_ci Utils::ToLocal(incumbent_context_); 22881cb0ef41Sopenharmony_ci v8::Context::BackupIncumbentScope incumbent(backup_incumbent_context); 22891cb0ef41Sopenharmony_ci resolver_->OnCompilationSucceeded(result); 22901cb0ef41Sopenharmony_ci} 22911cb0ef41Sopenharmony_ci 22921cb0ef41Sopenharmony_ciclass AsyncCompileJob::CompilationStateCallback 22931cb0ef41Sopenharmony_ci : public CompilationEventCallback { 22941cb0ef41Sopenharmony_ci public: 22951cb0ef41Sopenharmony_ci explicit CompilationStateCallback(AsyncCompileJob* job) : job_(job) {} 22961cb0ef41Sopenharmony_ci 22971cb0ef41Sopenharmony_ci void call(CompilationEvent event) override { 22981cb0ef41Sopenharmony_ci // This callback is only being called from a foreground task. 22991cb0ef41Sopenharmony_ci switch (event) { 23001cb0ef41Sopenharmony_ci case CompilationEvent::kFinishedExportWrappers: 23011cb0ef41Sopenharmony_ci // Even if baseline compilation units finish first, we trigger the 23021cb0ef41Sopenharmony_ci // "kFinishedExportWrappers" event first. 23031cb0ef41Sopenharmony_ci DCHECK(!last_event_.has_value()); 23041cb0ef41Sopenharmony_ci break; 23051cb0ef41Sopenharmony_ci case CompilationEvent::kFinishedBaselineCompilation: 23061cb0ef41Sopenharmony_ci DCHECK_EQ(CompilationEvent::kFinishedExportWrappers, last_event_); 23071cb0ef41Sopenharmony_ci if (job_->DecrementAndCheckFinisherCount()) { 23081cb0ef41Sopenharmony_ci // Install the native module in the cache, or reuse a conflicting one. 23091cb0ef41Sopenharmony_ci // If we get a conflicting module, wait until we are back in the 23101cb0ef41Sopenharmony_ci // main thread to update {job_->native_module_} to avoid a data race. 23111cb0ef41Sopenharmony_ci std::shared_ptr<NativeModule> native_module = job_->native_module_; 23121cb0ef41Sopenharmony_ci bool cache_hit = !GetWasmEngine()->UpdateNativeModuleCache( 23131cb0ef41Sopenharmony_ci false, &native_module, job_->isolate_); 23141cb0ef41Sopenharmony_ci DCHECK_EQ(cache_hit, native_module != job_->native_module_); 23151cb0ef41Sopenharmony_ci job_->DoSync<CompileFinished>(cache_hit ? std::move(native_module) 23161cb0ef41Sopenharmony_ci : nullptr); 23171cb0ef41Sopenharmony_ci } 23181cb0ef41Sopenharmony_ci break; 23191cb0ef41Sopenharmony_ci case CompilationEvent::kFinishedCompilationChunk: 23201cb0ef41Sopenharmony_ci DCHECK(CompilationEvent::kFinishedBaselineCompilation == last_event_ || 23211cb0ef41Sopenharmony_ci CompilationEvent::kFinishedCompilationChunk == last_event_); 23221cb0ef41Sopenharmony_ci break; 23231cb0ef41Sopenharmony_ci case CompilationEvent::kFinishedTopTierCompilation: 23241cb0ef41Sopenharmony_ci DCHECK(CompilationEvent::kFinishedBaselineCompilation == last_event_); 23251cb0ef41Sopenharmony_ci // At this point, the job will already be gone, thus do not access it 23261cb0ef41Sopenharmony_ci // here. 23271cb0ef41Sopenharmony_ci break; 23281cb0ef41Sopenharmony_ci case CompilationEvent::kFailedCompilation: 23291cb0ef41Sopenharmony_ci DCHECK(!last_event_.has_value() || 23301cb0ef41Sopenharmony_ci last_event_ == CompilationEvent::kFinishedExportWrappers); 23311cb0ef41Sopenharmony_ci if (job_->DecrementAndCheckFinisherCount()) { 23321cb0ef41Sopenharmony_ci // Don't update {job_->native_module_} to avoid data races with other 23331cb0ef41Sopenharmony_ci // compilation threads. Use a copy of the shared pointer instead. 23341cb0ef41Sopenharmony_ci std::shared_ptr<NativeModule> native_module = job_->native_module_; 23351cb0ef41Sopenharmony_ci GetWasmEngine()->UpdateNativeModuleCache(true, &native_module, 23361cb0ef41Sopenharmony_ci job_->isolate_); 23371cb0ef41Sopenharmony_ci job_->DoSync<CompileFailed>(); 23381cb0ef41Sopenharmony_ci } 23391cb0ef41Sopenharmony_ci break; 23401cb0ef41Sopenharmony_ci case CompilationEvent::kFinishedRecompilation: 23411cb0ef41Sopenharmony_ci // This event can happen either before or after 23421cb0ef41Sopenharmony_ci // {kFinishedTopTierCompilation}, hence don't remember this in 23431cb0ef41Sopenharmony_ci // {last_event_}. 23441cb0ef41Sopenharmony_ci return; 23451cb0ef41Sopenharmony_ci } 23461cb0ef41Sopenharmony_ci#ifdef DEBUG 23471cb0ef41Sopenharmony_ci last_event_ = event; 23481cb0ef41Sopenharmony_ci#endif 23491cb0ef41Sopenharmony_ci } 23501cb0ef41Sopenharmony_ci 23511cb0ef41Sopenharmony_ci private: 23521cb0ef41Sopenharmony_ci AsyncCompileJob* job_; 23531cb0ef41Sopenharmony_ci#ifdef DEBUG 23541cb0ef41Sopenharmony_ci // This will be modified by different threads, but they externally 23551cb0ef41Sopenharmony_ci // synchronize, so no explicit synchronization (currently) needed here. 23561cb0ef41Sopenharmony_ci base::Optional<CompilationEvent> last_event_; 23571cb0ef41Sopenharmony_ci#endif 23581cb0ef41Sopenharmony_ci}; 23591cb0ef41Sopenharmony_ci 23601cb0ef41Sopenharmony_ci// A closure to run a compilation step (either as foreground or background 23611cb0ef41Sopenharmony_ci// task) and schedule the next step(s), if any. 23621cb0ef41Sopenharmony_ciclass AsyncCompileJob::CompileStep { 23631cb0ef41Sopenharmony_ci public: 23641cb0ef41Sopenharmony_ci virtual ~CompileStep() = default; 23651cb0ef41Sopenharmony_ci 23661cb0ef41Sopenharmony_ci void Run(AsyncCompileJob* job, bool on_foreground) { 23671cb0ef41Sopenharmony_ci if (on_foreground) { 23681cb0ef41Sopenharmony_ci HandleScope scope(job->isolate_); 23691cb0ef41Sopenharmony_ci SaveAndSwitchContext saved_context(job->isolate_, *job->native_context_); 23701cb0ef41Sopenharmony_ci RunInForeground(job); 23711cb0ef41Sopenharmony_ci } else { 23721cb0ef41Sopenharmony_ci RunInBackground(job); 23731cb0ef41Sopenharmony_ci } 23741cb0ef41Sopenharmony_ci } 23751cb0ef41Sopenharmony_ci 23761cb0ef41Sopenharmony_ci virtual void RunInForeground(AsyncCompileJob*) { UNREACHABLE(); } 23771cb0ef41Sopenharmony_ci virtual void RunInBackground(AsyncCompileJob*) { UNREACHABLE(); } 23781cb0ef41Sopenharmony_ci}; 23791cb0ef41Sopenharmony_ci 23801cb0ef41Sopenharmony_ciclass AsyncCompileJob::CompileTask : public CancelableTask { 23811cb0ef41Sopenharmony_ci public: 23821cb0ef41Sopenharmony_ci CompileTask(AsyncCompileJob* job, bool on_foreground) 23831cb0ef41Sopenharmony_ci // We only manage the background tasks with the {CancelableTaskManager} of 23841cb0ef41Sopenharmony_ci // the {AsyncCompileJob}. Foreground tasks are managed by the system's 23851cb0ef41Sopenharmony_ci // {CancelableTaskManager}. Background tasks cannot spawn tasks managed by 23861cb0ef41Sopenharmony_ci // their own task manager. 23871cb0ef41Sopenharmony_ci : CancelableTask(on_foreground ? job->isolate_->cancelable_task_manager() 23881cb0ef41Sopenharmony_ci : &job->background_task_manager_), 23891cb0ef41Sopenharmony_ci job_(job), 23901cb0ef41Sopenharmony_ci on_foreground_(on_foreground) {} 23911cb0ef41Sopenharmony_ci 23921cb0ef41Sopenharmony_ci ~CompileTask() override { 23931cb0ef41Sopenharmony_ci if (job_ != nullptr && on_foreground_) ResetPendingForegroundTask(); 23941cb0ef41Sopenharmony_ci } 23951cb0ef41Sopenharmony_ci 23961cb0ef41Sopenharmony_ci void RunInternal() final { 23971cb0ef41Sopenharmony_ci if (!job_) return; 23981cb0ef41Sopenharmony_ci if (on_foreground_) ResetPendingForegroundTask(); 23991cb0ef41Sopenharmony_ci job_->step_->Run(job_, on_foreground_); 24001cb0ef41Sopenharmony_ci // After execution, reset {job_} such that we don't try to reset the pending 24011cb0ef41Sopenharmony_ci // foreground task when the task is deleted. 24021cb0ef41Sopenharmony_ci job_ = nullptr; 24031cb0ef41Sopenharmony_ci } 24041cb0ef41Sopenharmony_ci 24051cb0ef41Sopenharmony_ci void Cancel() { 24061cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(job_); 24071cb0ef41Sopenharmony_ci job_ = nullptr; 24081cb0ef41Sopenharmony_ci } 24091cb0ef41Sopenharmony_ci 24101cb0ef41Sopenharmony_ci private: 24111cb0ef41Sopenharmony_ci // {job_} will be cleared to cancel a pending task. 24121cb0ef41Sopenharmony_ci AsyncCompileJob* job_; 24131cb0ef41Sopenharmony_ci bool on_foreground_; 24141cb0ef41Sopenharmony_ci 24151cb0ef41Sopenharmony_ci void ResetPendingForegroundTask() const { 24161cb0ef41Sopenharmony_ci DCHECK_EQ(this, job_->pending_foreground_task_); 24171cb0ef41Sopenharmony_ci job_->pending_foreground_task_ = nullptr; 24181cb0ef41Sopenharmony_ci } 24191cb0ef41Sopenharmony_ci}; 24201cb0ef41Sopenharmony_ci 24211cb0ef41Sopenharmony_civoid AsyncCompileJob::StartForegroundTask() { 24221cb0ef41Sopenharmony_ci DCHECK_NULL(pending_foreground_task_); 24231cb0ef41Sopenharmony_ci 24241cb0ef41Sopenharmony_ci auto new_task = std::make_unique<CompileTask>(this, true); 24251cb0ef41Sopenharmony_ci pending_foreground_task_ = new_task.get(); 24261cb0ef41Sopenharmony_ci foreground_task_runner_->PostTask(std::move(new_task)); 24271cb0ef41Sopenharmony_ci} 24281cb0ef41Sopenharmony_ci 24291cb0ef41Sopenharmony_civoid AsyncCompileJob::ExecuteForegroundTaskImmediately() { 24301cb0ef41Sopenharmony_ci DCHECK_NULL(pending_foreground_task_); 24311cb0ef41Sopenharmony_ci 24321cb0ef41Sopenharmony_ci auto new_task = std::make_unique<CompileTask>(this, true); 24331cb0ef41Sopenharmony_ci pending_foreground_task_ = new_task.get(); 24341cb0ef41Sopenharmony_ci new_task->Run(); 24351cb0ef41Sopenharmony_ci} 24361cb0ef41Sopenharmony_ci 24371cb0ef41Sopenharmony_civoid AsyncCompileJob::CancelPendingForegroundTask() { 24381cb0ef41Sopenharmony_ci if (!pending_foreground_task_) return; 24391cb0ef41Sopenharmony_ci pending_foreground_task_->Cancel(); 24401cb0ef41Sopenharmony_ci pending_foreground_task_ = nullptr; 24411cb0ef41Sopenharmony_ci} 24421cb0ef41Sopenharmony_ci 24431cb0ef41Sopenharmony_civoid AsyncCompileJob::StartBackgroundTask() { 24441cb0ef41Sopenharmony_ci auto task = std::make_unique<CompileTask>(this, false); 24451cb0ef41Sopenharmony_ci 24461cb0ef41Sopenharmony_ci // If --wasm-num-compilation-tasks=0 is passed, do only spawn foreground 24471cb0ef41Sopenharmony_ci // tasks. This is used to make timing deterministic. 24481cb0ef41Sopenharmony_ci if (FLAG_wasm_num_compilation_tasks > 0) { 24491cb0ef41Sopenharmony_ci V8::GetCurrentPlatform()->CallOnWorkerThread(std::move(task)); 24501cb0ef41Sopenharmony_ci } else { 24511cb0ef41Sopenharmony_ci foreground_task_runner_->PostTask(std::move(task)); 24521cb0ef41Sopenharmony_ci } 24531cb0ef41Sopenharmony_ci} 24541cb0ef41Sopenharmony_ci 24551cb0ef41Sopenharmony_citemplate <typename Step, 24561cb0ef41Sopenharmony_ci AsyncCompileJob::UseExistingForegroundTask use_existing_fg_task, 24571cb0ef41Sopenharmony_ci typename... Args> 24581cb0ef41Sopenharmony_civoid AsyncCompileJob::DoSync(Args&&... args) { 24591cb0ef41Sopenharmony_ci NextStep<Step>(std::forward<Args>(args)...); 24601cb0ef41Sopenharmony_ci if (use_existing_fg_task && pending_foreground_task_ != nullptr) return; 24611cb0ef41Sopenharmony_ci StartForegroundTask(); 24621cb0ef41Sopenharmony_ci} 24631cb0ef41Sopenharmony_ci 24641cb0ef41Sopenharmony_citemplate <typename Step, typename... Args> 24651cb0ef41Sopenharmony_civoid AsyncCompileJob::DoImmediately(Args&&... args) { 24661cb0ef41Sopenharmony_ci NextStep<Step>(std::forward<Args>(args)...); 24671cb0ef41Sopenharmony_ci ExecuteForegroundTaskImmediately(); 24681cb0ef41Sopenharmony_ci} 24691cb0ef41Sopenharmony_ci 24701cb0ef41Sopenharmony_citemplate <typename Step, typename... Args> 24711cb0ef41Sopenharmony_civoid AsyncCompileJob::DoAsync(Args&&... args) { 24721cb0ef41Sopenharmony_ci NextStep<Step>(std::forward<Args>(args)...); 24731cb0ef41Sopenharmony_ci StartBackgroundTask(); 24741cb0ef41Sopenharmony_ci} 24751cb0ef41Sopenharmony_ci 24761cb0ef41Sopenharmony_citemplate <typename Step, typename... Args> 24771cb0ef41Sopenharmony_civoid AsyncCompileJob::NextStep(Args&&... args) { 24781cb0ef41Sopenharmony_ci step_.reset(new Step(std::forward<Args>(args)...)); 24791cb0ef41Sopenharmony_ci} 24801cb0ef41Sopenharmony_ci 24811cb0ef41Sopenharmony_ci//========================================================================== 24821cb0ef41Sopenharmony_ci// Step 1: (async) Decode the module. 24831cb0ef41Sopenharmony_ci//========================================================================== 24841cb0ef41Sopenharmony_ciclass AsyncCompileJob::DecodeModule : public AsyncCompileJob::CompileStep { 24851cb0ef41Sopenharmony_ci public: 24861cb0ef41Sopenharmony_ci explicit DecodeModule(Counters* counters, 24871cb0ef41Sopenharmony_ci std::shared_ptr<metrics::Recorder> metrics_recorder) 24881cb0ef41Sopenharmony_ci : counters_(counters), metrics_recorder_(std::move(metrics_recorder)) {} 24891cb0ef41Sopenharmony_ci 24901cb0ef41Sopenharmony_ci void RunInBackground(AsyncCompileJob* job) override { 24911cb0ef41Sopenharmony_ci ModuleResult result; 24921cb0ef41Sopenharmony_ci { 24931cb0ef41Sopenharmony_ci DisallowHandleAllocation no_handle; 24941cb0ef41Sopenharmony_ci DisallowGarbageCollection no_gc; 24951cb0ef41Sopenharmony_ci // Decode the module bytes. 24961cb0ef41Sopenharmony_ci TRACE_COMPILE("(1) Decoding module...\n"); 24971cb0ef41Sopenharmony_ci TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm.detailed"), 24981cb0ef41Sopenharmony_ci "wasm.DecodeModule"); 24991cb0ef41Sopenharmony_ci auto enabled_features = job->enabled_features_; 25001cb0ef41Sopenharmony_ci result = DecodeWasmModule( 25011cb0ef41Sopenharmony_ci enabled_features, job->wire_bytes_.start(), job->wire_bytes_.end(), 25021cb0ef41Sopenharmony_ci false, kWasmOrigin, counters_, metrics_recorder_, job->context_id(), 25031cb0ef41Sopenharmony_ci DecodingMethod::kAsync, GetWasmEngine()->allocator()); 25041cb0ef41Sopenharmony_ci 25051cb0ef41Sopenharmony_ci // Validate lazy functions here if requested. 25061cb0ef41Sopenharmony_ci if (!FLAG_wasm_lazy_validation && result.ok()) { 25071cb0ef41Sopenharmony_ci const WasmModule* module = result.value().get(); 25081cb0ef41Sopenharmony_ci DCHECK_EQ(module->origin, kWasmOrigin); 25091cb0ef41Sopenharmony_ci const bool lazy_module = job->wasm_lazy_compilation_; 25101cb0ef41Sopenharmony_ci if (MayCompriseLazyFunctions(module, enabled_features, lazy_module)) { 25111cb0ef41Sopenharmony_ci auto allocator = GetWasmEngine()->allocator(); 25121cb0ef41Sopenharmony_ci int start = module->num_imported_functions; 25131cb0ef41Sopenharmony_ci int end = start + module->num_declared_functions; 25141cb0ef41Sopenharmony_ci 25151cb0ef41Sopenharmony_ci for (int func_index = start; func_index < end; func_index++) { 25161cb0ef41Sopenharmony_ci const WasmFunction* func = &module->functions[func_index]; 25171cb0ef41Sopenharmony_ci base::Vector<const uint8_t> code = 25181cb0ef41Sopenharmony_ci job->wire_bytes_.GetFunctionBytes(func); 25191cb0ef41Sopenharmony_ci 25201cb0ef41Sopenharmony_ci CompileStrategy strategy = GetCompileStrategy( 25211cb0ef41Sopenharmony_ci module, enabled_features, func_index, lazy_module); 25221cb0ef41Sopenharmony_ci bool validate_lazily_compiled_function = 25231cb0ef41Sopenharmony_ci strategy == CompileStrategy::kLazy || 25241cb0ef41Sopenharmony_ci strategy == CompileStrategy::kLazyBaselineEagerTopTier; 25251cb0ef41Sopenharmony_ci if (validate_lazily_compiled_function) { 25261cb0ef41Sopenharmony_ci DecodeResult function_result = 25271cb0ef41Sopenharmony_ci ValidateSingleFunction(module, func_index, code, counters_, 25281cb0ef41Sopenharmony_ci allocator, enabled_features); 25291cb0ef41Sopenharmony_ci if (function_result.failed()) { 25301cb0ef41Sopenharmony_ci result = ModuleResult(function_result.error()); 25311cb0ef41Sopenharmony_ci break; 25321cb0ef41Sopenharmony_ci } 25331cb0ef41Sopenharmony_ci } 25341cb0ef41Sopenharmony_ci } 25351cb0ef41Sopenharmony_ci } 25361cb0ef41Sopenharmony_ci } 25371cb0ef41Sopenharmony_ci } 25381cb0ef41Sopenharmony_ci if (result.failed()) { 25391cb0ef41Sopenharmony_ci // Decoding failure; reject the promise and clean up. 25401cb0ef41Sopenharmony_ci job->DoSync<DecodeFail>(std::move(result).error()); 25411cb0ef41Sopenharmony_ci } else { 25421cb0ef41Sopenharmony_ci // Decode passed. 25431cb0ef41Sopenharmony_ci std::shared_ptr<WasmModule> module = std::move(result).value(); 25441cb0ef41Sopenharmony_ci const bool include_liftoff = FLAG_liftoff; 25451cb0ef41Sopenharmony_ci size_t code_size_estimate = 25461cb0ef41Sopenharmony_ci wasm::WasmCodeManager::EstimateNativeModuleCodeSize( 25471cb0ef41Sopenharmony_ci module.get(), include_liftoff, job->dynamic_tiering_); 25481cb0ef41Sopenharmony_ci job->DoSync<PrepareAndStartCompile>(std::move(module), true, 25491cb0ef41Sopenharmony_ci code_size_estimate); 25501cb0ef41Sopenharmony_ci } 25511cb0ef41Sopenharmony_ci } 25521cb0ef41Sopenharmony_ci 25531cb0ef41Sopenharmony_ci private: 25541cb0ef41Sopenharmony_ci Counters* const counters_; 25551cb0ef41Sopenharmony_ci std::shared_ptr<metrics::Recorder> metrics_recorder_; 25561cb0ef41Sopenharmony_ci}; 25571cb0ef41Sopenharmony_ci 25581cb0ef41Sopenharmony_ci//========================================================================== 25591cb0ef41Sopenharmony_ci// Step 1b: (sync) Fail decoding the module. 25601cb0ef41Sopenharmony_ci//========================================================================== 25611cb0ef41Sopenharmony_ciclass AsyncCompileJob::DecodeFail : public CompileStep { 25621cb0ef41Sopenharmony_ci public: 25631cb0ef41Sopenharmony_ci explicit DecodeFail(WasmError error) : error_(std::move(error)) {} 25641cb0ef41Sopenharmony_ci 25651cb0ef41Sopenharmony_ci private: 25661cb0ef41Sopenharmony_ci WasmError error_; 25671cb0ef41Sopenharmony_ci 25681cb0ef41Sopenharmony_ci void RunInForeground(AsyncCompileJob* job) override { 25691cb0ef41Sopenharmony_ci TRACE_COMPILE("(1b) Decoding failed.\n"); 25701cb0ef41Sopenharmony_ci // {job_} is deleted in DecodeFailed, therefore the {return}. 25711cb0ef41Sopenharmony_ci return job->DecodeFailed(error_); 25721cb0ef41Sopenharmony_ci } 25731cb0ef41Sopenharmony_ci}; 25741cb0ef41Sopenharmony_ci 25751cb0ef41Sopenharmony_ci//========================================================================== 25761cb0ef41Sopenharmony_ci// Step 2 (sync): Create heap-allocated data and start compile. 25771cb0ef41Sopenharmony_ci//========================================================================== 25781cb0ef41Sopenharmony_ciclass AsyncCompileJob::PrepareAndStartCompile : public CompileStep { 25791cb0ef41Sopenharmony_ci public: 25801cb0ef41Sopenharmony_ci PrepareAndStartCompile(std::shared_ptr<const WasmModule> module, 25811cb0ef41Sopenharmony_ci bool start_compilation, size_t code_size_estimate) 25821cb0ef41Sopenharmony_ci : module_(std::move(module)), 25831cb0ef41Sopenharmony_ci start_compilation_(start_compilation), 25841cb0ef41Sopenharmony_ci code_size_estimate_(code_size_estimate) {} 25851cb0ef41Sopenharmony_ci 25861cb0ef41Sopenharmony_ci private: 25871cb0ef41Sopenharmony_ci void RunInForeground(AsyncCompileJob* job) override { 25881cb0ef41Sopenharmony_ci TRACE_COMPILE("(2) Prepare and start compile...\n"); 25891cb0ef41Sopenharmony_ci 25901cb0ef41Sopenharmony_ci const bool streaming = job->wire_bytes_.length() == 0; 25911cb0ef41Sopenharmony_ci if (streaming) { 25921cb0ef41Sopenharmony_ci // Streaming compilation already checked for cache hits. 25931cb0ef41Sopenharmony_ci job->CreateNativeModule(module_, code_size_estimate_); 25941cb0ef41Sopenharmony_ci } else if (job->GetOrCreateNativeModule(std::move(module_), 25951cb0ef41Sopenharmony_ci code_size_estimate_)) { 25961cb0ef41Sopenharmony_ci job->FinishCompile(true); 25971cb0ef41Sopenharmony_ci return; 25981cb0ef41Sopenharmony_ci } 25991cb0ef41Sopenharmony_ci 26001cb0ef41Sopenharmony_ci // Make sure all compilation tasks stopped running. Decoding (async step) 26011cb0ef41Sopenharmony_ci // is done. 26021cb0ef41Sopenharmony_ci job->background_task_manager_.CancelAndWait(); 26031cb0ef41Sopenharmony_ci 26041cb0ef41Sopenharmony_ci CompilationStateImpl* compilation_state = 26051cb0ef41Sopenharmony_ci Impl(job->native_module_->compilation_state()); 26061cb0ef41Sopenharmony_ci compilation_state->AddCallback( 26071cb0ef41Sopenharmony_ci std::make_unique<CompilationStateCallback>(job)); 26081cb0ef41Sopenharmony_ci if (base::TimeTicks::IsHighResolution()) { 26091cb0ef41Sopenharmony_ci auto compile_mode = job->stream_ == nullptr 26101cb0ef41Sopenharmony_ci ? CompilationTimeCallback::kAsync 26111cb0ef41Sopenharmony_ci : CompilationTimeCallback::kStreaming; 26121cb0ef41Sopenharmony_ci compilation_state->AddCallback(std::make_unique<CompilationTimeCallback>( 26131cb0ef41Sopenharmony_ci job->isolate_->async_counters(), job->isolate_->metrics_recorder(), 26141cb0ef41Sopenharmony_ci job->context_id_, job->native_module_, compile_mode)); 26151cb0ef41Sopenharmony_ci } 26161cb0ef41Sopenharmony_ci 26171cb0ef41Sopenharmony_ci if (start_compilation_) { 26181cb0ef41Sopenharmony_ci std::unique_ptr<CompilationUnitBuilder> builder = 26191cb0ef41Sopenharmony_ci InitializeCompilation(job->isolate(), job->native_module_.get()); 26201cb0ef41Sopenharmony_ci compilation_state->InitializeCompilationUnits(std::move(builder)); 26211cb0ef41Sopenharmony_ci // We are in single-threaded mode, so there are no worker tasks that will 26221cb0ef41Sopenharmony_ci // do the compilation. We call {WaitForCompilationEvent} here so that the 26231cb0ef41Sopenharmony_ci // main thread paticipates and finishes the compilation. 26241cb0ef41Sopenharmony_ci if (FLAG_wasm_num_compilation_tasks == 0) { 26251cb0ef41Sopenharmony_ci compilation_state->WaitForCompilationEvent( 26261cb0ef41Sopenharmony_ci CompilationEvent::kFinishedBaselineCompilation); 26271cb0ef41Sopenharmony_ci } 26281cb0ef41Sopenharmony_ci } 26291cb0ef41Sopenharmony_ci } 26301cb0ef41Sopenharmony_ci 26311cb0ef41Sopenharmony_ci const std::shared_ptr<const WasmModule> module_; 26321cb0ef41Sopenharmony_ci const bool start_compilation_; 26331cb0ef41Sopenharmony_ci const size_t code_size_estimate_; 26341cb0ef41Sopenharmony_ci}; 26351cb0ef41Sopenharmony_ci 26361cb0ef41Sopenharmony_ci//========================================================================== 26371cb0ef41Sopenharmony_ci// Step 3a (sync): Compilation failed. 26381cb0ef41Sopenharmony_ci//========================================================================== 26391cb0ef41Sopenharmony_ciclass AsyncCompileJob::CompileFailed : public CompileStep { 26401cb0ef41Sopenharmony_ci private: 26411cb0ef41Sopenharmony_ci void RunInForeground(AsyncCompileJob* job) override { 26421cb0ef41Sopenharmony_ci TRACE_COMPILE("(3a) Compilation failed\n"); 26431cb0ef41Sopenharmony_ci DCHECK(job->native_module_->compilation_state()->failed()); 26441cb0ef41Sopenharmony_ci 26451cb0ef41Sopenharmony_ci // {job_} is deleted in AsyncCompileFailed, therefore the {return}. 26461cb0ef41Sopenharmony_ci return job->AsyncCompileFailed(); 26471cb0ef41Sopenharmony_ci } 26481cb0ef41Sopenharmony_ci}; 26491cb0ef41Sopenharmony_ci 26501cb0ef41Sopenharmony_cinamespace { 26511cb0ef41Sopenharmony_ciclass SampleTopTierCodeSizeCallback : public CompilationEventCallback { 26521cb0ef41Sopenharmony_ci public: 26531cb0ef41Sopenharmony_ci explicit SampleTopTierCodeSizeCallback( 26541cb0ef41Sopenharmony_ci std::weak_ptr<NativeModule> native_module) 26551cb0ef41Sopenharmony_ci : native_module_(std::move(native_module)) {} 26561cb0ef41Sopenharmony_ci 26571cb0ef41Sopenharmony_ci void call(CompilationEvent event) override { 26581cb0ef41Sopenharmony_ci if (event != CompilationEvent::kFinishedTopTierCompilation) return; 26591cb0ef41Sopenharmony_ci if (std::shared_ptr<NativeModule> native_module = native_module_.lock()) { 26601cb0ef41Sopenharmony_ci GetWasmEngine()->SampleTopTierCodeSizeInAllIsolates(native_module); 26611cb0ef41Sopenharmony_ci } 26621cb0ef41Sopenharmony_ci } 26631cb0ef41Sopenharmony_ci 26641cb0ef41Sopenharmony_ci private: 26651cb0ef41Sopenharmony_ci std::weak_ptr<NativeModule> native_module_; 26661cb0ef41Sopenharmony_ci}; 26671cb0ef41Sopenharmony_ci} // namespace 26681cb0ef41Sopenharmony_ci 26691cb0ef41Sopenharmony_ci//========================================================================== 26701cb0ef41Sopenharmony_ci// Step 3b (sync): Compilation finished. 26711cb0ef41Sopenharmony_ci//========================================================================== 26721cb0ef41Sopenharmony_ciclass AsyncCompileJob::CompileFinished : public CompileStep { 26731cb0ef41Sopenharmony_ci public: 26741cb0ef41Sopenharmony_ci explicit CompileFinished(std::shared_ptr<NativeModule> cached_native_module) 26751cb0ef41Sopenharmony_ci : cached_native_module_(std::move(cached_native_module)) {} 26761cb0ef41Sopenharmony_ci 26771cb0ef41Sopenharmony_ci private: 26781cb0ef41Sopenharmony_ci void RunInForeground(AsyncCompileJob* job) override { 26791cb0ef41Sopenharmony_ci TRACE_COMPILE("(3b) Compilation finished\n"); 26801cb0ef41Sopenharmony_ci if (cached_native_module_) { 26811cb0ef41Sopenharmony_ci job->native_module_ = cached_native_module_; 26821cb0ef41Sopenharmony_ci } else { 26831cb0ef41Sopenharmony_ci DCHECK(!job->native_module_->compilation_state()->failed()); 26841cb0ef41Sopenharmony_ci // Sample the generated code size when baseline compilation finished. 26851cb0ef41Sopenharmony_ci job->native_module_->SampleCodeSize(job->isolate_->counters(), 26861cb0ef41Sopenharmony_ci NativeModule::kAfterBaseline); 26871cb0ef41Sopenharmony_ci // Also, set a callback to sample the code size after top-tier compilation 26881cb0ef41Sopenharmony_ci // finished. This callback will *not* keep the NativeModule alive. 26891cb0ef41Sopenharmony_ci job->native_module_->compilation_state()->AddCallback( 26901cb0ef41Sopenharmony_ci std::make_unique<SampleTopTierCodeSizeCallback>(job->native_module_)); 26911cb0ef41Sopenharmony_ci } 26921cb0ef41Sopenharmony_ci // Then finalize and publish the generated module. 26931cb0ef41Sopenharmony_ci job->FinishCompile(cached_native_module_ != nullptr); 26941cb0ef41Sopenharmony_ci } 26951cb0ef41Sopenharmony_ci 26961cb0ef41Sopenharmony_ci std::shared_ptr<NativeModule> cached_native_module_; 26971cb0ef41Sopenharmony_ci}; 26981cb0ef41Sopenharmony_ci 26991cb0ef41Sopenharmony_civoid AsyncCompileJob::FinishModule() { 27001cb0ef41Sopenharmony_ci TRACE_COMPILE("(4) Finish module...\n"); 27011cb0ef41Sopenharmony_ci AsyncCompileSucceeded(module_object_); 27021cb0ef41Sopenharmony_ci GetWasmEngine()->RemoveCompileJob(this); 27031cb0ef41Sopenharmony_ci} 27041cb0ef41Sopenharmony_ci 27051cb0ef41Sopenharmony_ciAsyncStreamingProcessor::AsyncStreamingProcessor( 27061cb0ef41Sopenharmony_ci AsyncCompileJob* job, std::shared_ptr<Counters> async_counters, 27071cb0ef41Sopenharmony_ci AccountingAllocator* allocator) 27081cb0ef41Sopenharmony_ci : decoder_(job->enabled_features_), 27091cb0ef41Sopenharmony_ci job_(job), 27101cb0ef41Sopenharmony_ci compilation_unit_builder_(nullptr), 27111cb0ef41Sopenharmony_ci async_counters_(async_counters), 27121cb0ef41Sopenharmony_ci allocator_(allocator) {} 27131cb0ef41Sopenharmony_ci 27141cb0ef41Sopenharmony_ciAsyncStreamingProcessor::~AsyncStreamingProcessor() { 27151cb0ef41Sopenharmony_ci if (job_->native_module_ && job_->native_module_->wire_bytes().empty()) { 27161cb0ef41Sopenharmony_ci // Clean up the temporary cache entry. 27171cb0ef41Sopenharmony_ci GetWasmEngine()->StreamingCompilationFailed(prefix_hash_); 27181cb0ef41Sopenharmony_ci } 27191cb0ef41Sopenharmony_ci} 27201cb0ef41Sopenharmony_ci 27211cb0ef41Sopenharmony_civoid AsyncStreamingProcessor::FinishAsyncCompileJobWithError( 27221cb0ef41Sopenharmony_ci const WasmError& error) { 27231cb0ef41Sopenharmony_ci DCHECK(error.has_error()); 27241cb0ef41Sopenharmony_ci // Make sure all background tasks stopped executing before we change the state 27251cb0ef41Sopenharmony_ci // of the AsyncCompileJob to DecodeFail. 27261cb0ef41Sopenharmony_ci job_->background_task_manager_.CancelAndWait(); 27271cb0ef41Sopenharmony_ci 27281cb0ef41Sopenharmony_ci // Record event metrics. 27291cb0ef41Sopenharmony_ci auto duration = base::TimeTicks::Now() - job_->start_time_; 27301cb0ef41Sopenharmony_ci job_->metrics_event_.success = false; 27311cb0ef41Sopenharmony_ci job_->metrics_event_.streamed = true; 27321cb0ef41Sopenharmony_ci job_->metrics_event_.module_size_in_bytes = job_->wire_bytes_.length(); 27331cb0ef41Sopenharmony_ci job_->metrics_event_.function_count = num_functions_; 27341cb0ef41Sopenharmony_ci job_->metrics_event_.wall_clock_duration_in_us = duration.InMicroseconds(); 27351cb0ef41Sopenharmony_ci job_->isolate_->metrics_recorder()->DelayMainThreadEvent(job_->metrics_event_, 27361cb0ef41Sopenharmony_ci job_->context_id_); 27371cb0ef41Sopenharmony_ci 27381cb0ef41Sopenharmony_ci // Check if there is already a CompiledModule, in which case we have to clean 27391cb0ef41Sopenharmony_ci // up the CompilationStateImpl as well. 27401cb0ef41Sopenharmony_ci if (job_->native_module_) { 27411cb0ef41Sopenharmony_ci Impl(job_->native_module_->compilation_state()) 27421cb0ef41Sopenharmony_ci ->CancelCompilation(CompilationStateImpl::kCancelUnconditionally); 27431cb0ef41Sopenharmony_ci 27441cb0ef41Sopenharmony_ci job_->DoSync<AsyncCompileJob::DecodeFail, 27451cb0ef41Sopenharmony_ci AsyncCompileJob::kUseExistingForegroundTask>(error); 27461cb0ef41Sopenharmony_ci 27471cb0ef41Sopenharmony_ci // Clear the {compilation_unit_builder_} if it exists. This is needed 27481cb0ef41Sopenharmony_ci // because there is a check in the destructor of the 27491cb0ef41Sopenharmony_ci // {CompilationUnitBuilder} that it is empty. 27501cb0ef41Sopenharmony_ci if (compilation_unit_builder_) compilation_unit_builder_->Clear(); 27511cb0ef41Sopenharmony_ci } else { 27521cb0ef41Sopenharmony_ci job_->DoSync<AsyncCompileJob::DecodeFail>(error); 27531cb0ef41Sopenharmony_ci } 27541cb0ef41Sopenharmony_ci} 27551cb0ef41Sopenharmony_ci 27561cb0ef41Sopenharmony_ci// Process the module header. 27571cb0ef41Sopenharmony_cibool AsyncStreamingProcessor::ProcessModuleHeader( 27581cb0ef41Sopenharmony_ci base::Vector<const uint8_t> bytes, uint32_t offset) { 27591cb0ef41Sopenharmony_ci TRACE_STREAMING("Process module header...\n"); 27601cb0ef41Sopenharmony_ci decoder_.StartDecoding(job_->isolate()->counters(), 27611cb0ef41Sopenharmony_ci job_->isolate()->metrics_recorder(), 27621cb0ef41Sopenharmony_ci job_->context_id(), GetWasmEngine()->allocator()); 27631cb0ef41Sopenharmony_ci decoder_.DecodeModuleHeader(bytes, offset); 27641cb0ef41Sopenharmony_ci if (!decoder_.ok()) { 27651cb0ef41Sopenharmony_ci FinishAsyncCompileJobWithError(decoder_.FinishDecoding(false).error()); 27661cb0ef41Sopenharmony_ci return false; 27671cb0ef41Sopenharmony_ci } 27681cb0ef41Sopenharmony_ci prefix_hash_ = NativeModuleCache::WireBytesHash(bytes); 27691cb0ef41Sopenharmony_ci return true; 27701cb0ef41Sopenharmony_ci} 27711cb0ef41Sopenharmony_ci 27721cb0ef41Sopenharmony_ci// Process all sections except for the code section. 27731cb0ef41Sopenharmony_cibool AsyncStreamingProcessor::ProcessSection(SectionCode section_code, 27741cb0ef41Sopenharmony_ci base::Vector<const uint8_t> bytes, 27751cb0ef41Sopenharmony_ci uint32_t offset) { 27761cb0ef41Sopenharmony_ci TRACE_STREAMING("Process section %d ...\n", section_code); 27771cb0ef41Sopenharmony_ci if (compilation_unit_builder_) { 27781cb0ef41Sopenharmony_ci // We reached a section after the code section, we do not need the 27791cb0ef41Sopenharmony_ci // compilation_unit_builder_ anymore. 27801cb0ef41Sopenharmony_ci CommitCompilationUnits(); 27811cb0ef41Sopenharmony_ci compilation_unit_builder_.reset(); 27821cb0ef41Sopenharmony_ci } 27831cb0ef41Sopenharmony_ci if (before_code_section_) { 27841cb0ef41Sopenharmony_ci // Combine section hashes until code section. 27851cb0ef41Sopenharmony_ci prefix_hash_ = base::hash_combine(prefix_hash_, 27861cb0ef41Sopenharmony_ci NativeModuleCache::WireBytesHash(bytes)); 27871cb0ef41Sopenharmony_ci } 27881cb0ef41Sopenharmony_ci if (section_code == SectionCode::kUnknownSectionCode) { 27891cb0ef41Sopenharmony_ci size_t bytes_consumed = ModuleDecoder::IdentifyUnknownSection( 27901cb0ef41Sopenharmony_ci &decoder_, bytes, offset, §ion_code); 27911cb0ef41Sopenharmony_ci if (!decoder_.ok()) { 27921cb0ef41Sopenharmony_ci FinishAsyncCompileJobWithError(decoder_.FinishDecoding(false).error()); 27931cb0ef41Sopenharmony_ci return false; 27941cb0ef41Sopenharmony_ci } 27951cb0ef41Sopenharmony_ci if (section_code == SectionCode::kUnknownSectionCode) { 27961cb0ef41Sopenharmony_ci // Skip unknown sections that we do not know how to handle. 27971cb0ef41Sopenharmony_ci return true; 27981cb0ef41Sopenharmony_ci } 27991cb0ef41Sopenharmony_ci // Remove the unknown section tag from the payload bytes. 28001cb0ef41Sopenharmony_ci offset += bytes_consumed; 28011cb0ef41Sopenharmony_ci bytes = bytes.SubVector(bytes_consumed, bytes.size()); 28021cb0ef41Sopenharmony_ci } 28031cb0ef41Sopenharmony_ci constexpr bool verify_functions = false; 28041cb0ef41Sopenharmony_ci decoder_.DecodeSection(section_code, bytes, offset, verify_functions); 28051cb0ef41Sopenharmony_ci if (!decoder_.ok()) { 28061cb0ef41Sopenharmony_ci FinishAsyncCompileJobWithError(decoder_.FinishDecoding(false).error()); 28071cb0ef41Sopenharmony_ci return false; 28081cb0ef41Sopenharmony_ci } 28091cb0ef41Sopenharmony_ci return true; 28101cb0ef41Sopenharmony_ci} 28111cb0ef41Sopenharmony_ci 28121cb0ef41Sopenharmony_ci// Start the code section. 28131cb0ef41Sopenharmony_cibool AsyncStreamingProcessor::ProcessCodeSectionHeader( 28141cb0ef41Sopenharmony_ci int num_functions, uint32_t functions_mismatch_error_offset, 28151cb0ef41Sopenharmony_ci std::shared_ptr<WireBytesStorage> wire_bytes_storage, 28161cb0ef41Sopenharmony_ci int code_section_start, int code_section_length) { 28171cb0ef41Sopenharmony_ci DCHECK_LE(0, code_section_length); 28181cb0ef41Sopenharmony_ci before_code_section_ = false; 28191cb0ef41Sopenharmony_ci TRACE_STREAMING("Start the code section with %d functions...\n", 28201cb0ef41Sopenharmony_ci num_functions); 28211cb0ef41Sopenharmony_ci decoder_.StartCodeSection(); 28221cb0ef41Sopenharmony_ci if (!decoder_.CheckFunctionsCount(static_cast<uint32_t>(num_functions), 28231cb0ef41Sopenharmony_ci functions_mismatch_error_offset)) { 28241cb0ef41Sopenharmony_ci FinishAsyncCompileJobWithError(decoder_.FinishDecoding(false).error()); 28251cb0ef41Sopenharmony_ci return false; 28261cb0ef41Sopenharmony_ci } 28271cb0ef41Sopenharmony_ci 28281cb0ef41Sopenharmony_ci decoder_.set_code_section(code_section_start, 28291cb0ef41Sopenharmony_ci static_cast<uint32_t>(code_section_length)); 28301cb0ef41Sopenharmony_ci 28311cb0ef41Sopenharmony_ci prefix_hash_ = base::hash_combine(prefix_hash_, 28321cb0ef41Sopenharmony_ci static_cast<uint32_t>(code_section_length)); 28331cb0ef41Sopenharmony_ci if (!GetWasmEngine()->GetStreamingCompilationOwnership(prefix_hash_)) { 28341cb0ef41Sopenharmony_ci // Known prefix, wait until the end of the stream and check the cache. 28351cb0ef41Sopenharmony_ci prefix_cache_hit_ = true; 28361cb0ef41Sopenharmony_ci return true; 28371cb0ef41Sopenharmony_ci } 28381cb0ef41Sopenharmony_ci 28391cb0ef41Sopenharmony_ci // Execute the PrepareAndStartCompile step immediately and not in a separate 28401cb0ef41Sopenharmony_ci // task. 28411cb0ef41Sopenharmony_ci int num_imported_functions = 28421cb0ef41Sopenharmony_ci static_cast<int>(decoder_.module()->num_imported_functions); 28431cb0ef41Sopenharmony_ci DCHECK_EQ(kWasmOrigin, decoder_.module()->origin); 28441cb0ef41Sopenharmony_ci const bool include_liftoff = FLAG_liftoff; 28451cb0ef41Sopenharmony_ci size_t code_size_estimate = 28461cb0ef41Sopenharmony_ci wasm::WasmCodeManager::EstimateNativeModuleCodeSize( 28471cb0ef41Sopenharmony_ci num_functions, num_imported_functions, code_section_length, 28481cb0ef41Sopenharmony_ci include_liftoff, job_->dynamic_tiering_); 28491cb0ef41Sopenharmony_ci job_->DoImmediately<AsyncCompileJob::PrepareAndStartCompile>( 28501cb0ef41Sopenharmony_ci decoder_.shared_module(), false, code_size_estimate); 28511cb0ef41Sopenharmony_ci 28521cb0ef41Sopenharmony_ci auto* compilation_state = Impl(job_->native_module_->compilation_state()); 28531cb0ef41Sopenharmony_ci compilation_state->SetWireBytesStorage(std::move(wire_bytes_storage)); 28541cb0ef41Sopenharmony_ci DCHECK_EQ(job_->native_module_->module()->origin, kWasmOrigin); 28551cb0ef41Sopenharmony_ci 28561cb0ef41Sopenharmony_ci // Set outstanding_finishers_ to 2, because both the AsyncCompileJob and the 28571cb0ef41Sopenharmony_ci // AsyncStreamingProcessor have to finish. 28581cb0ef41Sopenharmony_ci job_->outstanding_finishers_.store(2); 28591cb0ef41Sopenharmony_ci compilation_unit_builder_ = 28601cb0ef41Sopenharmony_ci InitializeCompilation(job_->isolate(), job_->native_module_.get()); 28611cb0ef41Sopenharmony_ci return true; 28621cb0ef41Sopenharmony_ci} 28631cb0ef41Sopenharmony_ci 28641cb0ef41Sopenharmony_ci// Process a function body. 28651cb0ef41Sopenharmony_cibool AsyncStreamingProcessor::ProcessFunctionBody( 28661cb0ef41Sopenharmony_ci base::Vector<const uint8_t> bytes, uint32_t offset) { 28671cb0ef41Sopenharmony_ci TRACE_STREAMING("Process function body %d ...\n", num_functions_); 28681cb0ef41Sopenharmony_ci 28691cb0ef41Sopenharmony_ci decoder_.DecodeFunctionBody( 28701cb0ef41Sopenharmony_ci num_functions_, static_cast<uint32_t>(bytes.length()), offset, false); 28711cb0ef41Sopenharmony_ci 28721cb0ef41Sopenharmony_ci const WasmModule* module = decoder_.module(); 28731cb0ef41Sopenharmony_ci auto enabled_features = job_->enabled_features_; 28741cb0ef41Sopenharmony_ci uint32_t func_index = 28751cb0ef41Sopenharmony_ci num_functions_ + decoder_.module()->num_imported_functions; 28761cb0ef41Sopenharmony_ci DCHECK_EQ(module->origin, kWasmOrigin); 28771cb0ef41Sopenharmony_ci const bool lazy_module = job_->wasm_lazy_compilation_; 28781cb0ef41Sopenharmony_ci CompileStrategy strategy = 28791cb0ef41Sopenharmony_ci GetCompileStrategy(module, enabled_features, func_index, lazy_module); 28801cb0ef41Sopenharmony_ci bool validate_lazily_compiled_function = 28811cb0ef41Sopenharmony_ci !FLAG_wasm_lazy_validation && 28821cb0ef41Sopenharmony_ci (strategy == CompileStrategy::kLazy || 28831cb0ef41Sopenharmony_ci strategy == CompileStrategy::kLazyBaselineEagerTopTier); 28841cb0ef41Sopenharmony_ci if (validate_lazily_compiled_function) { 28851cb0ef41Sopenharmony_ci // The native module does not own the wire bytes until {SetWireBytes} is 28861cb0ef41Sopenharmony_ci // called in {OnFinishedStream}. Validation must use {bytes} parameter. 28871cb0ef41Sopenharmony_ci DecodeResult result = 28881cb0ef41Sopenharmony_ci ValidateSingleFunction(module, func_index, bytes, async_counters_.get(), 28891cb0ef41Sopenharmony_ci allocator_, enabled_features); 28901cb0ef41Sopenharmony_ci 28911cb0ef41Sopenharmony_ci if (result.failed()) { 28921cb0ef41Sopenharmony_ci FinishAsyncCompileJobWithError(result.error()); 28931cb0ef41Sopenharmony_ci return false; 28941cb0ef41Sopenharmony_ci } 28951cb0ef41Sopenharmony_ci } 28961cb0ef41Sopenharmony_ci 28971cb0ef41Sopenharmony_ci // Don't compile yet if we might have a cache hit. 28981cb0ef41Sopenharmony_ci if (prefix_cache_hit_) { 28991cb0ef41Sopenharmony_ci num_functions_++; 29001cb0ef41Sopenharmony_ci return true; 29011cb0ef41Sopenharmony_ci } 29021cb0ef41Sopenharmony_ci 29031cb0ef41Sopenharmony_ci auto* compilation_state = Impl(job_->native_module_->compilation_state()); 29041cb0ef41Sopenharmony_ci compilation_state->AddCompilationUnit(compilation_unit_builder_.get(), 29051cb0ef41Sopenharmony_ci func_index); 29061cb0ef41Sopenharmony_ci ++num_functions_; 29071cb0ef41Sopenharmony_ci 29081cb0ef41Sopenharmony_ci return true; 29091cb0ef41Sopenharmony_ci} 29101cb0ef41Sopenharmony_ci 29111cb0ef41Sopenharmony_civoid AsyncStreamingProcessor::CommitCompilationUnits() { 29121cb0ef41Sopenharmony_ci DCHECK(compilation_unit_builder_); 29131cb0ef41Sopenharmony_ci compilation_unit_builder_->Commit(); 29141cb0ef41Sopenharmony_ci} 29151cb0ef41Sopenharmony_ci 29161cb0ef41Sopenharmony_civoid AsyncStreamingProcessor::OnFinishedChunk() { 29171cb0ef41Sopenharmony_ci TRACE_STREAMING("FinishChunk...\n"); 29181cb0ef41Sopenharmony_ci if (compilation_unit_builder_) CommitCompilationUnits(); 29191cb0ef41Sopenharmony_ci} 29201cb0ef41Sopenharmony_ci 29211cb0ef41Sopenharmony_ci// Finish the processing of the stream. 29221cb0ef41Sopenharmony_civoid AsyncStreamingProcessor::OnFinishedStream( 29231cb0ef41Sopenharmony_ci base::OwnedVector<uint8_t> bytes) { 29241cb0ef41Sopenharmony_ci TRACE_STREAMING("Finish stream...\n"); 29251cb0ef41Sopenharmony_ci DCHECK_EQ(NativeModuleCache::PrefixHash(bytes.as_vector()), prefix_hash_); 29261cb0ef41Sopenharmony_ci ModuleResult result = decoder_.FinishDecoding(false); 29271cb0ef41Sopenharmony_ci if (result.failed()) { 29281cb0ef41Sopenharmony_ci FinishAsyncCompileJobWithError(result.error()); 29291cb0ef41Sopenharmony_ci return; 29301cb0ef41Sopenharmony_ci } 29311cb0ef41Sopenharmony_ci 29321cb0ef41Sopenharmony_ci job_->wire_bytes_ = ModuleWireBytes(bytes.as_vector()); 29331cb0ef41Sopenharmony_ci job_->bytes_copy_ = bytes.ReleaseData(); 29341cb0ef41Sopenharmony_ci 29351cb0ef41Sopenharmony_ci // Record event metrics. 29361cb0ef41Sopenharmony_ci auto duration = base::TimeTicks::Now() - job_->start_time_; 29371cb0ef41Sopenharmony_ci job_->metrics_event_.success = true; 29381cb0ef41Sopenharmony_ci job_->metrics_event_.streamed = true; 29391cb0ef41Sopenharmony_ci job_->metrics_event_.module_size_in_bytes = job_->wire_bytes_.length(); 29401cb0ef41Sopenharmony_ci job_->metrics_event_.function_count = num_functions_; 29411cb0ef41Sopenharmony_ci job_->metrics_event_.wall_clock_duration_in_us = duration.InMicroseconds(); 29421cb0ef41Sopenharmony_ci job_->isolate_->metrics_recorder()->DelayMainThreadEvent(job_->metrics_event_, 29431cb0ef41Sopenharmony_ci job_->context_id_); 29441cb0ef41Sopenharmony_ci 29451cb0ef41Sopenharmony_ci if (prefix_cache_hit_) { 29461cb0ef41Sopenharmony_ci // Restart as an asynchronous, non-streaming compilation. Most likely 29471cb0ef41Sopenharmony_ci // {PrepareAndStartCompile} will get the native module from the cache. 29481cb0ef41Sopenharmony_ci const bool include_liftoff = FLAG_liftoff; 29491cb0ef41Sopenharmony_ci size_t code_size_estimate = 29501cb0ef41Sopenharmony_ci wasm::WasmCodeManager::EstimateNativeModuleCodeSize( 29511cb0ef41Sopenharmony_ci result.value().get(), include_liftoff, job_->dynamic_tiering_); 29521cb0ef41Sopenharmony_ci job_->DoSync<AsyncCompileJob::PrepareAndStartCompile>( 29531cb0ef41Sopenharmony_ci std::move(result).value(), true, code_size_estimate); 29541cb0ef41Sopenharmony_ci return; 29551cb0ef41Sopenharmony_ci } 29561cb0ef41Sopenharmony_ci 29571cb0ef41Sopenharmony_ci // We have to open a HandleScope and prepare the Context for 29581cb0ef41Sopenharmony_ci // CreateNativeModule, PrepareRuntimeObjects and FinishCompile as this is a 29591cb0ef41Sopenharmony_ci // callback from the embedder. 29601cb0ef41Sopenharmony_ci HandleScope scope(job_->isolate_); 29611cb0ef41Sopenharmony_ci SaveAndSwitchContext saved_context(job_->isolate_, *job_->native_context_); 29621cb0ef41Sopenharmony_ci 29631cb0ef41Sopenharmony_ci // Record the size of the wire bytes. In synchronous and asynchronous 29641cb0ef41Sopenharmony_ci // (non-streaming) compilation, this happens in {DecodeWasmModule}. 29651cb0ef41Sopenharmony_ci auto* histogram = job_->isolate_->counters()->wasm_wasm_module_size_bytes(); 29661cb0ef41Sopenharmony_ci histogram->AddSample(job_->wire_bytes_.module_bytes().length()); 29671cb0ef41Sopenharmony_ci 29681cb0ef41Sopenharmony_ci const bool has_code_section = job_->native_module_ != nullptr; 29691cb0ef41Sopenharmony_ci bool cache_hit = false; 29701cb0ef41Sopenharmony_ci if (!has_code_section) { 29711cb0ef41Sopenharmony_ci // We are processing a WebAssembly module without code section. Create the 29721cb0ef41Sopenharmony_ci // native module now (would otherwise happen in {PrepareAndStartCompile} or 29731cb0ef41Sopenharmony_ci // {ProcessCodeSectionHeader}). 29741cb0ef41Sopenharmony_ci constexpr size_t kCodeSizeEstimate = 0; 29751cb0ef41Sopenharmony_ci cache_hit = job_->GetOrCreateNativeModule(std::move(result).value(), 29761cb0ef41Sopenharmony_ci kCodeSizeEstimate); 29771cb0ef41Sopenharmony_ci } else { 29781cb0ef41Sopenharmony_ci job_->native_module_->SetWireBytes( 29791cb0ef41Sopenharmony_ci {std::move(job_->bytes_copy_), job_->wire_bytes_.length()}); 29801cb0ef41Sopenharmony_ci } 29811cb0ef41Sopenharmony_ci const bool needs_finish = job_->DecrementAndCheckFinisherCount(); 29821cb0ef41Sopenharmony_ci DCHECK_IMPLIES(!has_code_section, needs_finish); 29831cb0ef41Sopenharmony_ci if (needs_finish) { 29841cb0ef41Sopenharmony_ci const bool failed = job_->native_module_->compilation_state()->failed(); 29851cb0ef41Sopenharmony_ci if (!cache_hit) { 29861cb0ef41Sopenharmony_ci cache_hit = !GetWasmEngine()->UpdateNativeModuleCache( 29871cb0ef41Sopenharmony_ci failed, &job_->native_module_, job_->isolate_); 29881cb0ef41Sopenharmony_ci } 29891cb0ef41Sopenharmony_ci if (failed) { 29901cb0ef41Sopenharmony_ci job_->AsyncCompileFailed(); 29911cb0ef41Sopenharmony_ci } else { 29921cb0ef41Sopenharmony_ci job_->FinishCompile(cache_hit); 29931cb0ef41Sopenharmony_ci } 29941cb0ef41Sopenharmony_ci } 29951cb0ef41Sopenharmony_ci} 29961cb0ef41Sopenharmony_ci 29971cb0ef41Sopenharmony_ci// Report an error detected in the StreamingDecoder. 29981cb0ef41Sopenharmony_civoid AsyncStreamingProcessor::OnError(const WasmError& error) { 29991cb0ef41Sopenharmony_ci TRACE_STREAMING("Stream error...\n"); 30001cb0ef41Sopenharmony_ci FinishAsyncCompileJobWithError(error); 30011cb0ef41Sopenharmony_ci} 30021cb0ef41Sopenharmony_ci 30031cb0ef41Sopenharmony_civoid AsyncStreamingProcessor::OnAbort() { 30041cb0ef41Sopenharmony_ci TRACE_STREAMING("Abort stream...\n"); 30051cb0ef41Sopenharmony_ci job_->Abort(); 30061cb0ef41Sopenharmony_ci} 30071cb0ef41Sopenharmony_ci 30081cb0ef41Sopenharmony_cibool AsyncStreamingProcessor::Deserialize( 30091cb0ef41Sopenharmony_ci base::Vector<const uint8_t> module_bytes, 30101cb0ef41Sopenharmony_ci base::Vector<const uint8_t> wire_bytes) { 30111cb0ef41Sopenharmony_ci TRACE_EVENT0("v8.wasm", "wasm.Deserialize"); 30121cb0ef41Sopenharmony_ci TimedHistogramScope time_scope( 30131cb0ef41Sopenharmony_ci job_->isolate()->counters()->wasm_deserialization_time(), 30141cb0ef41Sopenharmony_ci job_->isolate()); 30151cb0ef41Sopenharmony_ci // DeserializeNativeModule and FinishCompile assume that they are executed in 30161cb0ef41Sopenharmony_ci // a HandleScope, and that a context is set on the isolate. 30171cb0ef41Sopenharmony_ci HandleScope scope(job_->isolate_); 30181cb0ef41Sopenharmony_ci SaveAndSwitchContext saved_context(job_->isolate_, *job_->native_context_); 30191cb0ef41Sopenharmony_ci 30201cb0ef41Sopenharmony_ci MaybeHandle<WasmModuleObject> result = DeserializeNativeModule( 30211cb0ef41Sopenharmony_ci job_->isolate_, module_bytes, wire_bytes, job_->stream_->url()); 30221cb0ef41Sopenharmony_ci 30231cb0ef41Sopenharmony_ci if (result.is_null()) return false; 30241cb0ef41Sopenharmony_ci 30251cb0ef41Sopenharmony_ci job_->module_object_ = 30261cb0ef41Sopenharmony_ci job_->isolate_->global_handles()->Create(*result.ToHandleChecked()); 30271cb0ef41Sopenharmony_ci job_->native_module_ = job_->module_object_->shared_native_module(); 30281cb0ef41Sopenharmony_ci job_->wire_bytes_ = ModuleWireBytes(job_->native_module_->wire_bytes()); 30291cb0ef41Sopenharmony_ci job_->FinishCompile(false); 30301cb0ef41Sopenharmony_ci return true; 30311cb0ef41Sopenharmony_ci} 30321cb0ef41Sopenharmony_ci 30331cb0ef41Sopenharmony_ciCompilationStateImpl::CompilationStateImpl( 30341cb0ef41Sopenharmony_ci const std::shared_ptr<NativeModule>& native_module, 30351cb0ef41Sopenharmony_ci std::shared_ptr<Counters> async_counters, DynamicTiering dynamic_tiering) 30361cb0ef41Sopenharmony_ci : native_module_(native_module.get()), 30371cb0ef41Sopenharmony_ci native_module_weak_(std::move(native_module)), 30381cb0ef41Sopenharmony_ci async_counters_(std::move(async_counters)), 30391cb0ef41Sopenharmony_ci compilation_unit_queues_(native_module->num_functions()), 30401cb0ef41Sopenharmony_ci dynamic_tiering_(dynamic_tiering) {} 30411cb0ef41Sopenharmony_ci 30421cb0ef41Sopenharmony_civoid CompilationStateImpl::InitCompileJob() { 30431cb0ef41Sopenharmony_ci DCHECK_NULL(compile_job_); 30441cb0ef41Sopenharmony_ci compile_job_ = V8::GetCurrentPlatform()->PostJob( 30451cb0ef41Sopenharmony_ci TaskPriority::kUserVisible, std::make_unique<BackgroundCompileJob>( 30461cb0ef41Sopenharmony_ci native_module_weak_, async_counters_)); 30471cb0ef41Sopenharmony_ci} 30481cb0ef41Sopenharmony_ci 30491cb0ef41Sopenharmony_civoid CompilationStateImpl::CancelCompilation( 30501cb0ef41Sopenharmony_ci CompilationStateImpl::CancellationPolicy cancellation_policy) { 30511cb0ef41Sopenharmony_ci base::MutexGuard callbacks_guard(&callbacks_mutex_); 30521cb0ef41Sopenharmony_ci 30531cb0ef41Sopenharmony_ci if (cancellation_policy == kCancelInitialCompilation && 30541cb0ef41Sopenharmony_ci finished_events_.contains( 30551cb0ef41Sopenharmony_ci CompilationEvent::kFinishedBaselineCompilation)) { 30561cb0ef41Sopenharmony_ci // Initial compilation already finished; cannot be cancelled. 30571cb0ef41Sopenharmony_ci return; 30581cb0ef41Sopenharmony_ci } 30591cb0ef41Sopenharmony_ci 30601cb0ef41Sopenharmony_ci // std::memory_order_relaxed is sufficient because no other state is 30611cb0ef41Sopenharmony_ci // synchronized with |compile_cancelled_|. 30621cb0ef41Sopenharmony_ci compile_cancelled_.store(true, std::memory_order_relaxed); 30631cb0ef41Sopenharmony_ci 30641cb0ef41Sopenharmony_ci // No more callbacks after abort. 30651cb0ef41Sopenharmony_ci callbacks_.clear(); 30661cb0ef41Sopenharmony_ci} 30671cb0ef41Sopenharmony_ci 30681cb0ef41Sopenharmony_cibool CompilationStateImpl::cancelled() const { 30691cb0ef41Sopenharmony_ci return compile_cancelled_.load(std::memory_order_relaxed); 30701cb0ef41Sopenharmony_ci} 30711cb0ef41Sopenharmony_ci 30721cb0ef41Sopenharmony_ciuint8_t CompilationStateImpl::SetupCompilationProgressForFunction( 30731cb0ef41Sopenharmony_ci bool lazy_function, NativeModule* native_module, 30741cb0ef41Sopenharmony_ci const WasmFeatures& enabled_features, int func_index) { 30751cb0ef41Sopenharmony_ci ExecutionTierPair requested_tiers = 30761cb0ef41Sopenharmony_ci GetRequestedExecutionTiers(native_module, enabled_features, func_index); 30771cb0ef41Sopenharmony_ci CompileStrategy strategy = GetCompileStrategy( 30781cb0ef41Sopenharmony_ci native_module->module(), enabled_features, func_index, lazy_function); 30791cb0ef41Sopenharmony_ci 30801cb0ef41Sopenharmony_ci bool required_for_baseline = strategy == CompileStrategy::kEager; 30811cb0ef41Sopenharmony_ci bool required_for_top_tier = strategy != CompileStrategy::kLazy; 30821cb0ef41Sopenharmony_ci DCHECK_EQ(required_for_top_tier, 30831cb0ef41Sopenharmony_ci strategy == CompileStrategy::kEager || 30841cb0ef41Sopenharmony_ci strategy == CompileStrategy::kLazyBaselineEagerTopTier); 30851cb0ef41Sopenharmony_ci 30861cb0ef41Sopenharmony_ci // Count functions to complete baseline and top tier compilation. 30871cb0ef41Sopenharmony_ci if (required_for_baseline) outstanding_baseline_units_++; 30881cb0ef41Sopenharmony_ci if (required_for_top_tier) outstanding_top_tier_functions_++; 30891cb0ef41Sopenharmony_ci 30901cb0ef41Sopenharmony_ci // Initialize function's compilation progress. 30911cb0ef41Sopenharmony_ci ExecutionTier required_baseline_tier = required_for_baseline 30921cb0ef41Sopenharmony_ci ? requested_tiers.baseline_tier 30931cb0ef41Sopenharmony_ci : ExecutionTier::kNone; 30941cb0ef41Sopenharmony_ci ExecutionTier required_top_tier = 30951cb0ef41Sopenharmony_ci required_for_top_tier ? requested_tiers.top_tier : ExecutionTier::kNone; 30961cb0ef41Sopenharmony_ci uint8_t function_progress = 30971cb0ef41Sopenharmony_ci ReachedTierField::encode(ExecutionTier::kNone) | 30981cb0ef41Sopenharmony_ci RequiredBaselineTierField::encode(required_baseline_tier) | 30991cb0ef41Sopenharmony_ci RequiredTopTierField::encode(required_top_tier); 31001cb0ef41Sopenharmony_ci 31011cb0ef41Sopenharmony_ci return function_progress; 31021cb0ef41Sopenharmony_ci} 31031cb0ef41Sopenharmony_ci 31041cb0ef41Sopenharmony_civoid CompilationStateImpl::InitializeCompilationProgress( 31051cb0ef41Sopenharmony_ci bool lazy_module, int num_import_wrappers, int num_export_wrappers) { 31061cb0ef41Sopenharmony_ci DCHECK(!failed()); 31071cb0ef41Sopenharmony_ci auto enabled_features = native_module_->enabled_features(); 31081cb0ef41Sopenharmony_ci auto* module = native_module_->module(); 31091cb0ef41Sopenharmony_ci 31101cb0ef41Sopenharmony_ci base::MutexGuard guard(&callbacks_mutex_); 31111cb0ef41Sopenharmony_ci DCHECK_EQ(0, outstanding_baseline_units_); 31121cb0ef41Sopenharmony_ci DCHECK_EQ(0, outstanding_export_wrappers_); 31131cb0ef41Sopenharmony_ci DCHECK_EQ(0, outstanding_top_tier_functions_); 31141cb0ef41Sopenharmony_ci compilation_progress_.reserve(module->num_declared_functions); 31151cb0ef41Sopenharmony_ci int start = module->num_imported_functions; 31161cb0ef41Sopenharmony_ci int end = start + module->num_declared_functions; 31171cb0ef41Sopenharmony_ci 31181cb0ef41Sopenharmony_ci const bool prefer_liftoff = native_module_->IsTieredDown(); 31191cb0ef41Sopenharmony_ci for (int func_index = start; func_index < end; func_index++) { 31201cb0ef41Sopenharmony_ci if (prefer_liftoff) { 31211cb0ef41Sopenharmony_ci constexpr uint8_t kLiftoffOnlyFunctionProgress = 31221cb0ef41Sopenharmony_ci RequiredTopTierField::encode(ExecutionTier::kLiftoff) | 31231cb0ef41Sopenharmony_ci RequiredBaselineTierField::encode(ExecutionTier::kLiftoff) | 31241cb0ef41Sopenharmony_ci ReachedTierField::encode(ExecutionTier::kNone); 31251cb0ef41Sopenharmony_ci compilation_progress_.push_back(kLiftoffOnlyFunctionProgress); 31261cb0ef41Sopenharmony_ci outstanding_baseline_units_++; 31271cb0ef41Sopenharmony_ci outstanding_top_tier_functions_++; 31281cb0ef41Sopenharmony_ci continue; 31291cb0ef41Sopenharmony_ci } 31301cb0ef41Sopenharmony_ci uint8_t function_progress = SetupCompilationProgressForFunction( 31311cb0ef41Sopenharmony_ci lazy_module, native_module_, enabled_features, func_index); 31321cb0ef41Sopenharmony_ci compilation_progress_.push_back(function_progress); 31331cb0ef41Sopenharmony_ci } 31341cb0ef41Sopenharmony_ci DCHECK_IMPLIES(lazy_module, outstanding_baseline_units_ == 0); 31351cb0ef41Sopenharmony_ci DCHECK_IMPLIES(lazy_module, outstanding_top_tier_functions_ == 0); 31361cb0ef41Sopenharmony_ci DCHECK_LE(0, outstanding_baseline_units_); 31371cb0ef41Sopenharmony_ci DCHECK_LE(outstanding_baseline_units_, outstanding_top_tier_functions_); 31381cb0ef41Sopenharmony_ci outstanding_baseline_units_ += num_import_wrappers; 31391cb0ef41Sopenharmony_ci outstanding_export_wrappers_ = num_export_wrappers; 31401cb0ef41Sopenharmony_ci 31411cb0ef41Sopenharmony_ci // Trigger callbacks if module needs no baseline or top tier compilation. This 31421cb0ef41Sopenharmony_ci // can be the case for an empty or fully lazy module. 31431cb0ef41Sopenharmony_ci TriggerCallbacks(); 31441cb0ef41Sopenharmony_ci} 31451cb0ef41Sopenharmony_ci 31461cb0ef41Sopenharmony_ciuint8_t CompilationStateImpl::AddCompilationUnitInternal( 31471cb0ef41Sopenharmony_ci CompilationUnitBuilder* builder, int function_index, 31481cb0ef41Sopenharmony_ci uint8_t function_progress) { 31491cb0ef41Sopenharmony_ci ExecutionTier required_baseline_tier = 31501cb0ef41Sopenharmony_ci CompilationStateImpl::RequiredBaselineTierField::decode( 31511cb0ef41Sopenharmony_ci function_progress); 31521cb0ef41Sopenharmony_ci ExecutionTier required_top_tier = 31531cb0ef41Sopenharmony_ci CompilationStateImpl::RequiredTopTierField::decode(function_progress); 31541cb0ef41Sopenharmony_ci ExecutionTier reached_tier = 31551cb0ef41Sopenharmony_ci CompilationStateImpl::ReachedTierField::decode(function_progress); 31561cb0ef41Sopenharmony_ci 31571cb0ef41Sopenharmony_ci if (FLAG_experimental_wasm_gc) { 31581cb0ef41Sopenharmony_ci // The Turbofan optimizations we enable for WasmGC code can (for now) 31591cb0ef41Sopenharmony_ci // take a very long time, so skip Turbofan compilation for super-large 31601cb0ef41Sopenharmony_ci // functions. 31611cb0ef41Sopenharmony_ci // Besides, module serialization currently requires that all functions 31621cb0ef41Sopenharmony_ci // have been TF-compiled. By enabling this limit only for WasmGC, we 31631cb0ef41Sopenharmony_ci // make sure that non-experimental modules can be serialize as usual. 31641cb0ef41Sopenharmony_ci // TODO(jkummerow): This is a stop-gap solution to avoid excessive 31651cb0ef41Sopenharmony_ci // compile times. We would like to replace this hard threshold with 31661cb0ef41Sopenharmony_ci // a better solution (TBD) eventually. 31671cb0ef41Sopenharmony_ci constexpr uint32_t kMaxWasmFunctionSizeForTurbofan = 500 * KB; 31681cb0ef41Sopenharmony_ci uint32_t size = builder->module()->functions[function_index].code.length(); 31691cb0ef41Sopenharmony_ci if (size > kMaxWasmFunctionSizeForTurbofan) { 31701cb0ef41Sopenharmony_ci required_baseline_tier = ExecutionTier::kLiftoff; 31711cb0ef41Sopenharmony_ci if (required_top_tier == ExecutionTier::kTurbofan) { 31721cb0ef41Sopenharmony_ci required_top_tier = ExecutionTier::kLiftoff; 31731cb0ef41Sopenharmony_ci outstanding_top_tier_functions_--; 31741cb0ef41Sopenharmony_ci } 31751cb0ef41Sopenharmony_ci } 31761cb0ef41Sopenharmony_ci } 31771cb0ef41Sopenharmony_ci 31781cb0ef41Sopenharmony_ci if (reached_tier < required_baseline_tier) { 31791cb0ef41Sopenharmony_ci builder->AddBaselineUnit(function_index, required_baseline_tier); 31801cb0ef41Sopenharmony_ci } 31811cb0ef41Sopenharmony_ci if (reached_tier < required_top_tier && 31821cb0ef41Sopenharmony_ci required_baseline_tier != required_top_tier) { 31831cb0ef41Sopenharmony_ci builder->AddTopTierUnit(function_index, required_top_tier); 31841cb0ef41Sopenharmony_ci } 31851cb0ef41Sopenharmony_ci return CompilationStateImpl::RequiredBaselineTierField::encode( 31861cb0ef41Sopenharmony_ci required_baseline_tier) | 31871cb0ef41Sopenharmony_ci CompilationStateImpl::RequiredTopTierField::encode(required_top_tier) | 31881cb0ef41Sopenharmony_ci CompilationStateImpl::ReachedTierField::encode(reached_tier); 31891cb0ef41Sopenharmony_ci} 31901cb0ef41Sopenharmony_ci 31911cb0ef41Sopenharmony_civoid CompilationStateImpl::InitializeCompilationUnits( 31921cb0ef41Sopenharmony_ci std::unique_ptr<CompilationUnitBuilder> builder) { 31931cb0ef41Sopenharmony_ci int offset = native_module_->module()->num_imported_functions; 31941cb0ef41Sopenharmony_ci if (native_module_->IsTieredDown()) { 31951cb0ef41Sopenharmony_ci for (size_t i = 0; i < compilation_progress_.size(); ++i) { 31961cb0ef41Sopenharmony_ci int func_index = offset + static_cast<int>(i); 31971cb0ef41Sopenharmony_ci builder->AddDebugUnit(func_index); 31981cb0ef41Sopenharmony_ci } 31991cb0ef41Sopenharmony_ci } else { 32001cb0ef41Sopenharmony_ci base::MutexGuard guard(&callbacks_mutex_); 32011cb0ef41Sopenharmony_ci 32021cb0ef41Sopenharmony_ci for (size_t i = 0; i < compilation_progress_.size(); ++i) { 32031cb0ef41Sopenharmony_ci uint8_t function_progress = compilation_progress_[i]; 32041cb0ef41Sopenharmony_ci int func_index = offset + static_cast<int>(i); 32051cb0ef41Sopenharmony_ci compilation_progress_[i] = AddCompilationUnitInternal( 32061cb0ef41Sopenharmony_ci builder.get(), func_index, function_progress); 32071cb0ef41Sopenharmony_ci } 32081cb0ef41Sopenharmony_ci } 32091cb0ef41Sopenharmony_ci builder->Commit(); 32101cb0ef41Sopenharmony_ci} 32111cb0ef41Sopenharmony_ci 32121cb0ef41Sopenharmony_civoid CompilationStateImpl::AddCompilationUnit(CompilationUnitBuilder* builder, 32131cb0ef41Sopenharmony_ci int func_index) { 32141cb0ef41Sopenharmony_ci if (native_module_->IsTieredDown()) { 32151cb0ef41Sopenharmony_ci builder->AddDebugUnit(func_index); 32161cb0ef41Sopenharmony_ci return; 32171cb0ef41Sopenharmony_ci } 32181cb0ef41Sopenharmony_ci int offset = native_module_->module()->num_imported_functions; 32191cb0ef41Sopenharmony_ci int progress_index = func_index - offset; 32201cb0ef41Sopenharmony_ci uint8_t function_progress; 32211cb0ef41Sopenharmony_ci { 32221cb0ef41Sopenharmony_ci // TODO(ahaas): This lock may cause overhead. If so, we could get rid of the 32231cb0ef41Sopenharmony_ci // lock as follows: 32241cb0ef41Sopenharmony_ci // 1) Make compilation_progress_ an array of atomic<uint8_t>, and access it 32251cb0ef41Sopenharmony_ci // lock-free. 32261cb0ef41Sopenharmony_ci // 2) Have a copy of compilation_progress_ that we use for initialization. 32271cb0ef41Sopenharmony_ci // 3) Just re-calculate the content of compilation_progress_. 32281cb0ef41Sopenharmony_ci base::MutexGuard guard(&callbacks_mutex_); 32291cb0ef41Sopenharmony_ci function_progress = compilation_progress_[progress_index]; 32301cb0ef41Sopenharmony_ci } 32311cb0ef41Sopenharmony_ci uint8_t updated_function_progress = 32321cb0ef41Sopenharmony_ci AddCompilationUnitInternal(builder, func_index, function_progress); 32331cb0ef41Sopenharmony_ci if (updated_function_progress != function_progress) { 32341cb0ef41Sopenharmony_ci // This should happen very rarely (only for super-large functions), so we're 32351cb0ef41Sopenharmony_ci // not worried about overhead. 32361cb0ef41Sopenharmony_ci base::MutexGuard guard(&callbacks_mutex_); 32371cb0ef41Sopenharmony_ci compilation_progress_[progress_index] = updated_function_progress; 32381cb0ef41Sopenharmony_ci } 32391cb0ef41Sopenharmony_ci} 32401cb0ef41Sopenharmony_ci 32411cb0ef41Sopenharmony_civoid CompilationStateImpl::InitializeCompilationProgressAfterDeserialization( 32421cb0ef41Sopenharmony_ci base::Vector<const int> lazy_functions, 32431cb0ef41Sopenharmony_ci base::Vector<const int> liftoff_functions) { 32441cb0ef41Sopenharmony_ci TRACE_EVENT2("v8.wasm", "wasm.CompilationAfterDeserialization", 32451cb0ef41Sopenharmony_ci "num_lazy_functions", lazy_functions.size(), 32461cb0ef41Sopenharmony_ci "num_liftoff_functions", liftoff_functions.size()); 32471cb0ef41Sopenharmony_ci TimedHistogramScope lazy_compile_time_scope( 32481cb0ef41Sopenharmony_ci counters()->wasm_compile_after_deserialize()); 32491cb0ef41Sopenharmony_ci 32501cb0ef41Sopenharmony_ci auto* module = native_module_->module(); 32511cb0ef41Sopenharmony_ci auto enabled_features = native_module_->enabled_features(); 32521cb0ef41Sopenharmony_ci const bool lazy_module = IsLazyModule(module); 32531cb0ef41Sopenharmony_ci base::Optional<CodeSpaceWriteScope> lazy_code_space_write_scope; 32541cb0ef41Sopenharmony_ci if (lazy_module || !lazy_functions.empty()) { 32551cb0ef41Sopenharmony_ci lazy_code_space_write_scope.emplace(native_module_); 32561cb0ef41Sopenharmony_ci } 32571cb0ef41Sopenharmony_ci { 32581cb0ef41Sopenharmony_ci base::MutexGuard guard(&callbacks_mutex_); 32591cb0ef41Sopenharmony_ci DCHECK(compilation_progress_.empty()); 32601cb0ef41Sopenharmony_ci constexpr uint8_t kProgressAfterTurbofanDeserialization = 32611cb0ef41Sopenharmony_ci RequiredBaselineTierField::encode(ExecutionTier::kTurbofan) | 32621cb0ef41Sopenharmony_ci RequiredTopTierField::encode(ExecutionTier::kTurbofan) | 32631cb0ef41Sopenharmony_ci ReachedTierField::encode(ExecutionTier::kTurbofan); 32641cb0ef41Sopenharmony_ci finished_events_.Add(CompilationEvent::kFinishedExportWrappers); 32651cb0ef41Sopenharmony_ci if (liftoff_functions.empty() || lazy_module) { 32661cb0ef41Sopenharmony_ci // We have to trigger the compilation events to finish compilation. 32671cb0ef41Sopenharmony_ci // Typically the events get triggered when a CompilationUnit finishes, but 32681cb0ef41Sopenharmony_ci // with lazy compilation there are no compilation units. 32691cb0ef41Sopenharmony_ci // The {kFinishedBaselineCompilation} event is needed for module 32701cb0ef41Sopenharmony_ci // compilation to finish. 32711cb0ef41Sopenharmony_ci finished_events_.Add(CompilationEvent::kFinishedBaselineCompilation); 32721cb0ef41Sopenharmony_ci if (liftoff_functions.empty() && lazy_functions.empty()) { 32731cb0ef41Sopenharmony_ci // All functions exist now as TurboFan functions, so we can trigger the 32741cb0ef41Sopenharmony_ci // {kFinishedTopTierCompilation} event. 32751cb0ef41Sopenharmony_ci // The {kFinishedTopTierCompilation} event is needed for the C-API so 32761cb0ef41Sopenharmony_ci // that {serialize()} works after {deserialize()}. 32771cb0ef41Sopenharmony_ci finished_events_.Add(CompilationEvent::kFinishedTopTierCompilation); 32781cb0ef41Sopenharmony_ci } 32791cb0ef41Sopenharmony_ci } 32801cb0ef41Sopenharmony_ci compilation_progress_.assign(module->num_declared_functions, 32811cb0ef41Sopenharmony_ci kProgressAfterTurbofanDeserialization); 32821cb0ef41Sopenharmony_ci for (auto func_index : lazy_functions) { 32831cb0ef41Sopenharmony_ci native_module_->UseLazyStub(func_index); 32841cb0ef41Sopenharmony_ci 32851cb0ef41Sopenharmony_ci compilation_progress_[declared_function_index(module, func_index)] = 32861cb0ef41Sopenharmony_ci SetupCompilationProgressForFunction(/*lazy_function =*/true, 32871cb0ef41Sopenharmony_ci native_module_, enabled_features, 32881cb0ef41Sopenharmony_ci func_index); 32891cb0ef41Sopenharmony_ci } 32901cb0ef41Sopenharmony_ci for (auto func_index : liftoff_functions) { 32911cb0ef41Sopenharmony_ci if (lazy_module) { 32921cb0ef41Sopenharmony_ci native_module_->UseLazyStub(func_index); 32931cb0ef41Sopenharmony_ci } 32941cb0ef41Sopenharmony_ci // Check that {func_index} is not contained in {lazy_functions}. 32951cb0ef41Sopenharmony_ci DCHECK_EQ( 32961cb0ef41Sopenharmony_ci compilation_progress_[declared_function_index(module, func_index)], 32971cb0ef41Sopenharmony_ci kProgressAfterTurbofanDeserialization); 32981cb0ef41Sopenharmony_ci compilation_progress_[declared_function_index(module, func_index)] = 32991cb0ef41Sopenharmony_ci SetupCompilationProgressForFunction(lazy_module, native_module_, 33001cb0ef41Sopenharmony_ci enabled_features, func_index); 33011cb0ef41Sopenharmony_ci } 33021cb0ef41Sopenharmony_ci } 33031cb0ef41Sopenharmony_ci auto builder = std::make_unique<CompilationUnitBuilder>(native_module_); 33041cb0ef41Sopenharmony_ci InitializeCompilationUnits(std::move(builder)); 33051cb0ef41Sopenharmony_ci WaitForCompilationEvent(CompilationEvent::kFinishedBaselineCompilation); 33061cb0ef41Sopenharmony_ci} 33071cb0ef41Sopenharmony_ci 33081cb0ef41Sopenharmony_civoid CompilationStateImpl::InitializeRecompilation( 33091cb0ef41Sopenharmony_ci TieringState new_tiering_state, 33101cb0ef41Sopenharmony_ci std::unique_ptr<CompilationEventCallback> recompilation_finished_callback) { 33111cb0ef41Sopenharmony_ci DCHECK(!failed()); 33121cb0ef41Sopenharmony_ci 33131cb0ef41Sopenharmony_ci // Hold the mutex as long as possible, to synchronize between multiple 33141cb0ef41Sopenharmony_ci // recompilations that are triggered at the same time (e.g. when the profiler 33151cb0ef41Sopenharmony_ci // is disabled). 33161cb0ef41Sopenharmony_ci base::Optional<base::MutexGuard> guard(&callbacks_mutex_); 33171cb0ef41Sopenharmony_ci 33181cb0ef41Sopenharmony_ci // As long as there are outstanding recompilation functions, take part in 33191cb0ef41Sopenharmony_ci // compilation. This is to avoid recompiling for the same tier or for 33201cb0ef41Sopenharmony_ci // different tiers concurrently. Note that the compilation unit queues can run 33211cb0ef41Sopenharmony_ci // empty before {outstanding_recompilation_functions_} drops to zero. In this 33221cb0ef41Sopenharmony_ci // case, we do not wait for the last running compilation threads to finish 33231cb0ef41Sopenharmony_ci // their units, but just start our own recompilation already. 33241cb0ef41Sopenharmony_ci while (outstanding_recompilation_functions_ > 0 && 33251cb0ef41Sopenharmony_ci compilation_unit_queues_.GetTotalSize() > 0) { 33261cb0ef41Sopenharmony_ci guard.reset(); 33271cb0ef41Sopenharmony_ci constexpr JobDelegate* kNoDelegate = nullptr; 33281cb0ef41Sopenharmony_ci ExecuteCompilationUnits(native_module_weak_, async_counters_.get(), 33291cb0ef41Sopenharmony_ci kNoDelegate, kBaselineOrTopTier); 33301cb0ef41Sopenharmony_ci guard.emplace(&callbacks_mutex_); 33311cb0ef41Sopenharmony_ci } 33321cb0ef41Sopenharmony_ci 33331cb0ef41Sopenharmony_ci // Information about compilation progress is shared between this class and the 33341cb0ef41Sopenharmony_ci // NativeModule. Before updating information here, consult the NativeModule to 33351cb0ef41Sopenharmony_ci // find all functions that need recompilation. 33361cb0ef41Sopenharmony_ci // Since the current tiering state is updated on the NativeModule before 33371cb0ef41Sopenharmony_ci // triggering recompilation, it's OK if the information is slightly outdated. 33381cb0ef41Sopenharmony_ci // If we compile functions twice, the NativeModule will ignore all redundant 33391cb0ef41Sopenharmony_ci // code (or code compiled for the wrong tier). 33401cb0ef41Sopenharmony_ci std::vector<int> recompile_function_indexes = 33411cb0ef41Sopenharmony_ci native_module_->FindFunctionsToRecompile(new_tiering_state); 33421cb0ef41Sopenharmony_ci 33431cb0ef41Sopenharmony_ci callbacks_.emplace_back(std::move(recompilation_finished_callback)); 33441cb0ef41Sopenharmony_ci tiering_state_ = new_tiering_state; 33451cb0ef41Sopenharmony_ci 33461cb0ef41Sopenharmony_ci // If compilation progress is not initialized yet, then compilation didn't 33471cb0ef41Sopenharmony_ci // start yet, and new code will be kept tiered-down from the start. For 33481cb0ef41Sopenharmony_ci // streaming compilation, there is a special path to tier down later, when 33491cb0ef41Sopenharmony_ci // the module is complete. In any case, we don't need to recompile here. 33501cb0ef41Sopenharmony_ci base::Optional<CompilationUnitBuilder> builder; 33511cb0ef41Sopenharmony_ci if (compilation_progress_.size() > 0) { 33521cb0ef41Sopenharmony_ci builder.emplace(native_module_); 33531cb0ef41Sopenharmony_ci const WasmModule* module = native_module_->module(); 33541cb0ef41Sopenharmony_ci DCHECK_EQ(module->num_declared_functions, compilation_progress_.size()); 33551cb0ef41Sopenharmony_ci DCHECK_GE(module->num_declared_functions, 33561cb0ef41Sopenharmony_ci recompile_function_indexes.size()); 33571cb0ef41Sopenharmony_ci outstanding_recompilation_functions_ = 33581cb0ef41Sopenharmony_ci static_cast<int>(recompile_function_indexes.size()); 33591cb0ef41Sopenharmony_ci // Restart recompilation if another recompilation is already happening. 33601cb0ef41Sopenharmony_ci for (auto& progress : compilation_progress_) { 33611cb0ef41Sopenharmony_ci progress = MissingRecompilationField::update(progress, false); 33621cb0ef41Sopenharmony_ci } 33631cb0ef41Sopenharmony_ci auto new_tier = new_tiering_state == kTieredDown ? ExecutionTier::kLiftoff 33641cb0ef41Sopenharmony_ci : ExecutionTier::kTurbofan; 33651cb0ef41Sopenharmony_ci int imported = module->num_imported_functions; 33661cb0ef41Sopenharmony_ci // Generate necessary compilation units on the fly. 33671cb0ef41Sopenharmony_ci for (int function_index : recompile_function_indexes) { 33681cb0ef41Sopenharmony_ci DCHECK_LE(imported, function_index); 33691cb0ef41Sopenharmony_ci int slot_index = function_index - imported; 33701cb0ef41Sopenharmony_ci auto& progress = compilation_progress_[slot_index]; 33711cb0ef41Sopenharmony_ci progress = MissingRecompilationField::update(progress, true); 33721cb0ef41Sopenharmony_ci builder->AddRecompilationUnit(function_index, new_tier); 33731cb0ef41Sopenharmony_ci } 33741cb0ef41Sopenharmony_ci } 33751cb0ef41Sopenharmony_ci 33761cb0ef41Sopenharmony_ci // Trigger callback if module needs no recompilation. 33771cb0ef41Sopenharmony_ci if (outstanding_recompilation_functions_ == 0) { 33781cb0ef41Sopenharmony_ci TriggerCallbacks(base::EnumSet<CompilationEvent>( 33791cb0ef41Sopenharmony_ci {CompilationEvent::kFinishedRecompilation})); 33801cb0ef41Sopenharmony_ci } 33811cb0ef41Sopenharmony_ci 33821cb0ef41Sopenharmony_ci if (builder.has_value()) { 33831cb0ef41Sopenharmony_ci // Avoid holding lock while scheduling a compile job. 33841cb0ef41Sopenharmony_ci guard.reset(); 33851cb0ef41Sopenharmony_ci builder->Commit(); 33861cb0ef41Sopenharmony_ci } 33871cb0ef41Sopenharmony_ci} 33881cb0ef41Sopenharmony_ci 33891cb0ef41Sopenharmony_civoid CompilationStateImpl::AddCallback( 33901cb0ef41Sopenharmony_ci std::unique_ptr<CompilationEventCallback> callback) { 33911cb0ef41Sopenharmony_ci base::MutexGuard callbacks_guard(&callbacks_mutex_); 33921cb0ef41Sopenharmony_ci // Immediately trigger events that already happened. 33931cb0ef41Sopenharmony_ci for (auto event : {CompilationEvent::kFinishedExportWrappers, 33941cb0ef41Sopenharmony_ci CompilationEvent::kFinishedBaselineCompilation, 33951cb0ef41Sopenharmony_ci CompilationEvent::kFinishedTopTierCompilation, 33961cb0ef41Sopenharmony_ci CompilationEvent::kFailedCompilation}) { 33971cb0ef41Sopenharmony_ci if (finished_events_.contains(event)) { 33981cb0ef41Sopenharmony_ci callback->call(event); 33991cb0ef41Sopenharmony_ci } 34001cb0ef41Sopenharmony_ci } 34011cb0ef41Sopenharmony_ci constexpr base::EnumSet<CompilationEvent> kFinalEvents{ 34021cb0ef41Sopenharmony_ci CompilationEvent::kFinishedTopTierCompilation, 34031cb0ef41Sopenharmony_ci CompilationEvent::kFailedCompilation}; 34041cb0ef41Sopenharmony_ci if (!finished_events_.contains_any(kFinalEvents)) { 34051cb0ef41Sopenharmony_ci callbacks_.emplace_back(std::move(callback)); 34061cb0ef41Sopenharmony_ci } 34071cb0ef41Sopenharmony_ci} 34081cb0ef41Sopenharmony_ci 34091cb0ef41Sopenharmony_civoid CompilationStateImpl::CommitCompilationUnits( 34101cb0ef41Sopenharmony_ci base::Vector<WasmCompilationUnit> baseline_units, 34111cb0ef41Sopenharmony_ci base::Vector<WasmCompilationUnit> top_tier_units, 34121cb0ef41Sopenharmony_ci base::Vector<std::shared_ptr<JSToWasmWrapperCompilationUnit>> 34131cb0ef41Sopenharmony_ci js_to_wasm_wrapper_units) { 34141cb0ef41Sopenharmony_ci if (!js_to_wasm_wrapper_units.empty()) { 34151cb0ef41Sopenharmony_ci // |js_to_wasm_wrapper_units_| will only be initialized once. 34161cb0ef41Sopenharmony_ci DCHECK_EQ(0, outstanding_js_to_wasm_wrappers_.load()); 34171cb0ef41Sopenharmony_ci js_to_wasm_wrapper_units_.insert(js_to_wasm_wrapper_units_.end(), 34181cb0ef41Sopenharmony_ci js_to_wasm_wrapper_units.begin(), 34191cb0ef41Sopenharmony_ci js_to_wasm_wrapper_units.end()); 34201cb0ef41Sopenharmony_ci // Use release semantics such that updates to {js_to_wasm_wrapper_units_} 34211cb0ef41Sopenharmony_ci // are available to other threads doing an acquire load. 34221cb0ef41Sopenharmony_ci outstanding_js_to_wasm_wrappers_.store(js_to_wasm_wrapper_units.size(), 34231cb0ef41Sopenharmony_ci std::memory_order_release); 34241cb0ef41Sopenharmony_ci } 34251cb0ef41Sopenharmony_ci if (!baseline_units.empty() || !top_tier_units.empty()) { 34261cb0ef41Sopenharmony_ci compilation_unit_queues_.AddUnits(baseline_units, top_tier_units, 34271cb0ef41Sopenharmony_ci native_module_->module()); 34281cb0ef41Sopenharmony_ci } 34291cb0ef41Sopenharmony_ci compile_job_->NotifyConcurrencyIncrease(); 34301cb0ef41Sopenharmony_ci} 34311cb0ef41Sopenharmony_ci 34321cb0ef41Sopenharmony_civoid CompilationStateImpl::CommitTopTierCompilationUnit( 34331cb0ef41Sopenharmony_ci WasmCompilationUnit unit) { 34341cb0ef41Sopenharmony_ci CommitCompilationUnits({}, {&unit, 1}, {}); 34351cb0ef41Sopenharmony_ci} 34361cb0ef41Sopenharmony_ci 34371cb0ef41Sopenharmony_civoid CompilationStateImpl::AddTopTierPriorityCompilationUnit( 34381cb0ef41Sopenharmony_ci WasmCompilationUnit unit, size_t priority) { 34391cb0ef41Sopenharmony_ci compilation_unit_queues_.AddTopTierPriorityUnit(unit, priority); 34401cb0ef41Sopenharmony_ci { 34411cb0ef41Sopenharmony_ci base::MutexGuard guard(&callbacks_mutex_); 34421cb0ef41Sopenharmony_ci outstanding_top_tier_functions_++; 34431cb0ef41Sopenharmony_ci } 34441cb0ef41Sopenharmony_ci compile_job_->NotifyConcurrencyIncrease(); 34451cb0ef41Sopenharmony_ci} 34461cb0ef41Sopenharmony_ci 34471cb0ef41Sopenharmony_cistd::shared_ptr<JSToWasmWrapperCompilationUnit> 34481cb0ef41Sopenharmony_ciCompilationStateImpl::GetNextJSToWasmWrapperCompilationUnit() { 34491cb0ef41Sopenharmony_ci size_t outstanding_units = 34501cb0ef41Sopenharmony_ci outstanding_js_to_wasm_wrappers_.load(std::memory_order_relaxed); 34511cb0ef41Sopenharmony_ci // Use acquire semantics such that initialization of 34521cb0ef41Sopenharmony_ci // {js_to_wasm_wrapper_units_} is available. 34531cb0ef41Sopenharmony_ci while (outstanding_units && 34541cb0ef41Sopenharmony_ci !outstanding_js_to_wasm_wrappers_.compare_exchange_weak( 34551cb0ef41Sopenharmony_ci outstanding_units, outstanding_units - 1, 34561cb0ef41Sopenharmony_ci std::memory_order_acquire)) { 34571cb0ef41Sopenharmony_ci // Retry with updated {outstanding_units}. 34581cb0ef41Sopenharmony_ci } 34591cb0ef41Sopenharmony_ci if (outstanding_units == 0) return nullptr; 34601cb0ef41Sopenharmony_ci return js_to_wasm_wrapper_units_[outstanding_units - 1]; 34611cb0ef41Sopenharmony_ci} 34621cb0ef41Sopenharmony_ci 34631cb0ef41Sopenharmony_civoid CompilationStateImpl::FinalizeJSToWasmWrappers( 34641cb0ef41Sopenharmony_ci Isolate* isolate, const WasmModule* module, 34651cb0ef41Sopenharmony_ci Handle<FixedArray>* export_wrappers_out) { 34661cb0ef41Sopenharmony_ci *export_wrappers_out = isolate->factory()->NewFixedArray( 34671cb0ef41Sopenharmony_ci MaxNumExportWrappers(module), AllocationType::kOld); 34681cb0ef41Sopenharmony_ci // TODO(6792): Wrappers below are allocated with {Factory::NewCode}. As an 34691cb0ef41Sopenharmony_ci // optimization we create a code memory modification scope that avoids 34701cb0ef41Sopenharmony_ci // changing the page permissions back-and-forth between RWX and RX, because 34711cb0ef41Sopenharmony_ci // many such wrapper are allocated in sequence below. 34721cb0ef41Sopenharmony_ci TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("v8.wasm.detailed"), 34731cb0ef41Sopenharmony_ci "wasm.FinalizeJSToWasmWrappers", "wrappers", 34741cb0ef41Sopenharmony_ci js_to_wasm_wrapper_units_.size()); 34751cb0ef41Sopenharmony_ci CodePageCollectionMemoryModificationScope modification_scope(isolate->heap()); 34761cb0ef41Sopenharmony_ci for (auto& unit : js_to_wasm_wrapper_units_) { 34771cb0ef41Sopenharmony_ci DCHECK_EQ(isolate, unit->isolate()); 34781cb0ef41Sopenharmony_ci Handle<Code> code = unit->Finalize(); 34791cb0ef41Sopenharmony_ci int wrapper_index = 34801cb0ef41Sopenharmony_ci GetExportWrapperIndex(module, unit->sig(), unit->is_import()); 34811cb0ef41Sopenharmony_ci (*export_wrappers_out)->set(wrapper_index, ToCodeT(*code)); 34821cb0ef41Sopenharmony_ci RecordStats(*code, isolate->counters()); 34831cb0ef41Sopenharmony_ci } 34841cb0ef41Sopenharmony_ci} 34851cb0ef41Sopenharmony_ci 34861cb0ef41Sopenharmony_ciCompilationUnitQueues::Queue* CompilationStateImpl::GetQueueForCompileTask( 34871cb0ef41Sopenharmony_ci int task_id) { 34881cb0ef41Sopenharmony_ci return compilation_unit_queues_.GetQueueForTask(task_id); 34891cb0ef41Sopenharmony_ci} 34901cb0ef41Sopenharmony_ci 34911cb0ef41Sopenharmony_cibase::Optional<WasmCompilationUnit> 34921cb0ef41Sopenharmony_ciCompilationStateImpl::GetNextCompilationUnit( 34931cb0ef41Sopenharmony_ci CompilationUnitQueues::Queue* queue, CompileBaselineOnly baseline_only) { 34941cb0ef41Sopenharmony_ci return compilation_unit_queues_.GetNextUnit(queue, baseline_only); 34951cb0ef41Sopenharmony_ci} 34961cb0ef41Sopenharmony_ci 34971cb0ef41Sopenharmony_civoid CompilationStateImpl::OnFinishedUnits( 34981cb0ef41Sopenharmony_ci base::Vector<WasmCode*> code_vector) { 34991cb0ef41Sopenharmony_ci TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("v8.wasm.detailed"), 35001cb0ef41Sopenharmony_ci "wasm.OnFinishedUnits", "units", code_vector.size()); 35011cb0ef41Sopenharmony_ci 35021cb0ef41Sopenharmony_ci base::MutexGuard guard(&callbacks_mutex_); 35031cb0ef41Sopenharmony_ci 35041cb0ef41Sopenharmony_ci // In case of no outstanding compilation units we can return early. 35051cb0ef41Sopenharmony_ci // This is especially important for lazy modules that were deserialized. 35061cb0ef41Sopenharmony_ci // Compilation progress was not set up in these cases. 35071cb0ef41Sopenharmony_ci if (outstanding_baseline_units_ == 0 && outstanding_export_wrappers_ == 0 && 35081cb0ef41Sopenharmony_ci outstanding_top_tier_functions_ == 0 && 35091cb0ef41Sopenharmony_ci outstanding_recompilation_functions_ == 0) { 35101cb0ef41Sopenharmony_ci return; 35111cb0ef41Sopenharmony_ci } 35121cb0ef41Sopenharmony_ci 35131cb0ef41Sopenharmony_ci // Assume an order of execution tiers that represents the quality of their 35141cb0ef41Sopenharmony_ci // generated code. 35151cb0ef41Sopenharmony_ci static_assert(ExecutionTier::kNone < ExecutionTier::kLiftoff && 35161cb0ef41Sopenharmony_ci ExecutionTier::kLiftoff < ExecutionTier::kTurbofan, 35171cb0ef41Sopenharmony_ci "Assume an order on execution tiers"); 35181cb0ef41Sopenharmony_ci 35191cb0ef41Sopenharmony_ci DCHECK_EQ(compilation_progress_.size(), 35201cb0ef41Sopenharmony_ci native_module_->module()->num_declared_functions); 35211cb0ef41Sopenharmony_ci 35221cb0ef41Sopenharmony_ci base::EnumSet<CompilationEvent> triggered_events; 35231cb0ef41Sopenharmony_ci 35241cb0ef41Sopenharmony_ci for (size_t i = 0; i < code_vector.size(); i++) { 35251cb0ef41Sopenharmony_ci WasmCode* code = code_vector[i]; 35261cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(code); 35271cb0ef41Sopenharmony_ci DCHECK_LT(code->index(), native_module_->num_functions()); 35281cb0ef41Sopenharmony_ci 35291cb0ef41Sopenharmony_ci if (code->index() < 35301cb0ef41Sopenharmony_ci static_cast<int>(native_module_->num_imported_functions())) { 35311cb0ef41Sopenharmony_ci // Import wrapper. 35321cb0ef41Sopenharmony_ci DCHECK_EQ(code->tier(), ExecutionTier::kTurbofan); 35331cb0ef41Sopenharmony_ci outstanding_baseline_units_--; 35341cb0ef41Sopenharmony_ci } else { 35351cb0ef41Sopenharmony_ci // Function. 35361cb0ef41Sopenharmony_ci DCHECK_NE(code->tier(), ExecutionTier::kNone); 35371cb0ef41Sopenharmony_ci 35381cb0ef41Sopenharmony_ci // Read function's compilation progress. 35391cb0ef41Sopenharmony_ci // This view on the compilation progress may differ from the actually 35401cb0ef41Sopenharmony_ci // compiled code. Any lazily compiled function does not contribute to the 35411cb0ef41Sopenharmony_ci // compilation progress but may publish code to the code manager. 35421cb0ef41Sopenharmony_ci int slot_index = 35431cb0ef41Sopenharmony_ci declared_function_index(native_module_->module(), code->index()); 35441cb0ef41Sopenharmony_ci uint8_t function_progress = compilation_progress_[slot_index]; 35451cb0ef41Sopenharmony_ci ExecutionTier required_baseline_tier = 35461cb0ef41Sopenharmony_ci RequiredBaselineTierField::decode(function_progress); 35471cb0ef41Sopenharmony_ci ExecutionTier required_top_tier = 35481cb0ef41Sopenharmony_ci RequiredTopTierField::decode(function_progress); 35491cb0ef41Sopenharmony_ci ExecutionTier reached_tier = ReachedTierField::decode(function_progress); 35501cb0ef41Sopenharmony_ci 35511cb0ef41Sopenharmony_ci // Check whether required baseline or top tier are reached. 35521cb0ef41Sopenharmony_ci if (reached_tier < required_baseline_tier && 35531cb0ef41Sopenharmony_ci required_baseline_tier <= code->tier()) { 35541cb0ef41Sopenharmony_ci DCHECK_GT(outstanding_baseline_units_, 0); 35551cb0ef41Sopenharmony_ci outstanding_baseline_units_--; 35561cb0ef41Sopenharmony_ci } 35571cb0ef41Sopenharmony_ci if (code->tier() == ExecutionTier::kTurbofan) { 35581cb0ef41Sopenharmony_ci bytes_since_last_chunk_ += code->instructions().size(); 35591cb0ef41Sopenharmony_ci } 35601cb0ef41Sopenharmony_ci if (reached_tier < required_top_tier && 35611cb0ef41Sopenharmony_ci required_top_tier <= code->tier()) { 35621cb0ef41Sopenharmony_ci DCHECK_GT(outstanding_top_tier_functions_, 0); 35631cb0ef41Sopenharmony_ci outstanding_top_tier_functions_--; 35641cb0ef41Sopenharmony_ci } 35651cb0ef41Sopenharmony_ci 35661cb0ef41Sopenharmony_ci if (V8_UNLIKELY(MissingRecompilationField::decode(function_progress))) { 35671cb0ef41Sopenharmony_ci DCHECK_LT(0, outstanding_recompilation_functions_); 35681cb0ef41Sopenharmony_ci // If tiering up, accept any TurboFan code. For tiering down, look at 35691cb0ef41Sopenharmony_ci // the {for_debugging} flag. The tier can be Liftoff or TurboFan and is 35701cb0ef41Sopenharmony_ci // irrelevant here. In particular, we want to ignore any outstanding 35711cb0ef41Sopenharmony_ci // non-debugging units. 35721cb0ef41Sopenharmony_ci bool matches = tiering_state_ == kTieredDown 35731cb0ef41Sopenharmony_ci ? code->for_debugging() 35741cb0ef41Sopenharmony_ci : code->tier() == ExecutionTier::kTurbofan; 35751cb0ef41Sopenharmony_ci if (matches) { 35761cb0ef41Sopenharmony_ci outstanding_recompilation_functions_--; 35771cb0ef41Sopenharmony_ci compilation_progress_[slot_index] = MissingRecompilationField::update( 35781cb0ef41Sopenharmony_ci compilation_progress_[slot_index], false); 35791cb0ef41Sopenharmony_ci if (outstanding_recompilation_functions_ == 0) { 35801cb0ef41Sopenharmony_ci triggered_events.Add(CompilationEvent::kFinishedRecompilation); 35811cb0ef41Sopenharmony_ci } 35821cb0ef41Sopenharmony_ci } 35831cb0ef41Sopenharmony_ci } 35841cb0ef41Sopenharmony_ci 35851cb0ef41Sopenharmony_ci // Update function's compilation progress. 35861cb0ef41Sopenharmony_ci if (code->tier() > reached_tier) { 35871cb0ef41Sopenharmony_ci compilation_progress_[slot_index] = ReachedTierField::update( 35881cb0ef41Sopenharmony_ci compilation_progress_[slot_index], code->tier()); 35891cb0ef41Sopenharmony_ci } 35901cb0ef41Sopenharmony_ci DCHECK_LE(0, outstanding_baseline_units_); 35911cb0ef41Sopenharmony_ci } 35921cb0ef41Sopenharmony_ci } 35931cb0ef41Sopenharmony_ci 35941cb0ef41Sopenharmony_ci TriggerCallbacks(triggered_events); 35951cb0ef41Sopenharmony_ci} 35961cb0ef41Sopenharmony_ci 35971cb0ef41Sopenharmony_civoid CompilationStateImpl::OnFinishedJSToWasmWrapperUnits(int num) { 35981cb0ef41Sopenharmony_ci if (num == 0) return; 35991cb0ef41Sopenharmony_ci base::MutexGuard guard(&callbacks_mutex_); 36001cb0ef41Sopenharmony_ci DCHECK_GE(outstanding_export_wrappers_, num); 36011cb0ef41Sopenharmony_ci outstanding_export_wrappers_ -= num; 36021cb0ef41Sopenharmony_ci TriggerCallbacks(); 36031cb0ef41Sopenharmony_ci} 36041cb0ef41Sopenharmony_ci 36051cb0ef41Sopenharmony_civoid CompilationStateImpl::TriggerCallbacks( 36061cb0ef41Sopenharmony_ci base::EnumSet<CompilationEvent> triggered_events) { 36071cb0ef41Sopenharmony_ci DCHECK(!callbacks_mutex_.TryLock()); 36081cb0ef41Sopenharmony_ci 36091cb0ef41Sopenharmony_ci if (outstanding_export_wrappers_ == 0) { 36101cb0ef41Sopenharmony_ci triggered_events.Add(CompilationEvent::kFinishedExportWrappers); 36111cb0ef41Sopenharmony_ci if (outstanding_baseline_units_ == 0) { 36121cb0ef41Sopenharmony_ci triggered_events.Add(CompilationEvent::kFinishedBaselineCompilation); 36131cb0ef41Sopenharmony_ci if (dynamic_tiering_ == DynamicTiering::kDisabled && 36141cb0ef41Sopenharmony_ci outstanding_top_tier_functions_ == 0) { 36151cb0ef41Sopenharmony_ci triggered_events.Add(CompilationEvent::kFinishedTopTierCompilation); 36161cb0ef41Sopenharmony_ci } 36171cb0ef41Sopenharmony_ci } 36181cb0ef41Sopenharmony_ci } 36191cb0ef41Sopenharmony_ci 36201cb0ef41Sopenharmony_ci if (dynamic_tiering_ == DynamicTiering::kEnabled && 36211cb0ef41Sopenharmony_ci static_cast<size_t>(FLAG_wasm_caching_threshold) < 36221cb0ef41Sopenharmony_ci bytes_since_last_chunk_) { 36231cb0ef41Sopenharmony_ci triggered_events.Add(CompilationEvent::kFinishedCompilationChunk); 36241cb0ef41Sopenharmony_ci bytes_since_last_chunk_ = 0; 36251cb0ef41Sopenharmony_ci } 36261cb0ef41Sopenharmony_ci if (compile_failed_.load(std::memory_order_relaxed)) { 36271cb0ef41Sopenharmony_ci // *Only* trigger the "failed" event. 36281cb0ef41Sopenharmony_ci triggered_events = 36291cb0ef41Sopenharmony_ci base::EnumSet<CompilationEvent>({CompilationEvent::kFailedCompilation}); 36301cb0ef41Sopenharmony_ci } 36311cb0ef41Sopenharmony_ci 36321cb0ef41Sopenharmony_ci if (triggered_events.empty()) return; 36331cb0ef41Sopenharmony_ci 36341cb0ef41Sopenharmony_ci // Don't trigger past events again. 36351cb0ef41Sopenharmony_ci triggered_events -= finished_events_; 36361cb0ef41Sopenharmony_ci // Recompilation can happen multiple times, thus do not store this. There can 36371cb0ef41Sopenharmony_ci // also be multiple compilation chunks. 36381cb0ef41Sopenharmony_ci finished_events_ |= triggered_events - 36391cb0ef41Sopenharmony_ci CompilationEvent::kFinishedRecompilation - 36401cb0ef41Sopenharmony_ci CompilationEvent::kFinishedCompilationChunk; 36411cb0ef41Sopenharmony_ci 36421cb0ef41Sopenharmony_ci for (auto event : 36431cb0ef41Sopenharmony_ci {std::make_pair(CompilationEvent::kFailedCompilation, 36441cb0ef41Sopenharmony_ci "wasm.CompilationFailed"), 36451cb0ef41Sopenharmony_ci std::make_pair(CompilationEvent::kFinishedExportWrappers, 36461cb0ef41Sopenharmony_ci "wasm.ExportWrappersFinished"), 36471cb0ef41Sopenharmony_ci std::make_pair(CompilationEvent::kFinishedBaselineCompilation, 36481cb0ef41Sopenharmony_ci "wasm.BaselineFinished"), 36491cb0ef41Sopenharmony_ci std::make_pair(CompilationEvent::kFinishedTopTierCompilation, 36501cb0ef41Sopenharmony_ci "wasm.TopTierFinished"), 36511cb0ef41Sopenharmony_ci std::make_pair(CompilationEvent::kFinishedCompilationChunk, 36521cb0ef41Sopenharmony_ci "wasm.CompilationChunkFinished"), 36531cb0ef41Sopenharmony_ci std::make_pair(CompilationEvent::kFinishedRecompilation, 36541cb0ef41Sopenharmony_ci "wasm.RecompilationFinished")}) { 36551cb0ef41Sopenharmony_ci if (!triggered_events.contains(event.first)) continue; 36561cb0ef41Sopenharmony_ci DCHECK_NE(compilation_id_, kInvalidCompilationID); 36571cb0ef41Sopenharmony_ci TRACE_EVENT1("v8.wasm", event.second, "id", compilation_id_); 36581cb0ef41Sopenharmony_ci for (auto& callback : callbacks_) { 36591cb0ef41Sopenharmony_ci callback->call(event.first); 36601cb0ef41Sopenharmony_ci } 36611cb0ef41Sopenharmony_ci } 36621cb0ef41Sopenharmony_ci 36631cb0ef41Sopenharmony_ci if (outstanding_baseline_units_ == 0 && outstanding_export_wrappers_ == 0 && 36641cb0ef41Sopenharmony_ci outstanding_top_tier_functions_ == 0 && 36651cb0ef41Sopenharmony_ci outstanding_recompilation_functions_ == 0) { 36661cb0ef41Sopenharmony_ci callbacks_.erase( 36671cb0ef41Sopenharmony_ci std::remove_if( 36681cb0ef41Sopenharmony_ci callbacks_.begin(), callbacks_.end(), 36691cb0ef41Sopenharmony_ci [](std::unique_ptr<CompilationEventCallback>& event) { 36701cb0ef41Sopenharmony_ci return event->release_after_final_event() == 36711cb0ef41Sopenharmony_ci CompilationEventCallback::ReleaseAfterFinalEvent::kRelease; 36721cb0ef41Sopenharmony_ci }), 36731cb0ef41Sopenharmony_ci callbacks_.end()); 36741cb0ef41Sopenharmony_ci } 36751cb0ef41Sopenharmony_ci} 36761cb0ef41Sopenharmony_ci 36771cb0ef41Sopenharmony_civoid CompilationStateImpl::OnCompilationStopped(WasmFeatures detected) { 36781cb0ef41Sopenharmony_ci base::MutexGuard guard(&mutex_); 36791cb0ef41Sopenharmony_ci detected_features_.Add(detected); 36801cb0ef41Sopenharmony_ci} 36811cb0ef41Sopenharmony_ci 36821cb0ef41Sopenharmony_civoid CompilationStateImpl::PublishDetectedFeatures(Isolate* isolate) { 36831cb0ef41Sopenharmony_ci // Notifying the isolate of the feature counts must take place under 36841cb0ef41Sopenharmony_ci // the mutex, because even if we have finished baseline compilation, 36851cb0ef41Sopenharmony_ci // tiering compilations may still occur in the background. 36861cb0ef41Sopenharmony_ci base::MutexGuard guard(&mutex_); 36871cb0ef41Sopenharmony_ci UpdateFeatureUseCounts(isolate, detected_features_); 36881cb0ef41Sopenharmony_ci} 36891cb0ef41Sopenharmony_ci 36901cb0ef41Sopenharmony_civoid CompilationStateImpl::PublishCompilationResults( 36911cb0ef41Sopenharmony_ci std::vector<std::unique_ptr<WasmCode>> unpublished_code) { 36921cb0ef41Sopenharmony_ci if (unpublished_code.empty()) return; 36931cb0ef41Sopenharmony_ci 36941cb0ef41Sopenharmony_ci // For import wrapper compilation units, add result to the cache. 36951cb0ef41Sopenharmony_ci int num_imported_functions = native_module_->num_imported_functions(); 36961cb0ef41Sopenharmony_ci WasmImportWrapperCache* cache = native_module_->import_wrapper_cache(); 36971cb0ef41Sopenharmony_ci for (const auto& code : unpublished_code) { 36981cb0ef41Sopenharmony_ci int func_index = code->index(); 36991cb0ef41Sopenharmony_ci DCHECK_LE(0, func_index); 37001cb0ef41Sopenharmony_ci DCHECK_LT(func_index, native_module_->num_functions()); 37011cb0ef41Sopenharmony_ci if (func_index < num_imported_functions) { 37021cb0ef41Sopenharmony_ci const FunctionSig* sig = 37031cb0ef41Sopenharmony_ci native_module_->module()->functions[func_index].sig; 37041cb0ef41Sopenharmony_ci WasmImportWrapperCache::CacheKey key( 37051cb0ef41Sopenharmony_ci compiler::kDefaultImportCallKind, sig, 37061cb0ef41Sopenharmony_ci static_cast<int>(sig->parameter_count()), kNoSuspend); 37071cb0ef41Sopenharmony_ci // If two imported functions have the same key, only one of them should 37081cb0ef41Sopenharmony_ci // have been added as a compilation unit. So it is always the first time 37091cb0ef41Sopenharmony_ci // we compile a wrapper for this key here. 37101cb0ef41Sopenharmony_ci DCHECK_NULL((*cache)[key]); 37111cb0ef41Sopenharmony_ci (*cache)[key] = code.get(); 37121cb0ef41Sopenharmony_ci code->IncRef(); 37131cb0ef41Sopenharmony_ci } 37141cb0ef41Sopenharmony_ci } 37151cb0ef41Sopenharmony_ci PublishCode(base::VectorOf(unpublished_code)); 37161cb0ef41Sopenharmony_ci} 37171cb0ef41Sopenharmony_ci 37181cb0ef41Sopenharmony_civoid CompilationStateImpl::PublishCode( 37191cb0ef41Sopenharmony_ci base::Vector<std::unique_ptr<WasmCode>> code) { 37201cb0ef41Sopenharmony_ci WasmCodeRefScope code_ref_scope; 37211cb0ef41Sopenharmony_ci std::vector<WasmCode*> published_code = 37221cb0ef41Sopenharmony_ci native_module_->PublishCode(std::move(code)); 37231cb0ef41Sopenharmony_ci // Defer logging code in case wire bytes were not fully received yet. 37241cb0ef41Sopenharmony_ci if (native_module_->HasWireBytes()) { 37251cb0ef41Sopenharmony_ci GetWasmEngine()->LogCode(base::VectorOf(published_code)); 37261cb0ef41Sopenharmony_ci } 37271cb0ef41Sopenharmony_ci 37281cb0ef41Sopenharmony_ci OnFinishedUnits(base::VectorOf(std::move(published_code))); 37291cb0ef41Sopenharmony_ci} 37301cb0ef41Sopenharmony_ci 37311cb0ef41Sopenharmony_civoid CompilationStateImpl::SchedulePublishCompilationResults( 37321cb0ef41Sopenharmony_ci std::vector<std::unique_ptr<WasmCode>> unpublished_code) { 37331cb0ef41Sopenharmony_ci { 37341cb0ef41Sopenharmony_ci base::MutexGuard guard(&publish_mutex_); 37351cb0ef41Sopenharmony_ci if (publisher_running_) { 37361cb0ef41Sopenharmony_ci // Add new code to the queue and return. 37371cb0ef41Sopenharmony_ci publish_queue_.reserve(publish_queue_.size() + unpublished_code.size()); 37381cb0ef41Sopenharmony_ci for (auto& c : unpublished_code) { 37391cb0ef41Sopenharmony_ci publish_queue_.emplace_back(std::move(c)); 37401cb0ef41Sopenharmony_ci } 37411cb0ef41Sopenharmony_ci return; 37421cb0ef41Sopenharmony_ci } 37431cb0ef41Sopenharmony_ci publisher_running_ = true; 37441cb0ef41Sopenharmony_ci } 37451cb0ef41Sopenharmony_ci CodeSpaceWriteScope code_space_write_scope(native_module_); 37461cb0ef41Sopenharmony_ci while (true) { 37471cb0ef41Sopenharmony_ci PublishCompilationResults(std::move(unpublished_code)); 37481cb0ef41Sopenharmony_ci unpublished_code.clear(); 37491cb0ef41Sopenharmony_ci 37501cb0ef41Sopenharmony_ci // Keep publishing new code that came in. 37511cb0ef41Sopenharmony_ci base::MutexGuard guard(&publish_mutex_); 37521cb0ef41Sopenharmony_ci DCHECK(publisher_running_); 37531cb0ef41Sopenharmony_ci if (publish_queue_.empty()) { 37541cb0ef41Sopenharmony_ci publisher_running_ = false; 37551cb0ef41Sopenharmony_ci return; 37561cb0ef41Sopenharmony_ci } 37571cb0ef41Sopenharmony_ci unpublished_code.swap(publish_queue_); 37581cb0ef41Sopenharmony_ci } 37591cb0ef41Sopenharmony_ci} 37601cb0ef41Sopenharmony_ci 37611cb0ef41Sopenharmony_cisize_t CompilationStateImpl::NumOutstandingCompilations() const { 37621cb0ef41Sopenharmony_ci size_t outstanding_wrappers = 37631cb0ef41Sopenharmony_ci outstanding_js_to_wasm_wrappers_.load(std::memory_order_relaxed); 37641cb0ef41Sopenharmony_ci size_t outstanding_functions = compilation_unit_queues_.GetTotalSize(); 37651cb0ef41Sopenharmony_ci return outstanding_wrappers + outstanding_functions; 37661cb0ef41Sopenharmony_ci} 37671cb0ef41Sopenharmony_ci 37681cb0ef41Sopenharmony_civoid CompilationStateImpl::SetError() { 37691cb0ef41Sopenharmony_ci compile_cancelled_.store(true, std::memory_order_relaxed); 37701cb0ef41Sopenharmony_ci if (compile_failed_.exchange(true, std::memory_order_relaxed)) { 37711cb0ef41Sopenharmony_ci return; // Already failed before. 37721cb0ef41Sopenharmony_ci } 37731cb0ef41Sopenharmony_ci 37741cb0ef41Sopenharmony_ci base::MutexGuard callbacks_guard(&callbacks_mutex_); 37751cb0ef41Sopenharmony_ci TriggerCallbacks(); 37761cb0ef41Sopenharmony_ci callbacks_.clear(); 37771cb0ef41Sopenharmony_ci} 37781cb0ef41Sopenharmony_ci 37791cb0ef41Sopenharmony_civoid CompilationStateImpl::WaitForCompilationEvent( 37801cb0ef41Sopenharmony_ci CompilationEvent expect_event) { 37811cb0ef41Sopenharmony_ci class WaitForCompilationEventCallback : public CompilationEventCallback { 37821cb0ef41Sopenharmony_ci public: 37831cb0ef41Sopenharmony_ci WaitForCompilationEventCallback(std::shared_ptr<base::Semaphore> semaphore, 37841cb0ef41Sopenharmony_ci std::shared_ptr<std::atomic<bool>> done, 37851cb0ef41Sopenharmony_ci base::EnumSet<CompilationEvent> events) 37861cb0ef41Sopenharmony_ci : semaphore_(std::move(semaphore)), 37871cb0ef41Sopenharmony_ci done_(std::move(done)), 37881cb0ef41Sopenharmony_ci events_(events) {} 37891cb0ef41Sopenharmony_ci 37901cb0ef41Sopenharmony_ci void call(CompilationEvent event) override { 37911cb0ef41Sopenharmony_ci if (!events_.contains(event)) return; 37921cb0ef41Sopenharmony_ci done_->store(true, std::memory_order_relaxed); 37931cb0ef41Sopenharmony_ci semaphore_->Signal(); 37941cb0ef41Sopenharmony_ci } 37951cb0ef41Sopenharmony_ci 37961cb0ef41Sopenharmony_ci private: 37971cb0ef41Sopenharmony_ci std::shared_ptr<base::Semaphore> semaphore_; 37981cb0ef41Sopenharmony_ci std::shared_ptr<std::atomic<bool>> done_; 37991cb0ef41Sopenharmony_ci base::EnumSet<CompilationEvent> events_; 38001cb0ef41Sopenharmony_ci }; 38011cb0ef41Sopenharmony_ci 38021cb0ef41Sopenharmony_ci auto semaphore = std::make_shared<base::Semaphore>(0); 38031cb0ef41Sopenharmony_ci auto done = std::make_shared<std::atomic<bool>>(false); 38041cb0ef41Sopenharmony_ci base::EnumSet<CompilationEvent> events{expect_event, 38051cb0ef41Sopenharmony_ci CompilationEvent::kFailedCompilation}; 38061cb0ef41Sopenharmony_ci { 38071cb0ef41Sopenharmony_ci base::MutexGuard callbacks_guard(&callbacks_mutex_); 38081cb0ef41Sopenharmony_ci if (finished_events_.contains_any(events)) return; 38091cb0ef41Sopenharmony_ci callbacks_.emplace_back(std::make_unique<WaitForCompilationEventCallback>( 38101cb0ef41Sopenharmony_ci semaphore, done, events)); 38111cb0ef41Sopenharmony_ci } 38121cb0ef41Sopenharmony_ci 38131cb0ef41Sopenharmony_ci class WaitForEventDelegate final : public JobDelegate { 38141cb0ef41Sopenharmony_ci public: 38151cb0ef41Sopenharmony_ci explicit WaitForEventDelegate(std::shared_ptr<std::atomic<bool>> done) 38161cb0ef41Sopenharmony_ci : done_(std::move(done)) {} 38171cb0ef41Sopenharmony_ci 38181cb0ef41Sopenharmony_ci bool ShouldYield() override { 38191cb0ef41Sopenharmony_ci return done_->load(std::memory_order_relaxed); 38201cb0ef41Sopenharmony_ci } 38211cb0ef41Sopenharmony_ci 38221cb0ef41Sopenharmony_ci bool IsJoiningThread() const override { return true; } 38231cb0ef41Sopenharmony_ci 38241cb0ef41Sopenharmony_ci void NotifyConcurrencyIncrease() override { UNIMPLEMENTED(); } 38251cb0ef41Sopenharmony_ci 38261cb0ef41Sopenharmony_ci uint8_t GetTaskId() override { return kMainTaskId; } 38271cb0ef41Sopenharmony_ci 38281cb0ef41Sopenharmony_ci private: 38291cb0ef41Sopenharmony_ci std::shared_ptr<std::atomic<bool>> done_; 38301cb0ef41Sopenharmony_ci }; 38311cb0ef41Sopenharmony_ci 38321cb0ef41Sopenharmony_ci WaitForEventDelegate delegate{done}; 38331cb0ef41Sopenharmony_ci // Everything except for top-tier units will be processed with kBaselineOnly 38341cb0ef41Sopenharmony_ci // (including wrappers). Hence we choose this for any event except 38351cb0ef41Sopenharmony_ci // {kFinishedTopTierCompilation}. 38361cb0ef41Sopenharmony_ci auto compile_tiers = 38371cb0ef41Sopenharmony_ci expect_event == CompilationEvent::kFinishedTopTierCompilation 38381cb0ef41Sopenharmony_ci ? kBaselineOrTopTier 38391cb0ef41Sopenharmony_ci : kBaselineOnly; 38401cb0ef41Sopenharmony_ci ExecuteCompilationUnits(native_module_weak_, async_counters_.get(), &delegate, 38411cb0ef41Sopenharmony_ci compile_tiers); 38421cb0ef41Sopenharmony_ci semaphore->Wait(); 38431cb0ef41Sopenharmony_ci} 38441cb0ef41Sopenharmony_ci 38451cb0ef41Sopenharmony_cinamespace { 38461cb0ef41Sopenharmony_ciusing JSToWasmWrapperQueue = 38471cb0ef41Sopenharmony_ci WrapperQueue<JSToWasmWrapperKey, base::hash<JSToWasmWrapperKey>>; 38481cb0ef41Sopenharmony_ciusing JSToWasmWrapperUnitMap = 38491cb0ef41Sopenharmony_ci std::unordered_map<JSToWasmWrapperKey, 38501cb0ef41Sopenharmony_ci std::unique_ptr<JSToWasmWrapperCompilationUnit>, 38511cb0ef41Sopenharmony_ci base::hash<JSToWasmWrapperKey>>; 38521cb0ef41Sopenharmony_ci 38531cb0ef41Sopenharmony_ciclass CompileJSToWasmWrapperJob final : public JobTask { 38541cb0ef41Sopenharmony_ci public: 38551cb0ef41Sopenharmony_ci CompileJSToWasmWrapperJob(JSToWasmWrapperQueue* queue, 38561cb0ef41Sopenharmony_ci JSToWasmWrapperUnitMap* compilation_units) 38571cb0ef41Sopenharmony_ci : queue_(queue), 38581cb0ef41Sopenharmony_ci compilation_units_(compilation_units), 38591cb0ef41Sopenharmony_ci outstanding_units_(queue->size()) {} 38601cb0ef41Sopenharmony_ci 38611cb0ef41Sopenharmony_ci void Run(JobDelegate* delegate) override { 38621cb0ef41Sopenharmony_ci while (base::Optional<JSToWasmWrapperKey> key = queue_->pop()) { 38631cb0ef41Sopenharmony_ci JSToWasmWrapperCompilationUnit* unit = (*compilation_units_)[*key].get(); 38641cb0ef41Sopenharmony_ci unit->Execute(); 38651cb0ef41Sopenharmony_ci outstanding_units_.fetch_sub(1, std::memory_order_relaxed); 38661cb0ef41Sopenharmony_ci if (delegate && delegate->ShouldYield()) return; 38671cb0ef41Sopenharmony_ci } 38681cb0ef41Sopenharmony_ci } 38691cb0ef41Sopenharmony_ci 38701cb0ef41Sopenharmony_ci size_t GetMaxConcurrency(size_t /* worker_count */) const override { 38711cb0ef41Sopenharmony_ci DCHECK_GE(FLAG_wasm_num_compilation_tasks, 1); 38721cb0ef41Sopenharmony_ci // {outstanding_units_} includes the units that other workers are currently 38731cb0ef41Sopenharmony_ci // working on, so we can safely ignore the {worker_count} and just return 38741cb0ef41Sopenharmony_ci // the current number of outstanding units. 38751cb0ef41Sopenharmony_ci return std::min(static_cast<size_t>(FLAG_wasm_num_compilation_tasks), 38761cb0ef41Sopenharmony_ci outstanding_units_.load(std::memory_order_relaxed)); 38771cb0ef41Sopenharmony_ci } 38781cb0ef41Sopenharmony_ci 38791cb0ef41Sopenharmony_ci private: 38801cb0ef41Sopenharmony_ci JSToWasmWrapperQueue* const queue_; 38811cb0ef41Sopenharmony_ci JSToWasmWrapperUnitMap* const compilation_units_; 38821cb0ef41Sopenharmony_ci std::atomic<size_t> outstanding_units_; 38831cb0ef41Sopenharmony_ci}; 38841cb0ef41Sopenharmony_ci} // namespace 38851cb0ef41Sopenharmony_ci 38861cb0ef41Sopenharmony_civoid CompileJsToWasmWrappers(Isolate* isolate, const WasmModule* module, 38871cb0ef41Sopenharmony_ci Handle<FixedArray>* export_wrappers_out) { 38881cb0ef41Sopenharmony_ci TRACE_EVENT0("v8.wasm", "wasm.CompileJsToWasmWrappers"); 38891cb0ef41Sopenharmony_ci *export_wrappers_out = isolate->factory()->NewFixedArray( 38901cb0ef41Sopenharmony_ci MaxNumExportWrappers(module), AllocationType::kOld); 38911cb0ef41Sopenharmony_ci 38921cb0ef41Sopenharmony_ci JSToWasmWrapperQueue queue; 38931cb0ef41Sopenharmony_ci JSToWasmWrapperUnitMap compilation_units; 38941cb0ef41Sopenharmony_ci WasmFeatures enabled_features = WasmFeatures::FromIsolate(isolate); 38951cb0ef41Sopenharmony_ci 38961cb0ef41Sopenharmony_ci // Prepare compilation units in the main thread. 38971cb0ef41Sopenharmony_ci for (auto exp : module->export_table) { 38981cb0ef41Sopenharmony_ci if (exp.kind != kExternalFunction) continue; 38991cb0ef41Sopenharmony_ci auto& function = module->functions[exp.index]; 39001cb0ef41Sopenharmony_ci JSToWasmWrapperKey key(function.imported, *function.sig); 39011cb0ef41Sopenharmony_ci if (queue.insert(key)) { 39021cb0ef41Sopenharmony_ci auto unit = std::make_unique<JSToWasmWrapperCompilationUnit>( 39031cb0ef41Sopenharmony_ci isolate, function.sig, module, function.imported, enabled_features, 39041cb0ef41Sopenharmony_ci JSToWasmWrapperCompilationUnit::kAllowGeneric); 39051cb0ef41Sopenharmony_ci compilation_units.emplace(key, std::move(unit)); 39061cb0ef41Sopenharmony_ci } 39071cb0ef41Sopenharmony_ci } 39081cb0ef41Sopenharmony_ci 39091cb0ef41Sopenharmony_ci { 39101cb0ef41Sopenharmony_ci // This is nested inside the event above, so the name can be less 39111cb0ef41Sopenharmony_ci // descriptive. It's mainly to log the number of wrappers. 39121cb0ef41Sopenharmony_ci TRACE_EVENT1("v8.wasm", "wasm.JsToWasmWrapperCompilation", "num_wrappers", 39131cb0ef41Sopenharmony_ci compilation_units.size()); 39141cb0ef41Sopenharmony_ci auto job = 39151cb0ef41Sopenharmony_ci std::make_unique<CompileJSToWasmWrapperJob>(&queue, &compilation_units); 39161cb0ef41Sopenharmony_ci if (FLAG_wasm_num_compilation_tasks > 0) { 39171cb0ef41Sopenharmony_ci auto job_handle = V8::GetCurrentPlatform()->PostJob( 39181cb0ef41Sopenharmony_ci TaskPriority::kUserVisible, std::move(job)); 39191cb0ef41Sopenharmony_ci 39201cb0ef41Sopenharmony_ci // Wait for completion, while contributing to the work. 39211cb0ef41Sopenharmony_ci job_handle->Join(); 39221cb0ef41Sopenharmony_ci } else { 39231cb0ef41Sopenharmony_ci job->Run(nullptr); 39241cb0ef41Sopenharmony_ci } 39251cb0ef41Sopenharmony_ci } 39261cb0ef41Sopenharmony_ci 39271cb0ef41Sopenharmony_ci // Finalize compilation jobs in the main thread. 39281cb0ef41Sopenharmony_ci // TODO(6792): Wrappers below are allocated with {Factory::NewCode}. As an 39291cb0ef41Sopenharmony_ci // optimization we create a code memory modification scope that avoids 39301cb0ef41Sopenharmony_ci // changing the page permissions back-and-forth between RWX and RX, because 39311cb0ef41Sopenharmony_ci // many such wrapper are allocated in sequence below. 39321cb0ef41Sopenharmony_ci CodePageCollectionMemoryModificationScope modification_scope(isolate->heap()); 39331cb0ef41Sopenharmony_ci for (auto& pair : compilation_units) { 39341cb0ef41Sopenharmony_ci JSToWasmWrapperKey key = pair.first; 39351cb0ef41Sopenharmony_ci JSToWasmWrapperCompilationUnit* unit = pair.second.get(); 39361cb0ef41Sopenharmony_ci DCHECK_EQ(isolate, unit->isolate()); 39371cb0ef41Sopenharmony_ci Handle<Code> code = unit->Finalize(); 39381cb0ef41Sopenharmony_ci int wrapper_index = GetExportWrapperIndex(module, &key.second, key.first); 39391cb0ef41Sopenharmony_ci (*export_wrappers_out)->set(wrapper_index, ToCodeT(*code)); 39401cb0ef41Sopenharmony_ci RecordStats(*code, isolate->counters()); 39411cb0ef41Sopenharmony_ci } 39421cb0ef41Sopenharmony_ci} 39431cb0ef41Sopenharmony_ci 39441cb0ef41Sopenharmony_ciWasmCode* CompileImportWrapper( 39451cb0ef41Sopenharmony_ci NativeModule* native_module, Counters* counters, 39461cb0ef41Sopenharmony_ci compiler::WasmImportCallKind kind, const FunctionSig* sig, 39471cb0ef41Sopenharmony_ci int expected_arity, Suspend suspend, 39481cb0ef41Sopenharmony_ci WasmImportWrapperCache::ModificationScope* cache_scope) { 39491cb0ef41Sopenharmony_ci // Entry should exist, so that we don't insert a new one and invalidate 39501cb0ef41Sopenharmony_ci // other threads' iterators/references, but it should not have been compiled 39511cb0ef41Sopenharmony_ci // yet. 39521cb0ef41Sopenharmony_ci WasmImportWrapperCache::CacheKey key(kind, sig, expected_arity, suspend); 39531cb0ef41Sopenharmony_ci DCHECK_NULL((*cache_scope)[key]); 39541cb0ef41Sopenharmony_ci bool source_positions = is_asmjs_module(native_module->module()); 39551cb0ef41Sopenharmony_ci // Keep the {WasmCode} alive until we explicitly call {IncRef}. 39561cb0ef41Sopenharmony_ci WasmCodeRefScope code_ref_scope; 39571cb0ef41Sopenharmony_ci CompilationEnv env = native_module->CreateCompilationEnv(); 39581cb0ef41Sopenharmony_ci WasmCompilationResult result = compiler::CompileWasmImportCallWrapper( 39591cb0ef41Sopenharmony_ci &env, kind, sig, source_positions, expected_arity, suspend); 39601cb0ef41Sopenharmony_ci WasmCode* published_code; 39611cb0ef41Sopenharmony_ci { 39621cb0ef41Sopenharmony_ci CodeSpaceWriteScope code_space_write_scope(native_module); 39631cb0ef41Sopenharmony_ci std::unique_ptr<WasmCode> wasm_code = native_module->AddCode( 39641cb0ef41Sopenharmony_ci result.func_index, result.code_desc, result.frame_slot_count, 39651cb0ef41Sopenharmony_ci result.tagged_parameter_slots, 39661cb0ef41Sopenharmony_ci result.protected_instructions_data.as_vector(), 39671cb0ef41Sopenharmony_ci result.source_positions.as_vector(), GetCodeKind(result), 39681cb0ef41Sopenharmony_ci ExecutionTier::kNone, kNoDebugging); 39691cb0ef41Sopenharmony_ci published_code = native_module->PublishCode(std::move(wasm_code)); 39701cb0ef41Sopenharmony_ci } 39711cb0ef41Sopenharmony_ci (*cache_scope)[key] = published_code; 39721cb0ef41Sopenharmony_ci published_code->IncRef(); 39731cb0ef41Sopenharmony_ci counters->wasm_generated_code_size()->Increment( 39741cb0ef41Sopenharmony_ci published_code->instructions().length()); 39751cb0ef41Sopenharmony_ci counters->wasm_reloc_size()->Increment(published_code->reloc_info().length()); 39761cb0ef41Sopenharmony_ci return published_code; 39771cb0ef41Sopenharmony_ci} 39781cb0ef41Sopenharmony_ci 39791cb0ef41Sopenharmony_ci} // namespace wasm 39801cb0ef41Sopenharmony_ci} // namespace internal 39811cb0ef41Sopenharmony_ci} // namespace v8 39821cb0ef41Sopenharmony_ci 39831cb0ef41Sopenharmony_ci#undef TRACE_COMPILE 39841cb0ef41Sopenharmony_ci#undef TRACE_STREAMING 39851cb0ef41Sopenharmony_ci#undef TRACE_LAZY 3986