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") {
"src/objects/slots-inl.h",
"src/objects/slots.h",
"src/objects/stack-frame-info-inl.h",
"src/objects/stack-frame-info.cc",
"src/objects/stack-frame-info.h",
"src/objects/string-comparator.cc",
"src/objects/string-comparator.h",
......
......@@ -345,6 +345,7 @@ Type::bitset BitsetType::Lub(const MapRefLike& map) {
case CLASS_POSITIONS_TYPE:
case DEBUG_INFO_TYPE:
case STACK_FRAME_INFO_TYPE:
case STACK_TRACE_FRAME_TYPE:
case SMALL_ORDERED_HASH_MAP_TYPE:
case SMALL_ORDERED_HASH_SET_TYPE:
case SMALL_ORDERED_NAME_DICTIONARY_TYPE:
......
......@@ -3872,6 +3872,20 @@ Handle<BreakPoint> Factory::NewBreakPoint(int id, Handle<String> condition) {
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> stack_frame_info = Handle<StackFrameInfo>::cast(
NewStruct(STACK_FRAME_INFO_TYPE, NOT_TENURED));
......
......@@ -62,6 +62,7 @@ class PromiseResolveThenableJobTask;
class RegExpMatchInfo;
class ScriptContextTable;
class StackFrameInfo;
class StackTraceFrame;
class StoreHandler;
class TemplateObjectDescription;
class UncompiledDataWithoutPreparseData;
......@@ -439,6 +440,8 @@ class V8_EXPORT_PRIVATE Factory {
Handle<BreakPointInfo> NewBreakPointInfo(int source_position);
Handle<BreakPoint> NewBreakPoint(int id, Handle<String> condition);
Handle<StackTraceFrame> NewStackTraceFrame(Handle<FrameArray> frame_array,
int index);
Handle<StackFrameInfo> NewStackFrameInfo();
Handle<StackFrameInfo> NewStackFrameInfo(Handle<FrameArray> frame_array,
int index);
......
......@@ -295,7 +295,7 @@ Handle<Object> StackFrameBase::GetEvalOrigin() {
}
int StackFrameBase::GetScriptId() const {
if (!HasScript()) return -1;
if (!HasScript()) return kNone;
return GetScript()->id();
}
......@@ -467,7 +467,7 @@ Handle<Object> JSStackFrame::GetTypeName() {
int JSStackFrame::GetLineNumber() {
DCHECK_LE(0, GetPosition());
if (HasScript()) return Script::GetLineNumber(GetScript(), GetPosition()) + 1;
return -1;
return kNone;
}
int JSStackFrame::GetColumnNumber() {
......@@ -475,11 +475,11 @@ int JSStackFrame::GetColumnNumber() {
if (HasScript()) {
return Script::GetColumnNumber(GetScript(), GetPosition()) + 1;
}
return -1;
return kNone;
}
int JSStackFrame::GetPromiseIndex() const {
return is_promise_all_ ? offset_ : -1;
return is_promise_all_ ? offset_ : kNone;
}
bool JSStackFrame::IsNative() {
......@@ -521,14 +521,14 @@ void AppendFileLocation(Isolate* isolate, StackFrameBase* call_site,
}
int line_number = call_site->GetLineNumber();
if (line_number != -1) {
if (line_number != StackFrameBase::kNone) {
builder->AppendCharacter(':');
Handle<String> line_string = isolate->factory()->NumberToString(
handle(Smi::FromInt(line_number), isolate), isolate);
builder->AppendString(line_string);
int column_number = call_site->GetColumnNumber();
if (column_number != -1) {
if (column_number != StackFrameBase::kNone) {
builder->AppendCharacter(':');
Handle<String> column_string = isolate->factory()->NumberToString(
handle(Smi::FromInt(column_number), isolate), isolate);
......
......@@ -85,6 +85,9 @@ class StackFrameBase {
virtual MaybeHandle<String> ToString() = 0;
// Used to signal that the requested field is unknown.
static const int kNone = -1;
protected:
StackFrameBase() = default;
explicit StackFrameBase(Isolate* isolate) : isolate_(isolate) {}
......@@ -161,9 +164,9 @@ class WasmStackFrame : public StackFrameBase {
int GetPosition() const override;
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 IsToplevel() override { return false; }
......
......@@ -2054,6 +2054,14 @@ void DebugInfo::DebugInfoVerify(Isolate* isolate) {
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) {
CHECK(IsStackFrameInfo());
VerifyPointer(isolate, script_name());
......
......@@ -112,6 +112,7 @@ namespace internal {
V(PROTOTYPE_INFO_TYPE) \
V(SCRIPT_TYPE) \
V(STACK_FRAME_INFO_TYPE) \
V(STACK_TRACE_FRAME_TYPE) \
V(TUPLE2_TYPE) \
V(TUPLE3_TYPE) \
V(ARRAY_BOILERPLATE_DESCRIPTION_TYPE) \
......@@ -338,6 +339,7 @@ namespace internal {
V(_, PROTOTYPE_INFO_TYPE, PrototypeInfo, prototype_info) \
V(_, SCRIPT_TYPE, Script, script) \
V(_, STACK_FRAME_INFO_TYPE, StackFrameInfo, stack_frame_info) \
V(_, STACK_TRACE_FRAME_TYPE, StackTraceFrame, stack_trace_frame) \
V(_, TUPLE2_TYPE, Tuple2, tuple2) \
V(_, TUPLE3_TYPE, Tuple3, tuple3) \
V(_, ARRAY_BOILERPLATE_DESCRIPTION_TYPE, ArrayBoilerplateDescription, \
......
......@@ -2207,6 +2207,12 @@ void DebugInfo::DebugInfoPrint(std::ostream& os) { // NOLINT
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
PrintHeader(os, "StackFrame");
......
......@@ -159,6 +159,7 @@
// - BreakPoint
// - BreakPointInfo
// - StackFrameInfo
// - StackTraceFrame
// - SourcePositionTableWithFrameCache
// - CodeCache
// - PrototypeInfo
......
......@@ -185,6 +185,7 @@ enum InstanceType : uint16_t {
PROTOTYPE_INFO_TYPE,
SCRIPT_TYPE,
STACK_FRAME_INFO_TYPE,
STACK_TRACE_FRAME_TYPE,
TUPLE2_TYPE,
TUPLE3_TYPE,
ARRAY_BOILERPLATE_DESCRIPTION_TYPE,
......
......@@ -8,6 +8,7 @@
#include "src/objects/stack-frame-info.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):
#include "src/objects/object-macros.h"
......@@ -34,6 +35,15 @@ BOOL_ACCESSORS(StackFrameInfo, flag, is_constructor, kIsConstructorBit)
BOOL_ACCESSORS(StackFrameInfo, flag, is_wasm, kIsWasmBit)
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 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 @@
namespace v8 {
namespace internal {
class FrameArray;
class StackFrameInfo : public Struct {
public:
NEVER_READ_ONLY_SPACE
......@@ -59,6 +61,56 @@ class StackFrameInfo : public 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 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