 Chromium Code Reviews
 Chromium Code Reviews Issue 11275186:
  Collect stack trace on stack overflow.  (Closed) 
  Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
    
  
    Issue 11275186:
  Collect stack trace on stack overflow.  (Closed) 
  Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge| 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(); | 
| } |