Index: src/isolate.cc |
diff --git a/src/isolate.cc b/src/isolate.cc |
index a434db3abe04ea3a263723d0398e1a76ba3def44..b41dd37909a6512eb23c4d0a8280f2a75abd7615 100644 |
--- a/src/isolate.cc |
+++ b/src/isolate.cc |
@@ -356,21 +356,16 @@ class StackTraceHelper { |
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. The number of sloppy frames is stored as first element in |
- // the result array. |
- void CountSloppyFrames(JSFunction* fun) { |
+ // function. |
+ bool IsStrictFrame(JSFunction* fun) { |
if (!encountered_strict_function_) { |
- if (is_strict(fun->shared()->language_mode())) { |
- encountered_strict_function_ = true; |
- } else { |
- sloppy_frames_++; |
- } |
+ encountered_strict_function_ = is_strict(fun->shared()->language_mode()); |
} |
+ return encountered_strict_function_; |
} |
// Determines whether the given stack frame should be displayed in a stack |
@@ -380,8 +375,6 @@ class StackTraceHelper { |
IsInSameSecurityContext(fun); |
} |
- int sloppy_frames() const { return sloppy_frames_; } |
- |
private: |
// This mechanism excludes a number of uninteresting frames from the stack |
// trace. This can be be the first frame (which will be a builtin-exit frame |
@@ -427,7 +420,6 @@ class StackTraceHelper { |
const Handle<Object> caller_; |
bool skip_next_frame_; |
- int sloppy_frames_; |
bool encountered_strict_function_; |
}; |
@@ -440,33 +432,40 @@ Handle<Object> TheHoleToUndefined(Isolate* isolate, Handle<Object> in) { |
? 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); |
- // 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 limit; |
+ if (!GetStackTraceLimit(this, &limit)) return factory()->undefined_value(); |
- int initial_size = Min(limit, 10); |
- Handle<FixedArray> elements = |
- factory()->NewFixedArrayWithHoles(initial_size * 4 + 1); |
+ using ESTF = EncodedStackTraceFrame; |
+ int initial_size = Min(limit, 10) * ESTF::kElementsPerFrame; |
+ Handle<FixedArray> elements = factory()->NewFixedArrayWithHoles(initial_size); |
+ int cursor = 0; |
+ int frames_seen = 0; |
StackTraceHelper helper(this, mode, caller); |
- // 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(); |
@@ -486,25 +485,31 @@ Handle<Object> Isolate::CaptureSimpleStackTrace(Handle<JSReceiver> error_object, |
// 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. |
- Code* code = Code::cast(*abstract_code); |
- if (code->is_construct_stub()) { |
- recv = handle(heap()->call_site_constructor_symbol(), this); |
+ if (Code::cast(*abstract_code)->is_construct_stub()) { |
+ force_constructor = true; |
} |
} |
- Handle<Smi> offset(Smi::FromInt(frames[i].code_offset()), this); |
- elements = MaybeGrow(this, elements, cursor, cursor + 4); |
+ int flags = 0; |
+ if (helper.IsStrictFrame(*fun)) flags |= StackTraceFrame::kIsStrict; |
+ if (force_constructor) flags |= StackTraceFrame::kForceConstructor; |
+ |
+ elements = MaybeGrow(this, elements, cursor, |
+ cursor + ESTF::kElementsPerFrame); |
elements->set(cursor++, *TheHoleToUndefined(this, recv)); |
elements->set(cursor++, *fun); |
elements->set(cursor++, *abstract_code); |
- elements->set(cursor++, *offset); |
+ elements->set(cursor++, Smi::FromInt(offset)); |
+ elements->set(cursor++, Smi::FromInt(flags)); |
frames_seen++; |
} |
} break; |
@@ -515,26 +520,24 @@ Handle<Object> Isolate::CaptureSimpleStackTrace(Handle<JSReceiver> error_object, |
// Filter out internal frames that we do not want to show. |
if (!helper.IsVisibleInStackTrace(*fun)) continue; |
- helper.CountSloppyFrames(*fun); |
+ Handle<Object> recv = handle(exit_frame->receiver(), this); |
Handle<Code> code = handle(exit_frame->LookupCode(), this); |
- int offset = |
+ const int offset = |
static_cast<int>(exit_frame->pc() - code->instruction_start()); |
- // 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); |
- } |
+ int flags = 0; |
+ if (helper.IsStrictFrame(*fun)) flags |= StackTraceFrame::kIsStrict; |
+ if (exit_frame->IsConstructor()) |
+ flags |= StackTraceFrame::kForceConstructor; |
- elements = MaybeGrow(this, elements, cursor, cursor + 4); |
+ elements = |
+ MaybeGrow(this, elements, cursor, cursor + ESTF::kElementsPerFrame); |
elements->set(cursor++, *recv); |
elements->set(cursor++, *fun); |
elements->set(cursor++, *code); |
elements->set(cursor++, Smi::FromInt(offset)); |
+ elements->set(cursor++, Smi::FromInt(flags)); |
frames_seen++; |
} break; |
@@ -543,13 +546,21 @@ Handle<Object> Isolate::CaptureSimpleStackTrace(Handle<JSReceiver> error_object, |
Code* code = wasm_frame->unchecked_code(); |
Handle<AbstractCode> abstract_code = |
Handle<AbstractCode>(AbstractCode::cast(code), this); |
- int offset = |
+ const int offset = |
static_cast<int>(wasm_frame->pc() - code->instruction_start()); |
- elements = MaybeGrow(this, elements, cursor, cursor + 4); |
+ |
+ // 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)); |
+ |
+ elements = |
+ MaybeGrow(this, elements, cursor, cursor + ESTF::kElementsPerFrame); |
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)); |
+ elements->set(cursor++, Smi::FromInt(StackTraceFrame::kIsWasmFrame)); |
frames_seen++; |
} break; |
@@ -557,10 +568,12 @@ Handle<Object> Isolate::CaptureSimpleStackTrace(Handle<JSReceiver> error_object, |
break; |
} |
} |
- elements->set(0, Smi::FromInt(helper.sloppy_frames())); |
+ |
+ DCHECK_EQ(0, cursor % ESTF::kElementsPerFrame); |
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; |
} |
@@ -769,19 +782,6 @@ class CaptureStackTraceHelper { |
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) { |
DisallowJavascriptExecution no_js(this); |
@@ -1426,36 +1426,26 @@ Object* Isolate::PromoteScheduledException() { |
void Isolate::PrintCurrentStackTrace(FILE* out) { |
- StackTraceFrameIterator it(this); |
- while (!it.done()) { |
+ for (StackTraceFrameIterator it(this); !it.done(); it.Advance()) { |
+ if (!it.is_javascript()) continue; |
+ |
HandleScope scope(this); |
+ JavaScriptFrame* frame = it.javascript_frame(); |
+ |
// Find code position if recorded in relocation info. |
- 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()); |
+ 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); |
+ |
// Generate and print stack trace line. |
- Handle<String> line = |
- Execution::GetStackTraceLine(recv, fun, pos_obj, is_top_level); |
+ Handle<String> line = st_frame->ToString(); |
if (line->length() > 0) { |
line->PrintOn(out); |
PrintF(out, "\n"); |
@@ -1513,6 +1503,23 @@ bool Isolate::ComputeLocationFromException(MessageLocation* target, |
return true; |
} |
+namespace { |
+ |
+int PositionFromStackTrace(Handle<FixedArray> elements, int index) { |
+ DisallowHeapAllocation no_gc; |
+ using ESTF = EncodedStackTraceFrame; |
+ Object* maybe_code = elements->get(index + ESTF::kCodeOffset); |
+ 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 + ESTF::kOffsetOffset))->value(); |
+ return abstract_code->SourcePosition(code_offset); |
+ } |
+} |
+ |
+} // namespace |
bool Isolate::ComputeLocationFromStackTrace(MessageLocation* target, |
Handle<Object> exception) { |
@@ -1526,8 +1533,10 @@ bool Isolate::ComputeLocationFromStackTrace(MessageLocation* target, |
Handle<FixedArray> elements(FixedArray::cast(simple_stack_trace->elements())); |
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); |
+ using ESTF = EncodedStackTraceFrame; |
+ for (int i = 0; i < elements_limit; i += ESTF::kElementsPerFrame) { |
+ Handle<Object> fun_obj = |
+ handle(elements->get(i + ESTF::kFunctionOffset), this); |
if (fun_obj->IsSmi()) { |
// TODO(clemensh): handle wasm frames |
return false; |