| 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 "platform/address_sanitizer.h" | 7 #include "platform/address_sanitizer.h" |
| 8 | 8 |
| 9 #include "vm/dart_api_impl.h" | 9 #include "vm/dart_api_impl.h" |
| 10 #include "vm/dart_entry.h" | 10 #include "vm/dart_entry.h" |
| (...skipping 13 matching lines...) Expand all Loading... |
| 24 | 24 |
| 25 | 25 |
| 26 const char* Exceptions::kCastErrorDstName = "type cast"; | 26 const char* Exceptions::kCastErrorDstName = "type cast"; |
| 27 | 27 |
| 28 | 28 |
| 29 class StacktraceBuilder : public ValueObject { | 29 class StacktraceBuilder : public ValueObject { |
| 30 public: | 30 public: |
| 31 StacktraceBuilder() { } | 31 StacktraceBuilder() { } |
| 32 virtual ~StacktraceBuilder() { } | 32 virtual ~StacktraceBuilder() { } |
| 33 | 33 |
| 34 virtual void AddFrame(const Code& code, | 34 virtual void AddFrame(const Code& code, const Smi& offset) = 0; |
| 35 const Smi& offset, | |
| 36 bool is_catch_frame) = 0; | |
| 37 | |
| 38 virtual bool FullStacktrace() const = 0; | |
| 39 }; | 35 }; |
| 40 | 36 |
| 41 | 37 |
| 42 class RegularStacktraceBuilder : public StacktraceBuilder { | 38 class RegularStacktraceBuilder : public StacktraceBuilder { |
| 43 public: | 39 public: |
| 44 explicit RegularStacktraceBuilder(bool full_stacktrace) | 40 explicit RegularStacktraceBuilder(Isolate* isolate) |
| 45 : code_list_(GrowableObjectArray::Handle(GrowableObjectArray::New())), | 41 : code_list_( |
| 42 GrowableObjectArray::Handle(isolate, GrowableObjectArray::New())), |
| 46 pc_offset_list_( | 43 pc_offset_list_( |
| 47 GrowableObjectArray::Handle(GrowableObjectArray::New())), | 44 GrowableObjectArray::Handle(isolate, GrowableObjectArray::New())) { } |
| 48 catch_code_list_( | |
| 49 full_stacktrace ? | |
| 50 GrowableObjectArray::Handle(GrowableObjectArray::New()) : | |
| 51 GrowableObjectArray::Handle()), | |
| 52 catch_pc_offset_list_( | |
| 53 full_stacktrace ? | |
| 54 GrowableObjectArray::Handle(GrowableObjectArray::New()) : | |
| 55 GrowableObjectArray::Handle()), | |
| 56 full_stacktrace_(full_stacktrace) { } | |
| 57 ~RegularStacktraceBuilder() { } | 45 ~RegularStacktraceBuilder() { } |
| 58 | 46 |
| 59 const GrowableObjectArray& code_list() const { return code_list_; } | 47 const GrowableObjectArray& code_list() const { return code_list_; } |
| 60 const GrowableObjectArray& pc_offset_list() const { return pc_offset_list_; } | 48 const GrowableObjectArray& pc_offset_list() const { return pc_offset_list_; } |
| 61 const GrowableObjectArray& catch_code_list() const { | |
| 62 return catch_code_list_; | |
| 63 } | |
| 64 const GrowableObjectArray& catch_pc_offset_list() const { | |
| 65 return catch_pc_offset_list_; | |
| 66 } | |
| 67 virtual bool FullStacktrace() const { return full_stacktrace_; } | |
| 68 | 49 |
| 69 virtual void AddFrame(const Code& code, | 50 virtual void AddFrame(const Code& code, const Smi& offset) { |
| 70 const Smi& offset, | 51 code_list_.Add(code); |
| 71 bool is_catch_frame) { | 52 pc_offset_list_.Add(offset); |
| 72 if (is_catch_frame) { | |
| 73 catch_code_list_.Add(code); | |
| 74 catch_pc_offset_list_.Add(offset); | |
| 75 } else { | |
| 76 code_list_.Add(code); | |
| 77 pc_offset_list_.Add(offset); | |
| 78 } | |
| 79 } | 53 } |
| 80 | 54 |
| 81 private: | 55 private: |
| 82 const GrowableObjectArray& code_list_; | 56 const GrowableObjectArray& code_list_; |
| 83 const GrowableObjectArray& pc_offset_list_; | 57 const GrowableObjectArray& pc_offset_list_; |
| 84 const GrowableObjectArray& catch_code_list_; | |
| 85 const GrowableObjectArray& catch_pc_offset_list_; | |
| 86 bool full_stacktrace_; | |
| 87 | 58 |
| 88 DISALLOW_COPY_AND_ASSIGN(RegularStacktraceBuilder); | 59 DISALLOW_COPY_AND_ASSIGN(RegularStacktraceBuilder); |
| 89 }; | 60 }; |
| 90 | 61 |
| 91 | 62 |
| 92 class PreallocatedStacktraceBuilder : public StacktraceBuilder { | 63 class PreallocatedStacktraceBuilder : public StacktraceBuilder { |
| 93 public: | 64 public: |
| 94 explicit PreallocatedStacktraceBuilder(const Stacktrace& stacktrace) | 65 explicit PreallocatedStacktraceBuilder(const Stacktrace& stacktrace) |
| 95 : stacktrace_(stacktrace), | 66 : stacktrace_(stacktrace), |
| 96 cur_index_(0) { | 67 cur_index_(0) { |
| 97 ASSERT(stacktrace_.raw() == | 68 ASSERT(stacktrace_.raw() == |
| 98 Isolate::Current()->object_store()->preallocated_stack_trace()); | 69 Isolate::Current()->object_store()->preallocated_stack_trace()); |
| 99 } | 70 } |
| 100 ~PreallocatedStacktraceBuilder() { } | 71 ~PreallocatedStacktraceBuilder() { } |
| 101 | 72 |
| 102 virtual void AddFrame(const Code& code, | 73 virtual void AddFrame(const Code& code, const Smi& offset); |
| 103 const Smi& offset, | |
| 104 bool is_catch_frame); | |
| 105 | |
| 106 virtual bool FullStacktrace() const { return false; } | |
| 107 | 74 |
| 108 private: | 75 private: |
| 109 static const int kNumTopframes = 3; | 76 static const int kNumTopframes = 3; |
| 110 | 77 |
| 111 const Stacktrace& stacktrace_; | 78 const Stacktrace& stacktrace_; |
| 112 intptr_t cur_index_; | 79 intptr_t cur_index_; |
| 113 | 80 |
| 114 DISALLOW_COPY_AND_ASSIGN(PreallocatedStacktraceBuilder); | 81 DISALLOW_COPY_AND_ASSIGN(PreallocatedStacktraceBuilder); |
| 115 }; | 82 }; |
| 116 | 83 |
| 117 | 84 |
| 118 void PreallocatedStacktraceBuilder::AddFrame(const Code& code, | 85 void PreallocatedStacktraceBuilder::AddFrame(const Code& code, |
| 119 const Smi& offset, | 86 const Smi& offset) { |
| 120 bool is_catch_frame) { | |
| 121 if (cur_index_ >= Stacktrace::kPreallocatedStackdepth) { | 87 if (cur_index_ >= Stacktrace::kPreallocatedStackdepth) { |
| 122 // The number of frames is overflowing the preallocated stack trace object. | 88 // The number of frames is overflowing the preallocated stack trace object. |
| 123 Code& frame_code = Code::Handle(); | 89 Code& frame_code = Code::Handle(); |
| 124 Smi& frame_offset = Smi::Handle(); | 90 Smi& frame_offset = Smi::Handle(); |
| 125 intptr_t start = Stacktrace::kPreallocatedStackdepth - (kNumTopframes - 1); | 91 intptr_t start = Stacktrace::kPreallocatedStackdepth - (kNumTopframes - 1); |
| 126 intptr_t null_slot = start - 2; | 92 intptr_t null_slot = start - 2; |
| 127 // Add an empty slot to indicate the overflow so that the toString | 93 // Add an empty slot to indicate the overflow so that the toString |
| 128 // method can account for the overflow. | 94 // method can account for the overflow. |
| 129 if (stacktrace_.FunctionAtFrame(null_slot) != Function::null()) { | 95 if (stacktrace_.FunctionAtFrame(null_slot) != Function::null()) { |
| 130 stacktrace_.SetCodeAtFrame(null_slot, frame_code); | 96 stacktrace_.SetCodeAtFrame(null_slot, frame_code); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 144 cur_index_ += 1; | 110 cur_index_ += 1; |
| 145 } | 111 } |
| 146 | 112 |
| 147 | 113 |
| 148 static void BuildStackTrace(Isolate* isolate, StacktraceBuilder* builder) { | 114 static void BuildStackTrace(Isolate* isolate, StacktraceBuilder* builder) { |
| 149 StackFrameIterator frames(StackFrameIterator::kDontValidateFrames); | 115 StackFrameIterator frames(StackFrameIterator::kDontValidateFrames); |
| 150 StackFrame* frame = frames.NextFrame(); | 116 StackFrame* frame = frames.NextFrame(); |
| 151 ASSERT(frame != NULL); // We expect to find a dart invocation frame. | 117 ASSERT(frame != NULL); // We expect to find a dart invocation frame. |
| 152 Code& code = Code::Handle(); | 118 Code& code = Code::Handle(); |
| 153 Smi& offset = Smi::Handle(); | 119 Smi& offset = Smi::Handle(); |
| 154 bool dart_handler_found = false; | |
| 155 bool handler_pc_set = false; | |
| 156 while (frame != NULL) { | 120 while (frame != NULL) { |
| 157 while (!frame->IsEntryFrame()) { | 121 if (frame->IsDartFrame()) { |
| 158 if (frame->IsDartFrame()) { | 122 code = frame->LookupDartCode(); |
| 159 code = frame->LookupDartCode(); | 123 offset = Smi::New(frame->pc() - code.EntryPoint()); |
| 160 offset = Smi::New(frame->pc() - code.EntryPoint()); | 124 builder->AddFrame(code, offset); |
| 161 builder->AddFrame(code, offset, dart_handler_found); | |
| 162 bool needs_stacktrace = false; | |
| 163 bool is_catch_all = false; | |
| 164 uword handler_pc = kUwordMax; | |
| 165 if (!handler_pc_set && | |
| 166 frame->FindExceptionHandler(isolate, | |
| 167 &handler_pc, | |
| 168 &needs_stacktrace, | |
| 169 &is_catch_all)) { | |
| 170 handler_pc_set = true; | |
| 171 dart_handler_found = true; | |
| 172 if (!builder->FullStacktrace()) { | |
| 173 return; | |
| 174 } | |
| 175 } | |
| 176 } | |
| 177 frame = frames.NextFrame(); | |
| 178 ASSERT(frame != NULL); | |
| 179 } | |
| 180 ASSERT(frame->IsEntryFrame()); | |
| 181 if (!handler_pc_set) { | |
| 182 handler_pc_set = true; | |
| 183 if (!builder->FullStacktrace()) { | |
| 184 return; | |
| 185 } | |
| 186 } | 125 } |
| 187 frame = frames.NextFrame(); | 126 frame = frames.NextFrame(); |
| 188 } | 127 } |
| 189 } | 128 } |
| 190 | 129 |
| 191 | 130 |
| 192 // Iterate through the stack frames and try to find a frame with an | 131 // Iterate through the stack frames and try to find a frame with an |
| 193 // exception handler. Once found, set the pc, sp and fp so that execution | 132 // exception handler. Once found, set the pc, sp and fp so that execution |
| 194 // can continue in that frame. Sets 'needs_stacktrace' if there is no | 133 // can continue in that frame. Sets 'needs_stacktrace' if there is no |
| 195 // cath-all handler or if a stack-trace is specified in the catch. | 134 // cath-all handler or if a stack-trace is specified in the catch. |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 332 if (type.IsNull()) return Field::null(); | 271 if (type.IsNull()) return Field::null(); |
| 333 test_class = type.type_class(); | 272 test_class = type.type_class(); |
| 334 } | 273 } |
| 335 UNREACHABLE(); | 274 UNREACHABLE(); |
| 336 return Field::null(); | 275 return Field::null(); |
| 337 } | 276 } |
| 338 | 277 |
| 339 | 278 |
| 340 RawStacktrace* Exceptions::CurrentStacktrace() { | 279 RawStacktrace* Exceptions::CurrentStacktrace() { |
| 341 Isolate* isolate = Isolate::Current(); | 280 Isolate* isolate = Isolate::Current(); |
| 342 RegularStacktraceBuilder frame_builder(true); | 281 RegularStacktraceBuilder frame_builder(isolate); |
| 343 BuildStackTrace(isolate, &frame_builder); | 282 BuildStackTrace(isolate, &frame_builder); |
| 344 | 283 |
| 345 // Create arrays for code and pc_offset tuples of each frame. | 284 // Create arrays for code and pc_offset tuples of each frame. |
| 346 const Array& full_code_array = Array::Handle(isolate, | 285 const Array& full_code_array = Array::Handle(isolate, |
| 347 Array::MakeArray(frame_builder.code_list())); | 286 Array::MakeArray(frame_builder.code_list())); |
| 348 const Array& full_pc_offset_array = Array::Handle(isolate, | 287 const Array& full_pc_offset_array = Array::Handle(isolate, |
| 349 Array::MakeArray(frame_builder.pc_offset_list())); | 288 Array::MakeArray(frame_builder.pc_offset_list())); |
| 350 const Array& full_catch_code_array = Array::Handle(isolate, | |
| 351 Array::MakeArray(frame_builder.catch_code_list())); | |
| 352 const Array& full_catch_pc_offset_array = Array::Handle(isolate, | |
| 353 Array::MakeArray(frame_builder.catch_pc_offset_list())); | |
| 354 const Stacktrace& full_stacktrace = Stacktrace::Handle( | 289 const Stacktrace& full_stacktrace = Stacktrace::Handle( |
| 355 Stacktrace::New(full_code_array, full_pc_offset_array)); | 290 Stacktrace::New(full_code_array, full_pc_offset_array)); |
| 356 full_stacktrace.SetCatchStacktrace(full_catch_code_array, | |
| 357 full_catch_pc_offset_array); | |
| 358 return full_stacktrace.raw(); | 291 return full_stacktrace.raw(); |
| 359 } | 292 } |
| 360 | 293 |
| 361 | 294 |
| 362 static void ThrowExceptionHelper(Isolate* isolate, | 295 static void ThrowExceptionHelper(Isolate* isolate, |
| 363 const Instance& incoming_exception, | 296 const Instance& incoming_exception, |
| 364 const Stacktrace& existing_stacktrace, | 297 const Stacktrace& existing_stacktrace, |
| 365 const bool is_rethrow) { | 298 const bool is_rethrow) { |
| 366 bool use_preallocated_stacktrace = false; | 299 bool use_preallocated_stacktrace = false; |
| 367 Instance& exception = Instance::Handle(isolate, incoming_exception.raw()); | 300 Instance& exception = Instance::Handle(isolate, incoming_exception.raw()); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 383 PreallocatedStacktraceBuilder frame_builder(stacktrace); | 316 PreallocatedStacktraceBuilder frame_builder(stacktrace); |
| 384 handler_exists = FindExceptionHandler(isolate, | 317 handler_exists = FindExceptionHandler(isolate, |
| 385 &handler_pc, | 318 &handler_pc, |
| 386 &handler_sp, | 319 &handler_sp, |
| 387 &handler_fp, | 320 &handler_fp, |
| 388 &handler_needs_stacktrace); | 321 &handler_needs_stacktrace); |
| 389 if (handler_needs_stacktrace) { | 322 if (handler_needs_stacktrace) { |
| 390 BuildStackTrace(isolate, &frame_builder); | 323 BuildStackTrace(isolate, &frame_builder); |
| 391 } | 324 } |
| 392 } else { | 325 } else { |
| 393 // Get stacktrace field of class Error. | 326 // Get stacktrace field of class Error. This is needed to determine whether |
| 327 // we have a subclass of Error which carries around its stack trace. |
| 394 const Field& stacktrace_field = | 328 const Field& stacktrace_field = |
| 395 Field::Handle(isolate, LookupStacktraceField(exception)); | 329 Field::Handle(isolate, LookupStacktraceField(exception)); |
| 330 |
| 331 // Find the exception handler and determine if the handler needs a |
| 332 // stacktrace. |
| 396 handler_exists = FindExceptionHandler(isolate, | 333 handler_exists = FindExceptionHandler(isolate, |
| 397 &handler_pc, | 334 &handler_pc, |
| 398 &handler_sp, | 335 &handler_sp, |
| 399 &handler_fp, | 336 &handler_fp, |
| 400 &handler_needs_stacktrace); | 337 &handler_needs_stacktrace); |
| 401 if (!stacktrace_field.IsNull() || handler_needs_stacktrace) { | 338 if (!existing_stacktrace.IsNull()) { |
| 402 Array& code_array = Array::Handle(isolate, Object::empty_array().raw()); | 339 // If we have an existing stack trace then this better be a rethrow. The |
| 403 Array& pc_offset_array = | 340 // reverse is not necessarily true (e.g. Dart_PropagateError can cause |
| 404 Array::Handle(isolate, Object::empty_array().raw()); | 341 // a rethrow being called without an existing stacktrace.) |
| 405 // If we have an error with a stacktrace field then collect the full stack | 342 ASSERT(is_rethrow); |
| 406 // trace and store it into the field. | 343 ASSERT(stacktrace_field.IsNull() || |
| 407 if (!stacktrace_field.IsNull()) { | 344 (exception.GetField(stacktrace_field) != Object::null())); |
| 408 if (exception.GetField(stacktrace_field) == Object::null()) { | 345 stacktrace = existing_stacktrace.raw(); |
| 409 // This is an error object and we need to capture the full stack trace | 346 } else if (!stacktrace_field.IsNull() || handler_needs_stacktrace) { |
| 410 // here implicitly, so we set up the stack trace. The stack trace | 347 // Collect the stacktrace if needed. |
| 411 // field is set only once, it is not overriden. | 348 ASSERT(existing_stacktrace.IsNull()); |
| 412 const Stacktrace& full_stacktrace = | 349 stacktrace = Exceptions::CurrentStacktrace(); |
| 413 Stacktrace::Handle(isolate, Exceptions::CurrentStacktrace()); | 350 // If we have an Error object, then set its stackTrace field only if it |
| 414 exception.SetField(stacktrace_field, full_stacktrace); | 351 // not yet initialized. |
| 415 } | 352 if (!stacktrace_field.IsNull() && |
| 416 } | 353 (exception.GetField(stacktrace_field) == Object::null())) { |
| 417 if (handler_needs_stacktrace) { | 354 exception.SetField(stacktrace_field, stacktrace); |
| 418 RegularStacktraceBuilder frame_builder(false); | |
| 419 BuildStackTrace(isolate, &frame_builder); | |
| 420 | |
| 421 // Create arrays for code and pc_offset tuples of each frame. | |
| 422 code_array = Array::MakeArray(frame_builder.code_list()); | |
| 423 pc_offset_array = Array::MakeArray(frame_builder.pc_offset_list()); | |
| 424 } | |
| 425 if (existing_stacktrace.IsNull()) { | |
| 426 stacktrace = Stacktrace::New(code_array, pc_offset_array); | |
| 427 } else { | |
| 428 ASSERT(is_rethrow); | |
| 429 stacktrace = existing_stacktrace.raw(); | |
| 430 if (pc_offset_array.Length() != 0) { | |
| 431 // Skip the first frame during a rethrow. This is the catch clause | |
| 432 // with the rethrow statement, which is not part of the original | |
| 433 // trace a rethrow is supposed to preserve. | |
| 434 stacktrace.Append(code_array, pc_offset_array, 1); | |
| 435 } | |
| 436 // Since we are re throwing and appending to the existing stack trace | |
| 437 // we clear out the catch trace collected in the existing stack trace | |
| 438 // as that trace will not be valid anymore. | |
| 439 stacktrace.SetCatchStacktrace(Object::empty_array(), | |
| 440 Object::empty_array()); | |
| 441 } | 355 } |
| 442 } | 356 } |
| 443 } | 357 } |
| 444 // We expect to find a handler_pc, if the exception is unhandled | 358 // We expect to find a handler_pc, if the exception is unhandled |
| 445 // then we expect to at least have the dart entry frame on the | 359 // then we expect to at least have the dart entry frame on the |
| 446 // stack as Exceptions::Throw should happen only after a dart | 360 // stack as Exceptions::Throw should happen only after a dart |
| 447 // invocation has been done. | 361 // invocation has been done. |
| 448 ASSERT(handler_pc != 0); | 362 ASSERT(handler_pc != 0); |
| 449 | 363 |
| 450 if (FLAG_print_stacktrace_at_throw) { | 364 if (FLAG_print_stacktrace_at_throw) { |
| (...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 754 | 668 |
| 755 // Throw JavascriptCompatibilityError exception. | 669 // Throw JavascriptCompatibilityError exception. |
| 756 void Exceptions::ThrowJavascriptCompatibilityError(const char* msg) { | 670 void Exceptions::ThrowJavascriptCompatibilityError(const char* msg) { |
| 757 const Array& exc_args = Array::Handle(Array::New(1)); | 671 const Array& exc_args = Array::Handle(Array::New(1)); |
| 758 const String& msg_str = String::Handle(String::New(msg)); | 672 const String& msg_str = String::Handle(String::New(msg)); |
| 759 exc_args.SetAt(0, msg_str); | 673 exc_args.SetAt(0, msg_str); |
| 760 Exceptions::ThrowByType(Exceptions::kJavascriptCompatibilityError, exc_args); | 674 Exceptions::ThrowByType(Exceptions::kJavascriptCompatibilityError, exc_args); |
| 761 } | 675 } |
| 762 | 676 |
| 763 } // namespace dart | 677 } // namespace dart |
| OLD | NEW |