| Index: src/isolate.cc
|
| diff --git a/src/isolate.cc b/src/isolate.cc
|
| index adf180db06c7c16e506d0ab83a4b3f5f5202b233..8d32520252318ceac95219a5f8ea76b8696350a3 100644
|
| --- a/src/isolate.cc
|
| +++ b/src/isolate.cc
|
| @@ -312,32 +312,6 @@ void Isolate::PushStackTraceAndDie(unsigned int magic, void* ptr1, void* ptr2,
|
| base::OS::Abort();
|
| }
|
|
|
| -
|
| -// 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(JSFunction* fun,
|
| - Object* caller,
|
| - bool* seen_caller) {
|
| - if ((fun == caller) && !(*seen_caller)) {
|
| - *seen_caller = true;
|
| - return false;
|
| - }
|
| - // Skip all frames until we've seen the caller.
|
| - if (!(*seen_caller)) return false;
|
| - // Functions defined in native scripts are not visible unless directly
|
| - // exposed, in which case the native flag is set.
|
| - // 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 && fun->shared()->IsBuiltin()) {
|
| - return fun->shared()->native();
|
| - }
|
| - return true;
|
| -}
|
| -
|
| static Handle<FixedArray> MaybeGrow(Isolate* isolate,
|
| Handle<FixedArray> elements,
|
| int cur_position, int new_size) {
|
| @@ -354,6 +328,79 @@ static Handle<FixedArray> MaybeGrow(Isolate* isolate,
|
| return elements;
|
| }
|
|
|
| +class StackTraceHelper {
|
| + public:
|
| + StackTraceHelper(Isolate* isolate, Handle<Object> caller)
|
| + : isolate_(isolate), caller_(caller) {
|
| + // If the caller parameter is a function we skip frames until we're
|
| + // under it before starting to collect.
|
| + seen_caller_ = !caller->IsJSFunction();
|
| + encountered_strict_function_ = false;
|
| + sloppy_frames_ = 0;
|
| + }
|
| +
|
| + // The stack trace API should not expose receivers and function
|
| + // objects on frames deeper than the top-most one with a strict mode
|
| + // function. The number of sloppy frames is stored as first element in
|
| + // the result array.
|
| + void CountSloppyFrames(JSFunction* fun) {
|
| + if (!encountered_strict_function_) {
|
| + if (is_strict(fun->shared()->language_mode())) {
|
| + encountered_strict_function_ = true;
|
| + } else {
|
| + sloppy_frames_++;
|
| + }
|
| + }
|
| + }
|
| +
|
| + // Determines whether the given stack frame should be displayed in a stack
|
| + // trace.
|
| + bool IsVisibleInStackTrace(JSFunction* fun) {
|
| + return IsAfterCaller(fun) && IsNotInNativeScript(fun) &&
|
| + IsInSameSecurityContext(fun);
|
| + }
|
| +
|
| + int sloppy_frames() const { return sloppy_frames_; }
|
| +
|
| + private:
|
| + // 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.
|
| + bool IsAfterCaller(JSFunction* fun) {
|
| + if ((fun == *caller_) && !(seen_caller_)) {
|
| + seen_caller_ = true;
|
| + return false;
|
| + }
|
| + // Skip all frames until we've seen the caller.
|
| + if (!seen_caller_) return false;
|
| + return true;
|
| + }
|
| +
|
| + bool IsNotInNativeScript(JSFunction* fun) {
|
| + // Functions defined in native scripts are not visible unless directly
|
| + // exposed, in which case the native flag is set.
|
| + // 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 && fun->shared()->IsBuiltin()) {
|
| + return fun->shared()->native();
|
| + }
|
| + return true;
|
| + }
|
| +
|
| + bool IsInSameSecurityContext(JSFunction* fun) {
|
| + return isolate_->context()->HasSameSecurityTokenAs(fun->context());
|
| + }
|
| +
|
| + Isolate* isolate_;
|
| + Handle<Object> caller_;
|
| +
|
| + bool seen_caller_;
|
| + int sloppy_frames_;
|
| + bool encountered_strict_function_;
|
| +};
|
| +
|
| Handle<Object> Isolate::CaptureSimpleStackTrace(Handle<JSReceiver> error_object,
|
| Handle<Object> caller) {
|
| // Get stack trace limit.
|
| @@ -371,14 +418,11 @@ Handle<Object> Isolate::CaptureSimpleStackTrace(Handle<JSReceiver> error_object,
|
| Handle<FixedArray> elements =
|
| factory()->NewFixedArrayWithHoles(initial_size * 4 + 1);
|
|
|
| - // If the caller parameter is a function we skip frames until we're
|
| - // under it before starting to collect.
|
| - bool seen_caller = !caller->IsJSFunction();
|
| + StackTraceHelper helper(this, caller);
|
| +
|
| // First element is reserved to store the number of sloppy frames.
|
| int cursor = 1;
|
| int frames_seen = 0;
|
| - int sloppy_frames = 0;
|
| - bool encountered_strict_function = false;
|
| for (StackFrameIterator iter(this); !iter.done() && frames_seen < limit;
|
| iter.Advance()) {
|
| StackFrame* frame = iter.frame();
|
| @@ -395,29 +439,16 @@ Handle<Object> Isolate::CaptureSimpleStackTrace(Handle<JSReceiver> error_object,
|
| js_frame->Summarize(&frames);
|
| for (int i = frames.length() - 1; i >= 0; i--) {
|
| Handle<JSFunction> fun = frames[i].function();
|
| - Handle<Object> recv = frames[i].receiver();
|
| +
|
| // Filter out internal frames that we do not want to show.
|
| - if (!IsVisibleInStackTrace(*fun, *caller, &seen_caller)) continue;
|
| - // Filter out frames from other security contexts.
|
| - if (!this->context()->HasSameSecurityTokenAs(fun->context())) {
|
| - continue;
|
| - }
|
| - elements = MaybeGrow(this, elements, cursor, cursor + 4);
|
| + if (!helper.IsVisibleInStackTrace(*fun)) continue;
|
| + helper.CountSloppyFrames(*fun);
|
|
|
| + Handle<Object> recv = frames[i].receiver();
|
| Handle<AbstractCode> abstract_code = frames[i].abstract_code();
|
| -
|
| Handle<Smi> offset(Smi::FromInt(frames[i].code_offset()), this);
|
| - // The stack trace API should not expose receivers and function
|
| - // objects on frames deeper than the top-most one with a strict mode
|
| - // function. The number of sloppy frames is stored as first element in
|
| - // the result array.
|
| - if (!encountered_strict_function) {
|
| - if (is_strict(fun->shared()->language_mode())) {
|
| - encountered_strict_function = true;
|
| - } else {
|
| - sloppy_frames++;
|
| - }
|
| - }
|
| +
|
| + elements = MaybeGrow(this, elements, cursor, cursor + 4);
|
| elements->set(cursor++, *recv);
|
| elements->set(cursor++, *fun);
|
| elements->set(cursor++, *abstract_code);
|
| @@ -429,6 +460,11 @@ Handle<Object> Isolate::CaptureSimpleStackTrace(Handle<JSReceiver> error_object,
|
| case StackFrame::BUILTIN_EXIT: {
|
| BuiltinExitFrame* exit_frame = BuiltinExitFrame::cast(frame);
|
| Handle<JSFunction> fun = handle(exit_frame->function(), this);
|
| +
|
| + // Filter out internal frames that we do not want to show.
|
| + if (!helper.IsVisibleInStackTrace(*fun)) continue;
|
| + helper.CountSloppyFrames(*fun);
|
| +
|
| Handle<Code> code = handle(exit_frame->LookupCode(), this);
|
| int offset =
|
| static_cast<int>(exit_frame->pc() - code->instruction_start());
|
| @@ -469,7 +505,7 @@ Handle<Object> Isolate::CaptureSimpleStackTrace(Handle<JSReceiver> error_object,
|
| break;
|
| }
|
| }
|
| - elements->set(0, Smi::FromInt(sloppy_frames));
|
| + elements->set(0, Smi::FromInt(helper.sloppy_frames()));
|
| elements->Shrink(cursor);
|
| Handle<JSArray> result = factory()->NewJSArrayWithElements(elements);
|
| result->set_length(Smi::FromInt(cursor));
|
|
|