| 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 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 187 frame = frames.NextFrame(); | 187 frame = frames.NextFrame(); |
| 188 ASSERT(frame != NULL); | 188 ASSERT(frame != NULL); |
| 189 } | 189 } |
| 190 ASSERT(frame->IsEntryFrame()); | 190 ASSERT(frame->IsEntryFrame()); |
| 191 *handler_pc = frame->pc(); | 191 *handler_pc = frame->pc(); |
| 192 *handler_sp = frame->sp(); | 192 *handler_sp = frame->sp(); |
| 193 *handler_fp = frame->fp(); | 193 *handler_fp = frame->fp(); |
| 194 } | 194 } |
| 195 | 195 |
| 196 | 196 |
| 197 static void JumpToExceptionHandler(Isolate* isolate, | 197 static void JumpToExceptionHandler(Thread* thread, |
| 198 uword program_counter, | 198 uword program_counter, |
| 199 uword stack_pointer, | 199 uword stack_pointer, |
| 200 uword frame_pointer, | 200 uword frame_pointer, |
| 201 const Object& exception_object, | 201 const Object& exception_object, |
| 202 const Object& stacktrace_object) { | 202 const Object& stacktrace_object) { |
| 203 // The no_gc StackResource is unwound through the tear down of | 203 // The no_gc StackResource is unwound through the tear down of |
| 204 // stack resources below. | 204 // stack resources below. |
| 205 NoSafepointScope no_safepoint; | 205 NoSafepointScope no_safepoint; |
| 206 RawObject* raw_exception = exception_object.raw(); | 206 RawObject* raw_exception = exception_object.raw(); |
| 207 RawObject* raw_stacktrace = stacktrace_object.raw(); | 207 RawObject* raw_stacktrace = stacktrace_object.raw(); |
| 208 | 208 |
| 209 #if defined(USING_SIMULATOR) | 209 #if defined(USING_SIMULATOR) |
| 210 // Unwinding of the C++ frames and destroying of their stack resources is done | 210 // Unwinding of the C++ frames and destroying of their stack resources is done |
| 211 // by the simulator, because the target stack_pointer is a simulated stack | 211 // by the simulator, because the target stack_pointer is a simulated stack |
| 212 // pointer and not the C++ stack pointer. | 212 // pointer and not the C++ stack pointer. |
| 213 | 213 |
| 214 // Continue simulating at the given pc in the given frame after setting up the | 214 // Continue simulating at the given pc in the given frame after setting up the |
| 215 // exception object in the kExceptionObjectReg register and the stacktrace | 215 // exception object in the kExceptionObjectReg register and the stacktrace |
| 216 // object (may be raw null) in the kStackTraceObjectReg register. | 216 // object (may be raw null) in the kStackTraceObjectReg register. |
| 217 | 217 |
| 218 Simulator::Current()->Longjmp(program_counter, stack_pointer, frame_pointer, | 218 Simulator::Current()->Longjmp(program_counter, stack_pointer, frame_pointer, |
| 219 raw_exception, raw_stacktrace, isolate); | 219 raw_exception, raw_stacktrace, thread); |
| 220 #else | 220 #else |
| 221 // Prepare for unwinding frames by destroying all the stack resources | 221 // Prepare for unwinding frames by destroying all the stack resources |
| 222 // in the previous frames. | 222 // in the previous frames. |
| 223 StackResource::Unwind(isolate); | 223 StackResource::Unwind(thread->isolate()); |
| 224 | 224 |
| 225 // Call a stub to set up the exception object in kExceptionObjectReg, | 225 // Call a stub to set up the exception object in kExceptionObjectReg, |
| 226 // to set up the stacktrace object in kStackTraceObjectReg, and to | 226 // to set up the stacktrace object in kStackTraceObjectReg, and to |
| 227 // continue execution at the given pc in the given frame. | 227 // continue execution at the given pc in the given frame. |
| 228 typedef void (*ExcpHandler)(uword, uword, uword, RawObject*, RawObject*, | 228 typedef void (*ExcpHandler)(uword, uword, uword, RawObject*, RawObject*, |
| 229 Isolate*); | 229 Thread*); |
| 230 ExcpHandler func = reinterpret_cast<ExcpHandler>( | 230 ExcpHandler func = reinterpret_cast<ExcpHandler>( |
| 231 StubCode::JumpToExceptionHandlerEntryPoint()); | 231 StubCode::JumpToExceptionHandlerEntryPoint()); |
| 232 | 232 |
| 233 // Unpoison the stack before we tear it down in the generated stub code. | 233 // Unpoison the stack before we tear it down in the generated stub code. |
| 234 uword current_sp = Isolate::GetCurrentStackPointer() - 1024; | 234 uword current_sp = Isolate::GetCurrentStackPointer() - 1024; |
| 235 ASAN_UNPOISON(reinterpret_cast<void*>(current_sp), | 235 ASAN_UNPOISON(reinterpret_cast<void*>(current_sp), |
| 236 stack_pointer - current_sp); | 236 stack_pointer - current_sp); |
| 237 | 237 |
| 238 func(program_counter, stack_pointer, frame_pointer, | 238 func(program_counter, stack_pointer, frame_pointer, |
| 239 raw_exception, raw_stacktrace, isolate); | 239 raw_exception, raw_stacktrace, thread); |
| 240 #endif | 240 #endif |
| 241 UNREACHABLE(); | 241 UNREACHABLE(); |
| 242 } | 242 } |
| 243 | 243 |
| 244 | 244 |
| 245 static RawField* LookupStacktraceField(const Instance& instance) { | 245 static RawField* LookupStacktraceField(const Instance& instance) { |
| 246 if (instance.GetClassId() < kNumPredefinedCids) { | 246 if (instance.GetClassId() < kNumPredefinedCids) { |
| 247 // 'class Error' is not a predefined class. | 247 // 'class Error' is not a predefined class. |
| 248 return Field::null(); | 248 return Field::null(); |
| 249 } | 249 } |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 281 const Array& full_code_array = Array::Handle(isolate, | 281 const Array& full_code_array = Array::Handle(isolate, |
| 282 Array::MakeArray(frame_builder.code_list())); | 282 Array::MakeArray(frame_builder.code_list())); |
| 283 const Array& full_pc_offset_array = Array::Handle(isolate, | 283 const Array& full_pc_offset_array = Array::Handle(isolate, |
| 284 Array::MakeArray(frame_builder.pc_offset_list())); | 284 Array::MakeArray(frame_builder.pc_offset_list())); |
| 285 const Stacktrace& full_stacktrace = Stacktrace::Handle( | 285 const Stacktrace& full_stacktrace = Stacktrace::Handle( |
| 286 Stacktrace::New(full_code_array, full_pc_offset_array)); | 286 Stacktrace::New(full_code_array, full_pc_offset_array)); |
| 287 return full_stacktrace.raw(); | 287 return full_stacktrace.raw(); |
| 288 } | 288 } |
| 289 | 289 |
| 290 | 290 |
| 291 static void ThrowExceptionHelper(Isolate* isolate, | 291 static void ThrowExceptionHelper(Thread* thread, |
| 292 const Instance& incoming_exception, | 292 const Instance& incoming_exception, |
| 293 const Instance& existing_stacktrace, | 293 const Instance& existing_stacktrace, |
| 294 const bool is_rethrow) { | 294 const bool is_rethrow) { |
| 295 Isolate* isolate = thread->isolate(); |
| 295 bool use_preallocated_stacktrace = false; | 296 bool use_preallocated_stacktrace = false; |
| 296 Instance& exception = Instance::Handle(isolate, incoming_exception.raw()); | 297 Instance& exception = Instance::Handle(isolate, incoming_exception.raw()); |
| 297 if (exception.IsNull()) { | 298 if (exception.IsNull()) { |
| 298 exception ^= Exceptions::Create(Exceptions::kNullThrown, | 299 exception ^= Exceptions::Create(Exceptions::kNullThrown, |
| 299 Object::empty_array()); | 300 Object::empty_array()); |
| 300 } else if (exception.raw() == isolate->object_store()->out_of_memory() || | 301 } else if (exception.raw() == isolate->object_store()->out_of_memory() || |
| 301 exception.raw() == isolate->object_store()->stack_overflow()) { | 302 exception.raw() == isolate->object_store()->stack_overflow()) { |
| 302 use_preallocated_stacktrace = true; | 303 use_preallocated_stacktrace = true; |
| 303 } | 304 } |
| 304 uword handler_pc = 0; | 305 uword handler_pc = 0; |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 356 // stack as Exceptions::Throw should happen only after a dart | 357 // stack as Exceptions::Throw should happen only after a dart |
| 357 // invocation has been done. | 358 // invocation has been done. |
| 358 ASSERT(handler_pc != 0); | 359 ASSERT(handler_pc != 0); |
| 359 | 360 |
| 360 if (FLAG_print_stacktrace_at_throw) { | 361 if (FLAG_print_stacktrace_at_throw) { |
| 361 OS::Print("Exception '%s' thrown:\n", exception.ToCString()); | 362 OS::Print("Exception '%s' thrown:\n", exception.ToCString()); |
| 362 OS::Print("%s\n", stacktrace.ToCString()); | 363 OS::Print("%s\n", stacktrace.ToCString()); |
| 363 } | 364 } |
| 364 if (handler_exists) { | 365 if (handler_exists) { |
| 365 // Found a dart handler for the exception, jump to it. | 366 // Found a dart handler for the exception, jump to it. |
| 366 JumpToExceptionHandler(isolate, | 367 JumpToExceptionHandler(thread, |
| 367 handler_pc, | 368 handler_pc, |
| 368 handler_sp, | 369 handler_sp, |
| 369 handler_fp, | 370 handler_fp, |
| 370 exception, | 371 exception, |
| 371 stacktrace); | 372 stacktrace); |
| 372 } else { | 373 } else { |
| 373 // No dart exception handler found in this invocation sequence, | 374 // No dart exception handler found in this invocation sequence, |
| 374 // so we create an unhandled exception object and return to the | 375 // so we create an unhandled exception object and return to the |
| 375 // invocation stub so that it returns this unhandled exception | 376 // invocation stub so that it returns this unhandled exception |
| 376 // object. The C++ code which invoked this dart sequence can check | 377 // object. The C++ code which invoked this dart sequence can check |
| 377 // and do the appropriate thing (rethrow the exception to the | 378 // and do the appropriate thing (rethrow the exception to the |
| 378 // dart invocation sequence above it, print diagnostics and terminate | 379 // dart invocation sequence above it, print diagnostics and terminate |
| 379 // the isolate etc.). | 380 // the isolate etc.). |
| 380 const UnhandledException& unhandled_exception = UnhandledException::Handle( | 381 const UnhandledException& unhandled_exception = UnhandledException::Handle( |
| 381 isolate, UnhandledException::New(exception, stacktrace)); | 382 isolate, UnhandledException::New(exception, stacktrace)); |
| 382 stacktrace = Stacktrace::null(); | 383 stacktrace = Stacktrace::null(); |
| 383 JumpToExceptionHandler(isolate, | 384 JumpToExceptionHandler(thread, |
| 384 handler_pc, | 385 handler_pc, |
| 385 handler_sp, | 386 handler_sp, |
| 386 handler_fp, | 387 handler_fp, |
| 387 unhandled_exception, | 388 unhandled_exception, |
| 388 stacktrace); | 389 stacktrace); |
| 389 } | 390 } |
| 390 UNREACHABLE(); | 391 UNREACHABLE(); |
| 391 } | 392 } |
| 392 | 393 |
| 393 | 394 |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 467 } else { | 468 } else { |
| 468 OS::Print("type error.\n"); | 469 OS::Print("type error.\n"); |
| 469 } | 470 } |
| 470 } | 471 } |
| 471 // Throw TypeError or CastError instance. | 472 // Throw TypeError or CastError instance. |
| 472 Exceptions::ThrowByType(exception_type, args); | 473 Exceptions::ThrowByType(exception_type, args); |
| 473 UNREACHABLE(); | 474 UNREACHABLE(); |
| 474 } | 475 } |
| 475 | 476 |
| 476 | 477 |
| 477 void Exceptions::Throw(Isolate* isolate, const Instance& exception) { | 478 void Exceptions::Throw(Thread* thread, const Instance& exception) { |
| 478 // Do not notify debugger on stack overflow and out of memory exceptions. | 479 // Do not notify debugger on stack overflow and out of memory exceptions. |
| 479 // The VM would crash when the debugger calls back into the VM to | 480 // The VM would crash when the debugger calls back into the VM to |
| 480 // get values of variables. | 481 // get values of variables. |
| 482 Isolate* isolate = thread->isolate(); |
| 481 if (exception.raw() != isolate->object_store()->out_of_memory() && | 483 if (exception.raw() != isolate->object_store()->out_of_memory() && |
| 482 exception.raw() != isolate->object_store()->stack_overflow()) { | 484 exception.raw() != isolate->object_store()->stack_overflow()) { |
| 483 isolate->debugger()->SignalExceptionThrown(exception); | 485 isolate->debugger()->SignalExceptionThrown(exception); |
| 484 } | 486 } |
| 485 // Null object is a valid exception object. | 487 // Null object is a valid exception object. |
| 486 ThrowExceptionHelper(isolate, exception, Stacktrace::Handle(isolate), false); | 488 ThrowExceptionHelper(thread, exception, Stacktrace::Handle(isolate), false); |
| 487 } | 489 } |
| 488 | 490 |
| 489 | 491 void Exceptions::ReThrow(Thread* thread, |
| 490 void Exceptions::ReThrow(Isolate* isolate, | |
| 491 const Instance& exception, | 492 const Instance& exception, |
| 492 const Instance& stacktrace) { | 493 const Instance& stacktrace) { |
| 493 // Null object is a valid exception object. | 494 // Null object is a valid exception object. |
| 494 ThrowExceptionHelper(isolate, exception, stacktrace, true); | 495 ThrowExceptionHelper(thread, exception, stacktrace, true); |
| 495 } | 496 } |
| 496 | 497 |
| 497 | 498 |
| 498 void Exceptions::PropagateError(const Error& error) { | 499 void Exceptions::PropagateError(const Error& error) { |
| 499 Isolate* isolate = Isolate::Current(); | 500 Thread* thread = Thread::Current(); |
| 501 Isolate* isolate = thread->isolate(); |
| 500 ASSERT(isolate->top_exit_frame_info() != 0); | 502 ASSERT(isolate->top_exit_frame_info() != 0); |
| 501 if (error.IsUnhandledException()) { | 503 if (error.IsUnhandledException()) { |
| 502 // If the error object represents an unhandled exception, then | 504 // If the error object represents an unhandled exception, then |
| 503 // rethrow the exception in the normal fashion. | 505 // rethrow the exception in the normal fashion. |
| 504 const UnhandledException& uhe = UnhandledException::Cast(error); | 506 const UnhandledException& uhe = UnhandledException::Cast(error); |
| 505 const Instance& exc = Instance::Handle(isolate, uhe.exception()); | 507 const Instance& exc = Instance::Handle(isolate, uhe.exception()); |
| 506 const Instance& stk = Instance::Handle(isolate, uhe.stacktrace()); | 508 const Instance& stk = Instance::Handle(isolate, uhe.stacktrace()); |
| 507 Exceptions::ReThrow(isolate, exc, stk); | 509 Exceptions::ReThrow(thread, exc, stk); |
| 508 } else { | 510 } else { |
| 509 // Return to the invocation stub and return this error object. The | 511 // Return to the invocation stub and return this error object. The |
| 510 // C++ code which invoked this dart sequence can check and do the | 512 // C++ code which invoked this dart sequence can check and do the |
| 511 // appropriate thing. | 513 // appropriate thing. |
| 512 uword handler_pc = 0; | 514 uword handler_pc = 0; |
| 513 uword handler_sp = 0; | 515 uword handler_sp = 0; |
| 514 uword handler_fp = 0; | 516 uword handler_fp = 0; |
| 515 FindErrorHandler(&handler_pc, &handler_sp, &handler_fp); | 517 FindErrorHandler(&handler_pc, &handler_sp, &handler_fp); |
| 516 JumpToExceptionHandler(isolate, handler_pc, handler_sp, handler_fp, error, | 518 JumpToExceptionHandler(thread, handler_pc, handler_sp, handler_fp, error, |
| 517 Stacktrace::Handle(isolate)); // Null stacktrace. | 519 Stacktrace::Handle(isolate)); // Null stacktrace. |
| 518 } | 520 } |
| 519 UNREACHABLE(); | 521 UNREACHABLE(); |
| 520 } | 522 } |
| 521 | 523 |
| 522 | 524 |
| 523 void Exceptions::ThrowByType(ExceptionType type, const Array& arguments) { | 525 void Exceptions::ThrowByType(ExceptionType type, const Array& arguments) { |
| 524 Isolate* isolate = Isolate::Current(); | 526 Thread* thread = Thread::Current(); |
| 527 Isolate* isolate = thread->isolate(); |
| 525 const Object& result = Object::Handle(isolate, Create(type, arguments)); | 528 const Object& result = Object::Handle(isolate, Create(type, arguments)); |
| 526 if (result.IsError()) { | 529 if (result.IsError()) { |
| 527 // We got an error while constructing the exception object. | 530 // We got an error while constructing the exception object. |
| 528 // Propagate the error instead of throwing the exception. | 531 // Propagate the error instead of throwing the exception. |
| 529 PropagateError(Error::Cast(result)); | 532 PropagateError(Error::Cast(result)); |
| 530 } else { | 533 } else { |
| 531 ASSERT(result.IsInstance()); | 534 ASSERT(result.IsInstance()); |
| 532 Throw(isolate, Instance::Cast(result)); | 535 Throw(thread, Instance::Cast(result)); |
| 533 } | 536 } |
| 534 } | 537 } |
| 535 | 538 |
| 536 | 539 |
| 537 void Exceptions::ThrowOOM() { | 540 void Exceptions::ThrowOOM() { |
| 538 Isolate* isolate = Isolate::Current(); | 541 Thread* thread = Thread::Current(); |
| 542 Isolate* isolate = thread->isolate(); |
| 539 const Instance& oom = Instance::Handle( | 543 const Instance& oom = Instance::Handle( |
| 540 isolate, isolate->object_store()->out_of_memory()); | 544 isolate, isolate->object_store()->out_of_memory()); |
| 541 Throw(isolate, oom); | 545 Throw(thread, oom); |
| 542 } | 546 } |
| 543 | 547 |
| 544 | 548 |
| 545 void Exceptions::ThrowStackOverflow() { | 549 void Exceptions::ThrowStackOverflow() { |
| 546 Isolate* isolate = Isolate::Current(); | 550 Thread* thread = Thread::Current(); |
| 551 Isolate* isolate = thread->isolate(); |
| 547 const Instance& stack_overflow = Instance::Handle( | 552 const Instance& stack_overflow = Instance::Handle( |
| 548 isolate, isolate->object_store()->stack_overflow()); | 553 isolate, isolate->object_store()->stack_overflow()); |
| 549 Throw(isolate, stack_overflow); | 554 Throw(thread, stack_overflow); |
| 550 } | 555 } |
| 551 | 556 |
| 552 | 557 |
| 553 void Exceptions::ThrowArgumentError(const Instance& arg) { | 558 void Exceptions::ThrowArgumentError(const Instance& arg) { |
| 554 const Array& args = Array::Handle(Array::New(1)); | 559 const Array& args = Array::Handle(Array::New(1)); |
| 555 args.SetAt(0, arg); | 560 args.SetAt(0, arg); |
| 556 Exceptions::ThrowByType(Exceptions::kArgument, args); | 561 Exceptions::ThrowByType(Exceptions::kArgument, args); |
| 557 } | 562 } |
| 558 | 563 |
| 559 | 564 |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 664 | 669 |
| 665 // Throw JavascriptCompatibilityError exception. | 670 // Throw JavascriptCompatibilityError exception. |
| 666 void Exceptions::ThrowJavascriptCompatibilityError(const char* msg) { | 671 void Exceptions::ThrowJavascriptCompatibilityError(const char* msg) { |
| 667 const Array& exc_args = Array::Handle(Array::New(1)); | 672 const Array& exc_args = Array::Handle(Array::New(1)); |
| 668 const String& msg_str = String::Handle(String::New(msg)); | 673 const String& msg_str = String::Handle(String::New(msg)); |
| 669 exc_args.SetAt(0, msg_str); | 674 exc_args.SetAt(0, msg_str); |
| 670 Exceptions::ThrowByType(Exceptions::kJavascriptCompatibilityError, exc_args); | 675 Exceptions::ThrowByType(Exceptions::kJavascriptCompatibilityError, exc_args); |
| 671 } | 676 } |
| 672 | 677 |
| 673 } // namespace dart | 678 } // namespace dart |
| OLD | NEW |