Chromium Code Reviews| Index: src/isolate.cc |
| diff --git a/src/isolate.cc b/src/isolate.cc |
| index 75e15a454196573fce28a438032a7fe68e966ddb..2265693dbc66ac22155627325393fb8a81b33386 100644 |
| --- a/src/isolate.cc |
| +++ b/src/isolate.cc |
| @@ -553,7 +553,101 @@ 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. |
|
Yang
2012/11/07 11:02:38
This part is simply moved over from runtime.cc
|
| +bool ShowFrameInStackTrace(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); |
| + |
| + StackFrameIterator iter(this); |
| + // 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; |
| + while (!iter.done() && frames_seen < limit) { |
| + StackFrame* raw_frame = iter.frame(); |
| + if (ShowFrameInStackTrace(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); |
| + } |
| + } |
| + iter.Advance(); |
| + } |
| + 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(); |
| @@ -926,12 +1020,15 @@ Failure* Isolate::StackOverflow() { |
| 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); |
| + // Store the raw stack trace as hidden property so that the stack trace |
| + // string can be lazily formatted in javascript. |
| + Handle<JSArray> stack_trace = CaptureSimpleStackTrace( |
| + exception, factory()->undefined_value(), FLAG_stack_trace_limit); |
| + JSObject::SetHiddenProperty(exception, |
| + factory()->hidden_stack_trace_symbol(), |
| + stack_trace); |
| return Failure::Exception(); |
| } |