Commit 6e05eefe authored by Simon Zünd's avatar Simon Zünd Committed by Commit Bot

[stack trace] Introduce StackTraceFrame object

The StackTraceFrame object will be used in a future CL to replace
StackFrameInfo as the object returned by the inspector API, as well
as the object used in the stack_frame_cache.

The object itself is a simple wrapper around a reference to a
FrameArray plus an index, as well as a reference to a
StackFrameInfo object that will get lazily initialized.

This is the first step towards unifying stack trace representation
and collection.

R=jgruber@chromium.org

Bug: v8:8742
Change-Id: Iefc7d734fd274ffd164ddf6f43c226531aa26d4c
Reviewed-on: https://chromium-review.googlesource.com/c/1458017
Commit-Queue: Simon Zünd <szuend@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarMichael Starzinger <mstarzinger@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59544}
parent 2497023a
...@@ -2324,6 +2324,7 @@ v8_source_set("v8_base") { ...@@ -2324,6 +2324,7 @@ v8_source_set("v8_base") {
"src/objects/slots-inl.h", "src/objects/slots-inl.h",
"src/objects/slots.h", "src/objects/slots.h",
"src/objects/stack-frame-info-inl.h", "src/objects/stack-frame-info-inl.h",
"src/objects/stack-frame-info.cc",
"src/objects/stack-frame-info.h", "src/objects/stack-frame-info.h",
"src/objects/string-comparator.cc", "src/objects/string-comparator.cc",
"src/objects/string-comparator.h", "src/objects/string-comparator.h",
......
...@@ -345,6 +345,7 @@ Type::bitset BitsetType::Lub(const MapRefLike& map) { ...@@ -345,6 +345,7 @@ Type::bitset BitsetType::Lub(const MapRefLike& map) {
case CLASS_POSITIONS_TYPE: case CLASS_POSITIONS_TYPE:
case DEBUG_INFO_TYPE: case DEBUG_INFO_TYPE:
case STACK_FRAME_INFO_TYPE: case STACK_FRAME_INFO_TYPE:
case STACK_TRACE_FRAME_TYPE:
case SMALL_ORDERED_HASH_MAP_TYPE: case SMALL_ORDERED_HASH_MAP_TYPE:
case SMALL_ORDERED_HASH_SET_TYPE: case SMALL_ORDERED_HASH_SET_TYPE:
case SMALL_ORDERED_NAME_DICTIONARY_TYPE: case SMALL_ORDERED_NAME_DICTIONARY_TYPE:
......
...@@ -3872,6 +3872,20 @@ Handle<BreakPoint> Factory::NewBreakPoint(int id, Handle<String> condition) { ...@@ -3872,6 +3872,20 @@ Handle<BreakPoint> Factory::NewBreakPoint(int id, Handle<String> condition) {
return new_break_point; return new_break_point;
} }
Handle<StackTraceFrame> Factory::NewStackTraceFrame(
Handle<FrameArray> frame_array, int index) {
Handle<StackTraceFrame> frame = Handle<StackTraceFrame>::cast(
NewStruct(STACK_TRACE_FRAME_TYPE, NOT_TENURED));
frame->set_frame_array(*frame_array);
frame->set_frame_index(index);
frame->set_frame_info(*undefined_value());
int id = isolate()->last_stack_frame_info_id() + 1;
isolate()->set_last_stack_frame_info_id(id);
frame->set_id(id);
return frame;
}
Handle<StackFrameInfo> Factory::NewStackFrameInfo() { Handle<StackFrameInfo> Factory::NewStackFrameInfo() {
Handle<StackFrameInfo> stack_frame_info = Handle<StackFrameInfo>::cast( Handle<StackFrameInfo> stack_frame_info = Handle<StackFrameInfo>::cast(
NewStruct(STACK_FRAME_INFO_TYPE, NOT_TENURED)); NewStruct(STACK_FRAME_INFO_TYPE, NOT_TENURED));
......
...@@ -62,6 +62,7 @@ class PromiseResolveThenableJobTask; ...@@ -62,6 +62,7 @@ class PromiseResolveThenableJobTask;
class RegExpMatchInfo; class RegExpMatchInfo;
class ScriptContextTable; class ScriptContextTable;
class StackFrameInfo; class StackFrameInfo;
class StackTraceFrame;
class StoreHandler; class StoreHandler;
class TemplateObjectDescription; class TemplateObjectDescription;
class UncompiledDataWithoutPreparseData; class UncompiledDataWithoutPreparseData;
...@@ -439,6 +440,8 @@ class V8_EXPORT_PRIVATE Factory { ...@@ -439,6 +440,8 @@ class V8_EXPORT_PRIVATE Factory {
Handle<BreakPointInfo> NewBreakPointInfo(int source_position); Handle<BreakPointInfo> NewBreakPointInfo(int source_position);
Handle<BreakPoint> NewBreakPoint(int id, Handle<String> condition); Handle<BreakPoint> NewBreakPoint(int id, Handle<String> condition);
Handle<StackTraceFrame> NewStackTraceFrame(Handle<FrameArray> frame_array,
int index);
Handle<StackFrameInfo> NewStackFrameInfo(); Handle<StackFrameInfo> NewStackFrameInfo();
Handle<StackFrameInfo> NewStackFrameInfo(Handle<FrameArray> frame_array, Handle<StackFrameInfo> NewStackFrameInfo(Handle<FrameArray> frame_array,
int index); int index);
......
...@@ -295,7 +295,7 @@ Handle<Object> StackFrameBase::GetEvalOrigin() { ...@@ -295,7 +295,7 @@ Handle<Object> StackFrameBase::GetEvalOrigin() {
} }
int StackFrameBase::GetScriptId() const { int StackFrameBase::GetScriptId() const {
if (!HasScript()) return -1; if (!HasScript()) return kNone;
return GetScript()->id(); return GetScript()->id();
} }
...@@ -467,7 +467,7 @@ Handle<Object> JSStackFrame::GetTypeName() { ...@@ -467,7 +467,7 @@ Handle<Object> JSStackFrame::GetTypeName() {
int JSStackFrame::GetLineNumber() { int JSStackFrame::GetLineNumber() {
DCHECK_LE(0, GetPosition()); DCHECK_LE(0, GetPosition());
if (HasScript()) return Script::GetLineNumber(GetScript(), GetPosition()) + 1; if (HasScript()) return Script::GetLineNumber(GetScript(), GetPosition()) + 1;
return -1; return kNone;
} }
int JSStackFrame::GetColumnNumber() { int JSStackFrame::GetColumnNumber() {
...@@ -475,11 +475,11 @@ int JSStackFrame::GetColumnNumber() { ...@@ -475,11 +475,11 @@ int JSStackFrame::GetColumnNumber() {
if (HasScript()) { if (HasScript()) {
return Script::GetColumnNumber(GetScript(), GetPosition()) + 1; return Script::GetColumnNumber(GetScript(), GetPosition()) + 1;
} }
return -1; return kNone;
} }
int JSStackFrame::GetPromiseIndex() const { int JSStackFrame::GetPromiseIndex() const {
return is_promise_all_ ? offset_ : -1; return is_promise_all_ ? offset_ : kNone;
} }
bool JSStackFrame::IsNative() { bool JSStackFrame::IsNative() {
...@@ -521,14 +521,14 @@ void AppendFileLocation(Isolate* isolate, StackFrameBase* call_site, ...@@ -521,14 +521,14 @@ void AppendFileLocation(Isolate* isolate, StackFrameBase* call_site,
} }
int line_number = call_site->GetLineNumber(); int line_number = call_site->GetLineNumber();
if (line_number != -1) { if (line_number != StackFrameBase::kNone) {
builder->AppendCharacter(':'); builder->AppendCharacter(':');
Handle<String> line_string = isolate->factory()->NumberToString( Handle<String> line_string = isolate->factory()->NumberToString(
handle(Smi::FromInt(line_number), isolate), isolate); handle(Smi::FromInt(line_number), isolate), isolate);
builder->AppendString(line_string); builder->AppendString(line_string);
int column_number = call_site->GetColumnNumber(); int column_number = call_site->GetColumnNumber();
if (column_number != -1) { if (column_number != StackFrameBase::kNone) {
builder->AppendCharacter(':'); builder->AppendCharacter(':');
Handle<String> column_string = isolate->factory()->NumberToString( Handle<String> column_string = isolate->factory()->NumberToString(
handle(Smi::FromInt(column_number), isolate), isolate); handle(Smi::FromInt(column_number), isolate), isolate);
......
...@@ -85,6 +85,9 @@ class StackFrameBase { ...@@ -85,6 +85,9 @@ class StackFrameBase {
virtual MaybeHandle<String> ToString() = 0; virtual MaybeHandle<String> ToString() = 0;
// Used to signal that the requested field is unknown.
static const int kNone = -1;
protected: protected:
StackFrameBase() = default; StackFrameBase() = default;
explicit StackFrameBase(Isolate* isolate) : isolate_(isolate) {} explicit StackFrameBase(Isolate* isolate) : isolate_(isolate) {}
...@@ -161,9 +164,9 @@ class WasmStackFrame : public StackFrameBase { ...@@ -161,9 +164,9 @@ class WasmStackFrame : public StackFrameBase {
int GetPosition() const override; int GetPosition() const override;
int GetLineNumber() override { return wasm_func_index_; } int GetLineNumber() override { return wasm_func_index_; }
int GetColumnNumber() override { return -1; } int GetColumnNumber() override { return kNone; }
int GetPromiseIndex() const override { return -1; } int GetPromiseIndex() const override { return kNone; }
bool IsNative() override { return false; } bool IsNative() override { return false; }
bool IsToplevel() override { return false; } bool IsToplevel() override { return false; }
......
...@@ -2054,6 +2054,14 @@ void DebugInfo::DebugInfoVerify(Isolate* isolate) { ...@@ -2054,6 +2054,14 @@ void DebugInfo::DebugInfoVerify(Isolate* isolate) {
VerifyPointer(isolate, break_points()); VerifyPointer(isolate, break_points());
} }
void StackTraceFrame::StackTraceFrameVerify(Isolate* isolate) {
CHECK(IsStackTraceFrame());
VerifySmiField(kFrameIndexOffset);
VerifySmiField(kIdOffset);
VerifyPointer(isolate, frame_array());
VerifyPointer(isolate, frame_info());
}
void StackFrameInfo::StackFrameInfoVerify(Isolate* isolate) { void StackFrameInfo::StackFrameInfoVerify(Isolate* isolate) {
CHECK(IsStackFrameInfo()); CHECK(IsStackFrameInfo());
VerifyPointer(isolate, script_name()); VerifyPointer(isolate, script_name());
......
...@@ -112,6 +112,7 @@ namespace internal { ...@@ -112,6 +112,7 @@ namespace internal {
V(PROTOTYPE_INFO_TYPE) \ V(PROTOTYPE_INFO_TYPE) \
V(SCRIPT_TYPE) \ V(SCRIPT_TYPE) \
V(STACK_FRAME_INFO_TYPE) \ V(STACK_FRAME_INFO_TYPE) \
V(STACK_TRACE_FRAME_TYPE) \
V(TUPLE2_TYPE) \ V(TUPLE2_TYPE) \
V(TUPLE3_TYPE) \ V(TUPLE3_TYPE) \
V(ARRAY_BOILERPLATE_DESCRIPTION_TYPE) \ V(ARRAY_BOILERPLATE_DESCRIPTION_TYPE) \
...@@ -338,6 +339,7 @@ namespace internal { ...@@ -338,6 +339,7 @@ namespace internal {
V(_, PROTOTYPE_INFO_TYPE, PrototypeInfo, prototype_info) \ V(_, PROTOTYPE_INFO_TYPE, PrototypeInfo, prototype_info) \
V(_, SCRIPT_TYPE, Script, script) \ V(_, SCRIPT_TYPE, Script, script) \
V(_, STACK_FRAME_INFO_TYPE, StackFrameInfo, stack_frame_info) \ V(_, STACK_FRAME_INFO_TYPE, StackFrameInfo, stack_frame_info) \
V(_, STACK_TRACE_FRAME_TYPE, StackTraceFrame, stack_trace_frame) \
V(_, TUPLE2_TYPE, Tuple2, tuple2) \ V(_, TUPLE2_TYPE, Tuple2, tuple2) \
V(_, TUPLE3_TYPE, Tuple3, tuple3) \ V(_, TUPLE3_TYPE, Tuple3, tuple3) \
V(_, ARRAY_BOILERPLATE_DESCRIPTION_TYPE, ArrayBoilerplateDescription, \ V(_, ARRAY_BOILERPLATE_DESCRIPTION_TYPE, ArrayBoilerplateDescription, \
......
...@@ -2207,6 +2207,12 @@ void DebugInfo::DebugInfoPrint(std::ostream& os) { // NOLINT ...@@ -2207,6 +2207,12 @@ void DebugInfo::DebugInfoPrint(std::ostream& os) { // NOLINT
os << "\n - coverage_info: " << Brief(coverage_info()); os << "\n - coverage_info: " << Brief(coverage_info());
} }
void StackTraceFrame::StackTraceFramePrint(std::ostream& os) { // NOLINT
PrintHeader(os, "StackTraceFrame");
os << "\n - frame_index: " << frame_index();
os << "\n - id: " << id();
os << "\n - frame_info: " << Brief(frame_info());
}
void StackFrameInfo::StackFrameInfoPrint(std::ostream& os) { // NOLINT void StackFrameInfo::StackFrameInfoPrint(std::ostream& os) { // NOLINT
PrintHeader(os, "StackFrame"); PrintHeader(os, "StackFrame");
......
...@@ -159,6 +159,7 @@ ...@@ -159,6 +159,7 @@
// - BreakPoint // - BreakPoint
// - BreakPointInfo // - BreakPointInfo
// - StackFrameInfo // - StackFrameInfo
// - StackTraceFrame
// - SourcePositionTableWithFrameCache // - SourcePositionTableWithFrameCache
// - CodeCache // - CodeCache
// - PrototypeInfo // - PrototypeInfo
......
...@@ -185,6 +185,7 @@ enum InstanceType : uint16_t { ...@@ -185,6 +185,7 @@ enum InstanceType : uint16_t {
PROTOTYPE_INFO_TYPE, PROTOTYPE_INFO_TYPE,
SCRIPT_TYPE, SCRIPT_TYPE,
STACK_FRAME_INFO_TYPE, STACK_FRAME_INFO_TYPE,
STACK_TRACE_FRAME_TYPE,
TUPLE2_TYPE, TUPLE2_TYPE,
TUPLE3_TYPE, TUPLE3_TYPE,
ARRAY_BOILERPLATE_DESCRIPTION_TYPE, ARRAY_BOILERPLATE_DESCRIPTION_TYPE,
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "src/objects/stack-frame-info.h" #include "src/objects/stack-frame-info.h"
#include "src/heap/heap-write-barrier-inl.h" #include "src/heap/heap-write-barrier-inl.h"
#include "src/objects/frame-array-inl.h"
// Has to be the last include (doesn't have include guards): // Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h" #include "src/objects/object-macros.h"
...@@ -34,6 +35,15 @@ BOOL_ACCESSORS(StackFrameInfo, flag, is_constructor, kIsConstructorBit) ...@@ -34,6 +35,15 @@ BOOL_ACCESSORS(StackFrameInfo, flag, is_constructor, kIsConstructorBit)
BOOL_ACCESSORS(StackFrameInfo, flag, is_wasm, kIsWasmBit) BOOL_ACCESSORS(StackFrameInfo, flag, is_wasm, kIsWasmBit)
SMI_ACCESSORS(StackFrameInfo, id, kIdOffset) SMI_ACCESSORS(StackFrameInfo, id, kIdOffset)
OBJECT_CONSTRUCTORS_IMPL(StackTraceFrame, Struct)
NEVER_READ_ONLY_SPACE_IMPL(StackTraceFrame)
CAST_ACCESSOR(StackTraceFrame)
ACCESSORS(StackTraceFrame, frame_array, Object, kFrameArrayOffset)
SMI_ACCESSORS(StackTraceFrame, frame_index, kFrameIndexOffset)
ACCESSORS(StackTraceFrame, frame_info, Object, kFrameInfoOffset)
SMI_ACCESSORS(StackTraceFrame, id, kIdOffset)
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/objects/stack-frame-info.h"
#include "src/objects/stack-frame-info-inl.h"
namespace v8 {
namespace internal {
int StackTraceFrame::GetLineNumber(Handle<StackTraceFrame> frame) {
if (frame->frame_info()->IsUndefined()) InitializeFrameInfo(frame);
int line = GetFrameInfo(frame)->line_number();
return line != StackFrameBase::kNone ? line : Message::kNoLineNumberInfo;
}
int StackTraceFrame::GetColumnNumber(Handle<StackTraceFrame> frame) {
if (frame->frame_info()->IsUndefined()) InitializeFrameInfo(frame);
int column = GetFrameInfo(frame)->column_number();
return column != StackFrameBase::kNone ? column : Message::kNoColumnInfo;
}
int StackTraceFrame::GetScriptId(Handle<StackTraceFrame> frame) {
if (frame->frame_info()->IsUndefined()) InitializeFrameInfo(frame);
int id = GetFrameInfo(frame)->script_id();
return id != StackFrameBase::kNone ? id : Message::kNoScriptIdInfo;
}
Handle<Object> StackTraceFrame::GetFileName(Handle<StackTraceFrame> frame) {
if (frame->frame_info()->IsUndefined()) InitializeFrameInfo(frame);
auto name = GetFrameInfo(frame)->script_name();
return handle(name, frame->GetIsolate());
}
Handle<Object> StackTraceFrame::GetScriptNameOrSourceUrl(
Handle<StackTraceFrame> frame) {
if (frame->frame_info()->IsUndefined()) InitializeFrameInfo(frame);
auto name = GetFrameInfo(frame)->script_name_or_source_url();
return handle(name, frame->GetIsolate());
}
Handle<Object> StackTraceFrame::GetFunctionName(Handle<StackTraceFrame> frame) {
if (frame->frame_info()->IsUndefined()) InitializeFrameInfo(frame);
auto name = GetFrameInfo(frame)->function_name();
return handle(name, frame->GetIsolate());
}
bool StackTraceFrame::IsEval(Handle<StackTraceFrame> frame) {
if (frame->frame_info()->IsUndefined()) InitializeFrameInfo(frame);
return GetFrameInfo(frame)->is_eval();
}
bool StackTraceFrame::IsConstructor(Handle<StackTraceFrame> frame) {
if (frame->frame_info()->IsUndefined()) InitializeFrameInfo(frame);
return GetFrameInfo(frame)->is_constructor();
}
bool StackTraceFrame::IsWasm(Handle<StackTraceFrame> frame) {
if (frame->frame_info()->IsUndefined()) InitializeFrameInfo(frame);
return GetFrameInfo(frame)->is_wasm();
}
Handle<StackFrameInfo> StackTraceFrame::GetFrameInfo(
Handle<StackTraceFrame> frame) {
return handle(StackFrameInfo::cast(frame->frame_info()), frame->GetIsolate());
}
void StackTraceFrame::InitializeFrameInfo(Handle<StackTraceFrame> frame) {
Isolate* isolate = frame->GetIsolate();
Handle<StackFrameInfo> frame_info = isolate->factory()->NewStackFrameInfo(
handle(FrameArray::cast(frame->frame_array()), isolate),
frame->frame_index());
frame->set_frame_info(*frame_info);
// After initializing, we no longer need to keep a reference
// to the frame_array.
frame->set_frame_array(ReadOnlyRoots(isolate).undefined_value());
frame->set_frame_index(-1);
}
} // namespace internal
} // namespace v8
...@@ -13,6 +13,8 @@ ...@@ -13,6 +13,8 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
class FrameArray;
class StackFrameInfo : public Struct { class StackFrameInfo : public Struct {
public: public:
NEVER_READ_ONLY_SPACE NEVER_READ_ONLY_SPACE
...@@ -59,6 +61,56 @@ class StackFrameInfo : public Struct { ...@@ -59,6 +61,56 @@ class StackFrameInfo : public Struct {
OBJECT_CONSTRUCTORS(StackFrameInfo, Struct); OBJECT_CONSTRUCTORS(StackFrameInfo, Struct);
}; };
// This class is used to lazily initialize a StackFrameInfo object from
// a FrameArray plus an index.
// The first time any of the Get* or Is* methods is called, a
// StackFrameInfo object is allocated and all necessary information
// retrieved.
class StackTraceFrame : public Struct {
public:
NEVER_READ_ONLY_SPACE
DECL_ACCESSORS(frame_array, Object)
DECL_INT_ACCESSORS(frame_index)
DECL_ACCESSORS(frame_info, Object)
DECL_INT_ACCESSORS(id)
DECL_CAST(StackTraceFrame)
// Dispatched behavior.
DECL_PRINTER(StackTraceFrame)
DECL_VERIFIER(StackTraceFrame)
// Layout description.
#define STACK_FRAME_FIELDS(V) \
V(kFrameArrayOffset, kTaggedSize) \
V(kFrameIndexOffset, kTaggedSize) \
V(kFrameInfoOffset, kTaggedSize) \
V(kIdOffset, kTaggedSize) \
/* Total size. */ \
V(kSize, 0)
DEFINE_FIELD_OFFSET_CONSTANTS(Struct::kHeaderSize, STACK_FRAME_FIELDS)
#undef STACK_FRAME_FIELDS
static int GetLineNumber(Handle<StackTraceFrame> frame);
static int GetColumnNumber(Handle<StackTraceFrame> frame);
static int GetScriptId(Handle<StackTraceFrame> frame);
static Handle<Object> GetFileName(Handle<StackTraceFrame> frame);
static Handle<Object> GetScriptNameOrSourceUrl(Handle<StackTraceFrame> frame);
static Handle<Object> GetFunctionName(Handle<StackTraceFrame> frame);
static bool IsEval(Handle<StackTraceFrame> frame);
static bool IsConstructor(Handle<StackTraceFrame> frame);
static bool IsWasm(Handle<StackTraceFrame> frame);
private:
OBJECT_CONSTRUCTORS(StackTraceFrame, Struct);
static Handle<StackFrameInfo> GetFrameInfo(Handle<StackTraceFrame> frame);
static void InitializeFrameInfo(Handle<StackTraceFrame> frame);
};
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment