Files
sdk/runtime/vm/weak_code.cc
T
Vyacheslav Egorov 65f2e015ca VM: Fix race between background compiler and guarded cid update.
Rework how we check guarded state consistency in background compiler.

Background compiler was storing original fields inside guarded fields list. This caused a race during inlining when inliner would copy guarded fields one by one from the callee function into the caller, because ParsedFunction::AddToGuardedFields looks at the guarded_cid to filter out those fields that should not be guarded.

As a result if some guarded field transitioned to unguarded (kDynamicCid) after callee graph construction but before list of guarded fields were copied then AddToGuardedFields would simply skip that field because it now has guarded_cid() == kDynamicCid.

We fix this race by always placing copies into the list of guarded fields and unwrapping them only in FinalizeCode.

Placing the copies also allows us to simplify a lot of code that was trying to verify guarded state consistency before committing the generated optimized code - now that we store copies in the list we can just compare their state to the originals and abort if the state is different.

Additionally fix deduplication check that was comparing original fields with copies - resulting in adding the same field into the list multiple times.

Add an assertion that verifies that we are not trying to access guarded_cid of original field from background compiler.

R=fschneider@google.com
BUG=

Review URL: https://codereview.chromium.org/2006793002 .
2016-05-24 14:52:02 +02:00

136 lines
4.0 KiB
C++

// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/weak_code.h"
#include "platform/assert.h"
#include "vm/code_generator.h"
#include "vm/code_patcher.h"
#include "vm/object.h"
#include "vm/stack_frame.h"
namespace dart {
bool WeakCodeReferences::HasCodes() const {
return !array_.IsNull() && (array_.Length() > 0);
}
void WeakCodeReferences::Register(const Code& value) {
if (!array_.IsNull()) {
// Try to find and reuse cleared WeakProperty to avoid allocating new one.
WeakProperty& weak_property = WeakProperty::Handle();
for (intptr_t i = 0; i < array_.Length(); i++) {
weak_property ^= array_.At(i);
if (weak_property.key() == Code::null()) {
// Empty property found. Reuse it.
weak_property.set_key(value);
return;
}
}
}
const WeakProperty& weak_property = WeakProperty::Handle(
WeakProperty::New(Heap::kOld));
weak_property.set_key(value);
intptr_t length = array_.IsNull() ? 0 : array_.Length();
const Array& new_array = Array::Handle(
Array::Grow(array_, length + 1, Heap::kOld));
new_array.SetAt(length, weak_property);
UpdateArrayTo(new_array);
}
bool WeakCodeReferences::IsOptimizedCode(const Array& dependent_code,
const Code& code) {
if (!code.is_optimized()) {
return false;
}
WeakProperty& weak_property = WeakProperty::Handle();
for (intptr_t i = 0; i < dependent_code.Length(); i++) {
weak_property ^= dependent_code.At(i);
if (code.raw() == weak_property.key()) {
return true;
}
}
return false;
}
void WeakCodeReferences::DisableCode() {
const Array& code_objects = Array::Handle(array_.raw());
if (code_objects.IsNull()) {
return;
}
ASSERT(!FLAG_precompiled_runtime);
UpdateArrayTo(Object::null_array());
// Disable all code on stack.
Code& code = Code::Handle();
{
DartFrameIterator iterator;
StackFrame* frame = iterator.NextFrame();
while (frame != NULL) {
code = frame->LookupDartCode();
if (IsOptimizedCode(code_objects, code)) {
ReportDeoptimization(code);
DeoptimizeAt(code, frame->pc());
}
frame = iterator.NextFrame();
}
}
// Switch functions that use dependent code to unoptimized code.
WeakProperty& weak_property = WeakProperty::Handle();
Object& owner = Object::Handle();
Function& function = Function::Handle();
for (intptr_t i = 0; i < code_objects.Length(); i++) {
weak_property ^= code_objects.At(i);
code ^= weak_property.key();
if (code.IsNull()) {
// Code was garbage collected already.
continue;
}
owner = code.owner();
if (owner.IsFunction()) {
function ^= owner.raw();
} else if (owner.IsClass()) {
Class& cls = Class::Handle();
cls ^= owner.raw();
cls.DisableAllocationStub();
continue;
} else if (owner.IsNull()) {
code.Print();
continue;
}
// If function uses dependent code switch it to unoptimized.
if (code.is_optimized() && (function.CurrentCode() == code.raw())) {
ReportSwitchingCode(code);
function.SwitchToUnoptimizedCode();
} else if (function.unoptimized_code() == code.raw()) {
ReportSwitchingCode(code);
function.set_was_compiled(false);
function.ClearICDataArray();
// Remove the code object from the function. The next time the
// function is invoked, it will be compiled again.
function.ClearCode();
// Invalidate the old code object so existing references to it
// (from optimized code) will be patched when invoked.
if (!code.IsDisabled()) {
code.DisableDartCode();
}
} else {
// Make non-OSR code non-entrant.
if (!code.IsDisabled()) {
ReportSwitchingCode(code);
code.DisableDartCode();
}
}
}
}
} // namespace dart