Commit 73ac1d38 authored by kozyatinskiy's avatar kozyatinskiy Committed by Commit bot

[inspector] add async instrumentation for setTimeout in tests

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

Review-Url: https://codereview.chromium.org/2574803002
Cr-Commit-Position: refs/heads/master@{#41680}
parent c22c70b6
Checks that async stack contains setTimeout
inner1 (test.js:11:4)
foo1 (test.js:14:2)
-- setTimeout --
inner2 (test.js:18:4)
foo2 (test.js:20:2)
-- setTimeout --
inner3 (test.js:25:4)
foo3 (test.js:27:2)
(anonymous) (expr.js:0:0)
// Copyright 2016 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 that async stack contains setTimeout');
InspectorTest.addScript(`
var resolveCallback;
function foo1() {
function inner1() {
debugger;
resolveCallback();
}
inner1();
}
function foo2() {
function inner2() {
setTimeout(foo1, 0);
}
inner2();
}
function foo3() {
var promise = new Promise(resolve => resolveCallback = resolve);
function inner3() {
setTimeout(foo2, 0);
}
inner3();
return promise;
}
//# sourceURL=test.js`, 7, 26);
InspectorTest.setupScriptMap();
Protocol.Debugger.onPaused(message => {
InspectorTest.logCallFrames(message.params.callFrames);
var asyncStackTrace = message.params.asyncStackTrace;
while (asyncStackTrace) {
InspectorTest.log(`-- ${asyncStackTrace.description} --`);
InspectorTest.logCallFrames(asyncStackTrace.callFrames);
asyncStackTrace = asyncStackTrace.parent;
}
InspectorTest.log('');
Protocol.Debugger.resume();
});
Protocol.Debugger.enable();
Protocol.Debugger.setAsyncCallStackDepth({ maxDepth: 128 });
Protocol.Runtime.evaluate({ expression: "foo3()//# sourceURL=expr.js", awaitPromise: true })
.then(InspectorTest.completeTest);
......@@ -177,22 +177,23 @@ class UtilsExtension : public v8::Extension {
backend_runner_->Append(new ExecuteStringTask(
ToVector(args[0].As<v8::String>()), args[1].As<v8::String>(),
args[2].As<v8::Int32>(), args[3].As<v8::Int32>()));
args[2].As<v8::Int32>(), args[3].As<v8::Int32>(), nullptr, nullptr));
}
};
TaskRunner* UtilsExtension::backend_runner_ = nullptr;
class SetTimeoutTask : public TaskRunner::Task {
class SetTimeoutTask : public AsyncTask {
public:
SetTimeoutTask(v8::Isolate* isolate, v8::Local<v8::Function> function)
: function_(isolate, function) {}
SetTimeoutTask(v8::Isolate* isolate, v8::Local<v8::Function> function,
const char* task_name, v8_inspector::V8Inspector* inspector)
: AsyncTask(task_name, inspector), function_(isolate, function) {}
virtual ~SetTimeoutTask() {}
bool is_inspector_task() final { return false; }
void Run(v8::Isolate* isolate,
const v8::Global<v8::Context>& global_context) override {
void AsyncRun(v8::Isolate* isolate,
const v8::Global<v8::Context>& global_context) override {
v8::MicrotasksScope microtasks_scope(isolate,
v8::MicrotasksScope::kRunMicrotasks);
v8::HandleScope handle_scope(isolate);
......@@ -234,14 +235,20 @@ class SetTimeoutExtension : public v8::Extension {
}
v8::Isolate* isolate = args.GetIsolate();
v8::Local<v8::Context> context = isolate->GetCurrentContext();
std::unique_ptr<TaskRunner::Task> task;
v8_inspector::V8Inspector* inspector =
InspectorClientImpl::InspectorFromContext(context);
if (args[0]->IsFunction()) {
TaskRunner::FromContext(context)->Append(
new SetTimeoutTask(isolate, v8::Local<v8::Function>::Cast(args[0])));
task.reset(new SetTimeoutTask(isolate,
v8::Local<v8::Function>::Cast(args[0]),
"setTimeout", inspector));
} else {
TaskRunner::FromContext(context)->Append(new ExecuteStringTask(
task.reset(new ExecuteStringTask(
ToVector(args[0].As<v8::String>()), v8::String::Empty(isolate),
v8::Integer::New(isolate, 0), v8::Integer::New(isolate, 0)));
v8::Integer::New(isolate, 0), v8::Integer::New(isolate, 0),
"setTimeout", inspector));
}
TaskRunner::FromContext(context)->Append(task.release());
}
};
......@@ -334,9 +341,10 @@ class FrontendChannelImpl : public InspectorClientImpl::FrontendChannel {
v8::Local<v8::String> result = v8::String::Concat(prefix, message_string);
result = v8::String::Concat(result, suffix);
frontend_task_runner_->Append(new ExecuteStringTask(
ToVector(result), v8::String::Empty(isolate),
v8::Integer::New(isolate, 0), v8::Integer::New(isolate, 0)));
frontend_task_runner_->Append(
new ExecuteStringTask(ToVector(result), v8::String::Empty(isolate),
v8::Integer::New(isolate, 0),
v8::Integer::New(isolate, 0), nullptr, nullptr));
}
private:
......
......@@ -101,6 +101,17 @@ InspectorTest.logObject = function(object, title)
InspectorTest.log(lines.join("\n"));
}
InspectorTest.logCallFrames = function(callFrames)
{
for (var frame of callFrames) {
var functionName = frame.functionName || '(anonymous)';
var url = frame.url ? frame.url : InspectorTest._scriptMap.get(frame.location.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})`);
}
}
InspectorTest.completeTest = function()
{
Protocol.Debugger.disable().then(() => quit());
......@@ -113,7 +124,7 @@ InspectorTest.completeTestAfterPendingTimeouts = function()
awaitPromise: true }).then(InspectorTest.completeTest);
}
InspectorTest.addScript = (string) => compileAndRunWithOrigin(string, "", 0, 0);
InspectorTest.addScript = (string, lineOffset, columnOffset) => compileAndRunWithOrigin(string, "", lineOffset || 0, columnOffset || 0);
InspectorTest.addScriptWithUrl = (string, url) => compileAndRunWithOrigin(string, url, 0, 0);
InspectorTest.startDumpingProtocolMessages = function()
......@@ -143,6 +154,12 @@ InspectorTest.checkExpectation = function(fail, name, messageObject)
InspectorTest.expectedSuccess = InspectorTest.checkExpectation.bind(null, false);
InspectorTest.expectedError = InspectorTest.checkExpectation.bind(null, true);
InspectorTest.setupScriptMap = function() {
if (InspectorTest._scriptMap)
return;
InspectorTest._scriptMap = new Map();
}
InspectorTest.runTestSuite = function(testSuite)
{
function nextTest()
......@@ -194,6 +211,8 @@ InspectorTest._dispatchMessage = function(messageObject)
} else {
var eventName = messageObject["method"];
var eventHandler = InspectorTest._eventHandler[eventName];
if (InspectorTest._scriptMap && eventName === "Debugger.scriptParsed")
InspectorTest._scriptMap.set(messageObject.params.scriptId, JSON.parse(JSON.stringify(messageObject.params)));
if (eventHandler)
eventHandler(messageObject);
}
......
......@@ -4,6 +4,8 @@
#include "test/inspector/task-runner.h"
#include "test/inspector/inspector-impl.h"
#if !defined(_WIN32) && !defined(_WIN64)
#include <unistd.h> // NOLINT
#endif // !defined(_WIN32) && !defined(_WIN64)
......@@ -134,21 +136,44 @@ v8::internal::Vector<uint16_t> ToVector(v8::Local<v8::String> str) {
} // namespace
AsyncTask::AsyncTask(const char* task_name,
v8_inspector::V8Inspector* inspector)
: inspector_(task_name ? inspector : nullptr) {
if (inspector_) {
inspector_->asyncTaskScheduled(
v8_inspector::StringView(reinterpret_cast<const uint8_t*>(task_name),
strlen(task_name)),
this, false);
}
}
void AsyncTask::Run(v8::Isolate* isolate,
const v8::Global<v8::Context>& context) {
if (inspector_) inspector_->asyncTaskStarted(this);
AsyncRun(isolate, context);
if (inspector_) inspector_->asyncTaskFinished(this);
}
ExecuteStringTask::ExecuteStringTask(
const v8::internal::Vector<uint16_t>& expression,
v8::Local<v8::String> name, v8::Local<v8::Integer> line_offset,
v8::Local<v8::Integer> column_offset)
: expression_(expression),
v8::Local<v8::Integer> column_offset, const char* task_name,
v8_inspector::V8Inspector* inspector)
: AsyncTask(task_name, inspector),
expression_(expression),
name_(ToVector(name)),
line_offset_(line_offset.As<v8::Int32>()->Value()),
column_offset_(column_offset.As<v8::Int32>()->Value()) {}
ExecuteStringTask::ExecuteStringTask(
const v8::internal::Vector<const char>& expression)
: expression_utf8_(expression), line_offset_(0), column_offset_(0) {}
: AsyncTask(nullptr, nullptr),
expression_utf8_(expression),
line_offset_(0),
column_offset_(0) {}
void ExecuteStringTask::Run(v8::Isolate* isolate,
const v8::Global<v8::Context>& context) {
void ExecuteStringTask::AsyncRun(v8::Isolate* isolate,
const v8::Global<v8::Context>& context) {
v8::MicrotasksScope microtasks_scope(isolate,
v8::MicrotasksScope::kRunMicrotasks);
v8::HandleScope handle_scope(isolate);
......
......@@ -67,18 +67,33 @@ class TaskRunner : public v8::base::Thread {
DISALLOW_COPY_AND_ASSIGN(TaskRunner);
};
class ExecuteStringTask : public TaskRunner::Task {
class AsyncTask : public TaskRunner::Task {
public:
AsyncTask(const char* task_name, v8_inspector::V8Inspector* inspector);
virtual ~AsyncTask() = default;
void Run(v8::Isolate* isolate,
const v8::Global<v8::Context>& context) override;
virtual void AsyncRun(v8::Isolate* isolate,
const v8::Global<v8::Context>& context) = 0;
private:
v8_inspector::V8Inspector* inspector_;
};
class ExecuteStringTask : public AsyncTask {
public:
ExecuteStringTask(const v8::internal::Vector<uint16_t>& expression,
v8::Local<v8::String> name,
v8::Local<v8::Integer> line_offset,
v8::Local<v8::Integer> column_offset);
v8::Local<v8::Integer> column_offset, const char* task_name,
v8_inspector::V8Inspector* inspector);
explicit ExecuteStringTask(
const v8::internal::Vector<const char>& expression);
bool is_inspector_task() override { return false; }
void Run(v8::Isolate* isolate,
const v8::Global<v8::Context>& context) override;
void AsyncRun(v8::Isolate* isolate,
const v8::Global<v8::Context>& context) override;
private:
v8::internal::Vector<uint16_t> expression_;
......
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