Files
sdk/runtime/vm/weak_code.cc
T
Martin Kustermann ac8d2056a3 Fix asserts in StackFrameIterator which were effectively disabled
The assertions which tried to assert that we only use
StackFrameIterator to walk frames of the current thread was incorrect.
We already have cases where other threads will walk the stack of the
mutator thread, see below for an example where this can happen.

Thread::VisitObjectPointers was incorrectly passing Thread::Current() to
the StackFrameIterator instead of 'this'.  (Code in thread_registry.cc will
loop over a number of threads and calls VisitObjectPointers on them)

  Mutator thread:

    0  pthread_cond_wait@@GLIBC_2.3.2
    1  dart::Monitor::WaitMicros
    2  dart::Monitor::Wait
    3  dart::MonitorLocker::Wait
    4  dart::ThreadBarrier::Sync
    5  dart::GCMarker::MarkObjects
    6  dart::PageSpace::MarkSweep
    7  dart::Heap::CollectOldSpaceGarbage
    8  dart::Heap::CollectNewSpaceGarbage
    9  dart::Heap::CollectGarbage
    10 dart::DN_HelperObject_<native>
    11 dart::BootstrapNatives::<native>
    <dart frames>

  MarkTask thread:

    1  dart::EntryFrame::VisitObjectPointers
    2  dart::Thread::VisitObjectPointers          <---- Walks mutator thread stack
    3  dart::ThreadRegistry::VisitObjectPointers  <---- Iterates over a number of threads
    4  dart::Isolate::VisitStackPointers
    5  dart::Isolate::VisitObjectPointers
    6  dart::GCMarker::IterateRoots
    7  dart::MarkTask::Run
    8  dart::ThreadPool::Worker::Loop
    9  dart::ThreadPool::Worker::Main
    10 dart::ThreadStart

R=rmacnak@google.com

Review-Url: https://codereview.chromium.org/2845053003 .
2017-05-03 10:27:01 +02:00

138 lines
4.1 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_patcher.h"
#include "vm/object.h"
#include "vm/runtime_entry.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() {
Thread* thread = Thread::Current();
const Array& code_objects = Array::Handle(thread->zone(), 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(thread,
StackFrameIterator::kNoCrossThreadIteration);
StackFrame* frame = iterator.NextFrame();
while (frame != NULL) {
code = frame->LookupDartCode();
if (IsOptimizedCode(code_objects, code)) {
ReportDeoptimization(code);
DeoptimizeAt(code, frame);
}
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