| OLD | NEW |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/exceptions.h" | 5 #include "vm/exceptions.h" |
| 6 | 6 |
| 7 #include "vm/dart_api_impl.h" | 7 #include "vm/dart_api_impl.h" |
| 8 #include "vm/dart_entry.h" | 8 #include "vm/dart_entry.h" |
| 9 #include "vm/debugger.h" | 9 #include "vm/debugger.h" |
| 10 #include "vm/flags.h" | 10 #include "vm/flags.h" |
| (...skipping 26 matching lines...) Expand all Loading... |
| 37 "Stack traces will include methods marked invisible."); | 37 "Stack traces will include methods marked invisible."); |
| 38 | 38 |
| 39 const char* Exceptions::kCastErrorDstName = "type cast"; | 39 const char* Exceptions::kCastErrorDstName = "type cast"; |
| 40 | 40 |
| 41 | 41 |
| 42 class StacktraceBuilder : public ValueObject { | 42 class StacktraceBuilder : public ValueObject { |
| 43 public: | 43 public: |
| 44 StacktraceBuilder() { } | 44 StacktraceBuilder() { } |
| 45 virtual ~StacktraceBuilder() { } | 45 virtual ~StacktraceBuilder() { } |
| 46 | 46 |
| 47 virtual void AddFrame(const Function& func, | 47 virtual void AddFrame(const Code& code, |
| 48 const Code& code, | |
| 49 const Smi& offset, | 48 const Smi& offset, |
| 50 bool is_catch_frame) = 0; | 49 bool is_catch_frame) = 0; |
| 51 | 50 |
| 52 virtual bool FullStacktrace() const = 0; | 51 virtual bool FullStacktrace() const = 0; |
| 53 }; | 52 }; |
| 54 | 53 |
| 55 | 54 |
| 56 class RegularStacktraceBuilder : public StacktraceBuilder { | 55 class RegularStacktraceBuilder : public StacktraceBuilder { |
| 57 public: | 56 public: |
| 58 explicit RegularStacktraceBuilder(bool full_stacktrace) | 57 explicit RegularStacktraceBuilder(bool full_stacktrace) |
| 59 : func_list_(GrowableObjectArray::Handle(GrowableObjectArray::New())), | 58 : code_list_(GrowableObjectArray::Handle(GrowableObjectArray::New())), |
| 60 code_list_(GrowableObjectArray::Handle(GrowableObjectArray::New())), | |
| 61 pc_offset_list_( | 59 pc_offset_list_( |
| 62 GrowableObjectArray::Handle(GrowableObjectArray::New())), | 60 GrowableObjectArray::Handle(GrowableObjectArray::New())), |
| 63 catch_func_list_( | |
| 64 full_stacktrace ? | |
| 65 GrowableObjectArray::Handle(GrowableObjectArray::New()) : | |
| 66 GrowableObjectArray::Handle()), | |
| 67 catch_code_list_( | 61 catch_code_list_( |
| 68 full_stacktrace ? | 62 full_stacktrace ? |
| 69 GrowableObjectArray::Handle(GrowableObjectArray::New()) : | 63 GrowableObjectArray::Handle(GrowableObjectArray::New()) : |
| 70 GrowableObjectArray::Handle()), | 64 GrowableObjectArray::Handle()), |
| 71 catch_pc_offset_list_( | 65 catch_pc_offset_list_( |
| 72 full_stacktrace ? | 66 full_stacktrace ? |
| 73 GrowableObjectArray::Handle(GrowableObjectArray::New()) : | 67 GrowableObjectArray::Handle(GrowableObjectArray::New()) : |
| 74 GrowableObjectArray::Handle()), | 68 GrowableObjectArray::Handle()), |
| 75 full_stacktrace_(full_stacktrace) { } | 69 full_stacktrace_(full_stacktrace) { } |
| 76 ~RegularStacktraceBuilder() { } | 70 ~RegularStacktraceBuilder() { } |
| 77 | 71 |
| 78 const GrowableObjectArray& func_list() const { return func_list_; } | |
| 79 const GrowableObjectArray& code_list() const { return code_list_; } | 72 const GrowableObjectArray& code_list() const { return code_list_; } |
| 80 const GrowableObjectArray& pc_offset_list() const { return pc_offset_list_; } | 73 const GrowableObjectArray& pc_offset_list() const { return pc_offset_list_; } |
| 81 const GrowableObjectArray& catch_func_list() const { | |
| 82 return catch_func_list_; | |
| 83 } | |
| 84 const GrowableObjectArray& catch_code_list() const { | 74 const GrowableObjectArray& catch_code_list() const { |
| 85 return catch_code_list_; | 75 return catch_code_list_; |
| 86 } | 76 } |
| 87 const GrowableObjectArray& catch_pc_offset_list() const { | 77 const GrowableObjectArray& catch_pc_offset_list() const { |
| 88 return catch_pc_offset_list_; | 78 return catch_pc_offset_list_; |
| 89 } | 79 } |
| 90 virtual bool FullStacktrace() const { return full_stacktrace_; } | 80 virtual bool FullStacktrace() const { return full_stacktrace_; } |
| 91 | 81 |
| 92 virtual void AddFrame(const Function& func, | 82 virtual void AddFrame(const Code& code, |
| 93 const Code& code, | |
| 94 const Smi& offset, | 83 const Smi& offset, |
| 95 bool is_catch_frame) { | 84 bool is_catch_frame) { |
| 96 if (is_catch_frame) { | 85 if (is_catch_frame) { |
| 97 catch_func_list_.Add(func); | |
| 98 catch_code_list_.Add(code); | 86 catch_code_list_.Add(code); |
| 99 catch_pc_offset_list_.Add(offset); | 87 catch_pc_offset_list_.Add(offset); |
| 100 } else { | 88 } else { |
| 101 func_list_.Add(func); | |
| 102 code_list_.Add(code); | 89 code_list_.Add(code); |
| 103 pc_offset_list_.Add(offset); | 90 pc_offset_list_.Add(offset); |
| 104 } | 91 } |
| 105 } | 92 } |
| 106 | 93 |
| 107 private: | 94 private: |
| 108 const GrowableObjectArray& func_list_; | |
| 109 const GrowableObjectArray& code_list_; | 95 const GrowableObjectArray& code_list_; |
| 110 const GrowableObjectArray& pc_offset_list_; | 96 const GrowableObjectArray& pc_offset_list_; |
| 111 const GrowableObjectArray& catch_func_list_; | |
| 112 const GrowableObjectArray& catch_code_list_; | 97 const GrowableObjectArray& catch_code_list_; |
| 113 const GrowableObjectArray& catch_pc_offset_list_; | 98 const GrowableObjectArray& catch_pc_offset_list_; |
| 114 bool full_stacktrace_; | 99 bool full_stacktrace_; |
| 115 | 100 |
| 116 DISALLOW_COPY_AND_ASSIGN(RegularStacktraceBuilder); | 101 DISALLOW_COPY_AND_ASSIGN(RegularStacktraceBuilder); |
| 117 }; | 102 }; |
| 118 | 103 |
| 119 | 104 |
| 120 class PreallocatedStacktraceBuilder : public StacktraceBuilder { | 105 class PreallocatedStacktraceBuilder : public StacktraceBuilder { |
| 121 public: | 106 public: |
| 122 explicit PreallocatedStacktraceBuilder(const Stacktrace& stacktrace) | 107 explicit PreallocatedStacktraceBuilder(const Stacktrace& stacktrace) |
| 123 : stacktrace_(stacktrace), | 108 : stacktrace_(stacktrace), |
| 124 cur_index_(0) { | 109 cur_index_(0) { |
| 125 ASSERT(stacktrace_.raw() == | 110 ASSERT(stacktrace_.raw() == |
| 126 Isolate::Current()->object_store()->preallocated_stack_trace()); | 111 Isolate::Current()->object_store()->preallocated_stack_trace()); |
| 127 } | 112 } |
| 128 ~PreallocatedStacktraceBuilder() { } | 113 ~PreallocatedStacktraceBuilder() { } |
| 129 | 114 |
| 130 virtual void AddFrame(const Function& func, | 115 virtual void AddFrame(const Code& code, |
| 131 const Code& code, | |
| 132 const Smi& offset, | 116 const Smi& offset, |
| 133 bool is_catch_frame); | 117 bool is_catch_frame); |
| 134 | 118 |
| 135 virtual bool FullStacktrace() const { return false; } | 119 virtual bool FullStacktrace() const { return false; } |
| 136 | 120 |
| 137 private: | 121 private: |
| 138 static const int kNumTopframes = 3; | 122 static const int kNumTopframes = 3; |
| 139 | 123 |
| 140 const Stacktrace& stacktrace_; | 124 const Stacktrace& stacktrace_; |
| 141 intptr_t cur_index_; | 125 intptr_t cur_index_; |
| 142 | 126 |
| 143 DISALLOW_COPY_AND_ASSIGN(PreallocatedStacktraceBuilder); | 127 DISALLOW_COPY_AND_ASSIGN(PreallocatedStacktraceBuilder); |
| 144 }; | 128 }; |
| 145 | 129 |
| 146 | 130 |
| 147 void PreallocatedStacktraceBuilder::AddFrame(const Function& func, | 131 void PreallocatedStacktraceBuilder::AddFrame(const Code& code, |
| 148 const Code& code, | |
| 149 const Smi& offset, | 132 const Smi& offset, |
| 150 bool is_catch_frame) { | 133 bool is_catch_frame) { |
| 151 if (cur_index_ >= Stacktrace::kPreallocatedStackdepth) { | 134 if (cur_index_ >= Stacktrace::kPreallocatedStackdepth) { |
| 152 // The number of frames is overflowing the preallocated stack trace object. | 135 // The number of frames is overflowing the preallocated stack trace object. |
| 153 Function& frame_func = Function::Handle(); | |
| 154 Code& frame_code = Code::Handle(); | 136 Code& frame_code = Code::Handle(); |
| 155 Smi& frame_offset = Smi::Handle(); | 137 Smi& frame_offset = Smi::Handle(); |
| 156 intptr_t start = Stacktrace::kPreallocatedStackdepth - (kNumTopframes - 1); | 138 intptr_t start = Stacktrace::kPreallocatedStackdepth - (kNumTopframes - 1); |
| 157 intptr_t null_slot = start - 2; | 139 intptr_t null_slot = start - 2; |
| 158 // Add an empty slot to indicate the overflow so that the toString | 140 // Add an empty slot to indicate the overflow so that the toString |
| 159 // method can account for the overflow. | 141 // method can account for the overflow. |
| 160 if (stacktrace_.FunctionAtFrame(null_slot) != Function::null()) { | 142 if (stacktrace_.FunctionAtFrame(null_slot) != Function::null()) { |
| 161 stacktrace_.SetFunctionAtFrame(null_slot, frame_func); | |
| 162 stacktrace_.SetCodeAtFrame(null_slot, frame_code); | 143 stacktrace_.SetCodeAtFrame(null_slot, frame_code); |
| 163 } | 144 } |
| 164 // Move frames one slot down so that we can accomodate the new frame. | 145 // Move frames one slot down so that we can accomodate the new frame. |
| 165 for (intptr_t i = start; i < Stacktrace::kPreallocatedStackdepth; i++) { | 146 for (intptr_t i = start; i < Stacktrace::kPreallocatedStackdepth; i++) { |
| 166 intptr_t prev = (i - 1); | 147 intptr_t prev = (i - 1); |
| 167 frame_func = stacktrace_.FunctionAtFrame(i); | |
| 168 frame_code = stacktrace_.CodeAtFrame(i); | 148 frame_code = stacktrace_.CodeAtFrame(i); |
| 169 frame_offset = stacktrace_.PcOffsetAtFrame(i); | 149 frame_offset = stacktrace_.PcOffsetAtFrame(i); |
| 170 stacktrace_.SetFunctionAtFrame(prev, frame_func); | |
| 171 stacktrace_.SetCodeAtFrame(prev, frame_code); | 150 stacktrace_.SetCodeAtFrame(prev, frame_code); |
| 172 stacktrace_.SetPcOffsetAtFrame(prev, frame_offset); | 151 stacktrace_.SetPcOffsetAtFrame(prev, frame_offset); |
| 173 } | 152 } |
| 174 cur_index_ = (Stacktrace::kPreallocatedStackdepth - 1); | 153 cur_index_ = (Stacktrace::kPreallocatedStackdepth - 1); |
| 175 } | 154 } |
| 176 stacktrace_.SetFunctionAtFrame(cur_index_, func); | |
| 177 stacktrace_.SetCodeAtFrame(cur_index_, code); | 155 stacktrace_.SetCodeAtFrame(cur_index_, code); |
| 178 stacktrace_.SetPcOffsetAtFrame(cur_index_, offset); | 156 stacktrace_.SetPcOffsetAtFrame(cur_index_, offset); |
| 179 cur_index_ += 1; | 157 cur_index_ += 1; |
| 180 } | 158 } |
| 181 | 159 |
| 182 | 160 |
| 183 static bool ShouldShowFunction(const Function& function) { | |
| 184 if (FLAG_verbose_stacktrace) { | |
| 185 return true; | |
| 186 } | |
| 187 return function.is_visible(); | |
| 188 } | |
| 189 | |
| 190 | |
| 191 static void BuildStackTrace(StacktraceBuilder* builder) { | 161 static void BuildStackTrace(StacktraceBuilder* builder) { |
| 192 StackFrameIterator frames(StackFrameIterator::kDontValidateFrames); | 162 StackFrameIterator frames(StackFrameIterator::kDontValidateFrames); |
| 193 StackFrame* frame = frames.NextFrame(); | 163 StackFrame* frame = frames.NextFrame(); |
| 194 ASSERT(frame != NULL); // We expect to find a dart invocation frame. | 164 ASSERT(frame != NULL); // We expect to find a dart invocation frame. |
| 195 Function& func = Function::Handle(); | |
| 196 Code& code = Code::Handle(); | 165 Code& code = Code::Handle(); |
| 197 Smi& offset = Smi::Handle(); | 166 Smi& offset = Smi::Handle(); |
| 198 bool dart_handler_found = false; | 167 bool dart_handler_found = false; |
| 199 bool handler_pc_set = false; | 168 bool handler_pc_set = false; |
| 200 while (frame != NULL) { | 169 while (frame != NULL) { |
| 201 while (!frame->IsEntryFrame()) { | 170 while (!frame->IsEntryFrame()) { |
| 202 if (frame->IsDartFrame()) { | 171 if (frame->IsDartFrame()) { |
| 203 code = frame->LookupDartCode(); | 172 code = frame->LookupDartCode(); |
| 204 if (code.is_optimized()) { | 173 offset = Smi::New(frame->pc() - code.EntryPoint()); |
| 205 // For optimized frames, extract all the inlined functions if any | 174 builder->AddFrame(code, offset, dart_handler_found); |
| 206 // into the stack trace. | |
| 207 for (InlinedFunctionsIterator it(code, frame->pc()); | |
| 208 !it.Done(); it.Advance()) { | |
| 209 func = it.function(); | |
| 210 code = it.code(); | |
| 211 uword pc = it.pc(); | |
| 212 ASSERT(pc != 0); | |
| 213 ASSERT(code.EntryPoint() <= pc); | |
| 214 ASSERT(pc < (code.EntryPoint() + code.Size())); | |
| 215 if (ShouldShowFunction(func)) { | |
| 216 offset = Smi::New(pc - code.EntryPoint()); | |
| 217 builder->AddFrame(func, code, offset, dart_handler_found); | |
| 218 } | |
| 219 } | |
| 220 } else { | |
| 221 offset = Smi::New(frame->pc() - code.EntryPoint()); | |
| 222 func = code.function(); | |
| 223 if (ShouldShowFunction(func)) { | |
| 224 builder->AddFrame(func, code, offset, dart_handler_found); | |
| 225 } | |
| 226 } | |
| 227 bool needs_stacktrace = false; | 175 bool needs_stacktrace = false; |
| 228 bool is_catch_all = false; | 176 bool is_catch_all = false; |
| 229 uword handler_pc = kUwordMax; | 177 uword handler_pc = kUwordMax; |
| 230 if (!handler_pc_set && | 178 if (!handler_pc_set && |
| 231 frame->FindExceptionHandler(&handler_pc, | 179 frame->FindExceptionHandler(&handler_pc, |
| 232 &needs_stacktrace, | 180 &needs_stacktrace, |
| 233 &is_catch_all)) { | 181 &is_catch_all)) { |
| 234 handler_pc_set = true; | 182 handler_pc_set = true; |
| 235 dart_handler_found = true; | 183 dart_handler_found = true; |
| 236 if (!builder->FullStacktrace()) { | 184 if (!builder->FullStacktrace()) { |
| (...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 425 } | 373 } |
| 426 } else { | 374 } else { |
| 427 // Get stacktrace field of class Error. | 375 // Get stacktrace field of class Error. |
| 428 const Field& stacktrace_field = | 376 const Field& stacktrace_field = |
| 429 Field::Handle(isolate, LookupStacktraceField(exception)); | 377 Field::Handle(isolate, LookupStacktraceField(exception)); |
| 430 bool full_stacktrace = !stacktrace_field.IsNull(); | 378 bool full_stacktrace = !stacktrace_field.IsNull(); |
| 431 handler_exists = FindExceptionHandler(&handler_pc, | 379 handler_exists = FindExceptionHandler(&handler_pc, |
| 432 &handler_sp, | 380 &handler_sp, |
| 433 &handler_fp, | 381 &handler_fp, |
| 434 &handler_needs_stacktrace); | 382 &handler_needs_stacktrace); |
| 435 Array& func_array = Array::Handle(isolate, Object::empty_array().raw()); | |
| 436 Array& code_array = Array::Handle(isolate, Object::empty_array().raw()); | 383 Array& code_array = Array::Handle(isolate, Object::empty_array().raw()); |
| 437 Array& pc_offset_array = | 384 Array& pc_offset_array = |
| 438 Array::Handle(isolate, Object::empty_array().raw()); | 385 Array::Handle(isolate, Object::empty_array().raw()); |
| 439 if (handler_needs_stacktrace || full_stacktrace) { | 386 if (handler_needs_stacktrace || full_stacktrace) { |
| 440 RegularStacktraceBuilder frame_builder(full_stacktrace); | 387 RegularStacktraceBuilder frame_builder(full_stacktrace); |
| 441 BuildStackTrace(&frame_builder); | 388 BuildStackTrace(&frame_builder); |
| 442 | 389 |
| 443 // Create arrays for function, code and pc_offset triplet of each frame. | 390 // Create arrays for function, code and pc_offset triplet of each frame. |
| 444 func_array = Array::MakeArray(frame_builder.func_list()); | |
| 445 code_array = Array::MakeArray(frame_builder.code_list()); | 391 code_array = Array::MakeArray(frame_builder.code_list()); |
| 446 pc_offset_array = Array::MakeArray(frame_builder.pc_offset_list()); | 392 pc_offset_array = Array::MakeArray(frame_builder.pc_offset_list()); |
| 447 if (!stacktrace_field.IsNull()) { | 393 if (!stacktrace_field.IsNull()) { |
| 448 // This is an error object and we need to capture the full stack trace | 394 // This is an error object and we need to capture the full stack trace |
| 449 // here implicitly, so we set up the stack trace. The stack trace field | 395 // here implicitly, so we set up the stack trace. The stack trace field |
| 450 // is set only once, it is not overriden. | 396 // is set only once, it is not overriden. |
| 451 const Array& catch_func_array = Array::Handle(isolate, | |
| 452 Array::MakeArray(frame_builder.catch_func_list())); | |
| 453 const Array& catch_code_array = Array::Handle(isolate, | 397 const Array& catch_code_array = Array::Handle(isolate, |
| 454 Array::MakeArray(frame_builder.catch_code_list())); | 398 Array::MakeArray(frame_builder.catch_code_list())); |
| 455 const Array& catch_pc_offset_array = Array::Handle(isolate, | 399 const Array& catch_pc_offset_array = Array::Handle(isolate, |
| 456 Array::MakeArray(frame_builder.catch_pc_offset_list())); | 400 Array::MakeArray(frame_builder.catch_pc_offset_list())); |
| 457 stacktrace = Stacktrace::New(func_array, code_array, pc_offset_array); | 401 stacktrace = Stacktrace::New(code_array, pc_offset_array); |
| 458 stacktrace.SetCatchStacktrace(catch_func_array, | 402 stacktrace.SetCatchStacktrace(catch_code_array, |
| 459 catch_code_array, | |
| 460 catch_pc_offset_array); | 403 catch_pc_offset_array); |
| 461 if (exception.GetField(stacktrace_field) == Object::null()) { | 404 if (exception.GetField(stacktrace_field) == Object::null()) { |
| 462 exception.SetField(stacktrace_field, stacktrace); | 405 exception.SetField(stacktrace_field, stacktrace); |
| 463 } | 406 } |
| 464 } // if stacktrace needed. | 407 } // if stacktrace needed. |
| 465 } | 408 } |
| 466 if (existing_stacktrace.IsNull()) { | 409 if (existing_stacktrace.IsNull()) { |
| 467 stacktrace = Stacktrace::New(func_array, code_array, pc_offset_array); | 410 stacktrace = Stacktrace::New(code_array, pc_offset_array); |
| 468 } else { | 411 } else { |
| 469 stacktrace ^= existing_stacktrace.raw(); | 412 stacktrace ^= existing_stacktrace.raw(); |
| 470 if (pc_offset_array.Length() != 0) { | 413 if (pc_offset_array.Length() != 0) { |
| 471 stacktrace.Append(func_array, code_array, pc_offset_array); | 414 stacktrace.Append(code_array, pc_offset_array); |
| 472 } | 415 } |
| 473 // Since we are re throwing and appending to the existing stack trace | 416 // Since we are re throwing and appending to the existing stack trace |
| 474 // we clear out the catch trace collected in the existing stack trace | 417 // we clear out the catch trace collected in the existing stack trace |
| 475 // as that trace will not be valid anymore. | 418 // as that trace will not be valid anymore. |
| 476 stacktrace.SetCatchStacktrace(Object::empty_array(), | 419 stacktrace.SetCatchStacktrace(Object::empty_array(), |
| 477 Object::empty_array(), | |
| 478 Object::empty_array()); | 420 Object::empty_array()); |
| 479 } | 421 } |
| 480 } | 422 } |
| 481 // We expect to find a handler_pc, if the exception is unhandled | 423 // We expect to find a handler_pc, if the exception is unhandled |
| 482 // then we expect to at least have the dart entry frame on the | 424 // then we expect to at least have the dart entry frame on the |
| 483 // stack as Exceptions::Throw should happen only after a dart | 425 // stack as Exceptions::Throw should happen only after a dart |
| 484 // invocation has been done. | 426 // invocation has been done. |
| 485 ASSERT(handler_pc != 0); | 427 ASSERT(handler_pc != 0); |
| 486 | 428 |
| 487 if (FLAG_print_stacktrace_at_throw) { | 429 if (FLAG_print_stacktrace_at_throw) { |
| (...skipping 265 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 753 break; | 695 break; |
| 754 } | 696 } |
| 755 | 697 |
| 756 return DartLibraryCalls::InstanceCreate(library, | 698 return DartLibraryCalls::InstanceCreate(library, |
| 757 *class_name, | 699 *class_name, |
| 758 *constructor_name, | 700 *constructor_name, |
| 759 arguments); | 701 arguments); |
| 760 } | 702 } |
| 761 | 703 |
| 762 } // namespace dart | 704 } // namespace dart |
| OLD | NEW |