| 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 "lib/stacktrace.h" | 9 #include "lib/stacktrace.h" |
| 10 | 10 |
| 11 #include "vm/dart_api_impl.h" | 11 #include "vm/dart_api_impl.h" |
| 12 #include "vm/dart_entry.h" | 12 #include "vm/dart_entry.h" |
| 13 #include "vm/datastream.h" | 13 #include "vm/datastream.h" |
| 14 #include "vm/debugger.h" | 14 #include "vm/debugger.h" |
| 15 #include "vm/deopt_instructions.h" | 15 #include "vm/deopt_instructions.h" |
| 16 #include "vm/flags.h" | 16 #include "vm/flags.h" |
| 17 #include "vm/log.h" | 17 #include "vm/log.h" |
| 18 #include "vm/longjump.h" | 18 #include "vm/longjump.h" |
| 19 #include "vm/object.h" | 19 #include "vm/object.h" |
| 20 #include "vm/object_store.h" | 20 #include "vm/object_store.h" |
| 21 #include "vm/stack_frame.h" | 21 #include "vm/stack_frame.h" |
| 22 #include "vm/stub_code.h" | 22 #include "vm/stub_code.h" |
| 23 #include "vm/symbols.h" | 23 #include "vm/symbols.h" |
| 24 #include "vm/tags.h" | 24 #include "vm/tags.h" |
| 25 | 25 |
| 26 | |
| 27 namespace dart { | 26 namespace dart { |
| 28 | 27 |
| 29 DECLARE_FLAG(bool, trace_deoptimization); | 28 DECLARE_FLAG(bool, trace_deoptimization); |
| 30 DEFINE_FLAG(bool, | 29 DEFINE_FLAG(bool, |
| 31 print_stacktrace_at_throw, | 30 print_stacktrace_at_throw, |
| 32 false, | 31 false, |
| 33 "Prints a stack trace everytime a throw occurs."); | 32 "Prints a stack trace everytime a throw occurs."); |
| 34 | 33 |
| 35 | |
| 36 class StackTraceBuilder : public ValueObject { | 34 class StackTraceBuilder : public ValueObject { |
| 37 public: | 35 public: |
| 38 StackTraceBuilder() {} | 36 StackTraceBuilder() {} |
| 39 virtual ~StackTraceBuilder() {} | 37 virtual ~StackTraceBuilder() {} |
| 40 | 38 |
| 41 virtual void AddFrame(const Code& code, const Smi& offset) = 0; | 39 virtual void AddFrame(const Code& code, const Smi& offset) = 0; |
| 42 }; | 40 }; |
| 43 | 41 |
| 44 | |
| 45 class RegularStackTraceBuilder : public StackTraceBuilder { | 42 class RegularStackTraceBuilder : public StackTraceBuilder { |
| 46 public: | 43 public: |
| 47 explicit RegularStackTraceBuilder(Zone* zone) | 44 explicit RegularStackTraceBuilder(Zone* zone) |
| 48 : code_list_( | 45 : code_list_( |
| 49 GrowableObjectArray::Handle(zone, GrowableObjectArray::New())), | 46 GrowableObjectArray::Handle(zone, GrowableObjectArray::New())), |
| 50 pc_offset_list_( | 47 pc_offset_list_( |
| 51 GrowableObjectArray::Handle(zone, GrowableObjectArray::New())) {} | 48 GrowableObjectArray::Handle(zone, GrowableObjectArray::New())) {} |
| 52 ~RegularStackTraceBuilder() {} | 49 ~RegularStackTraceBuilder() {} |
| 53 | 50 |
| 54 const GrowableObjectArray& code_list() const { return code_list_; } | 51 const GrowableObjectArray& code_list() const { return code_list_; } |
| 55 const GrowableObjectArray& pc_offset_list() const { return pc_offset_list_; } | 52 const GrowableObjectArray& pc_offset_list() const { return pc_offset_list_; } |
| 56 | 53 |
| 57 virtual void AddFrame(const Code& code, const Smi& offset) { | 54 virtual void AddFrame(const Code& code, const Smi& offset) { |
| 58 code_list_.Add(code); | 55 code_list_.Add(code); |
| 59 pc_offset_list_.Add(offset); | 56 pc_offset_list_.Add(offset); |
| 60 } | 57 } |
| 61 | 58 |
| 62 private: | 59 private: |
| 63 const GrowableObjectArray& code_list_; | 60 const GrowableObjectArray& code_list_; |
| 64 const GrowableObjectArray& pc_offset_list_; | 61 const GrowableObjectArray& pc_offset_list_; |
| 65 | 62 |
| 66 DISALLOW_COPY_AND_ASSIGN(RegularStackTraceBuilder); | 63 DISALLOW_COPY_AND_ASSIGN(RegularStackTraceBuilder); |
| 67 }; | 64 }; |
| 68 | 65 |
| 69 | |
| 70 class PreallocatedStackTraceBuilder : public StackTraceBuilder { | 66 class PreallocatedStackTraceBuilder : public StackTraceBuilder { |
| 71 public: | 67 public: |
| 72 explicit PreallocatedStackTraceBuilder(const Instance& stacktrace) | 68 explicit PreallocatedStackTraceBuilder(const Instance& stacktrace) |
| 73 : stacktrace_(StackTrace::Cast(stacktrace)), | 69 : stacktrace_(StackTrace::Cast(stacktrace)), |
| 74 cur_index_(0), | 70 cur_index_(0), |
| 75 dropped_frames_(0) { | 71 dropped_frames_(0) { |
| 76 ASSERT(stacktrace_.raw() == | 72 ASSERT(stacktrace_.raw() == |
| 77 Isolate::Current()->object_store()->preallocated_stack_trace()); | 73 Isolate::Current()->object_store()->preallocated_stack_trace()); |
| 78 } | 74 } |
| 79 ~PreallocatedStackTraceBuilder() {} | 75 ~PreallocatedStackTraceBuilder() {} |
| 80 | 76 |
| 81 virtual void AddFrame(const Code& code, const Smi& offset); | 77 virtual void AddFrame(const Code& code, const Smi& offset); |
| 82 | 78 |
| 83 private: | 79 private: |
| 84 static const int kNumTopframes = StackTrace::kPreallocatedStackdepth / 2; | 80 static const int kNumTopframes = StackTrace::kPreallocatedStackdepth / 2; |
| 85 | 81 |
| 86 const StackTrace& stacktrace_; | 82 const StackTrace& stacktrace_; |
| 87 intptr_t cur_index_; | 83 intptr_t cur_index_; |
| 88 intptr_t dropped_frames_; | 84 intptr_t dropped_frames_; |
| 89 | 85 |
| 90 DISALLOW_COPY_AND_ASSIGN(PreallocatedStackTraceBuilder); | 86 DISALLOW_COPY_AND_ASSIGN(PreallocatedStackTraceBuilder); |
| 91 }; | 87 }; |
| 92 | 88 |
| 93 | |
| 94 void PreallocatedStackTraceBuilder::AddFrame(const Code& code, | 89 void PreallocatedStackTraceBuilder::AddFrame(const Code& code, |
| 95 const Smi& offset) { | 90 const Smi& offset) { |
| 96 if (cur_index_ >= StackTrace::kPreallocatedStackdepth) { | 91 if (cur_index_ >= StackTrace::kPreallocatedStackdepth) { |
| 97 // The number of frames is overflowing the preallocated stack trace object. | 92 // The number of frames is overflowing the preallocated stack trace object. |
| 98 Code& frame_code = Code::Handle(); | 93 Code& frame_code = Code::Handle(); |
| 99 Smi& frame_offset = Smi::Handle(); | 94 Smi& frame_offset = Smi::Handle(); |
| 100 intptr_t start = StackTrace::kPreallocatedStackdepth - (kNumTopframes - 1); | 95 intptr_t start = StackTrace::kPreallocatedStackdepth - (kNumTopframes - 1); |
| 101 intptr_t null_slot = start - 2; | 96 intptr_t null_slot = start - 2; |
| 102 // We are going to drop one frame. | 97 // We are going to drop one frame. |
| 103 dropped_frames_++; | 98 dropped_frames_++; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 119 stacktrace_.SetCodeAtFrame(prev, frame_code); | 114 stacktrace_.SetCodeAtFrame(prev, frame_code); |
| 120 stacktrace_.SetPcOffsetAtFrame(prev, frame_offset); | 115 stacktrace_.SetPcOffsetAtFrame(prev, frame_offset); |
| 121 } | 116 } |
| 122 cur_index_ = (StackTrace::kPreallocatedStackdepth - 1); | 117 cur_index_ = (StackTrace::kPreallocatedStackdepth - 1); |
| 123 } | 118 } |
| 124 stacktrace_.SetCodeAtFrame(cur_index_, code); | 119 stacktrace_.SetCodeAtFrame(cur_index_, code); |
| 125 stacktrace_.SetPcOffsetAtFrame(cur_index_, offset); | 120 stacktrace_.SetPcOffsetAtFrame(cur_index_, offset); |
| 126 cur_index_ += 1; | 121 cur_index_ += 1; |
| 127 } | 122 } |
| 128 | 123 |
| 129 | |
| 130 static void BuildStackTrace(StackTraceBuilder* builder) { | 124 static void BuildStackTrace(StackTraceBuilder* builder) { |
| 131 StackFrameIterator frames(StackFrameIterator::kDontValidateFrames, | 125 StackFrameIterator frames(StackFrameIterator::kDontValidateFrames, |
| 132 Thread::Current(), | 126 Thread::Current(), |
| 133 StackFrameIterator::kNoCrossThreadIteration); | 127 StackFrameIterator::kNoCrossThreadIteration); |
| 134 StackFrame* frame = frames.NextFrame(); | 128 StackFrame* frame = frames.NextFrame(); |
| 135 ASSERT(frame != NULL); // We expect to find a dart invocation frame. | 129 ASSERT(frame != NULL); // We expect to find a dart invocation frame. |
| 136 Code& code = Code::Handle(); | 130 Code& code = Code::Handle(); |
| 137 Smi& offset = Smi::Handle(); | 131 Smi& offset = Smi::Handle(); |
| 138 while (frame != NULL) { | 132 while (frame != NULL) { |
| 139 if (frame->IsDartFrame()) { | 133 if (frame->IsDartFrame()) { |
| 140 code = frame->LookupDartCode(); | 134 code = frame->LookupDartCode(); |
| 141 ASSERT(code.ContainsInstructionAt(frame->pc())); | 135 ASSERT(code.ContainsInstructionAt(frame->pc())); |
| 142 offset = Smi::New(frame->pc() - code.PayloadStart()); | 136 offset = Smi::New(frame->pc() - code.PayloadStart()); |
| 143 builder->AddFrame(code, offset); | 137 builder->AddFrame(code, offset); |
| 144 } | 138 } |
| 145 frame = frames.NextFrame(); | 139 frame = frames.NextFrame(); |
| 146 } | 140 } |
| 147 } | 141 } |
| 148 | 142 |
| 149 | |
| 150 static RawObject** VariableAt(uword fp, int stack_slot) { | 143 static RawObject** VariableAt(uword fp, int stack_slot) { |
| 151 #if defined(TARGET_ARCH_DBC) | 144 #if defined(TARGET_ARCH_DBC) |
| 152 return reinterpret_cast<RawObject**>(fp + stack_slot * kWordSize); | 145 return reinterpret_cast<RawObject**>(fp + stack_slot * kWordSize); |
| 153 #else | 146 #else |
| 154 if (stack_slot < 0) { | 147 if (stack_slot < 0) { |
| 155 return reinterpret_cast<RawObject**>(ParamAddress(fp, -stack_slot)); | 148 return reinterpret_cast<RawObject**>(ParamAddress(fp, -stack_slot)); |
| 156 } else { | 149 } else { |
| 157 return reinterpret_cast<RawObject**>( | 150 return reinterpret_cast<RawObject**>( |
| 158 LocalVarAddress(fp, kFirstLocalSlotFromFp - stack_slot)); | 151 LocalVarAddress(fp, kFirstLocalSlotFromFp - stack_slot)); |
| 159 } | 152 } |
| 160 #endif | 153 #endif |
| 161 } | 154 } |
| 162 | 155 |
| 163 | |
| 164 class ExceptionHandlerFinder : public StackResource { | 156 class ExceptionHandlerFinder : public StackResource { |
| 165 public: | 157 public: |
| 166 explicit ExceptionHandlerFinder(Thread* thread) | 158 explicit ExceptionHandlerFinder(Thread* thread) |
| 167 : StackResource(thread), thread_(thread), cache_(NULL), metadata_(NULL) {} | 159 : StackResource(thread), thread_(thread), cache_(NULL), metadata_(NULL) {} |
| 168 | 160 |
| 169 // Iterate through the stack frames and try to find a frame with an | 161 // Iterate through the stack frames and try to find a frame with an |
| 170 // exception handler. Once found, set the pc, sp and fp so that execution | 162 // exception handler. Once found, set the pc, sp and fp so that execution |
| 171 // can continue in that frame. Sets 'needs_stacktrace' if there is no | 163 // can continue in that frame. Sets 'needs_stacktrace' if there is no |
| 172 // cath-all handler or if a stack-trace is specified in the catch. | 164 // cath-all handler or if a stack-trace is specified in the catch. |
| 173 bool Find() { | 165 bool Find() { |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 340 typedef ReadStream::Raw<sizeof(intptr_t), intptr_t> Reader; | 332 typedef ReadStream::Raw<sizeof(intptr_t), intptr_t> Reader; |
| 341 Thread* thread_; | 333 Thread* thread_; |
| 342 CatchEntryStateCache* cache_; | 334 CatchEntryStateCache* cache_; |
| 343 Code* code_; | 335 Code* code_; |
| 344 bool handler_pc_set_; | 336 bool handler_pc_set_; |
| 345 intptr_t* metadata_; // MetaData generated from deopt. | 337 intptr_t* metadata_; // MetaData generated from deopt. |
| 346 CatchEntryState cached_; // Value of per PC MetaData cache. | 338 CatchEntryState cached_; // Value of per PC MetaData cache. |
| 347 intptr_t pc_; // Current pc in the handler frame. | 339 intptr_t pc_; // Current pc in the handler frame. |
| 348 }; | 340 }; |
| 349 | 341 |
| 350 | |
| 351 static void FindErrorHandler(uword* handler_pc, | 342 static void FindErrorHandler(uword* handler_pc, |
| 352 uword* handler_sp, | 343 uword* handler_sp, |
| 353 uword* handler_fp) { | 344 uword* handler_fp) { |
| 354 StackFrameIterator frames(StackFrameIterator::kDontValidateFrames, | 345 StackFrameIterator frames(StackFrameIterator::kDontValidateFrames, |
| 355 Thread::Current(), | 346 Thread::Current(), |
| 356 StackFrameIterator::kNoCrossThreadIteration); | 347 StackFrameIterator::kNoCrossThreadIteration); |
| 357 StackFrame* frame = frames.NextFrame(); | 348 StackFrame* frame = frames.NextFrame(); |
| 358 ASSERT(frame != NULL); | 349 ASSERT(frame != NULL); |
| 359 while (!frame->IsEntryFrame()) { | 350 while (!frame->IsEntryFrame()) { |
| 360 frame = frames.NextFrame(); | 351 frame = frames.NextFrame(); |
| 361 ASSERT(frame != NULL); | 352 ASSERT(frame != NULL); |
| 362 } | 353 } |
| 363 ASSERT(frame->IsEntryFrame()); | 354 ASSERT(frame->IsEntryFrame()); |
| 364 *handler_pc = frame->pc(); | 355 *handler_pc = frame->pc(); |
| 365 *handler_sp = frame->sp(); | 356 *handler_sp = frame->sp(); |
| 366 *handler_fp = frame->fp(); | 357 *handler_fp = frame->fp(); |
| 367 } | 358 } |
| 368 | 359 |
| 369 | |
| 370 static uword RemapExceptionPCForDeopt(Thread* thread, | 360 static uword RemapExceptionPCForDeopt(Thread* thread, |
| 371 uword program_counter, | 361 uword program_counter, |
| 372 uword frame_pointer) { | 362 uword frame_pointer) { |
| 373 #if !defined(TARGET_ARCH_DBC) | 363 #if !defined(TARGET_ARCH_DBC) |
| 374 MallocGrowableArray<PendingLazyDeopt>* pending_deopts = | 364 MallocGrowableArray<PendingLazyDeopt>* pending_deopts = |
| 375 thread->isolate()->pending_deopts(); | 365 thread->isolate()->pending_deopts(); |
| 376 if (pending_deopts->length() > 0) { | 366 if (pending_deopts->length() > 0) { |
| 377 // Check if the target frame is scheduled for lazy deopt. | 367 // Check if the target frame is scheduled for lazy deopt. |
| 378 for (intptr_t i = 0; i < pending_deopts->length(); i++) { | 368 for (intptr_t i = 0; i < pending_deopts->length(); i++) { |
| 379 if ((*pending_deopts)[i].fp() == frame_pointer) { | 369 if ((*pending_deopts)[i].fp() == frame_pointer) { |
| 380 // Deopt should now resume in the catch handler instead of after the | 370 // Deopt should now resume in the catch handler instead of after the |
| 381 // call. | 371 // call. |
| 382 (*pending_deopts)[i].set_pc(program_counter); | 372 (*pending_deopts)[i].set_pc(program_counter); |
| 383 | 373 |
| 384 // Jump to the deopt stub instead of the catch handler. | 374 // Jump to the deopt stub instead of the catch handler. |
| 385 program_counter = | 375 program_counter = |
| 386 StubCode::DeoptimizeLazyFromThrow_entry()->EntryPoint(); | 376 StubCode::DeoptimizeLazyFromThrow_entry()->EntryPoint(); |
| 387 if (FLAG_trace_deoptimization) { | 377 if (FLAG_trace_deoptimization) { |
| 388 THR_Print("Throwing to frame scheduled for lazy deopt fp=%" Pp "\n", | 378 THR_Print("Throwing to frame scheduled for lazy deopt fp=%" Pp "\n", |
| 389 frame_pointer); | 379 frame_pointer); |
| 390 } | 380 } |
| 391 break; | 381 break; |
| 392 } | 382 } |
| 393 } | 383 } |
| 394 } | 384 } |
| 395 #endif // !DBC | 385 #endif // !DBC |
| 396 return program_counter; | 386 return program_counter; |
| 397 } | 387 } |
| 398 | 388 |
| 399 | |
| 400 static void ClearLazyDeopts(Thread* thread, uword frame_pointer) { | 389 static void ClearLazyDeopts(Thread* thread, uword frame_pointer) { |
| 401 #if !defined(TARGET_ARCH_DBC) | 390 #if !defined(TARGET_ARCH_DBC) |
| 402 MallocGrowableArray<PendingLazyDeopt>* pending_deopts = | 391 MallocGrowableArray<PendingLazyDeopt>* pending_deopts = |
| 403 thread->isolate()->pending_deopts(); | 392 thread->isolate()->pending_deopts(); |
| 404 if (pending_deopts->length() > 0) { | 393 if (pending_deopts->length() > 0) { |
| 405 // We may be jumping over frames scheduled for lazy deopt. Remove these | 394 // We may be jumping over frames scheduled for lazy deopt. Remove these |
| 406 // frames from the pending deopt table, but only after unmarking them so | 395 // frames from the pending deopt table, but only after unmarking them so |
| 407 // any stack walk that happens before the stack is unwound will still work. | 396 // any stack walk that happens before the stack is unwound will still work. |
| 408 { | 397 { |
| 409 DartFrameIterator frames(thread, | 398 DartFrameIterator frames(thread, |
| (...skipping 23 matching lines...) Expand all Loading... |
| 433 } | 422 } |
| 434 } | 423 } |
| 435 | 424 |
| 436 #if defined(DEBUG) | 425 #if defined(DEBUG) |
| 437 ValidateFrames(); | 426 ValidateFrames(); |
| 438 #endif | 427 #endif |
| 439 } | 428 } |
| 440 #endif // !DBC | 429 #endif // !DBC |
| 441 } | 430 } |
| 442 | 431 |
| 443 | |
| 444 static void JumpToExceptionHandler(Thread* thread, | 432 static void JumpToExceptionHandler(Thread* thread, |
| 445 uword program_counter, | 433 uword program_counter, |
| 446 uword stack_pointer, | 434 uword stack_pointer, |
| 447 uword frame_pointer, | 435 uword frame_pointer, |
| 448 const Object& exception_object, | 436 const Object& exception_object, |
| 449 const Object& stacktrace_object) { | 437 const Object& stacktrace_object) { |
| 450 uword remapped_pc = | 438 uword remapped_pc = |
| 451 RemapExceptionPCForDeopt(thread, program_counter, frame_pointer); | 439 RemapExceptionPCForDeopt(thread, program_counter, frame_pointer); |
| 452 thread->set_active_exception(exception_object); | 440 thread->set_active_exception(exception_object); |
| 453 thread->set_active_stacktrace(stacktrace_object); | 441 thread->set_active_stacktrace(stacktrace_object); |
| 454 thread->set_resume_pc(remapped_pc); | 442 thread->set_resume_pc(remapped_pc); |
| 455 uword run_exception_pc = StubCode::RunExceptionHandler_entry()->EntryPoint(); | 443 uword run_exception_pc = StubCode::RunExceptionHandler_entry()->EntryPoint(); |
| 456 Exceptions::JumpToFrame(thread, run_exception_pc, stack_pointer, | 444 Exceptions::JumpToFrame(thread, run_exception_pc, stack_pointer, |
| 457 frame_pointer, false /* do not clear deopt */); | 445 frame_pointer, false /* do not clear deopt */); |
| 458 } | 446 } |
| 459 | 447 |
| 460 | |
| 461 void Exceptions::JumpToFrame(Thread* thread, | 448 void Exceptions::JumpToFrame(Thread* thread, |
| 462 uword program_counter, | 449 uword program_counter, |
| 463 uword stack_pointer, | 450 uword stack_pointer, |
| 464 uword frame_pointer, | 451 uword frame_pointer, |
| 465 bool clear_deopt_at_target) { | 452 bool clear_deopt_at_target) { |
| 466 uword fp_for_clearing = | 453 uword fp_for_clearing = |
| 467 (clear_deopt_at_target ? frame_pointer + 1 : frame_pointer); | 454 (clear_deopt_at_target ? frame_pointer + 1 : frame_pointer); |
| 468 ClearLazyDeopts(thread, fp_for_clearing); | 455 ClearLazyDeopts(thread, fp_for_clearing); |
| 469 #if defined(USING_SIMULATOR) | 456 #if defined(USING_SIMULATOR) |
| 470 // Unwinding of the C++ frames and destroying of their stack resources is done | 457 // Unwinding of the C++ frames and destroying of their stack resources is done |
| (...skipping 21 matching lines...) Expand all Loading... |
| 492 // Unpoison the stack before we tear it down in the generated stub code. | 479 // Unpoison the stack before we tear it down in the generated stub code. |
| 493 uword current_sp = Thread::GetCurrentStackPointer() - 1024; | 480 uword current_sp = Thread::GetCurrentStackPointer() - 1024; |
| 494 ASAN_UNPOISON(reinterpret_cast<void*>(current_sp), | 481 ASAN_UNPOISON(reinterpret_cast<void*>(current_sp), |
| 495 stack_pointer - current_sp); | 482 stack_pointer - current_sp); |
| 496 | 483 |
| 497 func(program_counter, stack_pointer, frame_pointer, thread); | 484 func(program_counter, stack_pointer, frame_pointer, thread); |
| 498 #endif | 485 #endif |
| 499 UNREACHABLE(); | 486 UNREACHABLE(); |
| 500 } | 487 } |
| 501 | 488 |
| 502 | |
| 503 static RawField* LookupStackTraceField(const Instance& instance) { | 489 static RawField* LookupStackTraceField(const Instance& instance) { |
| 504 if (instance.GetClassId() < kNumPredefinedCids) { | 490 if (instance.GetClassId() < kNumPredefinedCids) { |
| 505 // 'class Error' is not a predefined class. | 491 // 'class Error' is not a predefined class. |
| 506 return Field::null(); | 492 return Field::null(); |
| 507 } | 493 } |
| 508 Thread* thread = Thread::Current(); | 494 Thread* thread = Thread::Current(); |
| 509 Zone* zone = thread->zone(); | 495 Zone* zone = thread->zone(); |
| 510 Isolate* isolate = thread->isolate(); | 496 Isolate* isolate = thread->isolate(); |
| 511 Class& error_class = | 497 Class& error_class = |
| 512 Class::Handle(zone, isolate->object_store()->error_class()); | 498 Class::Handle(zone, isolate->object_store()->error_class()); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 525 Symbols::_stackTrace()); | 511 Symbols::_stackTrace()); |
| 526 } | 512 } |
| 527 type = test_class.super_type(); | 513 type = test_class.super_type(); |
| 528 if (type.IsNull()) return Field::null(); | 514 if (type.IsNull()) return Field::null(); |
| 529 test_class = type.type_class(); | 515 test_class = type.type_class(); |
| 530 } | 516 } |
| 531 UNREACHABLE(); | 517 UNREACHABLE(); |
| 532 return Field::null(); | 518 return Field::null(); |
| 533 } | 519 } |
| 534 | 520 |
| 535 | |
| 536 RawStackTrace* Exceptions::CurrentStackTrace() { | 521 RawStackTrace* Exceptions::CurrentStackTrace() { |
| 537 return GetStackTraceForException(); | 522 return GetStackTraceForException(); |
| 538 } | 523 } |
| 539 | 524 |
| 540 | |
| 541 static void ThrowExceptionHelper(Thread* thread, | 525 static void ThrowExceptionHelper(Thread* thread, |
| 542 const Instance& incoming_exception, | 526 const Instance& incoming_exception, |
| 543 const Instance& existing_stacktrace, | 527 const Instance& existing_stacktrace, |
| 544 const bool is_rethrow) { | 528 const bool is_rethrow) { |
| 545 Zone* zone = thread->zone(); | 529 Zone* zone = thread->zone(); |
| 546 Isolate* isolate = thread->isolate(); | 530 Isolate* isolate = thread->isolate(); |
| 547 bool use_preallocated_stacktrace = false; | 531 bool use_preallocated_stacktrace = false; |
| 548 Instance& exception = Instance::Handle(zone, incoming_exception.raw()); | 532 Instance& exception = Instance::Handle(zone, incoming_exception.raw()); |
| 549 if (exception.IsNull()) { | 533 if (exception.IsNull()) { |
| 550 exception ^= | 534 exception ^= |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 630 // the isolate etc.). | 614 // the isolate etc.). |
| 631 const UnhandledException& unhandled_exception = UnhandledException::Handle( | 615 const UnhandledException& unhandled_exception = UnhandledException::Handle( |
| 632 zone, UnhandledException::New(exception, stacktrace)); | 616 zone, UnhandledException::New(exception, stacktrace)); |
| 633 stacktrace = StackTrace::null(); | 617 stacktrace = StackTrace::null(); |
| 634 JumpToExceptionHandler(thread, handler_pc, handler_sp, handler_fp, | 618 JumpToExceptionHandler(thread, handler_pc, handler_sp, handler_fp, |
| 635 unhandled_exception, stacktrace); | 619 unhandled_exception, stacktrace); |
| 636 } | 620 } |
| 637 UNREACHABLE(); | 621 UNREACHABLE(); |
| 638 } | 622 } |
| 639 | 623 |
| 640 | |
| 641 // Static helpers for allocating, initializing, and throwing an error instance. | 624 // Static helpers for allocating, initializing, and throwing an error instance. |
| 642 | 625 |
| 643 // Return the script of the Dart function that called the native entry or the | 626 // Return the script of the Dart function that called the native entry or the |
| 644 // runtime entry. The frame iterator points to the callee. | 627 // runtime entry. The frame iterator points to the callee. |
| 645 RawScript* Exceptions::GetCallerScript(DartFrameIterator* iterator) { | 628 RawScript* Exceptions::GetCallerScript(DartFrameIterator* iterator) { |
| 646 StackFrame* caller_frame = iterator->NextFrame(); | 629 StackFrame* caller_frame = iterator->NextFrame(); |
| 647 ASSERT(caller_frame != NULL && caller_frame->IsDartFrame()); | 630 ASSERT(caller_frame != NULL && caller_frame->IsDartFrame()); |
| 648 const Function& caller = Function::Handle(caller_frame->LookupDartFunction()); | 631 const Function& caller = Function::Handle(caller_frame->LookupDartFunction()); |
| 649 ASSERT(!caller.IsNull()); | 632 ASSERT(!caller.IsNull()); |
| 650 return caller.script(); | 633 return caller.script(); |
| 651 } | 634 } |
| 652 | 635 |
| 653 | |
| 654 // Allocate a new instance of the given class name. | 636 // Allocate a new instance of the given class name. |
| 655 // TODO(hausner): Rename this NewCoreInstance to call out the fact that | 637 // TODO(hausner): Rename this NewCoreInstance to call out the fact that |
| 656 // the class name is resolved in the core library implicitly? | 638 // the class name is resolved in the core library implicitly? |
| 657 RawInstance* Exceptions::NewInstance(const char* class_name) { | 639 RawInstance* Exceptions::NewInstance(const char* class_name) { |
| 658 Thread* thread = Thread::Current(); | 640 Thread* thread = Thread::Current(); |
| 659 Zone* zone = thread->zone(); | 641 Zone* zone = thread->zone(); |
| 660 const String& cls_name = | 642 const String& cls_name = |
| 661 String::Handle(zone, Symbols::New(thread, class_name)); | 643 String::Handle(zone, Symbols::New(thread, class_name)); |
| 662 const Library& core_lib = Library::Handle(Library::CoreLibrary()); | 644 const Library& core_lib = Library::Handle(Library::CoreLibrary()); |
| 663 // No ambiguity error expected: passing NULL. | 645 // No ambiguity error expected: passing NULL. |
| 664 Class& cls = Class::Handle(core_lib.LookupClass(cls_name)); | 646 Class& cls = Class::Handle(core_lib.LookupClass(cls_name)); |
| 665 ASSERT(!cls.IsNull()); | 647 ASSERT(!cls.IsNull()); |
| 666 // There are no parameterized error types, so no need to set type arguments. | 648 // There are no parameterized error types, so no need to set type arguments. |
| 667 return Instance::New(cls); | 649 return Instance::New(cls); |
| 668 } | 650 } |
| 669 | 651 |
| 670 | |
| 671 // Allocate, initialize, and throw a TypeError or CastError. | 652 // Allocate, initialize, and throw a TypeError or CastError. |
| 672 // If error_msg is not null, throw a TypeError, even for a type cast. | 653 // If error_msg is not null, throw a TypeError, even for a type cast. |
| 673 void Exceptions::CreateAndThrowTypeError(TokenPosition location, | 654 void Exceptions::CreateAndThrowTypeError(TokenPosition location, |
| 674 const AbstractType& src_type, | 655 const AbstractType& src_type, |
| 675 const AbstractType& dst_type, | 656 const AbstractType& dst_type, |
| 676 const String& dst_name, | 657 const String& dst_name, |
| 677 const String& bound_error_msg) { | 658 const String& bound_error_msg) { |
| 678 ASSERT(!dst_name.IsNull()); // Pass Symbols::Empty() instead. | 659 ASSERT(!dst_name.IsNull()); // Pass Symbols::Empty() instead. |
| 679 Thread* thread = Thread::Current(); | 660 Thread* thread = Thread::Current(); |
| 680 Zone* zone = thread->zone(); | 661 Zone* zone = thread->zone(); |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 771 THR_Print("'%s': Failed type check: line %" Pd " pos %" Pd ": ", | 752 THR_Print("'%s': Failed type check: line %" Pd " pos %" Pd ": ", |
| 772 String::Handle(zone, script.url()).ToCString(), line, column); | 753 String::Handle(zone, script.url()).ToCString(), line, column); |
| 773 THR_Print("%s\n", error_msg.ToCString()); | 754 THR_Print("%s\n", error_msg.ToCString()); |
| 774 } | 755 } |
| 775 | 756 |
| 776 // Throw TypeError or CastError instance. | 757 // Throw TypeError or CastError instance. |
| 777 Exceptions::ThrowByType(exception_type, args); | 758 Exceptions::ThrowByType(exception_type, args); |
| 778 UNREACHABLE(); | 759 UNREACHABLE(); |
| 779 } | 760 } |
| 780 | 761 |
| 781 | |
| 782 void Exceptions::Throw(Thread* thread, const Instance& exception) { | 762 void Exceptions::Throw(Thread* thread, const Instance& exception) { |
| 783 // Do not notify debugger on stack overflow and out of memory exceptions. | 763 // Do not notify debugger on stack overflow and out of memory exceptions. |
| 784 // The VM would crash when the debugger calls back into the VM to | 764 // The VM would crash when the debugger calls back into the VM to |
| 785 // get values of variables. | 765 // get values of variables. |
| 786 if (FLAG_support_debugger) { | 766 if (FLAG_support_debugger) { |
| 787 Isolate* isolate = thread->isolate(); | 767 Isolate* isolate = thread->isolate(); |
| 788 if (exception.raw() != isolate->object_store()->out_of_memory() && | 768 if (exception.raw() != isolate->object_store()->out_of_memory() && |
| 789 exception.raw() != isolate->object_store()->stack_overflow()) { | 769 exception.raw() != isolate->object_store()->stack_overflow()) { |
| 790 isolate->debugger()->PauseException(exception); | 770 isolate->debugger()->PauseException(exception); |
| 791 } | 771 } |
| 792 } | 772 } |
| 793 // Null object is a valid exception object. | 773 // Null object is a valid exception object. |
| 794 ThrowExceptionHelper(thread, exception, StackTrace::Handle(thread->zone()), | 774 ThrowExceptionHelper(thread, exception, StackTrace::Handle(thread->zone()), |
| 795 false); | 775 false); |
| 796 } | 776 } |
| 797 | 777 |
| 798 | |
| 799 void Exceptions::ReThrow(Thread* thread, | 778 void Exceptions::ReThrow(Thread* thread, |
| 800 const Instance& exception, | 779 const Instance& exception, |
| 801 const Instance& stacktrace) { | 780 const Instance& stacktrace) { |
| 802 // Null object is a valid exception object. | 781 // Null object is a valid exception object. |
| 803 ThrowExceptionHelper(thread, exception, stacktrace, true); | 782 ThrowExceptionHelper(thread, exception, stacktrace, true); |
| 804 } | 783 } |
| 805 | 784 |
| 806 | |
| 807 void Exceptions::PropagateError(const Error& error) { | 785 void Exceptions::PropagateError(const Error& error) { |
| 808 Thread* thread = Thread::Current(); | 786 Thread* thread = Thread::Current(); |
| 809 Zone* zone = thread->zone(); | 787 Zone* zone = thread->zone(); |
| 810 ASSERT(thread->top_exit_frame_info() != 0); | 788 ASSERT(thread->top_exit_frame_info() != 0); |
| 811 if (error.IsUnhandledException()) { | 789 if (error.IsUnhandledException()) { |
| 812 // If the error object represents an unhandled exception, then | 790 // If the error object represents an unhandled exception, then |
| 813 // rethrow the exception in the normal fashion. | 791 // rethrow the exception in the normal fashion. |
| 814 const UnhandledException& uhe = UnhandledException::Cast(error); | 792 const UnhandledException& uhe = UnhandledException::Cast(error); |
| 815 const Instance& exc = Instance::Handle(zone, uhe.exception()); | 793 const Instance& exc = Instance::Handle(zone, uhe.exception()); |
| 816 const Instance& stk = Instance::Handle(zone, uhe.stacktrace()); | 794 const Instance& stk = Instance::Handle(zone, uhe.stacktrace()); |
| 817 Exceptions::ReThrow(thread, exc, stk); | 795 Exceptions::ReThrow(thread, exc, stk); |
| 818 } else { | 796 } else { |
| 819 // Return to the invocation stub and return this error object. The | 797 // Return to the invocation stub and return this error object. The |
| 820 // C++ code which invoked this dart sequence can check and do the | 798 // C++ code which invoked this dart sequence can check and do the |
| 821 // appropriate thing. | 799 // appropriate thing. |
| 822 uword handler_pc = 0; | 800 uword handler_pc = 0; |
| 823 uword handler_sp = 0; | 801 uword handler_sp = 0; |
| 824 uword handler_fp = 0; | 802 uword handler_fp = 0; |
| 825 FindErrorHandler(&handler_pc, &handler_sp, &handler_fp); | 803 FindErrorHandler(&handler_pc, &handler_sp, &handler_fp); |
| 826 JumpToExceptionHandler(thread, handler_pc, handler_sp, handler_fp, error, | 804 JumpToExceptionHandler(thread, handler_pc, handler_sp, handler_fp, error, |
| 827 StackTrace::Handle(zone)); // Null stacktrace. | 805 StackTrace::Handle(zone)); // Null stacktrace. |
| 828 } | 806 } |
| 829 UNREACHABLE(); | 807 UNREACHABLE(); |
| 830 } | 808 } |
| 831 | 809 |
| 832 | |
| 833 void Exceptions::ThrowByType(ExceptionType type, const Array& arguments) { | 810 void Exceptions::ThrowByType(ExceptionType type, const Array& arguments) { |
| 834 Thread* thread = Thread::Current(); | 811 Thread* thread = Thread::Current(); |
| 835 const Object& result = | 812 const Object& result = |
| 836 Object::Handle(thread->zone(), Create(type, arguments)); | 813 Object::Handle(thread->zone(), Create(type, arguments)); |
| 837 if (result.IsError()) { | 814 if (result.IsError()) { |
| 838 // We got an error while constructing the exception object. | 815 // We got an error while constructing the exception object. |
| 839 // Propagate the error instead of throwing the exception. | 816 // Propagate the error instead of throwing the exception. |
| 840 PropagateError(Error::Cast(result)); | 817 PropagateError(Error::Cast(result)); |
| 841 } else { | 818 } else { |
| 842 ASSERT(result.IsInstance()); | 819 ASSERT(result.IsInstance()); |
| 843 Throw(thread, Instance::Cast(result)); | 820 Throw(thread, Instance::Cast(result)); |
| 844 } | 821 } |
| 845 } | 822 } |
| 846 | 823 |
| 847 | |
| 848 void Exceptions::ThrowOOM() { | 824 void Exceptions::ThrowOOM() { |
| 849 Thread* thread = Thread::Current(); | 825 Thread* thread = Thread::Current(); |
| 850 Isolate* isolate = thread->isolate(); | 826 Isolate* isolate = thread->isolate(); |
| 851 const Instance& oom = Instance::Handle( | 827 const Instance& oom = Instance::Handle( |
| 852 thread->zone(), isolate->object_store()->out_of_memory()); | 828 thread->zone(), isolate->object_store()->out_of_memory()); |
| 853 Throw(thread, oom); | 829 Throw(thread, oom); |
| 854 } | 830 } |
| 855 | 831 |
| 856 | |
| 857 void Exceptions::ThrowStackOverflow() { | 832 void Exceptions::ThrowStackOverflow() { |
| 858 Thread* thread = Thread::Current(); | 833 Thread* thread = Thread::Current(); |
| 859 Isolate* isolate = thread->isolate(); | 834 Isolate* isolate = thread->isolate(); |
| 860 const Instance& stack_overflow = Instance::Handle( | 835 const Instance& stack_overflow = Instance::Handle( |
| 861 thread->zone(), isolate->object_store()->stack_overflow()); | 836 thread->zone(), isolate->object_store()->stack_overflow()); |
| 862 Throw(thread, stack_overflow); | 837 Throw(thread, stack_overflow); |
| 863 } | 838 } |
| 864 | 839 |
| 865 | |
| 866 void Exceptions::ThrowArgumentError(const Instance& arg) { | 840 void Exceptions::ThrowArgumentError(const Instance& arg) { |
| 867 const Array& args = Array::Handle(Array::New(1)); | 841 const Array& args = Array::Handle(Array::New(1)); |
| 868 args.SetAt(0, arg); | 842 args.SetAt(0, arg); |
| 869 Exceptions::ThrowByType(Exceptions::kArgument, args); | 843 Exceptions::ThrowByType(Exceptions::kArgument, args); |
| 870 } | 844 } |
| 871 | 845 |
| 872 | |
| 873 void Exceptions::ThrowRangeError(const char* argument_name, | 846 void Exceptions::ThrowRangeError(const char* argument_name, |
| 874 const Integer& argument_value, | 847 const Integer& argument_value, |
| 875 intptr_t expected_from, | 848 intptr_t expected_from, |
| 876 intptr_t expected_to) { | 849 intptr_t expected_to) { |
| 877 const Array& args = Array::Handle(Array::New(4)); | 850 const Array& args = Array::Handle(Array::New(4)); |
| 878 args.SetAt(0, argument_value); | 851 args.SetAt(0, argument_value); |
| 879 args.SetAt(1, Integer::Handle(Integer::New(expected_from))); | 852 args.SetAt(1, Integer::Handle(Integer::New(expected_from))); |
| 880 args.SetAt(2, Integer::Handle(Integer::New(expected_to))); | 853 args.SetAt(2, Integer::Handle(Integer::New(expected_to))); |
| 881 args.SetAt(3, String::Handle(String::New(argument_name))); | 854 args.SetAt(3, String::Handle(String::New(argument_name))); |
| 882 Exceptions::ThrowByType(Exceptions::kRange, args); | 855 Exceptions::ThrowByType(Exceptions::kRange, args); |
| 883 } | 856 } |
| 884 | 857 |
| 885 | |
| 886 void Exceptions::ThrowRangeErrorMsg(const char* msg) { | 858 void Exceptions::ThrowRangeErrorMsg(const char* msg) { |
| 887 const Array& args = Array::Handle(Array::New(1)); | 859 const Array& args = Array::Handle(Array::New(1)); |
| 888 args.SetAt(0, String::Handle(String::New(msg))); | 860 args.SetAt(0, String::Handle(String::New(msg))); |
| 889 Exceptions::ThrowByType(Exceptions::kRangeMsg, args); | 861 Exceptions::ThrowByType(Exceptions::kRangeMsg, args); |
| 890 } | 862 } |
| 891 | 863 |
| 892 | |
| 893 void Exceptions::ThrowCompileTimeError(const LanguageError& error) { | 864 void Exceptions::ThrowCompileTimeError(const LanguageError& error) { |
| 894 const Array& args = Array::Handle(Array::New(1)); | 865 const Array& args = Array::Handle(Array::New(1)); |
| 895 args.SetAt(0, String::Handle(error.FormatMessage())); | 866 args.SetAt(0, String::Handle(error.FormatMessage())); |
| 896 Exceptions::ThrowByType(Exceptions::kCompileTimeError, args); | 867 Exceptions::ThrowByType(Exceptions::kCompileTimeError, args); |
| 897 } | 868 } |
| 898 | 869 |
| 899 | |
| 900 RawObject* Exceptions::Create(ExceptionType type, const Array& arguments) { | 870 RawObject* Exceptions::Create(ExceptionType type, const Array& arguments) { |
| 901 Library& library = Library::Handle(); | 871 Library& library = Library::Handle(); |
| 902 const String* class_name = NULL; | 872 const String* class_name = NULL; |
| 903 const String* constructor_name = &Symbols::Dot(); | 873 const String* constructor_name = &Symbols::Dot(); |
| 904 switch (type) { | 874 switch (type) { |
| 905 case kNone: | 875 case kNone: |
| 906 case kStackOverflow: | 876 case kStackOverflow: |
| 907 case kOutOfMemory: | 877 case kOutOfMemory: |
| 908 UNREACHABLE(); | 878 UNREACHABLE(); |
| 909 break; | 879 break; |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 981 class_name = &Symbols::_CompileTimeError(); | 951 class_name = &Symbols::_CompileTimeError(); |
| 982 break; | 952 break; |
| 983 } | 953 } |
| 984 | 954 |
| 985 Thread* thread = Thread::Current(); | 955 Thread* thread = Thread::Current(); |
| 986 NoReloadScope no_reload_scope(thread->isolate(), thread); | 956 NoReloadScope no_reload_scope(thread->isolate(), thread); |
| 987 return DartLibraryCalls::InstanceCreate(library, *class_name, | 957 return DartLibraryCalls::InstanceCreate(library, *class_name, |
| 988 *constructor_name, arguments); | 958 *constructor_name, arguments); |
| 989 } | 959 } |
| 990 | 960 |
| 991 | |
| 992 } // namespace dart | 961 } // namespace dart |
| OLD | NEW |