feat(devtools): support multi instance

fix(devtools): add end line

fix(devtools): fix compile

fix(devtools): add define for context

fix(devtools): fix compile
This commit is contained in:
ivanfanwu
2022-08-02 11:04:50 +08:00
committed by churchill-zhang
parent b26f801d70
commit 207c92aa56
8 changed files with 188 additions and 88 deletions
+15
View File
@@ -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<TaskRunner> GetWorkerTaskRunner() {
return worker_task_runner_;
}
#if defined(ENABLE_INSPECTOR) && !defined(V8_WITHOUT_INSPECTOR)
inline void SetInspectorClient(std::shared_ptr<hippy::inspector::V8InspectorClientImpl> inspector_client) {
inspector_client_ = inspector_client;
}
inline std::shared_ptr<hippy::inspector::V8InspectorClientImpl> GetInspectorClient() {
return inspector_client_;
}
#endif
private:
void CreateVM(const std::shared_ptr<VMInitParam>& param);
@@ -71,4 +83,7 @@ class Engine {
std::unique_ptr<RegisterMap> map_;
std::mutex cnt_mutex_;
uint32_t scope_cnt_;
#if defined(ENABLE_INSPECTOR) && !defined(V8_WITHOUT_INSPECTOR)
std::shared_ptr<hippy::inspector::V8InspectorClientImpl> inspector_client_;
#endif
};
@@ -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> scope, std::weak_ptr<TaskRunner> runner);
explicit V8InspectorClientImpl(std::weak_ptr<TaskRunner> runner): js_runner_(std::move(runner)) {}
~V8InspectorClientImpl();
inline std::shared_ptr<TaskRunner> GetInspectorRunner() {
return inspector_runner_;
}
inline std::unique_ptr<V8ChannelImpl>& GetChannel() {
return channel_;
}
inline std::unique_ptr<v8_inspector::V8InspectorSession>& GetSession() {
return session_;
}
inline void SetSession(std::unique_ptr<v8_inspector::V8InspectorSession> session) {
session_ = std::move(session);
}
void CreateInspector(const std::shared_ptr<Scope>& scope);
#if defined(ENABLE_INSPECTOR) && !defined(V8_WITHOUT_INSPECTOR)
std::shared_ptr<V8InspectorContext> CreateInspectorContext(const std::shared_ptr<Scope> scope, std::shared_ptr<hippy::devtools::DevtoolsDataSource> devtools_data_source);
void DestroyInspectorContext(bool is_reload, const std::shared_ptr<V8InspectorContext> &inspector_context);
#endif
void SendMessageToV8(const std::shared_ptr<V8InspectorContext>& inspector_context, unicode_string_view&& params);
inline std::unique_ptr<v8_inspector::V8Inspector>& GetInspector() {
return inspector_;
}
#if defined(ENABLE_INSPECTOR) && !defined(V8_WITHOUT_INSPECTOR)
void Reset(std::shared_ptr<Scope> scope, const std::shared_ptr<hippy::devtools::DevtoolsDataSource> devtools_data_source);
void Connect(const std::shared_ptr<hippy::devtools::DevtoolsDataSource> devtools_data_source);
#endif
void SendMessageToV8(unicode_string_view&& params);
void CreateContext();
void DestroyContext();
v8::Local<v8::Context> ensureDefaultContextInGroup(int contextGroupId) override;
void runMessageLoopOnPause(int contextGroupId) override;
void quitMessageLoopOnPause() override;
void runIfWaitingForDebugger(int contextGroupId) override;
private:
std::shared_ptr<Scope> scope_;
void CreateContext(const std::shared_ptr<V8InspectorContext>& inspector_context);
void DestroyContext(const std::shared_ptr<V8InspectorContext>& inspector_context);
std::unique_ptr<v8_inspector::V8Inspector> inspector_;
std::unique_ptr<V8ChannelImpl> channel_;
std::unique_ptr<v8_inspector::V8InspectorSession> session_;
std::weak_ptr<TaskRunner> js_runner_;
std::shared_ptr<TaskRunner> inspector_runner_;
std::mutex mutex_;
std::shared_ptr<InterruptQueue> interrupt_queue_;
std::shared_ptr<V8InspectorContext> reload_inspector_context_;
std::atomic_int32_t context_group_count_{1};
std::unordered_map<int32_t, std::shared_ptr<V8InspectorContext>> inspector_context_map_;
std::mutex inspector_context_mutex_;
};
} // namespace inspector
@@ -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<V8ChannelImpl> channel,
std::unique_ptr<v8_inspector::V8InspectorSession> session)
: context_group_id_(group_id), channel_(std::move(channel)),
session_(std::move(session)) {}
inline void SetSession(std::unique_ptr<v8_inspector::V8InspectorSession> session) { session_ = std::move(session); }
#if defined(ENABLE_INSPECTOR) && !defined(V8_WITHOUT_INSPECTOR)
inline void SetDevtoolsDataSource(std::shared_ptr<hippy::devtools::DevtoolsDataSource> devtools_data_source) { if (channel_) { channel_->SetDevtoolsDataSource(std::move(devtools_data_source));} }
#endif
inline void SetScope(std::shared_ptr<Scope> scope) { scope_ = std::move(scope); }
inline std::shared_ptr<Scope> 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<V8ChannelImpl> channel_;
std::unique_ptr<v8_inspector::V8InspectorSession> session_;
std::shared_ptr<Scope> scope_;
};
} // namespace inspector
} // namespace hippy
@@ -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_ = bridge;
}
#if defined(ENABLE_INSPECTOR) && !defined(V8_WITHOUT_INSPECTOR)
inline void SetInspectorContext(std::shared_ptr<hippy::inspector::V8InspectorContext> inspector_context) {
inspector_context_ = inspector_context;
}
inline std::shared_ptr<hippy::inspector::V8InspectorContext> GetInspectorContext() { return inspector_context_; }
#endif
#ifdef ENABLE_INSPECTOR
inline void SetDevtoolsDataSource(std::shared_ptr<hippy::devtools::DevtoolsDataSource> devtools_data_source) {
devtools_data_source_ = devtools_data_source;
@@ -113,4 +115,7 @@ class Runtime {
#endif
std::shared_ptr<Bridge> bridge_;
#if defined(ENABLE_INSPECTOR) && !defined(V8_WITHOUT_INSPECTOR)
std::shared_ptr<hippy::inspector::V8InspectorContext> inspector_context_;
#endif
};
@@ -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"
@@ -25,15 +25,18 @@
#include <utility>
#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> scope, std::weak_ptr<TaskRunner> runner)
: scope_(std::move(scope)), js_runner_(std::move(runner)) {
void V8InspectorClientImpl::CreateInspector(const std::shared_ptr<Scope>& scope) {
if (inspector_) {
return;
}
std::shared_ptr<hippy::napi::V8Ctx> ctx =
std::static_pointer_cast<hippy::napi::V8Ctx>(scope_->GetContext());
std::static_pointer_cast<hippy::napi::V8Ctx>(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> scope, std::
map.Insert(interrupt_queue_->GetId(), interrupt_queue_);
}
#if defined(ENABLE_INSPECTOR) && !defined(V8_WITHOUT_INSPECTOR)
std::shared_ptr<V8InspectorContext> V8InspectorClientImpl::CreateInspectorContext(const std::shared_ptr<Scope> scope,
std::shared_ptr<hippy::devtools::DevtoolsDataSource> 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<V8ChannelImpl>();
channel->SetDevtoolsDataSource(devtools_data_source);
auto session = inspector_->connect(context_group_id, channel.get(), v8_inspector::StringView());
inspector_context = std::make_shared<V8InspectorContext>(context_group_id, std::move(channel), std::move(session));
std::lock_guard<std::mutex> 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<std::mutex> 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> scope,
const std::shared_ptr<hippy::devtools::DevtoolsDataSource> devtools_data_source) {
scope_ = std::move(scope);
channel_->SetDevtoolsDataSource(devtools_data_source);
}
void V8InspectorClientImpl::Connect(const std::shared_ptr<hippy::devtools::DevtoolsDataSource> devtools_data_source) {
channel_ = std::make_unique<V8ChannelImpl>();
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<V8InspectorContext>& inspector_context) {
std::shared_ptr<hippy::napi::V8Ctx> ctx =
std::static_pointer_cast<hippy::napi::V8Ctx>(scope_->GetContext());
std::static_pointer_cast<hippy::napi::V8Ctx>(inspector_context->GetScope()->GetContext());
v8::Isolate* isolate = ctx->isolate_;
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context =
v8::Local<v8::Context>::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<V8InspectorContext>& inspector_context_ref, unicode_string_view&& params) {
std::shared_ptr<TaskRunner> msg_runner;
{
std::unique_lock<std::mutex> lock(mutex_);
@@ -89,14 +115,15 @@ void V8InspectorClientImpl::SendMessageToV8(unicode_string_view&& params) {
interrupt_queue_->SetTaskRunner(msg_runner);
}
std::weak_ptr<V8InspectorContext> 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<int>(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<V8InspectorContext>& inspector_context) {
FOOTSTONE_DLOG(INFO) << "V8InspectorClientImpl DestroyContext";
std::shared_ptr<hippy::napi::V8Ctx> ctx =
std::static_pointer_cast<hippy::napi::V8Ctx>(scope_->GetContext());
std::static_pointer_cast<hippy::napi::V8Ctx>(inspector_context->GetScope()->GetContext());
if (!ctx) {
FOOTSTONE_DLOG(ERROR) << "V8InspectorClientImpl ctx error";
return;
@@ -158,8 +181,14 @@ void V8InspectorClientImpl::DestroyContext() {
v8::Local<v8::Context> V8InspectorClientImpl::ensureDefaultContextInGroup(
int contextGroupId) {
std::lock_guard<std::mutex> 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<hippy::napi::V8Ctx> ctx =
std::static_pointer_cast<hippy::napi::V8Ctx>(scope_->GetContext());
std::static_pointer_cast<hippy::napi::V8Ctx>(inspector_context_entry->second->GetScope()->GetContext());
v8::Isolate* isolate = ctx->isolate_;
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context =
@@ -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<V8InspectorClientImpl> global_inspector = nullptr;
#endif
static std::unordered_map<int64_t, std::pair<std::shared_ptr<Engine>, 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<void*>(runtime_id));
#if defined(ENABLE_INSPECTOR) && !defined(V8_WITHOUT_INSPECTOR)
std::shared_ptr<Runtime> runtime = Runtime::Find(runtime_id);
if (runtime->IsDebug()) {
auto inspector = std::make_shared<V8InspectorClientImpl>(runtime->GetEngine()->GetJsTaskRunner());
runtime->GetEngine()->SetInspectorClient(inspector);
}
#endif
};
std::unique_ptr<RegisterMap> engine_cb_map = std::make_unique<RegisterMap>();
@@ -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<std::mutex> lock(inspector_mutex);
if (!global_inspector) {
global_inspector = std::make_shared<V8InspectorClientImpl>(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> 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<std::mutex> 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<void
FOOTSTONE_LOG(INFO) << "js destroy begin, runtime_id = " << runtime_id << ", is_reload = " << is_reload;
#if defined(ENABLE_INSPECTOR) && !defined(V8_WITHOUT_INSPECTOR)
if (runtime->IsDebug()) {
std::lock_guard<std::mutex> lock(inspector_mutex);
global_inspector->DestroyContext();
global_inspector->Reset(nullptr, nullptr);
auto inspector_client = runtime->GetEngine()->GetInspectorClient();
if (inspector_client) {
auto inspector_context = runtime->GetInspectorContext();
inspector_client->DestroyInspectorContext(is_reload, inspector_context);
}
} else {
runtime->GetScope()->WillExit();
}
@@ -2361,6 +2361,7 @@
"$(inherited)",
"ENABLE_INSPECTOR=true",
"JS_USE_JSC=1",
"V8_WITHOUT_INSPECTOR=1",
);
HEADER_SEARCH_PATHS = (
"$(SRCROOT)/../../../../modules/footstone/include",
@@ -2402,6 +2403,7 @@
"$(inherited)",
"COCOAPODS=1",
"JS_USE_JSC=1",
"V8_WITHOUT_INSPECTOR=1",
);
HEADER_SEARCH_PATHS = (
"$(SRCROOT)/../../../../modules/footstone/include",