Index: src/inspector/v8-stack-trace-impl.cc |
diff --git a/src/inspector/v8-stack-trace-impl.cc b/src/inspector/v8-stack-trace-impl.cc |
index dddad36202accfe53a25bb0010aacfbd8a7112c5..8044e8f42c9dc305a4be0df9e24c8d68f450576e 100644 |
--- a/src/inspector/v8-stack-trace-impl.cc |
+++ b/src/inspector/v8-stack-trace-impl.cc |
@@ -23,8 +23,7 @@ static const v8::StackTrace::StackTraceOptions stackTraceOptions = |
v8::StackTrace::kExposeFramesAcrossSecurityOrigins); |
V8StackTraceImpl::Frame toFrame(v8::Local<v8::StackFrame> frame, |
- WasmTranslation* wasmTranslation, |
- int contextGroupId) { |
+ WasmTranslation* wasmTranslation) { |
String16 scriptId = String16::fromInteger(frame->GetScriptId()); |
String16 sourceName; |
v8::Local<v8::String> sourceNameValue(frame->GetScriptNameOrSourceURL()); |
@@ -51,7 +50,7 @@ V8StackTraceImpl::Frame toFrame(v8::Local<v8::StackFrame> frame, |
void toFramesVector(v8::Local<v8::StackTrace> stackTrace, |
std::vector<V8StackTraceImpl::Frame>& frames, |
size_t maxStackSize, v8::Isolate* isolate, |
- V8Debugger* debugger, int contextGroupId) { |
+ V8Debugger* debugger) { |
DCHECK(isolate->InContext()); |
int frameCount = stackTrace->GetFrameCount(); |
if (frameCount > static_cast<int>(maxStackSize)) |
@@ -59,19 +58,12 @@ void toFramesVector(v8::Local<v8::StackTrace> stackTrace, |
WasmTranslation* wasmTranslation = debugger->wasmTranslation(); |
for (int i = 0; i < frameCount; i++) { |
v8::Local<v8::StackFrame> stackFrame = stackTrace->GetFrame(i); |
- frames.push_back(toFrame(stackFrame, wasmTranslation, contextGroupId)); |
+ frames.push_back(toFrame(stackFrame, wasmTranslation)); |
} |
} |
} // namespace |
-V8StackTraceImpl::Frame::Frame() |
- : m_functionName("undefined"), |
- m_scriptId(""), |
- m_scriptName("undefined"), |
- m_lineNumber(0), |
- m_columnNumber(0) {} |
- |
V8StackTraceImpl::Frame::Frame(const String16& functionName, |
const String16& scriptId, |
const String16& scriptName, int lineNumber, |
@@ -85,8 +77,6 @@ V8StackTraceImpl::Frame::Frame(const String16& functionName, |
DCHECK(m_columnNumber != v8::Message::kNoColumnInfo); |
} |
-V8StackTraceImpl::Frame::~Frame() {} |
- |
// buildInspectorObject() and SourceLocation's toTracedValue() should set the |
// same fields. |
// If either of them is modified, the other should be also modified. |
@@ -101,11 +91,6 @@ V8StackTraceImpl::Frame::buildInspectorObject() const { |
.build(); |
} |
-V8StackTraceImpl::Frame V8StackTraceImpl::Frame::clone() const { |
- return Frame(m_functionName, m_scriptId, m_scriptName, m_lineNumber, |
- m_columnNumber); |
-} |
- |
// static |
void V8StackTraceImpl::setCaptureStackTraceForUncaughtExceptions( |
v8::Isolate* isolate, bool capture) { |
@@ -122,39 +107,52 @@ std::unique_ptr<V8StackTraceImpl> V8StackTraceImpl::create( |
v8::Isolate* isolate = debugger->inspector()->isolate(); |
v8::HandleScope scope(isolate); |
std::vector<V8StackTraceImpl::Frame> frames; |
- if (!stackTrace.IsEmpty()) |
- toFramesVector(stackTrace, frames, maxStackSize, isolate, debugger, |
- contextGroupId); |
+ if (!stackTrace.IsEmpty()) { |
+ toFramesVector(stackTrace, frames, maxStackSize, isolate, debugger); |
+ } |
int maxAsyncCallChainDepth = 1; |
V8StackTraceImpl* asyncCallChain = nullptr; |
+ V8StackTraceImpl* creationStack = nullptr; |
if (maxStackSize > 1) { |
asyncCallChain = debugger->currentAsyncCallChain(); |
+ creationStack = debugger->currentAsyncTaskCreationStack(); |
maxAsyncCallChainDepth = debugger->maxAsyncCallChainDepth(); |
} |
+ |
// Do not accidentally append async call chain from another group. This should |
- // not |
- // happen if we have proper instrumentation, but let's double-check to be |
+ // not happen if we have proper instrumentation, but let's double-check to be |
// safe. |
if (contextGroupId && asyncCallChain && asyncCallChain->m_contextGroupId && |
asyncCallChain->m_contextGroupId != contextGroupId) { |
asyncCallChain = nullptr; |
+ creationStack = nullptr; |
maxAsyncCallChainDepth = 1; |
} |
// Only the top stack in the chain may be empty and doesn't contain creation |
// stack , so ensure that second stack is non-empty (it's the top of appended |
// chain). |
- if (asyncCallChain && asyncCallChain->isEmpty() && |
- !asyncCallChain->m_creation) { |
+ if (asyncCallChain && !creationStack && !asyncCallChain->m_creation && |
+ asyncCallChain->isEmpty()) { |
asyncCallChain = asyncCallChain->m_parent.get(); |
} |
- if (stackTrace.IsEmpty() && !asyncCallChain) return nullptr; |
+ if (frames.empty() && !creationStack && !asyncCallChain) return nullptr; |
+ |
+ // When async call chain is empty but doesn't contain useful schedule stack |
+ // and parent async call chain contains creationg stack but doesn't |
+ // synchronous we can merge them together. |
+ // e.g. Promise ThenableJob. |
+ if (asyncCallChain && frames.empty() && |
+ asyncCallChain->m_description == description && !creationStack) { |
+ return asyncCallChain->cloneImpl(); |
+ } |
std::unique_ptr<V8StackTraceImpl> result(new V8StackTraceImpl( |
contextGroupId, description, frames, |
- asyncCallChain ? asyncCallChain->cloneImpl() : nullptr)); |
+ asyncCallChain ? asyncCallChain->cloneImpl() : nullptr, |
+ creationStack ? creationStack->cloneImpl() : nullptr)); |
// Crop to not exceed maxAsyncCallChainDepth. |
V8StackTraceImpl* deepest = result.get(); |
@@ -187,44 +185,34 @@ std::unique_ptr<V8StackTraceImpl> V8StackTraceImpl::cloneImpl() { |
std::vector<Frame> framesCopy(m_frames); |
std::unique_ptr<V8StackTraceImpl> copy( |
new V8StackTraceImpl(m_contextGroupId, m_description, framesCopy, |
- m_parent ? m_parent->cloneImpl() : nullptr)); |
- if (m_creation) copy->setCreation(m_creation->cloneImpl()); |
+ m_parent ? m_parent->cloneImpl() : nullptr, |
+ m_creation ? m_creation->cloneImpl() : nullptr)); |
return copy; |
} |
std::unique_ptr<V8StackTrace> V8StackTraceImpl::clone() { |
std::vector<Frame> frames; |
- for (size_t i = 0; i < m_frames.size(); i++) |
- frames.push_back(m_frames.at(i).clone()); |
- return std::unique_ptr<V8StackTraceImpl>( |
- new V8StackTraceImpl(m_contextGroupId, m_description, frames, nullptr)); |
+ for (size_t i = 0; i < m_frames.size(); i++) { |
+ frames.push_back(m_frames.at(i)); |
+ } |
+ return std::unique_ptr<V8StackTraceImpl>(new V8StackTraceImpl( |
+ m_contextGroupId, m_description, frames, nullptr, nullptr)); |
} |
V8StackTraceImpl::V8StackTraceImpl(int contextGroupId, |
const String16& description, |
std::vector<Frame>& frames, |
- std::unique_ptr<V8StackTraceImpl> parent) |
+ std::unique_ptr<V8StackTraceImpl> parent, |
+ std::unique_ptr<V8StackTraceImpl> creation) |
: m_contextGroupId(contextGroupId), |
m_description(description), |
- m_parent(std::move(parent)) { |
+ m_parent(std::move(parent)), |
+ m_creation(std::move(creation)) { |
m_frames.swap(frames); |
} |
V8StackTraceImpl::~V8StackTraceImpl() {} |
-void V8StackTraceImpl::setCreation(std::unique_ptr<V8StackTraceImpl> creation) { |
- m_creation = std::move(creation); |
- // When async call chain is empty but doesn't contain useful schedule stack |
- // and parent async call chain contains creationg stack but doesn't |
- // synchronous we can merge them together. |
- // e.g. Promise ThenableJob. |
- if (m_parent && isEmpty() && m_description == m_parent->m_description && |
- !m_parent->m_creation) { |
- m_frames.swap(m_parent->m_frames); |
- m_parent = std::move(m_parent->m_parent); |
- } |
-} |
- |
StringView V8StackTraceImpl::topSourceURL() const { |
DCHECK(m_frames.size()); |
return toStringView(m_frames[0].m_scriptName); |
@@ -252,6 +240,11 @@ StringView V8StackTraceImpl::topScriptId() const { |
std::unique_ptr<protocol::Runtime::StackTrace> |
V8StackTraceImpl::buildInspectorObjectImpl() const { |
+ return buildInspectorObjectImpl(nullptr); |
+} |
+ |
+std::unique_ptr<protocol::Runtime::StackTrace> |
+V8StackTraceImpl::buildInspectorObjectImpl(V8StackTraceImpl* creation) const { |
std::unique_ptr<protocol::Array<protocol::Runtime::CallFrame>> frames = |
protocol::Array<protocol::Runtime::CallFrame>::create(); |
for (size_t i = 0; i < m_frames.size(); i++) |
@@ -262,30 +255,36 @@ V8StackTraceImpl::buildInspectorObjectImpl() const { |
.setCallFrames(std::move(frames)) |
.build(); |
if (!m_description.isEmpty()) stackTrace->setDescription(m_description); |
- if (m_parent) stackTrace->setParent(m_parent->buildInspectorObjectImpl()); |
- if (m_creation && m_creation->m_frames.size()) { |
+ if (m_parent) { |
+ stackTrace->setParent(m_parent->buildInspectorObjectImpl(m_creation.get())); |
+ } |
+ if (creation && creation->m_frames.size()) { |
stackTrace->setPromiseCreationFrame( |
- m_creation->m_frames[0].buildInspectorObject()); |
+ creation->m_frames[0].buildInspectorObject()); |
} |
return stackTrace; |
} |
+// static |
std::unique_ptr<protocol::Runtime::StackTrace> |
-V8StackTraceImpl::buildInspectorObjectForTail(V8Debugger* debugger) const { |
+V8StackTraceImpl::buildInspectorObjectForTail(V8Debugger* debugger) { |
DCHECK(debugger); |
v8::HandleScope handleScope(debugger->inspector()->isolate()); |
// Next call collapses possible empty stack and ensures |
// maxAsyncCallChainDepth. |
+ V8StackTraceImpl* asyncChain = debugger->currentAsyncCallChain(); |
+ if (!asyncChain) return nullptr; |
std::unique_ptr<V8StackTraceImpl> fullChain = V8StackTraceImpl::create( |
- debugger, m_contextGroupId, v8::Local<v8::StackTrace>(), |
+ debugger, asyncChain->m_contextGroupId, v8::Local<v8::StackTrace>(), |
V8StackTraceImpl::maxCallStackSizeToCapture); |
if (!fullChain || !fullChain->m_parent) return nullptr; |
- return fullChain->m_parent->buildInspectorObjectImpl(); |
+ return fullChain->m_parent->buildInspectorObjectImpl( |
+ fullChain->m_creation.get()); |
} |
std::unique_ptr<protocol::Runtime::API::StackTrace> |
V8StackTraceImpl::buildInspectorObject() const { |
- return buildInspectorObjectImpl(); |
+ return buildInspectorObjectImpl(nullptr); |
} |
std::unique_ptr<StringBuffer> V8StackTraceImpl::toString() const { |