Commit ed9b2072 authored by Alexey Kozyatinskiy's avatar Alexey Kozyatinskiy Committed by Commit Bot

[inspector] reworked async instrumentation for promises

Old instrumentation was designed to collect promise creation stack and
promise scheduled stack together. In DevTools for last 6 months we
show only creation stack for promises. We got strong support from users
for new model. Now we can drop support for scheduled stacks and
simplify implementation.

New promise instrumentation is straightforward:
- we send kDebugPromiseThen when promise is created by .then call,
- we send kDebugPromiseCatch when promise is created by .catch call,
- we send kDebugWillHandle before chained callback and kDebugDidHandle
  after chained callback,
- and we send separate kDebugAsyncFunctionPromiseCreated for internal
  promise inside async await function.

Advantages:
- we reduce amount of captured stacks (we do not capture stack for
  promise that constructed not by .then or .catch),
- we can consider async task related to .then and .catch as one shot
  since chained callback is executed once,
- on V8 side we can implement required instrumentation using only
  promise hooks,

Disadvantage:
- see await-promise test, sometimes scheduled stack was useful since we
  add catch handler in native code,

Implementation details:
- on kInit promise hook we need to figure out why promise was created.
  We analyze builtin functions until first user defined function on
  current stack. If there is kAsyncFunctionPromiseCreate function then
  we send kDebugAsyncFunctionPromiseCreated event. If there is
  kPromiseThen or kPromiseCatch then only if this function is bottom
  builtin function we send corresponded event to inspector. We need it
  because Promise.all internally calls .then and in this case we have
  Promise.all and Promise.then on stack at the same time and we do not
  need to report this internally created promise to inspector.

Bug: chromium:778796
Cq-Include-Trybots: master.tryserver.blink:linux_trusty_blink_rel
Change-Id: I53f47ce8c5c4a9897655c3396c249ea59529ae47
Reviewed-on: https://chromium-review.googlesource.com/765208
Commit-Queue: Aleksey Kozyatinskiy <kozyatinskiy@chromium.org>
Reviewed-by: 's avatarSathya Gunasekaran <gsathya@chromium.org>
Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Reviewed-by: 's avatarDmitry Gozman <dgozman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49553}
parent 0481b23e
......@@ -821,12 +821,12 @@ void PromiseBuiltinsAssembler::InternalResolvePromise(Node* context,
void PromiseBuiltinsAssembler::PromiseFulfill(
Node* context, Node* promise, Node* result,
v8::Promise::PromiseState status) {
Label do_promisereset(this), debug_async_event_enqueue_recurring(this);
Label do_promisereset(this);
Node* const deferred_promise =
LoadObjectField(promise, JSPromise::kDeferredPromiseOffset);
GotoIf(IsUndefined(deferred_promise), &debug_async_event_enqueue_recurring);
GotoIf(IsUndefined(deferred_promise), &do_promisereset);
Node* const tasks =
status == v8::Promise::kFulfilled
......@@ -843,15 +843,7 @@ void PromiseBuiltinsAssembler::PromiseFulfill(
context);
CallRuntime(Runtime::kEnqueuePromiseReactionJob, context, info);
Goto(&debug_async_event_enqueue_recurring);
BIND(&debug_async_event_enqueue_recurring);
{
GotoIfNot(IsDebugActive(), &do_promisereset);
CallRuntime(Runtime::kDebugAsyncEventEnqueueRecurring, context, promise,
SmiConstant(status));
Goto(&do_promisereset);
}
Goto(&do_promisereset);
BIND(&do_promisereset);
{
......
......@@ -178,7 +178,7 @@ class DebugDelegate {
public:
virtual ~DebugDelegate() {}
virtual void PromiseEventOccurred(debug::PromiseDebugActionType type, int id,
int parent_id, bool created_by_user) {}
bool is_blackboxed) {}
virtual void ScriptCompiled(v8::Local<Script> script, bool is_live_edited,
bool has_compile_error) {}
// |break_points_hit| contains installed by JS debug API breakpoint objects.
......
......@@ -1746,28 +1746,55 @@ int GetReferenceAsyncTaskId(Isolate* isolate, Handle<JSPromise> promise) {
}
} // namespace
void Debug::RunPromiseHook(PromiseHookType type, Handle<JSPromise> promise,
void Debug::RunPromiseHook(PromiseHookType hook_type, Handle<JSPromise> promise,
Handle<Object> parent) {
if (hook_type == PromiseHookType::kResolve) return;
if (in_debug_scope() || ignore_events()) return;
if (!debug_delegate_) return;
PostponeInterruptsScope no_interrupts(isolate_);
int id = GetReferenceAsyncTaskId(isolate_, promise);
switch (type) {
case PromiseHookType::kInit:
OnAsyncTaskEvent(debug::kDebugPromiseCreated, id,
parent->IsJSPromise()
? GetReferenceAsyncTaskId(
isolate_, Handle<JSPromise>::cast(parent))
: 0);
return;
case PromiseHookType::kResolve:
// We can't use this hook because it's called before promise object will
// get resolved status.
return;
case PromiseHookType::kBefore:
OnAsyncTaskEvent(debug::kDebugWillHandle, id, 0);
return;
case PromiseHookType::kAfter:
OnAsyncTaskEvent(debug::kDebugDidHandle, id, 0);
return;
if (hook_type == PromiseHookType::kBefore) {
debug_delegate_->PromiseEventOccurred(debug::kDebugWillHandle, id, false);
} else if (hook_type == PromiseHookType::kAfter) {
debug_delegate_->PromiseEventOccurred(debug::kDebugDidHandle, id, false);
} else {
DCHECK(hook_type == PromiseHookType::kInit);
debug::PromiseDebugActionType type = debug::kDebugPromiseThen;
bool last_frame_was_promise_builtin = false;
JavaScriptFrameIterator it(isolate_);
while (!it.done()) {
std::vector<Handle<SharedFunctionInfo>> infos;
it.frame()->GetFunctions(&infos);
for (size_t i = 1; i <= infos.size(); ++i) {
Handle<SharedFunctionInfo> info = infos[infos.size() - i];
if (info->IsUserJavaScript()) {
// We should not report PromiseThen and PromiseCatch which is called
// indirectly, e.g. Promise.all calls Promise.then internally.
if (type == debug::kDebugAsyncFunctionPromiseCreated ||
last_frame_was_promise_builtin) {
debug_delegate_->PromiseEventOccurred(type, id, IsBlackboxed(info));
}
return;
}
last_frame_was_promise_builtin = false;
Handle<Code> code(info->code());
if (*code == *BUILTIN_CODE(isolate_, AsyncFunctionPromiseCreate)) {
type = debug::kDebugAsyncFunctionPromiseCreated;
last_frame_was_promise_builtin = true;
} else if (*code == *BUILTIN_CODE(isolate_, PromiseThen)) {
type = debug::kDebugPromiseThen;
last_frame_was_promise_builtin = true;
} else if (*code == *BUILTIN_CODE(isolate_, PromiseCatch)) {
type = debug::kDebugPromiseCatch;
last_frame_was_promise_builtin = true;
} else if (*code == *BUILTIN_CODE(isolate_, PromiseFinally)) {
type = debug::kDebugPromiseFinally;
last_frame_was_promise_builtin = true;
}
}
it.Advance();
}
}
}
......@@ -1857,23 +1884,6 @@ bool Debug::SetScriptSource(Handle<Script> script, Handle<String> source,
return true;
}
void Debug::OnAsyncTaskEvent(debug::PromiseDebugActionType type, int id,
int parent_id) {
if (in_debug_scope() || ignore_events()) return;
if (!debug_delegate_) return;
PostponeInterruptsScope no_interrupts(isolate_);
bool created_by_user = false;
if (type == debug::kDebugPromiseCreated) {
JavaScriptFrameIterator it(isolate_);
// We need to skip top frame which contains instrumentation.
it.Advance();
created_by_user =
!it.done() &&
!IsFrameBlackboxed(it.frame());
}
debug_delegate_->PromiseEventOccurred(type, id, parent_id, created_by_user);
}
void Debug::ProcessCompileEvent(v8::DebugEvent event, Handle<Script> script) {
// Attach the correct debug id to the script. The debug id is used by the
// inspector to filter scripts by native context.
......@@ -2161,8 +2171,7 @@ bool Debug::PerformSideEffectCheckForCallback(Address function) {
}
void LegacyDebugDelegate::PromiseEventOccurred(
v8::debug::PromiseDebugActionType type, int id, int parent_id,
bool created_by_user) {
v8::debug::PromiseDebugActionType type, int id, bool is_blackboxed) {
DebugScope debug_scope(isolate_->debug());
if (debug_scope.failed()) return;
HandleScope scope(isolate_);
......
......@@ -207,8 +207,6 @@ class Debug {
void OnPromiseReject(Handle<Object> promise, Handle<Object> value);
void OnCompileError(Handle<Script> script);
void OnAfterCompile(Handle<Script> script);
void OnAsyncTaskEvent(debug::PromiseDebugActionType type, int id,
int parent_id);
MUST_USE_RESULT MaybeHandle<Object> Call(Handle<Object> fun,
Handle<Object> data);
......@@ -260,7 +258,7 @@ class Debug {
void RecordGenerator(Handle<JSGeneratorObject> generator_object);
void RunPromiseHook(PromiseHookType type, Handle<JSPromise> promise,
void RunPromiseHook(PromiseHookType hook_type, Handle<JSPromise> promise,
Handle<Object> parent);
int NextAsyncTaskId(Handle<JSObject> promise);
......@@ -574,7 +572,7 @@ class LegacyDebugDelegate : public v8::debug::DebugDelegate {
public:
explicit LegacyDebugDelegate(Isolate* isolate) : isolate_(isolate) {}
void PromiseEventOccurred(v8::debug::PromiseDebugActionType type, int id,
int parent_id, bool created_by_user) override;
bool is_blackboxed) override;
void ScriptCompiled(v8::Local<v8::debug::Script> script, bool is_live_edited,
bool has_compile_error) override;
void BreakProgramRequested(v8::Local<v8::Context> paused_context,
......
......@@ -70,10 +70,10 @@ struct WasmDisassembly {
};
enum PromiseDebugActionType {
kDebugPromiseCreated,
kDebugEnqueueAsyncFunction,
kDebugEnqueuePromiseResolve,
kDebugEnqueuePromiseReject,
kDebugAsyncFunctionPromiseCreated,
kDebugPromiseThen,
kDebugPromiseCatch,
kDebugPromiseFinally,
kDebugWillHandle,
kDebugDidHandle,
};
......
......@@ -201,8 +201,7 @@
"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": "promiseCreationFrame", "$ref": "CallFrame", "optional": true, "experimental": true, "description": "Creation frame of the Promise which produced the next synchronous trace when resolved, if available." }
{ "name": "parent", "$ref": "StackTrace", "optional": true, "description": "Asynchronous JavaScript stack trace that preceded this stack, if available." }
]
},
{
......
......@@ -1284,7 +1284,6 @@ V8DebuggerAgentImpl::currentAsyncStackTrace() {
m_debugger->currentAsyncParent();
if (!asyncParent) return nullptr;
return asyncParent->buildInspectorObject(
m_debugger->currentAsyncCreation().get(),
m_debugger->maxAsyncCallChainDepth() - 1);
}
......
......@@ -526,26 +526,26 @@ bool V8Debugger::IsFunctionBlackboxed(v8::Local<v8::debug::Script> script,
}
void V8Debugger::PromiseEventOccurred(v8::debug::PromiseDebugActionType type,
int id, int parentId,
bool createdByUser) {
int id, bool isBlackboxed) {
// Async task events from Promises are given misaligned pointers to prevent
// from overlapping with other Blink task identifiers.
void* task = reinterpret_cast<void*>(id * 2 + 1);
void* parentTask =
parentId ? reinterpret_cast<void*>(parentId * 2 + 1) : nullptr;
switch (type) {
case v8::debug::kDebugPromiseCreated:
asyncTaskCreatedForStack(task, parentTask);
if (createdByUser && parentTask) asyncTaskCandidateForStepping(task);
break;
case v8::debug::kDebugEnqueueAsyncFunction:
case v8::debug::kDebugAsyncFunctionPromiseCreated:
asyncTaskScheduledForStack("async function", task, true);
if (!isBlackboxed) asyncTaskCandidateForStepping(task);
break;
case v8::debug::kDebugPromiseThen:
asyncTaskScheduledForStack("Promise.then", task, false);
if (!isBlackboxed) asyncTaskCandidateForStepping(task);
break;
case v8::debug::kDebugEnqueuePromiseResolve:
asyncTaskScheduledForStack("Promise.resolve", task, true);
case v8::debug::kDebugPromiseCatch:
asyncTaskScheduledForStack("Promise.catch", task, false);
if (!isBlackboxed) asyncTaskCandidateForStepping(task);
break;
case v8::debug::kDebugEnqueuePromiseReject:
asyncTaskScheduledForStack("Promise.reject", task, true);
case v8::debug::kDebugPromiseFinally:
asyncTaskScheduledForStack("Promise.finally", task, false);
if (!isBlackboxed) asyncTaskCandidateForStepping(task);
break;
case v8::debug::kDebugWillHandle:
asyncTaskStartedForStack(task);
......@@ -559,17 +559,9 @@ void V8Debugger::PromiseEventOccurred(v8::debug::PromiseDebugActionType type,
}
std::shared_ptr<AsyncStackTrace> V8Debugger::currentAsyncParent() {
// TODO(kozyatinskiy): implement creation chain as parent without hack.
if (!m_currentAsyncCreation.empty() && m_currentAsyncCreation.back()) {
return m_currentAsyncCreation.back();
}
return m_currentAsyncParent.empty() ? nullptr : m_currentAsyncParent.back();
}
std::shared_ptr<AsyncStackTrace> V8Debugger::currentAsyncCreation() {
return nullptr;
}
v8::MaybeLocal<v8::Value> V8Debugger::getTargetScopes(
v8::Local<v8::Context> context, v8::Local<v8::Value> value,
ScopeTargetKind kind) {
......@@ -734,22 +726,6 @@ void V8Debugger::setAsyncCallStackDepth(V8DebuggerAgentImpl* agent, int depth) {
if (!maxAsyncCallStackDepth) allAsyncTasksCanceled();
}
void V8Debugger::asyncTaskCreatedForStack(void* task, void* parentTask) {
if (!m_maxAsyncCallStackDepth) return;
if (parentTask) m_parentTask[task] = parentTask;
v8::HandleScope scope(m_isolate);
std::shared_ptr<AsyncStackTrace> asyncCreation =
AsyncStackTrace::capture(this, currentContextGroupId(), String16(),
V8StackTraceImpl::maxCallStackSizeToCapture);
// Passing one as maxStackSize forces no async chain for the new stack.
if (asyncCreation && !asyncCreation->isEmpty()) {
m_asyncTaskCreationStacks[task] = asyncCreation;
m_allAsyncStacks.push_back(std::move(asyncCreation));
++m_asyncStacksCount;
collectOldAsyncStacksIfNeeded();
}
}
void V8Debugger::asyncTaskScheduled(const StringView& taskName, void* task,
bool recurring) {
asyncTaskScheduledForStack(toString16(taskName), task, recurring);
......@@ -791,8 +767,6 @@ void V8Debugger::asyncTaskCanceledForStack(void* task) {
if (!m_maxAsyncCallStackDepth) return;
m_asyncTaskStacks.erase(task);
m_recurringTasks.erase(task);
m_parentTask.erase(task);
m_asyncTaskCreationStacks.erase(task);
}
void V8Debugger::asyncTaskStartedForStack(void* task) {
......@@ -805,26 +779,12 @@ void V8Debugger::asyncTaskStartedForStack(void* task) {
// <-- async stack requested here -->
// - asyncTaskFinished
m_currentTasks.push_back(task);
auto parentIt = m_parentTask.find(task);
AsyncTaskToStackTrace::iterator stackIt = m_asyncTaskStacks.find(
parentIt == m_parentTask.end() ? task : parentIt->second);
AsyncTaskToStackTrace::iterator stackIt = m_asyncTaskStacks.find(task);
if (stackIt != m_asyncTaskStacks.end()) {
m_currentAsyncParent.push_back(stackIt->second.lock());
} else {
m_currentAsyncParent.emplace_back();
}
auto itCreation = m_asyncTaskCreationStacks.find(task);
if (itCreation != m_asyncTaskCreationStacks.end()) {
m_currentAsyncCreation.push_back(itCreation->second.lock());
// TODO(kozyatinskiy): implement it without hack.
if (m_currentAsyncParent.back()) {
m_currentAsyncCreation.back()->setDescription(
m_currentAsyncParent.back()->description());
m_currentAsyncParent.back().reset();
}
} else {
m_currentAsyncCreation.emplace_back();
}
}
void V8Debugger::asyncTaskFinishedForStack(void* task) {
......@@ -834,9 +794,7 @@ void V8Debugger::asyncTaskFinishedForStack(void* task) {
DCHECK(m_currentTasks.back() == task);
m_currentTasks.pop_back();
DCHECK(m_currentAsyncParent.size() == m_currentAsyncCreation.size());
m_currentAsyncParent.pop_back();
m_currentAsyncCreation.pop_back();
if (m_recurringTasks.find(task) == m_recurringTasks.end()) {
asyncTaskCanceledForStack(task);
......@@ -883,10 +841,7 @@ void V8Debugger::allAsyncTasksCanceled() {
m_asyncTaskStacks.clear();
m_recurringTasks.clear();
m_currentAsyncParent.clear();
m_currentAsyncCreation.clear();
m_currentTasks.clear();
m_parentTask.clear();
m_asyncTaskCreationStacks.clear();
m_framesCache.clear();
m_allAsyncStacks.clear();
......@@ -937,7 +892,6 @@ void V8Debugger::collectOldAsyncStacksIfNeeded() {
--m_asyncStacksCount;
}
cleanupExpiredWeakPointers(m_asyncTaskStacks);
cleanupExpiredWeakPointers(m_asyncTaskCreationStacks);
for (auto it = m_recurringTasks.begin(); it != m_recurringTasks.end();) {
if (m_asyncTaskStacks.find(*it) == m_asyncTaskStacks.end()) {
it = m_recurringTasks.erase(it);
......@@ -945,15 +899,6 @@ void V8Debugger::collectOldAsyncStacksIfNeeded() {
++it;
}
}
for (auto it = m_parentTask.begin(); it != m_parentTask.end();) {
if (m_asyncTaskCreationStacks.find(it->second) ==
m_asyncTaskCreationStacks.end() &&
m_asyncTaskStacks.find(it->second) == m_asyncTaskStacks.end()) {
it = m_parentTask.erase(it);
} else {
++it;
}
}
cleanupExpiredWeakPointers(m_framesCache);
}
......@@ -985,9 +930,6 @@ void V8Debugger::setMaxAsyncTaskStacksForTest(int limit) {
void V8Debugger::dumpAsyncTaskStacksStateForTest() {
fprintf(stdout, "Async stacks count: %d\n", m_asyncStacksCount);
fprintf(stdout, "Scheduled async tasks: %zu\n", m_asyncTaskStacks.size());
fprintf(stdout, "Created async tasks: %zu\n",
m_asyncTaskCreationStacks.size());
fprintf(stdout, "Async tasks with parent: %zu\n", m_parentTask.size());
fprintf(stdout, "Recurring async tasks: %zu\n", m_recurringTasks.size());
fprintf(stdout, "\n");
}
......
......@@ -79,7 +79,6 @@ class V8Debugger : public v8::debug::DebugDelegate {
void setAsyncCallStackDepth(V8DebuggerAgentImpl*, int);
std::shared_ptr<AsyncStackTrace> currentAsyncParent();
std::shared_ptr<AsyncStackTrace> currentAsyncCreation();
std::shared_ptr<StackFrame> symbolize(v8::Local<v8::StackFrame> v8Frame);
......@@ -135,7 +134,6 @@ class V8Debugger : public v8::debug::DebugDelegate {
v8::MaybeLocal<v8::Value> generatorScopes(v8::Local<v8::Context>,
v8::Local<v8::Value>);
void asyncTaskCreatedForStack(void* task, void* parentTask);
void asyncTaskScheduledForStack(const String16& taskName, void* task,
bool recurring);
void asyncTaskCanceledForStack(void* task);
......@@ -149,7 +147,7 @@ class V8Debugger : public v8::debug::DebugDelegate {
// v8::debug::DebugEventListener implementation.
void PromiseEventOccurred(v8::debug::PromiseDebugActionType type, int id,
int parentId, bool createdByUser) override;
bool isBlackboxed) override;
void ScriptCompiled(v8::Local<v8::debug::Script> script, bool is_live_edited,
bool has_compile_error) override;
void BreakProgramRequested(
......@@ -181,16 +179,13 @@ class V8Debugger : public v8::debug::DebugDelegate {
using AsyncTaskToStackTrace =
protocol::HashMap<void*, std::weak_ptr<AsyncStackTrace>>;
AsyncTaskToStackTrace m_asyncTaskStacks;
AsyncTaskToStackTrace m_asyncTaskCreationStacks;
protocol::HashSet<void*> m_recurringTasks;
protocol::HashMap<void*, void*> m_parentTask;
int m_maxAsyncCallStacks;
int m_maxAsyncCallStackDepth;
std::vector<void*> m_currentTasks;
std::vector<std::shared_ptr<AsyncStackTrace>> m_currentAsyncParent;
std::vector<std::shared_ptr<AsyncStackTrace>> m_currentAsyncCreation;
void collectOldAsyncStacksIfNeeded();
int m_asyncStacksCount = 0;
......
......@@ -32,31 +32,23 @@ std::vector<std::shared_ptr<StackFrame>> toFramesVector(
void calculateAsyncChain(V8Debugger* debugger, int contextGroupId,
std::shared_ptr<AsyncStackTrace>* asyncParent,
std::shared_ptr<AsyncStackTrace>* asyncCreation,
int* maxAsyncDepth) {
*asyncParent = debugger->currentAsyncParent();
*asyncCreation = debugger->currentAsyncCreation();
if (maxAsyncDepth) *maxAsyncDepth = debugger->maxAsyncCallChainDepth();
DCHECK(!*asyncParent || !*asyncCreation ||
(*asyncParent)->contextGroupId() ==
(*asyncCreation)->contextGroupId());
// Do not accidentally append async call chain from another group. This should
// not happen if we have proper instrumentation, but let's double-check to be
// safe.
if (contextGroupId && *asyncParent &&
(*asyncParent)->contextGroupId() != contextGroupId) {
asyncParent->reset();
asyncCreation->reset();
if (maxAsyncDepth) *maxAsyncDepth = 0;
return;
}
// 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 (*asyncParent && !(*asyncCreation) && !(*asyncParent)->creation().lock() &&
(*asyncParent)->isEmpty()) {
// 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 (*asyncParent && (*asyncParent)->isEmpty()) {
*asyncParent = (*asyncParent)->parent().lock();
}
}
......@@ -64,11 +56,10 @@ void calculateAsyncChain(V8Debugger* debugger, int contextGroupId,
std::unique_ptr<protocol::Runtime::StackTrace> buildInspectorObjectCommon(
const std::vector<std::shared_ptr<StackFrame>>& frames,
const String16& description,
const std::shared_ptr<AsyncStackTrace>& asyncParent,
const std::shared_ptr<AsyncStackTrace>& asyncCreation, int maxAsyncDepth) {
const std::shared_ptr<AsyncStackTrace>& asyncParent, int maxAsyncDepth) {
if (asyncParent && frames.empty() &&
description == asyncParent->description() && !asyncCreation) {
return asyncParent->buildInspectorObject(nullptr, maxAsyncDepth);
description == asyncParent->description()) {
return asyncParent->buildInspectorObject(maxAsyncDepth);
}
std::unique_ptr<protocol::Array<protocol::Runtime::CallFrame>>
......@@ -82,8 +73,7 @@ std::unique_ptr<protocol::Runtime::StackTrace> buildInspectorObjectCommon(
.build();
if (!description.isEmpty()) stackTrace->setDescription(description);
if (asyncParent && maxAsyncDepth > 0) {
stackTrace->setParent(asyncParent->buildInspectorObject(asyncCreation.get(),
maxAsyncDepth - 1));
stackTrace->setParent(asyncParent->buildInspectorObject(maxAsyncDepth - 1));
}
return stackTrace;
}
......@@ -155,12 +145,10 @@ std::unique_ptr<V8StackTraceImpl> V8StackTraceImpl::create(
int maxAsyncDepth = 0;
std::shared_ptr<AsyncStackTrace> asyncParent;
std::shared_ptr<AsyncStackTrace> asyncCreation;
calculateAsyncChain(debugger, contextGroupId, &asyncParent, &asyncCreation,
&maxAsyncDepth);
if (frames.empty() && !asyncCreation && !asyncParent) return nullptr;
return std::unique_ptr<V8StackTraceImpl>(new V8StackTraceImpl(
std::move(frames), maxAsyncDepth, asyncParent, asyncCreation));
calculateAsyncChain(debugger, contextGroupId, &asyncParent, &maxAsyncDepth);
if (frames.empty() && !asyncParent) return nullptr;
return std::unique_ptr<V8StackTraceImpl>(
new V8StackTraceImpl(std::move(frames), maxAsyncDepth, asyncParent));
}
// static
......@@ -180,19 +168,16 @@ std::unique_ptr<V8StackTraceImpl> V8StackTraceImpl::capture(
V8StackTraceImpl::V8StackTraceImpl(
std::vector<std::shared_ptr<StackFrame>> frames, int maxAsyncDepth,
std::shared_ptr<AsyncStackTrace> asyncParent,
std::shared_ptr<AsyncStackTrace> asyncCreation)
std::shared_ptr<AsyncStackTrace> asyncParent)
: m_frames(std::move(frames)),
m_maxAsyncDepth(maxAsyncDepth),
m_asyncParent(asyncParent),
m_asyncCreation(asyncCreation) {}
m_asyncParent(asyncParent) {}
V8StackTraceImpl::~V8StackTraceImpl() {}
std::unique_ptr<V8StackTrace> V8StackTraceImpl::clone() {
return std::unique_ptr<V8StackTrace>(
new V8StackTraceImpl(m_frames, 0, std::shared_ptr<AsyncStackTrace>(),
std::shared_ptr<AsyncStackTrace>()));
new V8StackTraceImpl(m_frames, 0, std::shared_ptr<AsyncStackTrace>()));
}
bool V8StackTraceImpl::isEmpty() const { return m_frames.empty(); }
......@@ -220,7 +205,7 @@ StringView V8StackTraceImpl::topFunctionName() const {
std::unique_ptr<protocol::Runtime::StackTrace>
V8StackTraceImpl::buildInspectorObjectImpl() const {
return buildInspectorObjectCommon(m_frames, String16(), m_asyncParent.lock(),
m_asyncCreation.lock(), m_maxAsyncDepth);
m_maxAsyncDepth);
}
std::unique_ptr<protocol::Runtime::API::StackTrace>
......@@ -307,18 +292,15 @@ std::shared_ptr<AsyncStackTrace> AsyncStackTrace::capture(
}
std::shared_ptr<AsyncStackTrace> asyncParent;
std::shared_ptr<AsyncStackTrace> asyncCreation;
calculateAsyncChain(debugger, contextGroupId, &asyncParent, &asyncCreation,
nullptr);
calculateAsyncChain(debugger, contextGroupId, &asyncParent, nullptr);
if (frames.empty() && !asyncCreation && !asyncParent) return nullptr;
if (frames.empty() && !asyncParent) return nullptr;
// When async call chain is empty but doesn't contain useful schedule stack
// and parent async call chain contains creationg stack but doesn't
// synchronous we can merge them together.
// e.g. Promise ThenableJob.
// but doesn't synchronous we can merge them together. e.g. Promise
// ThenableJob.
if (asyncParent && frames.empty() &&
asyncParent->m_description == description && !asyncCreation) {
asyncParent->m_description == description) {
return asyncParent;
}
......@@ -326,30 +308,25 @@ std::shared_ptr<AsyncStackTrace> AsyncStackTrace::capture(
if (!contextGroupId && asyncParent) {
contextGroupId = asyncParent->m_contextGroupId;
}
return std::shared_ptr<AsyncStackTrace>(
new AsyncStackTrace(contextGroupId, description, std::move(frames),
asyncParent, asyncCreation));
return std::shared_ptr<AsyncStackTrace>(new AsyncStackTrace(
contextGroupId, description, std::move(frames), asyncParent));
}
AsyncStackTrace::AsyncStackTrace(
int contextGroupId, const String16& description,
std::vector<std::shared_ptr<StackFrame>> frames,
std::shared_ptr<AsyncStackTrace> asyncParent,
std::shared_ptr<AsyncStackTrace> asyncCreation)
std::shared_ptr<AsyncStackTrace> asyncParent)
: m_contextGroupId(contextGroupId),
m_description(description),
m_frames(std::move(frames)),
m_asyncParent(asyncParent),
m_asyncCreation(asyncCreation) {
m_asyncParent(asyncParent) {
DCHECK(m_contextGroupId);
}
std::unique_ptr<protocol::Runtime::StackTrace>
AsyncStackTrace::buildInspectorObject(AsyncStackTrace* asyncCreation,
int maxAsyncDepth) const {
AsyncStackTrace::buildInspectorObject(int maxAsyncDepth) const {
return buildInspectorObjectCommon(m_frames, m_description,
m_asyncParent.lock(),
m_asyncCreation.lock(), maxAsyncDepth);
m_asyncParent.lock(), maxAsyncDepth);
}
int AsyncStackTrace::contextGroupId() const { return m_contextGroupId; }
......@@ -360,10 +337,6 @@ std::weak_ptr<AsyncStackTrace> AsyncStackTrace::parent() const {
return m_asyncParent;
}
std::weak_ptr<AsyncStackTrace> AsyncStackTrace::creation() const {
return m_asyncCreation;
}
bool AsyncStackTrace::isEmpty() const { return m_frames.empty(); }
} // namespace v8_inspector
......@@ -78,8 +78,7 @@ class V8StackTraceImpl : public V8StackTrace {
private:
V8StackTraceImpl(std::vector<std::shared_ptr<StackFrame>> frames,
int maxAsyncDepth,
std::shared_ptr<AsyncStackTrace> asyncParent,
std::shared_ptr<AsyncStackTrace> asyncCreation);
std::shared_ptr<AsyncStackTrace> asyncParent);
class StackFrameIterator {
public:
......@@ -98,7 +97,6 @@ class V8StackTraceImpl : public V8StackTrace {
std::vector<std::shared_ptr<StackFrame>> m_frames;
int m_maxAsyncDepth;
std::weak_ptr<AsyncStackTrace> m_asyncParent;
std::weak_ptr<AsyncStackTrace> m_asyncCreation;
DISALLOW_COPY_AND_ASSIGN(V8StackTraceImpl);
};
......@@ -111,18 +109,13 @@ class AsyncStackTrace {
int maxStackSize);
std::unique_ptr<protocol::Runtime::StackTrace> buildInspectorObject(
AsyncStackTrace* asyncCreation, int maxAsyncDepth) const;
int maxAsyncDepth) const;
int contextGroupId() const;
const String16& description() const;
std::weak_ptr<AsyncStackTrace> parent() const;
std::weak_ptr<AsyncStackTrace> creation() const;
bool isEmpty() const;
void setDescription(const String16& description) {
// TODO(kozyatinskiy): implement it without hack.
m_description = description;
}
const std::vector<std::shared_ptr<StackFrame>>& frames() const {
return m_frames;
}
......@@ -130,15 +123,13 @@ class AsyncStackTrace {
private:
AsyncStackTrace(int contextGroupId, const String16& description,
std::vector<std::shared_ptr<StackFrame>> frames,
std::shared_ptr<AsyncStackTrace> asyncParent,
std::shared_ptr<AsyncStackTrace> asyncCreation);
std::shared_ptr<AsyncStackTrace> asyncParent);
int m_contextGroupId;
String16 m_description;
std::vector<std::shared_ptr<StackFrame>> m_frames;
std::weak_ptr<AsyncStackTrace> m_asyncParent;
std::weak_ptr<AsyncStackTrace> m_asyncCreation;
DISALLOW_COPY_AND_ASSIGN(AsyncStackTrace);
};
......
......@@ -1872,7 +1872,6 @@ RUNTIME_FUNCTION(Runtime_DebugAsyncFunctionPromiseCreated) {
handle(Smi::FromInt(id), isolate),
LanguageMode::kStrict)
.Assert();
isolate->debug()->OnAsyncTaskEvent(debug::kDebugEnqueueAsyncFunction, id, 0);
return isolate->heap()->undefined_value();
}
......@@ -1886,20 +1885,6 @@ RUNTIME_FUNCTION(Runtime_DebugPromiseReject) {
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_DebugAsyncEventEnqueueRecurring) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0);
CONVERT_SMI_ARG_CHECKED(status, 1);
if (isolate->debug()->is_active()) {
isolate->debug()->OnAsyncTaskEvent(
status == v8::Promise::kFulfilled ? debug::kDebugEnqueuePromiseResolve
: debug::kDebugEnqueuePromiseReject,
isolate->debug()->NextAsyncTaskId(promise), 0);
}
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_DebugIsActive) {
SealHandleScope shs(isolate);
return Smi::FromInt(isolate->debug()->is_active());
......
......@@ -45,9 +45,6 @@ RUNTIME_FUNCTION(Runtime_PromiseRejectEventFromStack) {
// undefined, which will be interpreted by PromiseRejectEvent
// as being a caught exception event.
rejected_promise = isolate->GetPromiseOnStackOnThrow();
isolate->debug()->OnAsyncTaskEvent(
debug::kDebugEnqueuePromiseReject,
isolate->debug()->NextAsyncTaskId(promise), 0);
}
PromiseRejectEvent(isolate, promise, rejected_promise, value, true);
return isolate->heap()->undefined_value();
......
......@@ -189,7 +189,6 @@ namespace internal {
F(DebugPushPromise, 1, 1) \
F(DebugPopPromise, 0, 1) \
F(DebugPromiseReject, 2, 1) \
F(DebugAsyncEventEnqueueRecurring, 2, 1) \
F(DebugAsyncFunctionPromiseCreated, 1, 1) \
F(DebugIsActive, 0, 1) \
F(DebugBreakInOptimizedCode, 0, 1) \
......
......@@ -8,12 +8,12 @@ test (test.js:21:2)
(anonymous) (expr1.js:0:0)
foo (test.js:10:2)
-- Promise.resolve --
-- Promise.then --
test (test.js:19:14)
(anonymous) (expr1.js:0:0)
foo (test.js:12:2)
-- Promise.resolve --
-- Promise.then --
test (test.js:19:14)
(anonymous) (expr1.js:0:0)
......
Checks async stack for late .then handlers with gc
foo1 (test.js:11:2)
-- Promise.resolve --
-- Promise.then --
test (test.js:18:14)
(anonymous) (expr.js:0:0)
foo1 (test.js:11:2)
-- Promise.resolve --
-- Promise.then --
test (test.js:22:14)
(anonymous) (expr.js:0:0)
foo1 (test.js:11:2)
-- Promise.resolve --
-- Promise.then --
test (test.js:24:14)
(anonymous) (expr.js:0:0)
......@@ -19,7 +19,7 @@ test (test.js:24:8)
(anonymous) (expr.js:0:0)
foo1 (test.js:9:2)
-- Promise.resolve --
-- Promise.then --
foo2 (test.js:19:43)
-- async function --
foo2 (test.js:13:19)
......
......@@ -2,78 +2,78 @@ Checks created frame for async call chain
Running test: testPromise
foo1 (test.js:10:2)
-- Promise.resolve --
-- Promise.then --
promise (test.js:20:14)
(anonymous) (expr.js:0:0)
Running test: testPromiseThen
foo1 (test.js:10:2)
-- Promise.resolve --
-- Promise.then --
promiseThen (test.js:28:14)
(anonymous) (expr.js:0:0)
foo2 (test.js:14:2)
-- Promise.resolve --
-- Promise.then --
promiseThen (test.js:29:14)
(anonymous) (expr.js:0:0)
Running test: testPromiseThenThen
foo1 (test.js:10:2)
-- Promise.resolve --
-- Promise.then --
promiseThenThen (test.js:37:14)
(anonymous) (expr.js:0:0)
foo1 (test.js:10:2)
-- Promise.resolve --
-- Promise.then --
promiseThenThen (test.js:38:14)
(anonymous) (expr.js:0:0)
foo2 (test.js:14:2)
-- Promise.resolve --
-- Promise.then --
promiseThenThen (test.js:37:25)
(anonymous) (expr.js:0:0)
Running test: testPromiseResolve
foo1 (test.js:10:2)
-- Promise.resolve --
-- Promise.then --
promiseResolve (test.js:44:27)
(anonymous) (expr.js:0:0)
Running test: testPromiseReject
foo1 (test.js:10:2)
-- Promise.reject --
-- Promise.catch --
promiseReject (test.js:48:31)
(anonymous) (expr.js:0:0)
Running test: testPromiseAll
foo1 (test.js:10:2)
-- Promise.resolve --
-- Promise.then --
promiseAll (test.js:52:44)
(anonymous) (expr.js:0:0)
Running test: testPromiseRace
foo1 (test.js:10:2)
-- Promise.resolve --
-- Promise.then --
promiseRace (test.js:56:45)
(anonymous) (expr.js:0:0)
Running test: testThenableJob1
foo1 (test.js:10:2)
-- Promise.resolve --
-- Promise.then --
thenableJob1 (test.js:60:72)
(anonymous) (expr.js:0:0)
Running test: testThenableJob2
foo1 (test.js:10:2)
-- Promise.resolve --
-- Promise.then --
thenableJob2 (test.js:64:57)
(anonymous) (expr.js:0:0)
......
......@@ -2,94 +2,94 @@ Checks that async chains for promises are correct.
Running test: testPromise
foo1 (test.js:9:2)
-- Promise.resolve --
-- Promise.then --
promise (test.js:19:14)
(anonymous) (testPromise.js:0:0)
Running test: testPromiseResolvedBySetTimeout
foo1 (test.js:9:2)
-- Promise.resolve --
-- Promise.then --
promiseResolvedBySetTimeout (test.js:27:14)
(anonymous) (testPromiseResolvedBySetTimeout.js:0:0)
Running test: testPromiseAll
foo1 (test.js:9:2)
-- Promise.resolve --
-- Promise.then --
promiseAll (test.js:37:35)
(anonymous) (testPromiseAll.js:0:0)
Running test: testPromiseAllReverseOrder
foo1 (test.js:9:2)
-- Promise.resolve --
-- Promise.then --
promiseAllReverseOrder (test.js:48:35)
(anonymous) (testPromiseAllReverseOrder.js:0:0)
Running test: testPromiseRace
foo1 (test.js:9:2)
-- Promise.resolve --
-- Promise.then --
promiseRace (test.js:59:36)
(anonymous) (testPromiseRace.js:0:0)
Running test: testTwoChainedCallbacks
foo1 (test.js:9:2)
-- Promise.resolve --
-- Promise.then --
twoChainedCallbacks (test.js:68:14)
(anonymous) (testTwoChainedCallbacks.js:0:0)
foo2 (test.js:13:2)
-- Promise.resolve --
-- Promise.then --
twoChainedCallbacks (test.js:68:25)
(anonymous) (testTwoChainedCallbacks.js:0:0)
Running test: testPromiseResolve
foo1 (test.js:9:2)
-- Promise.resolve --
-- Promise.then --
promiseResolve (test.js:74:27)
(anonymous) (testPromiseResolve.js:0:0)
foo2 (test.js:13:2)
-- Promise.resolve --
-- Promise.then --
promiseResolve (test.js:74:38)
(anonymous) (testPromiseResolve.js:0:0)
Running test: testThenableJobResolvedInSetTimeout
foo1 (test.js:9:2)
-- Promise.resolve --
-- Promise.then --
thenableJobResolvedInSetTimeout (test.js:86:40)
(anonymous) (testThenableJobResolvedInSetTimeout.js:0:0)
Running test: testThenableJobResolvedInSetTimeoutWithStack
foo1 (test.js:9:2)
-- Promise.resolve --
-- Promise.then --
thenableJobResolvedInSetTimeoutWithStack (test.js:104:40)
(anonymous) (testThenableJobResolvedInSetTimeoutWithStack.js:0:0)
Running test: testThenableJobResolvedByPromise
foo1 (test.js:9:2)
-- Promise.resolve --
-- Promise.then --
thenableJobResolvedByPromise (test.js:118:40)
(anonymous) (testThenableJobResolvedByPromise.js:0:0)
Running test: testThenableJobResolvedByPromiseWithStack
foo1 (test.js:9:2)
-- Promise.resolve --
-- Promise.then --
thenableJobResolvedByPromiseWithStack (test.js:136:40)
(anonymous) (testThenableJobResolvedByPromiseWithStack.js:0:0)
Running test: testLateThenCallback
foo1 (test.js:9:2)
-- Promise.resolve --
-- Promise.then --
lateThenCallback (test.js:145:12)
(anonymous) (testLateThenCallback.js:0:0)
......@@ -97,14 +97,14 @@ lateThenCallback (test.js:145:12)
Running test: testComplex
inner1 (test.js:154:6)
foo1 (test.js:156:4)
-- Promise.resolve --
-- Promise.then --
complex (test.js:202:5)
(anonymous) (testComplex.js:0:0)
p.then (test.js:207:8)
-- Promise.resolve --
-- Promise.then --
p.then (test.js:206:8)
-- Promise.resolve --
-- Promise.then --
setTimeout (test.js:205:6)
-- setTimeout --
complex (test.js:204:2)
......@@ -113,7 +113,21 @@ complex (test.js:204:2)
Running test: testReject
foo1 (test.js:9:2)
-- Promise.reject --
-- Promise.catch --
reject (test.js:217:31)
(anonymous) (testReject.js:0:0)
Running test: testFinally1
foo1 (test.js:9:2)
-- Promise.finally --
finally1 (test.js:221:33)
(anonymous) (testFinally1.js:0:0)
Running test: testFinally2
foo1 (test.js:9:2)
-- Promise.finally --
finally2 (test.js:225:34)
(anonymous) (testFinally2.js:0:0)
......@@ -217,6 +217,13 @@ function reject() {
return Promise.reject().catch(foo1);
}
function finally1() {
return Promise.reject().finally(foo1);
}
function finally2() {
return Promise.resolve().finally(foo1);
}
//# sourceURL=test.js`, 7, 26);
session.setupScriptMap();
......@@ -230,20 +237,12 @@ Protocol.Debugger.onPaused(message => {
Protocol.Debugger.enable();
Protocol.Debugger.setAsyncCallStackDepth({ maxDepth: 128 });
var testList = [
'promise',
'promiseResolvedBySetTimeout',
'promiseAll',
'promiseAllReverseOrder',
'promiseRace',
'twoChainedCallbacks',
'promiseResolve',
'thenableJobResolvedInSetTimeout',
'thenableJobResolvedInSetTimeoutWithStack',
'thenableJobResolvedByPromise',
'thenableJobResolvedByPromiseWithStack',
'lateThenCallback',
'complex',
'reject',
'promise', 'promiseResolvedBySetTimeout', 'promiseAll',
'promiseAllReverseOrder', 'promiseRace', 'twoChainedCallbacks',
'promiseResolve', 'thenableJobResolvedInSetTimeout',
'thenableJobResolvedInSetTimeoutWithStack', 'thenableJobResolvedByPromise',
'thenableJobResolvedByPromiseWithStack', 'lateThenCallback', 'complex',
'reject', 'finally1', 'finally2'
]
InspectorTest.runTestSuite(testList.map(name => {
return eval(`
......
Checks that we collect obsolete async tasks with async stacks.
Async stacks count: 2
Async stacks count: 1
Scheduled async tasks: 1
Created async tasks: 1
Async tasks with parent: 0
Recurring async tasks: 1
Recurring async tasks: 0
Async stacks count: 0
Scheduled async tasks: 0
Created async tasks: 0
Async tasks with parent: 0
Recurring async tasks: 0
Async stacks count: 2
Scheduled async tasks: 0
Created async tasks: 2
Async tasks with parent: 2
Scheduled async tasks: 2
Recurring async tasks: 0
Async stacks count: 0
Scheduled async tasks: 0
Created async tasks: 0
Async tasks with parent: 0
Recurring async tasks: 0
Async stacks count: 1
Scheduled async tasks: 1
Created async tasks: 0
Async tasks with parent: 0
Recurring async tasks: 0
Async stacks count: 0
Scheduled async tasks: 0
Created async tasks: 0
Async tasks with parent: 0
Recurring async tasks: 0
......@@ -7,7 +7,7 @@ let {session, contextGroup, Protocol} = InspectorTest.start('Checks that we coll
contextGroup.addScript(`
function test() {
inspector.setMaxAsyncTaskStacks(128);
var p = Promise.resolve();
var p = Promise.resolve().then(() => 42);
inspector.dumpAsyncTaskStacksStateForTest();
inspector.setMaxAsyncTaskStacks(128);
......
......@@ -7,11 +7,11 @@ actual async chain len: 1
inspector.setMaxAsyncTaskStacks(1024)
Run expression 'console.trace(42)' with async chain len: 2
actual async chain len: 1
actual async chain len: 2
inspector.setMaxAsyncTaskStacks(1024)
Run expression 'console.trace(42)' with async chain len: 5
actual async chain len: 1
actual async chain len: 5
inspector.setMaxAsyncTaskStacks(1024)
Run expression 'console.trace(42)' with async chain len: 1
......@@ -69,7 +69,7 @@ actual async chain len: 1
inspector.setMaxAsyncTaskStacks(2)
Run expression 'console.trace(42)' with async chain len: 2
actual async chain len: 0
actual async chain len: 2
inspector.setMaxAsyncTaskStacks(2)
Run expression 'console.trace(42)' with async chain len: 3
......@@ -95,11 +95,11 @@ actual async chain len: 1
inspector.setMaxAsyncTaskStacks(3)
Run expression 'console.trace(42)' with async chain len: 2
actual async chain len: 1
actual async chain len: 2
inspector.setMaxAsyncTaskStacks(3)
Run expression 'console.trace(42)' with async chain len: 3
actual async chain len: 1
actual async chain len: 3
inspector.setMaxAsyncTaskStacks(3)
Run expression 'console.trace(42)' with async chain len: 1
......@@ -119,11 +119,11 @@ actual async chain len: 1
inspector.setMaxAsyncTaskStacks(4)
Run expression 'console.trace(42)' with async chain len: 2
actual async chain len: 1
actual async chain len: 2
inspector.setMaxAsyncTaskStacks(4)
Run expression 'console.trace(42)' with async chain len: 3
actual async chain len: 1
actual async chain len: 3
inspector.setMaxAsyncTaskStacks(4)
Run expression 'console.trace(42)' with async chain len: 1
......@@ -143,11 +143,11 @@ actual async chain len: 1
inspector.setMaxAsyncTaskStacks(5)
Run expression 'console.trace(42)' with async chain len: 2
actual async chain len: 1
actual async chain len: 2
inspector.setMaxAsyncTaskStacks(5)
Run expression 'console.trace(42)' with async chain len: 3
actual async chain len: 1
actual async chain len: 3
inspector.setMaxAsyncTaskStacks(5)
Run expression 'console.trace(42)' with async chain len: 1
......@@ -167,11 +167,11 @@ actual async chain len: 1
inspector.setMaxAsyncTaskStacks(6)
Run expression 'console.trace(42)' with async chain len: 2
actual async chain len: 1
actual async chain len: 2
inspector.setMaxAsyncTaskStacks(6)
Run expression 'console.trace(42)' with async chain len: 3
actual async chain len: 1
actual async chain len: 3
inspector.setMaxAsyncTaskStacks(6)
Run expression 'console.trace(42)' with async chain len: 1
......@@ -191,11 +191,11 @@ actual async chain len: 1
inspector.setMaxAsyncTaskStacks(7)
Run expression 'console.trace(42)' with async chain len: 2
actual async chain len: 1
actual async chain len: 2
inspector.setMaxAsyncTaskStacks(7)
Run expression 'console.trace(42)' with async chain len: 3
actual async chain len: 1
actual async chain len: 3
inspector.setMaxAsyncTaskStacks(7)
Run expression 'console.trace(42)' with async chain len: 1
......
......@@ -138,11 +138,14 @@ InspectorTest.runAsyncTestSuite([
function runWithAsyncChainPromise(len, source) {
InspectorTest.log(`Run expression '${source}' with async chain len: ${len}`);
let then = '.then(() => 1)';
let pause = `.then(() => { ${source} })`;
Protocol.Runtime.evaluate({
expression: `Promise.resolve()${then.repeat(len - 1)}${pause}`
});
let asyncCall = `(function asyncCall(num) {
if (num === 0) {
${source};
return;
}
Promise.resolve().then(() => asyncCall(num - 1));
})(${len})`;
Protocol.Runtime.evaluate({expression: asyncCall});
}
function runWithAsyncChainSetTimeout(len, source) {
......
......@@ -62,7 +62,7 @@ Running test: testConsoleTraceWithEmptySync
url :
}
]
description : Promise.resolve
description : Promise.then
}
}
......
......@@ -40,11 +40,14 @@ let {session, contextGroup, Protocol} = InspectorTest.start('Tests how async pro
function runWithAsyncChainPromise(len, source) {
InspectorTest.log(`Run expression '${source}' with async chain len: ${len}`);
let then = '.then(() => 1)';
let pause = `.then(() => { ${source} })`;
Protocol.Runtime.evaluate({
expression: `Promise.resolve()${then.repeat(len - 1)}${pause}`
});
let asyncCall = `(function asyncCall(num) {
if (num === 0) {
${source};
return;
}
Promise.resolve().then(() => asyncCall(num - 1));
})(${len})`;
Protocol.Runtime.evaluate({expression: asyncCall});
}
async function setMaxAsyncTaskStacks(max) {
......
......@@ -26,22 +26,6 @@ Running test: testRejectedPromise
}
exceptionId : <exceptionId>
lineNumber : 0
stackTrace : {
callFrames : [
]
parent : {
callFrames : [
[0] : {
columnNumber : 8
functionName :
lineNumber : 0
scriptId : <scriptId>
url :
}
]
description : Promise.reject
}
}
text : Uncaught (in promise)
}
result : {
......@@ -66,29 +50,6 @@ Running test: testRejectedPromiseWithStack
}
exceptionId : <exceptionId>
lineNumber : 0
stackTrace : {
callFrames : [
]
parent : {
callFrames : [
[0] : {
columnNumber : 4
functionName : rejectPromise
lineNumber : 17
scriptId : <scriptId>
url : test.js
}
[1] : {
columnNumber : 0
functionName :
lineNumber : 0
scriptId : <scriptId>
url :
}
]
description : Promise.reject
}
}
text : Uncaught (in promise)
}
result : {
......@@ -114,29 +75,6 @@ Running test: testRejectedPromiseWithError
}
exceptionId : <exceptionId>
lineNumber : 0
stackTrace : {
callFrames : [
]
parent : {
callFrames : [
[0] : {
columnNumber : 4
functionName : rejectPromiseWithAnError
lineNumber : 24
scriptId : <scriptId>
url : test.js
}
[1] : {
columnNumber : 0
functionName :
lineNumber : 0
scriptId : <scriptId>
url :
}
]
description : Promise.reject
}
}
text : Uncaught (in promise) Error: MyError
}
result : {
......
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