diff options
Diffstat (limited to 'deps/v8/test/inspector/inspector-test.cc')
-rw-r--r-- | deps/v8/test/inspector/inspector-test.cc | 814 |
1 files changed, 467 insertions, 347 deletions
diff --git a/deps/v8/test/inspector/inspector-test.cc b/deps/v8/test/inspector/inspector-test.cc index b2dd6474bf..2e105c54d9 100644 --- a/deps/v8/test/inspector/inspector-test.cc +++ b/deps/v8/test/inspector/inspector-test.cc @@ -46,125 +46,256 @@ v8::internal::Vector<uint16_t> ToVector(v8::Local<v8::String> str) { return buffer; } -class UtilsExtension : public v8::Extension { +v8::Local<v8::String> ToV8String(v8::Isolate* isolate, const char* str) { + return v8::String::NewFromUtf8(isolate, str, v8::NewStringType::kNormal) + .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: - UtilsExtension() - : v8::Extension("v8_inspector/utils", - "native function print();" - "native function quit();" - "native function setlocale();" - "native function read();" - "native function load();" - "native function compileAndRunWithOrigin();" - "native function setCurrentTimeMSForTest();" - "native function setMemoryInfoForTest();" - "native function schedulePauseOnNextStatement();" - "native function cancelPauseOnNextStatement();" - "native function reconnect();" - "native function disconnect();" - "native function createContextGroup();") {} - virtual v8::Local<v8::FunctionTemplate> GetNativeFunctionTemplate( - v8::Isolate* isolate, v8::Local<v8::String> name) { - v8::Local<v8::Context> context = isolate->GetCurrentContext(); - if (name->Equals(context, v8::String::NewFromUtf8( - isolate, "print", v8::NewStringType::kNormal) - .ToLocalChecked()) - .FromJust()) { - return v8::FunctionTemplate::New(isolate, UtilsExtension::Print); - } else if (name->Equals(context, - v8::String::NewFromUtf8(isolate, "quit", - v8::NewStringType::kNormal) - .ToLocalChecked()) - .FromJust()) { - return v8::FunctionTemplate::New(isolate, UtilsExtension::Quit); - } else if (name->Equals(context, - v8::String::NewFromUtf8(isolate, "setlocale", - v8::NewStringType::kNormal) - .ToLocalChecked()) - .FromJust()) { - return v8::FunctionTemplate::New(isolate, UtilsExtension::SetLocale); - } else if (name->Equals(context, - v8::String::NewFromUtf8(isolate, "read", - v8::NewStringType::kNormal) - .ToLocalChecked()) - .FromJust()) { - return v8::FunctionTemplate::New(isolate, UtilsExtension::Read); - } else if (name->Equals(context, - v8::String::NewFromUtf8(isolate, "load", - v8::NewStringType::kNormal) - .ToLocalChecked()) - .FromJust()) { - return v8::FunctionTemplate::New(isolate, UtilsExtension::Load); - } else if (name->Equals(context, v8::String::NewFromUtf8( - isolate, "compileAndRunWithOrigin", - v8::NewStringType::kNormal) - .ToLocalChecked()) - .FromJust()) { - return v8::FunctionTemplate::New(isolate, - UtilsExtension::CompileAndRunWithOrigin); - } else if (name->Equals(context, v8::String::NewFromUtf8( - isolate, "setCurrentTimeMSForTest", - v8::NewStringType::kNormal) - .ToLocalChecked()) - .FromJust()) { - return v8::FunctionTemplate::New(isolate, - UtilsExtension::SetCurrentTimeMSForTest); - } else if (name->Equals(context, v8::String::NewFromUtf8( - isolate, "setMemoryInfoForTest", - v8::NewStringType::kNormal) - .ToLocalChecked()) - .FromJust()) { - return v8::FunctionTemplate::New(isolate, - UtilsExtension::SetMemoryInfoForTest); - } else if (name->Equals(context, - v8::String::NewFromUtf8( - isolate, "schedulePauseOnNextStatement", - v8::NewStringType::kNormal) - .ToLocalChecked()) - .FromJust()) { - return v8::FunctionTemplate::New( - isolate, UtilsExtension::SchedulePauseOnNextStatement); - } else if (name->Equals(context, v8::String::NewFromUtf8( - isolate, "cancelPauseOnNextStatement", - v8::NewStringType::kNormal) - .ToLocalChecked()) - .FromJust()) { - return v8::FunctionTemplate::New( - isolate, UtilsExtension::CancelPauseOnNextStatement); - } else if (name->Equals(context, - v8::String::NewFromUtf8(isolate, "reconnect", - v8::NewStringType::kNormal) - .ToLocalChecked()) - .FromJust()) { - return v8::FunctionTemplate::New(isolate, UtilsExtension::Reconnect); - } else if (name->Equals(context, - v8::String::NewFromUtf8(isolate, "disconnect", - v8::NewStringType::kNormal) - .ToLocalChecked()) - .FromJust()) { - return v8::FunctionTemplate::New(isolate, UtilsExtension::Disconnect); - } else if (name->Equals(context, v8::String::NewFromUtf8( - isolate, "createContextGroup", - v8::NewStringType::kNormal) - .ToLocalChecked()) - .FromJust()) { - return v8::FunctionTemplate::New(isolate, - UtilsExtension::CreateContextGroup); - } - return v8::Local<v8::FunctionTemplate>(); + 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(); } - static void set_backend_task_runner(TaskRunner* runner) { - backend_runner_ = runner; + 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(); } - static void set_inspector_client(InspectorClientImpl* client) { - inspector_client_ = client; + 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; + void Run(v8::Isolate* isolate, + v8::Local<v8::ObjectTemplate> global) override { + v8::Local<v8::ObjectTemplate> utils = v8::ObjectTemplate::New(isolate); + utils->Set(ToV8String(isolate, "print"), + v8::FunctionTemplate::New(isolate, &UtilsExtension::Print)); + utils->Set(ToV8String(isolate, "quit"), + v8::FunctionTemplate::New(isolate, &UtilsExtension::Quit)); + utils->Set(ToV8String(isolate, "setlocale"), + v8::FunctionTemplate::New(isolate, &UtilsExtension::Setlocale)); + utils->Set(ToV8String(isolate, "read"), + v8::FunctionTemplate::New(isolate, &UtilsExtension::Read)); + utils->Set(ToV8String(isolate, "load"), + v8::FunctionTemplate::New(isolate, &UtilsExtension::Load)); + utils->Set(ToV8String(isolate, "compileAndRunWithOrigin"), + v8::FunctionTemplate::New( + isolate, &UtilsExtension::CompileAndRunWithOrigin)); + utils->Set(ToV8String(isolate, "setCurrentTimeMSForTest"), + v8::FunctionTemplate::New( + isolate, &UtilsExtension::SetCurrentTimeMSForTest)); + utils->Set(ToV8String(isolate, "setMemoryInfoForTest"), + v8::FunctionTemplate::New( + isolate, &UtilsExtension::SetMemoryInfoForTest)); + utils->Set(ToV8String(isolate, "schedulePauseOnNextStatement"), + v8::FunctionTemplate::New( + isolate, &UtilsExtension::SchedulePauseOnNextStatement)); + utils->Set(ToV8String(isolate, "cancelPauseOnNextStatement"), + v8::FunctionTemplate::New( + isolate, &UtilsExtension::CancelPauseOnNextStatement)); + 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); + } + + static void set_backend_task_runner(TaskRunner* runner) { + backend_runner_ = runner; } 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++) { @@ -201,7 +332,7 @@ class UtilsExtension : public v8::Extension { static void Quit(const v8::FunctionCallbackInfo<v8::Value>& args) { Exit(); } - static void SetLocale(const v8::FunctionCallbackInfo<v8::Value>& args) { + static void Setlocale(const v8::FunctionCallbackInfo<v8::Value>& args) { if (args.Length() != 1 || !args[0]->IsString()) { fprintf(stderr, "Internal error: setlocale get one string argument."); Exit(); @@ -248,27 +379,31 @@ class UtilsExtension : public v8::Extension { } 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 task(chars); - v8::Global<v8::Context> context(isolate, isolate->GetCurrentContext()); - task.Run(isolate, context); + 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( @@ -277,7 +412,7 @@ class UtilsExtension : public v8::Extension { fprintf(stderr, "Internal error: setCurrentTimeMSForTest(time)."); Exit(); } - inspector_client_->setCurrentTimeMSForTest( + backend_runner_->data()->inspector()->SetCurrentTimeMSForTest( args[0].As<v8::Number>()->Value()); } @@ -287,112 +422,153 @@ class UtilsExtension : public v8::Extension { 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()."); + if (args.Length() != 1 || !args[0]->IsInt32()) { + fprintf(stderr, + "Internal error: cancelPauseOnNextStatement(context_group_id)."); + Exit(); + } + v8::base::Semaphore ready_semaphore(0); + backend_runner_->Append(new CancelPauseOnNextStatementTask( + &ready_semaphore, args[0].As<v8::Int32>()->Value())); + ready_semaphore.Wait(); + } + + static void SetLogConsoleApiMessageCalls( + const v8::FunctionCallbackInfo<v8::Value>& args) { + if (args.Length() != 1 || !args[0]->IsBoolean()) { + fprintf(stderr, "Internal error: setLogConsoleApiMessageCalls(bool)."); Exit(); } - inspector_client_->session()->cancelPauseOnNextStatement(); + backend_runner_->data()->inspector()->SetLogConsoleApiMessageCalls( + args[0].As<v8::Boolean>()->Value()); } - static void Reconnect(const v8::FunctionCallbackInfo<v8::Value>& args) { + static void CreateContextGroup( + const v8::FunctionCallbackInfo<v8::Value>& args) { if (args.Length() != 0) { - fprintf(stderr, "Internal error: reconnect()."); + fprintf(stderr, "Internal error: createContextGroup()."); Exit(); } v8::base::Semaphore ready_semaphore(0); - inspector_client_->scheduleReconnect(&ready_semaphore); + 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 Disconnect(const v8::FunctionCallbackInfo<v8::Value>& args) { - if (args.Length() != 0) { - fprintf(stderr, "Internal error: disconnect()."); + 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); - inspector_client_->scheduleDisconnect(&ready_semaphore); + 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 CreateContextGroup( + static void DisconnectSession( const v8::FunctionCallbackInfo<v8::Value>& args) { - if (args.Length() != 0) { - fprintf(stderr, "Internal error: createContextGroup()."); + if (args.Length() != 1 || !args[0]->IsInt32()) { + fprintf(stderr, "Internal error: disconnectionSession(session_id)."); Exit(); } - const char* backend_extensions[] = {"v8_inspector/setTimeout", - "v8_inspector/inspector"}; - v8::ExtensionConfiguration backend_configuration( - arraysize(backend_extensions), backend_extensions); + int session_id = args[0].As<v8::Int32>()->Value(); + SendMessageToFrontendTask::Unregister(session_id); v8::base::Semaphore ready_semaphore(0); - int context_group_id = 0; - inspector_client_->scheduleCreateContextGroup( - &backend_configuration, &ready_semaphore, &context_group_id); + v8::internal::Vector<uint16_t> state; + backend_runner_->Append( + new DisconnectSessionTask(&ready_semaphore, session_id, &state)); ready_semaphore.Wait(); args.GetReturnValue().Set( - v8::Int32::New(args.GetIsolate(), context_group_id)); + 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; } - void AsyncRun(v8::Isolate* isolate, - const v8::Global<v8::Context>& global_context) override { - v8::MicrotasksScope microtasks_scope(isolate, + private: + void AsyncRun() override { + v8::MicrotasksScope microtasks_scope(isolate(), v8::MicrotasksScope::kRunMicrotasks); - v8::HandleScope handle_scope(isolate); - v8::Local<v8::Context> context = global_context.Get(isolate); + v8::HandleScope handle_scope(isolate()); + v8::Local<v8::Context> context = data()->GetContext(context_group_id_); v8::Context::Scope context_scope(context); - v8::Local<v8::Function> function = function_.Get(isolate); + v8::Local<v8::Function> function = function_.Get(isolate()); v8::MaybeLocal<v8::Value> result; result = function->Call(context, context->Global(), 0, nullptr); } - private: v8::Global<v8::Function> function_; + int context_group_id_; }; -class SetTimeoutExtension : public v8::Extension { +class SetTimeoutExtension : public IsolateData::SetupGlobalTask { public: - SetTimeoutExtension() - : v8::Extension("v8_inspector/setTimeout", - "native function setTimeout();") {} - - virtual v8::Local<v8::FunctionTemplate> GetNativeFunctionTemplate( - v8::Isolate* isolate, v8::Local<v8::String> name) { - return v8::FunctionTemplate::New(isolate, SetTimeoutExtension::SetTimeout); + void Run(v8::Isolate* isolate, + v8::Local<v8::ObjectTemplate> global) override { + global->Set( + ToV8String(isolate, "setTimeout"), + v8::FunctionTemplate::New(isolate, &SetTimeoutExtension::SetTimeout)); } private: @@ -400,26 +576,27 @@ class SetTimeoutExtension : public v8::Extension { 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))); } - TaskRunner::FromContext(context)->Append(task.release()); + data->task_runner()->Append(task.release()); } }; @@ -430,96 +607,55 @@ bool StrictAccessCheck(v8::Local<v8::Context> accessing_context, return accessing_context.IsEmpty(); } -class InspectorExtension : public v8::Extension { +class InspectorExtension : public IsolateData::SetupGlobalTask { public: - InspectorExtension() - : v8::Extension("v8_inspector/inspector", - "native function attachInspector();" - "native function detachInspector();" - "native function setMaxAsyncTaskStacks();" - "native function breakProgram();" - "native function createObjectWithStrictCheck();" - "native function callWithScheduledBreak();" - "native function allowAccessorFormatting();") {} - - virtual v8::Local<v8::FunctionTemplate> GetNativeFunctionTemplate( - v8::Isolate* isolate, v8::Local<v8::String> name) { - v8::Local<v8::Context> context = isolate->GetCurrentContext(); - if (name->Equals(context, - v8::String::NewFromUtf8(isolate, "attachInspector", - v8::NewStringType::kNormal) - .ToLocalChecked()) - .FromJust()) { - return v8::FunctionTemplate::New(isolate, InspectorExtension::Attach); - } else if (name->Equals(context, - v8::String::NewFromUtf8(isolate, "detachInspector", - v8::NewStringType::kNormal) - .ToLocalChecked()) - .FromJust()) { - return v8::FunctionTemplate::New(isolate, InspectorExtension::Detach); - } else if (name->Equals(context, v8::String::NewFromUtf8( - isolate, "setMaxAsyncTaskStacks", - v8::NewStringType::kNormal) - .ToLocalChecked()) - .FromJust()) { - return v8::FunctionTemplate::New( - isolate, InspectorExtension::SetMaxAsyncTaskStacks); - } else if (name->Equals(context, - v8::String::NewFromUtf8(isolate, "breakProgram", - v8::NewStringType::kNormal) - .ToLocalChecked()) - .FromJust()) { - return v8::FunctionTemplate::New(isolate, - InspectorExtension::BreakProgram); - } else if (name->Equals(context, v8::String::NewFromUtf8( - isolate, "createObjectWithStrictCheck", - v8::NewStringType::kNormal) - .ToLocalChecked()) - .FromJust()) { - return v8::FunctionTemplate::New( - isolate, InspectorExtension::CreateObjectWithStrictCheck); - } else if (name->Equals(context, v8::String::NewFromUtf8( - isolate, "callWithScheduledBreak", - v8::NewStringType::kNormal) - .ToLocalChecked()) - .FromJust()) { - return v8::FunctionTemplate::New( - isolate, InspectorExtension::CallWithScheduledBreak); - } else if (name->Equals(context, v8::String::NewFromUtf8( - isolate, "allowAccessorFormatting", - v8::NewStringType::kNormal) - .ToLocalChecked()) - .FromJust()) { - return v8::FunctionTemplate::New( - isolate, InspectorExtension::AllowAccessorFormatting); - } - return v8::Local<v8::FunctionTemplate>(); + ~InspectorExtension() override = default; + void Run(v8::Isolate* isolate, + v8::Local<v8::ObjectTemplate> global) override { + v8::Local<v8::ObjectTemplate> inspector = v8::ObjectTemplate::New(isolate); + 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)); + inspector->Set( + ToV8String(isolate, "dumpAsyncTaskStacksStateForTest"), + v8::FunctionTemplate::New( + isolate, &InspectorExtension::DumpAsyncTaskStacksStateForTest)); + inspector->Set( + ToV8String(isolate, "breakProgram"), + v8::FunctionTemplate::New(isolate, &InspectorExtension::BreakProgram)); + inspector->Set( + ToV8String(isolate, "createObjectWithStrictCheck"), + v8::FunctionTemplate::New( + isolate, &InspectorExtension::CreateObjectWithStrictCheck)); + inspector->Set(ToV8String(isolate, "callWithScheduledBreak"), + v8::FunctionTemplate::New( + isolate, &InspectorExtension::CallWithScheduledBreak)); + inspector->Set(ToV8String(isolate, "allowAccessorFormatting"), + v8::FunctionTemplate::New( + isolate, &InspectorExtension::AllowAccessorFormatting)); + global->Set(ToV8String(isolate, "inspector"), inspector); } 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( @@ -528,12 +664,23 @@ class InspectorExtension : public v8::Extension { 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( + const v8::FunctionCallbackInfo<v8::Value>& args) { + if (args.Length() != 0) { + fprintf(stderr, "Internal error: dumpAsyncTaskStacksStateForTest()."); + Exit(); + } + v8_inspector::DumpAsyncTaskStacksStateForTest( + IsolateData::FromContext(args.GetIsolate()->GetCurrentContext()) + ->inspector() + ->inspector()); } static void BreakProgram(const v8::FunctionCallbackInfo<v8::Value>& args) { @@ -541,16 +688,14 @@ class InspectorExtension : public v8::Extension { 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( @@ -571,24 +716,23 @@ class InspectorExtension : public v8::Extension { 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( @@ -610,50 +754,22 @@ class InspectorExtension : public v8::Extension { } }; -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 @@ -666,45 +782,46 @@ int main(int argc, char* argv[]) { v8::V8::InitializeExternalStartupData(argv[0]); v8::V8::Initialize(); - SetTimeoutExtension set_timeout_extension; - v8::RegisterExtension(&set_timeout_extension); - InspectorExtension inspector_extension; - v8::RegisterExtension(&inspector_extension); - UtilsExtension utils_extension; - v8::RegisterExtension(&utils_extension); - SendMessageToBackendExtension send_message_to_backend_extension; - v8::RegisterExtension(&send_message_to_backend_extension); - v8::base::Semaphore ready_semaphore(0); - const char* backend_extensions[] = {"v8_inspector/setTimeout", - "v8_inspector/inspector"}; - v8::ExtensionConfiguration backend_configuration( - arraysize(backend_extensions), backend_extensions); - TaskRunner backend_runner(&backend_configuration, false, &ready_semaphore); + v8::StartupData startup_data = {nullptr, 0}; + for (int i = 1; i < argc; ++i) { + if (strcmp(argv[i], "--embed") == 0) { + argv[i++] = nullptr; + printf("Embedding script '%s'\n", argv[i]); + startup_data = v8::V8::CreateSnapshotDataBlob(argv[i]); + argv[i] = nullptr; + } + } + + 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(); - SendMessageToBackendExtension::set_backend_task_runner(&backend_runner); - UtilsExtension::set_backend_task_runner(&backend_runner); - const char* frontend_extensions[] = {"v8_inspector/utils", - "v8_inspector/frontend"}; - v8::ExtensionConfiguration frontend_configuration( - arraysize(frontend_extensions), frontend_extensions); - TaskRunner frontend_runner(&frontend_configuration, true, &ready_semaphore); + int frontend_context_group_id = 0; + frontend_runner.Append( + new CreateContextGroupTask(&ready_semaphore, &frontend_context_group_id)); ready_semaphore.Wait(); - FrontendChannelImpl frontend_channel(&frontend_runner); - InspectorClientImpl inspector_client(&backend_runner, &frontend_channel, - &ready_semaphore); + IsolateData::SetupGlobalTasks backend_extensions; + backend_extensions.emplace_back(new SetTimeoutExtension()); + backend_extensions.emplace_back(new InspectorExtension()); + 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(); - UtilsExtension::set_inspector_client(&inspector_client); + UtilsExtension::set_backend_task_runner(&backend_runner); task_runners.push_back(&frontend_runner); task_runners.push_back(&backend_runner); for (int i = 1; i < argc; ++i) { // Ignore unknown flags. - if (argv[i][0] == '-') continue; + if (argv[i] == nullptr || argv[i][0] == '-') continue; bool exists = false; v8::internal::Vector<const char> chars = @@ -714,10 +831,13 @@ 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(); backend_runner.Join(); + + delete startup_data.data; return 0; } |