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 @@ ...@@ -201,7 +201,8 @@
"properties": [ "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": "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": "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) { ...@@ -862,9 +862,32 @@ void V8Debugger::setAsyncCallStackDepth(V8DebuggerAgentImpl* agent, int depth) {
if (!maxAsyncCallStackDepth) allAsyncTasksCanceled(); 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) { void V8Debugger::asyncTaskCreated(void* task, void* parentTask) {
if (!m_maxAsyncCallStackDepth) return; if (!m_maxAsyncCallStackDepth) return;
if (parentTask) m_parentTask[task] = parentTask; 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, void V8Debugger::asyncTaskScheduled(const StringView& taskName, void* task,
...@@ -887,13 +910,7 @@ void V8Debugger::asyncTaskScheduled(const String16& taskName, void* task, ...@@ -887,13 +910,7 @@ void V8Debugger::asyncTaskScheduled(const String16& taskName, void* task,
if (chain) { if (chain) {
m_asyncTaskStacks[task] = std::move(chain); m_asyncTaskStacks[task] = std::move(chain);
if (recurring) m_recurringTasks.insert(task); if (recurring) m_recurringTasks.insert(task);
int id = ++m_lastTaskId; registerAsyncTaskIfNeeded(task);
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);
}
} }
} }
...@@ -902,6 +919,7 @@ void V8Debugger::asyncTaskCanceled(void* task) { ...@@ -902,6 +919,7 @@ void V8Debugger::asyncTaskCanceled(void* task) {
m_asyncTaskStacks.erase(task); m_asyncTaskStacks.erase(task);
m_recurringTasks.erase(task); m_recurringTasks.erase(task);
m_parentTask.erase(task); m_parentTask.erase(task);
m_asyncTaskCreationStacks.erase(task);
auto it = m_taskToId.find(task); auto it = m_taskToId.find(task);
if (it == m_taskToId.end()) return; if (it == m_taskToId.end()) return;
m_idToTask.erase(it->second); m_idToTask.erase(it->second);
...@@ -924,6 +942,10 @@ void V8Debugger::asyncTaskStarted(void* task) { ...@@ -924,6 +942,10 @@ void V8Debugger::asyncTaskStarted(void* task) {
std::unique_ptr<V8StackTraceImpl> stack; std::unique_ptr<V8StackTraceImpl> stack;
if (stackIt != m_asyncTaskStacks.end() && stackIt->second) if (stackIt != m_asyncTaskStacks.end() && stackIt->second)
stack = stackIt->second->cloneImpl(); 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)); m_currentStacks.push_back(std::move(stack));
} }
...@@ -947,6 +969,7 @@ void V8Debugger::allAsyncTasksCanceled() { ...@@ -947,6 +969,7 @@ void V8Debugger::allAsyncTasksCanceled() {
m_currentStacks.clear(); m_currentStacks.clear();
m_currentTasks.clear(); m_currentTasks.clear();
m_parentTask.clear(); m_parentTask.clear();
m_asyncTaskCreationStacks.clear();
m_idToTask.clear(); m_idToTask.clear();
m_taskToId.clear(); m_taskToId.clear();
m_lastTaskId = 0; m_lastTaskId = 0;
......
...@@ -134,6 +134,7 @@ class V8Debugger : public v8::debug::DebugDelegate { ...@@ -134,6 +134,7 @@ class V8Debugger : public v8::debug::DebugDelegate {
v8::Local<v8::Value>); v8::Local<v8::Value>);
void asyncTaskCreated(void* task, void* parentTask); void asyncTaskCreated(void* task, void* parentTask);
void registerAsyncTaskIfNeeded(void* task);
// v8::debug::DebugEventListener implementation. // v8::debug::DebugEventListener implementation.
void PromiseEventOccurred(v8::debug::PromiseDebugActionType type, int id, void PromiseEventOccurred(v8::debug::PromiseDebugActionType type, int id,
...@@ -166,6 +167,7 @@ class V8Debugger : public v8::debug::DebugDelegate { ...@@ -166,6 +167,7 @@ class V8Debugger : public v8::debug::DebugDelegate {
using AsyncTaskToStackTrace = using AsyncTaskToStackTrace =
protocol::HashMap<void*, std::unique_ptr<V8StackTraceImpl>>; protocol::HashMap<void*, std::unique_ptr<V8StackTraceImpl>>;
AsyncTaskToStackTrace m_asyncTaskStacks; AsyncTaskToStackTrace m_asyncTaskStacks;
AsyncTaskToStackTrace m_asyncTaskCreationStacks;
int m_maxAsyncCallStacks; int m_maxAsyncCallStacks;
std::map<int, void*> m_idToTask; std::map<int, void*> m_idToTask;
std::unordered_map<void*, int> m_taskToId; std::unordered_map<void*, int> m_taskToId;
......
...@@ -141,10 +141,13 @@ std::unique_ptr<V8StackTraceImpl> V8StackTraceImpl::create( ...@@ -141,10 +141,13 @@ std::unique_ptr<V8StackTraceImpl> V8StackTraceImpl::create(
maxAsyncCallChainDepth = 1; maxAsyncCallChainDepth = 1;
} }
// Only the top stack in the chain may be empty, so ensure that second stack // Only the top stack in the chain may be empty and doesn't contain creation
// is non-empty (it's the top of appended chain). // stack , so ensure that second stack is non-empty (it's the top of appended
if (asyncCallChain && asyncCallChain->isEmpty()) // chain).
if (asyncCallChain && asyncCallChain->isEmpty() &&
!asyncCallChain->m_creation) {
asyncCallChain = asyncCallChain->m_parent.get(); asyncCallChain = asyncCallChain->m_parent.get();
}
if (stackTrace.IsEmpty() && !asyncCallChain) return nullptr; if (stackTrace.IsEmpty() && !asyncCallChain) return nullptr;
...@@ -180,9 +183,11 @@ std::unique_ptr<V8StackTraceImpl> V8StackTraceImpl::capture( ...@@ -180,9 +183,11 @@ std::unique_ptr<V8StackTraceImpl> V8StackTraceImpl::capture(
std::unique_ptr<V8StackTraceImpl> V8StackTraceImpl::cloneImpl() { std::unique_ptr<V8StackTraceImpl> V8StackTraceImpl::cloneImpl() {
std::vector<Frame> framesCopy(m_frames); std::vector<Frame> framesCopy(m_frames);
return std::unique_ptr<V8StackTraceImpl>( std::unique_ptr<V8StackTraceImpl> copy(
new V8StackTraceImpl(m_contextGroupId, m_description, framesCopy, new V8StackTraceImpl(m_contextGroupId, m_description, framesCopy,
m_parent ? m_parent->cloneImpl() : nullptr)); m_parent ? m_parent->cloneImpl() : nullptr));
if (m_creation) copy->setCreation(m_creation->cloneImpl());
return copy;
} }
std::unique_ptr<V8StackTrace> V8StackTraceImpl::clone() { std::unique_ptr<V8StackTrace> V8StackTraceImpl::clone() {
...@@ -205,6 +210,19 @@ V8StackTraceImpl::V8StackTraceImpl(int contextGroupId, ...@@ -205,6 +210,19 @@ V8StackTraceImpl::V8StackTraceImpl(int contextGroupId,
V8StackTraceImpl::~V8StackTraceImpl() {} 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 { StringView V8StackTraceImpl::topSourceURL() const {
DCHECK(m_frames.size()); DCHECK(m_frames.size());
return toStringView(m_frames[0].m_scriptName); return toStringView(m_frames[0].m_scriptName);
...@@ -243,6 +261,10 @@ V8StackTraceImpl::buildInspectorObjectImpl() const { ...@@ -243,6 +261,10 @@ V8StackTraceImpl::buildInspectorObjectImpl() const {
.build(); .build();
if (!m_description.isEmpty()) stackTrace->setDescription(m_description); if (!m_description.isEmpty()) stackTrace->setDescription(m_description);
if (m_parent) stackTrace->setParent(m_parent->buildInspectorObjectImpl()); 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; return stackTrace;
} }
......
...@@ -81,6 +81,8 @@ class V8StackTraceImpl final : public V8StackTrace { ...@@ -81,6 +81,8 @@ class V8StackTraceImpl final : public V8StackTrace {
const override; const override;
std::unique_ptr<StringBuffer> toString() const override; std::unique_ptr<StringBuffer> toString() const override;
void setCreation(std::unique_ptr<V8StackTraceImpl> creation);
private: private:
V8StackTraceImpl(int contextGroupId, const String16& description, V8StackTraceImpl(int contextGroupId, const String16& description,
std::vector<Frame>& frames, std::vector<Frame>& frames,
...@@ -90,6 +92,7 @@ class V8StackTraceImpl final : public V8StackTrace { ...@@ -90,6 +92,7 @@ class V8StackTraceImpl final : public V8StackTrace {
String16 m_description; String16 m_description;
std::vector<Frame> m_frames; std::vector<Frame> m_frames;
std::unique_ptr<V8StackTraceImpl> m_parent; std::unique_ptr<V8StackTraceImpl> m_parent;
std::unique_ptr<V8StackTraceImpl> m_creation;
DISALLOW_COPY_AND_ASSIGN(V8StackTraceImpl); DISALLOW_COPY_AND_ASSIGN(V8StackTraceImpl);
}; };
......
Checks that async stacks works for async/await Checks that async stacks works for async/await
foo2 (test.js:15:2) foo2 (test.js:15:2)
-- async function (test.js:13:19)--
foo2 (test.js:13:19) foo2 (test.js:13:19)
test (test.js:24:8) test (test.js:24:8)
(anonymous) (expr.js:0:0) (anonymous) (expr.js:0:0)
foo2 (test.js:17:2) foo2 (test.js:17:2)
-- async function (test.js:13:19)--
foo2 (test.js:13:19) foo2 (test.js:13:19)
test (test.js:24:8) test (test.js:24:8)
(anonymous) (expr.js:0:0) (anonymous) (expr.js:0:0)
foo1 (test.js:9:2) foo1 (test.js:9:2)
foo2 (test.js:18:8) foo2 (test.js:18:8)
-- async function (test.js:13:19)--
foo2 (test.js:13:19) foo2 (test.js:13:19)
test (test.js:24:8) test (test.js:24:8)
(anonymous) (expr.js:0:0) (anonymous) (expr.js:0:0)
foo1 (test.js:9:2) 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) foo2 (test.js:19:30)
-- async function (test.js:13:19)--
foo2 (test.js:13:19) foo2 (test.js:13:19)
test (test.js:24:8) test (test.js:24:8)
(anonymous) (expr.js:0:0) (anonymous) (expr.js:0:0)
foo2 (test.js:20:2) foo2 (test.js:20:2)
-- async function (test.js:13:19)--
foo2 (test.js:13:19) foo2 (test.js:13:19)
test (test.js:24:8) test (test.js:24:8)
(anonymous) (expr.js:0:0) (anonymous) (expr.js:0:0)
......
...@@ -28,12 +28,7 @@ async function test() { ...@@ -28,12 +28,7 @@ async function test() {
InspectorTest.setupScriptMap(); InspectorTest.setupScriptMap();
Protocol.Debugger.onPaused(message => { Protocol.Debugger.onPaused(message => {
InspectorTest.logCallFrames(message.params.callFrames); InspectorTest.logCallFrames(message.params.callFrames);
var asyncStackTrace = message.params.asyncStackTrace; InspectorTest.logAsyncStackTrace(message.params.asyncStackTrace);
while (asyncStackTrace) {
InspectorTest.log(`-- ${asyncStackTrace.description} --`);
InspectorTest.logCallFrames(asyncStackTrace.callFrames);
asyncStackTrace = asyncStackTrace.parent;
}
InspectorTest.log(''); InspectorTest.log('');
Protocol.Debugger.resume(); 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. ...@@ -2,13 +2,14 @@ Checks that async chains for promises are correct.
Running test: testPromise Running test: testPromise
foo1 (test.js:9:2) foo1 (test.js:9:2)
-- Promise.resolve -- -- Promise.resolve (test.js:19:14)--
promise (test.js:20:2) promise (test.js:20:2)
(anonymous) (testPromise.js:0:0) (anonymous) (testPromise.js:0:0)
Running test: testPromiseResolvedBySetTimeout Running test: testPromiseResolvedBySetTimeout
foo1 (test.js:9:2) foo1 (test.js:9:2)
-- Promise.resolve (test.js:27:14)--
-- setTimeout -- -- setTimeout --
promiseResolvedBySetTimeout (test.js:28:2) promiseResolvedBySetTimeout (test.js:28:2)
(anonymous) (testPromiseResolvedBySetTimeout.js:0:0) (anonymous) (testPromiseResolvedBySetTimeout.js:0:0)
...@@ -16,96 +17,103 @@ promiseResolvedBySetTimeout (test.js:28:2) ...@@ -16,96 +17,103 @@ promiseResolvedBySetTimeout (test.js:28:2)
Running test: testPromiseAll Running test: testPromiseAll
foo1 (test.js:9:2) foo1 (test.js:9:2)
-- Promise.resolve -- -- Promise.resolve (test.js:37:35)--
-- Promise.resolve (test.js:37:19)--
promiseAll (test.js:39:2) promiseAll (test.js:39:2)
(anonymous) (testPromiseAll.js:0:0) (anonymous) (testPromiseAll.js:0:0)
Running test: testPromiseAllReverseOrder Running test: testPromiseAllReverseOrder
foo1 (test.js:9:2) foo1 (test.js:9:2)
-- Promise.resolve -- -- Promise.resolve (test.js:48:35)--
-- Promise.resolve (test.js:48:19)--
promiseAllReverseOrder (test.js:50:2) promiseAllReverseOrder (test.js:50:2)
(anonymous) (testPromiseAllReverseOrder.js:0:0) (anonymous) (testPromiseAllReverseOrder.js:0:0)
Running test: testPromiseRace Running test: testPromiseRace
foo1 (test.js:9:2) foo1 (test.js:9:2)
-- Promise.resolve -- -- Promise.resolve (test.js:59:36)--
-- Promise.resolve (test.js:59:19)--
promiseRace (test.js:60:2) promiseRace (test.js:60:2)
(anonymous) (testPromiseRace.js:0:0) (anonymous) (testPromiseRace.js:0:0)
Running test: testTwoChainedCallbacks Running test: testTwoChainedCallbacks
foo1 (test.js:9:2) foo1 (test.js:9:2)
-- Promise.resolve -- -- Promise.resolve (test.js:68:14)--
twoChainedCallbacks (test.js:69:2) twoChainedCallbacks (test.js:69:2)
(anonymous) (testTwoChainedCallbacks.js:0:0) (anonymous) (testTwoChainedCallbacks.js:0:0)
foo2 (test.js:13:2) foo2 (test.js:13:2)
-- Promise.resolve -- -- Promise.resolve (test.js:68:25)--
-- Promise.resolve (test.js:68:14)--
twoChainedCallbacks (test.js:69:2) twoChainedCallbacks (test.js:69:2)
(anonymous) (testTwoChainedCallbacks.js:0:0) (anonymous) (testTwoChainedCallbacks.js:0:0)
Running test: testPromiseResolve Running test: testPromiseResolve
foo1 (test.js:9:2) foo1 (test.js:9:2)
-- Promise.resolve -- -- Promise.resolve (test.js:74:27)--
promiseResolve (test.js:74:17) promiseResolve (test.js:74:17)
(anonymous) (testPromiseResolve.js:0:0) (anonymous) (testPromiseResolve.js:0:0)
foo2 (test.js:13:2) foo2 (test.js:13:2)
-- Promise.resolve -- -- Promise.resolve (test.js:74:38)--
-- Promise.resolve (test.js:74:27)--
promiseResolve (test.js:74:17) promiseResolve (test.js:74:17)
(anonymous) (testPromiseResolve.js:0:0) (anonymous) (testPromiseResolve.js:0:0)
Running test: testThenableJobResolvedInSetTimeout Running test: testThenableJobResolvedInSetTimeout
foo1 (test.js:9:2) foo1 (test.js:9:2)
-- Promise.resolve (test.js:86:40)--
-- setTimeout -- -- setTimeout --
thenableJob (test.js:81:4) thenableJob (test.js:81:4)
p1.then (test.js:86:25) p1.then (test.js:86:25)
-- Promise.resolve -- -- Promise.resolve (test.js:86:14)--
thenableJobResolvedInSetTimeout (test.js:87:2) thenableJobResolvedInSetTimeout (test.js:87:2)
(anonymous) (testThenableJobResolvedInSetTimeout.js:0:0) (anonymous) (testThenableJobResolvedInSetTimeout.js:0:0)
Running test: testThenableJobResolvedInSetTimeoutWithStack Running test: testThenableJobResolvedInSetTimeoutWithStack
foo1 (test.js:9:2) foo1 (test.js:9:2)
-- Promise.resolve -- -- Promise.resolve (test.js:104:40)--
inner (test.js:94:6) inner (test.js:94:6)
-- setTimeout -- -- setTimeout --
thenableJob (test.js:99:4) thenableJob (test.js:99:4)
p1.then (test.js:104:25) p1.then (test.js:104:25)
-- Promise.resolve -- -- Promise.resolve (test.js:104:14)--
thenableJobResolvedInSetTimeoutWithStack (test.js:105:2) thenableJobResolvedInSetTimeoutWithStack (test.js:105:2)
(anonymous) (testThenableJobResolvedInSetTimeoutWithStack.js:0:0) (anonymous) (testThenableJobResolvedInSetTimeoutWithStack.js:0:0)
Running test: testThenableJobResolvedByPromise Running test: testThenableJobResolvedByPromise
foo1 (test.js:9:2) foo1 (test.js:9:2)
-- Promise.resolve -- -- Promise.resolve (test.js:118:40)--
-- Promise.resolve (test.js:113:22)--
thenableJob (test.js:113:12) thenableJob (test.js:113:12)
p1.then (test.js:118:25) p1.then (test.js:118:25)
-- Promise.resolve -- -- Promise.resolve (test.js:118:14)--
thenableJobResolvedByPromise (test.js:119:2) thenableJobResolvedByPromise (test.js:119:2)
(anonymous) (testThenableJobResolvedByPromise.js:0:0) (anonymous) (testThenableJobResolvedByPromise.js:0:0)
Running test: testThenableJobResolvedByPromiseWithStack Running test: testThenableJobResolvedByPromiseWithStack
foo1 (test.js:9:2) foo1 (test.js:9:2)
-- Promise.resolve -- -- Promise.resolve (test.js:136:40)--
inner (test.js:126:6) inner (test.js:126:6)
-- Promise.resolve -- -- Promise.resolve (test.js:131:22)--
thenableJob (test.js:131:12) thenableJob (test.js:131:12)
p1.then (test.js:136:25) p1.then (test.js:136:25)
-- Promise.resolve -- -- Promise.resolve (test.js:136:14)--
thenableJobResolvedByPromiseWithStack (test.js:137:2) thenableJobResolvedByPromiseWithStack (test.js:137:2)
(anonymous) (testThenableJobResolvedByPromiseWithStack.js:0:0) (anonymous) (testThenableJobResolvedByPromiseWithStack.js:0:0)
Running test: testLateThenCallback Running test: testLateThenCallback
foo1 (test.js:9:2) foo1 (test.js:9:2)
-- Promise.resolve -- -- Promise.resolve (test.js:145:12)--
lateThenCallback (test.js:144:2) lateThenCallback (test.js:144:2)
(anonymous) (testLateThenCallback.js:0:0) (anonymous) (testLateThenCallback.js:0:0)
...@@ -113,43 +121,54 @@ lateThenCallback (test.js:144:2) ...@@ -113,43 +121,54 @@ lateThenCallback (test.js:144:2)
Running test: testComplex Running test: testComplex
inner1 (test.js:154:6) inner1 (test.js:154:6)
foo1 (test.js:156:4) foo1 (test.js:156:4)
-- Promise.resolve -- -- Promise.resolve (test.js:202:5)--
inner2 (test.js:162:6) inner2 (test.js:162:6)
-- Promise.resolve -- -- Promise.resolve (test.js:165:22)--
foo2 (test.js:165:12) foo2 (test.js:165:12)
-- Promise.resolve -- -- Promise.resolve (test.js:201:5)--
inner3 (test.js:172:6) inner3 (test.js:172:6)
-- setTimeout -- -- setTimeout --
foo3 (test.js:175:4) 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) 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) foo6 (test.js:192:34)
-- Promise.resolve -- -- Promise.resolve (test.js:197:5)--
complex (test.js:196:18) complex (test.js:196:18)
(anonymous) (testComplex.js:0:0) (anonymous) (testComplex.js:0:0)
p.then (test.js:207:8) 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) inner2 (test.js:162:6)
-- Promise.resolve -- -- Promise.resolve (test.js:165:22)--
foo2 (test.js:165:12) foo2 (test.js:165:12)
-- Promise.resolve -- -- Promise.resolve (test.js:201:5)--
inner3 (test.js:172:6) inner3 (test.js:172:6)
-- setTimeout -- -- setTimeout --
foo3 (test.js:175:4) 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) 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) foo6 (test.js:192:34)
-- Promise.resolve -- -- Promise.resolve (test.js:197:5)--
complex (test.js:196:18) complex (test.js:196:18)
(anonymous) (testComplex.js:0:0) (anonymous) (testComplex.js:0:0)
Running test: testReject Running test: testReject
foo1 (test.js:9:2) foo1 (test.js:9:2)
-- Promise.reject -- -- Promise.reject (test.js:217:31)--
reject (test.js:217:17) reject (test.js:217:17)
(anonymous) (testReject.js:0:0) (anonymous) (testReject.js:0:0)
...@@ -222,12 +222,7 @@ function reject() { ...@@ -222,12 +222,7 @@ function reject() {
InspectorTest.setupScriptMap(); InspectorTest.setupScriptMap();
Protocol.Debugger.onPaused(message => { Protocol.Debugger.onPaused(message => {
InspectorTest.logCallFrames(message.params.callFrames); InspectorTest.logCallFrames(message.params.callFrames);
var asyncStackTrace = message.params.asyncStackTrace; InspectorTest.logAsyncStackTrace(message.params.asyncStackTrace);
while (asyncStackTrace) {
InspectorTest.log(`-- ${asyncStackTrace.description} --`);
InspectorTest.logCallFrames(asyncStackTrace.callFrames);
asyncStackTrace = asyncStackTrace.parent;
}
InspectorTest.log(''); InspectorTest.log('');
Protocol.Debugger.resume(); Protocol.Debugger.resume();
}); });
......
...@@ -4,7 +4,7 @@ Running test: testZeroLimit ...@@ -4,7 +4,7 @@ Running test: testZeroLimit
foo1 (test.js:11:2) foo1 (test.js:11:2)
Running test: testOneLimit Running test: testTwoLimit
foo1 (test.js:11:2) foo1 (test.js:11:2)
-- Promise.resolve -- -- Promise.resolve --
promise (test.js:23:2) promise (test.js:23:2)
...@@ -17,11 +17,14 @@ foo1 (test.js:11:2) ...@@ -17,11 +17,14 @@ foo1 (test.js:11:2)
foo2 (test.js:15: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) foo1 (test.js:11:2)
-- Promise.resolve --
twoPromises (test.js:34:2)
(anonymous) (expr.js:0:0)
foo2 (test.js:15:2) foo2 (test.js:15:2)
-- Promise.resolve -- -- Promise.resolve --
...@@ -29,7 +32,7 @@ twoPromises (test.js:35:2) ...@@ -29,7 +32,7 @@ twoPromises (test.js:35:2)
(anonymous) (expr.js:0:0) (anonymous) (expr.js:0:0)
Running test: testOneLimitTwoSetTimeouts Running test: testTwoLimitTwoSetTimeouts
foo1 (test.js:11:2) foo1 (test.js:11:2)
foo2 (test.js:15:2) foo2 (test.js:15:2)
...@@ -38,7 +41,7 @@ twoSetTimeout (test.js:41:2) ...@@ -38,7 +41,7 @@ twoSetTimeout (test.js:41:2)
(anonymous) (expr.js:0:0) (anonymous) (expr.js:0:0)
Running test: testTwoLimitTwoSetTimeouts Running test: testThreeLimitTwoSetTimeouts
foo1 (test.js:11:2) foo1 (test.js:11:2)
-- setTimeout -- -- setTimeout --
twoSetTimeout (test.js:40:2) twoSetTimeout (test.js:40:2)
...@@ -84,54 +87,54 @@ foo10 (:0:18) ...@@ -84,54 +87,54 @@ foo10 (:0:18)
foo11 (:0:18) foo11 (:0:18)
(anonymous) (:0:29) (anonymous) (:0:29)
-- setTimeout -- -- setTimeout --
twentySetTimeout (test.js:55:4) twentySetTimeout (test.js:49:4)
(anonymous) (expr.js:0:0) (anonymous) (expr.js:0:0)
foo12 (:0:18) foo12 (:0:18)
(anonymous) (:0:29) (anonymous) (:0:29)
-- setTimeout -- -- setTimeout --
twentySetTimeout (test.js:55:4) twentySetTimeout (test.js:49:4)
(anonymous) (expr.js:0:0) (anonymous) (expr.js:0:0)
foo13 (:0:18) foo13 (:0:18)
(anonymous) (:0:29) (anonymous) (:0:29)
-- setTimeout -- -- setTimeout --
twentySetTimeout (test.js:55:4) twentySetTimeout (test.js:49:4)
(anonymous) (expr.js:0:0) (anonymous) (expr.js:0:0)
foo14 (:0:18) foo14 (:0:18)
(anonymous) (:0:29) (anonymous) (:0:29)
-- setTimeout -- -- setTimeout --
twentySetTimeout (test.js:55:4) twentySetTimeout (test.js:49:4)
(anonymous) (expr.js:0:0) (anonymous) (expr.js:0:0)
foo15 (:0:18) foo15 (:0:18)
(anonymous) (:0:29) (anonymous) (:0:29)
-- setTimeout -- -- setTimeout --
twentySetTimeout (test.js:55:4) twentySetTimeout (test.js:49:4)
(anonymous) (expr.js:0:0) (anonymous) (expr.js:0:0)
foo16 (:0:18) foo16 (:0:18)
(anonymous) (:0:29) (anonymous) (:0:29)
-- setTimeout -- -- setTimeout --
twentySetTimeout (test.js:55:4) twentySetTimeout (test.js:49:4)
(anonymous) (expr.js:0:0) (anonymous) (expr.js:0:0)
foo17 (:0:18) foo17 (:0:18)
(anonymous) (:0:29) (anonymous) (:0:29)
-- setTimeout -- -- setTimeout --
twentySetTimeout (test.js:55:4) twentySetTimeout (test.js:49:4)
(anonymous) (expr.js:0:0) (anonymous) (expr.js:0:0)
foo18 (:0:18) foo18 (:0:18)
(anonymous) (:0:29) (anonymous) (:0:29)
-- setTimeout -- -- setTimeout --
twentySetTimeout (test.js:55:4) twentySetTimeout (test.js:49:4)
(anonymous) (expr.js:0:0) (anonymous) (expr.js:0:0)
foo19 (:0:18) foo19 (:0:18)
(anonymous) (:0:29) (anonymous) (:0:29)
-- setTimeout -- -- setTimeout --
twentySetTimeout (test.js:55:4) twentySetTimeout (test.js:49:4)
(anonymous) (expr.js:0:0) (anonymous) (expr.js:0:0)
...@@ -42,12 +42,6 @@ function twoSetTimeout() { ...@@ -42,12 +42,6 @@ function twoSetTimeout() {
return new Promise(resolve => resolveTest = resolve); return new Promise(resolve => resolveTest = resolve);
} }
function threeSetTimeout() {
setTimeout(foo1, 0);
setTimeout(foo2, 0);
return new Promise(resolve => resolveTest = resolve);
}
function twentySetTimeout() { function twentySetTimeout() {
var resolve1; var resolve1;
var p1 = new Promise(resolve => resolve1 = resolve); var p1 = new Promise(resolve => resolve1 = resolve);
...@@ -85,14 +79,16 @@ InspectorTest.runTestSuite([ ...@@ -85,14 +79,16 @@ InspectorTest.runTestSuite([
.then(next); .then(next);
}, },
function testOneLimit(next) { function testTwoLimit(next) {
Protocol.Runtime.evaluate({ // we need one stack for parent task and one for next task.
expression: 'setMaxAsyncTaskStacks(1)//# sourceURL=expr.js'}) Protocol.Runtime
.then(() => Protocol.Runtime.evaluate({ .evaluate({expression: 'setMaxAsyncTaskStacks(2)//# sourceURL=expr.js'})
expression: 'promise()//# sourceURL=expr.js', awaitPromise: true .then(() => Protocol.Runtime.evaluate({
})) expression: 'promise()//# sourceURL=expr.js',
.then(() => cancelAllAsyncTasks()) awaitPromise: true
.then(next); }))
.then(() => cancelAllAsyncTasks())
.then(next);
}, },
function testOneLimitTwoPromises(next) { function testOneLimitTwoPromises(next) {
...@@ -108,19 +104,31 @@ InspectorTest.runTestSuite([ ...@@ -108,19 +104,31 @@ InspectorTest.runTestSuite([
.then(next); .then(next);
}, },
function testTwoLimitTwoPromises(next) { function testFourLimitTwoPromises(next) {
Protocol.Runtime.evaluate({ Protocol.Runtime
expression: 'setMaxAsyncTaskStacks(2)//# sourceURL=expr.js'}) .evaluate({expression: 'setMaxAsyncTaskStacks(4)//# sourceURL=expr.js'})
.then(() => Protocol.Runtime.evaluate({ .then(() => Protocol.Runtime.evaluate({
expression: 'twoPromises()//# sourceURL=expr.js', awaitPromise: true expression: 'twoPromises()//# sourceURL=expr.js',
})) awaitPromise: true
.then(() => cancelAllAsyncTasks()) }))
.then(next); .then(() => cancelAllAsyncTasks())
.then(next);
}, },
function testOneLimitTwoSetTimeouts(next) { function testSixLimitTwoPromises(next) {
Protocol.Runtime
.evaluate({expression: 'setMaxAsyncTaskStacks(6)//# sourceURL=expr.js'})
.then(() => Protocol.Runtime.evaluate({
expression: 'twoPromises()//# sourceURL=expr.js',
awaitPromise: true
}))
.then(() => cancelAllAsyncTasks())
.then(next);
},
function testTwoLimitTwoSetTimeouts(next) {
Protocol.Runtime.evaluate({ Protocol.Runtime.evaluate({
expression: 'setMaxAsyncTaskStacks(1)//# sourceURL=expr.js'}) expression: 'setMaxAsyncTaskStacks(2)//# sourceURL=expr.js'})
.then(() => Protocol.Runtime.evaluate({ .then(() => Protocol.Runtime.evaluate({
expression: 'twoSetTimeout()//# sourceURL=expr.js', awaitPromise: true expression: 'twoSetTimeout()//# sourceURL=expr.js', awaitPromise: true
})) }))
...@@ -128,9 +136,9 @@ InspectorTest.runTestSuite([ ...@@ -128,9 +136,9 @@ InspectorTest.runTestSuite([
.then(next); .then(next);
}, },
function testTwoLimitTwoSetTimeouts(next) { function testThreeLimitTwoSetTimeouts(next) {
Protocol.Runtime.evaluate({ Protocol.Runtime.evaluate({
expression: 'setMaxAsyncTaskStacks(2)//# sourceURL=expr.js'}) expression: 'setMaxAsyncTaskStacks(3)//# sourceURL=expr.js'})
.then(() => Protocol.Runtime.evaluate({ .then(() => Protocol.Runtime.evaluate({
expression: 'twoSetTimeout()//# sourceURL=expr.js', awaitPromise: true expression: 'twoSetTimeout()//# sourceURL=expr.js', awaitPromise: true
})) }))
......
...@@ -112,6 +112,21 @@ InspectorTest.logCallFrames = function(callFrames) ...@@ -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() InspectorTest.completeTest = function()
{ {
Protocol.Debugger.disable().then(() => quit()); 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