[inspector] reworked async stack instrumentation for async functions
New intstrumentation consists of: - kAsyncFunctionSuspended when async function is suspended on await (called on each await), - kAsyncFunctionFinished when async function is finished. Old instrumentation was based on reusing async function promise. Using this promise produces couple side effects: - for any promise instrumentation we first need to check if it is special case for async function promise or not - it requires expensive reading from promise object. - we capture stack for async functions even if it does not contain awaits. - we do not properly cancel async task created for async function. New intsrumntation resolved all these problems as well as provide clear mapping between async task and generator which we can use later to fetch scope information for async functions on pause. R=dgozman@chromium.org,yangguo@chromium.org Bug: v8:7078 Cq-Include-Trybots: master.tryserver.blink:linux_trusty_blink_rel Change-Id: Ifdcec947d91e6e3d4d5f9029bc080a19b8e23d41 Reviewed-on: https://chromium-review.googlesource.com/1043096 Reviewed-by: Sathya Gunasekaran <gsathya@chromium.org> Reviewed-by: Benedikt Meurer <bmeurer@chromium.org> Reviewed-by: Dmitry Gozman <dgozman@chromium.org> Commit-Queue: Aleksey Kozyatinskiy <kozyatinskiy@chromium.org> Cr-Commit-Position: refs/heads/master@{#53445}
This commit is contained in:
parent
9f4e74848b
commit
b6c9086ca1
@ -4110,7 +4110,7 @@ void Bootstrapper::ExportFromRuntime(Isolate* isolate,
|
||||
{
|
||||
Handle<JSFunction> function = SimpleCreateFunction(
|
||||
isolate, factory->empty_string(),
|
||||
Builtins::kAsyncFunctionPromiseRelease, 1, false);
|
||||
Builtins::kAsyncFunctionPromiseRelease, 2, false);
|
||||
native_context->set_async_function_promise_release(*function);
|
||||
}
|
||||
}
|
||||
|
@ -120,6 +120,11 @@ void AsyncFunctionBuiltinsAssembler::AsyncFunctionAwait(
|
||||
// TODO(jgruber): Use a faster specialized version of
|
||||
// InternalPerformPromiseThen.
|
||||
|
||||
Label after_debug_hook(this), call_debug_hook(this, Label::kDeferred);
|
||||
GotoIf(IsDebugActive(), &call_debug_hook);
|
||||
Goto(&after_debug_hook);
|
||||
BIND(&after_debug_hook);
|
||||
|
||||
Await(context, generator, awaited, outer_promise, AwaitContext::kLength,
|
||||
init_closure_context, Context::ASYNC_FUNCTION_AWAIT_RESOLVE_SHARED_FUN,
|
||||
Context::ASYNC_FUNCTION_AWAIT_REJECT_SHARED_FUN,
|
||||
@ -128,6 +133,10 @@ void AsyncFunctionBuiltinsAssembler::AsyncFunctionAwait(
|
||||
// Return outer promise to avoid adding an load of the outer promise before
|
||||
// suspending in BytecodeGenerator.
|
||||
Return(outer_promise);
|
||||
|
||||
BIND(&call_debug_hook);
|
||||
CallRuntime(Runtime::kDebugAsyncFunctionSuspended, context, outer_promise);
|
||||
Goto(&after_debug_hook);
|
||||
}
|
||||
|
||||
// Called by the parser from the desugaring of 'await' when catch
|
||||
@ -177,15 +186,13 @@ TF_BUILTIN(AsyncFunctionPromiseCreate, AsyncFunctionBuiltinsAssembler) {
|
||||
// Push the Promise under construction in an async function on
|
||||
// the catch prediction stack to handle exceptions thrown before
|
||||
// the first await.
|
||||
// Assign ID and create a recurring task to save stack for future
|
||||
// resumptions from await.
|
||||
CallRuntime(Runtime::kDebugAsyncFunctionPromiseCreated, context, promise);
|
||||
CallRuntime(Runtime::kDebugPushPromise, context, promise);
|
||||
Return(promise);
|
||||
}
|
||||
}
|
||||
|
||||
TF_BUILTIN(AsyncFunctionPromiseRelease, AsyncFunctionBuiltinsAssembler) {
|
||||
CSA_ASSERT_JS_ARGC_EQ(this, 1);
|
||||
CSA_ASSERT_JS_ARGC_EQ(this, 2);
|
||||
Node* const promise = Parameter(Descriptor::kPromise);
|
||||
Node* const context = Parameter(Descriptor::kContext);
|
||||
|
||||
@ -199,7 +206,8 @@ TF_BUILTIN(AsyncFunctionPromiseRelease, AsyncFunctionBuiltinsAssembler) {
|
||||
{
|
||||
// Pop the Promise under construction in an async function on
|
||||
// from catch prediction stack.
|
||||
CallRuntime(Runtime::kDebugPopPromise, context);
|
||||
CallRuntime(Runtime::kDebugAsyncFunctionFinished, context,
|
||||
Parameter(Descriptor::kCanSuspend), promise);
|
||||
Return(promise);
|
||||
}
|
||||
}
|
||||
|
@ -99,9 +99,8 @@ Node* AsyncBuiltinsAssembler::Await(
|
||||
// Add PromiseHooks if needed
|
||||
Label next(this);
|
||||
GotoIfNot(IsPromiseHookEnabledOrDebugIsActive(), &next);
|
||||
CallRuntime(Runtime::kPromiseHookInit, context, wrapped_value,
|
||||
outer_promise);
|
||||
CallRuntime(Runtime::kPromiseHookInit, context, throwaway, wrapped_value);
|
||||
CallRuntime(Runtime::kAwaitPromisesInit, context, wrapped_value,
|
||||
outer_promise, throwaway);
|
||||
Goto(&next);
|
||||
BIND(&next);
|
||||
}
|
||||
|
@ -421,7 +421,7 @@ namespace internal {
|
||||
TFJ(AsyncFunctionAwaitRejectClosure, 1, kSentError) \
|
||||
TFJ(AsyncFunctionAwaitResolveClosure, 1, kSentValue) \
|
||||
TFJ(AsyncFunctionPromiseCreate, 0) \
|
||||
TFJ(AsyncFunctionPromiseRelease, 1, kPromise) \
|
||||
TFJ(AsyncFunctionPromiseRelease, 2, kPromise, kCanSuspend) \
|
||||
\
|
||||
/* BigInt */ \
|
||||
CPP(BigIntConstructor) \
|
||||
|
@ -171,8 +171,8 @@ MaybeLocal<UnboundScript> CompileInspectorScript(Isolate* isolate,
|
||||
class DebugDelegate {
|
||||
public:
|
||||
virtual ~DebugDelegate() {}
|
||||
virtual void PromiseEventOccurred(debug::PromiseDebugActionType type, int id,
|
||||
bool is_blackboxed) {}
|
||||
virtual void AsyncEventOccurred(debug::DebugAsyncActionType type, int id,
|
||||
bool is_blackboxed) {}
|
||||
virtual void ScriptCompiled(v8::Local<Script> script, bool is_live_edited,
|
||||
bool has_compile_error) {}
|
||||
// |inspector_break_points_hit| contains id of breakpoints installed with
|
||||
|
@ -1734,7 +1734,7 @@ MaybeHandle<Object> Debug::MakeCompileEvent(Handle<Script> script,
|
||||
}
|
||||
|
||||
MaybeHandle<Object> Debug::MakeAsyncTaskEvent(
|
||||
v8::debug::PromiseDebugActionType type, int id) {
|
||||
v8::debug::DebugAsyncActionType type, int id) {
|
||||
// Create the async task event object.
|
||||
Handle<Object> argv[] = {Handle<Smi>(Smi::FromInt(type), isolate_),
|
||||
Handle<Smi>(Smi::FromInt(id), isolate_)};
|
||||
@ -1771,6 +1771,15 @@ void Debug::OnPromiseReject(Handle<Object> promise, Handle<Object> value) {
|
||||
}
|
||||
}
|
||||
|
||||
void Debug::OnAsyncFunctionStateChanged(Handle<JSPromise> promise,
|
||||
debug::DebugAsyncActionType event) {
|
||||
if (in_debug_scope() || ignore_events()) return;
|
||||
if (!debug_delegate_) return;
|
||||
PostponeInterruptsScope no_interrupts(isolate_);
|
||||
int id = NextAsyncTaskId(promise);
|
||||
debug_delegate_->AsyncEventOccurred(event, id, false);
|
||||
}
|
||||
|
||||
namespace {
|
||||
v8::Local<v8::Context> GetDebugEventContext(Isolate* isolate) {
|
||||
Handle<Context> context = isolate->debug()->debugger_entry()->GetContext();
|
||||
@ -1909,39 +1918,6 @@ void Debug::OnAfterCompile(Handle<Script> script) {
|
||||
ProcessCompileEvent(v8::AfterCompile, script);
|
||||
}
|
||||
|
||||
namespace {
|
||||
// In an async function, reuse the existing stack related to the outer
|
||||
// Promise. Otherwise, e.g. in a direct call to then, save a new stack.
|
||||
// Promises with multiple reactions with one or more of them being async
|
||||
// functions will not get a good stack trace, as async functions require
|
||||
// different stacks from direct Promise use, but we save and restore a
|
||||
// stack once for all reactions.
|
||||
//
|
||||
// If this isn't a case of async function, we return false, otherwise
|
||||
// we set the correct id and return true.
|
||||
//
|
||||
// TODO(littledan): Improve this case.
|
||||
int GetReferenceAsyncTaskId(Isolate* isolate, Handle<JSPromise> promise) {
|
||||
Handle<Symbol> handled_by_symbol =
|
||||
isolate->factory()->promise_handled_by_symbol();
|
||||
Handle<Object> handled_by_promise =
|
||||
JSObject::GetDataProperty(promise, handled_by_symbol);
|
||||
if (!handled_by_promise->IsJSPromise()) {
|
||||
return isolate->debug()->NextAsyncTaskId(promise);
|
||||
}
|
||||
Handle<JSPromise> handled_by_promise_js =
|
||||
Handle<JSPromise>::cast(handled_by_promise);
|
||||
Handle<Symbol> async_stack_id_symbol =
|
||||
isolate->factory()->promise_async_stack_id_symbol();
|
||||
Handle<Object> async_task_id =
|
||||
JSObject::GetDataProperty(handled_by_promise_js, async_stack_id_symbol);
|
||||
if (!async_task_id->IsSmi()) {
|
||||
return isolate->debug()->NextAsyncTaskId(promise);
|
||||
}
|
||||
return Handle<Smi>::cast(async_task_id)->value();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void Debug::RunPromiseHook(PromiseHookType hook_type, Handle<JSPromise> promise,
|
||||
Handle<Object> parent) {
|
||||
if (hook_type == PromiseHookType::kResolve) return;
|
||||
@ -1949,14 +1925,17 @@ void Debug::RunPromiseHook(PromiseHookType hook_type, Handle<JSPromise> promise,
|
||||
if (!debug_delegate_) return;
|
||||
PostponeInterruptsScope no_interrupts(isolate_);
|
||||
|
||||
int id = GetReferenceAsyncTaskId(isolate_, promise);
|
||||
if (hook_type == PromiseHookType::kBefore) {
|
||||
debug_delegate_->PromiseEventOccurred(debug::kDebugWillHandle, id, false);
|
||||
if (!promise->async_task_id()) return;
|
||||
debug_delegate_->AsyncEventOccurred(debug::kDebugWillHandle,
|
||||
promise->async_task_id(), false);
|
||||
} else if (hook_type == PromiseHookType::kAfter) {
|
||||
debug_delegate_->PromiseEventOccurred(debug::kDebugDidHandle, id, false);
|
||||
if (!promise->async_task_id()) return;
|
||||
debug_delegate_->AsyncEventOccurred(debug::kDebugDidHandle,
|
||||
promise->async_task_id(), false);
|
||||
} else {
|
||||
DCHECK(hook_type == PromiseHookType::kInit);
|
||||
debug::PromiseDebugActionType type = debug::kDebugPromiseThen;
|
||||
debug::DebugAsyncActionType type = debug::kDebugPromiseThen;
|
||||
bool last_frame_was_promise_builtin = false;
|
||||
JavaScriptFrameIterator it(isolate_);
|
||||
while (!it.done()) {
|
||||
@ -1967,18 +1946,15 @@ void Debug::RunPromiseHook(PromiseHookType hook_type, Handle<JSPromise> promise,
|
||||
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));
|
||||
if (last_frame_was_promise_builtin) {
|
||||
int id = NextAsyncTaskId(promise);
|
||||
debug_delegate_->AsyncEventOccurred(type, id, IsBlackboxed(info));
|
||||
}
|
||||
return;
|
||||
}
|
||||
last_frame_was_promise_builtin = false;
|
||||
if (info->HasBuiltinId()) {
|
||||
if (info->builtin_id() == Builtins::kAsyncFunctionPromiseCreate) {
|
||||
type = debug::kDebugAsyncFunctionPromiseCreated;
|
||||
last_frame_was_promise_builtin = true;
|
||||
} else if (info->builtin_id() == Builtins::kPromisePrototypeThen) {
|
||||
if (info->builtin_id() == Builtins::kPromisePrototypeThen) {
|
||||
type = debug::kDebugPromiseThen;
|
||||
last_frame_was_promise_builtin = true;
|
||||
} else if (info->builtin_id() == Builtins::kPromisePrototypeCatch) {
|
||||
@ -1995,19 +1971,11 @@ void Debug::RunPromiseHook(PromiseHookType hook_type, Handle<JSPromise> promise,
|
||||
}
|
||||
}
|
||||
|
||||
int Debug::NextAsyncTaskId(Handle<JSObject> promise) {
|
||||
LookupIterator it(promise, isolate_->factory()->promise_async_id_symbol());
|
||||
Maybe<bool> maybe = JSReceiver::HasProperty(&it);
|
||||
if (maybe.ToChecked()) {
|
||||
MaybeHandle<Object> result = Object::GetProperty(&it);
|
||||
return Handle<Smi>::cast(result.ToHandleChecked())->value();
|
||||
int Debug::NextAsyncTaskId(Handle<JSPromise> promise) {
|
||||
if (!promise->async_task_id()) {
|
||||
promise->set_async_task_id(++thread_local_.async_task_count_);
|
||||
}
|
||||
Handle<Smi> async_id =
|
||||
handle(Smi::FromInt(++thread_local_.async_task_count_), isolate_);
|
||||
Object::SetProperty(&it, async_id, LanguageMode::kSloppy,
|
||||
Object::MAY_BE_STORE_FROM_KEYED)
|
||||
.ToChecked();
|
||||
return async_id->value();
|
||||
return promise->async_task_id();
|
||||
}
|
||||
|
||||
namespace {
|
||||
@ -2494,8 +2462,8 @@ bool Debug::PerformSideEffectCheckForObject(Handle<Object> object) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void LegacyDebugDelegate::PromiseEventOccurred(
|
||||
v8::debug::PromiseDebugActionType type, int id, bool is_blackboxed) {
|
||||
void LegacyDebugDelegate::AsyncEventOccurred(
|
||||
v8::debug::DebugAsyncActionType type, int id, bool is_blackboxed) {
|
||||
DebugScope debug_scope(isolate_->debug());
|
||||
if (debug_scope.failed()) return;
|
||||
HandleScope scope(isolate_);
|
||||
|
@ -225,6 +225,9 @@ class Debug {
|
||||
void OnCompileError(Handle<Script> script);
|
||||
void OnAfterCompile(Handle<Script> script);
|
||||
|
||||
void OnAsyncFunctionStateChanged(Handle<JSPromise> promise,
|
||||
debug::DebugAsyncActionType);
|
||||
|
||||
V8_WARN_UNUSED_RESULT MaybeHandle<Object> Call(Handle<Object> fun,
|
||||
Handle<Object> data);
|
||||
Handle<Context> GetDebugContext();
|
||||
@ -279,7 +282,7 @@ class Debug {
|
||||
void RunPromiseHook(PromiseHookType hook_type, Handle<JSPromise> promise,
|
||||
Handle<Object> parent);
|
||||
|
||||
int NextAsyncTaskId(Handle<JSObject> promise);
|
||||
int NextAsyncTaskId(Handle<JSPromise> promise);
|
||||
|
||||
bool IsBlackboxed(Handle<SharedFunctionInfo> shared);
|
||||
|
||||
@ -459,7 +462,7 @@ class Debug {
|
||||
V8_WARN_UNUSED_RESULT MaybeHandle<Object> MakeCompileEvent(
|
||||
Handle<Script> script, v8::DebugEvent type);
|
||||
V8_WARN_UNUSED_RESULT MaybeHandle<Object> MakeAsyncTaskEvent(
|
||||
v8::debug::PromiseDebugActionType type, int id);
|
||||
v8::debug::DebugAsyncActionType type, int id);
|
||||
|
||||
void ProcessCompileEvent(v8::DebugEvent event, Handle<Script> script);
|
||||
void ProcessDebugEvent(v8::DebugEvent event, Handle<JSObject> event_data);
|
||||
@ -623,8 +626,8 @@ class Debug {
|
||||
class LegacyDebugDelegate : public v8::debug::DebugDelegate {
|
||||
public:
|
||||
explicit LegacyDebugDelegate(Isolate* isolate) : isolate_(isolate) {}
|
||||
void PromiseEventOccurred(v8::debug::PromiseDebugActionType type, int id,
|
||||
bool is_blackboxed) override;
|
||||
void AsyncEventOccurred(v8::debug::DebugAsyncActionType type, int id,
|
||||
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,
|
||||
|
@ -69,13 +69,14 @@ struct WasmDisassembly {
|
||||
OffsetTable offset_table;
|
||||
};
|
||||
|
||||
enum PromiseDebugActionType {
|
||||
kDebugAsyncFunctionPromiseCreated,
|
||||
enum DebugAsyncActionType {
|
||||
kDebugPromiseThen,
|
||||
kDebugPromiseCatch,
|
||||
kDebugPromiseFinally,
|
||||
kDebugWillHandle,
|
||||
kDebugDidHandle,
|
||||
kAsyncFunctionSuspended,
|
||||
kAsyncFunctionFinished
|
||||
};
|
||||
|
||||
enum BreakLocationType {
|
||||
|
@ -604,15 +604,12 @@ bool V8Debugger::IsFunctionBlackboxed(v8::Local<v8::debug::Script> script,
|
||||
return hasAgents && allBlackboxed;
|
||||
}
|
||||
|
||||
void V8Debugger::PromiseEventOccurred(v8::debug::PromiseDebugActionType type,
|
||||
int id, bool isBlackboxed) {
|
||||
void V8Debugger::AsyncEventOccurred(v8::debug::DebugAsyncActionType type,
|
||||
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);
|
||||
switch (type) {
|
||||
case v8::debug::kDebugAsyncFunctionPromiseCreated:
|
||||
asyncTaskScheduledForStack("async function", task, true);
|
||||
break;
|
||||
case v8::debug::kDebugPromiseThen:
|
||||
asyncTaskScheduledForStack("Promise.then", task, false);
|
||||
if (!isBlackboxed) asyncTaskCandidateForStepping(task, true);
|
||||
@ -633,6 +630,14 @@ void V8Debugger::PromiseEventOccurred(v8::debug::PromiseDebugActionType type,
|
||||
asyncTaskFinishedForStack(task);
|
||||
asyncTaskFinishedForStepping(task);
|
||||
break;
|
||||
case v8::debug::kAsyncFunctionSuspended:
|
||||
if (m_asyncTaskStacks.find(task) == m_asyncTaskStacks.end()) {
|
||||
asyncTaskScheduledForStack("async function", task, true);
|
||||
}
|
||||
break;
|
||||
case v8::debug::kAsyncFunctionFinished:
|
||||
asyncTaskCanceledForStack(task);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -170,8 +170,8 @@ class V8Debugger : public v8::debug::DebugDelegate {
|
||||
void asyncTaskCanceledForStepping(void* task);
|
||||
|
||||
// v8::debug::DebugEventListener implementation.
|
||||
void PromiseEventOccurred(v8::debug::PromiseDebugActionType type, int id,
|
||||
bool isBlackboxed) override;
|
||||
void AsyncEventOccurred(v8::debug::DebugAsyncActionType type, int id,
|
||||
bool isBlackboxed) override;
|
||||
void ScriptCompiled(v8::Local<v8::debug::Script> script, bool is_live_edited,
|
||||
bool has_compile_error) override;
|
||||
void BreakProgramRequested(
|
||||
|
@ -15984,6 +15984,14 @@ const char* JSPromise::Status(v8::Promise::PromiseState status) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
int JSPromise::async_task_id() const {
|
||||
return AsyncTaskIdField::decode(flags());
|
||||
}
|
||||
|
||||
void JSPromise::set_async_task_id(int id) {
|
||||
set_flags(AsyncTaskIdField::update(flags(), id));
|
||||
}
|
||||
|
||||
// static
|
||||
Handle<Object> JSPromise::Fulfill(Handle<JSPromise> promise,
|
||||
Handle<Object> value) {
|
||||
|
@ -45,6 +45,9 @@ class JSPromise : public JSObject {
|
||||
// block in an async function.
|
||||
DECL_BOOLEAN_ACCESSORS(handled_hint)
|
||||
|
||||
int async_task_id() const;
|
||||
void set_async_task_id(int id);
|
||||
|
||||
static const char* Status(Promise::PromiseState status);
|
||||
Promise::PromiseState status() const;
|
||||
void set_status(Promise::PromiseState status);
|
||||
@ -77,6 +80,7 @@ class JSPromise : public JSObject {
|
||||
static const int kStatusBits = 2;
|
||||
static const int kHasHandlerBit = 2;
|
||||
static const int kHandledHintBit = 3;
|
||||
class AsyncTaskIdField : public BitField<int, kHandledHintBit + 1, 22> {};
|
||||
|
||||
static const int kStatusShift = 0;
|
||||
static const int kStatusMask = 0x3;
|
||||
|
@ -407,6 +407,7 @@ class ParserBase {
|
||||
|
||||
void AddSuspend() { suspend_count_++; }
|
||||
int suspend_count() const { return suspend_count_; }
|
||||
bool CanSuspend() const { return suspend_count_ > 0; }
|
||||
|
||||
FunctionKind kind() const { return scope()->function_kind(); }
|
||||
|
||||
|
@ -2970,11 +2970,14 @@ Block* Parser::BuildRejectPromiseOnException(Block* inner_block) {
|
||||
// There is no TryCatchFinally node, so wrap it in an outer try/finally
|
||||
Block* outer_try_block = IgnoreCompletion(try_catch_statement);
|
||||
|
||||
// finally { %AsyncFunctionPromiseRelease(.promise) }
|
||||
// finally { %AsyncFunctionPromiseRelease(.promise, can_suspend) }
|
||||
Block* finally_block;
|
||||
{
|
||||
ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(1, zone());
|
||||
args->Add(factory()->NewVariableProxy(PromiseVariable()), zone());
|
||||
args->Add(factory()->NewBooleanLiteral(function_state_->CanSuspend(),
|
||||
kNoSourcePosition),
|
||||
zone());
|
||||
Expression* call_promise_release = factory()->NewCallRuntime(
|
||||
Context::ASYNC_FUNCTION_PROMISE_RELEASE_INDEX, args, kNoSourcePosition);
|
||||
Statement* promise_release = factory()->NewExpressionStatement(
|
||||
|
@ -1718,21 +1718,6 @@ RUNTIME_FUNCTION(Runtime_DebugPopPromise) {
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_DebugAsyncFunctionPromiseCreated) {
|
||||
DCHECK_EQ(1, args.length());
|
||||
HandleScope scope(isolate);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSObject, promise, 0);
|
||||
isolate->PushPromise(promise);
|
||||
int id = isolate->debug()->NextAsyncTaskId(promise);
|
||||
Handle<Symbol> async_stack_id_symbol =
|
||||
isolate->factory()->promise_async_stack_id_symbol();
|
||||
JSObject::SetProperty(promise, async_stack_id_symbol,
|
||||
handle(Smi::FromInt(id), isolate),
|
||||
LanguageMode::kStrict)
|
||||
.Assert();
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_DebugIsActive) {
|
||||
SealHandleScope shs(isolate);
|
||||
return Smi::FromInt(isolate->debug()->is_active());
|
||||
@ -1843,5 +1828,27 @@ RUNTIME_FUNCTION(Runtime_IncBlockCounter) {
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_DebugAsyncFunctionSuspended) {
|
||||
DCHECK_EQ(1, args.length());
|
||||
HandleScope scope(isolate);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0);
|
||||
isolate->debug()->OnAsyncFunctionStateChanged(promise,
|
||||
debug::kAsyncFunctionSuspended);
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_DebugAsyncFunctionFinished) {
|
||||
DCHECK_EQ(2, args.length());
|
||||
HandleScope scope(isolate);
|
||||
CONVERT_BOOLEAN_ARG_CHECKED(has_suspend, 0);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 1);
|
||||
isolate->PopPromise();
|
||||
if (has_suspend) {
|
||||
isolate->debug()->OnAsyncFunctionStateChanged(
|
||||
promise, debug::kAsyncFunctionFinished);
|
||||
}
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -112,6 +112,23 @@ RUNTIME_FUNCTION(Runtime_PromiseHookInit) {
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_AwaitPromisesInit) {
|
||||
DCHECK_EQ(3, args.length());
|
||||
HandleScope scope(isolate);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSPromise, wrapped_value, 0);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSPromise, outer_promise, 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSPromise, throwaway, 2);
|
||||
isolate->RunPromiseHook(PromiseHookType::kInit, wrapped_value, outer_promise);
|
||||
isolate->RunPromiseHook(PromiseHookType::kInit, throwaway, wrapped_value);
|
||||
// On inspector side we capture async stack trace and store it by
|
||||
// outer_promise->async_task_id when async function is suspended first time.
|
||||
// To use captured stack trace later throwaway promise should have the same
|
||||
// async_task_id as outer_promise since we generate WillHandle and DidHandle
|
||||
// events using throwaway promise.
|
||||
throwaway->set_async_task_id(outer_promise->async_task_id());
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_PromiseHookBefore) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_EQ(1, args.length());
|
||||
|
@ -132,7 +132,6 @@ namespace internal {
|
||||
F(ClearStepping, 0, 1) \
|
||||
F(CollectGarbage, 1, 1) \
|
||||
F(DebugApplyInstrumentation, 1, 1) \
|
||||
F(DebugAsyncFunctionPromiseCreated, 1, 1) \
|
||||
F(DebugBreakAtEntry, 1, 1) \
|
||||
F(DebugCollectCoverage, 0, 1) \
|
||||
F(DebugConstructedBy, 2, 1) \
|
||||
@ -150,6 +149,8 @@ namespace internal {
|
||||
F(DebugPropertyAttributesFromDetails, 1, 1) \
|
||||
F(DebugPropertyKindFromDetails, 1, 1) \
|
||||
F(DebugPushPromise, 1, 1) \
|
||||
F(DebugAsyncFunctionSuspended, 1, 1) \
|
||||
F(DebugAsyncFunctionFinished, 2, 1) \
|
||||
F(DebugReferencedBy, 3, 1) \
|
||||
F(DebugSetScriptSource, 2, 1) \
|
||||
F(DebugToggleBlockCoverage, 1, 1) \
|
||||
@ -426,6 +427,7 @@ namespace internal {
|
||||
F(PromiseHookAfter, 1, 1) \
|
||||
F(PromiseHookBefore, 1, 1) \
|
||||
F(PromiseHookInit, 2, 1) \
|
||||
F(AwaitPromisesInit, 3, 1) \
|
||||
F(PromiseMarkAsHandled, 1, 1) \
|
||||
F(PromiseRejectEventFromStack, 2, 1) \
|
||||
F(PromiseResult, 1, 1) \
|
||||
|
@ -16,7 +16,7 @@ snippet: "
|
||||
"
|
||||
frame size: 23
|
||||
parameter count: 1
|
||||
bytecode array length: 508
|
||||
bytecode array length: 514
|
||||
bytecodes: [
|
||||
B(SwitchOnGeneratorState), R(2), U8(0), U8(3),
|
||||
B(Mov), R(closure), R(12),
|
||||
@ -219,7 +219,10 @@ bytecodes: [
|
||||
B(LdaTheHole),
|
||||
B(SetPendingMessage),
|
||||
B(Star), R(14),
|
||||
B(CallJSRuntime), U8(%async_function_promise_release), R(11), U8(1),
|
||||
B(LdaTrue),
|
||||
B(Star), R(16),
|
||||
B(Mov), R(11), R(15),
|
||||
B(CallJSRuntime), U8(%async_function_promise_release), R(15), U8(2),
|
||||
B(Ldar), R(14),
|
||||
B(SetPendingMessage),
|
||||
B(Ldar), R(12),
|
||||
@ -266,7 +269,7 @@ snippet: "
|
||||
"
|
||||
frame size: 23
|
||||
parameter count: 1
|
||||
bytecode array length: 537
|
||||
bytecode array length: 543
|
||||
bytecodes: [
|
||||
B(SwitchOnGeneratorState), R(2), U8(0), U8(3),
|
||||
B(Mov), R(closure), R(12),
|
||||
@ -474,7 +477,10 @@ bytecodes: [
|
||||
B(LdaTheHole),
|
||||
B(SetPendingMessage),
|
||||
B(Star), R(14),
|
||||
B(CallJSRuntime), U8(%async_function_promise_release), R(11), U8(1),
|
||||
B(LdaTrue),
|
||||
B(Star), R(16),
|
||||
B(Mov), R(11), R(15),
|
||||
B(CallJSRuntime), U8(%async_function_promise_release), R(15), U8(2),
|
||||
B(Ldar), R(14),
|
||||
B(SetPendingMessage),
|
||||
B(Ldar), R(12),
|
||||
@ -532,7 +538,7 @@ snippet: "
|
||||
"
|
||||
frame size: 23
|
||||
parameter count: 1
|
||||
bytecode array length: 526
|
||||
bytecode array length: 532
|
||||
bytecodes: [
|
||||
B(SwitchOnGeneratorState), R(2), U8(0), U8(3),
|
||||
B(Mov), R(closure), R(12),
|
||||
@ -743,7 +749,10 @@ bytecodes: [
|
||||
B(LdaTheHole),
|
||||
B(SetPendingMessage),
|
||||
B(Star), R(14),
|
||||
B(CallJSRuntime), U8(%async_function_promise_release), R(11), U8(1),
|
||||
B(LdaTrue),
|
||||
B(Star), R(16),
|
||||
B(Mov), R(11), R(15),
|
||||
B(CallJSRuntime), U8(%async_function_promise_release), R(15), U8(2),
|
||||
B(Ldar), R(14),
|
||||
B(SetPendingMessage),
|
||||
B(Ldar), R(12),
|
||||
@ -791,7 +800,7 @@ snippet: "
|
||||
"
|
||||
frame size: 20
|
||||
parameter count: 1
|
||||
bytecode array length: 397
|
||||
bytecode array length: 403
|
||||
bytecodes: [
|
||||
/* 16 E> */ B(StackCheck),
|
||||
B(CallJSRuntime), U8(%async_function_promise_create), R(0), U8(0),
|
||||
@ -947,7 +956,10 @@ bytecodes: [
|
||||
B(LdaTheHole),
|
||||
B(SetPendingMessage),
|
||||
B(Star), R(12),
|
||||
B(CallJSRuntime), U8(%async_function_promise_release), R(9), U8(1),
|
||||
B(LdaFalse),
|
||||
B(Star), R(14),
|
||||
B(Mov), R(9), R(13),
|
||||
B(CallJSRuntime), U8(%async_function_promise_release), R(13), U8(2),
|
||||
B(Ldar), R(12),
|
||||
B(SetPendingMessage),
|
||||
B(Ldar), R(10),
|
||||
|
@ -926,7 +926,7 @@ snippet: "
|
||||
"
|
||||
frame size: 23
|
||||
parameter count: 2
|
||||
bytecode array length: 357
|
||||
bytecode array length: 363
|
||||
bytecodes: [
|
||||
/* 16 E> */ B(StackCheck),
|
||||
B(CallJSRuntime), U8(%async_function_promise_create), R(0), U8(0),
|
||||
@ -1074,7 +1074,10 @@ bytecodes: [
|
||||
B(LdaTheHole),
|
||||
B(SetPendingMessage),
|
||||
B(Star), R(15),
|
||||
B(CallJSRuntime), U8(%async_function_promise_release), R(12), U8(1),
|
||||
B(LdaFalse),
|
||||
B(Star), R(17),
|
||||
B(Mov), R(12), R(16),
|
||||
B(CallJSRuntime), U8(%async_function_promise_release), R(16), U8(2),
|
||||
B(Ldar), R(15),
|
||||
B(SetPendingMessage),
|
||||
B(Ldar), R(13),
|
||||
@ -1116,7 +1119,7 @@ snippet: "
|
||||
"
|
||||
frame size: 23
|
||||
parameter count: 2
|
||||
bytecode array length: 408
|
||||
bytecode array length: 414
|
||||
bytecodes: [
|
||||
B(SwitchOnGeneratorState), R(2), U8(0), U8(1),
|
||||
B(Mov), R(closure), R(12),
|
||||
@ -1282,7 +1285,10 @@ bytecodes: [
|
||||
B(LdaTheHole),
|
||||
B(SetPendingMessage),
|
||||
B(Star), R(14),
|
||||
B(CallJSRuntime), U8(%async_function_promise_release), R(11), U8(1),
|
||||
B(LdaTrue),
|
||||
B(Star), R(16),
|
||||
B(Mov), R(11), R(15),
|
||||
B(CallJSRuntime), U8(%async_function_promise_release), R(15), U8(2),
|
||||
B(Ldar), R(14),
|
||||
B(SetPendingMessage),
|
||||
B(Ldar), R(12),
|
||||
|
@ -381,7 +381,7 @@ snippet: "
|
||||
"
|
||||
frame size: 12
|
||||
parameter count: 1
|
||||
bytecode array length: 134
|
||||
bytecode array length: 140
|
||||
bytecodes: [
|
||||
/* 16 E> */ B(StackCheck),
|
||||
B(CallJSRuntime), U8(%async_function_promise_create), R(0), U8(0),
|
||||
@ -436,7 +436,10 @@ bytecodes: [
|
||||
B(LdaTheHole),
|
||||
B(SetPendingMessage),
|
||||
B(Star), R(6),
|
||||
B(CallJSRuntime), U8(%async_function_promise_release), R(3), U8(1),
|
||||
B(LdaFalse),
|
||||
B(Star), R(8),
|
||||
B(Mov), R(3), R(7),
|
||||
B(CallJSRuntime), U8(%async_function_promise_release), R(7), U8(2),
|
||||
B(Ldar), R(6),
|
||||
B(SetPendingMessage),
|
||||
B(Ldar), R(4),
|
||||
@ -468,7 +471,7 @@ snippet: "
|
||||
"
|
||||
frame size: 11
|
||||
parameter count: 1
|
||||
bytecode array length: 185
|
||||
bytecode array length: 191
|
||||
bytecodes: [
|
||||
B(SwitchOnGeneratorState), R(1), U8(0), U8(1),
|
||||
B(Mov), R(closure), R(3),
|
||||
@ -541,7 +544,10 @@ bytecodes: [
|
||||
B(LdaTheHole),
|
||||
B(SetPendingMessage),
|
||||
B(Star), R(5),
|
||||
B(CallJSRuntime), U8(%async_function_promise_release), R(2), U8(1),
|
||||
B(LdaTrue),
|
||||
B(Star), R(7),
|
||||
B(Mov), R(2), R(6),
|
||||
B(CallJSRuntime), U8(%async_function_promise_release), R(6), U8(2),
|
||||
B(Ldar), R(5),
|
||||
B(SetPendingMessage),
|
||||
B(Ldar), R(3),
|
||||
|
@ -1,58 +1,58 @@
|
||||
Checks that async chains for for-await-of are correct.
|
||||
|
||||
Running test: testBasic
|
||||
Debugger (test.js:12:2)
|
||||
Basic (test.js:50:4)
|
||||
Debugger (test.js:10:2)
|
||||
Basic (test.js:48:4)
|
||||
-- async function --
|
||||
Basic (test.js:48:20)
|
||||
Basic (test.js:47:19)
|
||||
(anonymous) (testBasic.js:0:0)
|
||||
|
||||
|
||||
Running test: testUncaughtReject
|
||||
Debugger (test.js:12:2)
|
||||
-- async function --
|
||||
UncaughtReject (test.js:54:29)
|
||||
Debugger (test.js:10:2)
|
||||
-- Promise.catch --
|
||||
UncaughtReject (test.js:58:21)
|
||||
(anonymous) (testUncaughtReject.js:0:0)
|
||||
|
||||
|
||||
Running test: testUncaughtThrow
|
||||
Debugger (test.js:12:2)
|
||||
-- async function --
|
||||
UncaughtThrow (test.js:63:28)
|
||||
Debugger (test.js:10:2)
|
||||
-- Promise.catch --
|
||||
UncaughtThrow (test.js:67:21)
|
||||
(anonymous) (testUncaughtThrow.js:0:0)
|
||||
|
||||
|
||||
Running test: testCaughtReject
|
||||
Debugger (test.js:12:2)
|
||||
CaughtReject (test.js:78:4)
|
||||
Debugger (test.js:10:2)
|
||||
CaughtReject (test.js:76:4)
|
||||
-- async function --
|
||||
CaughtReject (test.js:72:27)
|
||||
CaughtReject (test.js:72:21)
|
||||
(anonymous) (testCaughtReject.js:0:0)
|
||||
|
||||
|
||||
Running test: testCaughtThrow
|
||||
Debugger (test.js:12:2)
|
||||
CaughtThrow (test.js:88:4)
|
||||
Debugger (test.js:10:2)
|
||||
CaughtThrow (test.js:86:4)
|
||||
-- async function --
|
||||
CaughtThrow (test.js:82:26)
|
||||
CaughtThrow (test.js:82:21)
|
||||
(anonymous) (testCaughtThrow.js:0:0)
|
||||
|
||||
|
||||
Running test: testUncaughtRejectOnBreak
|
||||
|
||||
Running test: testUncaughtThrowOnBreak
|
||||
Debugger (test.js:12:2)
|
||||
-- async function --
|
||||
UncaughtThrowOnBreak (test.js:101:35)
|
||||
Debugger (test.js:10:2)
|
||||
-- Promise.catch --
|
||||
UncaughtThrowOnBreak (test.js:105:21)
|
||||
(anonymous) (testUncaughtThrowOnBreak.js:0:0)
|
||||
|
||||
|
||||
Running test: testCaughtRejectOnBreak
|
||||
|
||||
Running test: testCaughtThrowOnBreak
|
||||
Debugger (test.js:12:2)
|
||||
CaughtThrowOnBreak (test.js:126:4)
|
||||
Debugger (test.js:10:2)
|
||||
CaughtThrowOnBreak (test.js:124:4)
|
||||
-- async function --
|
||||
CaughtThrowOnBreak (test.js:120:33)
|
||||
CaughtThrowOnBreak (test.js:120:21)
|
||||
(anonymous) (testCaughtThrowOnBreak.js:0:0)
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
let {session, contextGroup, Protocol} = InspectorTest.start('Checks that async chains for for-await-of are correct.');
|
||||
|
||||
contextGroup.addScript(`
|
||||
contextGroup.addInlineScript(`
|
||||
|
||||
function Debugger(value) {
|
||||
debugger;
|
||||
@ -48,7 +48,7 @@ async function Basic() {
|
||||
Debugger();
|
||||
}
|
||||
}
|
||||
// TODO(kozyatinskiy): this stack trace is suspicious.
|
||||
|
||||
async function UncaughtReject() {
|
||||
async function loop() {
|
||||
for await (let x of [Reject(new Error("boop"))]) {
|
||||
@ -57,7 +57,7 @@ async function UncaughtReject() {
|
||||
}
|
||||
return loop().catch(Debugger);
|
||||
}
|
||||
// TODO(kozyatinskiy): this stack trace is suspicious.
|
||||
|
||||
async function UncaughtThrow() {
|
||||
async function loop() {
|
||||
for await (let x of [Throw(new Error("boop"))]) {
|
||||
@ -86,7 +86,7 @@ async function CaughtThrow() {
|
||||
Debugger(e);
|
||||
}
|
||||
}
|
||||
// TODO(kozyatinskiy): this stack trace is suspicious.
|
||||
|
||||
async function UncaughtRejectOnBreak() {
|
||||
async function loop() {
|
||||
for await (let x of RejectOnReturn(["0", "1"])) {
|
||||
@ -95,7 +95,7 @@ async function UncaughtRejectOnBreak() {
|
||||
}
|
||||
return loop().catch(Debugger);
|
||||
}
|
||||
// TODO(kozyatinskiy): this stack trace is suspicious.
|
||||
|
||||
async function UncaughtThrowOnBreak() {
|
||||
async function loop() {
|
||||
for await (let x of ThrowOnReturn(["0", "1"])) {
|
||||
@ -104,7 +104,7 @@ async function UncaughtThrowOnBreak() {
|
||||
}
|
||||
return loop().catch(Debugger);
|
||||
}
|
||||
// TODO(kozyatinskiy): this stack trace is suspicious.
|
||||
|
||||
async function CaughtRejectOnBreak() {
|
||||
try {
|
||||
for await (let x of RejectOnReturn(["0", "1"])) {
|
||||
@ -123,8 +123,7 @@ async function CaughtThrowOnBreak() {
|
||||
} catch (e) {
|
||||
Debugger(e);
|
||||
}
|
||||
}
|
||||
//# sourceURL=test.js`, 9, 26);
|
||||
}`, 'test.js');
|
||||
|
||||
session.setupScriptMap();
|
||||
Protocol.Debugger.onPaused(message => {
|
||||
|
25
test/inspector/debugger/async-function-step-out-expected.txt
Normal file
25
test/inspector/debugger/async-function-step-out-expected.txt
Normal file
@ -0,0 +1,25 @@
|
||||
stepOut async function
|
||||
bar (test.js:22:2)
|
||||
-- async function --
|
||||
bar (test.js:21:16)
|
||||
foo (test.js:17:8)
|
||||
-- async function --
|
||||
foo (test.js:16:16)
|
||||
test (test.js:12:8)
|
||||
-- async function --
|
||||
test (test.js:11:16)
|
||||
(anonymous) (:0:0)
|
||||
|
||||
foo (test.js:18:0)
|
||||
-- async function --
|
||||
foo (test.js:16:16)
|
||||
test (test.js:12:8)
|
||||
-- async function --
|
||||
test (test.js:11:16)
|
||||
(anonymous) (:0:0)
|
||||
|
||||
test (test.js:13:0)
|
||||
-- async function --
|
||||
test (test.js:11:16)
|
||||
(anonymous) (:0:0)
|
||||
|
50
test/inspector/debugger/async-function-step-out.js
Normal file
50
test/inspector/debugger/async-function-step-out.js
Normal file
@ -0,0 +1,50 @@
|
||||
// Copyright 2018 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.
|
||||
|
||||
let {session, contextGroup, Protocol} =
|
||||
InspectorTest.start('stepOut async function');
|
||||
|
||||
session.setupScriptMap();
|
||||
contextGroup.addInlineScript(`
|
||||
async function test() {
|
||||
await Promise.resolve();
|
||||
await foo();
|
||||
}
|
||||
|
||||
async function foo() {
|
||||
await Promise.resolve();
|
||||
await bar();
|
||||
}
|
||||
|
||||
async function bar() {
|
||||
await Promise.resolve();
|
||||
debugger;
|
||||
}
|
||||
`, 'test.js');
|
||||
|
||||
(async function test() {
|
||||
Protocol.Runtime.enable();
|
||||
Protocol.Runtime.onConsoleAPICalled(
|
||||
msg => InspectorTest.log(msg.params.args[0].value));
|
||||
Protocol.Debugger.enable();
|
||||
Protocol.Debugger.setAsyncCallStackDepth({maxDepth: 128});
|
||||
let finished =
|
||||
Protocol.Runtime.evaluate({expression: 'test()', awaitPromise: true})
|
||||
.then(() => false);
|
||||
while (true) {
|
||||
const r = await Promise.race([finished, waitPauseAndDumpStack()]);
|
||||
if (!r) break;
|
||||
Protocol.Debugger.stepOut();
|
||||
}
|
||||
InspectorTest.completeTest();
|
||||
})()
|
||||
|
||||
async function
|
||||
waitPauseAndDumpStack() {
|
||||
const {params} = await Protocol.Debugger.oncePaused();
|
||||
session.logCallFrames(params.callFrames);
|
||||
session.logAsyncStackTrace(params.asyncStackTrace);
|
||||
InspectorTest.log('');
|
||||
return true;
|
||||
}
|
@ -1,20 +1,20 @@
|
||||
Checks that async stacks works for async/await
|
||||
foo2 (test.js:15:2)
|
||||
-- async function --
|
||||
foo2 (test.js:13:19)
|
||||
foo2 (test.js:14:16)
|
||||
test (test.js:24:8)
|
||||
(anonymous) (expr.js:0:0)
|
||||
|
||||
foo2 (test.js:17:2)
|
||||
-- async function --
|
||||
foo2 (test.js:13:19)
|
||||
foo2 (test.js:14:16)
|
||||
test (test.js:24:8)
|
||||
(anonymous) (expr.js:0:0)
|
||||
|
||||
foo1 (test.js:9:2)
|
||||
foo2 (test.js:18:8)
|
||||
-- async function --
|
||||
foo2 (test.js:13:19)
|
||||
foo2 (test.js:14:16)
|
||||
test (test.js:24:8)
|
||||
(anonymous) (expr.js:0:0)
|
||||
|
||||
@ -22,13 +22,13 @@ foo1 (test.js:9:2)
|
||||
-- Promise.then --
|
||||
foo2 (test.js:19:43)
|
||||
-- async function --
|
||||
foo2 (test.js:13:19)
|
||||
foo2 (test.js:14:16)
|
||||
test (test.js:24:8)
|
||||
(anonymous) (expr.js:0:0)
|
||||
|
||||
foo2 (test.js:20:2)
|
||||
-- async function --
|
||||
foo2 (test.js:13:19)
|
||||
foo2 (test.js:14:16)
|
||||
test (test.js:24:8)
|
||||
(anonymous) (expr.js:0:0)
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
let {session, contextGroup, Protocol} = InspectorTest.start('Checks that async stacks works for async/await');
|
||||
|
||||
contextGroup.addScript(`
|
||||
contextGroup.addInlineScript(`
|
||||
async function foo1() {
|
||||
debugger;
|
||||
return Promise.resolve();
|
||||
@ -22,8 +22,7 @@ async function foo2() {
|
||||
|
||||
async function test() {
|
||||
await foo2();
|
||||
}
|
||||
//# sourceURL=test.js`, 7, 26);
|
||||
}`, 'test.js');
|
||||
|
||||
session.setupScriptMap();
|
||||
Protocol.Debugger.onPaused(message => {
|
||||
|
@ -8,7 +8,7 @@ asyncFact (test.js:9:2)
|
||||
|
||||
asyncFact (test.js:11:2)
|
||||
-- async function --
|
||||
asyncFact (test.js:8:24)
|
||||
asyncFact (test.js:10:20)
|
||||
asyncFact (test.js:10:20)
|
||||
asyncFact (test.js:10:20)
|
||||
asyncFact (test.js:10:20)
|
||||
@ -23,7 +23,7 @@ asyncFact (test.js:9:2)
|
||||
|
||||
asyncFact (test.js:11:2)
|
||||
-- async function --
|
||||
asyncFact (test.js:8:24)
|
||||
asyncFact (test.js:10:20)
|
||||
(anonymous) (expr.js:0:0)
|
||||
|
||||
|
||||
|
@ -120,6 +120,12 @@ InspectorTest.ContextGroup = class {
|
||||
utils.compileAndRunWithOrigin(this.id, string, url || '', lineOffset || 0, columnOffset || 0, false);
|
||||
}
|
||||
|
||||
addInlineScript(string, url) {
|
||||
const match = (new Error().stack).split('\n')[2].match(/([0-9]+):([0-9]+)/);
|
||||
this.addScript(
|
||||
string, match[1] * 1, match[1] * 1 + '.addInlineScript('.length, url);
|
||||
}
|
||||
|
||||
addModule(string, url, lineOffset, columnOffset) {
|
||||
utils.compileAndRunWithOrigin(this.id, string, url, lineOffset || 0, columnOffset || 0, true);
|
||||
}
|
||||
@ -213,7 +219,8 @@ InspectorTest.Session = class {
|
||||
logCallFrames(callFrames) {
|
||||
for (var frame of callFrames) {
|
||||
var functionName = frame.functionName || '(anonymous)';
|
||||
var url = frame.url ? frame.url : this._scriptMap.get(frame.location.scriptId).url;
|
||||
var scriptId = frame.location ? frame.location.scriptId : frame.scriptId;
|
||||
var url = frame.url ? frame.url : this._scriptMap.get(scriptId).url;
|
||||
var lineNumber = frame.location ? frame.location.lineNumber : frame.lineNumber;
|
||||
var columnNumber = frame.location ? frame.location.columnNumber : frame.columnNumber;
|
||||
InspectorTest.log(`${functionName} (${url}:${lineNumber}:${columnNumber})`);
|
||||
|
Loading…
Reference in New Issue
Block a user