Commit 447d7d67 authored by Clemens Backes's avatar Clemens Backes Committed by Commit Bot

[wasm][debug] Avoid repeated recompilation

If multiple isolates share the same module, and the debugger gets
enabled, then we trigger tier down in each isolate separately. To avoid
generating too much code, we only recompile functions that are not
already in the right tier.

This CL is only the first step towards an actual fix. Since we only
check already installed code (and ignore compilations that are already
scheduled), we might still compile the same functions multiple times. A
second CL will make sure that only one recompilation is running at the
same time.

R=thibaudm@chromium.org

Bug: chromium:1084369, v8:10359
Change-Id: Ic4f9afac1add0fe8ad9e5d68f22d3d41ba2e52be
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2213438Reviewed-by: 's avatarThibaud Michaud <thibaudm@chromium.org>
Commit-Queue: Clemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#67957}
parent a0e7456d
...@@ -2583,26 +2583,44 @@ void CompilationStateImpl::InitializeRecompilation( ...@@ -2583,26 +2583,44 @@ void CompilationStateImpl::InitializeRecompilation(
// Generate necessary compilation units on the fly. // Generate necessary compilation units on the fly.
CompilationUnitBuilder builder(native_module_); CompilationUnitBuilder builder(native_module_);
// Information about compilation progress is shared between this class and the
// NativeModule. Before updating information here, consult the NativeModule to
// find all functions that need recompilation.
// Since the current tiering state is updated on the NativeModule before
// triggering recompilation, it's OK if the information is slightly outdated.
// If we compile functions twice, the NativeModule will ignore all redundant
// code (or code compiled for the wrong tier).
std::vector<int> recompile_function_indexes =
native_module_->FindFunctionsToRecompile(new_tiering_state);
{ {
base::MutexGuard guard(&callbacks_mutex_); base::MutexGuard guard(&callbacks_mutex_);
// Restart recompilation if another recompilation is already happening. // If compilation progress is not initialized yet, then compilation didn't
outstanding_recompilation_functions_ = 0; // start yet, and new code will be kept tiered-down from the start. For
// If compilation hasn't started yet then code would be kept as tiered-down // streaming compilation, there is a special path to tier down later, when
// and don't need to recompile. // the module is complete. In any case, we don't need to recompile here.
if (compilation_progress_.size() > 0) { if (compilation_progress_.size() > 0) {
const WasmModule* module = native_module_->module(); const WasmModule* module = native_module_->module();
int imported = module->num_imported_functions; DCHECK_EQ(module->num_declared_functions, compilation_progress_.size());
int declared = module->num_declared_functions; DCHECK_GE(module->num_declared_functions,
outstanding_recompilation_functions_ = declared; recompile_function_indexes.size());
DCHECK_EQ(declared, compilation_progress_.size()); outstanding_recompilation_functions_ =
for (int slot_index = 0; slot_index < declared; ++slot_index) { static_cast<int>(recompile_function_indexes.size());
compilation_progress_[slot_index] = MissingRecompilationField::update( // Restart recompilation if another recompilation is already happening.
compilation_progress_[slot_index], true); for (auto& progress : compilation_progress_) {
builder.AddRecompilationUnit(imported + slot_index, progress = MissingRecompilationField::update(progress, false);
new_tiering_state == kTieredDown }
auto new_tier = new_tiering_state == kTieredDown
? ExecutionTier::kLiftoff ? ExecutionTier::kLiftoff
: ExecutionTier::kTurbofan); : ExecutionTier::kTurbofan;
int imported = module->num_imported_functions;
for (int function_index : recompile_function_indexes) {
DCHECK_LE(imported, function_index);
int slot_index = function_index - imported;
auto& progress = compilation_progress_[slot_index];
progress = MissingRecompilationField::update(progress, true);
builder.AddRecompilationUnit(function_index, new_tier);
} }
} }
......
...@@ -1869,6 +1869,23 @@ void NativeModule::TriggerRecompilation() { ...@@ -1869,6 +1869,23 @@ void NativeModule::TriggerRecompilation() {
RecompileNativeModule(this, current_state); RecompileNativeModule(this, current_state);
} }
std::vector<int> NativeModule::FindFunctionsToRecompile(
TieringState new_tiering_state) {
base::MutexGuard guard(&allocation_mutex_);
std::vector<int> function_indexes;
int imported = module()->num_imported_functions;
int declared = module()->num_declared_functions;
for (int slot_index = 0; slot_index < declared; ++slot_index) {
int function_index = imported + slot_index;
WasmCode* code = code_table_[slot_index];
bool code_is_good = new_tiering_state == kTieredDown
? code && code->for_debugging()
: code && code->tier() == ExecutionTier::kTurbofan;
if (!code_is_good) function_indexes.push_back(function_index);
}
return function_indexes;
}
void NativeModule::FreeCode(Vector<WasmCode* const> codes) { void NativeModule::FreeCode(Vector<WasmCode* const> codes) {
// Free the code space. // Free the code space.
code_allocator_.FreeCode(codes); code_allocator_.FreeCode(codes);
......
...@@ -612,6 +612,12 @@ class V8_EXPORT_PRIVATE NativeModule final { ...@@ -612,6 +612,12 @@ class V8_EXPORT_PRIVATE NativeModule final {
// concurrently, so this method might return before it is complete. // concurrently, so this method might return before it is complete.
void TriggerRecompilation(); void TriggerRecompilation();
// Find all functions that need to be recompiled for a new tier. Note that
// compilation jobs might run concurrently, so this method only considers the
// compilation state of this native module at the time of the call.
// Returns a vector of function indexes to recompile.
std::vector<int> FindFunctionsToRecompile(TieringState);
// Free a set of functions of this module. Uncommits whole pages if possible. // Free a set of functions of this module. Uncommits whole pages if possible.
// The given vector must be ordered by the instruction start address, and all // The given vector must be ordered by the instruction start address, and all
// {WasmCode} objects must not be used any more. // {WasmCode} objects must not be used any more.
......
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