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

This is a reland of 410ca4c50e

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: Clemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#66164}
This commit is contained in:
Z Nguyen-Huu 2020-02-05 09:32:47 -08:00 committed by Commit Bot
parent 1ae4669bcd
commit 1f7861c8a9
12 changed files with 177 additions and 40 deletions

View File

@ -9818,6 +9818,11 @@ MaybeLocal<UnboundScript> debug::CompileInspectorScript(Isolate* v8_isolate,
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,
debug::DebugDelegate* delegate) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);

View File

@ -219,6 +219,8 @@ class DebugDelegate {
V8_EXPORT_PRIVATE void SetDebugDelegate(Isolate* isolate,
DebugDelegate* listener);
V8_EXPORT_PRIVATE void TierDownAllModulesPerIsolate(Isolate* isolate);
class AsyncEventDelegate {
public:
virtual ~AsyncEventDelegate() = default;

View File

@ -124,6 +124,7 @@ void V8Debugger::enable() {
m_isolate->AddNearHeapLimitCallback(&V8Debugger::nearHeapLimitCallback, this);
v8::debug::ChangeBreakOnException(m_isolate, v8::debug::NoBreakOnException);
m_pauseOnExceptionsState = v8::debug::NoBreakOnException;
v8::debug::TierDownAllModulesPerIsolate(m_isolate);
}
void V8Debugger::disable() {

View File

@ -382,7 +382,8 @@ class CompilationStateImpl {
void InitializeCompilationProgress(bool lazy_module, int num_wrappers);
// 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
// set before {AddCompilationUnits} is run to ensure that it receives all
@ -408,7 +409,7 @@ class CompilationStateImpl {
void FinalizeJSToWasmWrappers(Isolate* isolate, const WasmModule* module,
Handle<FixedArray>* export_wrappers_out);
void OnFinishedUnits(Vector<WasmCode*>);
void OnFinishedUnits(Vector<WasmCode*>, Vector<WasmCompilationResult>);
void OnFinishedJSToWasmWrapperUnits(int num);
void TriggerCallbacks(bool completes_baseline_compilation,
bool completes_top_tier_compilation,
@ -557,6 +558,7 @@ class CompilationStateImpl {
using RequiredBaselineTierField = base::BitField8<ExecutionTier, 0, 2>;
using RequiredTopTierField = base::BitField8<ExecutionTier, 2, 2>;
using ReachedTierField = base::BitField8<ExecutionTier, 4, 2>;
using ReachedRecompilationTierField = base::BitField8<ExecutionTier, 6, 2>;
};
CompilationStateImpl* Impl(CompilationState* compilation_state) {
@ -1092,7 +1094,8 @@ bool ExecuteCompilationUnits(
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();
};
@ -1222,13 +1225,13 @@ void InitializeCompilationUnits(Isolate* isolate, NativeModule* native_module) {
builder.Commit();
}
void AddBaselineCompilationUnits(NativeModule* native_module) {
void AddBaselineCompilationUnits(NativeModule* native_module,
Vector<int> recompilation_functions) {
CompilationUnitBuilder builder(native_module);
auto* module = native_module->module();
uint32_t start = module->num_imported_functions;
uint32_t end = start + module->num_declared_functions;
for (uint32_t func_index = start; func_index < end; func_index++) {
for (int func_index : recompilation_functions) {
DCHECK_LE(native_module->num_imported_functions(), func_index);
DCHECK_LT(func_index, native_module->num_functions());
builder.AddBaselineUnit(func_index);
}
@ -1447,8 +1450,9 @@ void RecompileNativeModule(Isolate* isolate, NativeModule* native_module,
});
// Initialize the compilation units and kick off background compile tasks.
compilation_state->InitializeRecompilationProgress(tier);
AddBaselineCompilationUnits(native_module);
std::vector<int> recompilation_functions =
compilation_state->InitializeRecompilationProgress(tier);
AddBaselineCompilationUnits(native_module, VectorOf(recompilation_functions));
// The main thread contributes to the compilation, except if we need
// deterministic compilation; in that case, the single background task will
@ -2516,28 +2520,41 @@ void CompilationStateImpl::InitializeCompilationProgress(bool lazy_module,
}
}
void CompilationStateImpl::InitializeRecompilationProgress(ExecutionTier tier) {
std::vector<int> CompilationStateImpl::InitializeRecompilationProgress(
ExecutionTier tier) {
DCHECK(!failed());
auto* module = native_module_->module();
std::vector<int> recompilation_functions;
base::MutexGuard guard(&callbacks_mutex_);
// Ensure that we don't trigger recompilation if another recompilation is
// already happening.
DCHECK_EQ(0, outstanding_recompilation_functions_);
int start = module->num_imported_functions;
int end = start + module->num_declared_functions;
for (int function_index = start; function_index < end; function_index++) {
int slot_index = function_index - start;
DCHECK_LT(slot_index, compilation_progress_.size());
ExecutionTier reached_tier =
ReachedTierField::decode(compilation_progress_[slot_index]);
if (reached_tier != tier) {
outstanding_recompilation_functions_++;
// If compilation hasn't started yet then code would be keep as tiered-down
// and don't need to recompile.
if (compilation_progress_.size() > 0) {
int start = native_module_->module()->num_imported_functions;
int end = start + native_module_->module()->num_declared_functions;
for (int function_index = start; function_index < end; function_index++) {
int slot_index = function_index - start;
DCHECK_LT(slot_index, compilation_progress_.size());
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.
if (outstanding_recompilation_functions_ == 0) {
@ -2545,6 +2562,8 @@ void CompilationStateImpl::InitializeRecompilationProgress(ExecutionTier tier) {
callback(CompilationEvent::kFinishedRecompilation);
}
}
return recompilation_functions;
}
void CompilationStateImpl::AddCallback(CompilationState::callback_t callback) {
@ -2618,7 +2637,8 @@ CompilationStateImpl::GetNextCompilationUnit(
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",
"num_units", code_vector.size());
@ -2647,7 +2667,8 @@ void CompilationStateImpl::OnFinishedUnits(Vector<WasmCode*> code_vector) {
bool completes_top_tier_compilation = 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_LT(code->index(), native_module_->num_functions());
@ -2698,22 +2719,26 @@ void CompilationStateImpl::OnFinishedUnits(Vector<WasmCode*> code_vector) {
// counter once a function reaches Liftoff.
if (outstanding_recompilation_functions_ > 0) {
// TODO(duongn): extend this logic for tier up.
if (code->tier() == ExecutionTier::kLiftoff &&
reached_tier != ExecutionTier::kLiftoff) {
ExecutionTier recompilation_tier =
ReachedRecompilationTierField::decode(function_progress);
if (results[i].requested_tier == ExecutionTier::kLiftoff &&
recompilation_tier == ExecutionTier::kNone) {
DCHECK(code->tier() >= ExecutionTier::kLiftoff);
outstanding_recompilation_functions_--;
// Update function's compilation progress.
compilation_progress_[slot_index] = ReachedTierField::update(
compilation_progress_[slot_index], code->tier());
// Update function's recompilation progress.
compilation_progress_[slot_index] =
ReachedRecompilationTierField::update(
compilation_progress_[slot_index], code->tier());
if (outstanding_recompilation_functions_ == 0) {
completes_recompilation = true;
}
}
} else {
// Update function's compilation progress.
if (code->tier() > reached_tier) {
compilation_progress_[slot_index] = ReachedTierField::update(
compilation_progress_[slot_index], code->tier());
}
}
// Update function's compilation progress.
if (code->tier() > reached_tier) {
compilation_progress_[slot_index] = ReachedTierField::update(
compilation_progress_[slot_index], code->tier());
}
DCHECK_LE(0, outstanding_baseline_units_);
}

View File

@ -1122,6 +1122,12 @@ bool NativeModule::HasCode(uint32_t index) const {
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(
std::unique_ptr<WasmModuleSourceMap> source_map) {
source_map_ = std::move(source_map);
@ -1794,9 +1800,12 @@ bool NativeModule::IsRedirectedToInterpreter(uint32_t func_index) {
}
void NativeModule::TierDown(Isolate* isolate) {
// Do not tier down asm.js.
if (module()->origin != kWasmOrigin) return;
// Set the flag.
{
base::MutexGuard lock(&allocation_mutex_);
if (tier_down_) return;
tier_down_ = true;
}
// Tier down all functions.

View File

@ -445,6 +445,7 @@ class V8_EXPORT_PRIVATE NativeModule final {
WasmCode* GetCode(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);
WasmModuleSourceMap* GetWasmSourceMap() const;

View File

@ -573,6 +573,19 @@ void WasmEngine::RecompileAllFunctions(Isolate* isolate,
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(
Handle<WasmModuleObject> module_object) {
return module_object->shared_native_module();

View File

@ -193,6 +193,8 @@ class V8_EXPORT_PRIVATE WasmEngine {
void RecompileAllFunctions(Isolate* isolate, NativeModule* native_module,
ExecutionTier tier);
void TierDownAllModulesPerIsolate(Isolate* isolate);
// Exports the sharable parts of the given module object so that they can be
// transferred to a different Context/Isolate using the same engine.
std::shared_ptr<NativeModule> ExportNativeModule(

View File

@ -0,0 +1,39 @@
// 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());

View File

@ -0,0 +1,39 @@
// 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());

View File

@ -143,8 +143,9 @@
['arch in (s390, s390x, ppc, ppc64)', {
'regress/regress-crbug-1032042': [SKIP],
'regress/regress-crbug-840288': [SKIP],
'debug/wasm/debug-step-into-wasm': [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],
}],

View File

@ -2,11 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// 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');
const num_functions = 2;
const num_functions = 200;
function create_builder(delta = 0) {
const builder = new WasmModuleBuilder();