Commit b98dd0af authored by kozyatinskiy's avatar kozyatinskiy Committed by Commit bot

[inspector] added creation frame for async call chains for promises

With creation frame we can show additional information with description of each async stack trace, which could help user to understand where promises were chained.
At least in case of Promise.resolve().then(foo1).then(foo2) we would be able to show following stack trace for break in foo2 callback:

foo2 (test.js:14:2)
-- Promise.resolve (test.js:29:14)--
-- Promise.resolve (test.js:28:14)--
promiseThen (test.js:30:2)

More details: https://docs.google.com/document/d/1u19N45f1gSF7M39mGsycJEK3IPyJgIXCBnWyiPeuJFE

BUG=v8:5738
R=dgozman@chromium.org,gsathya@chromium.org

Review-Url: https://codereview.chromium.org/2648873002
Cr-Commit-Position: refs/heads/master@{#42682}
parent 25bfdf1b
......@@ -201,7 +201,8 @@
"properties": [
{ "name": "description", "type": "string", "optional": true, "description": "String label of this stack trace. For async traces this may be a name of the function that initiated the async call." },
{ "name": "callFrames", "type": "array", "items": { "$ref": "CallFrame" }, "description": "JavaScript function name." },
{ "name": "parent", "$ref": "StackTrace", "optional": true, "description": "Asynchronous JavaScript stack trace that preceded this stack, if available." }
{ "name": "parent", "$ref": "StackTrace", "optional": true, "description": "Asynchronous JavaScript stack trace that preceded this stack, if available." },
{ "name": "promiseCreationFrame", "$ref": "CallFrame", "optional": true, "experimental": true, "description": "Creation frame of the Promise which produced the next synchronous trace when resolved, if available." }
]
}
],
......
......@@ -862,9 +862,32 @@ void V8Debugger::setAsyncCallStackDepth(V8DebuggerAgentImpl* agent, int depth) {
if (!maxAsyncCallStackDepth) allAsyncTasksCanceled();
}
void V8Debugger::registerAsyncTaskIfNeeded(void* task) {
if (m_taskToId.find(task) != m_taskToId.end()) return;
int id = ++m_lastTaskId;
m_taskToId[task] = id;
m_idToTask[id] = task;
if (static_cast<int>(m_idToTask.size()) > m_maxAsyncCallStacks) {
void* taskToRemove = m_idToTask.begin()->second;
asyncTaskCanceled(taskToRemove);
}
}
void V8Debugger::asyncTaskCreated(void* task, void* parentTask) {
if (!m_maxAsyncCallStackDepth) return;
if (parentTask) m_parentTask[task] = parentTask;
v8::HandleScope scope(m_isolate);
// We don't need to pass context group id here because we gets this callback
// from V8 for promise events only.
// Passing one as maxStackSize forces no async chain for the new stack and
// allows us to not grow exponentially.
std::unique_ptr<V8StackTraceImpl> creationStack =
V8StackTraceImpl::capture(this, 0, 1, String16());
if (creationStack && !creationStack->isEmpty()) {
m_asyncTaskCreationStacks[task] = std::move(creationStack);
registerAsyncTaskIfNeeded(task);
}
}
void V8Debugger::asyncTaskScheduled(const StringView& taskName, void* task,
......@@ -887,13 +910,7 @@ void V8Debugger::asyncTaskScheduled(const String16& taskName, void* task,
if (chain) {
m_asyncTaskStacks[task] = std::move(chain);
if (recurring) m_recurringTasks.insert(task);
int id = ++m_lastTaskId;
m_taskToId[task] = id;
m_idToTask[id] = task;
if (static_cast<int>(m_idToTask.size()) > m_maxAsyncCallStacks) {
void* taskToRemove = m_idToTask.begin()->second;
asyncTaskCanceled(taskToRemove);
}
registerAsyncTaskIfNeeded(task);
}
}
......@@ -902,6 +919,7 @@ void V8Debugger::asyncTaskCanceled(void* task) {
m_asyncTaskStacks.erase(task);
m_recurringTasks.erase(task);
m_parentTask.erase(task);
m_asyncTaskCreationStacks.erase(task);
auto it = m_taskToId.find(task);
if (it == m_taskToId.end()) return;
m_idToTask.erase(it->second);
......@@ -924,6 +942,10 @@ void V8Debugger::asyncTaskStarted(void* task) {
std::unique_ptr<V8StackTraceImpl> stack;
if (stackIt != m_asyncTaskStacks.end() && stackIt->second)
stack = stackIt->second->cloneImpl();
auto itCreation = m_asyncTaskCreationStacks.find(task);
if (stack && itCreation != m_asyncTaskCreationStacks.end()) {
stack->setCreation(itCreation->second->cloneImpl());
}
m_currentStacks.push_back(std::move(stack));
}
......@@ -947,6 +969,7 @@ void V8Debugger::allAsyncTasksCanceled() {
m_currentStacks.clear();
m_currentTasks.clear();
m_parentTask.clear();
m_asyncTaskCreationStacks.clear();
m_idToTask.clear();
m_taskToId.clear();
m_lastTaskId = 0;
......
......@@ -134,6 +134,7 @@ class V8Debugger : public v8::debug::DebugDelegate {
v8::Local<v8::Value>);
void asyncTaskCreated(void* task, void* parentTask);
void registerAsyncTaskIfNeeded(void* task);
// v8::debug::DebugEventListener implementation.
void PromiseEventOccurred(v8::debug::PromiseDebugActionType type, int id,
......@@ -166,6 +167,7 @@ class V8Debugger : public v8::debug::DebugDelegate {
using AsyncTaskToStackTrace =
protocol::HashMap<void*, std::unique_ptr<V8StackTraceImpl>>;
AsyncTaskToStackTrace m_asyncTaskStacks;
AsyncTaskToStackTrace m_asyncTaskCreationStacks;
int m_maxAsyncCallStacks;
std::map<int, void*> m_idToTask;
std::unordered_map<void*, int> m_taskToId;
......
......@@ -141,10 +141,13 @@ std::unique_ptr<V8StackTraceImpl> V8StackTraceImpl::create(
maxAsyncCallChainDepth = 1;
}
// Only the top stack in the chain may be empty, so ensure that second stack
// is non-empty (it's the top of appended chain).
if (asyncCallChain && asyncCallChain->isEmpty())
// 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) {
asyncCallChain = asyncCallChain->m_parent.get();
}
if (stackTrace.IsEmpty() && !asyncCallChain) return nullptr;
......@@ -180,9 +183,11 @@ std::unique_ptr<V8StackTraceImpl> V8StackTraceImpl::capture(
std::unique_ptr<V8StackTraceImpl> V8StackTraceImpl::cloneImpl() {
std::vector<Frame> framesCopy(m_frames);
return std::unique_ptr<V8StackTraceImpl>(
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());
return copy;
}
std::unique_ptr<V8StackTrace> V8StackTraceImpl::clone() {
......@@ -205,6 +210,19 @@ V8StackTraceImpl::V8StackTraceImpl(int contextGroupId,
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);
......@@ -243,6 +261,10 @@ V8StackTraceImpl::buildInspectorObjectImpl() const {
.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()) {
stackTrace->setPromiseCreationFrame(
m_creation->m_frames[0].buildInspectorObject());
}
return stackTrace;
}
......
......@@ -81,6 +81,8 @@ class V8StackTraceImpl final : public V8StackTrace {
const override;
std::unique_ptr<StringBuffer> toString() const override;
void setCreation(std::unique_ptr<V8StackTraceImpl> creation);
private:
V8StackTraceImpl(int contextGroupId, const String16& description,
std::vector<Frame>& frames,
......@@ -90,6 +92,7 @@ class V8StackTraceImpl final : public V8StackTrace {
String16 m_description;
std::vector<Frame> m_frames;
std::unique_ptr<V8StackTraceImpl> m_parent;
std::unique_ptr<V8StackTraceImpl> m_creation;
DISALLOW_COPY_AND_ASSIGN(V8StackTraceImpl);
};
......
Checks that async stacks works for async/await
foo2 (test.js:15:2)
-- async function (test.js:13:19)--
foo2 (test.js:13:19)
test (test.js:24:8)
(anonymous) (expr.js:0:0)
foo2 (test.js:17:2)
-- async function (test.js:13:19)--
foo2 (test.js:13:19)
test (test.js:24:8)
(anonymous) (expr.js:0:0)
foo1 (test.js:9:2)
foo2 (test.js:18:8)
-- async function (test.js:13:19)--
foo2 (test.js:13:19)
test (test.js:24:8)
(anonymous) (expr.js:0:0)
foo1 (test.js:9:2)
(anonymous) (expr.js:0:0)
-- Promise.resolve (test.js:19:43)--
-- Promise.resolve (test.js:19:16)--
foo2 (test.js:19:30)
-- async function (test.js:13:19)--
foo2 (test.js:13:19)
test (test.js:24:8)
(anonymous) (expr.js:0:0)
foo2 (test.js:20:2)
-- async function (test.js:13:19)--
foo2 (test.js:13:19)
test (test.js:24:8)
(anonymous) (expr.js:0:0)
......
......@@ -28,12 +28,7 @@ async function test() {
InspectorTest.setupScriptMap();
Protocol.Debugger.onPaused(message => {
InspectorTest.logCallFrames(message.params.callFrames);
var asyncStackTrace = message.params.asyncStackTrace;
while (asyncStackTrace) {
InspectorTest.log(`-- ${asyncStackTrace.description} --`);
InspectorTest.logCallFrames(asyncStackTrace.callFrames);
asyncStackTrace = asyncStackTrace.parent;
}
InspectorTest.logAsyncStackTrace(message.params.asyncStackTrace);
InspectorTest.log('');
Protocol.Debugger.resume();
});
......
Checks created frame for async call chain
Running test: testPromise
foo1 (test.js:10:2)
-- Promise.resolve (test.js:20:14)--
promise (test.js:21:2)
(anonymous) (expr.js:0:0)
Running test: testPromiseThen
foo1 (test.js:10:2)
-- Promise.resolve (test.js:28:14)--
promiseThen (test.js:30:2)
(anonymous) (expr.js:0:0)
foo2 (test.js:14:2)
-- Promise.resolve (test.js:29:14)--
-- Promise.resolve (test.js:28:14)--
promiseThen (test.js:30:2)
(anonymous) (expr.js:0:0)
Running test: testPromiseThenThen
foo1 (test.js:10:2)
-- Promise.resolve (test.js:37:14)--
promiseThenThen (test.js:39:2)
(anonymous) (expr.js:0:0)
foo1 (test.js:10:2)
-- Promise.resolve (test.js:38:14)--
promiseThenThen (test.js:39:2)
(anonymous) (expr.js:0:0)
foo2 (test.js:14:2)
-- Promise.resolve (test.js:37:25)--
-- Promise.resolve (test.js:37:14)--
promiseThenThen (test.js:39:2)
(anonymous) (expr.js:0:0)
Running test: testPromiseResolve
foo1 (test.js:10:2)
-- Promise.resolve (test.js:44:27)--
promiseResolve (test.js:44:17)
(anonymous) (expr.js:0:0)
Running test: testPromiseReject
foo1 (test.js:10:2)
-- Promise.reject (test.js:48:31)--
promiseReject (test.js:48:17)
(anonymous) (expr.js:0:0)
Running test: testPromiseAll
foo1 (test.js:10:2)
-- Promise.resolve (test.js:52:44)--
-- Promise.resolve (test.js:52:17)--
promiseAll (test.js:52:31)
(anonymous) (expr.js:0:0)
Running test: testPromiseRace
foo1 (test.js:10:2)
-- Promise.resolve (test.js:56:45)--
-- Promise.resolve (test.js:56:17)--
promiseRace (test.js:56:32)
(anonymous) (expr.js:0:0)
Running test: testThenableJob1
foo1 (test.js:10:2)
-- Promise.resolve (test.js:60:72)--
-- Promise.resolve (test.js:60:56)--
Promise.resolve.then (test.js:60:46)
-- Promise.resolve (test.js:60:27)--
thenableJob1 (test.js:60:17)
(anonymous) (expr.js:0:0)
Running test: testThenableJob2
foo1 (test.js:10:2)
-- Promise.resolve (test.js:64:57)--
Promise.resolve.then (test.js:64:46)
-- Promise.resolve (test.js:64:27)--
thenableJob2 (test.js:64:17)
(anonymous) (expr.js:0:0)
Running test: testSetTimeouts
foo1 (test.js:10:2)
setTimeout (test.js:72:25)
-- setTimeout --
setTimeout (test.js:72:6)
-- setTimeout --
setTimeout (test.js:71:4)
-- setTimeout --
setTimeouts (test.js:70:2)
(anonymous) (expr.js:0:0)
// Copyright 2017 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.
print('Checks created frame for async call chain');
InspectorTest.addScript(
`
function foo1() {
debugger;
}
function foo2() {
debugger;
}
function promise() {
var resolve;
var p1 = new Promise(r => resolve = r);
var p2 = p1.then(foo1);
resolve();
return p2;
}
function promiseThen() {
var resolve;
var p1 = new Promise(r => resolve = r);
var p2 = p1.then(foo1);
var p3 = p2.then(foo2);
resolve();
return p3;
}
function promiseThenThen() {
var resolve;
var p1 = new Promise(r => resolve = r);
var p2 = p1.then(foo1).then(foo2);
var p3 = p1.then(foo1);
resolve();
return p2;
}
function promiseResolve() {
return Promise.resolve().then(foo1);
}
function promiseReject() {
return Promise.reject().catch(foo1);
}
function promiseAll() {
return Promise.all([ Promise.resolve() ]).then(foo1);
}
function promiseRace() {
return Promise.race([ Promise.resolve() ]).then(foo1);
}
function thenableJob1() {
return Promise.resolve().then(() => Promise.resolve().then(() => 42)).then(foo1);
}
function thenableJob2() {
return Promise.resolve().then(() => Promise.resolve()).then(foo1);
}
function setTimeouts() {
var resolve;
var p = new Promise(r => resolve = r);
setTimeout(() =>
setTimeout(() =>
setTimeout(() => { foo1(); resolve(); }, 0), 0), 0);
return p;
}
//# sourceURL=test.js`,
8, 4);
InspectorTest.setupScriptMap();
Protocol.Debugger.onPaused(message => {
InspectorTest.logCallFrames(message.params.callFrames);
InspectorTest.logAsyncStackTrace(message.params.asyncStackTrace);
InspectorTest.log('');
Protocol.Debugger.resume();
});
Protocol.Debugger.enable();
Protocol.Debugger.setAsyncCallStackDepth({maxDepth: 128});
InspectorTest.runTestSuite([
function testPromise(next) {
Protocol.Runtime
.evaluate(
{expression: 'promise()//# sourceURL=expr.js', awaitPromise: true})
.then(next);
},
function testPromiseThen(next) {
Protocol.Runtime
.evaluate({
expression: 'promiseThen()//# sourceURL=expr.js',
awaitPromise: true
})
.then(next);
},
function testPromiseThenThen(next) {
Protocol.Runtime
.evaluate({
expression: 'promiseThenThen()//# sourceURL=expr.js',
awaitPromise: true
})
.then(next);
},
function testPromiseResolve(next) {
Protocol.Runtime
.evaluate({
expression: 'promiseResolve()//# sourceURL=expr.js',
awaitPromise: true
})
.then(next);
},
function testPromiseReject(next) {
Protocol.Runtime
.evaluate({
expression: 'promiseReject()//# sourceURL=expr.js',
awaitPromise: true
})
.then(next);
},
function testPromiseAll(next) {
Protocol.Runtime
.evaluate({
expression: 'promiseAll()//# sourceURL=expr.js',
awaitPromise: true
})
.then(next);
},
function testPromiseRace(next) {
Protocol.Runtime
.evaluate({
expression: 'promiseRace()//# sourceURL=expr.js',
awaitPromise: true
})
.then(next);
},
function testThenableJob1(next) {
Protocol.Runtime
.evaluate({
expression: 'thenableJob1()//# sourceURL=expr.js',
awaitPromise: true
})
.then(next);
},
function testThenableJob2(next) {
Protocol.Runtime
.evaluate({
expression: 'thenableJob2()//# sourceURL=expr.js',
awaitPromise: true
})
.then(next);
},
function testSetTimeouts(next) {
Protocol.Runtime
.evaluate({
expression: 'setTimeouts()//# sourceURL=expr.js',
awaitPromise: true
})
.then(next);
}
]);
......@@ -2,13 +2,14 @@ Checks that async chains for promises are correct.
Running test: testPromise
foo1 (test.js:9:2)
-- Promise.resolve --
-- Promise.resolve (test.js:19:14)--
promise (test.js:20:2)
(anonymous) (testPromise.js:0:0)
Running test: testPromiseResolvedBySetTimeout
foo1 (test.js:9:2)
-- Promise.resolve (test.js:27:14)--
-- setTimeout --
promiseResolvedBySetTimeout (test.js:28:2)
(anonymous) (testPromiseResolvedBySetTimeout.js:0:0)
......@@ -16,96 +17,103 @@ promiseResolvedBySetTimeout (test.js:28:2)
Running test: testPromiseAll
foo1 (test.js:9:2)
-- Promise.resolve --
-- Promise.resolve (test.js:37:35)--
-- Promise.resolve (test.js:37:19)--
promiseAll (test.js:39:2)
(anonymous) (testPromiseAll.js:0:0)
Running test: testPromiseAllReverseOrder
foo1 (test.js:9:2)
-- Promise.resolve --
-- Promise.resolve (test.js:48:35)--
-- Promise.resolve (test.js:48:19)--
promiseAllReverseOrder (test.js:50:2)
(anonymous) (testPromiseAllReverseOrder.js:0:0)
Running test: testPromiseRace
foo1 (test.js:9:2)
-- Promise.resolve --
-- Promise.resolve (test.js:59:36)--
-- Promise.resolve (test.js:59:19)--
promiseRace (test.js:60:2)
(anonymous) (testPromiseRace.js:0:0)
Running test: testTwoChainedCallbacks
foo1 (test.js:9:2)
-- Promise.resolve --
-- Promise.resolve (test.js:68:14)--
twoChainedCallbacks (test.js:69:2)
(anonymous) (testTwoChainedCallbacks.js:0:0)
foo2 (test.js:13:2)
-- Promise.resolve --
-- Promise.resolve (test.js:68:25)--
-- Promise.resolve (test.js:68:14)--
twoChainedCallbacks (test.js:69:2)
(anonymous) (testTwoChainedCallbacks.js:0:0)
Running test: testPromiseResolve
foo1 (test.js:9:2)
-- Promise.resolve --
-- Promise.resolve (test.js:74:27)--
promiseResolve (test.js:74:17)
(anonymous) (testPromiseResolve.js:0:0)
foo2 (test.js:13:2)
-- Promise.resolve --
-- Promise.resolve (test.js:74:38)--
-- Promise.resolve (test.js:74:27)--
promiseResolve (test.js:74:17)
(anonymous) (testPromiseResolve.js:0:0)
Running test: testThenableJobResolvedInSetTimeout
foo1 (test.js:9:2)
-- Promise.resolve (test.js:86:40)--
-- setTimeout --
thenableJob (test.js:81:4)
p1.then (test.js:86:25)
-- Promise.resolve --
-- Promise.resolve (test.js:86:14)--
thenableJobResolvedInSetTimeout (test.js:87:2)
(anonymous) (testThenableJobResolvedInSetTimeout.js:0:0)
Running test: testThenableJobResolvedInSetTimeoutWithStack
foo1 (test.js:9:2)
-- Promise.resolve --
-- Promise.resolve (test.js:104:40)--
inner (test.js:94:6)
-- setTimeout --
thenableJob (test.js:99:4)
p1.then (test.js:104:25)
-- Promise.resolve --
-- Promise.resolve (test.js:104:14)--
thenableJobResolvedInSetTimeoutWithStack (test.js:105:2)
(anonymous) (testThenableJobResolvedInSetTimeoutWithStack.js:0:0)
Running test: testThenableJobResolvedByPromise
foo1 (test.js:9:2)
-- Promise.resolve --
-- Promise.resolve (test.js:118:40)--
-- Promise.resolve (test.js:113:22)--
thenableJob (test.js:113:12)
p1.then (test.js:118:25)
-- Promise.resolve --
-- Promise.resolve (test.js:118:14)--
thenableJobResolvedByPromise (test.js:119:2)
(anonymous) (testThenableJobResolvedByPromise.js:0:0)
Running test: testThenableJobResolvedByPromiseWithStack
foo1 (test.js:9:2)
-- Promise.resolve --
-- Promise.resolve (test.js:136:40)--
inner (test.js:126:6)
-- Promise.resolve --
-- Promise.resolve (test.js:131:22)--
thenableJob (test.js:131:12)
p1.then (test.js:136:25)
-- Promise.resolve --
-- Promise.resolve (test.js:136:14)--
thenableJobResolvedByPromiseWithStack (test.js:137:2)
(anonymous) (testThenableJobResolvedByPromiseWithStack.js:0:0)
Running test: testLateThenCallback
foo1 (test.js:9:2)
-- Promise.resolve --
-- Promise.resolve (test.js:145:12)--
lateThenCallback (test.js:144:2)
(anonymous) (testLateThenCallback.js:0:0)
......@@ -113,43 +121,54 @@ lateThenCallback (test.js:144:2)
Running test: testComplex
inner1 (test.js:154:6)
foo1 (test.js:156:4)
-- Promise.resolve --
-- Promise.resolve (test.js:202:5)--
inner2 (test.js:162:6)
-- Promise.resolve --
-- Promise.resolve (test.js:165:22)--
foo2 (test.js:165:12)
-- Promise.resolve --
-- Promise.resolve (test.js:201:5)--
inner3 (test.js:172:6)
-- setTimeout --
foo3 (test.js:175:4)
-- Promise.resolve --
-- Promise.resolve (test.js:200:5)--
-- Promise.resolve (test.js:199:5)--
-- Promise.resolve (test.js:188:7)--
-- Promise.resolve (test.js:187:19)--
foo5 (test.js:187:52)
-- Promise.resolve --
-- Promise.resolve (test.js:198:5)--
-- Promise.resolve (test.js:193:7)--
-- Promise.resolve (test.js:192:19)--
foo6 (test.js:192:34)
-- Promise.resolve --
-- Promise.resolve (test.js:197:5)--
complex (test.js:196:18)
(anonymous) (testComplex.js:0:0)
p.then (test.js:207:8)
-- Promise.resolve --
-- Promise.resolve (test.js:206:8)--
-- Promise.resolve (test.js:202:5)--
inner2 (test.js:162:6)
-- Promise.resolve --
-- Promise.resolve (test.js:165:22)--
foo2 (test.js:165:12)
-- Promise.resolve --
-- Promise.resolve (test.js:201:5)--
inner3 (test.js:172:6)
-- setTimeout --
foo3 (test.js:175:4)
-- Promise.resolve --
-- Promise.resolve (test.js:200:5)--
-- Promise.resolve (test.js:199:5)--
-- Promise.resolve (test.js:188:7)--
-- Promise.resolve (test.js:187:19)--
foo5 (test.js:187:52)
-- Promise.resolve --
-- Promise.resolve (test.js:198:5)--
-- Promise.resolve (test.js:193:7)--
-- Promise.resolve (test.js:192:19)--
foo6 (test.js:192:34)
-- Promise.resolve --
-- Promise.resolve (test.js:197:5)--
complex (test.js:196:18)
(anonymous) (testComplex.js:0:0)
Running test: testReject
foo1 (test.js:9:2)
-- Promise.reject --
-- Promise.reject (test.js:217:31)--
reject (test.js:217:17)
(anonymous) (testReject.js:0:0)
......@@ -222,12 +222,7 @@ function reject() {
InspectorTest.setupScriptMap();
Protocol.Debugger.onPaused(message => {
InspectorTest.logCallFrames(message.params.callFrames);
var asyncStackTrace = message.params.asyncStackTrace;
while (asyncStackTrace) {
InspectorTest.log(`-- ${asyncStackTrace.description} --`);
InspectorTest.logCallFrames(asyncStackTrace.callFrames);
asyncStackTrace = asyncStackTrace.parent;
}
InspectorTest.logAsyncStackTrace(message.params.asyncStackTrace);
InspectorTest.log('');
Protocol.Debugger.resume();
});
......
......@@ -4,7 +4,7 @@ Running test: testZeroLimit
foo1 (test.js:11:2)
Running test: testOneLimit
Running test: testTwoLimit
foo1 (test.js:11:2)
-- Promise.resolve --
promise (test.js:23:2)
......@@ -17,11 +17,14 @@ foo1 (test.js:11:2)
foo2 (test.js:15:2)
Running test: testTwoLimitTwoPromises
Running test: testFourLimitTwoPromises
foo1 (test.js:11:2)
foo2 (test.js:15:2)
Running test: testSixLimitTwoPromises
foo1 (test.js:11:2)
-- Promise.resolve --
twoPromises (test.js:34:2)
(anonymous) (expr.js:0:0)
foo2 (test.js:15:2)
-- Promise.resolve --
......@@ -29,7 +32,7 @@ twoPromises (test.js:35:2)
(anonymous) (expr.js:0:0)
Running test: testOneLimitTwoSetTimeouts
Running test: testTwoLimitTwoSetTimeouts
foo1 (test.js:11:2)
foo2 (test.js:15:2)
......@@ -38,7 +41,7 @@ twoSetTimeout (test.js:41:2)
(anonymous) (expr.js:0:0)
Running test: testTwoLimitTwoSetTimeouts
Running test: testThreeLimitTwoSetTimeouts
foo1 (test.js:11:2)
-- setTimeout --
twoSetTimeout (test.js:40:2)
......@@ -84,54 +87,54 @@ foo10 (:0:18)
foo11 (:0:18)
(anonymous) (:0:29)
-- setTimeout --
twentySetTimeout (test.js:55:4)
twentySetTimeout (test.js:49:4)
(anonymous) (expr.js:0:0)
foo12 (:0:18)
(anonymous) (:0:29)
-- setTimeout --
twentySetTimeout (test.js:55:4)
twentySetTimeout (test.js:49:4)
(anonymous) (expr.js:0:0)
foo13 (:0:18)
(anonymous) (:0:29)
-- setTimeout --
twentySetTimeout (test.js:55:4)
twentySetTimeout (test.js:49:4)
(anonymous) (expr.js:0:0)
foo14 (:0:18)
(anonymous) (:0:29)
-- setTimeout --
twentySetTimeout (test.js:55:4)
twentySetTimeout (test.js:49:4)
(anonymous) (expr.js:0:0)
foo15 (:0:18)
(anonymous) (:0:29)
-- setTimeout --
twentySetTimeout (test.js:55:4)
twentySetTimeout (test.js:49:4)
(anonymous) (expr.js:0:0)
foo16 (:0:18)
(anonymous) (:0:29)
-- setTimeout --
twentySetTimeout (test.js:55:4)
twentySetTimeout (test.js:49:4)
(anonymous) (expr.js:0:0)
foo17 (:0:18)
(anonymous) (:0:29)
-- setTimeout --
twentySetTimeout (test.js:55:4)
twentySetTimeout (test.js:49:4)
(anonymous) (expr.js:0:0)
foo18 (:0:18)
(anonymous) (:0:29)
-- setTimeout --
twentySetTimeout (test.js:55:4)
twentySetTimeout (test.js:49:4)
(anonymous) (expr.js:0:0)
foo19 (:0:18)
(anonymous) (:0:29)
-- setTimeout --
twentySetTimeout (test.js:55:4)
twentySetTimeout (test.js:49:4)
(anonymous) (expr.js:0:0)
......@@ -42,12 +42,6 @@ function twoSetTimeout() {
return new Promise(resolve => resolveTest = resolve);
}
function threeSetTimeout() {
setTimeout(foo1, 0);
setTimeout(foo2, 0);
return new Promise(resolve => resolveTest = resolve);
}
function twentySetTimeout() {
var resolve1;
var p1 = new Promise(resolve => resolve1 = resolve);
......@@ -85,11 +79,13 @@ InspectorTest.runTestSuite([
.then(next);
},
function testOneLimit(next) {
Protocol.Runtime.evaluate({
expression: 'setMaxAsyncTaskStacks(1)//# sourceURL=expr.js'})
function testTwoLimit(next) {
// we need one stack for parent task and one for next task.
Protocol.Runtime
.evaluate({expression: 'setMaxAsyncTaskStacks(2)//# sourceURL=expr.js'})
.then(() => Protocol.Runtime.evaluate({
expression: 'promise()//# sourceURL=expr.js', awaitPromise: true
expression: 'promise()//# sourceURL=expr.js',
awaitPromise: true
}))
.then(() => cancelAllAsyncTasks())
.then(next);
......@@ -108,21 +104,23 @@ InspectorTest.runTestSuite([
.then(next);
},
function testTwoLimitTwoPromises(next) {
Protocol.Runtime.evaluate({
expression: 'setMaxAsyncTaskStacks(2)//# sourceURL=expr.js'})
function testFourLimitTwoPromises(next) {
Protocol.Runtime
.evaluate({expression: 'setMaxAsyncTaskStacks(4)//# sourceURL=expr.js'})
.then(() => Protocol.Runtime.evaluate({
expression: 'twoPromises()//# sourceURL=expr.js', awaitPromise: true
expression: 'twoPromises()//# sourceURL=expr.js',
awaitPromise: true
}))
.then(() => cancelAllAsyncTasks())
.then(next);
},
function testOneLimitTwoSetTimeouts(next) {
Protocol.Runtime.evaluate({
expression: 'setMaxAsyncTaskStacks(1)//# sourceURL=expr.js'})
function testSixLimitTwoPromises(next) {
Protocol.Runtime
.evaluate({expression: 'setMaxAsyncTaskStacks(6)//# sourceURL=expr.js'})
.then(() => Protocol.Runtime.evaluate({
expression: 'twoSetTimeout()//# sourceURL=expr.js', awaitPromise: true
expression: 'twoPromises()//# sourceURL=expr.js',
awaitPromise: true
}))
.then(() => cancelAllAsyncTasks())
.then(next);
......@@ -138,6 +136,16 @@ InspectorTest.runTestSuite([
.then(next);
},
function testThreeLimitTwoSetTimeouts(next) {
Protocol.Runtime.evaluate({
expression: 'setMaxAsyncTaskStacks(3)//# sourceURL=expr.js'})
.then(() => Protocol.Runtime.evaluate({
expression: 'twoSetTimeout()//# sourceURL=expr.js', awaitPromise: true
}))
.then(() => cancelAllAsyncTasks())
.then(next);
},
function testTenLimitTwentySetTimeouts(next) {
Protocol.Runtime.evaluate({
expression: 'setMaxAsyncTaskStacks(10)//# sourceURL=expr.js'})
......
......@@ -112,6 +112,21 @@ InspectorTest.logCallFrames = function(callFrames)
}
}
InspectorTest.logAsyncStackTrace = function(asyncStackTrace)
{
while (asyncStackTrace) {
if (asyncStackTrace.promiseCreationFrame) {
var frame = asyncStackTrace.promiseCreationFrame;
InspectorTest.log(`-- ${asyncStackTrace.description} (${frame.url
}:${frame.lineNumber}:${frame.columnNumber})--`);
} else {
InspectorTest.log(`-- ${asyncStackTrace.description} --`);
}
InspectorTest.logCallFrames(asyncStackTrace.callFrames);
asyncStackTrace = asyncStackTrace.parent;
}
}
InspectorTest.completeTest = function()
{
Protocol.Debugger.disable().then(() => quit());
......
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