Index: src/isolate.cc |
diff --git a/src/isolate.cc b/src/isolate.cc |
index ca38e9f221461b7f447e1bf35aa8939985a9b40c..bdf82926ceea02c8663061278c0c3e7846d2c845 100644 |
--- a/src/isolate.cc |
+++ b/src/isolate.cc |
@@ -978,7 +978,7 @@ Object* Isolate::Throw(Object* exception, MessageLocation* location) { |
// present. This flag is intended for use by JavaScript developers, so |
// print a user-friendly stack trace (not an internal one). |
if (FLAG_abort_on_uncaught_exception && |
- !PredictWhetherExceptionIsCaught(*exception_handle)) { |
+ PredictExceptionCatcher() != CAUGHT_BY_JAVASCRIPT) { |
FLAG_abort_on_uncaught_exception = false; // Prevent endless recursion. |
PrintF(stderr, "%s\n\nFROM\n", |
MessageHandler::GetLocalizedMessage(this, message_obj).get()); |
@@ -1003,18 +1003,6 @@ Object* Isolate::ReThrow(Object* exception) { |
} |
-// TODO(turbofan): Make sure table is sorted and use binary search. |
-static int LookupInHandlerTable(Code* code, int pc_offset) { |
- FixedArray* handler_table = code->handler_table(); |
- for (int i = 0; i < handler_table->length(); i += 2) { |
- int return_offset = Smi::cast(handler_table->get(i))->value(); |
- int handler_offset = Smi::cast(handler_table->get(i + 1))->value(); |
- if (pc_offset == return_offset) return handler_offset; |
- } |
- return -1; |
-} |
- |
- |
Object* Isolate::FindHandler() { |
Object* exception = pending_exception(); |
@@ -1036,7 +1024,6 @@ Object* Isolate::FindHandler() { |
// For JSEntryStub frames we always have a handler. |
if (frame->is_entry() || frame->is_entry_construct()) { |
StackHandler* handler = frame->top_handler(); |
- DCHECK_EQ(0, handler->index()); |
// Restore the next handler. |
thread_local_top()->handler_ = handler->next()->address(); |
@@ -1048,39 +1035,44 @@ Object* Isolate::FindHandler() { |
break; |
} |
- // For JavaScript frames which have a handler, we use the handler. |
- if (frame->is_java_script() && catchable_by_js && frame->HasHandler()) { |
- StackHandler* handler = frame->top_handler(); |
+ // For optimized frames we perform a lookup in the handler table. |
+ if (frame->is_optimized() && catchable_by_js) { |
+ OptimizedFrame* js_frame = static_cast<OptimizedFrame*>(frame); |
+ int stack_slots = 0; // Will contain stack slot count of frame. |
+ offset = js_frame->LookupExceptionHandlerInTable(&stack_slots); |
+ if (offset < 0) continue; |
- // Restore the next handler. |
- thread_local_top()->handler_ = handler->next()->address(); |
+ // Compute the stack pointer from the frame pointer. This ensures that |
+ // argument slots on the stack are dropped as returning would. |
+ Address return_sp = frame->fp() - |
+ StandardFrameConstants::kFixedFrameSizeFromFp - |
+ stack_slots * kPointerSize; |
- // Gather information from the handler. |
+ // Gather information from the frame. |
code = frame->LookupCode(); |
- context = handler->context(); |
- offset = Smi::cast(code->handler_table()->get(handler->index()))->value(); |
- handler_sp = handler->address() + StackHandlerConstants::kSize; |
+ handler_sp = return_sp; |
handler_fp = frame->fp(); |
break; |
} |
- // For optimized frames we perform a lookup in the handler table. |
- if (frame->is_optimized() && catchable_by_js) { |
- Code* frame_code = frame->LookupCode(); |
- DCHECK(frame_code->is_optimized_code()); |
- int pc_offset = static_cast<int>(frame->pc() - frame_code->entry()); |
- int handler_offset = LookupInHandlerTable(frame_code, pc_offset); |
- if (handler_offset < 0) continue; |
+ // For JavaScript frames we perform a range lookup in the handler table. |
+ if (frame->is_java_script() && catchable_by_js) { |
+ JavaScriptFrame* js_frame = static_cast<JavaScriptFrame*>(frame); |
+ int stack_slots = 0; // Will contain operand stack depth of handler. |
+ offset = js_frame->LookupExceptionHandlerInTable(&stack_slots); |
+ if (offset < 0) continue; |
// Compute the stack pointer from the frame pointer. This ensures that |
- // argument slots on the stack are dropped as returning would. |
+ // operand stack slots are dropped for nested statements. Also restore |
+ // correct context for the handler which is pushed within the try-block. |
Address return_sp = frame->fp() - |
StandardFrameConstants::kFixedFrameSizeFromFp - |
- frame_code->stack_slots() * kPointerSize; |
+ stack_slots * kPointerSize; |
+ STATIC_ASSERT(TryBlockConstant::kElementCount == 1); |
+ context = Context::cast(Memory::Object_at(return_sp - kPointerSize)); |
// Gather information from the frame. |
- code = frame_code; |
- offset = handler_offset; |
+ code = frame->LookupCode(); |
handler_sp = return_sp; |
handler_fp = frame->fp(); |
break; |
@@ -1103,33 +1095,40 @@ Object* Isolate::FindHandler() { |
} |
-// TODO(mstarzinger): We shouldn't need the exception object here. |
-bool Isolate::PredictWhetherExceptionIsCaught(Object* exception) { |
- if (IsExternalHandlerOnTop(exception)) return true; |
+Isolate::CatchType Isolate::PredictExceptionCatcher() { |
+ Address external_handler = thread_local_top()->try_catch_handler_address(); |
+ Address entry_handler = Isolate::handler(thread_local_top()); |
+ if (IsExternalHandlerOnTop(nullptr)) return CAUGHT_BY_EXTERNAL; |
- // Search for a JavaScript handler by performing a full walk over the stack |
- // and dispatching according to the frame type. |
+ // Search for an exception handler by performing a full walk over the stack. |
for (StackFrameIterator iter(this); !iter.done(); iter.Advance()) { |
StackFrame* frame = iter.frame(); |
- // For JavaScript frames which have a handler, we use the handler. |
- if (frame->is_java_script() && frame->HasHandler()) { |
- return true; |
+ // For JSEntryStub frames we update the JS_ENTRY handler. |
+ if (frame->is_entry() || frame->is_entry_construct()) { |
+ entry_handler = frame->top_handler()->next()->address(); |
} |
- // For optimized frames we perform a lookup in the handler table. |
- if (frame->is_optimized()) { |
- Code* frame_code = frame->LookupCode(); |
- DCHECK(frame_code->is_optimized_code()); |
- int pc_offset = static_cast<int>(frame->pc() - frame_code->entry()); |
- int handler_offset = LookupInHandlerTable(frame_code, pc_offset); |
- if (handler_offset < 0) continue; |
- return true; |
+ // For JavaScript frames we perform a lookup in the handler table. |
+ if (frame->is_java_script()) { |
+ JavaScriptFrame* js_frame = static_cast<JavaScriptFrame*>(frame); |
+ int stack_slots = 0; // The computed stack slot count is not used. |
+ if (js_frame->LookupExceptionHandlerInTable(&stack_slots) > 0) { |
+ return CAUGHT_BY_JAVASCRIPT; |
+ } |
+ } |
+ |
+ // The exception has been externally caught if and only if there is an |
+ // external handler which is on top of the top-most JS_ENTRY handler. |
+ if (external_handler != nullptr && !try_catch_handler()->is_verbose_) { |
+ if (entry_handler == nullptr || entry_handler > external_handler) { |
+ return CAUGHT_BY_EXTERNAL; |
+ } |
} |
} |
// Handler not found. |
- return false; |
+ return NOT_CAUGHT; |
} |
@@ -1511,13 +1510,16 @@ bool Isolate::OptionalRescheduleException(bool is_bottom_call) { |
} |
-void Isolate::PushPromise(Handle<JSObject> promise) { |
+void Isolate::PushPromise(Handle<JSObject> promise, |
+ Handle<JSFunction> function) { |
ThreadLocalTop* tltop = thread_local_top(); |
PromiseOnStack* prev = tltop->promise_on_stack_; |
- StackHandler* handler = StackHandler::FromAddress(Isolate::handler(tltop)); |
- Handle<JSObject> global_handle = |
+ Handle<JSObject> global_promise = |
Handle<JSObject>::cast(global_handles()->Create(*promise)); |
- tltop->promise_on_stack_ = new PromiseOnStack(handler, global_handle, prev); |
+ Handle<JSFunction> global_function = |
+ Handle<JSFunction>::cast(global_handles()->Create(*function)); |
+ tltop->promise_on_stack_ = |
+ new PromiseOnStack(global_function, global_promise, prev); |
} |
@@ -1525,10 +1527,12 @@ void Isolate::PopPromise() { |
ThreadLocalTop* tltop = thread_local_top(); |
if (tltop->promise_on_stack_ == NULL) return; |
PromiseOnStack* prev = tltop->promise_on_stack_->prev(); |
- Handle<Object> global_handle = tltop->promise_on_stack_->promise(); |
+ Handle<Object> global_function = tltop->promise_on_stack_->function(); |
+ Handle<Object> global_promise = tltop->promise_on_stack_->promise(); |
delete tltop->promise_on_stack_; |
tltop->promise_on_stack_ = prev; |
- global_handles()->Destroy(global_handle.location()); |
+ global_handles()->Destroy(global_function.location()); |
+ global_handles()->Destroy(global_promise.location()); |
} |
@@ -1536,12 +1540,21 @@ Handle<Object> Isolate::GetPromiseOnStackOnThrow() { |
Handle<Object> undefined = factory()->undefined_value(); |
ThreadLocalTop* tltop = thread_local_top(); |
if (tltop->promise_on_stack_ == NULL) return undefined; |
- StackHandler* promise_try = tltop->promise_on_stack_->handler(); |
- // Find the top-most try-catch handler. |
- StackHandler* handler = StackHandler::FromAddress(Isolate::handler(tltop)); |
- // Throwing inside a Promise only leads to a reject if not caught by an inner |
- // try-catch or try-finally. |
- if (handler == promise_try) return tltop->promise_on_stack_->promise(); |
+ Handle<JSFunction> promise_function = tltop->promise_on_stack_->function(); |
+ // Find the top-most try-catch or try-finally handler. |
+ if (PredictExceptionCatcher() != CAUGHT_BY_JAVASCRIPT) return undefined; |
+ for (JavaScriptFrameIterator it(this); !it.done(); it.Advance()) { |
+ JavaScriptFrame* frame = it.frame(); |
+ int stack_slots = 0; // The computed stack slot count is not used. |
+ if (frame->LookupExceptionHandlerInTable(&stack_slots) > 0) { |
+ // Throwing inside a Promise only leads to a reject if not caught by an |
+ // inner try-catch or try-finally. |
+ if (frame->function() == *promise_function) { |
+ return tltop->promise_on_stack_->promise(); |
+ } |
+ return undefined; |
+ } |
+ } |
return undefined; |
} |