| Index: src/isolate.cc
|
| diff --git a/src/isolate.cc b/src/isolate.cc
|
| index a40a297c9587756b323f402dd2f89ec744be43fa..859d91381b1c290b2b14a9523656739a82bef2e7 100644
|
| --- a/src/isolate.cc
|
| +++ b/src/isolate.cc
|
| @@ -357,16 +357,21 @@
|
| break;
|
| }
|
| 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.
|
| - bool IsStrictFrame(JSFunction* fun) {
|
| + // function. The number of sloppy frames is stored as first element in
|
| + // the result array.
|
| + void CountSloppyFrames(JSFunction* fun) {
|
| if (!encountered_strict_function_) {
|
| - encountered_strict_function_ = is_strict(fun->shared()->language_mode());
|
| - }
|
| - return 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
|
| @@ -375,6 +380,8 @@
|
| return ShouldIncludeFrame(fun) && IsNotInNativeScript(fun) &&
|
| IsInSameSecurityContext(fun);
|
| }
|
| +
|
| + int sloppy_frames() const { return sloppy_frames_; }
|
|
|
| private:
|
| // This mechanism excludes a number of uninteresting frames from the stack
|
| @@ -421,6 +428,7 @@
|
| const Handle<Object> caller_;
|
| bool skip_next_frame_;
|
|
|
| + int sloppy_frames_;
|
| bool encountered_strict_function_;
|
| };
|
|
|
| @@ -433,38 +441,34 @@
|
| ? Handle<Object>::cast(isolate->factory()->undefined_value())
|
| : in;
|
| }
|
| -
|
| -bool GetStackTraceLimit(Isolate* isolate, int* result) {
|
| - Handle<JSObject> error = isolate->error_function();
|
| - Handle<String> stackTraceLimit =
|
| - isolate->factory()->InternalizeUtf8String("stackTraceLimit");
|
| - DCHECK(!stackTraceLimit.is_null());
|
| -
|
| - Handle<Object> stack_trace_limit =
|
| - JSReceiver::GetDataProperty(error, stackTraceLimit);
|
| - if (!stack_trace_limit->IsNumber()) return false;
|
| -
|
| - // Ensure that limit is not negative.
|
| - *result = Max(FastD2IChecked(stack_trace_limit->Number()), 0);
|
| - return true;
|
| -}
|
| -
|
| -} // namespace
|
| +}
|
|
|
| Handle<Object> Isolate::CaptureSimpleStackTrace(Handle<JSReceiver> error_object,
|
| FrameSkipMode mode,
|
| Handle<Object> caller) {
|
| DisallowJavascriptExecution no_js(this);
|
|
|
| - int limit;
|
| - if (!GetStackTraceLimit(this, &limit)) return factory()->undefined_value();
|
| + // Get stack trace limit.
|
| + Handle<JSObject> error = error_function();
|
| + Handle<String> stackTraceLimit =
|
| + factory()->InternalizeUtf8String("stackTraceLimit");
|
| + DCHECK(!stackTraceLimit.is_null());
|
| + Handle<Object> stack_trace_limit =
|
| + JSReceiver::GetDataProperty(error, stackTraceLimit);
|
| + if (!stack_trace_limit->IsNumber()) return factory()->undefined_value();
|
| + int limit = FastD2IChecked(stack_trace_limit->Number());
|
| + limit = Max(limit, 0); // Ensure that limit is not negative.
|
|
|
| int initial_size = Min(limit, 10);
|
| - Handle<FixedArray> elements = factory()->NewFixedArrayWithHoles(initial_size);
|
| -
|
| - int cursor = 0;
|
| + Handle<FixedArray> elements =
|
| + factory()->NewFixedArrayWithHoles(initial_size * 4 + 1);
|
| +
|
| StackTraceHelper helper(this, mode, caller);
|
| - for (StackFrameIterator iter(this); !iter.done() && cursor < limit;
|
| +
|
| + // First element is reserved to store the number of sloppy frames.
|
| + int cursor = 1;
|
| + int frames_seen = 0;
|
| + for (StackFrameIterator iter(this); !iter.done() && frames_seen < limit;
|
| iter.Advance()) {
|
| StackFrame* frame = iter.frame();
|
|
|
| @@ -483,33 +487,26 @@
|
|
|
| // Filter out internal frames that we do not want to show.
|
| if (!helper.IsVisibleInStackTrace(*fun)) continue;
|
| + helper.CountSloppyFrames(*fun);
|
|
|
| Handle<Object> recv = frames[i].receiver();
|
| Handle<AbstractCode> abstract_code = frames[i].abstract_code();
|
| - const int offset = frames[i].code_offset();
|
| -
|
| - bool force_constructor = false;
|
| if (frame->type() == StackFrame::BUILTIN) {
|
| // Help CallSite::IsConstructor correctly detect hand-written
|
| // construct stubs.
|
| - if (Code::cast(*abstract_code)->is_construct_stub()) {
|
| - force_constructor = true;
|
| + Code* code = Code::cast(*abstract_code);
|
| + if (code->is_construct_stub()) {
|
| + recv = handle(heap()->call_site_constructor_symbol(), this);
|
| }
|
| }
|
| -
|
| - int flags = 0;
|
| - if (helper.IsStrictFrame(*fun)) flags |= StackTraceFrame::kIsStrict;
|
| - if (force_constructor) flags |= StackTraceFrame::kForceConstructor;
|
| -
|
| - Handle<StackTraceFrame> callsite = factory()->NewStackTraceFrame();
|
| - callsite->set_flags(flags);
|
| - callsite->set_receiver(*TheHoleToUndefined(this, recv));
|
| - callsite->set_function(*fun);
|
| - callsite->set_abstract_code(*abstract_code);
|
| - callsite->set_offset(offset);
|
| -
|
| - elements = MaybeGrow(this, elements, cursor, cursor + 1);
|
| - elements->set(cursor++, *callsite);
|
| + Handle<Smi> offset(Smi::FromInt(frames[i].code_offset()), this);
|
| +
|
| + elements = MaybeGrow(this, elements, cursor, cursor + 4);
|
| + elements->set(cursor++, *TheHoleToUndefined(this, recv));
|
| + elements->set(cursor++, *fun);
|
| + elements->set(cursor++, *abstract_code);
|
| + elements->set(cursor++, *offset);
|
| + frames_seen++;
|
| }
|
| } break;
|
|
|
| @@ -519,26 +516,27 @@
|
|
|
| // Filter out internal frames that we do not want to show.
|
| if (!helper.IsVisibleInStackTrace(*fun)) continue;
|
| -
|
| - Handle<Object> recv = handle(exit_frame->receiver(), this);
|
| + helper.CountSloppyFrames(*fun);
|
| +
|
| Handle<Code> code = handle(exit_frame->LookupCode(), this);
|
| - const int offset =
|
| + int offset =
|
| static_cast<int>(exit_frame->pc() - code->instruction_start());
|
|
|
| - int flags = 0;
|
| - if (helper.IsStrictFrame(*fun)) flags |= StackTraceFrame::kIsStrict;
|
| - if (exit_frame->IsConstructor())
|
| - flags |= StackTraceFrame::kForceConstructor;
|
| -
|
| - Handle<StackTraceFrame> callsite = factory()->NewStackTraceFrame();
|
| - callsite->set_flags(flags);
|
| - callsite->set_receiver(*recv);
|
| - callsite->set_function(*fun);
|
| - callsite->set_abstract_code(AbstractCode::cast(*code));
|
| - callsite->set_offset(offset);
|
| -
|
| - elements = MaybeGrow(this, elements, cursor, cursor + 1);
|
| - elements->set(cursor++, *callsite);
|
| + // In order to help CallSite::IsConstructor detect builtin constructors,
|
| + // we reuse the receiver field to pass along a special symbol.
|
| + Handle<Object> recv;
|
| + if (exit_frame->IsConstructor()) {
|
| + recv = factory()->call_site_constructor_symbol();
|
| + } else {
|
| + recv = handle(exit_frame->receiver(), this);
|
| + }
|
| +
|
| + elements = MaybeGrow(this, elements, cursor, cursor + 4);
|
| + elements->set(cursor++, *recv);
|
| + elements->set(cursor++, *fun);
|
| + elements->set(cursor++, *code);
|
| + elements->set(cursor++, Smi::FromInt(offset));
|
| + frames_seen++;
|
| } break;
|
|
|
| case StackFrame::WASM: {
|
| @@ -546,34 +544,24 @@
|
| Code* code = wasm_frame->unchecked_code();
|
| Handle<AbstractCode> abstract_code =
|
| Handle<AbstractCode>(AbstractCode::cast(code), this);
|
| - const int offset =
|
| + int offset =
|
| static_cast<int>(wasm_frame->pc() - code->instruction_start());
|
| -
|
| - // TODO(wasm): The wasm object returned by the WasmFrame should always
|
| - // be a wasm object.
|
| - DCHECK(wasm::IsWasmObject(wasm_frame->wasm_obj()) ||
|
| - wasm_frame->wasm_obj()->IsUndefined(this));
|
| -
|
| - Handle<StackTraceFrame> callsite = factory()->NewStackTraceFrame();
|
| - callsite->set_flags(StackTraceFrame::kIsWasmFrame);
|
| - callsite->set_wasm_object(wasm_frame->wasm_obj());
|
| - callsite->set_wasm_function_index(wasm_frame->function_index());
|
| - callsite->set_abstract_code(*abstract_code);
|
| - callsite->set_offset(offset);
|
| -
|
| - elements = MaybeGrow(this, elements, cursor, cursor + 1);
|
| - elements->set(cursor++, *callsite);
|
| + elements = MaybeGrow(this, elements, cursor, cursor + 4);
|
| + elements->set(cursor++, wasm_frame->wasm_obj());
|
| + elements->set(cursor++, Smi::FromInt(wasm_frame->function_index()));
|
| + elements->set(cursor++, *abstract_code);
|
| + elements->set(cursor++, Smi::FromInt(offset));
|
| + frames_seen++;
|
| } break;
|
|
|
| default:
|
| break;
|
| }
|
| }
|
| -
|
| + elements->set(0, Smi::FromInt(helper.sloppy_frames()));
|
| elements->Shrink(cursor);
|
| Handle<JSArray> result = factory()->NewJSArrayWithElements(elements);
|
| result->set_length(Smi::FromInt(cursor));
|
| -
|
| // TODO(yangguo): Queue this structured stack trace for preprocessing on GC.
|
| return result;
|
| }
|
| @@ -781,6 +769,19 @@
|
| Handle<String> eval_key_;
|
| Handle<String> constructor_key_;
|
| };
|
| +
|
| +
|
| +int PositionFromStackTrace(Handle<FixedArray> elements, int index) {
|
| + DisallowHeapAllocation no_gc;
|
| + Object* maybe_code = elements->get(index + 2);
|
| + if (maybe_code->IsSmi()) {
|
| + return Smi::cast(maybe_code)->value();
|
| + } else {
|
| + AbstractCode* abstract_code = AbstractCode::cast(maybe_code);
|
| + int code_offset = Smi::cast(elements->get(index + 3))->value();
|
| + return abstract_code->SourcePosition(code_offset);
|
| + }
|
| +}
|
|
|
| Handle<JSArray> Isolate::CaptureCurrentStackTrace(
|
| int frame_limit, StackTrace::StackTraceOptions options) {
|
| @@ -1426,26 +1427,36 @@
|
|
|
|
|
| void Isolate::PrintCurrentStackTrace(FILE* out) {
|
| - for (StackTraceFrameIterator it(this); !it.done(); it.Advance()) {
|
| - if (!it.is_javascript()) continue;
|
| -
|
| + StackTraceFrameIterator it(this);
|
| + while (!it.done()) {
|
| HandleScope scope(this);
|
| - JavaScriptFrame* frame = it.javascript_frame();
|
| -
|
| // Find code position if recorded in relocation info.
|
| - AbstractCode* abstract_code = AbstractCode::cast(frame->LookupCode());
|
| - const int code_offset =
|
| - static_cast<int>(frame->pc() - abstract_code->instruction_start());
|
| -
|
| - Handle<StackTraceFrame> st_frame = factory()->NewStackTraceFrame();
|
| -
|
| - st_frame->set_receiver(frame->receiver());
|
| - st_frame->set_function(frame->function());
|
| - st_frame->set_abstract_code(abstract_code);
|
| - st_frame->set_offset(code_offset);
|
| -
|
| + StandardFrame* frame = it.frame();
|
| + AbstractCode* abstract_code;
|
| + int code_offset;
|
| + if (frame->is_interpreted()) {
|
| + InterpretedFrame* iframe = reinterpret_cast<InterpretedFrame*>(frame);
|
| + abstract_code = AbstractCode::cast(iframe->GetBytecodeArray());
|
| + code_offset = iframe->GetBytecodeOffset();
|
| + } else {
|
| + DCHECK(frame->is_java_script() || frame->is_wasm());
|
| + Code* code = frame->LookupCode();
|
| + abstract_code = AbstractCode::cast(code);
|
| + code_offset = static_cast<int>(frame->pc() - code->instruction_start());
|
| + }
|
| + int pos = abstract_code->SourcePosition(code_offset);
|
| + JavaScriptFrame* js_frame = JavaScriptFrame::cast(frame);
|
| + Handle<Object> pos_obj(Smi::FromInt(pos), this);
|
| + // Fetch function and receiver.
|
| + Handle<JSFunction> fun(js_frame->function(), this);
|
| + Handle<Object> recv(js_frame->receiver(), this);
|
| + // Advance to the next JavaScript frame and determine if the
|
| + // current frame is the top-level frame.
|
| + it.Advance();
|
| + Handle<Object> is_top_level = factory()->ToBoolean(it.done());
|
| // Generate and print stack trace line.
|
| - Handle<String> line = st_frame->ToString();
|
| + Handle<String> line =
|
| + Execution::GetStackTraceLine(recv, fun, pos_obj, is_top_level);
|
| if (line->length() > 0) {
|
| line->PrintOn(out);
|
| PrintF(out, "\n");
|
| @@ -1514,24 +1525,21 @@
|
| Handle<JSArray> simple_stack_trace = Handle<JSArray>::cast(property);
|
|
|
| Handle<FixedArray> elements(FixedArray::cast(simple_stack_trace->elements()));
|
| - const int elements_limit = Smi::cast(simple_stack_trace->length())->value();
|
| -
|
| - for (int i = 0; i < elements_limit; i++) {
|
| - DCHECK(elements->get(i)->IsStackTraceFrame());
|
| - Handle<StackTraceFrame> frame(StackTraceFrame::cast(elements->get(i)));
|
| -
|
| - if (frame->IsWasmFrame()) {
|
| + int elements_limit = Smi::cast(simple_stack_trace->length())->value();
|
| +
|
| + for (int i = 1; i < elements_limit; i += 4) {
|
| + Handle<Object> fun_obj = handle(elements->get(i + 1), this);
|
| + if (fun_obj->IsSmi()) {
|
| // TODO(clemensh): handle wasm frames
|
| return false;
|
| }
|
| -
|
| - Handle<JSFunction> fun = handle(frame->function());
|
| + Handle<JSFunction> fun = Handle<JSFunction>::cast(fun_obj);
|
| if (!fun->shared()->IsSubjectToDebugging()) continue;
|
|
|
| Object* script = fun->shared()->script();
|
| if (script->IsScript() &&
|
| !(Script::cast(script)->source()->IsUndefined(this))) {
|
| - const int pos = frame->GetPosition();
|
| + int pos = PositionFromStackTrace(elements, i);
|
| Handle<Script> casted_script(Script::cast(script));
|
| *target = MessageLocation(casted_script, pos, pos + 1);
|
| return true;
|
|
|