| // 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_trace.h" |
| #include "vm/stack_frame.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(ValidationPolicy::kDontValidateFrames, thread, |
| StackFrameIterator::kNoCrossThreadIteration); |
| StackFrame* frame = frames.NextFrame(); |
| ASSERT(frame != NULL); // We expect to find a dart invocation frame. |
| 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 { |
| function = frame->LookupDartFunction(); |
| 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(ValidationPolicy::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); |
| Bytecode& bytecode = Bytecode::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 { |
| if (frame->is_interpreted()) { |
| bytecode = frame->LookupDartBytecode(); |
| function = bytecode.function(); |
| offset = Smi::New(frame->pc() - bytecode.PayloadStart()); |
| code_array.SetAt(array_offset, bytecode); |
| } 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().raw()); |
| const Object& code_object = Object::Handle(async_code_array->At(1)); |
| if (code_object.IsCode()) { |
| *async_function = Code::Cast(code_object).function(); |
| } else { |
| ASSERT(code_object.IsBytecode()); |
| *async_function = Bytecode::Cast(code_object).function(); |
| } |
| ASSERT(!async_function->IsNull()); |
| ASSERT(async_function->IsAsyncFunction() || |
| async_function->IsAsyncGenerator()); |
| return async_stack_trace_length; |
| } |
| |
| } // namespace dart |