From 207c92aa56a2f4a3fb2c8a295045298ab296bc1e Mon Sep 17 00:00:00 2001 From: ivanfanwu Date: Mon, 1 Aug 2022 16:55:05 +0800 Subject: [PATCH] feat(devtools): support multi instance fix(devtools): add end line fix(devtools): fix compile fix(devtools): add define for context fix(devtools): fix compile --- driver/js/core/include/core/engine.h | 15 +++ .../v8/inspector/v8_inspector_client_impl.h | 44 +++----- .../v8/inspector/v8_inspector_context.h | 61 +++++++++++ .../js/core/include/core/runtime/v8/runtime.h | 13 ++- .../include/devtools/devtools_data_source.h | 1 - .../v8/inspector/v8_inspector_client_impl.cc | 101 +++++++++++------- .../js/core/src/runtime/v8/v8_bridge_utils.cc | 39 +++---- .../HippyDemo.xcodeproj/project.pbxproj | 2 + 8 files changed, 188 insertions(+), 88 deletions(-) create mode 100644 driver/js/core/include/core/runtime/v8/inspector/v8_inspector_context.h diff --git a/driver/js/core/include/core/engine.h b/driver/js/core/include/core/engine.h index 55f372d0b..dec52f29b 100644 --- a/driver/js/core/include/core/engine.h +++ b/driver/js/core/include/core/engine.h @@ -31,6 +31,10 @@ #include "core/base/common.h" #include "core/napi/js_native_api_types.h" +#if defined(ENABLE_INSPECTOR) && !defined(V8_WITHOUT_INSPECTOR) +#include "core/runtime/v8/inspector/v8_inspector_client_impl.h" +#endif + class Scope; class Engine { @@ -60,6 +64,14 @@ class Engine { inline std::shared_ptr GetWorkerTaskRunner() { return worker_task_runner_; } +#if defined(ENABLE_INSPECTOR) && !defined(V8_WITHOUT_INSPECTOR) + inline void SetInspectorClient(std::shared_ptr inspector_client) { + inspector_client_ = inspector_client; + } + inline std::shared_ptr GetInspectorClient() { + return inspector_client_; + } +#endif private: void CreateVM(const std::shared_ptr& param); @@ -71,4 +83,7 @@ class Engine { std::unique_ptr map_; std::mutex cnt_mutex_; uint32_t scope_cnt_; +#if defined(ENABLE_INSPECTOR) && !defined(V8_WITHOUT_INSPECTOR) + std::shared_ptr inspector_client_; +#endif }; diff --git a/driver/js/core/include/core/runtime/v8/inspector/v8_inspector_client_impl.h b/driver/js/core/include/core/runtime/v8/inspector/v8_inspector_client_impl.h index 337877efe..73cf60b2a 100644 --- a/driver/js/core/include/core/runtime/v8/inspector/v8_inspector_client_impl.h +++ b/driver/js/core/include/core/runtime/v8/inspector/v8_inspector_client_impl.h @@ -26,10 +26,9 @@ #include "footstone/unicode_string_view.h" #include "footstone/task_runner.h" -#include "core/napi/v8/js_native_api_v8.h" #include "core/runtime/v8/inspector/v8_channel_impl.h" +#include "core/runtime/v8/inspector/v8_inspector_context.h" #include "core/runtime/v8/interrupt_queue.h" -#include "core/scope.h" namespace hippy { namespace inspector { @@ -40,51 +39,38 @@ class V8InspectorClientImpl : public v8_inspector::V8InspectorClient, using unicode_string_view = footstone::stringview::unicode_string_view; using TaskRunner = footstone::TaskRunner; - explicit V8InspectorClientImpl(std::shared_ptr scope, std::weak_ptr runner); + explicit V8InspectorClientImpl(std::weak_ptr runner): js_runner_(std::move(runner)) {} ~V8InspectorClientImpl(); - inline std::shared_ptr GetInspectorRunner() { - return inspector_runner_; - } - - inline std::unique_ptr& GetChannel() { - return channel_; - } - - inline std::unique_ptr& GetSession() { - return session_; - } - - inline void SetSession(std::unique_ptr session) { - session_ = std::move(session); - } + void CreateInspector(const std::shared_ptr& scope); +#if defined(ENABLE_INSPECTOR) && !defined(V8_WITHOUT_INSPECTOR) + std::shared_ptr CreateInspectorContext(const std::shared_ptr scope, std::shared_ptr devtools_data_source); + void DestroyInspectorContext(bool is_reload, const std::shared_ptr &inspector_context); +#endif + void SendMessageToV8(const std::shared_ptr& inspector_context, unicode_string_view&& params); inline std::unique_ptr& GetInspector() { return inspector_; } -#if defined(ENABLE_INSPECTOR) && !defined(V8_WITHOUT_INSPECTOR) - void Reset(std::shared_ptr scope, const std::shared_ptr devtools_data_source); - void Connect(const std::shared_ptr devtools_data_source); -#endif - - void SendMessageToV8(unicode_string_view&& params); - void CreateContext(); - void DestroyContext(); v8::Local ensureDefaultContextInGroup(int contextGroupId) override; void runMessageLoopOnPause(int contextGroupId) override; void quitMessageLoopOnPause() override; void runIfWaitingForDebugger(int contextGroupId) override; private: - std::shared_ptr scope_; + void CreateContext(const std::shared_ptr& inspector_context); + void DestroyContext(const std::shared_ptr& inspector_context); + std::unique_ptr inspector_; - std::unique_ptr channel_; - std::unique_ptr session_; std::weak_ptr js_runner_; std::shared_ptr inspector_runner_; std::mutex mutex_; std::shared_ptr interrupt_queue_; + std::shared_ptr reload_inspector_context_; + std::atomic_int32_t context_group_count_{1}; + std::unordered_map> inspector_context_map_; + std::mutex inspector_context_mutex_; }; } // namespace inspector diff --git a/driver/js/core/include/core/runtime/v8/inspector/v8_inspector_context.h b/driver/js/core/include/core/runtime/v8/inspector/v8_inspector_context.h new file mode 100644 index 000000000..ee99d0747 --- /dev/null +++ b/driver/js/core/include/core/runtime/v8/inspector/v8_inspector_context.h @@ -0,0 +1,61 @@ +/* + * + * Tencent is pleased to support the open source community by making + * Hippy available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#pragma once + +#include "core/runtime/v8/inspector/v8_channel_impl.h" + +class Scope; + +namespace hippy { +namespace inspector { + +class V8InspectorContext { + public: + explicit V8InspectorContext(int32_t group_id, + std::unique_ptr channel, + std::unique_ptr session) + : context_group_id_(group_id), channel_(std::move(channel)), + session_(std::move(session)) {} + + inline void SetSession(std::unique_ptr session) { session_ = std::move(session); } +#if defined(ENABLE_INSPECTOR) && !defined(V8_WITHOUT_INSPECTOR) + inline void SetDevtoolsDataSource(std::shared_ptr devtools_data_source) { if (channel_) { channel_->SetDevtoolsDataSource(std::move(devtools_data_source));} } +#endif + inline void SetScope(std::shared_ptr scope) { scope_ = std::move(scope); } + inline std::shared_ptr GetScope() { return scope_; } + inline V8ChannelImpl* GetV8Channel() { return channel_.get(); } + inline int32_t GetContextGroupId() { return context_group_id_; } + + inline void SendMessageToV8(const v8_inspector::StringView message_view) { + if (channel_) { + session_->dispatchProtocolMessage(message_view); + } + } + + private: + int32_t context_group_id_; + std::unique_ptr channel_; + std::unique_ptr session_; + std::shared_ptr scope_; +}; +} // namespace inspector +} // namespace hippy diff --git a/driver/js/core/include/core/runtime/v8/runtime.h b/driver/js/core/include/core/runtime/v8/runtime.h index 2698ba1f3..d189b0059 100644 --- a/driver/js/core/include/core/runtime/v8/runtime.h +++ b/driver/js/core/include/core/runtime/v8/runtime.h @@ -31,10 +31,6 @@ #include "jni/scoped_java_ref.h" #endif -#if defined(ENABLE_INSPECTOR) && !defined(V8_WITHOUT_INSPECTOR) -#include "core/runtime/v8/inspector/v8_inspector_client_impl.h" -#endif - #include "core/engine.h" #include "core/napi/js_native_api.h" #include "core/napi/v8/js_native_api_v8.h" @@ -72,6 +68,12 @@ class Runtime { inline void SetBridge(std::shared_ptr bridge) { bridge_ = bridge; } +#if defined(ENABLE_INSPECTOR) && !defined(V8_WITHOUT_INSPECTOR) + inline void SetInspectorContext(std::shared_ptr inspector_context) { + inspector_context_ = inspector_context; + } + inline std::shared_ptr GetInspectorContext() { return inspector_context_; } +#endif #ifdef ENABLE_INSPECTOR inline void SetDevtoolsDataSource(std::shared_ptr devtools_data_source) { devtools_data_source_ = devtools_data_source; @@ -113,4 +115,7 @@ class Runtime { #endif std::shared_ptr bridge_; +#if defined(ENABLE_INSPECTOR) && !defined(V8_WITHOUT_INSPECTOR) + std::shared_ptr inspector_context_; +#endif }; diff --git a/driver/js/core/include/devtools/devtools_data_source.h b/driver/js/core/include/devtools/devtools_data_source.h index e1536182e..4a058f093 100644 --- a/driver/js/core/include/devtools/devtools_data_source.h +++ b/driver/js/core/include/devtools/devtools_data_source.h @@ -26,7 +26,6 @@ #include "footstone/task_runner.h" #include "api/devtools_backend_service.h" #include "api/devtools_config.h" -#include "core/engine.h" #include "dom/root_node.h" #include "devtools/adapter/hippy_runtime_adapter.h" #include "devtools/adapter/hippy_vm_request_adapter.h" diff --git a/driver/js/core/src/runtime/v8/inspector/v8_inspector_client_impl.cc b/driver/js/core/src/runtime/v8/inspector/v8_inspector_client_impl.cc index 53a2bb376..59c5be290 100644 --- a/driver/js/core/src/runtime/v8/inspector/v8_inspector_client_impl.cc +++ b/driver/js/core/src/runtime/v8/inspector/v8_inspector_client_impl.cc @@ -25,15 +25,18 @@ #include #include "core/runtime/v8/bridge.h" +#include "core/napi/v8/js_native_api_v8.h" namespace hippy::inspector { constexpr uint8_t kProjectName[] = "Hippy"; -V8InspectorClientImpl::V8InspectorClientImpl(std::shared_ptr scope, std::weak_ptr runner) - : scope_(std::move(scope)), js_runner_(std::move(runner)) { +void V8InspectorClientImpl::CreateInspector(const std::shared_ptr& scope) { + if (inspector_) { + return; + } std::shared_ptr ctx = - std::static_pointer_cast(scope_->GetContext()); + std::static_pointer_cast(scope->GetContext()); v8::Isolate* isolate = ctx->isolate_; v8::HandleScope handle_scope(isolate); inspector_ = v8_inspector::V8Inspector::create(isolate, this); @@ -42,38 +45,61 @@ V8InspectorClientImpl::V8InspectorClientImpl(std::shared_ptr scope, std:: map.Insert(interrupt_queue_->GetId(), interrupt_queue_); } +#if defined(ENABLE_INSPECTOR) && !defined(V8_WITHOUT_INSPECTOR) +std::shared_ptr V8InspectorClientImpl::CreateInspectorContext(const std::shared_ptr scope, + std::shared_ptr devtools_data_source) { + auto inspector_context = reload_inspector_context_; + if (inspector_context) { + FOOTSTONE_DLOG(INFO) << "reload need inspector reuse context, session and change bridge"; + inspector_context->SetDevtoolsDataSource(std::move(devtools_data_source)); + } else { + auto context_group_id = context_group_count_.fetch_add(1, std::memory_order_relaxed); + auto channel = std::make_unique(); + channel->SetDevtoolsDataSource(devtools_data_source); + auto session = inspector_->connect(context_group_id, channel.get(), v8_inspector::StringView()); + inspector_context = std::make_shared(context_group_id, std::move(channel), std::move(session)); + std::lock_guard lock(inspector_context_mutex_); + inspector_context_map_[context_group_id] = inspector_context; + } + inspector_context->SetScope(scope); + // enter v8 context + CreateContext(inspector_context); + return inspector_context; +} + +void V8InspectorClientImpl::DestroyInspectorContext(bool is_reload, + const std::shared_ptr< + V8InspectorContext> &inspector_context) { + // exit v8 context + DestroyContext(inspector_context); + // preserve inspector_context for reload reuse + reload_inspector_context_ = is_reload ? inspector_context: nullptr; + if (!is_reload) { + std::lock_guard lock(inspector_context_mutex_); + inspector_context_map_.erase(inspector_context->GetContextGroupId()); + } + inspector_context->SetScope(nullptr); +} +#endif + V8InspectorClientImpl::~V8InspectorClientImpl() { auto& map = InterruptQueue::GetPersistentMap(); map.Erase(interrupt_queue_->GetId()); } -#if defined(ENABLE_INSPECTOR) && !defined(V8_WITHOUT_INSPECTOR) -void V8InspectorClientImpl::Reset(std::shared_ptr scope, - const std::shared_ptr devtools_data_source) { - scope_ = std::move(scope); - channel_->SetDevtoolsDataSource(devtools_data_source); -} - -void V8InspectorClientImpl::Connect(const std::shared_ptr devtools_data_source) { - channel_ = std::make_unique(); - session_ = inspector_->connect(1, channel_.get(), v8_inspector::StringView()); - channel_->SetDevtoolsDataSource(devtools_data_source); -} -#endif - -void V8InspectorClientImpl::CreateContext() { +void V8InspectorClientImpl::CreateContext(const std::shared_ptr& inspector_context) { std::shared_ptr ctx = - std::static_pointer_cast(scope_->GetContext()); + std::static_pointer_cast(inspector_context->GetScope()->GetContext()); v8::Isolate* isolate = ctx->isolate_; v8::HandleScope handle_scope(isolate); v8::Local context = v8::Local::New(isolate, ctx->context_persistent_); v8::Context::Scope context_scope(context); inspector_->contextCreated(v8_inspector::V8ContextInfo( - context, 1, v8_inspector::StringView(kProjectName, arraysize(kProjectName)))); + context, inspector_context->GetContextGroupId(), v8_inspector::StringView(kProjectName, arraysize(kProjectName)))); } -void V8InspectorClientImpl::SendMessageToV8(unicode_string_view&& params) { +void V8InspectorClientImpl::SendMessageToV8(const std::shared_ptr& inspector_context_ref, unicode_string_view&& params) { std::shared_ptr msg_runner; { std::unique_lock lock(mutex_); @@ -89,14 +115,15 @@ void V8InspectorClientImpl::SendMessageToV8(unicode_string_view&& params) { interrupt_queue_->SetTaskRunner(msg_runner); } + std::weak_ptr weak_inspector_context = inspector_context_ref; auto weak_self = weak_from_this(); - auto msg_unit = [params, weak_self] { + auto msg_unit = [weak_inspector_context, params, weak_self] { auto self = weak_self.lock(); if (!self) { return; } - const auto& channel = self->GetChannel(); - if (!channel) { + auto inspector_context = weak_inspector_context.lock(); + if (!inspector_context) { return; } const auto& inspector = self->GetInspector(); @@ -106,8 +133,8 @@ void V8InspectorClientImpl::SendMessageToV8(unicode_string_view&& params) { case unicode_string_view::Encoding::Latin1: { std::string str = params.latin1_value(); if (!str.compare("chrome_socket_closed")) { - auto session = inspector->connect(1, channel.get(), v8_inspector::StringView()); - self->SetSession(std::move(session)); + auto session = inspector->connect(inspector_context->GetContextGroupId(), inspector_context->GetV8Channel(), v8_inspector::StringView()); + inspector_context->SetSession(std::move(session)); return; } message_view = v8_inspector::StringView( @@ -117,8 +144,8 @@ void V8InspectorClientImpl::SendMessageToV8(unicode_string_view&& params) { case unicode_string_view::Encoding::Utf16: { std::u16string str = params.utf16_value(); if (!str.compare(u"chrome_socket_closed")) { - auto session = inspector->connect(1, channel.get(), v8_inspector::StringView()); - self->SetSession(std::move(session)); + auto session = inspector->connect(inspector_context->GetContextGroupId(), inspector_context->GetV8Channel(), v8_inspector::StringView()); + inspector_context->SetSession(std::move(session)); return; } message_view = v8_inspector::StringView( @@ -129,19 +156,15 @@ void V8InspectorClientImpl::SendMessageToV8(unicode_string_view&& params) { FOOTSTONE_DLOG(INFO) << "encoding = " << static_cast(encoding); FOOTSTONE_UNREACHABLE(); } - const auto& session = self->GetSession(); - if (!session) { - return; - } - session->dispatchProtocolMessage(message_view); + inspector_context->SendMessageToV8(message_view); }; interrupt_queue_->PostTask(std::move(msg_unit)); } -void V8InspectorClientImpl::DestroyContext() { +void V8InspectorClientImpl::DestroyContext(const std::shared_ptr& inspector_context) { FOOTSTONE_DLOG(INFO) << "V8InspectorClientImpl DestroyContext"; std::shared_ptr ctx = - std::static_pointer_cast(scope_->GetContext()); + std::static_pointer_cast(inspector_context->GetScope()->GetContext()); if (!ctx) { FOOTSTONE_DLOG(ERROR) << "V8InspectorClientImpl ctx error"; return; @@ -158,8 +181,14 @@ void V8InspectorClientImpl::DestroyContext() { v8::Local V8InspectorClientImpl::ensureDefaultContextInGroup( int contextGroupId) { + std::lock_guard lock(inspector_context_mutex_); + auto inspector_context_entry = inspector_context_map_.find(contextGroupId); + if (inspector_context_entry == inspector_context_map_.end()) { + FOOTSTONE_DLOG(INFO) << "ensureDefaultContextInGroup = " << contextGroupId; + FOOTSTONE_UNREACHABLE(); + } std::shared_ptr ctx = - std::static_pointer_cast(scope_->GetContext()); + std::static_pointer_cast(inspector_context_entry->second->GetScope()->GetContext()); v8::Isolate* isolate = ctx->isolate_; v8::HandleScope handle_scope(isolate); v8::Local context = diff --git a/driver/js/core/src/runtime/v8/v8_bridge_utils.cc b/driver/js/core/src/runtime/v8/v8_bridge_utils.cc index 4abf31fa2..31deda73b 100644 --- a/driver/js/core/src/runtime/v8/v8_bridge_utils.cc +++ b/driver/js/core/src/runtime/v8/v8_bridge_utils.cc @@ -67,8 +67,6 @@ constexpr char kWorkerRunnerName[] = "hippy_worker"; #if defined(ENABLE_INSPECTOR) && !defined(V8_WITHOUT_INSPECTOR) using V8InspectorClientImpl = hippy::inspector::V8InspectorClientImpl; -std::mutex inspector_mutex; -std::shared_ptr global_inspector = nullptr; #endif static std::unordered_map, uint32_t>> reuse_engine_map; @@ -104,6 +102,13 @@ int64_t V8BridgeUtils::InitInstance(bool enable_v8_serialization, v8::HandleScope handle_scope(isolate); isolate->AddMessageListener(V8BridgeUtils::HandleUncaughtJsError); isolate->SetData(kRuntimeSlotIndex, reinterpret_cast(runtime_id)); +#if defined(ENABLE_INSPECTOR) && !defined(V8_WITHOUT_INSPECTOR) + std::shared_ptr runtime = Runtime::Find(runtime_id); + if (runtime->IsDebug()) { + auto inspector = std::make_shared(runtime->GetEngine()->GetJsTaskRunner()); + runtime->GetEngine()->SetInspectorClient(inspector); + } +#endif }; std::unique_ptr engine_cb_map = std::make_unique(); @@ -130,14 +135,12 @@ int64_t V8BridgeUtils::InitInstance(bool enable_v8_serialization, } #if defined(ENABLE_INSPECTOR) && !defined(V8_WITHOUT_INSPECTOR) if (runtime->IsDebug()) { - std::lock_guard lock(inspector_mutex); - if (!global_inspector) { - global_inspector = std::make_shared(scope, scope->GetTaskRunner()); - global_inspector->Connect(runtime->GetDevtoolsDataSource()); - } else { - global_inspector->Reset(scope, runtime->GetDevtoolsDataSource()); + auto inspector_client = runtime->GetEngine()->GetInspectorClient(); + if (inspector_client) { + inspector_client->CreateInspector(scope); + auto inspector_context = inspector_client->CreateInspectorContext(scope, runtime->GetDevtoolsDataSource()); + runtime->SetInspectorContext(inspector_context); } - global_inspector->CreateContext(); } #endif std::shared_ptr ctx = scope->GetContext(); @@ -206,12 +209,10 @@ int64_t V8BridgeUtils::InitInstance(bool enable_v8_serialization, FOOTSTONE_DLOG(FATAL) << "RunApp send_v8_func_ j_runtime_id invalid or not debugger"; return; } - { - std::lock_guard lock(inspector_mutex); - if (global_inspector) { - auto u16str = StringViewUtils::Convert(unicode_string_view(data), unicode_string_view::Encoding::Utf16); - global_inspector->SendMessageToV8(std::move(u16str)); - } + auto inspector_client = runtime->GetEngine()->GetInspectorClient(); + if (inspector_client) { + auto u16str = StringViewUtils::Convert(unicode_string_view(data), unicode_string_view::Encoding::Utf16); + inspector_client->SendMessageToV8(runtime->GetInspectorContext(), std::move(u16str)); } }); } @@ -396,9 +397,11 @@ void V8BridgeUtils::DestroyInstance(int64_t runtime_id, const std::function