diff options
Diffstat (limited to 'deps/v8/src/isolate.cc')
-rw-r--r-- | deps/v8/src/isolate.cc | 178 |
1 files changed, 148 insertions, 30 deletions
diff --git a/deps/v8/src/isolate.cc b/deps/v8/src/isolate.cc index 75e15a4541..15d0bdd441 100644 --- a/deps/v8/src/isolate.cc +++ b/deps/v8/src/isolate.cc @@ -426,11 +426,6 @@ char* Isolate::Iterate(ObjectVisitor* v, char* thread_storage) { } -void Isolate::IterateThread(ThreadVisitor* v) { - v->VisitThread(this, thread_local_top()); -} - - void Isolate::IterateThread(ThreadVisitor* v, char* t) { ThreadLocalTop* thread = reinterpret_cast<ThreadLocalTop*>(t); v->VisitThread(this, thread); @@ -553,7 +548,97 @@ void Isolate::PushStackTraceAndDie(unsigned int magic, } -void Isolate::CaptureAndSetCurrentStackTraceFor(Handle<JSObject> error_object) { +// Determines whether the given stack frame should be displayed in +// a stack trace. The caller is the error constructor that asked +// for the stack trace to be collected. The first time a construct +// call to this function is encountered it is skipped. The seen_caller +// in/out parameter is used to remember if the caller has been seen +// yet. +static bool IsVisibleInStackTrace(StackFrame* raw_frame, + Object* caller, + bool* seen_caller) { + // Only display JS frames. + if (!raw_frame->is_java_script()) return false; + JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame); + Object* raw_fun = frame->function(); + // Not sure when this can happen but skip it just in case. + if (!raw_fun->IsJSFunction()) return false; + if ((raw_fun == caller) && !(*seen_caller)) { + *seen_caller = true; + return false; + } + // Skip all frames until we've seen the caller. + if (!(*seen_caller)) return false; + // Also, skip non-visible built-in functions and any call with the builtins + // object as receiver, so as to not reveal either the builtins object or + // an internal function. + // The --builtins-in-stack-traces command line flag allows including + // internal call sites in the stack trace for debugging purposes. + if (!FLAG_builtins_in_stack_traces) { + JSFunction* fun = JSFunction::cast(raw_fun); + if (frame->receiver()->IsJSBuiltinsObject() || + (fun->IsBuiltin() && !fun->shared()->native())) { + return false; + } + } + return true; +} + + +Handle<JSArray> Isolate::CaptureSimpleStackTrace(Handle<JSObject> error_object, + Handle<Object> caller, + int limit) { + limit = Max(limit, 0); // Ensure that limit is not negative. + int initial_size = Min(limit, 10); + Handle<FixedArray> elements = + factory()->NewFixedArrayWithHoles(initial_size * 4); + + // If the caller parameter is a function we skip frames until we're + // under it before starting to collect. + bool seen_caller = !caller->IsJSFunction(); + int cursor = 0; + int frames_seen = 0; + for (StackFrameIterator iter(this); + !iter.done() && frames_seen < limit; + iter.Advance()) { + StackFrame* raw_frame = iter.frame(); + if (IsVisibleInStackTrace(raw_frame, *caller, &seen_caller)) { + frames_seen++; + JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame); + // Set initial size to the maximum inlining level + 1 for the outermost + // function. + List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1); + frame->Summarize(&frames); + for (int i = frames.length() - 1; i >= 0; i--) { + if (cursor + 4 > elements->length()) { + int new_capacity = JSObject::NewElementsCapacity(elements->length()); + Handle<FixedArray> new_elements = + factory()->NewFixedArrayWithHoles(new_capacity); + for (int i = 0; i < cursor; i++) { + new_elements->set(i, elements->get(i)); + } + elements = new_elements; + } + ASSERT(cursor + 4 <= elements->length()); + + Handle<Object> recv = frames[i].receiver(); + Handle<JSFunction> fun = frames[i].function(); + Handle<Code> code = frames[i].code(); + Handle<Smi> offset(Smi::FromInt(frames[i].offset())); + elements->set(cursor++, *recv); + elements->set(cursor++, *fun); + elements->set(cursor++, *code); + elements->set(cursor++, *offset); + } + } + } + Handle<JSArray> result = factory()->NewJSArrayWithElements(elements); + result->set_length(Smi::FromInt(cursor)); + return result; +} + + +void Isolate::CaptureAndSetDetailedStackTrace(Handle<JSObject> error_object) { if (capture_stack_trace_for_uncaught_exceptions_) { // Capture stack trace for a detailed exception message. Handle<String> key = factory()->hidden_stack_trace_symbol(); @@ -574,8 +659,6 @@ Handle<JSArray> Isolate::CaptureCurrentStackTrace( Handle<String> column_key = factory()->LookupAsciiSymbol("column"); Handle<String> line_key = factory()->LookupAsciiSymbol("lineNumber"); Handle<String> script_key = factory()->LookupAsciiSymbol("scriptName"); - Handle<String> name_or_source_url_key = - factory()->LookupAsciiSymbol("nameOrSourceURL"); Handle<String> script_name_or_source_url_key = factory()->LookupAsciiSymbol("scriptNameOrSourceURL"); Handle<String> function_key = factory()->LookupAsciiSymbol("functionName"); @@ -635,18 +718,7 @@ Handle<JSArray> Isolate::CaptureCurrentStackTrace( } if (options & StackTrace::kScriptNameOrSourceURL) { - Handle<Object> script_name(script->name(), this); - Handle<JSValue> script_wrapper = GetScriptWrapper(script); - Handle<Object> property = GetProperty(script_wrapper, - name_or_source_url_key); - ASSERT(property->IsJSFunction()); - Handle<JSFunction> method = Handle<JSFunction>::cast(property); - bool caught_exception; - Handle<Object> result = Execution::TryCall(method, script_wrapper, 0, - NULL, &caught_exception); - if (caught_exception) { - result = factory()->undefined_value(); - } + Handle<Object> result = GetScriptNameOrSourceURL(script); CHECK_NOT_EMPTY_HANDLE(this, JSObject::SetLocalPropertyIgnoreAttributes( stack_frame, script_name_or_source_url_key, @@ -923,15 +995,28 @@ const char* const Isolate::kStackOverflowMessage = Failure* Isolate::StackOverflow() { HandleScope scope; + // At this point we cannot create an Error object using its javascript + // constructor. Instead, we copy the pre-constructed boilerplate and + // attach the stack trace as a hidden property. Handle<String> key = factory()->stack_overflow_symbol(); Handle<JSObject> boilerplate = Handle<JSObject>::cast(GetProperty(js_builtins_object(), key)); - Handle<Object> exception = Copy(boilerplate); - // TODO(1240995): To avoid having to call JavaScript code to compute - // the message for stack overflow exceptions which is very likely to - // double fault with another stack overflow exception, we use a - // precomputed message. + Handle<JSObject> exception = Copy(boilerplate); DoThrow(*exception, NULL); + + // Get stack trace limit. + Handle<Object> error = GetProperty(js_builtins_object(), "$Error"); + if (!error->IsJSObject()) return Failure::Exception(); + Handle<Object> stack_trace_limit = + GetProperty(Handle<JSObject>::cast(error), "stackTraceLimit"); + if (!stack_trace_limit->IsNumber()) return Failure::Exception(); + int limit = static_cast<int>(stack_trace_limit->Number()); + + Handle<JSArray> stack_trace = CaptureSimpleStackTrace( + exception, factory()->undefined_value(), limit); + JSObject::SetHiddenProperty(exception, + factory()->hidden_stack_trace_symbol(), + stack_trace); return Failure::Exception(); } @@ -972,9 +1057,12 @@ void Isolate::ScheduleThrow(Object* exception) { // When scheduling a throw we first throw the exception to get the // error reporting if it is uncaught before rescheduling it. Throw(exception); - thread_local_top()->scheduled_exception_ = pending_exception(); - thread_local_top()->external_caught_exception_ = false; - clear_pending_exception(); + PropagatePendingExceptionToExternalTryCatch(); + if (has_pending_exception()) { + thread_local_top()->scheduled_exception_ = pending_exception(); + thread_local_top()->external_caught_exception_ = false; + clear_pending_exception(); + } } @@ -1138,10 +1226,22 @@ void Isolate::DoThrow(Object* exception, MessageLocation* location) { stack_trace_for_uncaught_exceptions_options_); } } + + Handle<Object> exception_arg = exception_handle; + // If the exception argument is a custom object, turn it into a string + // before throwing as uncaught exception. Note that the pending + // exception object to be set later must not be turned into a string. + if (exception_arg->IsJSObject() && !IsErrorObject(exception_arg)) { + bool failed = false; + exception_arg = Execution::ToDetailString(exception_arg, &failed); + if (failed) { + exception_arg = factory()->LookupAsciiSymbol("exception"); + } + } Handle<Object> message_obj = MessageHandler::MakeMessageObject( "uncaught_exception", location, - HandleVector<Object>(&exception_handle, 1), + HandleVector<Object>(&exception_arg, 1), stack_trace, stack_trace_object); thread_local_top()->pending_message_obj_ = *message_obj; @@ -1264,6 +1364,24 @@ void Isolate::ReportPendingMessages() { } +MessageLocation Isolate::GetMessageLocation() { + ASSERT(has_pending_exception()); + + if (thread_local_top_.pending_exception_ != Failure::OutOfMemoryException() && + thread_local_top_.pending_exception_ != heap()->termination_exception() && + thread_local_top_.has_pending_message_ && + !thread_local_top_.pending_message_obj_->IsTheHole() && + thread_local_top_.pending_message_script_ != NULL) { + Handle<Script> script(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_; + return MessageLocation(script, start_pos, end_pos); + } + + return MessageLocation(); +} + + void Isolate::TraceException(bool flag) { FLAG_trace_exception = flag; // TODO(isolates): This is an unfortunate use. } @@ -1926,7 +2044,7 @@ bool Isolate::Init(Deserializer* des) { // If we are deserializing, log non-function code objects and compiled // functions found in the snapshot. - if (create_heap_objects && + if (!create_heap_objects && (FLAG_log_code || FLAG_ll_prof || logger_->is_logging_code_events())) { HandleScope scope; LOG(this, LogCodeObjects()); |