[inspector] Refactor inspector test
- moved all extensions to inspector_test.cc; - properly supported multiple context groups and sessions; - better isolation between components; - better infrastructure in protocol-test. BUG=chromium:590878 Review-Url: https://codereview.chromium.org/2890463004 Cr-Commit-Position: refs/heads/master@{#45409}
This commit is contained in:
parent
c9756be93b
commit
55849b167c
@ -10,11 +10,11 @@ const expression = `
|
||||
delete Object.prototype.RemoteObject;
|
||||
this.RemoteObject = v;
|
||||
|
||||
inspector.detachInspector();
|
||||
inspector.fireContextDestroyed();
|
||||
setTimeout(function() {
|
||||
// Attach the inspector again for the sake of establishing a
|
||||
// communication channel with the frontend test runner.
|
||||
inspector.attachInspector();
|
||||
inspector.fireContextCreated();
|
||||
console.log("End of test");
|
||||
}, 0);
|
||||
},
|
||||
@ -23,8 +23,8 @@ const expression = `
|
||||
// Before the whole script runs, the inspector is already attached.
|
||||
// Re-attach the inspector and trigger the console API to make sure that the
|
||||
// injected inspector script runs again (and triggers the above setter).
|
||||
inspector.detachInspector();
|
||||
inspector.attachInspector();
|
||||
inspector.fireContextDestroyed();
|
||||
inspector.fireContextCreated();
|
||||
console.log("First inspector activity after attaching inspector");
|
||||
console.log("End of test");
|
||||
`;
|
||||
|
@ -8,6 +8,6 @@ InspectorTest.log('Check destroying agent inside of breakProgram');
|
||||
await Protocol.Debugger.enable();
|
||||
Protocol.Runtime.evaluate({expression: 'inspector.breakProgram(\'\', \'{}\')'});
|
||||
await Protocol.Debugger.oncePaused();
|
||||
utils.disconnect();
|
||||
InspectorTest.session.disconnect();
|
||||
utils.quit();
|
||||
})();
|
||||
|
@ -188,16 +188,16 @@ InspectorTest.runTestSuite([
|
||||
},
|
||||
|
||||
function testAsyncDOMBreakpoint(next) {
|
||||
utils.schedulePauseOnNextStatement('', '');
|
||||
InspectorTest.contextGroup.schedulePauseOnNextStatement('', '');
|
||||
InspectorTest.log('> all frames in framework:');
|
||||
Protocol.Runtime
|
||||
.evaluate(
|
||||
{expression: 'asyncDOMBreakpoint()//# sourceURL=framework.js'})
|
||||
.then(() => utils.cancelPauseOnNextStatement())
|
||||
.then(() => InspectorTest.contextGroup.cancelPauseOnNextStatement())
|
||||
.then(
|
||||
() => Protocol.Runtime.evaluate(
|
||||
{expression: '42//# sourceURL=user.js'}))
|
||||
.then(() => utils.schedulePauseOnNextStatement('', ''))
|
||||
.then(() => InspectorTest.contextGroup.schedulePauseOnNextStatement('', ''))
|
||||
.then(
|
||||
() => Protocol.Runtime.evaluate(
|
||||
{expression: 'asyncDOMBreakpoint()//# sourceURL=user.js'}))
|
||||
|
@ -64,7 +64,7 @@ var testSuite = [
|
||||
];
|
||||
|
||||
function testPositions(positions) {
|
||||
utils.schedulePauseOnNextStatement('', '');
|
||||
InspectorTest.contextGroup.schedulePauseOnNextStatement('', '');
|
||||
return Protocol.Debugger
|
||||
.setBlackboxedRanges({scriptId: scriptId, positions: positions})
|
||||
.then(InspectorTest.logMessage)
|
||||
|
@ -47,7 +47,7 @@ Protocol.Debugger.enable()
|
||||
|
||||
var testSuite = [
|
||||
function testStepIntoFromUser(next) {
|
||||
utils.schedulePauseOnNextStatement('', '');
|
||||
InspectorTest.contextGroup.schedulePauseOnNextStatement('', '');
|
||||
test('testStepFromUser()', [
|
||||
'print', // before testStepFromUser call
|
||||
'stepInto', 'stepInto', 'print', // userFoo
|
||||
@ -57,7 +57,7 @@ var testSuite = [
|
||||
},
|
||||
|
||||
function testStepOverFromUser(next) {
|
||||
utils.schedulePauseOnNextStatement('', '');
|
||||
InspectorTest.contextGroup.schedulePauseOnNextStatement('', '');
|
||||
test('testStepFromUser()', [
|
||||
'print', // before testStepFromUser call
|
||||
'stepInto', 'stepInto', 'print', // userFoo
|
||||
@ -67,7 +67,7 @@ var testSuite = [
|
||||
},
|
||||
|
||||
function testStepOutFromUser(next) {
|
||||
utils.schedulePauseOnNextStatement('', '');
|
||||
InspectorTest.contextGroup.schedulePauseOnNextStatement('', '');
|
||||
test('testStepFromUser()', [
|
||||
'print', // before testStepFromUser call
|
||||
'stepInto', 'stepInto', 'print', // userFoo
|
||||
|
@ -153,7 +153,7 @@ function foo6() { Promise.resolve().then(() => 42) }`;
|
||||
function compileScript(source, origin) {
|
||||
var promise = Protocol.Debugger.onceScriptParsed().then(message => message.params.scriptId);
|
||||
if (!origin) origin = { name: '', line_offset: 0, column_offset: 0 };
|
||||
utils.compileAndRunWithOrigin(source, origin.name, origin.line_offset, origin.column_offset, false);
|
||||
InspectorTest.addScript(source, origin.line_offset, origin.column_offset, origin.name);
|
||||
return promise;
|
||||
}
|
||||
|
||||
|
@ -33,17 +33,17 @@ InspectorTest.runTestSuite([
|
||||
},
|
||||
|
||||
function testSchedulePauseOnNextStatement(next) {
|
||||
utils.schedulePauseOnNextStatement('reason', JSON.stringify({a: 42}));
|
||||
InspectorTest.contextGroup.schedulePauseOnNextStatement('reason', JSON.stringify({a: 42}));
|
||||
Protocol.Runtime.evaluate({ expression: 'foo()//# sourceURL=expr1.js'})
|
||||
.then(() => Protocol.Runtime.evaluate({
|
||||
expression: 'foo()//# sourceURL=expr2.js'}))
|
||||
.then(() => utils.cancelPauseOnNextStatement())
|
||||
.then(() => InspectorTest.contextGroup.cancelPauseOnNextStatement())
|
||||
.then(next);
|
||||
},
|
||||
|
||||
function testCancelPauseOnNextStatement(next) {
|
||||
utils.schedulePauseOnNextStatement('reason', JSON.stringify({a: 42}));
|
||||
utils.cancelPauseOnNextStatement();
|
||||
InspectorTest.contextGroup.schedulePauseOnNextStatement('reason', JSON.stringify({a: 42}));
|
||||
InspectorTest.contextGroup.cancelPauseOnNextStatement();
|
||||
Protocol.Runtime.evaluate({ expression: 'foo()'})
|
||||
.then(next);
|
||||
}
|
||||
|
@ -24,50 +24,53 @@ InspectorTest.runAsyncTestSuite([
|
||||
},
|
||||
|
||||
async function testSkipOtherContext1() {
|
||||
let contextGroupId = utils.createContextGroup();
|
||||
Protocol.Debugger.enable({}, contextGroupId);
|
||||
let contextGroup = InspectorTest.createContextGroup();
|
||||
let session = InspectorTest.createSession(contextGroup);
|
||||
session.Protocol.Debugger.enable({});
|
||||
Protocol.Debugger.pause();
|
||||
Protocol.Runtime.evaluate({expression: 'var a = 42; //# sourceURL=framework.js'});
|
||||
Protocol.Runtime.evaluate({expression: 'var a = 239;'}, contextGroupId);
|
||||
session.Protocol.Runtime.evaluate({expression: 'var a = 239;'});
|
||||
Protocol.Runtime.evaluate({expression: 'var a = 1;'});
|
||||
await waitPauseAndDumpLocation();
|
||||
await Protocol.Debugger.resume();
|
||||
await Protocol.Debugger.disable({}, contextGroupId);
|
||||
await session.Protocol.Debugger.disable({});
|
||||
},
|
||||
|
||||
async function testSkipOtherContext2() {
|
||||
let contextGroupId = utils.createContextGroup();
|
||||
Protocol.Debugger.enable({}, contextGroupId);
|
||||
Protocol.Debugger.pause({}, contextGroupId);
|
||||
let contextGroup = InspectorTest.createContextGroup();
|
||||
let session = InspectorTest.createSession(contextGroup);
|
||||
InspectorTest.setupScriptMap(session);
|
||||
session.Protocol.Debugger.enable({});
|
||||
session.Protocol.Debugger.pause({});
|
||||
Protocol.Runtime.evaluate({expression: 'var a = 42; //# sourceURL=framework.js'});
|
||||
Protocol.Runtime.evaluate({expression: 'var a = 239;'}, contextGroupId);
|
||||
session.Protocol.Runtime.evaluate({expression: 'var a = 239;'});
|
||||
Protocol.Runtime.evaluate({expression: 'var a = 1;'});
|
||||
await waitPauseAndDumpLocation();
|
||||
await waitPauseAndDumpLocation(session);
|
||||
// should not resume pause from different context group id.
|
||||
Protocol.Debugger.resume();
|
||||
Protocol.Debugger.stepOver({}, contextGroupId);
|
||||
await waitPauseAndDumpLocation();
|
||||
await Protocol.Debugger.resume({}, contextGroupId);
|
||||
await Protocol.Debugger.disable({}, contextGroupId);
|
||||
session.Protocol.Debugger.stepOver({});
|
||||
await waitPauseAndDumpLocation(session);
|
||||
await session.Protocol.Debugger.resume({});
|
||||
await session.Protocol.Debugger.disable({});
|
||||
},
|
||||
|
||||
async function testWithNativeBreakpoint() {
|
||||
utils.schedulePauseOnNextStatement('', '');
|
||||
InspectorTest.contextGroup.schedulePauseOnNextStatement('', '');
|
||||
await Protocol.Debugger.pause();
|
||||
utils.cancelPauseOnNextStatement();
|
||||
InspectorTest.contextGroup.cancelPauseOnNextStatement();
|
||||
Protocol.Runtime.evaluate({expression: 'var a = 42;'});
|
||||
await waitPauseAndDumpLocation();
|
||||
await Protocol.Debugger.resume();
|
||||
|
||||
await Protocol.Debugger.pause();
|
||||
utils.schedulePauseOnNextStatement('', '');
|
||||
utils.cancelPauseOnNextStatement();
|
||||
InspectorTest.contextGroup.schedulePauseOnNextStatement('', '');
|
||||
InspectorTest.contextGroup.cancelPauseOnNextStatement();
|
||||
Protocol.Runtime.evaluate({expression: 'var a = 42;'});
|
||||
await waitPauseAndDumpLocation();
|
||||
await Protocol.Debugger.resume();
|
||||
|
||||
utils.schedulePauseOnNextStatement('', '');
|
||||
utils.cancelPauseOnNextStatement();
|
||||
InspectorTest.contextGroup.schedulePauseOnNextStatement('', '');
|
||||
InspectorTest.contextGroup.cancelPauseOnNextStatement();
|
||||
await Protocol.Debugger.pause();
|
||||
Protocol.Runtime.evaluate({expression: 'var a = 42;'});
|
||||
await waitPauseAndDumpLocation();
|
||||
@ -85,9 +88,10 @@ InspectorTest.runAsyncTestSuite([
|
||||
}
|
||||
]);
|
||||
|
||||
async function waitPauseAndDumpLocation() {
|
||||
var message = await Protocol.Debugger.oncePaused();
|
||||
async function waitPauseAndDumpLocation(session) {
|
||||
session = session || InspectorTest.session;
|
||||
var message = await session.Protocol.Debugger.oncePaused();
|
||||
InspectorTest.log('paused at:');
|
||||
await InspectorTest.logSourceLocation(message.params.callFrames[0].location);
|
||||
await InspectorTest.logSourceLocation(message.params.callFrames[0].location, session);
|
||||
return message;
|
||||
}
|
||||
|
@ -7,24 +7,26 @@ InspectorTest.log('Checks stepping with more then one context group.');
|
||||
(async function test() {
|
||||
InspectorTest.setupScriptMap();
|
||||
await Protocol.Debugger.enable();
|
||||
let contextGroupId = utils.createContextGroup();
|
||||
await Protocol.Debugger.enable({}, contextGroupId);
|
||||
let contextGroup = InspectorTest.createContextGroup();
|
||||
let session = InspectorTest.createSession(contextGroup);
|
||||
InspectorTest.setupScriptMap(session);
|
||||
await session.Protocol.Debugger.enable({});
|
||||
Protocol.Runtime.evaluate({expression: 'debugger'});
|
||||
Protocol.Runtime.evaluate({expression: 'setTimeout(() => { debugger }, 0)'}, contextGroupId);
|
||||
session.Protocol.Runtime.evaluate({expression: 'setTimeout(() => { debugger }, 0)'});
|
||||
Protocol.Runtime.evaluate({expression: 'setTimeout(() => 42, 0)'});
|
||||
await waitPauseAndDumpLocation();
|
||||
await waitPauseAndDumpLocation(InspectorTest.session);
|
||||
Protocol.Debugger.stepOver();
|
||||
await Protocol.Debugger.oncePaused();
|
||||
Protocol.Debugger.stepOver();
|
||||
await waitPauseAndDumpLocation();
|
||||
await Protocol.Debugger.disable({}, contextGroupId);
|
||||
await waitPauseAndDumpLocation(InspectorTest.session);
|
||||
await session.Protocol.Debugger.disable({});
|
||||
await Protocol.Debugger.disable();
|
||||
InspectorTest.completeTest();
|
||||
})();
|
||||
|
||||
async function waitPauseAndDumpLocation() {
|
||||
var message = await Protocol.Debugger.oncePaused();
|
||||
async function waitPauseAndDumpLocation(session) {
|
||||
var message = await session.Protocol.Debugger.oncePaused();
|
||||
InspectorTest.log('paused at:');
|
||||
await InspectorTest.logSourceLocation(message.params.callFrames[0].location);
|
||||
await InspectorTest.logSourceLocation(message.params.callFrames[0].location, session);
|
||||
return message;
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
Protocol.Debugger.onPaused(message => {
|
||||
let url = InspectorTest._scriptMap.get(message.params.callFrames[0].location.scriptId).url;
|
||||
let url = InspectorTest.session._scriptMap.get(message.params.callFrames[0].location.scriptId).url;
|
||||
if (url !== 'test.js') {
|
||||
InspectorTest.log('InjectedSciptSource on stack.');
|
||||
InspectorTest.completeTest();
|
||||
|
@ -4,7 +4,7 @@
|
||||
// Flags: --expose-inspector-scripts
|
||||
|
||||
Protocol.Debugger.onPaused(message => {
|
||||
let url = InspectorTest._scriptMap.get(message.params.callFrames[0].location.scriptId).url;
|
||||
let url = InspectorTest.session._scriptMap.get(message.params.callFrames[0].location.scriptId).url;
|
||||
if (url !== 'test.js') {
|
||||
InspectorTest.log('InjectedSciptSource on stack.');
|
||||
InspectorTest.completeTest();
|
||||
|
@ -27,8 +27,7 @@ function testFunction(bytes) {
|
||||
new WebAssembly.Module(buffer);
|
||||
}
|
||||
|
||||
InspectorTest.addScriptWithUrl(
|
||||
testFunction.toString(), 'v8://test/testFunction');
|
||||
InspectorTest.addScript(testFunction.toString(), 0, 0, 'v8://test/testFunction');
|
||||
InspectorTest.addScript('var module_bytes = ' + JSON.stringify(module_bytes));
|
||||
|
||||
Protocol.Debugger.enable();
|
||||
|
@ -7,41 +7,35 @@
|
||||
#include "include/v8.h"
|
||||
|
||||
#include "src/vector.h"
|
||||
#include "test/inspector/isolate-data.h"
|
||||
#include "test/inspector/task-runner.h"
|
||||
|
||||
namespace {
|
||||
|
||||
const int kInspectorClientIndex = 0;
|
||||
|
||||
class ChannelImpl final : public v8_inspector::V8Inspector::Channel {
|
||||
public:
|
||||
explicit ChannelImpl(InspectorClientImpl::FrontendChannel* frontend_channel)
|
||||
: frontend_channel_(frontend_channel) {}
|
||||
ChannelImpl(InspectorClientImpl::FrontendChannel* frontend_channel,
|
||||
int session_id)
|
||||
: frontend_channel_(frontend_channel), session_id_(session_id) {}
|
||||
virtual ~ChannelImpl() = default;
|
||||
|
||||
private:
|
||||
void sendResponse(
|
||||
int callId,
|
||||
std::unique_ptr<v8_inspector::StringBuffer> message) override {
|
||||
frontend_channel_->SendMessageToFrontend(message->string());
|
||||
frontend_channel_->SendMessageToFrontend(session_id_, message->string());
|
||||
}
|
||||
void sendNotification(
|
||||
std::unique_ptr<v8_inspector::StringBuffer> message) override {
|
||||
frontend_channel_->SendMessageToFrontend(message->string());
|
||||
frontend_channel_->SendMessageToFrontend(session_id_, message->string());
|
||||
}
|
||||
void flushProtocolNotifications() override {}
|
||||
|
||||
InspectorClientImpl::FrontendChannel* frontend_channel_;
|
||||
int session_id_;
|
||||
DISALLOW_COPY_AND_ASSIGN(ChannelImpl);
|
||||
};
|
||||
|
||||
InspectorClientImpl* InspectorClientFromContext(
|
||||
v8::Local<v8::Context> context) {
|
||||
InspectorClientImpl* inspector_client = static_cast<InspectorClientImpl*>(
|
||||
context->GetAlignedPointerFromEmbedderData(kInspectorClientIndex));
|
||||
CHECK(inspector_client);
|
||||
return inspector_client;
|
||||
}
|
||||
|
||||
v8::internal::Vector<uint16_t> ToVector(v8::Local<v8::String> str) {
|
||||
v8::internal::Vector<uint16_t> buffer =
|
||||
v8::internal::Vector<uint16_t>::New(str->Length());
|
||||
@ -55,7 +49,7 @@ void MessageHandler(v8::Local<v8::Message> message,
|
||||
v8::Local<v8::Context> context = isolate->GetEnteredContext();
|
||||
if (context.IsEmpty()) return;
|
||||
v8_inspector::V8Inspector* inspector =
|
||||
InspectorClientImpl::InspectorFromContext(context);
|
||||
IsolateData::FromContext(context)->inspector()->inspector();
|
||||
|
||||
v8::Local<v8::StackTrace> stack = message->GetStackTrace();
|
||||
int script_id =
|
||||
@ -106,154 +100,90 @@ void Print(v8::Isolate* isolate, const v8_inspector::StringView& string) {
|
||||
}
|
||||
} // namespace
|
||||
|
||||
class ConnectTask : public TaskRunner::Task {
|
||||
public:
|
||||
ConnectTask(InspectorClientImpl* client, v8::base::Semaphore* ready_semaphore)
|
||||
: client_(client), ready_semaphore_(ready_semaphore) {}
|
||||
virtual ~ConnectTask() = default;
|
||||
|
||||
bool is_inspector_task() final { return true; }
|
||||
|
||||
private:
|
||||
void Run() override {
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
client_->connect();
|
||||
if (ready_semaphore_) ready_semaphore_->Signal();
|
||||
}
|
||||
|
||||
InspectorClientImpl* client_;
|
||||
v8::base::Semaphore* ready_semaphore_;
|
||||
};
|
||||
|
||||
class DisconnectTask : public TaskRunner::Task {
|
||||
public:
|
||||
explicit DisconnectTask(InspectorClientImpl* client, bool reset_inspector,
|
||||
v8::base::Semaphore* ready_semaphore)
|
||||
: client_(client),
|
||||
reset_inspector_(reset_inspector),
|
||||
ready_semaphore_(ready_semaphore) {}
|
||||
virtual ~DisconnectTask() = default;
|
||||
|
||||
bool is_inspector_task() final { return true; }
|
||||
|
||||
private:
|
||||
void Run() override {
|
||||
client_->disconnect(reset_inspector_);
|
||||
if (ready_semaphore_) ready_semaphore_->Signal();
|
||||
}
|
||||
|
||||
InspectorClientImpl* client_;
|
||||
bool reset_inspector_;
|
||||
v8::base::Semaphore* ready_semaphore_;
|
||||
};
|
||||
|
||||
class CreateContextGroupTask : public TaskRunner::Task {
|
||||
public:
|
||||
CreateContextGroupTask(InspectorClientImpl* client,
|
||||
IsolateData::SetupGlobalTasks setup_global_tasks,
|
||||
v8::base::Semaphore* ready_semaphore,
|
||||
int* context_group_id)
|
||||
: client_(client),
|
||||
setup_global_tasks_(std::move(setup_global_tasks)),
|
||||
ready_semaphore_(ready_semaphore),
|
||||
context_group_id_(context_group_id) {}
|
||||
virtual ~CreateContextGroupTask() = default;
|
||||
|
||||
bool is_inspector_task() final { return true; }
|
||||
|
||||
private:
|
||||
void Run() override {
|
||||
*context_group_id_ = client_->createContextGroup(setup_global_tasks_);
|
||||
if (ready_semaphore_) ready_semaphore_->Signal();
|
||||
}
|
||||
|
||||
InspectorClientImpl* client_;
|
||||
IsolateData::SetupGlobalTasks setup_global_tasks_;
|
||||
v8::base::Semaphore* ready_semaphore_;
|
||||
int* context_group_id_;
|
||||
};
|
||||
|
||||
InspectorClientImpl::InspectorClientImpl(TaskRunner* task_runner,
|
||||
FrontendChannel* frontend_channel,
|
||||
v8::base::Semaphore* ready_semaphore)
|
||||
: isolate_(nullptr),
|
||||
task_runner_(task_runner),
|
||||
InspectorClientImpl::InspectorClientImpl(v8::Isolate* isolate,
|
||||
TaskRunner* task_runner,
|
||||
FrontendChannel* frontend_channel)
|
||||
: task_runner_(task_runner),
|
||||
isolate_(isolate),
|
||||
frontend_channel_(frontend_channel) {
|
||||
task_runner_->Append(new ConnectTask(this, ready_semaphore));
|
||||
isolate_->AddMessageListener(MessageHandler);
|
||||
inspector_ = v8_inspector::V8Inspector::create(isolate_, this);
|
||||
}
|
||||
|
||||
InspectorClientImpl::~InspectorClientImpl() {}
|
||||
|
||||
void InspectorClientImpl::connect() {
|
||||
isolate_ = task_runner_->data()->isolate();
|
||||
isolate_->AddMessageListener(MessageHandler);
|
||||
channel_.reset(new ChannelImpl(frontend_channel_));
|
||||
inspector_ = v8_inspector::V8Inspector::create(isolate_, this);
|
||||
|
||||
if (states_.empty()) {
|
||||
ConnectToContextGroup(task_runner_->default_context_group_id(),
|
||||
v8_inspector::StringView());
|
||||
} else {
|
||||
for (const auto& it : states_)
|
||||
ConnectToContextGroup(it.first, it.second->string());
|
||||
}
|
||||
states_.clear();
|
||||
int InspectorClientImpl::ConnectSession(int context_group_id,
|
||||
const v8_inspector::StringView& state) {
|
||||
int session_id = ++last_session_id_;
|
||||
channels_[session_id].reset(new ChannelImpl(frontend_channel_, session_id));
|
||||
sessions_[session_id] =
|
||||
inspector_->connect(context_group_id, channels_[session_id].get(), state);
|
||||
context_group_by_session_[sessions_[session_id].get()] = context_group_id;
|
||||
return session_id;
|
||||
}
|
||||
|
||||
void InspectorClientImpl::ConnectToContextGroup(
|
||||
int context_group_id, v8_inspector::StringView state) {
|
||||
v8::Local<v8::Context> context =
|
||||
task_runner_->data()->GetContext(context_group_id);
|
||||
sessions_[context_group_id] =
|
||||
inspector_->connect(context_group_id, channel_.get(), state);
|
||||
context->SetAlignedPointerInEmbedderData(kInspectorClientIndex, this);
|
||||
std::unique_ptr<v8_inspector::StringBuffer>
|
||||
InspectorClientImpl::DisconnectSession(int session_id) {
|
||||
auto it = sessions_.find(session_id);
|
||||
CHECK(it != sessions_.end());
|
||||
context_group_by_session_.erase(it->second.get());
|
||||
std::unique_ptr<v8_inspector::StringBuffer> result = it->second->stateJSON();
|
||||
sessions_.erase(it);
|
||||
channels_.erase(session_id);
|
||||
return result;
|
||||
}
|
||||
|
||||
void InspectorClientImpl::SendMessage(int session_id,
|
||||
const v8_inspector::StringView& message) {
|
||||
auto it = sessions_.find(session_id);
|
||||
if (it != sessions_.end()) it->second->dispatchProtocolMessage(message);
|
||||
}
|
||||
|
||||
void InspectorClientImpl::BreakProgram(
|
||||
int context_group_id, const v8_inspector::StringView& reason,
|
||||
const v8_inspector::StringView& details) {
|
||||
for (int session_id : GetSessionIds(context_group_id)) {
|
||||
auto it = sessions_.find(session_id);
|
||||
if (it != sessions_.end()) it->second->breakProgram(reason, details);
|
||||
}
|
||||
}
|
||||
|
||||
void InspectorClientImpl::SchedulePauseOnNextStatement(
|
||||
int context_group_id, const v8_inspector::StringView& reason,
|
||||
const v8_inspector::StringView& details) {
|
||||
for (int session_id : GetSessionIds(context_group_id)) {
|
||||
auto it = sessions_.find(session_id);
|
||||
if (it != sessions_.end())
|
||||
it->second->schedulePauseOnNextStatement(reason, details);
|
||||
}
|
||||
}
|
||||
|
||||
void InspectorClientImpl::CancelPauseOnNextStatement(int context_group_id) {
|
||||
for (int session_id : GetSessionIds(context_group_id)) {
|
||||
auto it = sessions_.find(session_id);
|
||||
if (it != sessions_.end()) it->second->cancelPauseOnNextStatement();
|
||||
}
|
||||
}
|
||||
|
||||
void InspectorClientImpl::ContextCreated(v8::Local<v8::Context> context,
|
||||
int context_group_id) {
|
||||
v8_inspector::V8ContextInfo info(context, context_group_id,
|
||||
v8_inspector::StringView());
|
||||
info.hasMemoryOnConsole = true;
|
||||
inspector_->contextCreated(info);
|
||||
}
|
||||
|
||||
void InspectorClientImpl::scheduleReconnect(
|
||||
v8::base::Semaphore* ready_semaphore) {
|
||||
task_runner_->Append(
|
||||
new DisconnectTask(this, /* reset_inspector */ true, nullptr));
|
||||
task_runner_->Append(new ConnectTask(this, ready_semaphore));
|
||||
void InspectorClientImpl::ContextDestroyed(v8::Local<v8::Context> context) {
|
||||
inspector_->contextDestroyed(context);
|
||||
}
|
||||
|
||||
void InspectorClientImpl::scheduleDisconnect(
|
||||
v8::base::Semaphore* ready_semaphore) {
|
||||
task_runner_->Append(
|
||||
new DisconnectTask(this, /* reset_inspector */ false, ready_semaphore));
|
||||
}
|
||||
|
||||
void InspectorClientImpl::disconnect(bool reset_inspector) {
|
||||
for (const auto& it : sessions_) {
|
||||
states_[it.first] = it.second->stateJSON();
|
||||
std::vector<int> InspectorClientImpl::GetSessionIds(int context_group_id) {
|
||||
std::vector<int> result;
|
||||
for (auto& it : sessions_) {
|
||||
if (context_group_by_session_[it.second.get()] == context_group_id)
|
||||
result.push_back(it.first);
|
||||
}
|
||||
sessions_.clear();
|
||||
if (reset_inspector) inspector_.reset();
|
||||
}
|
||||
|
||||
void InspectorClientImpl::scheduleCreateContextGroup(
|
||||
IsolateData::SetupGlobalTasks setup_global_tasks,
|
||||
v8::base::Semaphore* ready_semaphore, int* context_group_id) {
|
||||
task_runner_->Append(new CreateContextGroupTask(
|
||||
this, std::move(setup_global_tasks), ready_semaphore, context_group_id));
|
||||
}
|
||||
|
||||
int InspectorClientImpl::createContextGroup(
|
||||
const IsolateData::SetupGlobalTasks& setup_global_tasks) {
|
||||
v8::HandleScope handle_scope(isolate_);
|
||||
int context_group_id = task_runner_->data()->CreateContextGroup();
|
||||
v8::Local<v8::Context> context =
|
||||
task_runner_->data()->GetContext(context_group_id);
|
||||
context->SetAlignedPointerInEmbedderData(kInspectorClientIndex, this);
|
||||
v8_inspector::StringView state;
|
||||
sessions_[context_group_id] =
|
||||
inspector_->connect(context_group_id, channel_.get(), state);
|
||||
inspector_->contextCreated(v8_inspector::V8ContextInfo(
|
||||
context, context_group_id, v8_inspector::StringView()));
|
||||
return context_group_id;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool InspectorClientImpl::formatAccessorsAsProperties(
|
||||
@ -276,7 +206,7 @@ v8::Local<v8::Context> InspectorClientImpl::ensureDefaultContextInGroup(
|
||||
return task_runner_->data()->GetContext(context_group_id);
|
||||
}
|
||||
|
||||
void InspectorClientImpl::setCurrentTimeMSForTest(double time) {
|
||||
void InspectorClientImpl::SetCurrentTimeMSForTest(double time) {
|
||||
current_time_ = time;
|
||||
current_time_set_for_test_ = true;
|
||||
}
|
||||
@ -286,12 +216,12 @@ double InspectorClientImpl::currentTimeMS() {
|
||||
return v8::base::OS::TimeCurrentMillis();
|
||||
}
|
||||
|
||||
void InspectorClientImpl::setMemoryInfoForTest(
|
||||
void InspectorClientImpl::SetMemoryInfoForTest(
|
||||
v8::Local<v8::Value> memory_info) {
|
||||
memory_info_.Reset(isolate_, memory_info);
|
||||
}
|
||||
|
||||
void InspectorClientImpl::setLogConsoleApiMessageCalls(bool log) {
|
||||
void InspectorClientImpl::SetLogConsoleApiMessageCalls(bool log) {
|
||||
log_console_api_message_calls_ = log;
|
||||
}
|
||||
|
||||
@ -322,78 +252,3 @@ void InspectorClientImpl::consoleAPIMessage(
|
||||
Print(isolate_, stack->toString()->string());
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
|
||||
v8_inspector::V8Inspector* InspectorClientImpl::InspectorFromContext(
|
||||
v8::Local<v8::Context> context) {
|
||||
return InspectorClientFromContext(context)->inspector_.get();
|
||||
}
|
||||
|
||||
v8_inspector::V8InspectorSession* InspectorClientImpl::SessionFromContext(
|
||||
v8::Local<v8::Context> context) {
|
||||
InspectorClientImpl* client = InspectorClientFromContext(context);
|
||||
for (auto& it : client->sessions_) {
|
||||
if (client->task_runner_->data()->GetContext(it.first) == context)
|
||||
return it.second.get();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
v8_inspector::V8InspectorSession* InspectorClientImpl::session(
|
||||
int context_group_id) {
|
||||
if (context_group_id) {
|
||||
return sessions_[context_group_id].get();
|
||||
} else {
|
||||
return sessions_.begin()->second.get();
|
||||
}
|
||||
}
|
||||
|
||||
class SendMessageToBackendTask : public TaskRunner::Task {
|
||||
public:
|
||||
explicit SendMessageToBackendTask(
|
||||
const v8::internal::Vector<uint16_t>& message, int context_group_id)
|
||||
: message_(message), context_group_id_(context_group_id) {}
|
||||
|
||||
bool is_inspector_task() final { return true; }
|
||||
|
||||
private:
|
||||
void Run() override {
|
||||
v8_inspector::V8InspectorSession* session = nullptr;
|
||||
{
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
if (!context_group_id_) {
|
||||
session = InspectorClientImpl::SessionFromContext(default_context());
|
||||
} else {
|
||||
session = InspectorClientFromContext(default_context())
|
||||
->sessions_[context_group_id_]
|
||||
.get();
|
||||
}
|
||||
if (!session) return;
|
||||
}
|
||||
v8_inspector::StringView message_view(message_.start(), message_.length());
|
||||
session->dispatchProtocolMessage(message_view);
|
||||
}
|
||||
|
||||
v8::internal::Vector<uint16_t> message_;
|
||||
int context_group_id_;
|
||||
};
|
||||
|
||||
TaskRunner* SendMessageToBackendExtension::backend_task_runner_ = nullptr;
|
||||
|
||||
void SendMessageToBackendExtension::Run(v8::Isolate* isolate,
|
||||
v8::Local<v8::ObjectTemplate> global) {
|
||||
global->Set(
|
||||
v8::String::NewFromUtf8(isolate, "sendMessageToBackend",
|
||||
v8::NewStringType::kNormal)
|
||||
.ToLocalChecked(),
|
||||
v8::FunctionTemplate::New(
|
||||
isolate, &SendMessageToBackendExtension::SendMessageToBackend));
|
||||
}
|
||||
|
||||
void SendMessageToBackendExtension::SendMessageToBackend(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
CHECK(backend_task_runner_);
|
||||
CHECK(args.Length() == 2 && args[0]->IsString() && args[1]->IsInt32());
|
||||
v8::Local<v8::String> message = args[0].As<v8::String>();
|
||||
backend_task_runner_->Append(new SendMessageToBackendTask(
|
||||
ToVector(message), args[1].As<v8::Int32>()->Value()));
|
||||
}
|
||||
|
@ -5,11 +5,15 @@
|
||||
#ifndef V8_TEST_INSPECTOR_PROTOCOL_INSPECTOR_IMPL_H_
|
||||
#define V8_TEST_INSPECTOR_PROTOCOL_INSPECTOR_IMPL_H_
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "include/v8-inspector.h"
|
||||
#include "include/v8.h"
|
||||
#include "src/base/macros.h"
|
||||
#include "src/base/platform/platform.h"
|
||||
#include "test/inspector/task-runner.h"
|
||||
|
||||
class TaskRunner;
|
||||
|
||||
class InspectorClientImpl : public v8_inspector::V8InspectorClient {
|
||||
public:
|
||||
@ -17,31 +21,30 @@ class InspectorClientImpl : public v8_inspector::V8InspectorClient {
|
||||
public:
|
||||
virtual ~FrontendChannel() = default;
|
||||
virtual void SendMessageToFrontend(
|
||||
const v8_inspector::StringView& message) = 0;
|
||||
int session_id, const v8_inspector::StringView& message) = 0;
|
||||
};
|
||||
|
||||
InspectorClientImpl(TaskRunner* task_runner,
|
||||
FrontendChannel* frontend_channel,
|
||||
v8::base::Semaphore* ready_semaphore);
|
||||
InspectorClientImpl(v8::Isolate* isolate, TaskRunner* task_runner,
|
||||
FrontendChannel* frontend_channel);
|
||||
virtual ~InspectorClientImpl();
|
||||
|
||||
void scheduleReconnect(v8::base::Semaphore* ready_semaphore);
|
||||
void scheduleDisconnect(v8::base::Semaphore* ready_semaphore);
|
||||
void scheduleCreateContextGroup(
|
||||
IsolateData::SetupGlobalTasks setup_global_tasks,
|
||||
v8::base::Semaphore* ready_semaphore, int* context_group_id);
|
||||
|
||||
static v8_inspector::V8Inspector* InspectorFromContext(
|
||||
v8::Local<v8::Context> context);
|
||||
static v8_inspector::V8InspectorSession* SessionFromContext(
|
||||
v8::Local<v8::Context> context);
|
||||
|
||||
// context_group_id = 0 means default context group.
|
||||
v8_inspector::V8InspectorSession* session(int context_group_id = 0);
|
||||
|
||||
void setCurrentTimeMSForTest(double time);
|
||||
void setMemoryInfoForTest(v8::Local<v8::Value> memory_info);
|
||||
void setLogConsoleApiMessageCalls(bool log);
|
||||
v8_inspector::V8Inspector* inspector() const { return inspector_.get(); }
|
||||
int ConnectSession(int context_group_id,
|
||||
const v8_inspector::StringView& state);
|
||||
std::unique_ptr<v8_inspector::StringBuffer> DisconnectSession(int session_id);
|
||||
void SendMessage(int session_id, const v8_inspector::StringView& message);
|
||||
void BreakProgram(int context_group_id,
|
||||
const v8_inspector::StringView& reason,
|
||||
const v8_inspector::StringView& details);
|
||||
void SchedulePauseOnNextStatement(int context_group_id,
|
||||
const v8_inspector::StringView& reason,
|
||||
const v8_inspector::StringView& details);
|
||||
void CancelPauseOnNextStatement(int context_group_id);
|
||||
void SetCurrentTimeMSForTest(double time);
|
||||
void SetMemoryInfoForTest(v8::Local<v8::Value> memory_info);
|
||||
void SetLogConsoleApiMessageCalls(bool log);
|
||||
void ContextCreated(v8::Local<v8::Context> context, int context_group_id);
|
||||
void ContextDestroyed(v8::Local<v8::Context> context);
|
||||
|
||||
private:
|
||||
// V8InspectorClient implementation.
|
||||
@ -59,30 +62,18 @@ class InspectorClientImpl : public v8_inspector::V8InspectorClient {
|
||||
const v8_inspector::StringView& url,
|
||||
unsigned lineNumber, unsigned columnNumber,
|
||||
v8_inspector::V8StackTrace*) override;
|
||||
friend class SendMessageToBackendTask;
|
||||
|
||||
friend class ConnectTask;
|
||||
void connect();
|
||||
void ConnectToContextGroup(int context_group_id,
|
||||
v8_inspector::StringView state);
|
||||
friend class DisconnectTask;
|
||||
void disconnect(bool reset_inspector);
|
||||
friend class CreateContextGroupTask;
|
||||
int createContextGroup(
|
||||
const IsolateData::SetupGlobalTasks& setup_global_tasks);
|
||||
std::vector<int> GetSessionIds(int context_group_id);
|
||||
|
||||
std::unique_ptr<v8_inspector::V8Inspector> inspector_;
|
||||
std::unique_ptr<v8_inspector::V8Inspector::Channel> channel_;
|
||||
|
||||
int last_session_id_ = 0;
|
||||
std::map<int, std::unique_ptr<v8_inspector::V8InspectorSession>> sessions_;
|
||||
std::map<int, std::unique_ptr<v8_inspector::StringBuffer>> states_;
|
||||
|
||||
std::map<v8_inspector::V8InspectorSession*, int> context_group_by_session_;
|
||||
std::map<int, std::unique_ptr<v8_inspector::V8Inspector::Channel>> channels_;
|
||||
TaskRunner* task_runner_;
|
||||
v8::Isolate* isolate_;
|
||||
v8::Global<v8::Value> memory_info_;
|
||||
|
||||
TaskRunner* task_runner_;
|
||||
FrontendChannel* frontend_channel_;
|
||||
|
||||
bool current_time_set_for_test_ = false;
|
||||
double current_time_ = 0.0;
|
||||
bool log_console_api_message_calls_ = false;
|
||||
@ -90,19 +81,4 @@ class InspectorClientImpl : public v8_inspector::V8InspectorClient {
|
||||
DISALLOW_COPY_AND_ASSIGN(InspectorClientImpl);
|
||||
};
|
||||
|
||||
class SendMessageToBackendExtension : public IsolateData::SetupGlobalTask {
|
||||
public:
|
||||
void Run(v8::Isolate* isolate, v8::Local<v8::ObjectTemplate> global) override;
|
||||
|
||||
static void set_backend_task_runner(TaskRunner* task_runner) {
|
||||
backend_task_runner_ = task_runner;
|
||||
}
|
||||
|
||||
private:
|
||||
static void SendMessageToBackend(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
|
||||
static TaskRunner* backend_task_runner_;
|
||||
};
|
||||
|
||||
#endif // V8_TEST_INSPECTOR_PROTOCOL_INSPECTOR_IMPL_H_
|
||||
|
@ -51,6 +51,196 @@ v8::Local<v8::String> ToV8String(v8::Isolate* isolate, const char* str) {
|
||||
.ToLocalChecked();
|
||||
}
|
||||
|
||||
v8::internal::Vector<uint16_t> ToVector(
|
||||
const v8_inspector::StringView& string) {
|
||||
v8::internal::Vector<uint16_t> buffer =
|
||||
v8::internal::Vector<uint16_t>::New(static_cast<int>(string.length()));
|
||||
for (size_t i = 0; i < string.length(); i++) {
|
||||
if (string.is8Bit())
|
||||
buffer[i] = string.characters8()[i];
|
||||
else
|
||||
buffer[i] = string.characters16()[i];
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
class CreateContextGroupTask : public TaskRunner::Task {
|
||||
public:
|
||||
CreateContextGroupTask(v8::base::Semaphore* ready_semaphore,
|
||||
int* context_group_id)
|
||||
: ready_semaphore_(ready_semaphore),
|
||||
context_group_id_(context_group_id) {}
|
||||
virtual ~CreateContextGroupTask() = default;
|
||||
bool is_inspector_task() final { return true; }
|
||||
|
||||
private:
|
||||
void Run() override {
|
||||
*context_group_id_ = data()->CreateContextGroup();
|
||||
if (ready_semaphore_) ready_semaphore_->Signal();
|
||||
}
|
||||
|
||||
v8::base::Semaphore* ready_semaphore_;
|
||||
int* context_group_id_;
|
||||
};
|
||||
|
||||
class ConnectSessionTask : public TaskRunner::Task {
|
||||
public:
|
||||
ConnectSessionTask(v8::base::Semaphore* ready_semaphore, int context_group_id,
|
||||
const v8::internal::Vector<uint16_t>& state,
|
||||
int* session_id)
|
||||
: ready_semaphore_(ready_semaphore),
|
||||
context_group_id_(context_group_id),
|
||||
state_(state),
|
||||
session_id_(session_id) {}
|
||||
virtual ~ConnectSessionTask() = default;
|
||||
bool is_inspector_task() final { return true; }
|
||||
|
||||
private:
|
||||
void Run() override {
|
||||
v8_inspector::StringView state(state_.start(), state_.length());
|
||||
*session_id_ =
|
||||
data()->inspector()->ConnectSession(context_group_id_, state);
|
||||
if (ready_semaphore_) ready_semaphore_->Signal();
|
||||
}
|
||||
|
||||
v8::base::Semaphore* ready_semaphore_;
|
||||
int context_group_id_;
|
||||
const v8::internal::Vector<uint16_t>& state_;
|
||||
int* session_id_;
|
||||
};
|
||||
|
||||
class DisconnectSessionTask : public TaskRunner::Task {
|
||||
public:
|
||||
DisconnectSessionTask(v8::base::Semaphore* ready_semaphore, int session_id,
|
||||
v8::internal::Vector<uint16_t>* state)
|
||||
: ready_semaphore_(ready_semaphore),
|
||||
session_id_(session_id),
|
||||
state_(state) {}
|
||||
virtual ~DisconnectSessionTask() = default;
|
||||
bool is_inspector_task() final { return true; }
|
||||
|
||||
private:
|
||||
void Run() override {
|
||||
std::unique_ptr<v8_inspector::StringBuffer> state =
|
||||
data()->inspector()->DisconnectSession(session_id_);
|
||||
*state_ = ToVector(state->string());
|
||||
if (ready_semaphore_) ready_semaphore_->Signal();
|
||||
}
|
||||
|
||||
v8::base::Semaphore* ready_semaphore_;
|
||||
int session_id_;
|
||||
v8::internal::Vector<uint16_t>* state_;
|
||||
};
|
||||
|
||||
class SendMessageToBackendTask : public TaskRunner::Task {
|
||||
public:
|
||||
explicit SendMessageToBackendTask(
|
||||
int session_id, const v8::internal::Vector<uint16_t>& message)
|
||||
: session_id_(session_id), message_(message) {}
|
||||
bool is_inspector_task() final { return true; }
|
||||
|
||||
private:
|
||||
void Run() override {
|
||||
v8_inspector::StringView message_view(message_.start(), message_.length());
|
||||
data()->inspector()->SendMessage(session_id_, message_view);
|
||||
}
|
||||
|
||||
int session_id_;
|
||||
v8::internal::Vector<uint16_t> message_;
|
||||
};
|
||||
|
||||
class SchedulePauseOnNextStatementTask : public TaskRunner::Task {
|
||||
public:
|
||||
SchedulePauseOnNextStatementTask(
|
||||
v8::base::Semaphore* ready_semaphore, int context_group_id,
|
||||
const v8::internal::Vector<uint16_t>& reason,
|
||||
const v8::internal::Vector<uint16_t>& details)
|
||||
: ready_semaphore_(ready_semaphore),
|
||||
context_group_id_(context_group_id),
|
||||
reason_(reason),
|
||||
details_(details) {}
|
||||
virtual ~SchedulePauseOnNextStatementTask() = default;
|
||||
bool is_inspector_task() final { return true; }
|
||||
|
||||
private:
|
||||
void Run() override {
|
||||
v8_inspector::StringView reason(reason_.start(), reason_.length());
|
||||
v8_inspector::StringView details(details_.start(), details_.length());
|
||||
data()->inspector()->SchedulePauseOnNextStatement(context_group_id_, reason,
|
||||
details);
|
||||
if (ready_semaphore_) ready_semaphore_->Signal();
|
||||
}
|
||||
|
||||
v8::base::Semaphore* ready_semaphore_;
|
||||
int context_group_id_;
|
||||
const v8::internal::Vector<uint16_t>& reason_;
|
||||
const v8::internal::Vector<uint16_t>& details_;
|
||||
};
|
||||
|
||||
class CancelPauseOnNextStatementTask : public TaskRunner::Task {
|
||||
public:
|
||||
CancelPauseOnNextStatementTask(v8::base::Semaphore* ready_semaphore,
|
||||
int context_group_id)
|
||||
: ready_semaphore_(ready_semaphore),
|
||||
context_group_id_(context_group_id) {}
|
||||
virtual ~CancelPauseOnNextStatementTask() = default;
|
||||
bool is_inspector_task() final { return true; }
|
||||
|
||||
private:
|
||||
void Run() override {
|
||||
data()->inspector()->CancelPauseOnNextStatement(context_group_id_);
|
||||
if (ready_semaphore_) ready_semaphore_->Signal();
|
||||
}
|
||||
|
||||
v8::base::Semaphore* ready_semaphore_;
|
||||
int context_group_id_;
|
||||
};
|
||||
|
||||
class SendMessageToFrontendTask : public TaskRunner::Task {
|
||||
public:
|
||||
SendMessageToFrontendTask(int context_group_id, int session_id,
|
||||
const v8::internal::Vector<uint16_t>& message)
|
||||
: context_group_id_(context_group_id),
|
||||
session_id_(session_id),
|
||||
message_(message) {}
|
||||
virtual ~SendMessageToFrontendTask() {}
|
||||
|
||||
bool is_inspector_task() final { return false; }
|
||||
|
||||
static void Register(int session_id, v8::Isolate* isolate,
|
||||
v8::Local<v8::Function> dispatcher) {
|
||||
dispatchers_[session_id].Reset(isolate, dispatcher);
|
||||
}
|
||||
|
||||
static void Unregister(int session_id) { dispatchers_.erase(session_id); }
|
||||
|
||||
private:
|
||||
void Run() override {
|
||||
v8::MicrotasksScope microtasks_scope(isolate(),
|
||||
v8::MicrotasksScope::kRunMicrotasks);
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
v8::Local<v8::Context> context = data()->GetContext(context_group_id_);
|
||||
v8::Context::Scope context_scope(context);
|
||||
|
||||
if (dispatchers_.find(session_id_) == dispatchers_.end()) return;
|
||||
v8::Local<v8::Function> function = dispatchers_[session_id_].Get(isolate());
|
||||
v8::Local<v8::Value> message =
|
||||
v8::String::NewFromTwoByte(isolate(), message_.start(),
|
||||
v8::NewStringType::kNormal,
|
||||
static_cast<int>(message_.size()))
|
||||
.ToLocalChecked();
|
||||
v8::MaybeLocal<v8::Value> result;
|
||||
result = function->Call(context, context->Global(), 1, &message);
|
||||
}
|
||||
|
||||
static std::map<int, v8::Global<v8::Function>> dispatchers_;
|
||||
int context_group_id_;
|
||||
int session_id_;
|
||||
v8::internal::Vector<uint16_t> message_;
|
||||
};
|
||||
|
||||
std::map<int, v8::Global<v8::Function>> SendMessageToFrontendTask::dispatchers_;
|
||||
|
||||
class UtilsExtension : public IsolateData::SetupGlobalTask {
|
||||
public:
|
||||
~UtilsExtension() override = default;
|
||||
@ -82,16 +272,21 @@ class UtilsExtension : public IsolateData::SetupGlobalTask {
|
||||
utils->Set(ToV8String(isolate, "cancelPauseOnNextStatement"),
|
||||
v8::FunctionTemplate::New(
|
||||
isolate, &UtilsExtension::CancelPauseOnNextStatement));
|
||||
utils->Set(ToV8String(isolate, "reconnect"),
|
||||
v8::FunctionTemplate::New(isolate, &UtilsExtension::Reconnect));
|
||||
utils->Set(ToV8String(isolate, "disconnect"),
|
||||
v8::FunctionTemplate::New(isolate, &UtilsExtension::Disconnect));
|
||||
utils->Set(ToV8String(isolate, "setLogConsoleApiMessageCalls"),
|
||||
v8::FunctionTemplate::New(
|
||||
isolate, &UtilsExtension::SetLogConsoleApiMessageCalls));
|
||||
utils->Set(ToV8String(isolate, "createContextGroup"),
|
||||
v8::FunctionTemplate::New(isolate,
|
||||
&UtilsExtension::CreateContextGroup));
|
||||
utils->Set(
|
||||
ToV8String(isolate, "connectSession"),
|
||||
v8::FunctionTemplate::New(isolate, &UtilsExtension::ConnectSession));
|
||||
utils->Set(
|
||||
ToV8String(isolate, "disconnectSession"),
|
||||
v8::FunctionTemplate::New(isolate, &UtilsExtension::DisconnectSession));
|
||||
utils->Set(ToV8String(isolate, "sendMessageToBackend"),
|
||||
v8::FunctionTemplate::New(
|
||||
isolate, &UtilsExtension::SendMessageToBackend));
|
||||
global->Set(ToV8String(isolate, "utils"), utils);
|
||||
}
|
||||
|
||||
@ -99,13 +294,8 @@ class UtilsExtension : public IsolateData::SetupGlobalTask {
|
||||
backend_runner_ = runner;
|
||||
}
|
||||
|
||||
static void set_inspector_client(InspectorClientImpl* client) {
|
||||
inspector_client_ = client;
|
||||
}
|
||||
|
||||
private:
|
||||
static TaskRunner* backend_runner_;
|
||||
static InspectorClientImpl* inspector_client_;
|
||||
|
||||
static void Print(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
for (int i = 0; i < args.Length(); i++) {
|
||||
@ -189,27 +379,31 @@ class UtilsExtension : public IsolateData::SetupGlobalTask {
|
||||
}
|
||||
v8::internal::Vector<const char> chars;
|
||||
v8::Isolate* isolate = args.GetIsolate();
|
||||
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
||||
IsolateData* data = IsolateData::FromContext(context);
|
||||
int context_group_id = data->GetContextGroupId(context);
|
||||
if (ReadFile(isolate, args[0], &chars)) {
|
||||
ExecuteStringTask(chars).RunOnTaskRunner(
|
||||
IsolateData::FromContext(isolate->GetCurrentContext())
|
||||
->task_runner());
|
||||
ExecuteStringTask(chars, context_group_id).RunOnIsolate(data);
|
||||
}
|
||||
}
|
||||
|
||||
static void CompileAndRunWithOrigin(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
if (args.Length() != 5 || !args[0]->IsString() || !args[1]->IsString() ||
|
||||
!args[2]->IsInt32() || !args[3]->IsInt32() || !args[4]->IsBoolean()) {
|
||||
if (args.Length() != 6 || !args[0]->IsInt32() || !args[1]->IsString() ||
|
||||
!args[2]->IsString() || !args[3]->IsInt32() || !args[4]->IsInt32() ||
|
||||
!args[5]->IsBoolean()) {
|
||||
fprintf(stderr,
|
||||
"Internal error: compileAndRunWithOrigin(source, name, line, "
|
||||
"Internal error: compileAndRunWithOrigin(context_group_id, "
|
||||
"source, name, line, "
|
||||
"column, is_module).");
|
||||
Exit();
|
||||
}
|
||||
|
||||
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[4].As<v8::Boolean>(), nullptr, nullptr));
|
||||
nullptr, args[0].As<v8::Int32>()->Value(), nullptr,
|
||||
ToVector(args[1].As<v8::String>()), args[2].As<v8::String>(),
|
||||
args[3].As<v8::Int32>(), args[4].As<v8::Int32>(),
|
||||
args[5].As<v8::Boolean>()));
|
||||
}
|
||||
|
||||
static void SetCurrentTimeMSForTest(
|
||||
@ -218,7 +412,7 @@ class UtilsExtension : public IsolateData::SetupGlobalTask {
|
||||
fprintf(stderr, "Internal error: setCurrentTimeMSForTest(time).");
|
||||
Exit();
|
||||
}
|
||||
inspector_client_->setCurrentTimeMSForTest(
|
||||
backend_runner_->data()->inspector()->SetCurrentTimeMSForTest(
|
||||
args[0].As<v8::Number>()->Value());
|
||||
}
|
||||
|
||||
@ -228,51 +422,36 @@ class UtilsExtension : public IsolateData::SetupGlobalTask {
|
||||
fprintf(stderr, "Internal error: setMemoryInfoForTest(value).");
|
||||
Exit();
|
||||
}
|
||||
inspector_client_->setMemoryInfoForTest(args[0]);
|
||||
backend_runner_->data()->inspector()->SetMemoryInfoForTest(args[0]);
|
||||
}
|
||||
|
||||
static void SchedulePauseOnNextStatement(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
if (args.Length() != 2 || !args[0]->IsString() || !args[1]->IsString()) {
|
||||
fprintf(
|
||||
stderr,
|
||||
"Internal error: schedulePauseOnNextStatement('reason', 'details').");
|
||||
if (args.Length() != 3 || !args[0]->IsInt32() || !args[1]->IsString() ||
|
||||
!args[2]->IsString()) {
|
||||
fprintf(stderr,
|
||||
"Internal error: schedulePauseOnNextStatement(context_group_id, "
|
||||
"'reason', 'details').");
|
||||
Exit();
|
||||
}
|
||||
v8::internal::Vector<uint16_t> reason = ToVector(args[0].As<v8::String>());
|
||||
v8_inspector::StringView reason_view(reason.start(), reason.length());
|
||||
v8::internal::Vector<uint16_t> details = ToVector(args[1].As<v8::String>());
|
||||
v8_inspector::StringView details_view(details.start(), details.length());
|
||||
inspector_client_->session()->schedulePauseOnNextStatement(reason_view,
|
||||
details_view);
|
||||
v8::internal::Vector<uint16_t> reason = ToVector(args[1].As<v8::String>());
|
||||
v8::internal::Vector<uint16_t> details = ToVector(args[2].As<v8::String>());
|
||||
v8::base::Semaphore ready_semaphore(0);
|
||||
backend_runner_->Append(new SchedulePauseOnNextStatementTask(
|
||||
&ready_semaphore, args[0].As<v8::Int32>()->Value(), reason, details));
|
||||
ready_semaphore.Wait();
|
||||
}
|
||||
|
||||
static void CancelPauseOnNextStatement(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
if (args.Length() != 0) {
|
||||
fprintf(stderr, "Internal error: cancelPauseOnNextStatement().");
|
||||
Exit();
|
||||
}
|
||||
inspector_client_->session()->cancelPauseOnNextStatement();
|
||||
}
|
||||
|
||||
static void Reconnect(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
if (args.Length() != 0) {
|
||||
fprintf(stderr, "Internal error: reconnect().");
|
||||
if (args.Length() != 1 || !args[0]->IsInt32()) {
|
||||
fprintf(stderr,
|
||||
"Internal error: cancelPauseOnNextStatement(context_group_id).");
|
||||
Exit();
|
||||
}
|
||||
v8::base::Semaphore ready_semaphore(0);
|
||||
inspector_client_->scheduleReconnect(&ready_semaphore);
|
||||
ready_semaphore.Wait();
|
||||
}
|
||||
|
||||
static void Disconnect(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
if (args.Length() != 0) {
|
||||
fprintf(stderr, "Internal error: disconnect().");
|
||||
Exit();
|
||||
}
|
||||
v8::base::Semaphore ready_semaphore(0);
|
||||
inspector_client_->scheduleDisconnect(&ready_semaphore);
|
||||
backend_runner_->Append(new CancelPauseOnNextStatementTask(
|
||||
&ready_semaphore, args[0].As<v8::Int32>()->Value()));
|
||||
ready_semaphore.Wait();
|
||||
}
|
||||
|
||||
@ -282,22 +461,86 @@ class UtilsExtension : public IsolateData::SetupGlobalTask {
|
||||
fprintf(stderr, "Internal error: setLogConsoleApiMessageCalls(bool).");
|
||||
Exit();
|
||||
}
|
||||
inspector_client_->setLogConsoleApiMessageCalls(
|
||||
backend_runner_->data()->inspector()->SetLogConsoleApiMessageCalls(
|
||||
args[0].As<v8::Boolean>()->Value());
|
||||
}
|
||||
|
||||
static void CreateContextGroup(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
if (args.Length() != 0) {
|
||||
fprintf(stderr, "Internal error: createContextGroup().");
|
||||
Exit();
|
||||
}
|
||||
v8::base::Semaphore ready_semaphore(0);
|
||||
int context_group_id = 0;
|
||||
backend_runner_->Append(
|
||||
new CreateContextGroupTask(&ready_semaphore, &context_group_id));
|
||||
ready_semaphore.Wait();
|
||||
args.GetReturnValue().Set(
|
||||
v8::Int32::New(args.GetIsolate(), context_group_id));
|
||||
}
|
||||
|
||||
static void ConnectSession(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
if (args.Length() != 3 || !args[0]->IsInt32() || !args[1]->IsString() ||
|
||||
!args[2]->IsFunction()) {
|
||||
fprintf(stderr,
|
||||
"Internal error: connectionSession(context_group_id, state, "
|
||||
"dispatch).");
|
||||
Exit();
|
||||
}
|
||||
v8::internal::Vector<uint16_t> state = ToVector(args[1].As<v8::String>());
|
||||
v8::base::Semaphore ready_semaphore(0);
|
||||
int session_id = 0;
|
||||
backend_runner_->Append(new ConnectSessionTask(
|
||||
&ready_semaphore, args[0].As<v8::Int32>()->Value(), state,
|
||||
&session_id));
|
||||
ready_semaphore.Wait();
|
||||
SendMessageToFrontendTask::Register(session_id, args.GetIsolate(),
|
||||
args[2].As<v8::Function>());
|
||||
args.GetReturnValue().Set(v8::Int32::New(args.GetIsolate(), session_id));
|
||||
}
|
||||
|
||||
static void DisconnectSession(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
if (args.Length() != 1 || !args[0]->IsInt32()) {
|
||||
fprintf(stderr, "Internal error: disconnectionSession(session_id).");
|
||||
Exit();
|
||||
}
|
||||
int session_id = args[0].As<v8::Int32>()->Value();
|
||||
SendMessageToFrontendTask::Unregister(session_id);
|
||||
v8::base::Semaphore ready_semaphore(0);
|
||||
v8::internal::Vector<uint16_t> state;
|
||||
backend_runner_->Append(
|
||||
new DisconnectSessionTask(&ready_semaphore, session_id, &state));
|
||||
ready_semaphore.Wait();
|
||||
args.GetReturnValue().Set(
|
||||
v8::String::NewFromTwoByte(args.GetIsolate(), state.start(),
|
||||
v8::NewStringType::kNormal,
|
||||
static_cast<int>(state.size()))
|
||||
.ToLocalChecked());
|
||||
}
|
||||
|
||||
static void SendMessageToBackend(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
if (args.Length() != 2 || !args[0]->IsInt32() || !args[1]->IsString()) {
|
||||
fprintf(stderr,
|
||||
"Internal error: sendMessageToBackend(session_id, message).");
|
||||
Exit();
|
||||
}
|
||||
backend_runner_->Append(new SendMessageToBackendTask(
|
||||
args[0].As<v8::Int32>()->Value(), ToVector(args[1].As<v8::String>())));
|
||||
}
|
||||
};
|
||||
|
||||
TaskRunner* UtilsExtension::backend_runner_ = nullptr;
|
||||
InspectorClientImpl* UtilsExtension::inspector_client_ = nullptr;
|
||||
|
||||
class SetTimeoutTask : public AsyncTask {
|
||||
public:
|
||||
SetTimeoutTask(v8::Isolate* isolate, v8::Local<v8::Function> function,
|
||||
const char* task_name, v8_inspector::V8Inspector* inspector)
|
||||
: AsyncTask(task_name, inspector), function_(isolate, function) {}
|
||||
SetTimeoutTask(IsolateData* data, int context_group_id, const char* task_name,
|
||||
v8::Local<v8::Function> function)
|
||||
: AsyncTask(data, task_name),
|
||||
function_(data->isolate(), function),
|
||||
context_group_id_(context_group_id) {}
|
||||
virtual ~SetTimeoutTask() {}
|
||||
|
||||
bool is_inspector_task() final { return false; }
|
||||
@ -307,7 +550,7 @@ class SetTimeoutTask : public AsyncTask {
|
||||
v8::MicrotasksScope microtasks_scope(isolate(),
|
||||
v8::MicrotasksScope::kRunMicrotasks);
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
v8::Local<v8::Context> context = default_context();
|
||||
v8::Local<v8::Context> context = data()->GetContext(context_group_id_);
|
||||
v8::Context::Scope context_scope(context);
|
||||
|
||||
v8::Local<v8::Function> function = function_.Get(isolate());
|
||||
@ -316,6 +559,7 @@ class SetTimeoutTask : public AsyncTask {
|
||||
}
|
||||
|
||||
v8::Global<v8::Function> function_;
|
||||
int context_group_id_;
|
||||
};
|
||||
|
||||
class SetTimeoutExtension : public IsolateData::SetupGlobalTask {
|
||||
@ -332,26 +576,27 @@ class SetTimeoutExtension : public IsolateData::SetupGlobalTask {
|
||||
if (args.Length() != 2 || !args[1]->IsNumber() ||
|
||||
(!args[0]->IsFunction() && !args[0]->IsString()) ||
|
||||
args[1].As<v8::Number>()->Value() != 0.0) {
|
||||
fprintf(stderr,
|
||||
"Internal error: only setTimeout(function, 0) is supported.");
|
||||
fprintf(
|
||||
stderr,
|
||||
"Internal error: only setTimeout(function|code, 0) is supported.");
|
||||
Exit();
|
||||
}
|
||||
v8::Isolate* isolate = args.GetIsolate();
|
||||
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
||||
IsolateData* data = IsolateData::FromContext(context);
|
||||
int context_group_id = data->GetContextGroupId(context);
|
||||
std::unique_ptr<TaskRunner::Task> task;
|
||||
v8_inspector::V8Inspector* inspector =
|
||||
InspectorClientImpl::InspectorFromContext(context);
|
||||
if (args[0]->IsFunction()) {
|
||||
task.reset(new SetTimeoutTask(isolate,
|
||||
v8::Local<v8::Function>::Cast(args[0]),
|
||||
"setTimeout", inspector));
|
||||
task.reset(new SetTimeoutTask(data, context_group_id, "setTimeout",
|
||||
v8::Local<v8::Function>::Cast(args[0])));
|
||||
} else {
|
||||
task.reset(new ExecuteStringTask(
|
||||
data, context_group_id, "setTimeout",
|
||||
ToVector(args[0].As<v8::String>()), v8::String::Empty(isolate),
|
||||
v8::Integer::New(isolate, 0), v8::Integer::New(isolate, 0),
|
||||
v8::Boolean::New(isolate, false), "setTimeout", inspector));
|
||||
v8::Boolean::New(isolate, false)));
|
||||
}
|
||||
IsolateData::FromContext(context)->task_runner()->Append(task.release());
|
||||
data->task_runner()->Append(task.release());
|
||||
}
|
||||
};
|
||||
|
||||
@ -368,12 +613,12 @@ class InspectorExtension : public IsolateData::SetupGlobalTask {
|
||||
void Run(v8::Isolate* isolate,
|
||||
v8::Local<v8::ObjectTemplate> global) override {
|
||||
v8::Local<v8::ObjectTemplate> inspector = v8::ObjectTemplate::New(isolate);
|
||||
inspector->Set(
|
||||
ToV8String(isolate, "attachInspector"),
|
||||
v8::FunctionTemplate::New(isolate, &InspectorExtension::Attach));
|
||||
inspector->Set(
|
||||
ToV8String(isolate, "detachInspector"),
|
||||
v8::FunctionTemplate::New(isolate, &InspectorExtension::Detach));
|
||||
inspector->Set(ToV8String(isolate, "fireContextCreated"),
|
||||
v8::FunctionTemplate::New(
|
||||
isolate, &InspectorExtension::FireContextCreated));
|
||||
inspector->Set(ToV8String(isolate, "fireContextDestroyed"),
|
||||
v8::FunctionTemplate::New(
|
||||
isolate, &InspectorExtension::FireContextDestroyed));
|
||||
inspector->Set(ToV8String(isolate, "setMaxAsyncTaskStacks"),
|
||||
v8::FunctionTemplate::New(
|
||||
isolate, &InspectorExtension::SetMaxAsyncTaskStacks));
|
||||
@ -398,29 +643,19 @@ class InspectorExtension : public IsolateData::SetupGlobalTask {
|
||||
}
|
||||
|
||||
private:
|
||||
static void Attach(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
v8::Isolate* isolate = args.GetIsolate();
|
||||
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
||||
v8_inspector::V8Inspector* inspector =
|
||||
InspectorClientImpl::InspectorFromContext(context);
|
||||
if (!inspector) {
|
||||
fprintf(stderr, "Inspector client not found - cannot attach!");
|
||||
Exit();
|
||||
}
|
||||
inspector->contextCreated(
|
||||
v8_inspector::V8ContextInfo(context, 1, v8_inspector::StringView()));
|
||||
static void FireContextCreated(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
|
||||
IsolateData* data = IsolateData::FromContext(context);
|
||||
data->inspector()->ContextCreated(context,
|
||||
data->GetContextGroupId(context));
|
||||
}
|
||||
|
||||
static void Detach(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
v8::Isolate* isolate = args.GetIsolate();
|
||||
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
||||
v8_inspector::V8Inspector* inspector =
|
||||
InspectorClientImpl::InspectorFromContext(context);
|
||||
if (!inspector) {
|
||||
fprintf(stderr, "Inspector client not found - cannot detach!");
|
||||
Exit();
|
||||
}
|
||||
inspector->contextDestroyed(context);
|
||||
static void FireContextDestroyed(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
|
||||
IsolateData* data = IsolateData::FromContext(context);
|
||||
data->inspector()->ContextDestroyed(context);
|
||||
}
|
||||
|
||||
static void SetMaxAsyncTaskStacks(
|
||||
@ -429,12 +664,11 @@ class InspectorExtension : public IsolateData::SetupGlobalTask {
|
||||
fprintf(stderr, "Internal error: setMaxAsyncTaskStacks(max).");
|
||||
Exit();
|
||||
}
|
||||
v8_inspector::V8Inspector* inspector =
|
||||
InspectorClientImpl::InspectorFromContext(
|
||||
args.GetIsolate()->GetCurrentContext());
|
||||
CHECK(inspector);
|
||||
v8_inspector::SetMaxAsyncTaskStacksForTest(
|
||||
inspector, args[0].As<v8::Int32>()->Value());
|
||||
IsolateData::FromContext(args.GetIsolate()->GetCurrentContext())
|
||||
->inspector()
|
||||
->inspector(),
|
||||
args[0].As<v8::Int32>()->Value());
|
||||
}
|
||||
|
||||
static void DumpAsyncTaskStacksStateForTest(
|
||||
@ -443,11 +677,10 @@ class InspectorExtension : public IsolateData::SetupGlobalTask {
|
||||
fprintf(stderr, "Internal error: dumpAsyncTaskStacksStateForTest().");
|
||||
Exit();
|
||||
}
|
||||
v8_inspector::V8Inspector* inspector =
|
||||
InspectorClientImpl::InspectorFromContext(
|
||||
args.GetIsolate()->GetCurrentContext());
|
||||
CHECK(inspector);
|
||||
v8_inspector::DumpAsyncTaskStacksStateForTest(inspector);
|
||||
v8_inspector::DumpAsyncTaskStacksStateForTest(
|
||||
IsolateData::FromContext(args.GetIsolate()->GetCurrentContext())
|
||||
->inspector()
|
||||
->inspector());
|
||||
}
|
||||
|
||||
static void BreakProgram(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
@ -455,16 +688,14 @@ class InspectorExtension : public IsolateData::SetupGlobalTask {
|
||||
fprintf(stderr, "Internal error: breakProgram('reason', 'details').");
|
||||
Exit();
|
||||
}
|
||||
v8_inspector::V8InspectorSession* session =
|
||||
InspectorClientImpl::SessionFromContext(
|
||||
args.GetIsolate()->GetCurrentContext());
|
||||
CHECK(session);
|
||||
|
||||
v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
|
||||
IsolateData* data = IsolateData::FromContext(context);
|
||||
v8::internal::Vector<uint16_t> reason = ToVector(args[0].As<v8::String>());
|
||||
v8_inspector::StringView reason_view(reason.start(), reason.length());
|
||||
v8::internal::Vector<uint16_t> details = ToVector(args[1].As<v8::String>());
|
||||
v8_inspector::StringView details_view(details.start(), details.length());
|
||||
session->breakProgram(reason_view, details_view);
|
||||
data->inspector()->BreakProgram(data->GetContextGroupId(context),
|
||||
reason_view, details_view);
|
||||
}
|
||||
|
||||
static void CreateObjectWithStrictCheck(
|
||||
@ -485,24 +716,23 @@ class InspectorExtension : public IsolateData::SetupGlobalTask {
|
||||
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
if (args.Length() != 3 || !args[0]->IsFunction() || !args[1]->IsString() ||
|
||||
!args[2]->IsString()) {
|
||||
fprintf(stderr, "Internal error: breakProgram('reason', 'details').");
|
||||
fprintf(stderr,
|
||||
"Internal error: callWithScheduledBreak('reason', 'details').");
|
||||
Exit();
|
||||
}
|
||||
v8_inspector::V8InspectorSession* session =
|
||||
InspectorClientImpl::SessionFromContext(
|
||||
args.GetIsolate()->GetCurrentContext());
|
||||
CHECK(session);
|
||||
|
||||
v8::internal::Vector<uint16_t> reason = ToVector(args[1].As<v8::String>());
|
||||
v8_inspector::StringView reason_view(reason.start(), reason.length());
|
||||
v8::internal::Vector<uint16_t> details = ToVector(args[2].As<v8::String>());
|
||||
v8_inspector::StringView details_view(details.start(), details.length());
|
||||
session->schedulePauseOnNextStatement(reason_view, details_view);
|
||||
v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
|
||||
IsolateData* data = IsolateData::FromContext(context);
|
||||
int context_group_id = data->GetContextGroupId(context);
|
||||
data->inspector()->SchedulePauseOnNextStatement(context_group_id,
|
||||
reason_view, details_view);
|
||||
v8::MaybeLocal<v8::Value> result;
|
||||
result = args[0].As<v8::Function>()->Call(context, context->Global(), 0,
|
||||
nullptr);
|
||||
session->cancelPauseOnNextStatement();
|
||||
data->inspector()->CancelPauseOnNextStatement(context_group_id);
|
||||
}
|
||||
|
||||
static void AllowAccessorFormatting(
|
||||
@ -524,68 +754,22 @@ class InspectorExtension : public IsolateData::SetupGlobalTask {
|
||||
}
|
||||
};
|
||||
|
||||
void UtilsExtension::CreateContextGroup(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
if (args.Length() != 0) {
|
||||
fprintf(stderr, "Internal error: createContextGroup().");
|
||||
Exit();
|
||||
}
|
||||
v8::base::Semaphore ready_semaphore(0);
|
||||
int context_group_id = 0;
|
||||
IsolateData::SetupGlobalTasks setup_global;
|
||||
setup_global.emplace_back(new SetTimeoutExtension());
|
||||
setup_global.emplace_back(new InspectorExtension());
|
||||
inspector_client_->scheduleCreateContextGroup(
|
||||
std::move(setup_global), &ready_semaphore, &context_group_id);
|
||||
ready_semaphore.Wait();
|
||||
args.GetReturnValue().Set(
|
||||
v8::Int32::New(args.GetIsolate(), context_group_id));
|
||||
}
|
||||
|
||||
v8::Local<v8::String> ToString(v8::Isolate* isolate,
|
||||
const v8_inspector::StringView& string) {
|
||||
if (string.is8Bit())
|
||||
return v8::String::NewFromOneByte(isolate, string.characters8(),
|
||||
v8::NewStringType::kNormal,
|
||||
static_cast<int>(string.length()))
|
||||
.ToLocalChecked();
|
||||
else
|
||||
return v8::String::NewFromTwoByte(isolate, string.characters16(),
|
||||
v8::NewStringType::kNormal,
|
||||
static_cast<int>(string.length()))
|
||||
.ToLocalChecked();
|
||||
}
|
||||
|
||||
class FrontendChannelImpl : public InspectorClientImpl::FrontendChannel {
|
||||
public:
|
||||
explicit FrontendChannelImpl(TaskRunner* frontend_task_runner)
|
||||
: frontend_task_runner_(frontend_task_runner) {}
|
||||
FrontendChannelImpl(TaskRunner* frontend_task_runner, int context_group_id)
|
||||
: frontend_task_runner_(frontend_task_runner),
|
||||
context_group_id_(context_group_id) {}
|
||||
virtual ~FrontendChannelImpl() {}
|
||||
|
||||
void SendMessageToFrontend(const v8_inspector::StringView& message) final {
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
v8::HandleScope scope(v8::Isolate::GetCurrent());
|
||||
|
||||
v8::Local<v8::String> prefix =
|
||||
v8::String::NewFromUtf8(isolate, "InspectorTest._dispatchMessage(",
|
||||
v8::NewStringType::kInternalized)
|
||||
.ToLocalChecked();
|
||||
v8::Local<v8::String> message_string = ToString(isolate, message);
|
||||
v8::Local<v8::String> suffix =
|
||||
v8::String::NewFromUtf8(isolate, ")", v8::NewStringType::kInternalized)
|
||||
.ToLocalChecked();
|
||||
|
||||
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),
|
||||
v8::Boolean::New(isolate, false), nullptr, nullptr));
|
||||
void SendMessageToFrontend(int session_id,
|
||||
const v8_inspector::StringView& message) final {
|
||||
frontend_task_runner_->Append(new SendMessageToFrontendTask(
|
||||
context_group_id_, session_id, ToVector(message)));
|
||||
}
|
||||
|
||||
private:
|
||||
TaskRunner* frontend_task_runner_;
|
||||
int context_group_id_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@ -610,29 +794,28 @@ int main(int argc, char* argv[]) {
|
||||
}
|
||||
}
|
||||
|
||||
IsolateData::SetupGlobalTasks frontend_extensions;
|
||||
frontend_extensions.emplace_back(new UtilsExtension());
|
||||
TaskRunner frontend_runner(std::move(frontend_extensions), true,
|
||||
&ready_semaphore, nullptr, nullptr);
|
||||
ready_semaphore.Wait();
|
||||
|
||||
int frontend_context_group_id = 0;
|
||||
frontend_runner.Append(
|
||||
new CreateContextGroupTask(&ready_semaphore, &frontend_context_group_id));
|
||||
ready_semaphore.Wait();
|
||||
|
||||
IsolateData::SetupGlobalTasks backend_extensions;
|
||||
backend_extensions.emplace_back(new SetTimeoutExtension());
|
||||
backend_extensions.emplace_back(new InspectorExtension());
|
||||
TaskRunner backend_runner(std::move(backend_extensions), false,
|
||||
&ready_semaphore,
|
||||
startup_data.data ? &startup_data : nullptr);
|
||||
FrontendChannelImpl frontend_channel(&frontend_runner,
|
||||
frontend_context_group_id);
|
||||
TaskRunner backend_runner(
|
||||
std::move(backend_extensions), false, &ready_semaphore,
|
||||
startup_data.data ? &startup_data : nullptr, &frontend_channel);
|
||||
ready_semaphore.Wait();
|
||||
SendMessageToBackendExtension::set_backend_task_runner(&backend_runner);
|
||||
UtilsExtension::set_backend_task_runner(&backend_runner);
|
||||
|
||||
IsolateData::SetupGlobalTasks frontend_extensions;
|
||||
frontend_extensions.emplace_back(new UtilsExtension());
|
||||
frontend_extensions.emplace_back(new SendMessageToBackendExtension());
|
||||
TaskRunner frontend_runner(std::move(frontend_extensions), true,
|
||||
&ready_semaphore, nullptr);
|
||||
ready_semaphore.Wait();
|
||||
|
||||
FrontendChannelImpl frontend_channel(&frontend_runner);
|
||||
InspectorClientImpl inspector_client(&backend_runner, &frontend_channel,
|
||||
&ready_semaphore);
|
||||
ready_semaphore.Wait();
|
||||
UtilsExtension::set_inspector_client(&inspector_client);
|
||||
|
||||
task_runners.push_back(&frontend_runner);
|
||||
task_runners.push_back(&backend_runner);
|
||||
|
||||
@ -648,7 +831,8 @@ int main(int argc, char* argv[]) {
|
||||
argv[i]);
|
||||
Exit();
|
||||
}
|
||||
frontend_runner.Append(new ExecuteStringTask(chars));
|
||||
frontend_runner.Append(
|
||||
new ExecuteStringTask(chars, frontend_context_group_id));
|
||||
}
|
||||
|
||||
frontend_runner.Join();
|
||||
|
@ -10,6 +10,7 @@
|
||||
namespace {
|
||||
|
||||
const int kIsolateDataIndex = 2;
|
||||
const int kContextGroupIdIndex = 3;
|
||||
|
||||
v8::internal::Vector<uint16_t> ToVector(v8::Local<v8::String> str) {
|
||||
v8::internal::Vector<uint16_t> buffer =
|
||||
@ -22,7 +23,8 @@ v8::internal::Vector<uint16_t> ToVector(v8::Local<v8::String> str) {
|
||||
|
||||
IsolateData::IsolateData(TaskRunner* task_runner,
|
||||
IsolateData::SetupGlobalTasks setup_global_tasks,
|
||||
v8::StartupData* startup_data)
|
||||
v8::StartupData* startup_data,
|
||||
InspectorClientImpl::FrontendChannel* channel)
|
||||
: task_runner_(task_runner),
|
||||
setup_global_tasks_(std::move(setup_global_tasks)) {
|
||||
v8::Isolate::CreateParams params;
|
||||
@ -31,6 +33,8 @@ IsolateData::IsolateData(TaskRunner* task_runner,
|
||||
params.snapshot_blob = startup_data;
|
||||
isolate_ = v8::Isolate::New(params);
|
||||
isolate_->SetMicrotasksPolicy(v8::MicrotasksPolicy::kScoped);
|
||||
if (channel)
|
||||
inspector_.reset(new InspectorClientImpl(isolate_, task_runner, channel));
|
||||
}
|
||||
|
||||
IsolateData* IsolateData::FromContext(v8::Local<v8::Context> context) {
|
||||
@ -39,6 +43,7 @@ IsolateData* IsolateData::FromContext(v8::Local<v8::Context> context) {
|
||||
}
|
||||
|
||||
int IsolateData::CreateContextGroup() {
|
||||
v8::HandleScope handle_scope(isolate_);
|
||||
v8::Local<v8::ObjectTemplate> global_template =
|
||||
v8::ObjectTemplate::New(isolate_);
|
||||
for (auto it = setup_global_tasks_.begin(); it != setup_global_tasks_.end();
|
||||
@ -49,7 +54,11 @@ int IsolateData::CreateContextGroup() {
|
||||
v8::Context::New(isolate_, nullptr, global_template);
|
||||
context->SetAlignedPointerInEmbedderData(kIsolateDataIndex, this);
|
||||
int context_group_id = ++last_context_group_id_;
|
||||
// Should be 2-byte aligned.
|
||||
context->SetAlignedPointerInEmbedderData(
|
||||
kContextGroupIdIndex, reinterpret_cast<void*>(context_group_id * 2));
|
||||
contexts_[context_group_id].Reset(isolate_, context);
|
||||
if (inspector_) inspector_->ContextCreated(context, context_group_id);
|
||||
return context_group_id;
|
||||
}
|
||||
|
||||
@ -57,6 +66,13 @@ v8::Local<v8::Context> IsolateData::GetContext(int context_group_id) {
|
||||
return contexts_[context_group_id].Get(isolate_);
|
||||
}
|
||||
|
||||
int IsolateData::GetContextGroupId(v8::Local<v8::Context> context) {
|
||||
return static_cast<int>(
|
||||
reinterpret_cast<intptr_t>(
|
||||
context->GetAlignedPointerFromEmbedderData(kContextGroupIdIndex)) /
|
||||
2);
|
||||
}
|
||||
|
||||
void IsolateData::RegisterModule(v8::Local<v8::Context> context,
|
||||
v8::internal::Vector<uint16_t> name,
|
||||
v8::ScriptCompiler::Source* source) {
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "include/v8-platform.h"
|
||||
#include "include/v8.h"
|
||||
#include "src/vector.h"
|
||||
#include "test/inspector/inspector-impl.h"
|
||||
|
||||
class TaskRunner;
|
||||
|
||||
@ -25,13 +26,16 @@ class IsolateData {
|
||||
using SetupGlobalTasks = std::vector<std::unique_ptr<SetupGlobalTask>>;
|
||||
|
||||
IsolateData(TaskRunner* task_runner, SetupGlobalTasks setup_global_tasks,
|
||||
v8::StartupData* startup_data);
|
||||
v8::StartupData* startup_data,
|
||||
InspectorClientImpl::FrontendChannel* channel);
|
||||
static IsolateData* FromContext(v8::Local<v8::Context> context);
|
||||
|
||||
v8::Isolate* isolate() const { return isolate_; }
|
||||
InspectorClientImpl* inspector() const { return inspector_.get(); }
|
||||
TaskRunner* task_runner() const { return task_runner_; }
|
||||
int CreateContextGroup();
|
||||
v8::Local<v8::Context> GetContext(int context_group_id);
|
||||
int GetContextGroupId(v8::Local<v8::Context> context);
|
||||
void RegisterModule(v8::Local<v8::Context> context,
|
||||
v8::internal::Vector<uint16_t> name,
|
||||
v8::ScriptCompiler::Source* source);
|
||||
@ -53,6 +57,7 @@ class IsolateData {
|
||||
TaskRunner* task_runner_;
|
||||
SetupGlobalTasks setup_global_tasks_;
|
||||
v8::Isolate* isolate_;
|
||||
std::unique_ptr<InspectorClientImpl> inspector_;
|
||||
int last_context_group_id_ = 0;
|
||||
std::map<int, v8::Global<v8::Context>> contexts_;
|
||||
std::map<v8::internal::Vector<uint16_t>, v8::Global<v8::Module>,
|
||||
|
@ -2,9 +2,9 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
const id = ++InspectorTest._requestId;
|
||||
const id = ++InspectorTest.session._requestId;
|
||||
var command = { "method": "Runtime.evaluate", "params": { expression: "\"!!!\"" }, "id": id };
|
||||
InspectorTest.sendRawCommand(id, JSON.stringify(command).replace("!!!", "\\u041F\\u0440\\u0438\\u0432\\u0435\\u0442 \\u043C\\u0438\\u0440"), step2);
|
||||
InspectorTest.session.sendRawCommand(id, JSON.stringify(command).replace("!!!", "\\u041F\\u0440\\u0438\\u0432\\u0435\\u0442 \\u043C\\u0438\\u0440"), step2);
|
||||
|
||||
function step2(msg)
|
||||
{
|
||||
|
@ -3,33 +3,102 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
InspectorTest = {};
|
||||
InspectorTest._dispatchTable = new Map();
|
||||
InspectorTest._requestId = 0;
|
||||
InspectorTest._dumpInspectorProtocolMessages = false;
|
||||
InspectorTest._eventHandler = {};
|
||||
InspectorTest._commandsForLogging = new Set();
|
||||
|
||||
Protocol = new Proxy({}, {
|
||||
get: function(target, agentName, receiver) {
|
||||
return new Proxy({}, {
|
||||
get: function(target, methodName, receiver) {
|
||||
const eventPattern = /^on(ce)?([A-Z][A-Za-z0-9]+)/;
|
||||
var match = eventPattern.exec(methodName);
|
||||
if (!match) {
|
||||
return (args, contextGroupId) => InspectorTest._sendCommandPromise(`${agentName}.${methodName}`, args || {}, contextGroupId);
|
||||
} else {
|
||||
var eventName = match[2];
|
||||
eventName = eventName.charAt(0).toLowerCase() + eventName.slice(1);
|
||||
if (match[1])
|
||||
return () => InspectorTest._waitForEventPromise(
|
||||
`${agentName}.${eventName}`);
|
||||
else
|
||||
return (listener) => { InspectorTest._eventHandler[`${agentName}.${eventName}`] = listener };
|
||||
InspectorTest.createContextGroup = function() {
|
||||
var contextGroup = {};
|
||||
contextGroup.id = utils.createContextGroup();
|
||||
contextGroup.schedulePauseOnNextStatement = (reason, details) => utils.schedulePauseOnNextStatement(contextGroup.id, reason, details);
|
||||
contextGroup.cancelPauseOnNextStatement = () => utils.cancelPauseOnNextStatement(contextGroup.id);
|
||||
contextGroup.addScript = (string, lineOffset, columnOffset, url) => utils.compileAndRunWithOrigin(contextGroup.id, string, url || '', lineOffset || 0, columnOffset || 0, false);
|
||||
contextGroup.addModule = (string, url, lineOffset, columnOffset) => utils.compileAndRunWithOrigin(contextGroup.id, string, url, lineOffset || 0, columnOffset || 0, true);
|
||||
return contextGroup;
|
||||
}
|
||||
|
||||
InspectorTest._sessions = new Map();
|
||||
InspectorTest.createSession = function(contextGroup) {
|
||||
var session = {
|
||||
contextGroup: contextGroup,
|
||||
_dispatchTable: new Map(),
|
||||
_eventHandler: {},
|
||||
_requestId: 0,
|
||||
};
|
||||
session.Protocol = new Proxy({}, {
|
||||
get: function(target, agentName, receiver) {
|
||||
return new Proxy({}, {
|
||||
get: function(target, methodName, receiver) {
|
||||
const eventPattern = /^on(ce)?([A-Z][A-Za-z0-9]+)/;
|
||||
var match = eventPattern.exec(methodName);
|
||||
if (!match) {
|
||||
return args => session._sendCommandPromise(`${agentName}.${methodName}`, args || {});
|
||||
} else {
|
||||
var eventName = match[2];
|
||||
eventName = eventName.charAt(0).toLowerCase() + eventName.slice(1);
|
||||
if (match[1])
|
||||
return () => InspectorTest._waitForEventPromise(session, `${agentName}.${eventName}`);
|
||||
else
|
||||
return (listener) => { session._eventHandler[`${agentName}.${eventName}`] = listener };
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
session._dispatchMessage = messageString => {
|
||||
let messageObject = JSON.parse(messageString);
|
||||
if (InspectorTest._dumpInspectorProtocolMessages)
|
||||
utils.print("backend: " + JSON.stringify(messageObject));
|
||||
try {
|
||||
var messageId = messageObject["id"];
|
||||
if (typeof messageId === "number") {
|
||||
var handler = session._dispatchTable.get(messageId);
|
||||
if (handler) {
|
||||
handler(messageObject);
|
||||
session._dispatchTable.delete(messageId);
|
||||
}
|
||||
} else {
|
||||
var eventName = messageObject["method"];
|
||||
var eventHandler = session._eventHandler[eventName];
|
||||
if (session._scriptMap && eventName === "Debugger.scriptParsed")
|
||||
session._scriptMap.set(messageObject.params.scriptId, JSON.parse(JSON.stringify(messageObject.params)));
|
||||
if (eventName === "Debugger.scriptParsed" && messageObject.params.url === "wait-pending-tasks.js")
|
||||
return;
|
||||
if (eventHandler)
|
||||
eventHandler(messageObject);
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
InspectorTest.log("Exception when dispatching message: " + e + "\n" + e.stack + "\n message = " + JSON.stringify(messageObject, null, 2));
|
||||
InspectorTest.completeTest();
|
||||
}
|
||||
};
|
||||
session.id = utils.connectSession(contextGroup.id, '', session._dispatchMessage.bind(session));
|
||||
InspectorTest._sessions.set(session.id, session);
|
||||
session.disconnect = () => utils.disconnectSession(session.id);
|
||||
session.reconnect = () => {
|
||||
InspectorTest._sessions.delete(session.id);
|
||||
var state = utils.disconnectSession(session.id);
|
||||
session.id = utils.connectSession(contextGroup.id, state, session._dispatchMessage.bind(session));
|
||||
InspectorTest._sessions.set(session.id, session);
|
||||
};
|
||||
session.sendRawCommand = (requestId, command, handler) => {
|
||||
if (InspectorTest._dumpInspectorProtocolMessages)
|
||||
utils.print("frontend: " + command);
|
||||
session._dispatchTable.set(requestId, handler);
|
||||
utils.sendMessageToBackend(session.id, command);
|
||||
}
|
||||
});
|
||||
session._sendCommandPromise = (method, params) => {
|
||||
var requestId = ++session._requestId;
|
||||
var messageObject = { "id": requestId, "method": method, "params": params };
|
||||
var fulfillCallback;
|
||||
var promise = new Promise(fulfill => fulfillCallback = fulfill);
|
||||
if (InspectorTest._commandsForLogging.has(method)) {
|
||||
utils.print(method + ' called');
|
||||
}
|
||||
session.sendRawCommand(requestId, JSON.stringify(messageObject), fulfillCallback);
|
||||
return promise;
|
||||
}
|
||||
return session;
|
||||
}
|
||||
|
||||
InspectorTest.logProtocolCommandCalls = (command) => InspectorTest._commandsForLogging.add(command);
|
||||
|
||||
@ -108,28 +177,29 @@ InspectorTest.logObject = function(object, title)
|
||||
InspectorTest.log(lines.join("\n"));
|
||||
}
|
||||
|
||||
InspectorTest.logCallFrames = function(callFrames)
|
||||
InspectorTest.logCallFrames = function(callFrames, session)
|
||||
{
|
||||
session = session || InspectorTest.session;
|
||||
for (var frame of callFrames) {
|
||||
var functionName = frame.functionName || '(anonymous)';
|
||||
var url = frame.url ? frame.url : InspectorTest._scriptMap.get(frame.location.scriptId).url;
|
||||
var url = frame.url ? frame.url : session._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.logSourceLocation = function(location)
|
||||
InspectorTest.logSourceLocation = function(location, session)
|
||||
{
|
||||
session = session || InspectorTest.session;
|
||||
var scriptId = location.scriptId;
|
||||
if (!InspectorTest._scriptMap || !InspectorTest._scriptMap.has(scriptId)) {
|
||||
if (!session._scriptMap || !session._scriptMap.has(scriptId)) {
|
||||
InspectorTest.log("InspectorTest.setupScriptMap should be called before Protocol.Debugger.enable.");
|
||||
InspectorTest.completeTest();
|
||||
}
|
||||
var script = InspectorTest._scriptMap.get(scriptId);
|
||||
var script = session._scriptMap.get(scriptId);
|
||||
if (!script.scriptSource) {
|
||||
// TODO(kozyatinskiy): doesn't assume that contextId == contextGroupId.
|
||||
return Protocol.Debugger.getScriptSource({ scriptId }, script.executionContextId)
|
||||
return session.Protocol.Debugger.getScriptSource({ scriptId })
|
||||
.then(message => script.scriptSource = message.result.scriptSource)
|
||||
.then(dumpSourceWithLocation);
|
||||
}
|
||||
@ -146,14 +216,15 @@ InspectorTest.logSourceLocation = function(location)
|
||||
}
|
||||
}
|
||||
|
||||
InspectorTest.logSourceLocations = function(locations) {
|
||||
InspectorTest.logSourceLocations = function(locations, session) {
|
||||
if (locations.length == 0) return Promise.resolve();
|
||||
return InspectorTest.logSourceLocation(locations[0])
|
||||
.then(() => InspectorTest.logSourceLocations(locations.splice(1)));
|
||||
return InspectorTest.logSourceLocation(locations[0], session)
|
||||
.then(() => InspectorTest.logSourceLocations(locations.splice(1), session));
|
||||
}
|
||||
|
||||
InspectorTest.logAsyncStackTrace = function(asyncStackTrace)
|
||||
InspectorTest.logAsyncStackTrace = function(asyncStackTrace, session)
|
||||
{
|
||||
session = InspectorTest.session || session;
|
||||
while (asyncStackTrace) {
|
||||
if (asyncStackTrace.promiseCreationFrame) {
|
||||
var frame = asyncStackTrace.promiseCreationFrame;
|
||||
@ -162,7 +233,7 @@ InspectorTest.logAsyncStackTrace = function(asyncStackTrace)
|
||||
} else {
|
||||
InspectorTest.log(`-- ${asyncStackTrace.description} --`);
|
||||
}
|
||||
InspectorTest.logCallFrames(asyncStackTrace.callFrames);
|
||||
InspectorTest.logCallFrames(asyncStackTrace.callFrames, session);
|
||||
asyncStackTrace = asyncStackTrace.parent;
|
||||
}
|
||||
}
|
||||
@ -176,26 +247,17 @@ InspectorTest.completeTestAfterPendingTimeouts = function()
|
||||
|
||||
InspectorTest.waitPendingTasks = function()
|
||||
{
|
||||
return Protocol.Runtime.evaluate({ expression: "new Promise(r => setTimeout(r, 0))//# sourceURL=wait-pending-tasks.js", awaitPromise: true });
|
||||
var promises = [];
|
||||
for (var session of InspectorTest._sessions.values())
|
||||
promises.push(session.Protocol.Runtime.evaluate({ expression: "new Promise(r => setTimeout(r, 0))//# sourceURL=wait-pending-tasks.js", awaitPromise: true }));
|
||||
return Promise.all(promises);
|
||||
}
|
||||
|
||||
InspectorTest.addScript = (string, lineOffset, columnOffset) => utils.compileAndRunWithOrigin(string, "", lineOffset || 0, columnOffset || 0, false);
|
||||
InspectorTest.addScriptWithUrl = (string, url) => utils.compileAndRunWithOrigin(string, url, 0, 0, false);
|
||||
InspectorTest.addModule = (string, url, lineOffset, columnOffset) => utils.compileAndRunWithOrigin(string, url, lineOffset || 0, columnOffset || 0, true);
|
||||
|
||||
InspectorTest.startDumpingProtocolMessages = function()
|
||||
{
|
||||
InspectorTest._dumpInspectorProtocolMessages = true;
|
||||
}
|
||||
|
||||
InspectorTest.sendRawCommand = function(requestId, command, handler, contextGroupId)
|
||||
{
|
||||
if (InspectorTest._dumpInspectorProtocolMessages)
|
||||
utils.print("frontend: " + command);
|
||||
InspectorTest._dispatchTable.set(requestId, handler);
|
||||
sendMessageToBackend(command, contextGroupId || 0);
|
||||
}
|
||||
|
||||
InspectorTest.checkExpectation = function(fail, name, messageObject)
|
||||
{
|
||||
if (fail === !!messageObject.error) {
|
||||
@ -210,10 +272,11 @@ 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)
|
||||
InspectorTest.setupScriptMap = function(session) {
|
||||
session = session || InspectorTest.session;
|
||||
if (session._scriptMap)
|
||||
return;
|
||||
InspectorTest._scriptMap = new Map();
|
||||
session._scriptMap = new Map();
|
||||
}
|
||||
|
||||
InspectorTest.runTestSuite = function(testSuite)
|
||||
@ -234,68 +297,28 @@ InspectorTest.runTestSuite = function(testSuite)
|
||||
InspectorTest.runAsyncTestSuite = async function(testSuite) {
|
||||
for (var test of testSuite) {
|
||||
InspectorTest.log("\nRunning test: " + test.name);
|
||||
await test();
|
||||
try {
|
||||
await test();
|
||||
} catch (e) {
|
||||
utils.print(e.stack);
|
||||
}
|
||||
}
|
||||
InspectorTest.completeTest();
|
||||
}
|
||||
|
||||
InspectorTest._sendCommandPromise = function(method, params, contextGroupId)
|
||||
InspectorTest._waitForEventPromise = function(session, eventName)
|
||||
{
|
||||
var requestId = ++InspectorTest._requestId;
|
||||
var messageObject = { "id": requestId, "method": method, "params": params };
|
||||
var fulfillCallback;
|
||||
var promise = new Promise(fulfill => fulfillCallback = fulfill);
|
||||
if (InspectorTest._commandsForLogging.has(method)) {
|
||||
utils.print(method + ' called');
|
||||
}
|
||||
InspectorTest.sendRawCommand(requestId, JSON.stringify(messageObject), fulfillCallback, contextGroupId);
|
||||
return promise;
|
||||
}
|
||||
|
||||
InspectorTest._waitForEventPromise = function(eventName)
|
||||
{
|
||||
return new Promise(fulfill => InspectorTest._eventHandler[eventName] = fullfillAndClearListener.bind(null, fulfill));
|
||||
return new Promise(fulfill => session._eventHandler[eventName] = fullfillAndClearListener.bind(null, fulfill));
|
||||
|
||||
function fullfillAndClearListener(fulfill, result)
|
||||
{
|
||||
delete InspectorTest._eventHandler[eventName];
|
||||
delete session._eventHandler[eventName];
|
||||
fulfill(result);
|
||||
}
|
||||
}
|
||||
|
||||
InspectorTest._dispatchMessage = function(messageObject)
|
||||
{
|
||||
if (InspectorTest._dumpInspectorProtocolMessages)
|
||||
utils.print("backend: " + JSON.stringify(messageObject));
|
||||
try {
|
||||
var messageId = messageObject["id"];
|
||||
if (typeof messageId === "number") {
|
||||
var handler = InspectorTest._dispatchTable.get(messageId);
|
||||
if (handler) {
|
||||
handler(messageObject);
|
||||
InspectorTest._dispatchTable.delete(messageId);
|
||||
}
|
||||
} 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 (eventName === "Debugger.scriptParsed" && messageObject.params.url === "wait-pending-tasks.js")
|
||||
return;
|
||||
if (eventHandler)
|
||||
eventHandler(messageObject);
|
||||
}
|
||||
} catch (e) {
|
||||
InspectorTest.log("Exception when dispatching message: " + e + "\n" + e.stack + "\n message = " + JSON.stringify(messageObject, null, 2));
|
||||
InspectorTest.completeTest();
|
||||
}
|
||||
}
|
||||
|
||||
InspectorTest.loadScript = function(fileName) {
|
||||
InspectorTest.addScript(utils.read(fileName));
|
||||
}
|
||||
|
||||
InspectorTest.setupInjectedScriptEnvironment = function(debug) {
|
||||
InspectorTest.setupInjectedScriptEnvironment = function(debug, session) {
|
||||
session = session || InspectorTest.session;
|
||||
let scriptSource = '';
|
||||
// First define all getters on Object.prototype.
|
||||
let injectedScriptSource = utils.read('src/inspector/injected-script-source.js');
|
||||
@ -314,17 +337,28 @@ InspectorTest.setupInjectedScriptEnvironment = function(debug) {
|
||||
__proto__: null
|
||||
});
|
||||
`).join('\n') + '})();';
|
||||
InspectorTest.addScript(scriptSource);
|
||||
session.contextGroup.addScript(scriptSource);
|
||||
|
||||
if (debug) {
|
||||
InspectorTest.log('WARNING: InspectorTest.setupInjectedScriptEnvironment with debug flag for debugging only and should not be landed.');
|
||||
InspectorTest.log('WARNING: run test with --expose-inspector-scripts flag to get more details.');
|
||||
InspectorTest.log('WARNING: you can additionally comment rjsmin in xxd.py to get unminified injected-script-source.js.');
|
||||
InspectorTest.setupScriptMap();
|
||||
Protocol.Debugger.enable();
|
||||
Protocol.Debugger.onPaused(message => {
|
||||
InspectorTest.setupScriptMap(session);
|
||||
sesison.Protocol.Debugger.enable();
|
||||
session.Protocol.Debugger.onPaused(message => {
|
||||
let callFrames = message.params.callFrames;
|
||||
InspectorTest.logSourceLocations(callFrames.map(frame => frame.location));
|
||||
InspectorTest.logSourceLocations(callFrames.map(frame => frame.location), session);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
InspectorTest.contextGroup = InspectorTest.createContextGroup();
|
||||
InspectorTest.session = InspectorTest.createSession(InspectorTest.contextGroup);
|
||||
this.Protocol = InspectorTest.session.Protocol;
|
||||
InspectorTest.addScript = InspectorTest.contextGroup.addScript.bind(InspectorTest.contextGroup);
|
||||
InspectorTest.addModule = InspectorTest.contextGroup.addModule.bind(InspectorTest.contextGroup);
|
||||
InspectorTest.loadScript = fileName => InspectorTest.addScript(utils.read(fileName));
|
||||
} catch (e) {
|
||||
utils.print(e.stack);
|
||||
}
|
||||
|
@ -4,24 +4,20 @@
|
||||
|
||||
InspectorTest.log('Checks createContext().');
|
||||
|
||||
InspectorTest.setupScriptMap();
|
||||
Protocol.Runtime.onExecutionContextCreated(InspectorTest.logMessage);
|
||||
Protocol.Debugger.onPaused((message) => {
|
||||
InspectorTest.logSourceLocation(message.params.callFrames[0].location);
|
||||
Protocol.Debugger.stepOut();
|
||||
});
|
||||
var executionContextIds = new Set();
|
||||
Protocol.Debugger.onScriptParsed(message => executionContextIds.add(message.params.executionContextId));
|
||||
var contextGroupId;
|
||||
var contextGroup = InspectorTest.createContextGroup();
|
||||
var session = InspectorTest.createSession(contextGroup);
|
||||
setup(InspectorTest.session);
|
||||
setup(session);
|
||||
|
||||
Protocol.Runtime.enable()
|
||||
.then(() => contextGroupId = utils.createContextGroup())
|
||||
.then(() => Protocol.Runtime.enable({}, contextGroupId))
|
||||
.then(() => session.Protocol.Runtime.enable({}))
|
||||
.then(() => Protocol.Debugger.enable())
|
||||
.then(() => Protocol.Debugger.enable({}, contextGroupId))
|
||||
.then(() => session.Protocol.Debugger.enable({}))
|
||||
.then(InspectorTest.logMessage)
|
||||
.then(() => {
|
||||
Protocol.Runtime.evaluate({ expression: 'debugger;' })
|
||||
Protocol.Runtime.evaluate({ expression: 'setTimeout(x => x * 2, 0)' }, contextGroupId);
|
||||
Protocol.Runtime.evaluate({ expression: 'debugger;' });
|
||||
session.Protocol.Runtime.evaluate({expression: 'setTimeout(x => x * 2, 0)'});
|
||||
Protocol.Runtime.evaluate({ expression: 'setTimeout(x => x * 3, 0)' });
|
||||
})
|
||||
.then(() => InspectorTest.waitPendingTasks())
|
||||
@ -29,14 +25,25 @@ Protocol.Runtime.enable()
|
||||
InspectorTest.log(`Reported script's execution id: ${executionContextIds.size}`);
|
||||
executionContextIds.clear();
|
||||
})
|
||||
.then(() => utils.reconnect())
|
||||
.then(() => InspectorTest.session.reconnect())
|
||||
.then(() => session.reconnect())
|
||||
.then(() => {
|
||||
Protocol.Runtime.evaluate({ expression: 'debugger;' })
|
||||
Protocol.Runtime.evaluate({ expression: 'setTimeout(x => x * 2, 0)' }, contextGroupId);
|
||||
session.Protocol.Runtime.evaluate({ expression: 'setTimeout(x => x * 2, 0)' });
|
||||
Protocol.Runtime.evaluate({ expression: 'setTimeout(x => x * 3, 0)' });
|
||||
})
|
||||
.then(() => InspectorTest.waitPendingTasks())
|
||||
.then(() => Protocol.Debugger.disable({}, contextGroupId))
|
||||
.then(() => session.Protocol.Debugger.disable({}))
|
||||
.then(() => Protocol.Debugger.disable({}))
|
||||
.then(() => InspectorTest.log(`Reported script's execution id: ${executionContextIds.size}`))
|
||||
.then(InspectorTest.completeTest);
|
||||
|
||||
function setup(session) {
|
||||
session.Protocol.Runtime.onExecutionContextCreated(InspectorTest.logMessage);
|
||||
InspectorTest.setupScriptMap(session);
|
||||
session.Protocol.Debugger.onPaused((message) => {
|
||||
InspectorTest.logSourceLocation(message.params.callFrames[0].location, session);
|
||||
session.Protocol.Debugger.stepOut();
|
||||
});
|
||||
session.Protocol.Debugger.onScriptParsed(message => executionContextIds.add(message.params.executionContextId));
|
||||
}
|
||||
|
@ -56,9 +56,9 @@ InspectorTest.runTestSuite([
|
||||
|
||||
function testSetCustomObjectFormatterEnabled(next) {
|
||||
Protocol.Runtime.onConsoleAPICalled(InspectorTest.logMessage);
|
||||
// cleanup console message storage
|
||||
reconnect();
|
||||
Protocol.Runtime.enable()
|
||||
Protocol.Runtime.discardConsoleEntries()
|
||||
.then(reconnect)
|
||||
.then(() => Protocol.Runtime.enable())
|
||||
.then(() => Protocol.Runtime.setCustomObjectFormatterEnabled({ enabled: true }))
|
||||
.then(reconnect)
|
||||
.then(() => Protocol.Runtime.evaluate({ expression: 'console.log({ name: 42 })'}))
|
||||
@ -73,5 +73,5 @@ InspectorTest.runTestSuite([
|
||||
|
||||
function reconnect() {
|
||||
InspectorTest.logMessage('will reconnect..');
|
||||
utils.reconnect();
|
||||
InspectorTest.session.reconnect();
|
||||
}
|
||||
|
@ -17,7 +17,15 @@ void ReportUncaughtException(v8::Isolate* isolate,
|
||||
CHECK(try_catch.HasCaught());
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
std::string message = *v8::String::Utf8Value(try_catch.Message()->Get());
|
||||
fprintf(stderr, "Unhandle exception: %s\n", message.data());
|
||||
int line = try_catch.Message()
|
||||
->GetLineNumber(isolate->GetCurrentContext())
|
||||
.FromJust();
|
||||
std::string source_line =
|
||||
*v8::String::Utf8Value(try_catch.Message()
|
||||
->GetSourceLine(isolate->GetCurrentContext())
|
||||
.ToLocalChecked());
|
||||
fprintf(stderr, "Unhandle exception: %s @%s[%d]\n", message.data(),
|
||||
source_line.data(), line);
|
||||
}
|
||||
|
||||
v8::internal::Vector<uint16_t> ToVector(v8::Local<v8::String> str) {
|
||||
@ -32,10 +40,12 @@ v8::internal::Vector<uint16_t> ToVector(v8::Local<v8::String> str) {
|
||||
TaskRunner::TaskRunner(IsolateData::SetupGlobalTasks setup_global_tasks,
|
||||
bool catch_exceptions,
|
||||
v8::base::Semaphore* ready_semaphore,
|
||||
v8::StartupData* startup_data)
|
||||
v8::StartupData* startup_data,
|
||||
InspectorClientImpl::FrontendChannel* channel)
|
||||
: Thread(Options("Task Runner")),
|
||||
setup_global_tasks_(std::move(setup_global_tasks)),
|
||||
startup_data_(startup_data),
|
||||
channel_(channel),
|
||||
catch_exceptions_(catch_exceptions),
|
||||
ready_semaphore_(ready_semaphore),
|
||||
data_(nullptr),
|
||||
@ -47,13 +57,8 @@ TaskRunner::TaskRunner(IsolateData::SetupGlobalTasks setup_global_tasks,
|
||||
TaskRunner::~TaskRunner() { Join(); }
|
||||
|
||||
void TaskRunner::Run() {
|
||||
data_.reset(
|
||||
new IsolateData(this, std::move(setup_global_tasks_), startup_data_));
|
||||
|
||||
v8::Isolate::Scope isolate_scope(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
default_context_group_id_ = data_->CreateContextGroup();
|
||||
|
||||
data_.reset(new IsolateData(this, std::move(setup_global_tasks_),
|
||||
startup_data_, channel_));
|
||||
if (ready_semaphore_) ready_semaphore_->Signal();
|
||||
RunMessageLoop(false);
|
||||
}
|
||||
@ -66,7 +71,7 @@ void TaskRunner::RunMessageLoop(bool only_protocol) {
|
||||
v8::Isolate::Scope isolate_scope(isolate());
|
||||
if (catch_exceptions_) {
|
||||
v8::TryCatch try_catch(isolate());
|
||||
task->RunOnTaskRunner(this);
|
||||
task->RunOnIsolate(data_.get());
|
||||
delete task;
|
||||
if (try_catch.HasCaught()) {
|
||||
ReportUncaughtException(isolate(), try_catch);
|
||||
@ -75,7 +80,7 @@ void TaskRunner::RunMessageLoop(bool only_protocol) {
|
||||
_exit(0);
|
||||
}
|
||||
} else {
|
||||
task->RunOnTaskRunner(this);
|
||||
task->RunOnIsolate(data_.get());
|
||||
delete task;
|
||||
}
|
||||
}
|
||||
@ -115,44 +120,45 @@ TaskRunner::Task* TaskRunner::GetNext(bool only_protocol) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
AsyncTask::AsyncTask(IsolateData* data, const char* task_name)
|
||||
: instrumenting_(data && task_name) {
|
||||
if (!instrumenting_) return;
|
||||
data->inspector()->inspector()->asyncTaskScheduled(
|
||||
v8_inspector::StringView(reinterpret_cast<const uint8_t*>(task_name),
|
||||
strlen(task_name)),
|
||||
this, false);
|
||||
}
|
||||
|
||||
void AsyncTask::Run() {
|
||||
if (inspector_) inspector_->asyncTaskStarted(this);
|
||||
if (instrumenting_) data()->inspector()->inspector()->asyncTaskStarted(this);
|
||||
AsyncRun();
|
||||
if (inspector_) inspector_->asyncTaskFinished(this);
|
||||
if (instrumenting_) data()->inspector()->inspector()->asyncTaskFinished(this);
|
||||
}
|
||||
|
||||
ExecuteStringTask::ExecuteStringTask(
|
||||
IsolateData* data, int context_group_id, const char* task_name,
|
||||
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::Boolean> is_module,
|
||||
const char* task_name, v8_inspector::V8Inspector* inspector)
|
||||
: AsyncTask(task_name, inspector),
|
||||
v8::Local<v8::Integer> column_offset, v8::Local<v8::Boolean> is_module)
|
||||
: AsyncTask(data, task_name),
|
||||
expression_(expression),
|
||||
name_(ToVector(name)),
|
||||
line_offset_(line_offset.As<v8::Int32>()->Value()),
|
||||
column_offset_(column_offset.As<v8::Int32>()->Value()),
|
||||
is_module_(is_module->Value()) {}
|
||||
is_module_(is_module->Value()),
|
||||
context_group_id_(context_group_id) {}
|
||||
|
||||
ExecuteStringTask::ExecuteStringTask(
|
||||
const v8::internal::Vector<const char>& expression)
|
||||
: AsyncTask(nullptr, nullptr), expression_utf8_(expression) {}
|
||||
const v8::internal::Vector<const char>& expression, int context_group_id)
|
||||
: AsyncTask(nullptr, nullptr),
|
||||
expression_utf8_(expression),
|
||||
context_group_id_(context_group_id) {}
|
||||
|
||||
void ExecuteStringTask::AsyncRun() {
|
||||
v8::MicrotasksScope microtasks_scope(isolate(),
|
||||
v8::MicrotasksScope::kRunMicrotasks);
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
v8::Local<v8::Context> context = default_context();
|
||||
v8::Local<v8::Context> context = data()->GetContext(context_group_id_);
|
||||
v8::Context::Scope context_scope(context);
|
||||
|
||||
v8::Local<v8::String> name =
|
||||
@ -193,7 +199,6 @@ void ExecuteStringTask::AsyncRun() {
|
||||
v8::MaybeLocal<v8::Value> result;
|
||||
result = script->Run(context);
|
||||
} else {
|
||||
IsolateData::FromContext(context)->RegisterModule(context, name_,
|
||||
&scriptSource);
|
||||
data()->RegisterModule(context, name_, &scriptSource);
|
||||
}
|
||||
}
|
||||
|
@ -23,30 +23,27 @@ class TaskRunner : public v8::base::Thread {
|
||||
public:
|
||||
virtual ~Task() {}
|
||||
virtual bool is_inspector_task() = 0;
|
||||
void RunOnTaskRunner(TaskRunner* task_runner) {
|
||||
task_runner_ = task_runner;
|
||||
void RunOnIsolate(IsolateData* data) {
|
||||
data_ = data;
|
||||
Run();
|
||||
task_runner_ = nullptr;
|
||||
data_ = nullptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void Run() = 0;
|
||||
v8::Isolate* isolate() const { return task_runner_->data_->isolate(); }
|
||||
v8::Local<v8::Context> default_context() const {
|
||||
return task_runner_->data_->GetContext(
|
||||
task_runner_->default_context_group_id_);
|
||||
}
|
||||
v8::Isolate* isolate() const { return data_->isolate(); }
|
||||
IsolateData* data() const { return data_; }
|
||||
|
||||
private:
|
||||
TaskRunner* task_runner_ = nullptr;
|
||||
IsolateData* data_ = nullptr;
|
||||
};
|
||||
|
||||
TaskRunner(IsolateData::SetupGlobalTasks setup_global_tasks,
|
||||
bool catch_exceptions, v8::base::Semaphore* ready_semaphore,
|
||||
v8::StartupData* startup_data);
|
||||
v8::StartupData* startup_data,
|
||||
InspectorClientImpl::FrontendChannel* channel);
|
||||
virtual ~TaskRunner();
|
||||
IsolateData* data() const { return data_.get(); }
|
||||
int default_context_group_id() const { return default_context_group_id_; }
|
||||
|
||||
// Thread implementation.
|
||||
void Run() override;
|
||||
@ -66,10 +63,10 @@ class TaskRunner : public v8::base::Thread {
|
||||
|
||||
IsolateData::SetupGlobalTasks setup_global_tasks_;
|
||||
v8::StartupData* startup_data_;
|
||||
InspectorClientImpl::FrontendChannel* channel_;
|
||||
bool catch_exceptions_;
|
||||
v8::base::Semaphore* ready_semaphore_;
|
||||
std::unique_ptr<IsolateData> data_;
|
||||
int default_context_group_id_;
|
||||
|
||||
// deferred_queue_ combined with queue_ (in this order) have all tasks in the
|
||||
// correct order. Sometimes we skip non-protocol tasks by moving them from
|
||||
@ -87,26 +84,27 @@ class TaskRunner : public v8::base::Thread {
|
||||
|
||||
class AsyncTask : public TaskRunner::Task {
|
||||
public:
|
||||
AsyncTask(const char* task_name, v8_inspector::V8Inspector* inspector);
|
||||
AsyncTask(IsolateData* data, const char* task_name);
|
||||
virtual ~AsyncTask() = default;
|
||||
|
||||
protected:
|
||||
virtual void AsyncRun() = 0;
|
||||
void Run() override;
|
||||
|
||||
v8_inspector::V8Inspector* inspector_;
|
||||
bool instrumenting_;
|
||||
};
|
||||
|
||||
class ExecuteStringTask : public AsyncTask {
|
||||
public:
|
||||
ExecuteStringTask(const v8::internal::Vector<uint16_t>& expression,
|
||||
ExecuteStringTask(IsolateData* data, int context_group_id,
|
||||
const char* task_name,
|
||||
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::Boolean> is_module, const char* task_name,
|
||||
v8_inspector::V8Inspector* inspector);
|
||||
explicit ExecuteStringTask(
|
||||
const v8::internal::Vector<const char>& expression);
|
||||
v8::Local<v8::Boolean> is_module);
|
||||
ExecuteStringTask(const v8::internal::Vector<const char>& expression,
|
||||
int context_group_id);
|
||||
bool is_inspector_task() override { return false; }
|
||||
|
||||
private:
|
||||
@ -118,6 +116,7 @@ class ExecuteStringTask : public AsyncTask {
|
||||
int32_t line_offset_ = 0;
|
||||
int32_t column_offset_ = 0;
|
||||
bool is_module_ = false;
|
||||
int context_group_id_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ExecuteStringTask);
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user