Commit 1f7861c8 authored by Z Nguyen-Huu's avatar Z Nguyen-Huu Committed by Commit Bot

Reland "[wasm] Tierdown wasm module upon "Debugger.enable""

This is a reland of 410ca4c5

Skip new test for unsupported liftoff architecture.
Previously, if there is some unsupported liftoff functions, it fall
through Turbofan but recompilation didn't catch and count it. This CL
fixes it by using requested_tier on finished units.

Avoid to tier down asm.js.
Introduce reached recompilation tier to monitor recompilation progress.

Original change's description:
> [wasm] Tierdown wasm module upon "Debugger.enable"
>
> Put a logic in Wasm Engine to tier down all existing modules per isolate
> when debugger is enabled. This CL does not handle new module added after
> debugger is enabled yet.
>
> Bug: v8:9654
> Change-Id: I87060f5c416506543fcaf231bff9999d06ba4c0d
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2013692
> Commit-Queue: Z Nguyen-Huu <duongn@microsoft.com>
> Reviewed-by: Simon Zünd <szuend@chromium.org>
> Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
> Reviewed-by: Clemens Backes <clemensb@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#66017}

TBR=szuend@chromium.org,bmeurer@chromium.org

Bug: v8:9654
Change-Id: I6014ae52d1e04726e64ee9267c5ce559090414d7
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2031744
Commit-Queue: Z Nguyen-Huu <duongn@microsoft.com>
Reviewed-by: 's avatarClemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#66164}
parent 1ae4669b
...@@ -9818,6 +9818,11 @@ MaybeLocal<UnboundScript> debug::CompileInspectorScript(Isolate* v8_isolate, ...@@ -9818,6 +9818,11 @@ MaybeLocal<UnboundScript> debug::CompileInspectorScript(Isolate* v8_isolate,
RETURN_ESCAPED(ToApiHandle<UnboundScript>(result)); RETURN_ESCAPED(ToApiHandle<UnboundScript>(result));
} }
void debug::TierDownAllModulesPerIsolate(Isolate* v8_isolate) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
isolate->wasm_engine()->TierDownAllModulesPerIsolate(isolate);
}
void debug::SetDebugDelegate(Isolate* v8_isolate, void debug::SetDebugDelegate(Isolate* v8_isolate,
debug::DebugDelegate* delegate) { debug::DebugDelegate* delegate) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
......
...@@ -219,6 +219,8 @@ class DebugDelegate { ...@@ -219,6 +219,8 @@ class DebugDelegate {
V8_EXPORT_PRIVATE void SetDebugDelegate(Isolate* isolate, V8_EXPORT_PRIVATE void SetDebugDelegate(Isolate* isolate,
DebugDelegate* listener); DebugDelegate* listener);
V8_EXPORT_PRIVATE void TierDownAllModulesPerIsolate(Isolate* isolate);
class AsyncEventDelegate { class AsyncEventDelegate {
public: public:
virtual ~AsyncEventDelegate() = default; virtual ~AsyncEventDelegate() = default;
......
...@@ -124,6 +124,7 @@ void V8Debugger::enable() { ...@@ -124,6 +124,7 @@ void V8Debugger::enable() {
m_isolate->AddNearHeapLimitCallback(&V8Debugger::nearHeapLimitCallback, this); m_isolate->AddNearHeapLimitCallback(&V8Debugger::nearHeapLimitCallback, this);
v8::debug::ChangeBreakOnException(m_isolate, v8::debug::NoBreakOnException); v8::debug::ChangeBreakOnException(m_isolate, v8::debug::NoBreakOnException);
m_pauseOnExceptionsState = v8::debug::NoBreakOnException; m_pauseOnExceptionsState = v8::debug::NoBreakOnException;
v8::debug::TierDownAllModulesPerIsolate(m_isolate);
} }
void V8Debugger::disable() { void V8Debugger::disable() {
......
...@@ -382,7 +382,8 @@ class CompilationStateImpl { ...@@ -382,7 +382,8 @@ class CompilationStateImpl {
void InitializeCompilationProgress(bool lazy_module, int num_wrappers); void InitializeCompilationProgress(bool lazy_module, int num_wrappers);
// Initialize compilation progress for recompilation of the whole module. // Initialize compilation progress for recompilation of the whole module.
void InitializeRecompilationProgress(ExecutionTier tier); // Return a vector of functions to recompile.
std::vector<int> InitializeRecompilationProgress(ExecutionTier tier);
// Add the callback function to be called on compilation events. Needs to be // Add the callback function to be called on compilation events. Needs to be
// set before {AddCompilationUnits} is run to ensure that it receives all // set before {AddCompilationUnits} is run to ensure that it receives all
...@@ -408,7 +409,7 @@ class CompilationStateImpl { ...@@ -408,7 +409,7 @@ class CompilationStateImpl {
void FinalizeJSToWasmWrappers(Isolate* isolate, const WasmModule* module, void FinalizeJSToWasmWrappers(Isolate* isolate, const WasmModule* module,
Handle<FixedArray>* export_wrappers_out); Handle<FixedArray>* export_wrappers_out);
void OnFinishedUnits(Vector<WasmCode*>); void OnFinishedUnits(Vector<WasmCode*>, Vector<WasmCompilationResult>);
void OnFinishedJSToWasmWrapperUnits(int num); void OnFinishedJSToWasmWrapperUnits(int num);
void TriggerCallbacks(bool completes_baseline_compilation, void TriggerCallbacks(bool completes_baseline_compilation,
bool completes_top_tier_compilation, bool completes_top_tier_compilation,
...@@ -557,6 +558,7 @@ class CompilationStateImpl { ...@@ -557,6 +558,7 @@ class CompilationStateImpl {
using RequiredBaselineTierField = base::BitField8<ExecutionTier, 0, 2>; using RequiredBaselineTierField = base::BitField8<ExecutionTier, 0, 2>;
using RequiredTopTierField = base::BitField8<ExecutionTier, 2, 2>; using RequiredTopTierField = base::BitField8<ExecutionTier, 2, 2>;
using ReachedTierField = base::BitField8<ExecutionTier, 4, 2>; using ReachedTierField = base::BitField8<ExecutionTier, 4, 2>;
using ReachedRecompilationTierField = base::BitField8<ExecutionTier, 6, 2>;
}; };
CompilationStateImpl* Impl(CompilationState* compilation_state) { CompilationStateImpl* Impl(CompilationState* compilation_state) {
...@@ -1092,7 +1094,8 @@ bool ExecuteCompilationUnits( ...@@ -1092,7 +1094,8 @@ bool ExecuteCompilationUnits(
native_module->engine()->LogCode(VectorOf(code_vector)); native_module->engine()->LogCode(VectorOf(code_vector));
compile_scope->compilation_state()->OnFinishedUnits(VectorOf(code_vector)); compile_scope->compilation_state()->OnFinishedUnits(
VectorOf(code_vector), VectorOf(results_to_publish));
results_to_publish.clear(); results_to_publish.clear();
}; };
...@@ -1222,13 +1225,13 @@ void InitializeCompilationUnits(Isolate* isolate, NativeModule* native_module) { ...@@ -1222,13 +1225,13 @@ void InitializeCompilationUnits(Isolate* isolate, NativeModule* native_module) {
builder.Commit(); builder.Commit();
} }
void AddBaselineCompilationUnits(NativeModule* native_module) { void AddBaselineCompilationUnits(NativeModule* native_module,
Vector<int> recompilation_functions) {
CompilationUnitBuilder builder(native_module); CompilationUnitBuilder builder(native_module);
auto* module = native_module->module();
uint32_t start = module->num_imported_functions; for (int func_index : recompilation_functions) {
uint32_t end = start + module->num_declared_functions; DCHECK_LE(native_module->num_imported_functions(), func_index);
for (uint32_t func_index = start; func_index < end; func_index++) { DCHECK_LT(func_index, native_module->num_functions());
builder.AddBaselineUnit(func_index); builder.AddBaselineUnit(func_index);
} }
...@@ -1447,8 +1450,9 @@ void RecompileNativeModule(Isolate* isolate, NativeModule* native_module, ...@@ -1447,8 +1450,9 @@ void RecompileNativeModule(Isolate* isolate, NativeModule* native_module,
}); });
// Initialize the compilation units and kick off background compile tasks. // Initialize the compilation units and kick off background compile tasks.
compilation_state->InitializeRecompilationProgress(tier); std::vector<int> recompilation_functions =
AddBaselineCompilationUnits(native_module); compilation_state->InitializeRecompilationProgress(tier);
AddBaselineCompilationUnits(native_module, VectorOf(recompilation_functions));
// The main thread contributes to the compilation, except if we need // The main thread contributes to the compilation, except if we need
// deterministic compilation; in that case, the single background task will // deterministic compilation; in that case, the single background task will
...@@ -2516,28 +2520,41 @@ void CompilationStateImpl::InitializeCompilationProgress(bool lazy_module, ...@@ -2516,28 +2520,41 @@ void CompilationStateImpl::InitializeCompilationProgress(bool lazy_module,
} }
} }
void CompilationStateImpl::InitializeRecompilationProgress(ExecutionTier tier) { std::vector<int> CompilationStateImpl::InitializeRecompilationProgress(
ExecutionTier tier) {
DCHECK(!failed()); DCHECK(!failed());
auto* module = native_module_->module();
std::vector<int> recompilation_functions;
base::MutexGuard guard(&callbacks_mutex_); base::MutexGuard guard(&callbacks_mutex_);
// Ensure that we don't trigger recompilation if another recompilation is // Ensure that we don't trigger recompilation if another recompilation is
// already happening. // already happening.
DCHECK_EQ(0, outstanding_recompilation_functions_); DCHECK_EQ(0, outstanding_recompilation_functions_);
int start = module->num_imported_functions; // If compilation hasn't started yet then code would be keep as tiered-down
int end = start + module->num_declared_functions; // and don't need to recompile.
for (int function_index = start; function_index < end; function_index++) { if (compilation_progress_.size() > 0) {
int slot_index = function_index - start; int start = native_module_->module()->num_imported_functions;
DCHECK_LT(slot_index, compilation_progress_.size()); int end = start + native_module_->module()->num_declared_functions;
ExecutionTier reached_tier = for (int function_index = start; function_index < end; function_index++) {
ReachedTierField::decode(compilation_progress_[slot_index]); int slot_index = function_index - start;
if (reached_tier != tier) { DCHECK_LT(slot_index, compilation_progress_.size());
outstanding_recompilation_functions_++; ExecutionTier reached_tier =
ReachedTierField::decode(compilation_progress_[slot_index]);
compilation_progress_[slot_index] = ReachedRecompilationTierField::update(
compilation_progress_[slot_index], ExecutionTier::kLiftoff);
if (reached_tier != tier ||
!native_module_->HasCodeWithTier(function_index, tier)) {
outstanding_recompilation_functions_++;
recompilation_functions.push_back(function_index);
compilation_progress_[slot_index] =
ReachedRecompilationTierField::update(
compilation_progress_[slot_index], ExecutionTier::kNone);
}
} }
DCHECK_LE(0, outstanding_recompilation_functions_);
DCHECK_LE(outstanding_recompilation_functions_,
native_module_->module()->num_declared_functions);
} }
DCHECK_LE(0, outstanding_recompilation_functions_);
DCHECK_LE(outstanding_recompilation_functions_,
module->num_declared_functions);
// Trigger callbacks if module needs no recompilation. // Trigger callbacks if module needs no recompilation.
if (outstanding_recompilation_functions_ == 0) { if (outstanding_recompilation_functions_ == 0) {
...@@ -2545,6 +2562,8 @@ void CompilationStateImpl::InitializeRecompilationProgress(ExecutionTier tier) { ...@@ -2545,6 +2562,8 @@ void CompilationStateImpl::InitializeRecompilationProgress(ExecutionTier tier) {
callback(CompilationEvent::kFinishedRecompilation); callback(CompilationEvent::kFinishedRecompilation);
} }
} }
return recompilation_functions;
} }
void CompilationStateImpl::AddCallback(CompilationState::callback_t callback) { void CompilationStateImpl::AddCallback(CompilationState::callback_t callback) {
...@@ -2618,7 +2637,8 @@ CompilationStateImpl::GetNextCompilationUnit( ...@@ -2618,7 +2637,8 @@ CompilationStateImpl::GetNextCompilationUnit(
return compilation_unit_queues_.GetNextUnit(task_id, baseline_only); return compilation_unit_queues_.GetNextUnit(task_id, baseline_only);
} }
void CompilationStateImpl::OnFinishedUnits(Vector<WasmCode*> code_vector) { void CompilationStateImpl::OnFinishedUnits(
Vector<WasmCode*> code_vector, Vector<WasmCompilationResult> results) {
TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("v8.wasm"), "OnFinishedUnits", TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("v8.wasm"), "OnFinishedUnits",
"num_units", code_vector.size()); "num_units", code_vector.size());
...@@ -2647,7 +2667,8 @@ void CompilationStateImpl::OnFinishedUnits(Vector<WasmCode*> code_vector) { ...@@ -2647,7 +2667,8 @@ void CompilationStateImpl::OnFinishedUnits(Vector<WasmCode*> code_vector) {
bool completes_top_tier_compilation = false; bool completes_top_tier_compilation = false;
bool completes_recompilation = false; bool completes_recompilation = false;
for (WasmCode* code : code_vector) { for (size_t i = 0; i < code_vector.size(); i++) {
WasmCode* code = code_vector[i];
DCHECK_NOT_NULL(code); DCHECK_NOT_NULL(code);
DCHECK_LT(code->index(), native_module_->num_functions()); DCHECK_LT(code->index(), native_module_->num_functions());
...@@ -2698,22 +2719,26 @@ void CompilationStateImpl::OnFinishedUnits(Vector<WasmCode*> code_vector) { ...@@ -2698,22 +2719,26 @@ void CompilationStateImpl::OnFinishedUnits(Vector<WasmCode*> code_vector) {
// counter once a function reaches Liftoff. // counter once a function reaches Liftoff.
if (outstanding_recompilation_functions_ > 0) { if (outstanding_recompilation_functions_ > 0) {
// TODO(duongn): extend this logic for tier up. // TODO(duongn): extend this logic for tier up.
if (code->tier() == ExecutionTier::kLiftoff && ExecutionTier recompilation_tier =
reached_tier != ExecutionTier::kLiftoff) { ReachedRecompilationTierField::decode(function_progress);
if (results[i].requested_tier == ExecutionTier::kLiftoff &&
recompilation_tier == ExecutionTier::kNone) {
DCHECK(code->tier() >= ExecutionTier::kLiftoff);
outstanding_recompilation_functions_--; outstanding_recompilation_functions_--;
// Update function's compilation progress. // Update function's recompilation progress.
compilation_progress_[slot_index] = ReachedTierField::update( compilation_progress_[slot_index] =
compilation_progress_[slot_index], code->tier()); ReachedRecompilationTierField::update(
compilation_progress_[slot_index], code->tier());
if (outstanding_recompilation_functions_ == 0) { if (outstanding_recompilation_functions_ == 0) {
completes_recompilation = true; completes_recompilation = true;
} }
} }
} else { }
// Update function's compilation progress.
if (code->tier() > reached_tier) { // Update function's compilation progress.
compilation_progress_[slot_index] = ReachedTierField::update( if (code->tier() > reached_tier) {
compilation_progress_[slot_index], code->tier()); compilation_progress_[slot_index] = ReachedTierField::update(
} compilation_progress_[slot_index], code->tier());
} }
DCHECK_LE(0, outstanding_baseline_units_); DCHECK_LE(0, outstanding_baseline_units_);
} }
......
...@@ -1122,6 +1122,12 @@ bool NativeModule::HasCode(uint32_t index) const { ...@@ -1122,6 +1122,12 @@ bool NativeModule::HasCode(uint32_t index) const {
return code_table_[declared_function_index(module(), index)] != nullptr; return code_table_[declared_function_index(module(), index)] != nullptr;
} }
bool NativeModule::HasCodeWithTier(uint32_t index, ExecutionTier tier) const {
base::MutexGuard guard(&allocation_mutex_);
return code_table_[declared_function_index(module(), index)] != nullptr &&
code_table_[declared_function_index(module(), index)]->tier() == tier;
}
void NativeModule::SetWasmSourceMap( void NativeModule::SetWasmSourceMap(
std::unique_ptr<WasmModuleSourceMap> source_map) { std::unique_ptr<WasmModuleSourceMap> source_map) {
source_map_ = std::move(source_map); source_map_ = std::move(source_map);
...@@ -1794,9 +1800,12 @@ bool NativeModule::IsRedirectedToInterpreter(uint32_t func_index) { ...@@ -1794,9 +1800,12 @@ bool NativeModule::IsRedirectedToInterpreter(uint32_t func_index) {
} }
void NativeModule::TierDown(Isolate* isolate) { void NativeModule::TierDown(Isolate* isolate) {
// Do not tier down asm.js.
if (module()->origin != kWasmOrigin) return;
// Set the flag. // Set the flag.
{ {
base::MutexGuard lock(&allocation_mutex_); base::MutexGuard lock(&allocation_mutex_);
if (tier_down_) return;
tier_down_ = true; tier_down_ = true;
} }
// Tier down all functions. // Tier down all functions.
......
...@@ -445,6 +445,7 @@ class V8_EXPORT_PRIVATE NativeModule final { ...@@ -445,6 +445,7 @@ class V8_EXPORT_PRIVATE NativeModule final {
WasmCode* GetCode(uint32_t index) const; WasmCode* GetCode(uint32_t index) const;
bool HasCode(uint32_t index) const; bool HasCode(uint32_t index) const;
bool HasCodeWithTier(uint32_t index, ExecutionTier tier) const;
void SetWasmSourceMap(std::unique_ptr<WasmModuleSourceMap> source_map); void SetWasmSourceMap(std::unique_ptr<WasmModuleSourceMap> source_map);
WasmModuleSourceMap* GetWasmSourceMap() const; WasmModuleSourceMap* GetWasmSourceMap() const;
......
...@@ -573,6 +573,19 @@ void WasmEngine::RecompileAllFunctions(Isolate* isolate, ...@@ -573,6 +573,19 @@ void WasmEngine::RecompileAllFunctions(Isolate* isolate,
RecompileNativeModule(isolate, native_module, tier); RecompileNativeModule(isolate, native_module, tier);
} }
void WasmEngine::TierDownAllModulesPerIsolate(Isolate* isolate) {
std::vector<NativeModule*> native_modules;
{
base::MutexGuard lock(&mutex_);
for (auto* native_module : isolates_[isolate]->native_modules) {
native_modules.push_back(native_module);
}
}
for (auto* native_module : native_modules) {
native_module->TierDown(isolate);
}
}
std::shared_ptr<NativeModule> WasmEngine::ExportNativeModule( std::shared_ptr<NativeModule> WasmEngine::ExportNativeModule(
Handle<WasmModuleObject> module_object) { Handle<WasmModuleObject> module_object) {
return module_object->shared_native_module(); return module_object->shared_native_module();
......
...@@ -193,6 +193,8 @@ class V8_EXPORT_PRIVATE WasmEngine { ...@@ -193,6 +193,8 @@ class V8_EXPORT_PRIVATE WasmEngine {
void RecompileAllFunctions(Isolate* isolate, NativeModule* native_module, void RecompileAllFunctions(Isolate* isolate, NativeModule* native_module,
ExecutionTier tier); ExecutionTier tier);
void TierDownAllModulesPerIsolate(Isolate* isolate);
// Exports the sharable parts of the given module object so that they can be // Exports the sharable parts of the given module object so that they can be
// transferred to a different Context/Isolate using the same engine. // transferred to a different Context/Isolate using the same engine.
std::shared_ptr<NativeModule> ExportNativeModule( std::shared_ptr<NativeModule> ExportNativeModule(
......
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --experimental-wasm-anyref
load("test/mjsunit/wasm/wasm-module-builder.js");
// Create a simple Wasm module.
function create_builder() {
const builder = new WasmModuleBuilder();
builder.addFunction('main', kSig_r_v)
.addBody([kExprRefNull])
.exportFunc();
return builder;
}
const instance = create_builder().instantiate();
// Test recompilation.
const Debug = new DebugWrapper();
Debug.enable();
assertFalse(%IsLiftoffFunction(instance.exports.main));
// Async.
async function testTierDownToLiftoffAsync() {
Debug.disable();
const builder = new WasmModuleBuilder();
builder.addFunction('main', kSig_i_r)
.addBody([kExprLocalGet, 0, kExprRefIsNull])
.exportFunc();
const asyncInstance = await builder.asyncInstantiate();
// Test recompilation.
Debug.enable();
assertFalse(%IsLiftoffFunction(instance.exports.main));
}
assertPromiseResult(testTierDownToLiftoffAsync());
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
load("test/mjsunit/wasm/wasm-module-builder.js");
const num_functions = 200;
// Create a simple Wasm script.
function create_builder(delta = 0) {
const builder = new WasmModuleBuilder();
for (let i = 0; i < num_functions; ++i) {
builder.addFunction('f' + i, kSig_i_v)
.addBody(wasmI32Const(i + delta))
.exportFunc();
}
return builder;
}
function check(instance) {
for (let i = 0; i < num_functions; ++i) {
assertTrue(%IsLiftoffFunction(instance.exports['f' + i]));
}
}
const instance = create_builder().instantiate();
const Debug = new DebugWrapper();
Debug.enable();
check(instance);
// Async.
async function testTierDownToLiftoffAsync() {
Debug.disable();
const asyncInstance = await create_builder(num_functions).asyncInstantiate();
Debug.enable();
check(asyncInstance);
}
assertPromiseResult(testTierDownToLiftoffAsync());
...@@ -143,8 +143,9 @@ ...@@ -143,8 +143,9 @@
['arch in (s390, s390x, ppc, ppc64)', { ['arch in (s390, s390x, ppc, ppc64)', {
'regress/regress-crbug-1032042': [SKIP], 'regress/regress-crbug-1032042': [SKIP],
'regress/regress-crbug-840288': [SKIP], 'regress/regress-crbug-840288': [SKIP],
'debug/wasm/debug-step-into-wasm': [SKIP],
'debug/wasm/asm-debug': [SKIP], 'debug/wasm/asm-debug': [SKIP],
'debug/wasm/debug-enabled-tier-down-wasm': [SKIP],
'debug/wasm/debug-step-into-wasm': [SKIP],
'debug/wasm/frame-inspection': [SKIP], 'debug/wasm/frame-inspection': [SKIP],
}], }],
......
...@@ -2,11 +2,11 @@ ...@@ -2,11 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// Flags: --allow-natives-syntax --liftoff --wasm-tier-up --no-stress-opt // Flags: --allow-natives-syntax
load('test/mjsunit/wasm/wasm-module-builder.js'); load('test/mjsunit/wasm/wasm-module-builder.js');
const num_functions = 2; const num_functions = 200;
function create_builder(delta = 0) { function create_builder(delta = 0) {
const builder = new WasmModuleBuilder(); const builder = new WasmModuleBuilder();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment