OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <stdlib.h> | 5 #include <stdlib.h> |
6 | 6 |
7 #include <fstream> // NOLINT(readability/streams) | 7 #include <fstream> // NOLINT(readability/streams) |
8 #include <sstream> | 8 #include <sstream> |
9 | 9 |
10 #include "src/v8.h" | 10 #include "src/v8.h" |
(...skipping 960 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
971 ReportBootstrappingException(exception_handle, location); | 971 ReportBootstrappingException(exception_handle, location); |
972 } else { | 972 } else { |
973 Handle<Object> message_obj = CreateMessage(exception_handle, location); | 973 Handle<Object> message_obj = CreateMessage(exception_handle, location); |
974 thread_local_top()->pending_message_obj_ = *message_obj; | 974 thread_local_top()->pending_message_obj_ = *message_obj; |
975 | 975 |
976 // If the abort-on-uncaught-exception flag is specified, abort on any | 976 // If the abort-on-uncaught-exception flag is specified, abort on any |
977 // exception not caught by JavaScript, even when an external handler is | 977 // exception not caught by JavaScript, even when an external handler is |
978 // present. This flag is intended for use by JavaScript developers, so | 978 // present. This flag is intended for use by JavaScript developers, so |
979 // print a user-friendly stack trace (not an internal one). | 979 // print a user-friendly stack trace (not an internal one). |
980 if (FLAG_abort_on_uncaught_exception && | 980 if (FLAG_abort_on_uncaught_exception && |
981 !PredictWhetherExceptionIsCaught(*exception_handle)) { | 981 PredictExceptionCatcher() != CAUGHT_BY_JAVASCRIPT) { |
982 FLAG_abort_on_uncaught_exception = false; // Prevent endless recursion. | 982 FLAG_abort_on_uncaught_exception = false; // Prevent endless recursion. |
983 PrintF(stderr, "%s\n\nFROM\n", | 983 PrintF(stderr, "%s\n\nFROM\n", |
984 MessageHandler::GetLocalizedMessage(this, message_obj).get()); | 984 MessageHandler::GetLocalizedMessage(this, message_obj).get()); |
985 PrintCurrentStackTrace(stderr); | 985 PrintCurrentStackTrace(stderr); |
986 base::OS::Abort(); | 986 base::OS::Abort(); |
987 } | 987 } |
988 } | 988 } |
989 } | 989 } |
990 | 990 |
991 // Set the exception being thrown. | 991 // Set the exception being thrown. |
992 set_pending_exception(*exception_handle); | 992 set_pending_exception(*exception_handle); |
993 return heap()->exception(); | 993 return heap()->exception(); |
994 } | 994 } |
995 | 995 |
996 | 996 |
997 Object* Isolate::ReThrow(Object* exception) { | 997 Object* Isolate::ReThrow(Object* exception) { |
998 DCHECK(!has_pending_exception()); | 998 DCHECK(!has_pending_exception()); |
999 | 999 |
1000 // Set the exception being re-thrown. | 1000 // Set the exception being re-thrown. |
1001 set_pending_exception(exception); | 1001 set_pending_exception(exception); |
1002 return heap()->exception(); | 1002 return heap()->exception(); |
1003 } | 1003 } |
1004 | 1004 |
1005 | 1005 |
1006 // TODO(turbofan): Make sure table is sorted and use binary search. | |
1007 static int LookupInHandlerTable(Code* code, int pc_offset) { | |
1008 FixedArray* handler_table = code->handler_table(); | |
1009 for (int i = 0; i < handler_table->length(); i += 2) { | |
1010 int return_offset = Smi::cast(handler_table->get(i))->value(); | |
1011 int handler_offset = Smi::cast(handler_table->get(i + 1))->value(); | |
1012 if (pc_offset == return_offset) return handler_offset; | |
1013 } | |
1014 return -1; | |
1015 } | |
1016 | |
1017 | |
1018 Object* Isolate::FindHandler() { | 1006 Object* Isolate::FindHandler() { |
1019 Object* exception = pending_exception(); | 1007 Object* exception = pending_exception(); |
1020 | 1008 |
1021 Code* code = nullptr; | 1009 Code* code = nullptr; |
1022 Context* context = nullptr; | 1010 Context* context = nullptr; |
1023 intptr_t offset = 0; | 1011 intptr_t offset = 0; |
1024 Address handler_sp = nullptr; | 1012 Address handler_sp = nullptr; |
1025 Address handler_fp = nullptr; | 1013 Address handler_fp = nullptr; |
1026 | 1014 |
1027 // Special handling of termination exceptions, uncatchable by JavaScript code, | 1015 // Special handling of termination exceptions, uncatchable by JavaScript code, |
1028 // we unwind the handlers until the top ENTRY handler is found. | 1016 // we unwind the handlers until the top ENTRY handler is found. |
1029 bool catchable_by_js = is_catchable_by_javascript(exception); | 1017 bool catchable_by_js = is_catchable_by_javascript(exception); |
1030 | 1018 |
1031 // Compute handler and stack unwinding information by performing a full walk | 1019 // Compute handler and stack unwinding information by performing a full walk |
1032 // over the stack and dispatching according to the frame type. | 1020 // over the stack and dispatching according to the frame type. |
1033 for (StackFrameIterator iter(this); !iter.done(); iter.Advance()) { | 1021 for (StackFrameIterator iter(this); !iter.done(); iter.Advance()) { |
1034 StackFrame* frame = iter.frame(); | 1022 StackFrame* frame = iter.frame(); |
1035 | 1023 |
1036 // For JSEntryStub frames we always have a handler. | 1024 // For JSEntryStub frames we always have a handler. |
1037 if (frame->is_entry() || frame->is_entry_construct()) { | 1025 if (frame->is_entry() || frame->is_entry_construct()) { |
1038 StackHandler* handler = frame->top_handler(); | 1026 StackHandler* handler = frame->top_handler(); |
1039 DCHECK_EQ(0, handler->index()); | |
1040 | 1027 |
1041 // Restore the next handler. | 1028 // Restore the next handler. |
1042 thread_local_top()->handler_ = handler->next()->address(); | 1029 thread_local_top()->handler_ = handler->next()->address(); |
1043 | 1030 |
1044 // Gather information from the handler. | 1031 // Gather information from the handler. |
1045 code = frame->LookupCode(); | 1032 code = frame->LookupCode(); |
1046 handler_sp = handler->address() + StackHandlerConstants::kSize; | 1033 handler_sp = handler->address() + StackHandlerConstants::kSize; |
1047 offset = Smi::cast(code->handler_table()->get(0))->value(); | 1034 offset = Smi::cast(code->handler_table()->get(0))->value(); |
1048 break; | 1035 break; |
1049 } | 1036 } |
1050 | 1037 |
1051 // For JavaScript frames which have a handler, we use the handler. | |
1052 if (frame->is_java_script() && catchable_by_js && frame->HasHandler()) { | |
1053 StackHandler* handler = frame->top_handler(); | |
1054 | |
1055 // Restore the next handler. | |
1056 thread_local_top()->handler_ = handler->next()->address(); | |
1057 | |
1058 // Gather information from the handler. | |
1059 code = frame->LookupCode(); | |
1060 context = handler->context(); | |
1061 offset = Smi::cast(code->handler_table()->get(handler->index()))->value(); | |
1062 handler_sp = handler->address() + StackHandlerConstants::kSize; | |
1063 handler_fp = frame->fp(); | |
1064 break; | |
1065 } | |
1066 | |
1067 // For optimized frames we perform a lookup in the handler table. | 1038 // For optimized frames we perform a lookup in the handler table. |
1068 if (frame->is_optimized() && catchable_by_js) { | 1039 if (frame->is_optimized() && catchable_by_js) { |
1069 Code* frame_code = frame->LookupCode(); | 1040 OptimizedFrame* js_frame = static_cast<OptimizedFrame*>(frame); |
1070 DCHECK(frame_code->is_optimized_code()); | 1041 int stack_slots = 0; // Will contain stack slot count of frame. |
1071 int pc_offset = static_cast<int>(frame->pc() - frame_code->entry()); | 1042 offset = js_frame->LookupExceptionHandlerInTable(&stack_slots); |
1072 int handler_offset = LookupInHandlerTable(frame_code, pc_offset); | 1043 if (offset < 0) continue; |
1073 if (handler_offset < 0) continue; | |
1074 | 1044 |
1075 // Compute the stack pointer from the frame pointer. This ensures that | 1045 // Compute the stack pointer from the frame pointer. This ensures that |
1076 // argument slots on the stack are dropped as returning would. | 1046 // argument slots on the stack are dropped as returning would. |
1077 Address return_sp = frame->fp() - | 1047 Address return_sp = frame->fp() - |
1078 StandardFrameConstants::kFixedFrameSizeFromFp - | 1048 StandardFrameConstants::kFixedFrameSizeFromFp - |
1079 frame_code->stack_slots() * kPointerSize; | 1049 stack_slots * kPointerSize; |
1080 | 1050 |
1081 // Gather information from the frame. | 1051 // Gather information from the frame. |
1082 code = frame_code; | 1052 code = frame->LookupCode(); |
1083 offset = handler_offset; | |
1084 handler_sp = return_sp; | 1053 handler_sp = return_sp; |
1085 handler_fp = frame->fp(); | 1054 handler_fp = frame->fp(); |
1086 break; | 1055 break; |
| 1056 } |
| 1057 |
| 1058 // For JavaScript frames we perform a range lookup in the handler table. |
| 1059 if (frame->is_java_script() && catchable_by_js) { |
| 1060 JavaScriptFrame* js_frame = static_cast<JavaScriptFrame*>(frame); |
| 1061 int stack_slots = 0; // Will contain operand stack depth of handler. |
| 1062 offset = js_frame->LookupExceptionHandlerInTable(&stack_slots); |
| 1063 if (offset < 0) continue; |
| 1064 |
| 1065 // Compute the stack pointer from the frame pointer. This ensures that |
| 1066 // operand stack slots are dropped for nested statements. Also restore |
| 1067 // correct context for the handler which is pushed within the try-block. |
| 1068 Address return_sp = frame->fp() - |
| 1069 StandardFrameConstants::kFixedFrameSizeFromFp - |
| 1070 stack_slots * kPointerSize; |
| 1071 STATIC_ASSERT(TryBlockConstant::kElementCount == 1); |
| 1072 context = Context::cast(Memory::Object_at(return_sp - kPointerSize)); |
| 1073 |
| 1074 // Gather information from the frame. |
| 1075 code = frame->LookupCode(); |
| 1076 handler_sp = return_sp; |
| 1077 handler_fp = frame->fp(); |
| 1078 break; |
1087 } | 1079 } |
1088 } | 1080 } |
1089 | 1081 |
1090 // Handler must exist. | 1082 // Handler must exist. |
1091 CHECK(code != nullptr); | 1083 CHECK(code != nullptr); |
1092 | 1084 |
1093 // Store information to be consumed by the CEntryStub. | 1085 // Store information to be consumed by the CEntryStub. |
1094 thread_local_top()->pending_handler_context_ = context; | 1086 thread_local_top()->pending_handler_context_ = context; |
1095 thread_local_top()->pending_handler_code_ = code; | 1087 thread_local_top()->pending_handler_code_ = code; |
1096 thread_local_top()->pending_handler_offset_ = offset; | 1088 thread_local_top()->pending_handler_offset_ = offset; |
1097 thread_local_top()->pending_handler_fp_ = handler_fp; | 1089 thread_local_top()->pending_handler_fp_ = handler_fp; |
1098 thread_local_top()->pending_handler_sp_ = handler_sp; | 1090 thread_local_top()->pending_handler_sp_ = handler_sp; |
1099 | 1091 |
1100 // Return and clear pending exception. | 1092 // Return and clear pending exception. |
1101 clear_pending_exception(); | 1093 clear_pending_exception(); |
1102 return exception; | 1094 return exception; |
1103 } | 1095 } |
1104 | 1096 |
1105 | 1097 |
1106 // TODO(mstarzinger): We shouldn't need the exception object here. | 1098 Isolate::CatchType Isolate::PredictExceptionCatcher() { |
1107 bool Isolate::PredictWhetherExceptionIsCaught(Object* exception) { | 1099 Address external_handler = thread_local_top()->try_catch_handler_address(); |
1108 if (IsExternalHandlerOnTop(exception)) return true; | 1100 Address entry_handler = Isolate::handler(thread_local_top()); |
| 1101 if (IsExternalHandlerOnTop(nullptr)) return CAUGHT_BY_EXTERNAL; |
1109 | 1102 |
1110 // Search for a JavaScript handler by performing a full walk over the stack | 1103 // Search for an exception handler by performing a full walk over the stack. |
1111 // and dispatching according to the frame type. | |
1112 for (StackFrameIterator iter(this); !iter.done(); iter.Advance()) { | 1104 for (StackFrameIterator iter(this); !iter.done(); iter.Advance()) { |
1113 StackFrame* frame = iter.frame(); | 1105 StackFrame* frame = iter.frame(); |
1114 | 1106 |
1115 // For JavaScript frames which have a handler, we use the handler. | 1107 // For JSEntryStub frames we update the JS_ENTRY handler. |
1116 if (frame->is_java_script() && frame->HasHandler()) { | 1108 if (frame->is_entry() || frame->is_entry_construct()) { |
1117 return true; | 1109 entry_handler = frame->top_handler()->next()->address(); |
1118 } | 1110 } |
1119 | 1111 |
1120 // For optimized frames we perform a lookup in the handler table. | 1112 // For JavaScript frames we perform a lookup in the handler table. |
1121 if (frame->is_optimized()) { | 1113 if (frame->is_java_script()) { |
1122 Code* frame_code = frame->LookupCode(); | 1114 JavaScriptFrame* js_frame = static_cast<JavaScriptFrame*>(frame); |
1123 DCHECK(frame_code->is_optimized_code()); | 1115 int stack_slots = 0; // The computed stack slot count is not used. |
1124 int pc_offset = static_cast<int>(frame->pc() - frame_code->entry()); | 1116 if (js_frame->LookupExceptionHandlerInTable(&stack_slots) > 0) { |
1125 int handler_offset = LookupInHandlerTable(frame_code, pc_offset); | 1117 return CAUGHT_BY_JAVASCRIPT; |
1126 if (handler_offset < 0) continue; | 1118 } |
1127 return true; | 1119 } |
| 1120 |
| 1121 // The exception has been externally caught if and only if there is an |
| 1122 // external handler which is on top of the top-most JS_ENTRY handler. |
| 1123 if (external_handler != nullptr && !try_catch_handler()->is_verbose_) { |
| 1124 if (entry_handler == nullptr || entry_handler > external_handler) { |
| 1125 return CAUGHT_BY_EXTERNAL; |
| 1126 } |
1128 } | 1127 } |
1129 } | 1128 } |
1130 | 1129 |
1131 // Handler not found. | 1130 // Handler not found. |
1132 return false; | 1131 return NOT_CAUGHT; |
1133 } | 1132 } |
1134 | 1133 |
1135 | 1134 |
1136 Object* Isolate::ThrowIllegalOperation() { | 1135 Object* Isolate::ThrowIllegalOperation() { |
1137 if (FLAG_stack_trace_on_illegal) PrintStack(stdout); | 1136 if (FLAG_stack_trace_on_illegal) PrintStack(stdout); |
1138 return Throw(heap()->illegal_access_string()); | 1137 return Throw(heap()->illegal_access_string()); |
1139 } | 1138 } |
1140 | 1139 |
1141 | 1140 |
1142 void Isolate::ScheduleThrow(Object* exception) { | 1141 void Isolate::ScheduleThrow(Object* exception) { |
(...skipping 361 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1504 return false; | 1503 return false; |
1505 } | 1504 } |
1506 | 1505 |
1507 // Reschedule the exception. | 1506 // Reschedule the exception. |
1508 thread_local_top()->scheduled_exception_ = pending_exception(); | 1507 thread_local_top()->scheduled_exception_ = pending_exception(); |
1509 clear_pending_exception(); | 1508 clear_pending_exception(); |
1510 return true; | 1509 return true; |
1511 } | 1510 } |
1512 | 1511 |
1513 | 1512 |
1514 void Isolate::PushPromise(Handle<JSObject> promise) { | 1513 void Isolate::PushPromise(Handle<JSObject> promise, |
| 1514 Handle<JSFunction> function) { |
1515 ThreadLocalTop* tltop = thread_local_top(); | 1515 ThreadLocalTop* tltop = thread_local_top(); |
1516 PromiseOnStack* prev = tltop->promise_on_stack_; | 1516 PromiseOnStack* prev = tltop->promise_on_stack_; |
1517 StackHandler* handler = StackHandler::FromAddress(Isolate::handler(tltop)); | 1517 Handle<JSObject> global_promise = |
1518 Handle<JSObject> global_handle = | |
1519 Handle<JSObject>::cast(global_handles()->Create(*promise)); | 1518 Handle<JSObject>::cast(global_handles()->Create(*promise)); |
1520 tltop->promise_on_stack_ = new PromiseOnStack(handler, global_handle, prev); | 1519 Handle<JSFunction> global_function = |
| 1520 Handle<JSFunction>::cast(global_handles()->Create(*function)); |
| 1521 tltop->promise_on_stack_ = |
| 1522 new PromiseOnStack(global_function, global_promise, prev); |
1521 } | 1523 } |
1522 | 1524 |
1523 | 1525 |
1524 void Isolate::PopPromise() { | 1526 void Isolate::PopPromise() { |
1525 ThreadLocalTop* tltop = thread_local_top(); | 1527 ThreadLocalTop* tltop = thread_local_top(); |
1526 if (tltop->promise_on_stack_ == NULL) return; | 1528 if (tltop->promise_on_stack_ == NULL) return; |
1527 PromiseOnStack* prev = tltop->promise_on_stack_->prev(); | 1529 PromiseOnStack* prev = tltop->promise_on_stack_->prev(); |
1528 Handle<Object> global_handle = tltop->promise_on_stack_->promise(); | 1530 Handle<Object> global_function = tltop->promise_on_stack_->function(); |
| 1531 Handle<Object> global_promise = tltop->promise_on_stack_->promise(); |
1529 delete tltop->promise_on_stack_; | 1532 delete tltop->promise_on_stack_; |
1530 tltop->promise_on_stack_ = prev; | 1533 tltop->promise_on_stack_ = prev; |
1531 global_handles()->Destroy(global_handle.location()); | 1534 global_handles()->Destroy(global_function.location()); |
| 1535 global_handles()->Destroy(global_promise.location()); |
1532 } | 1536 } |
1533 | 1537 |
1534 | 1538 |
1535 Handle<Object> Isolate::GetPromiseOnStackOnThrow() { | 1539 Handle<Object> Isolate::GetPromiseOnStackOnThrow() { |
1536 Handle<Object> undefined = factory()->undefined_value(); | 1540 Handle<Object> undefined = factory()->undefined_value(); |
1537 ThreadLocalTop* tltop = thread_local_top(); | 1541 ThreadLocalTop* tltop = thread_local_top(); |
1538 if (tltop->promise_on_stack_ == NULL) return undefined; | 1542 if (tltop->promise_on_stack_ == NULL) return undefined; |
1539 StackHandler* promise_try = tltop->promise_on_stack_->handler(); | 1543 Handle<JSFunction> promise_function = tltop->promise_on_stack_->function(); |
1540 // Find the top-most try-catch handler. | 1544 // Find the top-most try-catch or try-finally handler. |
1541 StackHandler* handler = StackHandler::FromAddress(Isolate::handler(tltop)); | 1545 if (PredictExceptionCatcher() != CAUGHT_BY_JAVASCRIPT) return undefined; |
1542 // Throwing inside a Promise only leads to a reject if not caught by an inner | 1546 for (JavaScriptFrameIterator it(this); !it.done(); it.Advance()) { |
1543 // try-catch or try-finally. | 1547 JavaScriptFrame* frame = it.frame(); |
1544 if (handler == promise_try) return tltop->promise_on_stack_->promise(); | 1548 int stack_slots = 0; // The computed stack slot count is not used. |
| 1549 if (frame->LookupExceptionHandlerInTable(&stack_slots) > 0) { |
| 1550 // Throwing inside a Promise only leads to a reject if not caught by an |
| 1551 // inner try-catch or try-finally. |
| 1552 if (frame->function() == *promise_function) { |
| 1553 return tltop->promise_on_stack_->promise(); |
| 1554 } |
| 1555 return undefined; |
| 1556 } |
| 1557 } |
1545 return undefined; | 1558 return undefined; |
1546 } | 1559 } |
1547 | 1560 |
1548 | 1561 |
1549 void Isolate::SetCaptureStackTraceForUncaughtExceptions( | 1562 void Isolate::SetCaptureStackTraceForUncaughtExceptions( |
1550 bool capture, | 1563 bool capture, |
1551 int frame_limit, | 1564 int frame_limit, |
1552 StackTrace::StackTraceOptions options) { | 1565 StackTrace::StackTraceOptions options) { |
1553 capture_stack_trace_for_uncaught_exceptions_ = capture; | 1566 capture_stack_trace_for_uncaught_exceptions_ = capture; |
1554 stack_trace_for_uncaught_exceptions_frame_limit_ = frame_limit; | 1567 stack_trace_for_uncaught_exceptions_frame_limit_ = frame_limit; |
(...skipping 1087 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2642 if (prev_ && prev_->Intercept(flag)) return true; | 2655 if (prev_ && prev_->Intercept(flag)) return true; |
2643 // Then check whether this scope intercepts. | 2656 // Then check whether this scope intercepts. |
2644 if ((flag & intercept_mask_)) { | 2657 if ((flag & intercept_mask_)) { |
2645 intercepted_flags_ |= flag; | 2658 intercepted_flags_ |= flag; |
2646 return true; | 2659 return true; |
2647 } | 2660 } |
2648 return false; | 2661 return false; |
2649 } | 2662 } |
2650 | 2663 |
2651 } } // namespace v8::internal | 2664 } } // namespace v8::internal |
OLD | NEW |