Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(206)

Side by Side Diff: src/inspector/v8-stack-trace-impl.cc

Issue 2825713002: Revert of [inspector] avoid cloning of async call chains (Closed)
Patch Set: Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/inspector/v8-stack-trace-impl.h ('k') | test/inspector/debugger/async-stacks-limit.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2016 the V8 project authors. All rights reserved. 1 // Copyright 2016 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/inspector/v8-stack-trace-impl.h" 5 #include "src/inspector/v8-stack-trace-impl.h"
6 6
7 #include <algorithm> 7 #include "src/inspector/string-util.h"
8 #include "src/inspector/v8-debugger-agent-impl.h"
9 #include "src/inspector/v8-debugger.h"
10 #include "src/inspector/v8-inspector-impl.h"
8 11
9 #include "src/inspector/v8-debugger.h" 12 #include "include/v8-version.h"
10 #include "src/inspector/wasm-translation.h"
11 13
12 namespace v8_inspector { 14 namespace v8_inspector {
13 15
14 namespace { 16 namespace {
15 17
16 static const v8::StackTrace::StackTraceOptions stackTraceOptions = 18 static const v8::StackTrace::StackTraceOptions stackTraceOptions =
17 static_cast<v8::StackTrace::StackTraceOptions>( 19 static_cast<v8::StackTrace::StackTraceOptions>(
18 v8::StackTrace::kDetailed | 20 v8::StackTrace::kLineNumber | v8::StackTrace::kColumnOffset |
21 v8::StackTrace::kScriptId | v8::StackTrace::kScriptNameOrSourceURL |
22 v8::StackTrace::kFunctionName |
19 v8::StackTrace::kExposeFramesAcrossSecurityOrigins); 23 v8::StackTrace::kExposeFramesAcrossSecurityOrigins);
20 24
21 std::vector<V8StackTraceImpl::Frame> toFramesVector( 25 V8StackTraceImpl::Frame toFrame(v8::Local<v8::StackFrame> frame,
22 V8Debugger* debugger, v8::Local<v8::StackTrace> v8StackTrace, 26 WasmTranslation* wasmTranslation) {
23 int maxStackSize) { 27 String16 scriptId = String16::fromInteger(frame->GetScriptId());
24 DCHECK(debugger->isolate()->InContext()); 28 String16 sourceName;
25 int frameCount = std::min(v8StackTrace->GetFrameCount(), maxStackSize); 29 v8::Local<v8::String> sourceNameValue(frame->GetScriptNameOrSourceURL());
26 std::vector<V8StackTraceImpl::Frame> frames; 30 if (!sourceNameValue.IsEmpty())
27 for (int i = 0; i < frameCount; ++i) { 31 sourceName = toProtocolString(sourceNameValue);
28 v8::Local<v8::StackFrame> v8Frame = v8StackTrace->GetFrame(i); 32
29 frames.emplace_back(v8Frame); 33 String16 functionName;
30 // TODO(clemensh): Figure out a way to do this translation only right before 34 v8::Local<v8::String> functionNameValue(frame->GetFunctionName());
31 // sending the stack trace over wire. 35 if (!functionNameValue.IsEmpty())
32 if (v8Frame->IsWasm()) frames.back().translate(debugger->wasmTranslation()); 36 functionName = toProtocolString(functionNameValue);
37
38 int sourceLineNumber = frame->GetLineNumber() - 1;
39 int sourceColumn = frame->GetColumn() - 1;
40 // TODO(clemensh): Figure out a way to do this translation only right before
41 // sending the stack trace over wire.
42 if (frame->IsWasm()) {
43 wasmTranslation->TranslateWasmScriptLocationToProtocolLocation(
44 &scriptId, &sourceLineNumber, &sourceColumn);
33 } 45 }
34 return frames; 46 return V8StackTraceImpl::Frame(functionName, scriptId, sourceName,
47 sourceLineNumber + 1, sourceColumn + 1);
35 } 48 }
36 49
37 void calculateAsyncChain(V8Debugger* debugger, int contextGroupId, 50 void toFramesVector(v8::Local<v8::StackTrace> stackTrace,
38 std::shared_ptr<AsyncStackTrace>* asyncParent, 51 std::vector<V8StackTraceImpl::Frame>& frames,
39 std::shared_ptr<AsyncStackTrace>* asyncCreation, 52 size_t maxStackSize, v8::Isolate* isolate,
40 int* maxAsyncDepth) { 53 V8Debugger* debugger) {
41 *asyncParent = debugger->currentAsyncParent(); 54 DCHECK(isolate->InContext());
42 *asyncCreation = debugger->currentAsyncCreation(); 55 int frameCount = stackTrace->GetFrameCount();
43 if (maxAsyncDepth) *maxAsyncDepth = debugger->maxAsyncCallChainDepth(); 56 if (frameCount > static_cast<int>(maxStackSize))
44 57 frameCount = static_cast<int>(maxStackSize);
45 DCHECK(!*asyncParent || !*asyncCreation || 58 WasmTranslation* wasmTranslation = debugger->wasmTranslation();
46 (*asyncParent)->contextGroupId() == 59 for (int i = 0; i < frameCount; i++) {
47 (*asyncCreation)->contextGroupId()); 60 v8::Local<v8::StackFrame> stackFrame = stackTrace->GetFrame(i);
48 // Do not accidentally append async call chain from another group. This should 61 frames.push_back(toFrame(stackFrame, wasmTranslation));
49 // not happen if we have proper instrumentation, but let's double-check to be
50 // safe.
51 if (contextGroupId && *asyncParent && (*asyncParent)->contextGroupId() &&
52 (*asyncParent)->contextGroupId() != contextGroupId) {
53 asyncParent->reset();
54 asyncCreation->reset();
55 if (maxAsyncDepth) *maxAsyncDepth = 0;
56 return;
57 } 62 }
58
59 // Only the top stack in the chain may be empty and doesn't contain creation
60 // stack, so ensure that second stack is non-empty (it's the top of appended
61 // chain).
62 if (*asyncParent && !(*asyncCreation) && !(*asyncParent)->creation().lock() &&
63 (*asyncParent)->isEmpty()) {
64 *asyncParent = (*asyncParent)->parent().lock();
65 }
66 }
67
68 std::unique_ptr<protocol::Runtime::StackTrace> buildInspectorObjectCommon(
69 const std::vector<V8StackTraceImpl::Frame>& frames,
70 const std::shared_ptr<AsyncStackTrace>& asyncParent,
71 const std::shared_ptr<AsyncStackTrace>& asyncCreation, int maxAsyncDepth) {
72 std::unique_ptr<protocol::Array<protocol::Runtime::CallFrame>>
73 inspectorFrames = protocol::Array<protocol::Runtime::CallFrame>::create();
74 for (size_t i = 0; i < frames.size(); i++) {
75 inspectorFrames->addItem(frames[i].buildInspectorObject());
76 }
77 std::unique_ptr<protocol::Runtime::StackTrace> stackTrace =
78 protocol::Runtime::StackTrace::create()
79 .setCallFrames(std::move(inspectorFrames))
80 .build();
81 if (asyncParent && maxAsyncDepth > 0) {
82 stackTrace->setParent(asyncParent->buildInspectorObject(asyncCreation.get(),
83 maxAsyncDepth - 1));
84 }
85 return stackTrace;
86 } 63 }
87 64
88 } // namespace 65 } // namespace
89 66
90 V8StackTraceImpl::Frame::Frame(v8::Local<v8::StackFrame> v8Frame) 67 V8StackTraceImpl::Frame::Frame(const String16& functionName,
91 : m_functionName(toProtocolString(v8Frame->GetFunctionName())), 68 const String16& scriptId,
92 m_scriptId(String16::fromInteger(v8Frame->GetScriptId())), 69 const String16& scriptName, int lineNumber,
93 m_sourceURL(toProtocolString(v8Frame->GetScriptNameOrSourceURL())), 70 int column)
94 m_lineNumber(v8Frame->GetLineNumber() - 1), 71 : m_functionName(functionName),
95 m_columnNumber(v8Frame->GetColumn() - 1) { 72 m_scriptId(scriptId),
96 DCHECK(m_lineNumber + 1 != v8::Message::kNoLineNumberInfo); 73 m_scriptName(scriptName),
97 DCHECK(m_columnNumber + 1 != v8::Message::kNoColumnInfo); 74 m_lineNumber(lineNumber),
75 m_columnNumber(column) {
76 DCHECK(m_lineNumber != v8::Message::kNoLineNumberInfo);
77 DCHECK(m_columnNumber != v8::Message::kNoColumnInfo);
98 } 78 }
99 79
100 void V8StackTraceImpl::Frame::translate(WasmTranslation* wasmTranslation) { 80 // buildInspectorObject() and SourceLocation's toTracedValue() should set the
101 wasmTranslation->TranslateWasmScriptLocationToProtocolLocation( 81 // same fields.
102 &m_scriptId, &m_lineNumber, &m_columnNumber); 82 // If either of them is modified, the other should be also modified.
103 }
104
105 const String16& V8StackTraceImpl::Frame::functionName() const {
106 return m_functionName;
107 }
108
109 const String16& V8StackTraceImpl::Frame::scriptId() const { return m_scriptId; }
110
111 const String16& V8StackTraceImpl::Frame::sourceURL() const {
112 return m_sourceURL;
113 }
114
115 int V8StackTraceImpl::Frame::lineNumber() const { return m_lineNumber; }
116
117 int V8StackTraceImpl::Frame::columnNumber() const { return m_columnNumber; }
118
119 std::unique_ptr<protocol::Runtime::CallFrame> 83 std::unique_ptr<protocol::Runtime::CallFrame>
120 V8StackTraceImpl::Frame::buildInspectorObject() const { 84 V8StackTraceImpl::Frame::buildInspectorObject() const {
121 return protocol::Runtime::CallFrame::create() 85 return protocol::Runtime::CallFrame::create()
122 .setFunctionName(m_functionName) 86 .setFunctionName(m_functionName)
123 .setScriptId(m_scriptId) 87 .setScriptId(m_scriptId)
124 .setUrl(m_sourceURL) 88 .setUrl(m_scriptName)
125 .setLineNumber(m_lineNumber) 89 .setLineNumber(m_lineNumber - 1)
126 .setColumnNumber(m_columnNumber) 90 .setColumnNumber(m_columnNumber - 1)
127 .build(); 91 .build();
128 } 92 }
129 93
130 // static 94 // static
131 void V8StackTraceImpl::setCaptureStackTraceForUncaughtExceptions( 95 void V8StackTraceImpl::setCaptureStackTraceForUncaughtExceptions(
132 v8::Isolate* isolate, bool capture) { 96 v8::Isolate* isolate, bool capture) {
133 isolate->SetCaptureStackTraceForUncaughtExceptions( 97 isolate->SetCaptureStackTraceForUncaughtExceptions(
134 capture, V8StackTraceImpl::maxCallStackSizeToCapture); 98 capture, V8StackTraceImpl::maxCallStackSizeToCapture, stackTraceOptions);
135 } 99 }
136 100
137 // static 101 // static
138 std::unique_ptr<V8StackTraceImpl> V8StackTraceImpl::create( 102 std::unique_ptr<V8StackTraceImpl> V8StackTraceImpl::create(
139 V8Debugger* debugger, int contextGroupId, 103 V8Debugger* debugger, int contextGroupId,
140 v8::Local<v8::StackTrace> v8StackTrace, int maxStackSize) { 104 v8::Local<v8::StackTrace> stackTrace, size_t maxStackSize,
105 const String16& description) {
141 DCHECK(debugger); 106 DCHECK(debugger);
142 107 v8::Isolate* isolate = debugger->inspector()->isolate();
143 v8::Isolate* isolate = debugger->isolate();
144 v8::HandleScope scope(isolate); 108 v8::HandleScope scope(isolate);
145
146 std::vector<V8StackTraceImpl::Frame> frames; 109 std::vector<V8StackTraceImpl::Frame> frames;
147 if (!v8StackTrace.IsEmpty() && v8StackTrace->GetFrameCount()) { 110 if (!stackTrace.IsEmpty()) {
148 frames = toFramesVector(debugger, v8StackTrace, maxStackSize); 111 toFramesVector(stackTrace, frames, maxStackSize, isolate, debugger);
149 } 112 }
150 113
151 int maxAsyncDepth = 0; 114 int maxAsyncCallChainDepth = 1;
152 std::shared_ptr<AsyncStackTrace> asyncParent; 115 V8StackTraceImpl* asyncCallChain = nullptr;
153 std::shared_ptr<AsyncStackTrace> asyncCreation; 116 V8StackTraceImpl* creationStack = nullptr;
154 calculateAsyncChain(debugger, contextGroupId, &asyncParent, &asyncCreation, 117 if (maxStackSize > 1) {
155 &maxAsyncDepth); 118 asyncCallChain = debugger->currentAsyncCallChain();
156 if (frames.empty() && !asyncCreation && !asyncParent) return nullptr; 119 creationStack = debugger->currentAsyncTaskCreationStack();
157 return std::unique_ptr<V8StackTraceImpl>( 120 maxAsyncCallChainDepth = debugger->maxAsyncCallChainDepth();
158 new V8StackTraceImpl(frames, maxAsyncDepth, asyncParent, asyncCreation)); 121 }
122
123 // Do not accidentally append async call chain from another group. This should
124 // not happen if we have proper instrumentation, but let's double-check to be
125 // safe.
126 if (contextGroupId && asyncCallChain && asyncCallChain->m_contextGroupId &&
127 asyncCallChain->m_contextGroupId != contextGroupId) {
128 asyncCallChain = nullptr;
129 creationStack = nullptr;
130 maxAsyncCallChainDepth = 1;
131 }
132
133 // Only the top stack in the chain may be empty and doesn't contain creation
134 // stack , so ensure that second stack is non-empty (it's the top of appended
135 // chain).
136 if (asyncCallChain && !creationStack && !asyncCallChain->m_creation &&
137 asyncCallChain->isEmpty()) {
138 asyncCallChain = asyncCallChain->m_parent.get();
139 }
140
141 if (frames.empty() && !creationStack && !asyncCallChain) return nullptr;
142
143 // When async call chain is empty but doesn't contain useful schedule stack
144 // and parent async call chain contains creationg stack but doesn't
145 // synchronous we can merge them together.
146 // e.g. Promise ThenableJob.
147 if (asyncCallChain && frames.empty() &&
148 asyncCallChain->m_description == description && !creationStack) {
149 return asyncCallChain->cloneImpl();
150 }
151
152 std::unique_ptr<V8StackTraceImpl> result(new V8StackTraceImpl(
153 contextGroupId, description, frames,
154 asyncCallChain ? asyncCallChain->cloneImpl() : nullptr,
155 creationStack ? creationStack->cloneImpl() : nullptr));
156
157 // Crop to not exceed maxAsyncCallChainDepth.
158 V8StackTraceImpl* deepest = result.get();
159 while (deepest && maxAsyncCallChainDepth) {
160 deepest = deepest->m_parent.get();
161 maxAsyncCallChainDepth--;
162 }
163 if (deepest) deepest->m_parent.reset();
164
165 return result;
159 } 166 }
160 167
161 // static 168 // static
162 std::unique_ptr<V8StackTraceImpl> V8StackTraceImpl::capture( 169 std::unique_ptr<V8StackTraceImpl> V8StackTraceImpl::capture(
163 V8Debugger* debugger, int contextGroupId, int maxStackSize) { 170 V8Debugger* debugger, int contextGroupId, size_t maxStackSize,
171 const String16& description) {
164 DCHECK(debugger); 172 DCHECK(debugger);
165 v8::Isolate* isolate = debugger->isolate(); 173 v8::Isolate* isolate = debugger->inspector()->isolate();
166 v8::HandleScope handleScope(isolate); 174 v8::HandleScope handleScope(isolate);
167 v8::Local<v8::StackTrace> v8StackTrace; 175 v8::Local<v8::StackTrace> stackTrace;
168 if (isolate->InContext()) { 176 if (isolate->InContext()) {
169 v8StackTrace = v8::StackTrace::CurrentStackTrace(isolate, maxStackSize, 177 stackTrace = v8::StackTrace::CurrentStackTrace(
170 stackTraceOptions); 178 isolate, static_cast<int>(maxStackSize), stackTraceOptions);
171 } 179 }
172 return V8StackTraceImpl::create(debugger, contextGroupId, v8StackTrace, 180 return V8StackTraceImpl::create(debugger, contextGroupId, stackTrace,
173 maxStackSize); 181 maxStackSize, description);
174 } 182 }
175 183
176 V8StackTraceImpl::V8StackTraceImpl( 184 std::unique_ptr<V8StackTraceImpl> V8StackTraceImpl::cloneImpl() {
177 const std::vector<Frame> frames, int maxAsyncDepth, 185 std::vector<Frame> framesCopy(m_frames);
178 std::shared_ptr<AsyncStackTrace> asyncParent, 186 std::unique_ptr<V8StackTraceImpl> copy(
179 std::shared_ptr<AsyncStackTrace> asyncCreation) 187 new V8StackTraceImpl(m_contextGroupId, m_description, framesCopy,
180 : m_frames(frames), 188 m_parent ? m_parent->cloneImpl() : nullptr,
181 m_maxAsyncDepth(maxAsyncDepth), 189 m_creation ? m_creation->cloneImpl() : nullptr));
182 m_asyncParent(asyncParent), 190 return copy;
183 m_asyncCreation(asyncCreation) {} 191 }
192
193 std::unique_ptr<V8StackTrace> V8StackTraceImpl::clone() {
194 std::vector<Frame> frames;
195 for (size_t i = 0; i < m_frames.size(); i++) {
196 frames.push_back(m_frames.at(i));
197 }
198 return std::unique_ptr<V8StackTraceImpl>(new V8StackTraceImpl(
199 m_contextGroupId, m_description, frames, nullptr, nullptr));
200 }
201
202 V8StackTraceImpl::V8StackTraceImpl(int contextGroupId,
203 const String16& description,
204 std::vector<Frame>& frames,
205 std::unique_ptr<V8StackTraceImpl> parent,
206 std::unique_ptr<V8StackTraceImpl> creation)
207 : m_contextGroupId(contextGroupId),
208 m_description(description),
209 m_parent(std::move(parent)),
210 m_creation(std::move(creation)) {
211 m_frames.swap(frames);
212 }
184 213
185 V8StackTraceImpl::~V8StackTraceImpl() {} 214 V8StackTraceImpl::~V8StackTraceImpl() {}
186 215
187 std::unique_ptr<V8StackTrace> V8StackTraceImpl::clone() {
188 return std::unique_ptr<V8StackTrace>(
189 new V8StackTraceImpl(m_frames, 0, std::shared_ptr<AsyncStackTrace>(),
190 std::shared_ptr<AsyncStackTrace>()));
191 }
192
193 bool V8StackTraceImpl::isEmpty() const { return m_frames.empty(); }
194
195 StringView V8StackTraceImpl::topSourceURL() const { 216 StringView V8StackTraceImpl::topSourceURL() const {
196 return toStringView(m_frames[0].sourceURL()); 217 DCHECK(m_frames.size());
218 return toStringView(m_frames[0].m_scriptName);
197 } 219 }
198 220
199 int V8StackTraceImpl::topLineNumber() const { 221 int V8StackTraceImpl::topLineNumber() const {
200 return m_frames[0].lineNumber() + 1; 222 DCHECK(m_frames.size());
223 return m_frames[0].m_lineNumber;
201 } 224 }
202 225
203 int V8StackTraceImpl::topColumnNumber() const { 226 int V8StackTraceImpl::topColumnNumber() const {
204 return m_frames[0].columnNumber() + 1; 227 DCHECK(m_frames.size());
228 return m_frames[0].m_columnNumber;
229 }
230
231 StringView V8StackTraceImpl::topFunctionName() const {
232 DCHECK(m_frames.size());
233 return toStringView(m_frames[0].m_functionName);
205 } 234 }
206 235
207 StringView V8StackTraceImpl::topScriptId() const { 236 StringView V8StackTraceImpl::topScriptId() const {
208 return toStringView(m_frames[0].scriptId()); 237 DCHECK(m_frames.size());
209 } 238 return toStringView(m_frames[0].m_scriptId);
210
211 StringView V8StackTraceImpl::topFunctionName() const {
212 return toStringView(m_frames[0].functionName());
213 } 239 }
214 240
215 std::unique_ptr<protocol::Runtime::StackTrace> 241 std::unique_ptr<protocol::Runtime::StackTrace>
216 V8StackTraceImpl::buildInspectorObjectImpl() const { 242 V8StackTraceImpl::buildInspectorObjectImpl() const {
217 return buildInspectorObjectCommon(m_frames, m_asyncParent.lock(), 243 return buildInspectorObjectImpl(nullptr);
218 m_asyncCreation.lock(), m_maxAsyncDepth); 244 }
245
246 std::unique_ptr<protocol::Runtime::StackTrace>
247 V8StackTraceImpl::buildInspectorObjectImpl(V8StackTraceImpl* creation) const {
248 std::unique_ptr<protocol::Array<protocol::Runtime::CallFrame>> frames =
249 protocol::Array<protocol::Runtime::CallFrame>::create();
250 for (size_t i = 0; i < m_frames.size(); i++)
251 frames->addItem(m_frames.at(i).buildInspectorObject());
252
253 std::unique_ptr<protocol::Runtime::StackTrace> stackTrace =
254 protocol::Runtime::StackTrace::create()
255 .setCallFrames(std::move(frames))
256 .build();
257 if (!m_description.isEmpty()) stackTrace->setDescription(m_description);
258 if (m_parent) {
259 stackTrace->setParent(m_parent->buildInspectorObjectImpl(m_creation.get()));
260 }
261 if (creation && creation->m_frames.size()) {
262 stackTrace->setPromiseCreationFrame(
263 creation->m_frames[0].buildInspectorObject());
264 }
265 return stackTrace;
266 }
267
268 // static
269 std::unique_ptr<protocol::Runtime::StackTrace>
270 V8StackTraceImpl::buildInspectorObjectForTail(V8Debugger* debugger) {
271 DCHECK(debugger);
272 v8::HandleScope handleScope(debugger->inspector()->isolate());
273 // Next call collapses possible empty stack and ensures
274 // maxAsyncCallChainDepth.
275 V8StackTraceImpl* asyncChain = debugger->currentAsyncCallChain();
276 if (!asyncChain) return nullptr;
277 std::unique_ptr<V8StackTraceImpl> fullChain = V8StackTraceImpl::create(
278 debugger, asyncChain->m_contextGroupId, v8::Local<v8::StackTrace>(),
279 V8StackTraceImpl::maxCallStackSizeToCapture);
280 if (!fullChain || !fullChain->m_parent) return nullptr;
281 return fullChain->m_parent->buildInspectorObjectImpl(
282 fullChain->m_creation.get());
219 } 283 }
220 284
221 std::unique_ptr<protocol::Runtime::API::StackTrace> 285 std::unique_ptr<protocol::Runtime::API::StackTrace>
222 V8StackTraceImpl::buildInspectorObject() const { 286 V8StackTraceImpl::buildInspectorObject() const {
223 return buildInspectorObjectImpl(); 287 return buildInspectorObjectImpl(nullptr);
224 } 288 }
225 289
226 std::unique_ptr<StringBuffer> V8StackTraceImpl::toString() const { 290 std::unique_ptr<StringBuffer> V8StackTraceImpl::toString() const {
227 String16Builder stackTrace; 291 String16Builder stackTrace;
228 for (size_t i = 0; i < m_frames.size(); ++i) { 292 for (size_t i = 0; i < m_frames.size(); ++i) {
229 const Frame& frame = m_frames[i]; 293 const Frame& frame = m_frames[i];
230 stackTrace.append("\n at " + (frame.functionName().length() 294 stackTrace.append("\n at " + (frame.functionName().length()
231 ? frame.functionName() 295 ? frame.functionName()
232 : "(anonymous function)")); 296 : "(anonymous function)"));
233 stackTrace.append(" ("); 297 stackTrace.append(" (");
234 stackTrace.append(frame.sourceURL()); 298 stackTrace.append(frame.sourceURL());
235 stackTrace.append(':'); 299 stackTrace.append(':');
236 stackTrace.append(String16::fromInteger(frame.lineNumber())); 300 stackTrace.append(String16::fromInteger(frame.lineNumber()));
237 stackTrace.append(':'); 301 stackTrace.append(':');
238 stackTrace.append(String16::fromInteger(frame.columnNumber())); 302 stackTrace.append(String16::fromInteger(frame.columnNumber()));
239 stackTrace.append(')'); 303 stackTrace.append(')');
240 } 304 }
241 String16 string = stackTrace.toString(); 305 String16 string = stackTrace.toString();
242 return StringBufferImpl::adopt(string); 306 return StringBufferImpl::adopt(string);
243 } 307 }
244 308
245 // static
246 std::shared_ptr<AsyncStackTrace> AsyncStackTrace::capture(
247 V8Debugger* debugger, int contextGroupId, const String16& description,
248 int maxStackSize) {
249 DCHECK(debugger);
250
251 v8::Isolate* isolate = debugger->isolate();
252 v8::HandleScope handleScope(isolate);
253
254 std::vector<V8StackTraceImpl::Frame> frames;
255 if (isolate->InContext()) {
256 v8::Local<v8::StackTrace> v8StackTrace = v8::StackTrace::CurrentStackTrace(
257 isolate, maxStackSize, stackTraceOptions);
258 frames = toFramesVector(debugger, v8StackTrace, maxStackSize);
259 }
260
261 std::shared_ptr<AsyncStackTrace> asyncParent;
262 std::shared_ptr<AsyncStackTrace> asyncCreation;
263 calculateAsyncChain(debugger, contextGroupId, &asyncParent, &asyncCreation,
264 nullptr);
265
266 if (frames.empty() && !asyncCreation && !asyncParent) return nullptr;
267
268 // When async call chain is empty but doesn't contain useful schedule stack
269 // and parent async call chain contains creationg stack but doesn't
270 // synchronous we can merge them together.
271 // e.g. Promise ThenableJob.
272 if (asyncParent && frames.empty() &&
273 asyncParent->m_description == description && !asyncCreation) {
274 return asyncParent;
275 }
276
277 return std::shared_ptr<AsyncStackTrace>(new AsyncStackTrace(
278 contextGroupId, description, frames, asyncParent, asyncCreation));
279 }
280
281 AsyncStackTrace::AsyncStackTrace(
282 int contextGroupId, const String16& description,
283 const std::vector<V8StackTraceImpl::Frame>& frames,
284 std::shared_ptr<AsyncStackTrace> asyncParent,
285 std::shared_ptr<AsyncStackTrace> asyncCreation)
286 : m_contextGroupId(contextGroupId),
287 m_description(description),
288 m_frames(frames),
289 m_asyncParent(asyncParent),
290 m_asyncCreation(asyncCreation) {}
291
292 std::unique_ptr<protocol::Runtime::StackTrace>
293 AsyncStackTrace::buildInspectorObject(AsyncStackTrace* asyncCreation,
294 int maxAsyncDepth) const {
295 std::unique_ptr<protocol::Runtime::StackTrace> stackTrace =
296 buildInspectorObjectCommon(m_frames, m_asyncParent.lock(),
297 m_asyncCreation.lock(), maxAsyncDepth);
298 if (!m_description.isEmpty()) stackTrace->setDescription(m_description);
299 if (asyncCreation && !asyncCreation->isEmpty()) {
300 stackTrace->setPromiseCreationFrame(
301 asyncCreation->m_frames[0].buildInspectorObject());
302 }
303 return stackTrace;
304 }
305
306 int AsyncStackTrace::contextGroupId() const { return m_contextGroupId; }
307
308 std::weak_ptr<AsyncStackTrace> AsyncStackTrace::parent() const {
309 return m_asyncParent;
310 }
311
312 std::weak_ptr<AsyncStackTrace> AsyncStackTrace::creation() const {
313 return m_asyncCreation;
314 }
315
316 bool AsyncStackTrace::isEmpty() const { return m_frames.empty(); }
317
318 } // namespace v8_inspector 309 } // namespace v8_inspector
OLDNEW
« no previous file with comments | « src/inspector/v8-stack-trace-impl.h ('k') | test/inspector/debugger/async-stacks-limit.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698