Files
sdk/runtime/vm/stack_trace.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

114 lines
4.2 KiB
C++

// Copyright (c) 2017, 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/stack_frame.h"
#include "vm/stack_trace.h"
namespace dart {
// Count the number of frames that are on the stack.
intptr_t StackTraceUtils::CountFrames(Thread* thread,
int skip_frames,
const Function& async_function) {
Zone* zone = thread->zone();
intptr_t frame_count = 0;
StackFrameIterator frames(StackFrameIterator::kDontValidateFrames, thread,
StackFrameIterator::kNoCrossThreadIteration);
StackFrame* frame = frames.NextFrame();
ASSERT(frame != NULL); // We expect to find a dart invocation frame.
Code& code = Code::Handle(zone);
Function& function = Function::Handle(zone);
const bool async_function_is_null = async_function.IsNull();
while (frame != NULL) {
if (frame->IsDartFrame()) {
if (skip_frames > 0) {
skip_frames--;
} else {
code = frame->LookupDartCode();
function = code.function();
frame_count++;
if (!async_function_is_null &&
(async_function.raw() == function.parent_function())) {
return frame_count;
}
}
}
frame = frames.NextFrame();
}
// We hit the sentinel.
ASSERT(async_function_is_null);
return frame_count;
}
intptr_t StackTraceUtils::CollectFrames(Thread* thread,
const Array& code_array,
const Array& pc_offset_array,
intptr_t array_offset,
intptr_t count,
int skip_frames) {
Zone* zone = thread->zone();
StackFrameIterator frames(StackFrameIterator::kDontValidateFrames, thread,
StackFrameIterator::kNoCrossThreadIteration);
StackFrame* frame = frames.NextFrame();
ASSERT(frame != NULL); // We expect to find a dart invocation frame.
Function& function = Function::Handle(zone);
Code& code = Code::Handle(zone);
Smi& offset = Smi::Handle(zone);
intptr_t collected_frames_count = 0;
while ((frame != NULL) && (collected_frames_count < count)) {
if (frame->IsDartFrame()) {
if (skip_frames > 0) {
skip_frames--;
} else {
code = frame->LookupDartCode();
function = code.function();
offset = Smi::New(frame->pc() - code.PayloadStart());
code_array.SetAt(array_offset, code);
pc_offset_array.SetAt(array_offset, offset);
array_offset++;
collected_frames_count++;
}
}
frame = frames.NextFrame();
}
return collected_frames_count;
}
intptr_t StackTraceUtils::ExtractAsyncStackTraceInfo(
Thread* thread,
Function* async_function,
StackTrace* async_stack_trace_out,
Array* async_code_array,
Array* async_pc_offset_array) {
if (thread->async_stack_trace() == StackTrace::null()) {
return 0;
}
*async_stack_trace_out = thread->async_stack_trace();
ASSERT(!async_stack_trace_out->IsNull());
const StackTrace& async_stack_trace =
StackTrace::Handle(thread->async_stack_trace());
const intptr_t async_stack_trace_length = async_stack_trace.Length();
// At least two entries (0: gap marker, 1: async function).
ASSERT(async_stack_trace_length >= 2);
// Validate the structure of this stack trace.
*async_code_array = async_stack_trace.code_array();
ASSERT(!async_code_array->IsNull());
*async_pc_offset_array = async_stack_trace.pc_offset_array();
ASSERT(!async_pc_offset_array->IsNull());
// We start with the asynchronous gap marker.
ASSERT(async_code_array->At(0) != Code::null());
ASSERT(async_code_array->At(0) ==
StubCode::AsynchronousGapMarker_entry()->code());
const Code& code = Code::Handle(Code::RawCast(async_code_array->At(1)));
*async_function = code.function();
ASSERT(!async_function->IsNull());
ASSERT(async_function->IsAsyncFunction() ||
async_function->IsAsyncGenerator());
return async_stack_trace_length;
}
} // namespace dart