summaryrefslogtreecommitdiff
path: root/deps/v8/src/isolate.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/isolate.cc')
-rw-r--r--deps/v8/src/isolate.cc786
1 files changed, 408 insertions, 378 deletions
diff --git a/deps/v8/src/isolate.cc b/deps/v8/src/isolate.cc
index 2c8367d7a1..e9713dbec0 100644
--- a/deps/v8/src/isolate.cc
+++ b/deps/v8/src/isolate.cc
@@ -34,8 +34,8 @@
#include "src/runtime-profiler.h"
#include "src/sampler.h"
#include "src/scopeinfo.h"
-#include "src/serialize.h"
#include "src/simulator.h"
+#include "src/snapshot/serialize.h"
#include "src/version.h"
#include "src/vm-state-inl.h"
@@ -82,16 +82,13 @@ void ThreadLocalTop::InitializeInternal() {
external_caught_exception_ = false;
failed_access_check_callback_ = NULL;
save_context_ = NULL;
- catcher_ = NULL;
promise_on_stack_ = NULL;
// These members are re-initialized later after deserialization
// is complete.
pending_exception_ = NULL;
- has_pending_message_ = false;
rethrowing_message_ = false;
pending_message_obj_ = NULL;
- pending_message_script_ = NULL;
scheduled_exception_ = NULL;
}
@@ -190,7 +187,6 @@ void Isolate::Iterate(ObjectVisitor* v, ThreadLocalTop* thread) {
// Visit the roots from the top for a given thread.
v->VisitPointer(&thread->pending_exception_);
v->VisitPointer(&(thread->pending_message_obj_));
- v->VisitPointer(bit_cast<Object**>(&(thread->pending_message_script_)));
v->VisitPointer(bit_cast<Object**>(&(thread->context_)));
v->VisitPointer(&thread->scheduled_exception_);
@@ -199,7 +195,6 @@ void Isolate::Iterate(ObjectVisitor* v, ThreadLocalTop* thread) {
block = block->next_) {
v->VisitPointer(bit_cast<Object**>(&(block->exception_)));
v->VisitPointer(bit_cast<Object**>(&(block->message_obj_)));
- v->VisitPointer(bit_cast<Object**>(&(block->message_script_)));
}
// Iterate over pointers on native execution stack.
@@ -255,7 +250,6 @@ void Isolate::RegisterTryCatchHandler(v8::TryCatch* that) {
void Isolate::UnregisterTryCatchHandler(v8::TryCatch* that) {
DCHECK(thread_local_top()->try_catch_handler() == that);
thread_local_top()->set_try_catch_handler(that->next_);
- thread_local_top()->catcher_ = NULL;
}
@@ -550,7 +544,7 @@ class CaptureStackTraceHelper {
}
if (!function_key_.is_null()) {
- Handle<Object> fun_name(fun->shared()->DebugName(), isolate_);
+ Handle<Object> fun_name = JSFunction::GetDebugName(fun);
JSObject::AddProperty(stack_frame, function_key_, fun_name, NONE);
}
@@ -611,7 +605,7 @@ Handle<JSArray> Isolate::GetDetailedFromSimpleStackTrace(
Address pc = code->address() + offset->value();
bool is_constructor =
recv->IsJSObject() &&
- Handle<JSObject>::cast(recv)->map()->constructor() == *fun;
+ Handle<JSObject>::cast(recv)->map()->GetConstructor() == *fun;
Handle<JSObject> stack_frame =
helper.NewStackFrameObject(fun, code, pc, is_constructor);
@@ -724,7 +718,9 @@ void Isolate::SetFailedAccessCheckCallback(
static inline AccessCheckInfo* GetAccessCheckInfo(Isolate* isolate,
Handle<JSObject> receiver) {
- JSFunction* constructor = JSFunction::cast(receiver->map()->constructor());
+ Object* maybe_constructor = receiver->map()->GetConstructor();
+ if (!maybe_constructor->IsJSFunction()) return NULL;
+ JSFunction* constructor = JSFunction::cast(maybe_constructor);
if (!constructor->shared()->IsApiFunction()) return NULL;
Object* data_obj =
@@ -735,15 +731,16 @@ static inline AccessCheckInfo* GetAccessCheckInfo(Isolate* isolate,
}
-void Isolate::ReportFailedAccessCheck(Handle<JSObject> receiver,
- v8::AccessType type) {
+static void ThrowAccessCheckError(Isolate* isolate) {
+ Handle<String> message =
+ isolate->factory()->InternalizeUtf8String("no access");
+ isolate->ScheduleThrow(*isolate->factory()->NewTypeError(message));
+}
+
+
+void Isolate::ReportFailedAccessCheck(Handle<JSObject> receiver) {
if (!thread_local_top()->failed_access_check_callback_) {
- Handle<String> message = factory()->InternalizeUtf8String("no access");
- Handle<Object> error;
- ASSIGN_RETURN_ON_EXCEPTION_VALUE(
- this, error, factory()->NewTypeError(message), /* void */);
- ScheduleThrow(*error);
- return;
+ return ThrowAccessCheckError(this);
}
DCHECK(receiver->IsAccessCheckNeeded());
@@ -754,47 +751,17 @@ void Isolate::ReportFailedAccessCheck(Handle<JSObject> receiver,
Handle<Object> data;
{ DisallowHeapAllocation no_gc;
AccessCheckInfo* access_check_info = GetAccessCheckInfo(this, receiver);
- if (!access_check_info) return;
+ if (!access_check_info) {
+ AllowHeapAllocation doesnt_matter_anymore;
+ return ThrowAccessCheckError(this);
+ }
data = handle(access_check_info->data(), this);
}
// Leaving JavaScript.
VMState<EXTERNAL> state(this);
thread_local_top()->failed_access_check_callback_(
- v8::Utils::ToLocal(receiver),
- type,
- v8::Utils::ToLocal(data));
-}
-
-
-enum MayAccessDecision {
- YES, NO, UNKNOWN
-};
-
-
-static MayAccessDecision MayAccessPreCheck(Isolate* isolate,
- Handle<JSObject> receiver,
- v8::AccessType type) {
- DisallowHeapAllocation no_gc;
- // During bootstrapping, callback functions are not enabled yet.
- if (isolate->bootstrapper()->IsActive()) return YES;
-
- if (receiver->IsJSGlobalProxy()) {
- Object* receiver_context = JSGlobalProxy::cast(*receiver)->native_context();
- if (!receiver_context->IsContext()) return NO;
-
- // Get the native context of current top context.
- // avoid using Isolate::native_context() because it uses Handle.
- Context* native_context =
- isolate->context()->global_object()->native_context();
- if (receiver_context == native_context) return YES;
-
- if (Context::cast(receiver_context)->security_token() ==
- native_context->security_token())
- return YES;
- }
-
- return UNKNOWN;
+ v8::Utils::ToLocal(receiver), v8::ACCESS_HAS, v8::Utils::ToLocal(data));
}
@@ -810,21 +777,33 @@ bool Isolate::IsInternallyUsedPropertyName(Object* name) {
}
-bool Isolate::MayNamedAccess(Handle<JSObject> receiver,
- Handle<Object> key,
- v8::AccessType type) {
+bool Isolate::MayAccess(Handle<JSObject> receiver) {
DCHECK(receiver->IsJSGlobalProxy() || receiver->IsAccessCheckNeeded());
- // Skip checks for internally used properties. Note, we do not
- // require existence of a context in this case.
- if (IsInternallyUsedPropertyName(key)) return true;
-
// Check for compatibility between the security tokens in the
// current lexical context and the accessed object.
DCHECK(context());
- MayAccessDecision decision = MayAccessPreCheck(this, receiver, type);
- if (decision != UNKNOWN) return decision == YES;
+ {
+ DisallowHeapAllocation no_gc;
+ // During bootstrapping, callback functions are not enabled yet.
+ if (bootstrapper()->IsActive()) return true;
+
+ if (receiver->IsJSGlobalProxy()) {
+ Object* receiver_context =
+ JSGlobalProxy::cast(*receiver)->native_context();
+ if (!receiver_context->IsContext()) return false;
+
+ // Get the native context of current top context.
+ // avoid using Isolate::native_context() because it uses Handle.
+ Context* native_context = context()->global_object()->native_context();
+ if (receiver_context == native_context) return true;
+
+ if (Context::cast(receiver_context)->security_token() ==
+ native_context->security_token())
+ return true;
+ }
+ }
HandleScope scope(this);
Handle<Object> data;
@@ -838,47 +817,13 @@ bool Isolate::MayNamedAccess(Handle<JSObject> receiver,
data = handle(access_check_info->data(), this);
}
- LOG(this, ApiNamedSecurityCheck(*key));
+ LOG(this, ApiSecurityCheck());
// Leaving JavaScript.
VMState<EXTERNAL> state(this);
- return callback(v8::Utils::ToLocal(receiver),
- v8::Utils::ToLocal(key),
- type,
- v8::Utils::ToLocal(data));
-}
-
-
-bool Isolate::MayIndexedAccess(Handle<JSObject> receiver,
- uint32_t index,
- v8::AccessType type) {
- DCHECK(receiver->IsJSGlobalProxy() || receiver->IsAccessCheckNeeded());
- // Check for compatibility between the security tokens in the
- // current lexical context and the accessed object.
- DCHECK(context());
-
- MayAccessDecision decision = MayAccessPreCheck(this, receiver, type);
- if (decision != UNKNOWN) return decision == YES;
-
- HandleScope scope(this);
- Handle<Object> data;
- v8::IndexedSecurityCallback callback;
- { DisallowHeapAllocation no_gc;
- // Get named access check callback
- AccessCheckInfo* access_check_info = GetAccessCheckInfo(this, receiver);
- if (!access_check_info) return false;
- Object* fun_obj = access_check_info->indexed_callback();
- callback = v8::ToCData<v8::IndexedSecurityCallback>(fun_obj);
- if (!callback) return false;
- data = handle(access_check_info->data(), this);
- }
-
- LOG(this, ApiIndexedSecurityCheck(index));
-
- // Leaving JavaScript.
- VMState<EXTERNAL> state(this);
- return callback(
- v8::Utils::ToLocal(receiver), index, type, v8::Utils::ToLocal(data));
+ Handle<Object> key = factory()->undefined_value();
+ return callback(v8::Utils::ToLocal(receiver), v8::Utils::ToLocal(key),
+ v8::ACCESS_HAS, v8::Utils::ToLocal(data));
}
@@ -895,7 +840,7 @@ Object* Isolate::StackOverflow() {
Handle<JSObject> boilerplate = Handle<JSObject>::cast(
Object::GetProperty(js_builtins_object(), key).ToHandleChecked());
Handle<JSObject> exception = factory()->CopyJSObject(boilerplate);
- DoThrow(*exception, NULL);
+ Throw(*exception, nullptr);
CaptureAndSetSimpleStackTrace(exception, factory()->undefined_value());
return heap()->exception();
@@ -903,8 +848,7 @@ Object* Isolate::StackOverflow() {
Object* Isolate::TerminateExecution() {
- DoThrow(heap_.termination_exception(), NULL);
- return heap()->exception();
+ return Throw(heap_.termination_exception(), nullptr);
}
@@ -949,19 +893,119 @@ void Isolate::InvokeApiInterruptCallbacks() {
}
+void ReportBootstrappingException(Handle<Object> exception,
+ MessageLocation* location) {
+ base::OS::PrintError("Exception thrown during bootstrapping\n");
+ if (location == NULL || location->script().is_null()) return;
+ // We are bootstrapping and caught an error where the location is set
+ // and we have a script for the location.
+ // In this case we could have an extension (or an internal error
+ // somewhere) and we print out the line number at which the error occured
+ // to the console for easier debugging.
+ int line_number =
+ location->script()->GetLineNumber(location->start_pos()) + 1;
+ if (exception->IsString() && location->script()->name()->IsString()) {
+ base::OS::PrintError(
+ "Extension or internal compilation error: %s in %s at line %d.\n",
+ String::cast(*exception)->ToCString().get(),
+ String::cast(location->script()->name())->ToCString().get(),
+ line_number);
+ } else if (location->script()->name()->IsString()) {
+ base::OS::PrintError(
+ "Extension or internal compilation error in %s at line %d.\n",
+ String::cast(location->script()->name())->ToCString().get(),
+ line_number);
+ } else {
+ base::OS::PrintError("Extension or internal compilation error.\n");
+ }
+#ifdef OBJECT_PRINT
+ // Since comments and empty lines have been stripped from the source of
+ // builtins, print the actual source here so that line numbers match.
+ if (location->script()->source()->IsString()) {
+ Handle<String> src(String::cast(location->script()->source()));
+ PrintF("Failing script:\n");
+ int len = src->length();
+ int line_number = 1;
+ PrintF("%5d: ", line_number);
+ for (int i = 0; i < len; i++) {
+ uint16_t character = src->Get(i);
+ PrintF("%c", character);
+ if (character == '\n' && i < len - 2) {
+ PrintF("%5d: ", ++line_number);
+ }
+ }
+ }
+#endif
+}
+
+
Object* Isolate::Throw(Object* exception, MessageLocation* location) {
- DoThrow(exception, location);
+ DCHECK(!has_pending_exception());
+
+ HandleScope scope(this);
+ Handle<Object> exception_handle(exception, this);
+
+ // Determine whether a message needs to be created for the given exception
+ // depending on the following criteria:
+ // 1) External v8::TryCatch missing: Always create a message because any
+ // JavaScript handler for a finally-block might re-throw to top-level.
+ // 2) External v8::TryCatch exists: Only create a message if the handler
+ // captures messages or is verbose (which reports despite the catch).
+ // 3) ReThrow from v8::TryCatch: The message from a previous throw still
+ // exists and we preserve it instead of creating a new message.
+ bool requires_message = try_catch_handler() == nullptr ||
+ try_catch_handler()->is_verbose_ ||
+ try_catch_handler()->capture_message_;
+ bool rethrowing_message = thread_local_top()->rethrowing_message_;
+
+ thread_local_top()->rethrowing_message_ = false;
+
+ // Notify debugger of exception.
+ if (is_catchable_by_javascript(exception)) {
+ debug()->OnThrow(exception_handle);
+ }
+
+ // Generate the message if required.
+ if (requires_message && !rethrowing_message) {
+ MessageLocation potential_computed_location;
+ if (location == NULL) {
+ // If no location was specified we use a computed one instead.
+ ComputeLocation(&potential_computed_location);
+ location = &potential_computed_location;
+ }
+
+ if (bootstrapper()->IsActive()) {
+ // It's not safe to try to make message objects or collect stack traces
+ // while the bootstrapper is active since the infrastructure may not have
+ // been properly initialized.
+ ReportBootstrappingException(exception_handle, location);
+ } else {
+ Handle<Object> message_obj = CreateMessage(exception_handle, location);
+ thread_local_top()->pending_message_obj_ = *message_obj;
+
+ // If the abort-on-uncaught-exception flag is specified, abort on any
+ // exception not caught by JavaScript, even when an external handler is
+ // 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 &&
+ 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());
+ PrintCurrentStackTrace(stderr);
+ base::OS::Abort();
+ }
+ }
+ }
+
+ // Set the exception being thrown.
+ set_pending_exception(*exception_handle);
return heap()->exception();
}
Object* Isolate::ReThrow(Object* exception) {
- bool can_be_caught_externally = false;
- bool catchable_by_javascript = is_catchable_by_javascript(exception);
- ShouldReportException(&can_be_caught_externally, catchable_by_javascript);
-
- thread_local_top()->catcher_ = can_be_caught_externally ?
- try_catch_handler() : NULL;
+ DCHECK(!has_pending_exception());
// Set the exception being re-thrown.
set_pending_exception(exception);
@@ -969,9 +1013,138 @@ Object* Isolate::ReThrow(Object* exception) {
}
+Object* Isolate::FindHandler() {
+ Object* exception = pending_exception();
+
+ Code* code = nullptr;
+ Context* context = nullptr;
+ intptr_t offset = 0;
+ Address handler_sp = nullptr;
+ Address handler_fp = nullptr;
+
+ // Special handling of termination exceptions, uncatchable by JavaScript code,
+ // we unwind the handlers until the top ENTRY handler is found.
+ bool catchable_by_js = is_catchable_by_javascript(exception);
+
+ // Compute handler and stack unwinding information by performing a full walk
+ // over the stack and dispatching according to the frame type.
+ for (StackFrameIterator iter(this); !iter.done(); iter.Advance()) {
+ StackFrame* frame = iter.frame();
+
+ // For JSEntryStub frames we always have a handler.
+ if (frame->is_entry() || frame->is_entry_construct()) {
+ StackHandler* handler = frame->top_handler();
+
+ // Restore the next handler.
+ thread_local_top()->handler_ = handler->next()->address();
+
+ // Gather information from the handler.
+ code = frame->LookupCode();
+ handler_sp = handler->address() + StackHandlerConstants::kSize;
+ offset = Smi::cast(code->handler_table()->get(0))->value();
+ break;
+ }
+
+ // 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;
+
+ // 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 frame.
+ code = frame->LookupCode();
+ handler_sp = return_sp;
+ handler_fp = frame->fp();
+ break;
+ }
+
+ // 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
+ // 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 -
+ stack_slots * kPointerSize;
+ STATIC_ASSERT(TryBlockConstant::kElementCount == 1);
+ context = Context::cast(Memory::Object_at(return_sp - kPointerSize));
+
+ // Gather information from the frame.
+ code = frame->LookupCode();
+ handler_sp = return_sp;
+ handler_fp = frame->fp();
+ break;
+ }
+ }
+
+ // Handler must exist.
+ CHECK(code != nullptr);
+
+ // Store information to be consumed by the CEntryStub.
+ thread_local_top()->pending_handler_context_ = context;
+ thread_local_top()->pending_handler_code_ = code;
+ thread_local_top()->pending_handler_offset_ = offset;
+ thread_local_top()->pending_handler_fp_ = handler_fp;
+ thread_local_top()->pending_handler_sp_ = handler_sp;
+
+ // Return and clear pending exception.
+ clear_pending_exception();
+ return exception;
+}
+
+
+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 an exception handler by performing a full walk over the stack.
+ for (StackFrameIterator iter(this); !iter.done(); iter.Advance()) {
+ StackFrame* frame = iter.frame();
+
+ // 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 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 NOT_CAUGHT;
+}
+
+
Object* Isolate::ThrowIllegalOperation() {
if (FLAG_stack_trace_on_illegal) PrintStack(stdout);
- return Throw(heap_.illegal_access_string());
+ return Throw(heap()->illegal_access_string());
}
@@ -994,13 +1167,8 @@ void Isolate::RestorePendingMessageFromTryCatch(v8::TryCatch* handler) {
DCHECK(handler->rethrow_);
DCHECK(handler->capture_message_);
Object* message = reinterpret_cast<Object*>(handler->message_obj_);
- Object* script = reinterpret_cast<Object*>(handler->message_script_);
DCHECK(message->IsJSMessageObject() || message->IsTheHole());
- DCHECK(script->IsScript() || script->IsTheHole());
thread_local_top()->pending_message_obj_ = message;
- thread_local_top()->pending_message_script_ = script;
- thread_local_top()->pending_message_start_pos_ = handler->message_start_pos_;
- thread_local_top()->pending_message_end_pos_ = handler->message_end_pos_;
}
@@ -1127,37 +1295,6 @@ bool Isolate::ComputeLocationFromStackTrace(MessageLocation* target,
}
-bool Isolate::ShouldReportException(bool* can_be_caught_externally,
- bool catchable_by_javascript) {
- // Find the top-most try-catch handler.
- StackHandler* handler =
- StackHandler::FromAddress(Isolate::handler(thread_local_top()));
- while (handler != NULL && !handler->is_catch()) {
- handler = handler->next();
- }
-
- // Get the address of the external handler so we can compare the address to
- // determine which one is closer to the top of the stack.
- Address external_handler_address =
- thread_local_top()->try_catch_handler_address();
-
- // The exception has been externally caught if and only if there is
- // an external handler which is on top of the top-most try-catch
- // handler.
- *can_be_caught_externally = external_handler_address != NULL &&
- (handler == NULL || handler->address() > external_handler_address ||
- !catchable_by_javascript);
-
- if (*can_be_caught_externally) {
- // Only report the exception if the external handler is verbose.
- return try_catch_handler()->is_verbose_;
- } else {
- // Report the exception if it isn't caught by JavaScript code.
- return handler == NULL;
- }
-}
-
-
// Traverse prototype chain to find out whether the object is derived from
// the Error object.
bool Isolate::IsErrorObject(Handle<Object> obj) {
@@ -1172,7 +1309,7 @@ bool Isolate::IsErrorObject(Handle<Object> obj) {
for (PrototypeIterator iter(this, *obj, PrototypeIterator::START_AT_RECEIVER);
!iter.IsAtEnd(); iter.Advance()) {
if (iter.GetCurrent()->IsJSProxy()) return false;
- if (JSObject::cast(iter.GetCurrent())->map()->constructor() ==
+ if (JSObject::cast(iter.GetCurrent())->map()->GetConstructor() ==
*error_constructor) {
return true;
}
@@ -1180,8 +1317,6 @@ bool Isolate::IsErrorObject(Handle<Object> obj) {
return false;
}
-static int fatal_exception_depth = 0;
-
Handle<JSMessageObject> Isolate::CreateMessage(Handle<Object> exception,
MessageLocation* location) {
@@ -1231,190 +1366,96 @@ Handle<JSMessageObject> Isolate::CreateMessage(Handle<Object> exception,
}
-void ReportBootstrappingException(Handle<Object> exception,
- MessageLocation* location) {
- base::OS::PrintError("Exception thrown during bootstrapping\n");
- if (location == NULL || location->script().is_null()) return;
- // We are bootstrapping and caught an error where the location is set
- // and we have a script for the location.
- // In this case we could have an extension (or an internal error
- // somewhere) and we print out the line number at which the error occured
- // to the console for easier debugging.
- int line_number =
- location->script()->GetLineNumber(location->start_pos()) + 1;
- if (exception->IsString() && location->script()->name()->IsString()) {
- base::OS::PrintError(
- "Extension or internal compilation error: %s in %s at line %d.\n",
- String::cast(*exception)->ToCString().get(),
- String::cast(location->script()->name())->ToCString().get(),
- line_number);
- } else if (location->script()->name()->IsString()) {
- base::OS::PrintError(
- "Extension or internal compilation error in %s at line %d.\n",
- String::cast(location->script()->name())->ToCString().get(),
- line_number);
- } else {
- base::OS::PrintError("Extension or internal compilation error.\n");
- }
-#ifdef OBJECT_PRINT
- // Since comments and empty lines have been stripped from the source of
- // builtins, print the actual source here so that line numbers match.
- if (location->script()->source()->IsString()) {
- Handle<String> src(String::cast(location->script()->source()));
- PrintF("Failing script:\n");
- int len = src->length();
- int line_number = 1;
- PrintF("%5d: ", line_number);
- for (int i = 0; i < len; i++) {
- uint16_t character = src->Get(i);
- PrintF("%c", character);
- if (character == '\n' && i < len - 2) {
- PrintF("%5d: ", ++line_number);
- }
- }
- }
-#endif
-}
+bool Isolate::IsJavaScriptHandlerOnTop(Object* exception) {
+ DCHECK_NE(heap()->the_hole_value(), exception);
+ // For uncatchable exceptions, the JavaScript handler cannot be on top.
+ if (!is_catchable_by_javascript(exception)) return false;
-void Isolate::DoThrow(Object* exception, MessageLocation* location) {
- DCHECK(!has_pending_exception());
+ // Get the top-most JS_ENTRY handler, cannot be on top if it doesn't exist.
+ Address entry_handler = Isolate::handler(thread_local_top());
+ if (entry_handler == nullptr) return false;
- HandleScope scope(this);
- Handle<Object> exception_handle(exception, this);
-
- // Determine reporting and whether the exception is caught externally.
- bool catchable_by_javascript = is_catchable_by_javascript(exception);
- bool can_be_caught_externally = false;
- bool should_report_exception =
- ShouldReportException(&can_be_caught_externally, catchable_by_javascript);
- bool report_exception = catchable_by_javascript && should_report_exception;
- bool try_catch_needs_message =
- can_be_caught_externally && try_catch_handler()->capture_message_;
- bool rethrowing_message = thread_local_top()->rethrowing_message_;
-
- thread_local_top()->rethrowing_message_ = false;
-
- // Notify debugger of exception.
- if (catchable_by_javascript) {
- debug()->OnThrow(exception_handle, report_exception);
- }
+ // Get the address of the external handler so we can compare the address to
+ // determine which one is closer to the top of the stack.
+ Address external_handler = thread_local_top()->try_catch_handler_address();
+ if (external_handler == nullptr) return true;
- // Generate the message if required.
- if (!rethrowing_message && (report_exception || try_catch_needs_message)) {
- MessageLocation potential_computed_location;
- if (location == NULL) {
- // If no location was specified we use a computed one instead.
- ComputeLocation(&potential_computed_location);
- location = &potential_computed_location;
- }
+ // 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.
+ //
+ // Note, that finally clauses would re-throw an exception unless it's aborted
+ // by jumps in control flow (like return, break, etc.) and we'll have another
+ // chance to set proper v8::TryCatch later.
+ return (entry_handler < external_handler);
+}
- if (bootstrapper()->IsActive()) {
- // It's not safe to try to make message objects or collect stack traces
- // while the bootstrapper is active since the infrastructure may not have
- // been properly initialized.
- ReportBootstrappingException(exception_handle, location);
- } else {
- Handle<Object> message_obj = CreateMessage(exception_handle, location);
- thread_local_top()->pending_message_obj_ = *message_obj;
- thread_local_top()->pending_message_script_ = *location->script();
- thread_local_top()->pending_message_start_pos_ = location->start_pos();
- thread_local_top()->pending_message_end_pos_ = location->end_pos();
+bool Isolate::IsExternalHandlerOnTop(Object* exception) {
+ DCHECK_NE(heap()->the_hole_value(), exception);
- // If the abort-on-uncaught-exception flag is specified, abort on any
- // exception not caught by JavaScript, even when an external handler is
- // present. This flag is intended for use by JavaScript developers, so
- // print a user-friendly stack trace (not an internal one).
- if (fatal_exception_depth == 0 && FLAG_abort_on_uncaught_exception &&
- (report_exception || can_be_caught_externally)) {
- fatal_exception_depth++;
- PrintF(stderr, "%s\n\nFROM\n",
- MessageHandler::GetLocalizedMessage(this, message_obj).get());
- PrintCurrentStackTrace(stderr);
- base::OS::Abort();
- }
- }
- }
+ // Get the address of the external handler so we can compare the address to
+ // determine which one is closer to the top of the stack.
+ Address external_handler = thread_local_top()->try_catch_handler_address();
+ if (external_handler == nullptr) return false;
- // Save the message for reporting if the the exception remains uncaught.
- thread_local_top()->has_pending_message_ = report_exception;
+ // For uncatchable exceptions, the external handler is always on top.
+ if (!is_catchable_by_javascript(exception)) return true;
- // Do not forget to clean catcher_ if currently thrown exception cannot
- // be caught. If necessary, ReThrow will update the catcher.
- thread_local_top()->catcher_ = can_be_caught_externally ?
- try_catch_handler() : NULL;
+ // Get the top-most JS_ENTRY handler, cannot be on top if it doesn't exist.
+ Address entry_handler = Isolate::handler(thread_local_top());
+ if (entry_handler == nullptr) return true;
- set_pending_exception(*exception_handle);
+ // 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.
+ //
+ // Note, that finally clauses would re-throw an exception unless it's aborted
+ // by jumps in control flow (like return, break, etc.) and we'll have another
+ // chance to set proper v8::TryCatch later.
+ return (entry_handler > external_handler);
}
-bool Isolate::HasExternalTryCatch() {
- DCHECK(has_pending_exception());
+void Isolate::ReportPendingMessages() {
+ Object* exception = pending_exception();
- return (thread_local_top()->catcher_ != NULL) &&
- (try_catch_handler() == thread_local_top()->catcher_);
-}
+ // Try to propagate the exception to an external v8::TryCatch handler. If
+ // propagation was unsuccessful, then we will get another chance at reporting
+ // the pending message if the exception is re-thrown.
+ bool has_been_propagated = PropagatePendingExceptionToExternalTryCatch();
+ if (!has_been_propagated) return;
+ // Clear the pending message object early to avoid endless recursion.
+ Object* message_obj = thread_local_top_.pending_message_obj_;
+ clear_pending_message();
-bool Isolate::IsFinallyOnTop() {
- // Get the address of the external handler so we can compare the address to
- // determine which one is closer to the top of the stack.
- Address external_handler_address =
- thread_local_top()->try_catch_handler_address();
- DCHECK(external_handler_address != NULL);
-
- // The exception has been externally caught if and only if there is
- // an external handler which is on top of the top-most try-finally
- // handler.
- // There should be no try-catch blocks as they would prohibit us from
- // finding external catcher in the first place (see catcher_ check above).
- //
- // Note, that finally clause would rethrow an exception unless it's
- // aborted by jumps in control flow like return, break, etc. and we'll
- // have another chances to set proper v8::TryCatch.
- StackHandler* handler =
- StackHandler::FromAddress(Isolate::handler(thread_local_top()));
- while (handler != NULL && handler->address() < external_handler_address) {
- DCHECK(!handler->is_catch());
- if (handler->is_finally()) return true;
+ // For uncatchable exceptions we do nothing. If needed, the exception and the
+ // message have already been propagated to v8::TryCatch.
+ if (!is_catchable_by_javascript(exception)) return;
- handler = handler->next();
+ // Determine whether the message needs to be reported to all message handlers
+ // depending on whether and external v8::TryCatch or an internal JavaScript
+ // handler is on top.
+ bool should_report_exception;
+ if (IsExternalHandlerOnTop(exception)) {
+ // Only report the exception if the external handler is verbose.
+ should_report_exception = try_catch_handler()->is_verbose_;
+ } else {
+ // Report the exception if it isn't caught by JavaScript code.
+ should_report_exception = !IsJavaScriptHandlerOnTop(exception);
}
- return false;
-}
-
-
-void Isolate::ReportPendingMessages() {
- DCHECK(has_pending_exception());
- bool can_clear_message = PropagatePendingExceptionToExternalTryCatch();
-
- HandleScope scope(this);
- if (thread_local_top_.pending_exception_ == heap()->termination_exception()) {
- // Do nothing: if needed, the exception has been already propagated to
- // v8::TryCatch.
- } else {
- if (thread_local_top_.has_pending_message_) {
- thread_local_top_.has_pending_message_ = false;
- if (!thread_local_top_.pending_message_obj_->IsTheHole()) {
- HandleScope scope(this);
- Handle<Object> message_obj(thread_local_top_.pending_message_obj_,
- this);
- if (!thread_local_top_.pending_message_script_->IsTheHole()) {
- Handle<Script> script(
- Script::cast(thread_local_top_.pending_message_script_));
- int start_pos = thread_local_top_.pending_message_start_pos_;
- int end_pos = thread_local_top_.pending_message_end_pos_;
- MessageLocation location(script, start_pos, end_pos);
- MessageHandler::ReportMessage(this, &location, message_obj);
- } else {
- MessageHandler::ReportMessage(this, NULL, message_obj);
- }
- }
- }
+ // Actually report the pending message to all message handlers.
+ if (!message_obj->IsTheHole() && should_report_exception) {
+ HandleScope scope(this);
+ Handle<JSMessageObject> message(JSMessageObject::cast(message_obj));
+ Handle<JSValue> script_wrapper(JSValue::cast(message->script()));
+ Handle<Script> script(Script::cast(script_wrapper->value()));
+ int start_pos = message->start_position();
+ int end_pos = message->end_position();
+ MessageLocation location(script, start_pos, end_pos);
+ MessageHandler::ReportMessage(this, &location, message);
}
- if (can_clear_message) clear_pending_message();
}
@@ -1422,12 +1463,13 @@ MessageLocation Isolate::GetMessageLocation() {
DCHECK(has_pending_exception());
if (thread_local_top_.pending_exception_ != heap()->termination_exception() &&
- thread_local_top_.has_pending_message_ &&
!thread_local_top_.pending_message_obj_->IsTheHole()) {
- Handle<Script> script(
- Script::cast(thread_local_top_.pending_message_script_));
- int start_pos = thread_local_top_.pending_message_start_pos_;
- int end_pos = thread_local_top_.pending_message_end_pos_;
+ Handle<JSMessageObject> message_obj(
+ JSMessageObject::cast(thread_local_top_.pending_message_obj_));
+ Handle<JSValue> script_wrapper(JSValue::cast(message_obj->script()));
+ Handle<Script> script(Script::cast(script_wrapper->value()));
+ int start_pos = message_obj->start_position();
+ int end_pos = message_obj->end_position();
return MessageLocation(script, start_pos, end_pos);
}
@@ -1478,13 +1520,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);
}
@@ -1492,10 +1537,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());
}
@@ -1503,17 +1550,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));
- do {
- 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;
}
- handler = handler->next();
- // Throwing inside a Promise can be intercepted by an inner try-catch, so
- // we stop at the first try-catch handler.
- } while (handler != NULL && !handler->is_catch());
+ }
return undefined;
}
@@ -1757,11 +1808,6 @@ void Isolate::TearDown() {
thread_data_table_->RemoveAllThreads(this);
}
- if (serialize_partial_snapshot_cache_ != NULL) {
- delete[] serialize_partial_snapshot_cache_;
- serialize_partial_snapshot_cache_ = NULL;
- }
-
delete this;
// Restore the previous current isolate.
@@ -1775,6 +1821,16 @@ void Isolate::GlobalTearDown() {
}
+void Isolate::ClearSerializerData() {
+ delete external_reference_table_;
+ external_reference_table_ = NULL;
+ delete external_reference_map_;
+ external_reference_map_ = NULL;
+ delete root_index_map_;
+ root_index_map_ = NULL;
+}
+
+
void Isolate::Deinit() {
TRACE_ISOLATE(deinit);
@@ -1822,26 +1878,8 @@ void Isolate::Deinit() {
heap_profiler_ = NULL;
delete cpu_profiler_;
cpu_profiler_ = NULL;
-}
-
-
-void Isolate::PushToPartialSnapshotCache(Object* obj) {
- int length = serialize_partial_snapshot_cache_length();
- int capacity = serialize_partial_snapshot_cache_capacity();
- if (length >= capacity) {
- int new_capacity = static_cast<int>((capacity + 10) * 1.2);
- Object** new_array = new Object*[new_capacity];
- for (int i = 0; i < length; i++) {
- new_array[i] = serialize_partial_snapshot_cache()[i];
- }
- if (capacity != 0) delete[] serialize_partial_snapshot_cache();
- set_serialize_partial_snapshot_cache(new_array);
- set_serialize_partial_snapshot_cache_capacity(new_capacity);
- }
-
- serialize_partial_snapshot_cache()[length] = obj;
- set_serialize_partial_snapshot_cache_length(length + 1);
+ ClearSerializerData();
}
@@ -1930,9 +1968,6 @@ Isolate::~Isolate() {
delete string_stream_debug_object_cache_;
string_stream_debug_object_cache_ = NULL;
- delete external_reference_table_;
- external_reference_table_ = NULL;
-
delete random_number_generator_;
random_number_generator_ = NULL;
@@ -1948,22 +1983,20 @@ void Isolate::InitializeThreadLocal() {
bool Isolate::PropagatePendingExceptionToExternalTryCatch() {
- DCHECK(has_pending_exception());
+ Object* exception = pending_exception();
- bool has_external_try_catch = HasExternalTryCatch();
- if (!has_external_try_catch) {
+ if (IsJavaScriptHandlerOnTop(exception)) {
thread_local_top_.external_caught_exception_ = false;
- return true;
+ return false;
}
- bool catchable_by_js = is_catchable_by_javascript(pending_exception());
- if (catchable_by_js && IsFinallyOnTop()) {
+ if (!IsExternalHandlerOnTop(exception)) {
thread_local_top_.external_caught_exception_ = false;
- return false;
+ return true;
}
thread_local_top_.external_caught_exception_ = true;
- if (thread_local_top_.pending_exception_ == heap()->termination_exception()) {
+ if (!is_catchable_by_javascript(exception)) {
try_catch_handler()->can_continue_ = false;
try_catch_handler()->has_terminated_ = true;
try_catch_handler()->exception_ = heap()->null_value();
@@ -1971,8 +2004,6 @@ bool Isolate::PropagatePendingExceptionToExternalTryCatch() {
v8::TryCatch* handler = try_catch_handler();
DCHECK(thread_local_top_.pending_message_obj_->IsJSMessageObject() ||
thread_local_top_.pending_message_obj_->IsTheHole());
- DCHECK(thread_local_top_.pending_message_script_->IsScript() ||
- thread_local_top_.pending_message_script_->IsTheHole());
handler->can_continue_ = true;
handler->has_terminated_ = false;
handler->exception_ = pending_exception();
@@ -1980,9 +2011,6 @@ bool Isolate::PropagatePendingExceptionToExternalTryCatch() {
if (thread_local_top_.pending_message_obj_->IsTheHole()) return true;
handler->message_obj_ = thread_local_top_.pending_message_obj_;
- handler->message_script_ = thread_local_top_.pending_message_script_;
- handler->message_start_pos_ = thread_local_top_.pending_message_start_pos_;
- handler->message_end_pos_ = thread_local_top_.pending_message_end_pos_;
}
return true;
}
@@ -2088,7 +2116,7 @@ bool Isolate::Init(Deserializer* des) {
if (create_heap_objects) {
// Terminate the cache array with the sentinel so we can iterate.
- PushToPartialSnapshotCache(heap_.undefined_value());
+ partial_snapshot_cache_.Add(heap_.undefined_value());
}
InitializeThreadLocal();
@@ -2589,6 +2617,7 @@ void Isolate::CheckDetachedContextsAfterGC() {
int new_length = 0;
for (int i = 0; i < length; i += 2) {
int mark_sweeps = Smi::cast(detached_contexts->get(i))->value();
+ DCHECK(detached_contexts->get(i + 1)->IsWeakCell());
WeakCell* cell = WeakCell::cast(detached_contexts->get(i + 1));
if (!cell->cleared()) {
detached_contexts->set(new_length, Smi::FromInt(mark_sweeps + 1));
@@ -2602,6 +2631,7 @@ void Isolate::CheckDetachedContextsAfterGC() {
length - new_length, length);
for (int i = 0; i < new_length; i += 2) {
int mark_sweeps = Smi::cast(detached_contexts->get(i))->value();
+ DCHECK(detached_contexts->get(i + 1)->IsWeakCell());
WeakCell* cell = WeakCell::cast(detached_contexts->get(i + 1));
if (mark_sweeps > 3) {
PrintF("detached context 0x%p\n survived %d GCs (leak?)\n",
@@ -2612,8 +2642,8 @@ void Isolate::CheckDetachedContextsAfterGC() {
if (new_length == 0) {
heap()->set_detached_contexts(heap()->empty_fixed_array());
} else if (new_length < length) {
- heap()->RightTrimFixedArray<Heap::FROM_GC>(*detached_contexts,
- length - new_length);
+ heap()->RightTrimFixedArray<Heap::FROM_MUTATOR>(*detached_contexts,
+ length - new_length);
}
}