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; |