[wasm][gc] Fix potential deadlock

This fixes a deadlock that was detected by layout tests executing with
--future (hence enabling wasm code gc). It did not fail anywhere in v8
because GC is only triggered once we have > 1MB potentially dead code.
I plan to add a '--stress-wasm-code-gc' flag, which lowers this limit
to zero, thereby triggering GC when finding a single potentially dead
code. This mode found this issue, but also finds more, so I need to fix
other issues before enabling these stress tests.

R=mstarzinger@chromium.org

Bug: v8:8217
Change-Id: I373955b90c8b79d7b9e16184729f45db947eeeab
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1583728
Reviewed-by: Michael Starzinger <mstarzinger@chromium.org>
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#61034}
This commit is contained in:
Clemens Hammacher 2019-04-25 15:35:47 +02:00 committed by Commit Bot
parent f5124b42a1
commit 34554ec00e

View File

@ -665,29 +665,35 @@ void WasmEngine::SampleTopTierCodeSizeInAllIsolates(
void WasmEngine::ReportLiveCodeForGC(Isolate* isolate,
Vector<WasmCode*> live_code) {
base::MutexGuard guard(&mutex_);
DCHECK_NOT_NULL(current_gc_info_);
auto outstanding_isolate_it =
current_gc_info_->outstanding_isolates.find(isolate);
DCHECK_NE(current_gc_info_->outstanding_isolates.end(),
outstanding_isolate_it);
auto* fg_task = outstanding_isolate_it->second;
if (fg_task) fg_task->Cancel();
current_gc_info_->outstanding_isolates.erase(outstanding_isolate_it);
for (WasmCode* code : live_code) current_gc_info_->dead_code.erase(code);
// Get the set of dead code under the mutex, but decrement the ref count after
// releasing the mutex to avoid deadlocks.
OwnedVector<WasmCode*> dead_code;
{
base::MutexGuard guard(&mutex_);
DCHECK_NOT_NULL(current_gc_info_);
auto outstanding_isolate_it =
current_gc_info_->outstanding_isolates.find(isolate);
DCHECK_NE(current_gc_info_->outstanding_isolates.end(),
outstanding_isolate_it);
auto* fg_task = outstanding_isolate_it->second;
if (fg_task) fg_task->Cancel();
current_gc_info_->outstanding_isolates.erase(outstanding_isolate_it);
for (WasmCode* code : live_code) current_gc_info_->dead_code.erase(code);
if (current_gc_info_->outstanding_isolates.empty()) {
// All remaining code in {current_gc_info->dead_code} is really dead. Remove
// it from the set of potentially dead code, and decrement its ref count.
auto dead_code = OwnedVector<WasmCode*>::Of(current_gc_info_->dead_code);
for (WasmCode* code : dead_code) {
auto* native_module_info = native_modules_[code->native_module()].get();
DCHECK_EQ(1, native_module_info->potentially_dead_code.count(code));
native_module_info->potentially_dead_code.erase(code);
if (current_gc_info_->outstanding_isolates.empty()) {
// All remaining code in {current_gc_info->dead_code} is really dead.
// Remove it from the set of potentially dead code, and decrement its ref
// count.
dead_code = OwnedVector<WasmCode*>::Of(current_gc_info_->dead_code);
for (WasmCode* code : dead_code) {
auto* native_module_info = native_modules_[code->native_module()].get();
DCHECK_EQ(1, native_module_info->potentially_dead_code.count(code));
native_module_info->potentially_dead_code.erase(code);
}
current_gc_info_.reset();
}
WasmCode::DecrementRefCount(dead_code.as_vector());
current_gc_info_.reset();
}
if (!dead_code.empty()) WasmCode::DecrementRefCount(dead_code.as_vector());
}
bool WasmEngine::AddPotentiallyDeadCode(WasmCode* code) {