refactor: allocate api::Debugger on cpp heap (#48266)

* refactor: remove unused isolate arg from Debugger ctor

* refactor: make Debugger ctor, dtor public

needed for cppgc::MakeGarbageCollected()

This is what upstream does, e.g. https://chromium-review.googlesource.com/c/chromium/src/+/6722236

* fixup! refactor: remove unused isolate arg from Debugger ctor

mark Debugger ctor as explicit

* refactor: in EventEmitterMixin, handle both old and new WrapperInfo types

* refactor: make electron::api::Debugger inherit from gin::Wrappable

* refactor: add api::Debugger::GetTypeName()

* refactor: add api::Debugger::GetClassName()
This commit is contained in:
Charles Kerr
2025-09-11 15:03:17 -05:00
committed by GitHub
parent 45353ae38c
commit a6959ca97b
6 changed files with 72 additions and 34 deletions

View File

@@ -8,17 +8,18 @@ electron objects that extend gin::Wrappable and gets
allocated on the cpp heap
diff --git a/gin/public/wrappable_pointer_tags.h b/gin/public/wrappable_pointer_tags.h
index 80ec409efe1635390887d1324be661643818abff..112a23f81680f5fcc2b016d8f5362e3a03507c8a 100644
index 80ec409efe1635390887d1324be661643818abff..2b82f96d12715b6476c456b73dfd1a7342736f8e 100644
--- a/gin/public/wrappable_pointer_tags.h
+++ b/gin/public/wrappable_pointer_tags.h
@@ -66,7 +66,10 @@ enum WrappablePointerTag : uint16_t {
@@ -66,7 +66,11 @@ enum WrappablePointerTag : uint16_t {
kTextInputControllerBindings, // content::TextInputControllerBindings
kWebAXObjectProxy, // content::WebAXObjectProxy
kWrappedExceptionHandler, // extensions::WrappedExceptionHandler
- kLastPointerTag = kWrappedExceptionHandler,
+ kElectronApp, // electron::api::App
+ kElectronSession, // electron::api::Session
+ kElectronDebugger, // electron::api::Debugger
+ kElectronEvent, // gin_helper::internal::Event
+ kElectronSession, // electron::api::Session
+ kLastPointerTag = kElectronEvent,
};

View File

@@ -19,15 +19,18 @@
#include "shell/common/gin_converters/value_converter.h"
#include "shell/common/gin_helper/handle.h"
#include "shell/common/gin_helper/promise.h"
#include "v8/include/cppgc/allocation.h"
#include "v8/include/v8-cppgc.h"
using content::DevToolsAgentHost;
namespace electron::api {
gin::DeprecatedWrapperInfo Debugger::kWrapperInfo = {gin::kEmbedderNativeGin};
gin::WrapperInfo Debugger::kWrapperInfo = {{gin::kEmbedderNativeGin},
gin::kElectronDebugger};
Debugger::Debugger(v8::Isolate* isolate, content::WebContents* web_contents)
: content::WebContentsObserver(web_contents), web_contents_(web_contents) {}
Debugger::Debugger(content::WebContents* web_contents)
: content::WebContentsObserver{web_contents}, web_contents_{web_contents} {}
Debugger::~Debugger() = default;
@@ -178,10 +181,10 @@ void Debugger::ClearPendingRequests() {
}
// static
gin_helper::Handle<Debugger> Debugger::Create(
v8::Isolate* isolate,
content::WebContents* web_contents) {
return gin_helper::CreateHandle(isolate, new Debugger(isolate, web_contents));
Debugger* Debugger::Create(v8::Isolate* isolate,
content::WebContents* web_contents) {
return cppgc::MakeGarbageCollected<Debugger>(
isolate->GetCppHeap()->GetAllocationHandle(), web_contents);
}
gin::ObjectTemplateBuilder Debugger::GetObjectTemplateBuilder(
@@ -194,8 +197,12 @@ gin::ObjectTemplateBuilder Debugger::GetObjectTemplateBuilder(
.SetMethod("sendCommand", &Debugger::SendCommand);
}
const char* Debugger::GetTypeName() {
return "Debugger";
const gin::WrapperInfo* Debugger::wrapper_info() const {
return &kWrapperInfo;
}
const char* Debugger::GetHumanReadableName() const {
return "Electron / Debugger";
}
} // namespace electron::api

View File

@@ -11,8 +11,8 @@
#include "base/values.h"
#include "content/public/browser/devtools_agent_host_client.h"
#include "content/public/browser/web_contents_observer.h"
#include "gin/wrappable.h"
#include "shell/browser/event_emitter_mixin.h"
#include "shell/common/gin_helper/wrappable.h"
namespace content {
class DevToolsAgentHost;
@@ -32,29 +32,32 @@ class Promise;
namespace electron::api {
class Debugger final : public gin_helper::DeprecatedWrappable<Debugger>,
class Debugger final : public gin::Wrappable<Debugger>,
public gin_helper::EventEmitterMixin<Debugger>,
public content::DevToolsAgentHostClient,
private content::WebContentsObserver {
public:
static gin_helper::Handle<Debugger> Create(
v8::Isolate* isolate,
content::WebContents* web_contents);
static Debugger* Create(v8::Isolate* isolate,
content::WebContents* web_contents);
// Make public for cppgc::MakeGarbageCollected.
explicit Debugger(content::WebContents* web_contents);
~Debugger() override;
// gin_helper::Wrappable
static gin::DeprecatedWrapperInfo kWrapperInfo;
static gin::WrapperInfo kWrapperInfo;
gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) override;
const char* GetTypeName() override;
const gin::WrapperInfo* wrapper_info() const override;
const char* GetHumanReadableName() const override;
const char* GetClassName() const { return "Debugger"; }
// disable copy
Debugger(const Debugger&) = delete;
Debugger& operator=(const Debugger&) = delete;
protected:
Debugger(v8::Isolate* isolate, content::WebContents* web_contents);
~Debugger() override;
// content::DevToolsAgentHostClient:
void AgentHostClosed(content::DevToolsAgentHost* agent_host) override;
void DispatchProtocolMessage(content::DevToolsAgentHost* agent_host,

View File

@@ -3804,11 +3804,16 @@ v8::Local<v8::Value> WebContents::DevToolsWebContents(v8::Isolate* isolate) {
}
v8::Local<v8::Value> WebContents::Debugger(v8::Isolate* isolate) {
if (debugger_.IsEmpty()) {
auto handle = electron::api::Debugger::Create(isolate, web_contents());
debugger_.Reset(isolate, handle.ToV8());
if (!debugger_) {
debugger_ = electron::api::Debugger::Create(isolate, web_contents());
}
return v8::Local<v8::Value>::New(isolate, debugger_);
v8::HandleScope handle_scope{isolate};
v8::Local<v8::Object> wrapper;
if (!debugger_->GetWrapper(isolate).ToLocal(&wrapper)) {
return v8::Null(isolate);
}
return v8::Local<v8::Value>::New(isolate, wrapper);
}
content::RenderFrameHost* WebContents::MainFrame() {

View File

@@ -31,6 +31,7 @@
#include "content/public/common/stop_find_action.h"
#include "electron/buildflags/buildflags.h"
#include "printing/buildflags/buildflags.h"
#include "shell/browser/api/electron_api_debugger.h"
#include "shell/browser/api/electron_api_session.h"
#include "shell/browser/api/save_page_handler.h"
#include "shell/browser/background_throttling_source.h"
@@ -772,7 +773,7 @@ class WebContents final : public ExclusiveAccessContext,
cppgc::Persistent<api::Session> session_;
v8::Global<v8::Value> devtools_web_contents_;
v8::Global<v8::Value> debugger_;
cppgc::Persistent<api::Debugger> debugger_;
std::unique_ptr<WebViewGuestDelegate> guest_delegate_;
std::unique_ptr<FrameSubscriber> frame_subscriber_;

View File

@@ -6,6 +6,7 @@
#define ELECTRON_SHELL_BROWSER_EVENT_EMITTER_MIXIN_H_
#include <string_view>
#include <type_traits>
#include <utility>
#include "gin/object_template_builder.h"
@@ -57,17 +58,37 @@ class EventEmitterMixin {
gin::ObjectTemplateBuilder GetObjectTemplateBuilder(v8::Isolate* isolate) {
gin::PerIsolateData* data = gin::PerIsolateData::From(isolate);
auto* wrapper_info = &(static_cast<T*>(this)->kWrapperInfo);
v8::Local<v8::FunctionTemplate> constructor =
data->DeprecatedGetFunctionTemplate(wrapper_info);
// DeprecatedWrapperInfo support will be removed as part of
// https://github.com/electron/electron/issues/47922
constexpr bool is_deprecated_wrapper =
std::is_same_v<decltype(wrapper_info), gin::DeprecatedWrapperInfo*>;
v8::Local<v8::FunctionTemplate> constructor;
if constexpr (is_deprecated_wrapper) {
constructor = data->DeprecatedGetFunctionTemplate(wrapper_info);
} else {
constructor = data->GetFunctionTemplate(wrapper_info);
}
const char* class_name = "";
if constexpr (is_deprecated_wrapper) {
class_name = static_cast<T*>(this)->GetTypeName();
} else {
class_name = static_cast<T*>(this)->GetClassName();
}
if (constructor.IsEmpty()) {
constructor = v8::FunctionTemplate::New(isolate);
constructor->SetClassName(
gin::StringToV8(isolate, static_cast<T*>(this)->GetTypeName()));
constructor->SetClassName(gin::StringToV8(isolate, class_name));
constructor->Inherit(internal::GetEventEmitterTemplate(isolate));
data->DeprecatedSetFunctionTemplate(wrapper_info, constructor);
if constexpr (is_deprecated_wrapper) {
data->DeprecatedSetFunctionTemplate(wrapper_info, constructor);
} else {
data->SetFunctionTemplate(wrapper_info, constructor);
}
}
return gin::ObjectTemplateBuilder(isolate,
static_cast<T*>(this)->GetTypeName(),
return gin::ObjectTemplateBuilder(isolate, class_name,
constructor->InstanceTemplate());
}
};