| Index: runtime/vm/debugger.cc
|
| diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
|
| index 5cf5419f449621b75e7f9f63387cb4fe403fa3e9..a74a0f53fb38beae9814b94fdaa9e8c8f4466b7e 100644
|
| --- a/runtime/vm/debugger.cc
|
| +++ b/runtime/vm/debugger.cc
|
| @@ -259,7 +259,7 @@ ActivationFrame::ActivationFrame(uword pc,
|
| ctx_(Context::ZoneHandle()),
|
| code_(Code::ZoneHandle(code.raw())),
|
| function_(Function::ZoneHandle(code.function())),
|
| - live_frame_((kind == kRegular) || (kind == kAsyncActivation)),
|
| + live_frame_(kind == kRegular),
|
| token_pos_initialized_(false),
|
| token_pos_(TokenPosition::kNoSource),
|
| try_index_(-1),
|
| @@ -297,37 +297,6 @@ ActivationFrame::ActivationFrame(Kind kind)
|
| desc_indices_(8),
|
| pc_desc_(PcDescriptors::ZoneHandle()) {}
|
|
|
| -
|
| -ActivationFrame::ActivationFrame(const Closure& async_activation)
|
| - : pc_(0),
|
| - fp_(0),
|
| - sp_(0),
|
| - ctx_(Context::ZoneHandle()),
|
| - code_(Code::ZoneHandle()),
|
| - function_(Function::ZoneHandle()),
|
| - live_frame_(false),
|
| - token_pos_initialized_(false),
|
| - token_pos_(TokenPosition::kNoSource),
|
| - try_index_(-1),
|
| - line_number_(-1),
|
| - column_number_(-1),
|
| - context_level_(-1),
|
| - deopt_frame_(Array::ZoneHandle()),
|
| - deopt_frame_offset_(0),
|
| - kind_(kAsyncActivation),
|
| - vars_initialized_(false),
|
| - var_descriptors_(LocalVarDescriptors::ZoneHandle()),
|
| - desc_indices_(8),
|
| - pc_desc_(PcDescriptors::ZoneHandle()) {
|
| - // Extract the function and the code from the asynchronous activation.
|
| - function_ = async_activation.function();
|
| - code_ = function_.unoptimized_code();
|
| - ctx_ = async_activation.context();
|
| - ASSERT(fp_ == 0);
|
| - ASSERT(!ctx_.IsNull());
|
| -}
|
| -
|
| -
|
| bool Debugger::NeedsIsolateEvents() {
|
| return ((isolate_ != Dart::vm_isolate()) &&
|
| !ServiceIsolate::IsServiceIsolateDescendant(isolate_) &&
|
| @@ -710,231 +679,6 @@ intptr_t ActivationFrame::ContextLevel() {
|
| return context_level_;
|
| }
|
|
|
| -RawObject* ActivationFrame::GetAsyncCompleter() {
|
| - if (!function_.IsAsyncClosure()) {
|
| - return Object::null();
|
| - }
|
| - GetVarDescriptors();
|
| - intptr_t var_desc_len = var_descriptors_.Length();
|
| - if (!live_frame_) {
|
| - // Not actually on the stack. Pull it out of the closure's context.
|
| - intptr_t var_desc_len = var_descriptors_.Length();
|
| - for (intptr_t i = 0; i < var_desc_len; i++) {
|
| - RawLocalVarDescriptors::VarInfo var_info;
|
| - var_descriptors_.GetInfo(i, &var_info);
|
| - const int8_t kind = var_info.kind();
|
| - if (var_descriptors_.GetName(i) == Symbols::AsyncCompleter().raw()) {
|
| - ASSERT(kind == RawLocalVarDescriptors::kContextVar);
|
| - ASSERT(!ctx_.IsNull());
|
| - return ctx_.At(var_info.index());
|
| - }
|
| - }
|
| - } else {
|
| - ASSERT(fp() != 0);
|
| - // On the stack.
|
| - for (intptr_t i = 0; i < var_desc_len; i++) {
|
| - RawLocalVarDescriptors::VarInfo var_info;
|
| - var_descriptors_.GetInfo(i, &var_info);
|
| - if (var_descriptors_.GetName(i) == Symbols::AsyncCompleter().raw()) {
|
| - const int8_t kind = var_info.kind();
|
| - if (kind == RawLocalVarDescriptors::kStackVar) {
|
| - return GetStackVar(var_info.index());
|
| - } else {
|
| - ASSERT(kind == RawLocalVarDescriptors::kContextVar);
|
| - return GetContextVar(var_info.scope_id, var_info.index());
|
| - }
|
| - }
|
| - }
|
| - }
|
| - return Object::null();
|
| -}
|
| -
|
| -
|
| -RawObject* ActivationFrame::GetAsyncCompleterAwaiter(const Object& completer) {
|
| - const Class& sync_completer_cls = Class::Handle(completer.clazz());
|
| - ASSERT(!sync_completer_cls.IsNull());
|
| - const Class& completer_cls = Class::Handle(sync_completer_cls.SuperClass());
|
| - const Field& future_field =
|
| - Field::Handle(completer_cls.LookupInstanceFieldAllowPrivate(
|
| - Symbols::CompleterFuture()));
|
| - ASSERT(!future_field.IsNull());
|
| - Instance& future = Instance::Handle();
|
| - future ^= Instance::Cast(completer).GetField(future_field);
|
| - ASSERT(!future.IsNull());
|
| - const Class& future_cls = Class::Handle(future.clazz());
|
| - ASSERT(!future_cls.IsNull());
|
| - const Field& awaiter_field = Field::Handle(
|
| - future_cls.LookupInstanceFieldAllowPrivate(Symbols::_Awaiter()));
|
| - ASSERT(!awaiter_field.IsNull());
|
| - return future.GetField(awaiter_field);
|
| -}
|
| -
|
| -
|
| -RawObject* ActivationFrame::GetAsyncStreamControllerStream() {
|
| - if (!function_.IsAsyncGenClosure()) {
|
| - return Object::null();
|
| - }
|
| - GetVarDescriptors();
|
| - intptr_t var_desc_len = var_descriptors_.Length();
|
| - if (!live_frame_) {
|
| - // Not actually on the stack. Pull it out of the closure's context.
|
| - intptr_t var_desc_len = var_descriptors_.Length();
|
| - for (intptr_t i = 0; i < var_desc_len; i++) {
|
| - RawLocalVarDescriptors::VarInfo var_info;
|
| - var_descriptors_.GetInfo(i, &var_info);
|
| - const int8_t kind = var_info.kind();
|
| - if (var_descriptors_.GetName(i) == Symbols::ControllerStream().raw()) {
|
| - ASSERT(kind == RawLocalVarDescriptors::kContextVar);
|
| - ASSERT(!ctx_.IsNull());
|
| - return ctx_.At(var_info.index());
|
| - }
|
| - }
|
| - } else {
|
| - ASSERT(fp() != 0);
|
| - // On the stack.
|
| - for (intptr_t i = 0; i < var_desc_len; i++) {
|
| - RawLocalVarDescriptors::VarInfo var_info;
|
| - var_descriptors_.GetInfo(i, &var_info);
|
| - if (var_descriptors_.GetName(i) == Symbols::ControllerStream().raw()) {
|
| - const int8_t kind = var_info.kind();
|
| - if (kind == RawLocalVarDescriptors::kStackVar) {
|
| - return GetStackVar(var_info.index());
|
| - } else {
|
| - ASSERT(kind == RawLocalVarDescriptors::kContextVar);
|
| - return GetContextVar(var_info.scope_id, var_info.index());
|
| - }
|
| - }
|
| - }
|
| - }
|
| - return Object::null();
|
| -}
|
| -
|
| -
|
| -RawObject* ActivationFrame::GetAsyncStreamControllerStreamAwaiter(
|
| - const Object& stream) {
|
| - const Class& stream_cls = Class::Handle(stream.clazz());
|
| - ASSERT(!stream_cls.IsNull());
|
| - const Class& stream_impl_cls = Class::Handle(stream_cls.SuperClass());
|
| - const Field& awaiter_field = Field::Handle(
|
| - stream_impl_cls.LookupInstanceFieldAllowPrivate(Symbols::_Awaiter()));
|
| - ASSERT(!awaiter_field.IsNull());
|
| - return Instance::Cast(stream).GetField(awaiter_field);
|
| -}
|
| -
|
| -
|
| -RawObject* ActivationFrame::GetAsyncAwaiter() {
|
| - const Object& completer = Object::Handle(GetAsyncCompleter());
|
| - if (!completer.IsNull()) {
|
| - return GetAsyncCompleterAwaiter(completer);
|
| - }
|
| - const Object& async_stream_controller_stream =
|
| - Object::Handle(GetAsyncStreamControllerStream());
|
| - if (!async_stream_controller_stream.IsNull()) {
|
| - return GetAsyncStreamControllerStreamAwaiter(
|
| - async_stream_controller_stream);
|
| - }
|
| - return Object::null();
|
| -}
|
| -
|
| -
|
| -bool ActivationFrame::HandlesException(const Instance& exc_obj) {
|
| - intptr_t try_index = TryIndex();
|
| - if (try_index < 0) {
|
| - return false;
|
| - }
|
| - ExceptionHandlers& handlers = ExceptionHandlers::Handle();
|
| - Array& handled_types = Array::Handle();
|
| - AbstractType& type = Type::Handle();
|
| - const TypeArguments& no_instantiator = TypeArguments::Handle();
|
| - const intptr_t try_index_threshold = CatchClauseNode::kImplicitAsyncTryIndex;
|
| - const bool is_async =
|
| - function().IsAsyncClosure() || function().IsAsyncGenClosure();
|
| - handlers = code().exception_handlers();
|
| - ASSERT(!handlers.IsNull());
|
| - intptr_t num_handlers_checked = 0;
|
| - while (try_index >= try_index_threshold) {
|
| - // Detect circles in the exception handler data.
|
| - num_handlers_checked++;
|
| - ASSERT(num_handlers_checked <= handlers.num_entries());
|
| - // Only consider user written handlers for async methods.
|
| - if (!is_async || !handlers.IsGenerated(try_index)) {
|
| - handled_types = handlers.GetHandledTypes(try_index);
|
| - const intptr_t num_types = handled_types.Length();
|
| - for (intptr_t k = 0; k < num_types; k++) {
|
| - type ^= handled_types.At(k);
|
| - ASSERT(!type.IsNull());
|
| - // Uninstantiated types are not added to ExceptionHandlers data.
|
| - ASSERT(type.IsInstantiated());
|
| - if (type.IsMalformed()) {
|
| - continue;
|
| - }
|
| - if (type.IsDynamicType()) {
|
| - return true;
|
| - }
|
| - if (exc_obj.IsInstanceOf(type, no_instantiator, NULL)) {
|
| - return true;
|
| - }
|
| - }
|
| - }
|
| - try_index = handlers.OuterTryIndex(try_index);
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -
|
| -void ActivationFrame::ExtractTokenPositionFromAsyncClosure() {
|
| - // Attempt to determine the token position from the async closure.
|
| - ASSERT(function_.IsAsyncGenClosure() || function_.IsAsyncClosure());
|
| - // This should only be called on frames that aren't active on the stack.
|
| - ASSERT(fp() == 0);
|
| - const Array& await_to_token_map =
|
| - Array::Handle(code_.await_token_positions());
|
| - if (await_to_token_map.IsNull()) {
|
| - // No mapping.
|
| - return;
|
| - }
|
| - GetVarDescriptors();
|
| - GetPcDescriptors();
|
| - intptr_t var_desc_len = var_descriptors_.Length();
|
| - intptr_t await_jump_var = -1;
|
| - for (intptr_t i = 0; i < var_desc_len; i++) {
|
| - RawLocalVarDescriptors::VarInfo var_info;
|
| - var_descriptors_.GetInfo(i, &var_info);
|
| - const int8_t kind = var_info.kind();
|
| - if (var_descriptors_.GetName(i) == Symbols::AwaitJumpVar().raw()) {
|
| - ASSERT(kind == RawLocalVarDescriptors::kContextVar);
|
| - ASSERT(!ctx_.IsNull());
|
| - Object& await_jump_index = Object::Handle(ctx_.At(var_info.index()));
|
| - ASSERT(await_jump_index.IsSmi());
|
| - await_jump_var = Smi::Cast(await_jump_index).Value();
|
| - }
|
| - }
|
| - if (await_jump_var < 0) {
|
| - return;
|
| - }
|
| - ASSERT(await_jump_var < await_to_token_map.Length());
|
| - const Object& token_pos =
|
| - Object::Handle(await_to_token_map.At(await_jump_var));
|
| - if (token_pos.IsNull()) {
|
| - return;
|
| - }
|
| - ASSERT(token_pos.IsSmi());
|
| - token_pos_ = TokenPosition(Smi::Cast(token_pos).Value());
|
| - token_pos_initialized_ = true;
|
| - PcDescriptors::Iterator iter(pc_desc_, RawPcDescriptors::kAnyKind);
|
| - while (iter.MoveNext()) {
|
| - if (iter.TokenPos() == token_pos_) {
|
| - // Match the lowest try index at this token position.
|
| - // TODO(johnmccutchan): Is this heuristic precise enough?
|
| - if (iter.TryIndex() != CatchClauseNode::kInvalidTryIndex) {
|
| - if ((try_index_ == -1) || (iter.TryIndex() < try_index_)) {
|
| - try_index_ = iter.TryIndex();
|
| - }
|
| - }
|
| - }
|
| - }
|
| -}
|
| -
|
|
|
| // Get the saved current context of this activation.
|
| const Context& ActivationFrame::GetSavedCurrentContext() {
|
| @@ -980,10 +724,35 @@ RawObject* ActivationFrame::GetAsyncOperation() {
|
|
|
| ActivationFrame* DebuggerStackTrace::GetHandlerFrame(
|
| const Instance& exc_obj) const {
|
| + ExceptionHandlers& handlers = ExceptionHandlers::Handle();
|
| + Array& handled_types = Array::Handle();
|
| + AbstractType& type = Type::Handle();
|
| + const TypeArguments& no_instantiator = TypeArguments::Handle();
|
| for (intptr_t frame_index = 0; frame_index < Length(); frame_index++) {
|
| ActivationFrame* frame = FrameAt(frame_index);
|
| - if (frame->HandlesException(exc_obj)) {
|
| - return frame;
|
| + intptr_t try_index = frame->TryIndex();
|
| + if (try_index < 0) continue;
|
| + handlers = frame->code().exception_handlers();
|
| + ASSERT(!handlers.IsNull());
|
| + intptr_t num_handlers_checked = 0;
|
| + while (try_index >= 0) {
|
| + // Detect circles in the exception handler data.
|
| + num_handlers_checked++;
|
| + ASSERT(num_handlers_checked <= handlers.num_entries());
|
| + handled_types = handlers.GetHandledTypes(try_index);
|
| + const intptr_t num_types = handled_types.Length();
|
| + for (intptr_t k = 0; k < num_types; k++) {
|
| + type ^= handled_types.At(k);
|
| + ASSERT(!type.IsNull());
|
| + // Uninstantiated types are not added to ExceptionHandlers data.
|
| + ASSERT(type.IsInstantiated());
|
| + if (type.IsMalformed()) continue;
|
| + if (type.IsDynamicType()) return frame;
|
| + if (exc_obj.IsInstanceOf(type, no_instantiator, NULL)) {
|
| + return frame;
|
| + }
|
| + }
|
| + try_index = handlers.OuterTryIndex(try_index);
|
| }
|
| }
|
| return NULL;
|
| @@ -1383,10 +1152,7 @@ void ActivationFrame::PrintToJSONObjectRegular(JSONObject* jsobj, bool full) {
|
| TokenPosition visible_end_token_pos;
|
| VariableAt(v, &var_name, &declaration_token_pos, &visible_start_token_pos,
|
| &visible_end_token_pos, &var_value);
|
| - if ((var_name.raw() != Symbols::AsyncOperation().raw()) &&
|
| - (var_name.raw() != Symbols::AsyncCompleter().raw()) &&
|
| - (var_name.raw() != Symbols::ControllerStream().raw()) &&
|
| - (var_name.raw() != Symbols::AwaitJumpVar().raw())) {
|
| + if (var_name.raw() != Symbols::AsyncOperation().raw()) {
|
| JSONObject jsvar(&jsvars);
|
| jsvar.AddProperty("type", "BoundVariable");
|
| var_name = String::ScrubName(var_name);
|
| @@ -1782,12 +1548,10 @@ ActivationFrame* Debugger::CollectDartFrame(Isolate* isolate,
|
| StackFrame* frame,
|
| const Code& code,
|
| const Array& deopt_frame,
|
| - intptr_t deopt_frame_offset,
|
| - ActivationFrame::Kind kind) {
|
| + intptr_t deopt_frame_offset) {
|
| ASSERT(code.ContainsInstructionAt(pc));
|
| - ActivationFrame* activation =
|
| - new ActivationFrame(pc, frame->fp(), frame->sp(), code, deopt_frame,
|
| - deopt_frame_offset, kind);
|
| + ActivationFrame* activation = new ActivationFrame(
|
| + pc, frame->fp(), frame->sp(), code, deopt_frame, deopt_frame_offset);
|
| if (FLAG_trace_debugger_stacktrace) {
|
| const Context& ctx = activation->GetSavedCurrentContext();
|
| OS::PrintErr("\tUsing saved context: %s\n", ctx.ToCString());
|
| @@ -1964,64 +1728,6 @@ DebuggerStackTrace* Debugger::CollectAsyncCausalStackTrace() {
|
| return stack_trace;
|
| }
|
|
|
| -
|
| -DebuggerStackTrace* Debugger::CollectAwaiterReturnStackTrace() {
|
| - if (!FLAG_causal_async_stacks) {
|
| - return NULL;
|
| - }
|
| - Thread* thread = Thread::Current();
|
| - Zone* zone = thread->zone();
|
| - Isolate* isolate = thread->isolate();
|
| - DebuggerStackTrace* stack_trace = new DebuggerStackTrace(8);
|
| -
|
| - StackFrameIterator iterator(StackFrameIterator::kDontValidateFrames);
|
| -
|
| - Code& code = Code::Handle(zone);
|
| - Function& function = Function::Handle(zone);
|
| - Code& inlined_code = Code::Handle(zone);
|
| - Closure& async_activation = Closure::Handle(zone);
|
| - Array& deopt_frame = Array::Handle(zone);
|
| -
|
| - for (StackFrame* frame = iterator.NextFrame(); frame != NULL;
|
| - frame = iterator.NextFrame()) {
|
| - ASSERT(frame->IsValid());
|
| - if (frame->IsDartFrame()) {
|
| - code = frame->LookupDartCode();
|
| - function = code.function();
|
| - if (function.IsAsyncClosure() || function.IsAsyncGenClosure()) {
|
| - ActivationFrame* activation = CollectDartFrame(
|
| - isolate, frame->pc(), frame, code, Object::null_array(), 0,
|
| - ActivationFrame::kAsyncActivation);
|
| - ASSERT(activation != NULL);
|
| - stack_trace->AddActivation(activation);
|
| - // Grab the awaiter.
|
| - async_activation ^= activation->GetAsyncAwaiter();
|
| - break;
|
| - } else {
|
| - AppendCodeFrames(thread, isolate, zone, stack_trace, frame, &code,
|
| - &inlined_code, &deopt_frame);
|
| - }
|
| - }
|
| - }
|
| -
|
| - // Return NULL to indicate that there is no useful information in this stack
|
| - // trace because we never found an awaiter.
|
| - if (async_activation.IsNull()) {
|
| - return NULL;
|
| - }
|
| -
|
| - // Append the awaiter return call stack.
|
| - while (!async_activation.IsNull()) {
|
| - ActivationFrame* activation = new ActivationFrame(async_activation);
|
| - async_activation ^= activation->GetAsyncAwaiter();
|
| - activation->ExtractTokenPositionFromAsyncClosure();
|
| - stack_trace->AddActivation(activation);
|
| - }
|
| -
|
| - return stack_trace;
|
| -}
|
| -
|
| -
|
| ActivationFrame* Debugger::TopDartFrame() const {
|
| StackFrameIterator iterator(false);
|
| StackFrame* frame = iterator.NextFrame();
|
| @@ -2122,29 +1828,6 @@ Dart_ExceptionPauseInfo Debugger::GetExceptionPauseInfo() const {
|
| }
|
|
|
|
|
| -bool Debugger::ShouldPauseOnAsyncException(DebuggerStackTrace* stack_trace,
|
| - const Instance& exc) {
|
| - if (exc_pause_info_ == kNoPauseOnExceptions) {
|
| - return false;
|
| - }
|
| - if (exc_pause_info_ == kPauseOnAllExceptions) {
|
| - return true;
|
| - }
|
| - ASSERT(exc_pause_info_ == kPauseOnUnhandledExceptions);
|
| - for (intptr_t i = 0; i < stack_trace->Length(); i++) {
|
| - ActivationFrame* frame = stack_trace->FrameAt(i);
|
| - if (frame->HandlesException(exc)) {
|
| - if (FLAG_verbose_debug) {
|
| - OS::PrintErr("%s is caught by frame %s\n", exc.ToCString(),
|
| - frame->ToCString());
|
| - }
|
| - return false;
|
| - }
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -
|
| bool Debugger::ShouldPauseOnException(DebuggerStackTrace* stack_trace,
|
| const Instance& exception) {
|
| if (exc_pause_info_ == kNoPauseOnExceptions) {
|
| @@ -2176,16 +1859,9 @@ void Debugger::PauseException(const Instance& exc) {
|
| (exc_pause_info_ == kNoPauseOnExceptions)) {
|
| return;
|
| }
|
| - DebuggerStackTrace* awaiter_stack_trace = CollectAwaiterReturnStackTrace();
|
| DebuggerStackTrace* stack_trace = CollectStackTrace();
|
| - if (awaiter_stack_trace != NULL) {
|
| - if (!ShouldPauseOnAsyncException(awaiter_stack_trace, exc)) {
|
| - return;
|
| - }
|
| - } else {
|
| - if (!ShouldPauseOnException(stack_trace, exc)) {
|
| - return;
|
| - }
|
| + if (!ShouldPauseOnException(stack_trace, exc)) {
|
| + return;
|
| }
|
| ServiceEvent event(isolate_, ServiceEvent::kPauseException);
|
| event.set_exception(&exc);
|
|
|