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

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

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

Powered by Google App Engine
This is Rietveld 408576698