| Index: runtime/vm/debugger.cc
|
| ===================================================================
|
| --- runtime/vm/debugger.cc (revision 17157)
|
| +++ runtime/vm/debugger.cc (working copy)
|
| @@ -301,6 +301,12 @@
|
| }
|
|
|
|
|
| +intptr_t ActivationFrame::TryIndex() {
|
| + intptr_t desc_index = PcDescIndex();
|
| + return pc_desc_.TryIndex(desc_index);
|
| +}
|
| +
|
| +
|
| intptr_t ActivationFrame::LineNumber() {
|
| // Compute line number lazily since it causes scanning of the script.
|
| if (line_number_ < 0) {
|
| @@ -372,6 +378,59 @@
|
| }
|
|
|
|
|
| +// TODO(hausner): Eliminate this helper function by sorting the
|
| +// ExceptionHandlers entries by try_index and eliminating
|
| +// the try_index field altogether.
|
| +static intptr_t FindTryIndex(const ExceptionHandlers& handlers,
|
| + intptr_t try_index) {
|
| + intptr_t len = handlers.Length();
|
| + for (int i = 0; i < len; i++) {
|
| + if (handlers.TryIndex(i) == try_index) return i;
|
| + }
|
| + UNREACHABLE();
|
| + return -1;
|
| +}
|
| +
|
| +
|
| +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 (int frame_index = 0; frame_index < Length(); frame_index++) {
|
| + ActivationFrame* frame = trace_[frame_index];
|
| + intptr_t try_index = frame->TryIndex();
|
| + if (try_index < 0) continue;
|
| + const Code& code = frame->DartCode();
|
| + handlers = code.exception_handlers();
|
| + ASSERT(!handlers.IsNull());
|
| + intptr_t num_handlers_checked = 0;
|
| + while (try_index >= 0) {
|
| + intptr_t i = FindTryIndex(handlers, try_index);
|
| + // Detect circles in the exception handler data.
|
| + num_handlers_checked++;
|
| + ASSERT(num_handlers_checked <= handlers.Length());
|
| + handled_types = handlers.GetHandledTypes(i);
|
| + const intptr_t num_types = handled_types.Length();
|
| + for (int 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.IsDynamicType()) return frame;
|
| + if (type.IsMalformed()) continue;
|
| + if (exc_obj.IsInstanceOf(type, no_instantiator, NULL)) {
|
| + return frame;
|
| + }
|
| + }
|
| + try_index = handlers.OuterTryIndex(i);
|
| + }
|
| + }
|
| + return NULL;
|
| +}
|
| +
|
| +
|
| void ActivationFrame::GetDescIndices() {
|
| if (vars_initialized_) {
|
| return;
|
| @@ -866,31 +925,29 @@
|
| }
|
|
|
|
|
| -// TODO(hausner): Determine whether the exception is handled or not.
|
| bool Debugger::ShouldPauseOnException(DebuggerStackTrace* stack_trace,
|
| - const Object& exc) {
|
| + const Instance& exc) {
|
| if (exc_pause_info_ == kNoPauseOnExceptions) {
|
| return false;
|
| }
|
| - if ((exc_pause_info_ & kPauseOnAllExceptions) != 0) {
|
| + if (exc_pause_info_ == kPauseOnAllExceptions) {
|
| return true;
|
| }
|
| - // Assume TypeError and AssertionError exceptions are unhandled.
|
| - const Class& exc_class = Class::Handle(exc.clazz());
|
| - const String& class_name = String::Handle(exc_class.Name());
|
| - // TODO(hausner): Note the poor man's type test. This code will go
|
| - // away when we have a way to determine whether an exception is unhandled.
|
| - if (class_name.Equals("TypeErrorImplementation")) {
|
| + ASSERT(exc_pause_info_ == kPauseOnUnhandledExceptions);
|
| + ActivationFrame* handler_frame = stack_trace->GetHandlerFrame(exc);
|
| + if (handler_frame == NULL) {
|
| + // Did not find an exception handler that catches this exception.
|
| + // Note that this check is not precise, since we can't check
|
| + // uninstantiated types, i.e. types containing type parameters.
|
| + // Thus, we may report an exception as unhandled when in fact
|
| + // it will be caught once we unwind the stack.
|
| return true;
|
| }
|
| - if (class_name.Equals("AssertionErrorImplementation")) {
|
| - return true;
|
| - }
|
| return false;
|
| }
|
|
|
|
|
| -void Debugger::SignalExceptionThrown(const Object& exc) {
|
| +void Debugger::SignalExceptionThrown(const Instance& exc) {
|
| // We ignore this exception event when the VM is executing code invoked
|
| // by the debugger to evaluate variables values, when we see a nested
|
| // breakpoint or exception event, or if the debugger is not
|
|
|