refactor: allocate gin_helper::internal::Event on cpp heap (#48161)

This commit is contained in:
Robo 2025-08-27 09:30:50 +09:00 committed by GitHub
commit e0db4046b2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 156 additions and 116 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 a507d1d837ab3ec2b2d3ae7978d9d410ab2ec2d1..5a69c5c7c5ed0e834e09ff3a2d0f0126ba4ccf99 100644
index a507d1d837ab3ec2b2d3ae7978d9d410ab2ec2d1..2f4b90949972c3c4641bc9e489bd0c73c2f0a981 100644
--- a/gin/public/wrappable_pointer_tags.h
+++ b/gin/public/wrappable_pointer_tags.h
@@ -72,7 +72,9 @@ enum WrappablePointerTag : uint16_t {
@@ -72,7 +72,10 @@ enum WrappablePointerTag : uint16_t {
kTextInputControllerBindings, // content::TextInputControllerBindings
kWebAXObjectProxy, // content::WebAXObjectProxy
kWrappedExceptionHandler, // extensions::WrappedExceptionHandler
- kLastPointerTag = kWrappedExceptionHandler,
+ kElectronApp, // electron::api::App
+ kElectronSession, // electron::api::Session
+ kLastPointerTag = kElectronSession,
+ kElectronEvent, // gin_helper::internal::Event
+ kLastPointerTag = kElectronEvent,
};
static_assert(kLastPointerTag <

View file

@ -194,14 +194,15 @@ void BaseWindow::OnWindowQueryEndSession(
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
v8::HandleScope handle_scope(isolate);
gin_helper::Handle<gin_helper::internal::Event> event =
gin_helper::internal::Event* event =
gin_helper::internal::Event::New(isolate);
v8::Local<v8::Object> event_object = event.ToV8().As<v8::Object>();
v8::Local<v8::Object> event_object =
event->GetWrapper(isolate).ToLocalChecked();
gin::Dictionary dict(isolate, event_object);
dict.Set("reasons", reasons);
EmitWithoutEvent("query-session-end", event);
EmitWithoutEvent("query-session-end", event_object);
if (event->GetDefaultPrevented()) {
*prevent_default = true;
}
@ -211,14 +212,15 @@ void BaseWindow::OnWindowEndSession(const std::vector<std::string>& reasons) {
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
v8::HandleScope handle_scope(isolate);
gin_helper::Handle<gin_helper::internal::Event> event =
gin_helper::internal::Event* event =
gin_helper::internal::Event::New(isolate);
v8::Local<v8::Object> event_object = event.ToV8().As<v8::Object>();
v8::Local<v8::Object> event_object =
event->GetWrapper(isolate).ToLocalChecked();
gin::Dictionary dict(isolate, event_object);
dict.Set("reasons", reasons);
EmitWithoutEvent("session-end", event);
EmitWithoutEvent("session-end", event_object);
}
void BaseWindow::OnWindowBlur() {

View file

@ -1117,9 +1117,10 @@ void WebContents::OnDidAddMessageToConsole(
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
v8::HandleScope handle_scope(isolate);
gin_helper::Handle<gin_helper::internal::Event> event =
gin_helper::internal::Event* event =
gin_helper::internal::Event::New(isolate);
v8::Local<v8::Object> event_object = event.ToV8().As<v8::Object>();
v8::Local<v8::Object> event_object =
event->GetWrapper(isolate).ToLocalChecked();
gin_helper::Dictionary dict(isolate, event_object);
dict.SetGetter("frame", source_frame);
@ -1131,7 +1132,7 @@ void WebContents::OnDidAddMessageToConsole(
// TODO(samuelmaddock): Delete when deprecated arguments are fully removed.
dict.Set("_level", static_cast<int32_t>(level));
EmitWithoutEvent("-console-message", event);
EmitWithoutEvent("-console-message", event_object);
}
void WebContents::OnCreateWindow(
@ -1515,9 +1516,10 @@ void WebContents::RendererUnresponsive(
base::RepeatingClosure hang_monitor_restarter) {
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
v8::HandleScope handle_scope(isolate);
gin_helper::Handle<gin_helper::internal::Event> event =
gin_helper::internal::Event* event =
gin_helper::internal::Event::New(isolate);
v8::Local<v8::Object> event_object = event.ToV8().As<v8::Object>();
v8::Local<v8::Object> event_object =
event->GetWrapper(isolate).ToLocalChecked();
gin::Dictionary dict(isolate, event_object);
auto* web_contents_impl = static_cast<content::WebContentsImpl*>(source);
@ -1531,7 +1533,7 @@ void WebContents::RendererUnresponsive(
static_cast<content::RenderWidgetHostImpl*>(render_widget_host);
dict.Set("rendererInitialized", rwh_impl->renderer_initialized());
EmitWithoutEvent("-unresponsive", event);
EmitWithoutEvent("-unresponsive", event_object);
}
void WebContents::RendererResponsive(
@ -1700,12 +1702,13 @@ content::JavaScriptDialogManager* WebContents::GetJavaScriptDialogManager(
void WebContents::OnAudioStateChanged(bool audible) {
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
v8::HandleScope handle_scope(isolate);
gin_helper::Handle<gin_helper::internal::Event> event =
gin_helper::internal::Event* event =
gin_helper::internal::Event::New(isolate);
v8::Local<v8::Object> event_object = event.ToV8().As<v8::Object>();
v8::Local<v8::Object> event_object =
event->GetWrapper(isolate).ToLocalChecked();
gin::Dictionary dict(isolate, event_object);
dict.Set("audible", audible);
EmitWithoutEvent("audio-state-changed", event);
EmitWithoutEvent("audio-state-changed", event_object);
}
void WebContents::BeforeUnloadFired(bool proceed) {
@ -1968,9 +1971,10 @@ bool WebContents::EmitNavigationEvent(
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
v8::HandleScope handle_scope(isolate);
gin_helper::Handle<gin_helper::internal::Event> event =
gin_helper::internal::Event* event =
gin_helper::internal::Event::New(isolate);
v8::Local<v8::Object> event_object = event.ToV8().As<v8::Object>();
v8::Local<v8::Object> event_object =
event->GetWrapper(isolate).ToLocalChecked();
gin_helper::Dictionary dict(isolate, event_object);
dict.Set("url", url);
@ -1981,8 +1985,8 @@ bool WebContents::EmitNavigationEvent(
dict.SetGetter("frame", frame_host);
dict.SetGetter("initiator", initiator_frame_host);
EmitWithoutEvent(event_name, event, url, is_same_document, is_main_frame,
frame_process_id, frame_routing_id);
EmitWithoutEvent(event_name, event_object, url, is_same_document,
is_main_frame, frame_process_id, frame_routing_id);
return event->GetDefaultPrevented();
}
@ -3632,16 +3636,17 @@ void WebContents::OnPaint(const gfx::Rect& dirty_rect,
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
v8::HandleScope handle_scope(isolate);
gin_helper::Handle<gin_helper::internal::Event> event =
gin_helper::internal::Event* event =
gin_helper::internal::Event::New(isolate);
v8::Local<v8::Object> event_object = event.ToV8().As<v8::Object>();
v8::Local<v8::Object> event_object =
event->GetWrapper(isolate).ToLocalChecked();
gin_helper::Dictionary dict(isolate, event_object);
if (offscreen_use_shared_texture_) {
dict.Set("texture", tex);
}
EmitWithoutEvent("paint", event, dirty_rect,
EmitWithoutEvent("paint", event_object, dirty_rect,
gfx::Image::CreateFrom1xBitmap(bitmap));
}

View file

@ -18,6 +18,7 @@
#include "shell/common/gin_helper/handle.h"
#include "shell/common/gin_helper/reply_channel.h"
#include "shell/common/v8_util.h"
#include "v8/include/cppgc/macros.h"
namespace electron {
@ -25,15 +26,17 @@ namespace electron {
// See ipc-dispatch.ts for JS listeners.
template <typename T>
class IpcDispatcher {
CPPGC_DISALLOW_NEW();
public:
void Message(gin_helper::Handle<gin_helper::internal::Event>& event,
void Message(v8::Local<v8::Object> event,
const std::string& channel,
blink::CloneableMessage args) {
TRACE_EVENT1("electron", "IpcDispatcher::Message", "channel", channel);
emitter()->EmitWithoutEvent("-ipc-message", event, channel, args);
}
void Invoke(gin_helper::Handle<gin_helper::internal::Event>& event,
void Invoke(v8::Local<v8::Object> event,
const std::string& channel,
blink::CloneableMessage arguments) {
TRACE_EVENT1("electron", "IpcDispatcher::Invoke", "channel", channel);
@ -41,8 +44,7 @@ class IpcDispatcher {
std::move(arguments));
}
void ReceivePostMessage(
gin_helper::Handle<gin_helper::internal::Event>& event,
void ReceivePostMessage(v8::Local<v8::Object> event,
const std::string& channel,
blink::TransferableMessage message) {
TRACE_EVENT1("electron", "IpcDispatcher::ReceivePostMessage", "channel",
@ -57,7 +59,7 @@ class IpcDispatcher {
std::move(wrapped_ports));
}
void MessageSync(gin_helper::Handle<gin_helper::internal::Event>& event,
void MessageSync(v8::Local<v8::Object> event,
const std::string& channel,
blink::CloneableMessage arguments) {
TRACE_EVENT1("electron", "IpcDispatcher::MessageSync", "channel", channel);
@ -65,7 +67,7 @@ class IpcDispatcher {
std::move(arguments));
}
void MessageHost(gin_helper::Handle<gin_helper::internal::Event>& event,
void MessageHost(v8::Local<v8::Object> event,
const std::string& channel,
blink::CloneableMessage arguments) {
TRACE_EVENT1("electron", "IpcDispatcher::MessageHost", "channel", channel);

View file

@ -48,10 +48,10 @@ void ElectronApiIPCHandlerImpl::Message(bool internal,
if (session && session->Get()) {
v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate();
v8::HandleScope handle_scope(isolate);
auto event = MakeIPCEvent(isolate, session->Get(), internal);
if (event.IsEmpty())
return;
session->Get()->Message(event, channel, std::move(arguments));
auto* event = MakeIPCEvent(isolate, session->Get(), internal);
v8::Local<v8::Object> event_object =
event->GetWrapper(isolate).ToLocalChecked();
session->Get()->Message(event_object, channel, std::move(arguments));
}
}
void ElectronApiIPCHandlerImpl::Invoke(bool internal,
@ -62,11 +62,11 @@ void ElectronApiIPCHandlerImpl::Invoke(bool internal,
if (session && session->Get()) {
v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate();
v8::HandleScope handle_scope(isolate);
auto event =
auto* event =
MakeIPCEvent(isolate, session->Get(), internal, std::move(callback));
if (event.IsEmpty())
return;
session->Get()->Invoke(event, channel, std::move(arguments));
v8::Local<v8::Object> event_object =
event->GetWrapper(isolate).ToLocalChecked();
session->Get()->Invoke(event_object, channel, std::move(arguments));
}
}
@ -77,10 +77,11 @@ void ElectronApiIPCHandlerImpl::ReceivePostMessage(
if (session && session->Get()) {
v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate();
v8::HandleScope handle_scope(isolate);
auto event = MakeIPCEvent(isolate, session->Get(), false);
if (event.IsEmpty())
return;
session->Get()->ReceivePostMessage(event, channel, std::move(message));
auto* event = MakeIPCEvent(isolate, session->Get(), false);
v8::Local<v8::Object> event_object =
event->GetWrapper(isolate).ToLocalChecked();
session->Get()->ReceivePostMessage(event_object, channel,
std::move(message));
}
}
@ -92,11 +93,11 @@ void ElectronApiIPCHandlerImpl::MessageSync(bool internal,
if (session && session->Get()) {
v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate();
v8::HandleScope handle_scope(isolate);
auto event =
auto* event =
MakeIPCEvent(isolate, session->Get(), internal, std::move(callback));
if (event.IsEmpty())
return;
session->Get()->MessageSync(event, channel, std::move(arguments));
v8::Local<v8::Object> event_object =
event->GetWrapper(isolate).ToLocalChecked();
session->Get()->MessageSync(event_object, channel, std::move(arguments));
}
}
@ -106,10 +107,10 @@ void ElectronApiIPCHandlerImpl::MessageHost(const std::string& channel,
if (session && session->Get()) {
v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate();
v8::HandleScope handle_scope(isolate);
auto event = MakeIPCEvent(isolate, session->Get(), false);
if (event.IsEmpty())
return;
session->Get()->MessageHost(event, channel, std::move(arguments));
auto* event = MakeIPCEvent(isolate, session->Get(), false);
v8::Local<v8::Object> event_object =
event->GetWrapper(isolate).ToLocalChecked();
session->Get()->MessageHost(event_object, channel, std::move(arguments));
}
}
@ -123,8 +124,7 @@ gin::WeakCell<api::Session>* ElectronApiIPCHandlerImpl::GetSession() {
: nullptr;
}
gin_helper::Handle<gin_helper::internal::Event>
ElectronApiIPCHandlerImpl::MakeIPCEvent(
gin_helper::internal::Event* ElectronApiIPCHandlerImpl::MakeIPCEvent(
v8::Isolate* isolate,
api::Session* session,
bool internal,
@ -159,9 +159,11 @@ ElectronApiIPCHandlerImpl::MakeIPCEvent(
}
content::RenderFrameHost* frame = GetRenderFrameHost();
gin_helper::Handle<gin_helper::internal::Event> event =
gin_helper::internal::Event* event =
gin_helper::internal::Event::New(isolate);
gin_helper::Dictionary dict(isolate, event.ToV8().As<v8::Object>());
v8::Local<v8::Object> event_object =
event->GetWrapper(isolate).ToLocalChecked();
gin_helper::Dictionary dict(isolate, event_object);
dict.Set("type", "frame");
dict.Set("sender", web_contents());
if (internal)

View file

@ -72,7 +72,7 @@ class ElectronApiIPCHandlerImpl : public mojom::ElectronApiIPC,
content::RenderFrameHost* GetRenderFrameHost();
gin::WeakCell<api::Session>* GetSession();
gin_helper::Handle<gin_helper::internal::Event> MakeIPCEvent(
gin_helper::internal::Event* MakeIPCEvent(
v8::Isolate* isolate,
api::Session* session,
bool internal,

View file

@ -75,10 +75,10 @@ void ElectronApiSWIPCHandlerImpl::Message(bool internal,
if (session && session->Get()) {
v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate();
v8::HandleScope handle_scope(isolate);
auto event = MakeIPCEvent(isolate, session->Get(), internal);
if (event.IsEmpty())
return;
session->Get()->Message(event, channel, std::move(arguments));
auto* event = MakeIPCEvent(isolate, session->Get(), internal);
v8::Local<v8::Object> event_object =
event->GetWrapper(isolate).ToLocalChecked();
session->Get()->Message(event_object, channel, std::move(arguments));
}
}
@ -90,11 +90,11 @@ void ElectronApiSWIPCHandlerImpl::Invoke(bool internal,
if (session && session->Get()) {
v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate();
v8::HandleScope handle_scope(isolate);
auto event =
auto* event =
MakeIPCEvent(isolate, session->Get(), internal, std::move(callback));
if (event.IsEmpty())
return;
session->Get()->Invoke(event, channel, std::move(arguments));
v8::Local<v8::Object> event_object =
event->GetWrapper(isolate).ToLocalChecked();
session->Get()->Invoke(event_object, channel, std::move(arguments));
}
}
@ -105,10 +105,11 @@ void ElectronApiSWIPCHandlerImpl::ReceivePostMessage(
if (session && session->Get()) {
v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate();
v8::HandleScope handle_scope(isolate);
auto event = MakeIPCEvent(isolate, session->Get(), false);
if (event.IsEmpty())
return;
session->Get()->ReceivePostMessage(event, channel, std::move(message));
auto* event = MakeIPCEvent(isolate, session->Get(), false);
v8::Local<v8::Object> event_object =
event->GetWrapper(isolate).ToLocalChecked();
session->Get()->ReceivePostMessage(event_object, channel,
std::move(message));
}
}
@ -120,11 +121,11 @@ void ElectronApiSWIPCHandlerImpl::MessageSync(bool internal,
if (session && session->Get()) {
v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate();
v8::HandleScope handle_scope(isolate);
auto event =
auto* event =
MakeIPCEvent(isolate, session->Get(), internal, std::move(callback));
if (event.IsEmpty())
return;
session->Get()->MessageSync(event, channel, std::move(arguments));
v8::Local<v8::Object> event_object =
event->GetWrapper(isolate).ToLocalChecked();
session->Get()->MessageSync(event_object, channel, std::move(arguments));
}
}
@ -144,8 +145,7 @@ gin::WeakCell<api::Session>* ElectronApiSWIPCHandlerImpl::GetSession() {
return api::Session::FromBrowserContext(GetBrowserContext());
}
gin_helper::Handle<gin_helper::internal::Event>
ElectronApiSWIPCHandlerImpl::MakeIPCEvent(
gin_helper::internal::Event* ElectronApiSWIPCHandlerImpl::MakeIPCEvent(
v8::Isolate* isolate,
api::Session* session,
bool internal,
@ -159,9 +159,10 @@ ElectronApiSWIPCHandlerImpl::MakeIPCEvent(
return {};
}
gin_helper::Handle<gin_helper::internal::Event> event =
gin_helper::internal::Event* event =
gin_helper::internal::Event::New(isolate);
v8::Local<v8::Object> event_object = event.ToV8().As<v8::Object>();
v8::Local<v8::Object> event_object =
event->GetWrapper(isolate).ToLocalChecked();
gin_helper::Dictionary dict(isolate, event_object);
dict.Set("type", "service-worker");

View file

@ -13,7 +13,6 @@
#include "electron/shell/common/api/api.mojom.h"
#include "mojo/public/cpp/bindings/associated_receiver.h"
#include "shell/common/gin_helper/event.h"
#include "shell/common/gin_helper/handle.h"
namespace content {
class RenderProcessHost;
@ -75,7 +74,7 @@ class ElectronApiSWIPCHandlerImpl : public mojom::ElectronApiIPC,
ElectronBrowserContext* GetBrowserContext();
gin::WeakCell<api::Session>* GetSession();
gin_helper::Handle<gin_helper::internal::Event> MakeIPCEvent(
gin_helper::internal::Event* MakeIPCEvent(
v8::Isolate* isolate,
api::Session* session,
bool internal,

View file

@ -48,9 +48,10 @@ void ElectronNSSCryptoModuleDelegate::RequestPasswordOnUIThread(
v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate();
v8::HandleScope handle_scope(isolate);
gin_helper::Handle<gin_helper::internal::Event> event =
gin_helper::internal::Event* event =
gin_helper::internal::Event::New(isolate);
v8::Local<v8::Object> event_object = event.ToV8().As<v8::Object>();
v8::Local<v8::Object> event_object =
event->GetWrapper(isolate).ToLocalChecked();
gin_helper::Dictionary dict(isolate, event_object);
dict.Set("hostname", server_.host());
dict.Set("tokenName", token_name);

View file

@ -32,8 +32,10 @@ class EventEmitterMixin {
v8::Local<v8::Object> wrapper;
if (!static_cast<T*>(this)->GetWrapper(isolate).ToLocal(&wrapper))
return false;
gin_helper::Handle<internal::Event> event = internal::Event::New(isolate);
gin_helper::EmitEvent(isolate, wrapper, name, event,
internal::Event* event = internal::Event::New(isolate);
v8::Local<v8::Object> event_object =
event->GetWrapper(isolate).ToLocalChecked();
gin_helper::EmitEvent(isolate, wrapper, name, event_object,
std::forward<Args>(args)...);
return event->GetDefaultPrevented();
}

View file

@ -3,21 +3,24 @@
// found in the LICENSE file.
#include "shell/common/gin_helper/event.h"
#include "gin/dictionary.h"
#include "gin/object_template_builder.h"
#include "shell/common/gin_helper/handle.h"
#include "v8/include/cppgc/allocation.h"
#include "v8/include/v8-cppgc.h"
namespace gin_helper::internal {
// static
gin_helper::Handle<Event> Event::New(v8::Isolate* isolate) {
return gin_helper::CreateHandle(isolate, new Event());
Event* Event::New(v8::Isolate* isolate) {
auto* event = cppgc::MakeGarbageCollected<Event>(
isolate->GetCppHeap()->GetAllocationHandle());
return event;
}
// static
v8::Local<v8::ObjectTemplate> Event::FillObjectTemplate(
v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> templ) {
return gin::ObjectTemplateBuilder(isolate, "Event", templ)
return gin::ObjectTemplateBuilder(isolate, GetClassName(), templ)
.SetMethod("preventDefault", &Event::PreventDefault)
.SetProperty("defaultPrevented", &Event::GetDefaultPrevented)
.Build();
@ -27,10 +30,15 @@ Event::Event() = default;
Event::~Event() = default;
gin::DeprecatedWrapperInfo Event::kWrapperInfo = {gin::kEmbedderNativeGin};
gin::WrapperInfo Event::kWrapperInfo = {{gin::kEmbedderNativeGin},
gin::kElectronEvent};
const char* Event::GetTypeName() {
return GetClassName();
const gin::WrapperInfo* Event::wrapper_info() const {
return &kWrapperInfo;
}
const char* Event::GetHumanReadableName() const {
return "Electron / Event";
}
} // namespace gin_helper::internal

View file

@ -5,38 +5,27 @@
#ifndef ELECTRON_SHELL_COMMON_GIN_HELPER_EVENT_H_
#define ELECTRON_SHELL_COMMON_GIN_HELPER_EVENT_H_
#include "gin/wrappable.h"
#include "shell/common/gin_helper/constructible.h"
#include "shell/common/gin_helper/wrappable.h"
namespace gin_helper {
template <typename T>
class Handle;
} // namespace gin_helper
namespace v8 {
class Isolate;
template <typename T>
class Local;
class Object;
class ObjectTemplate;
} // namespace v8
namespace gin_helper::internal {
class Event final : public gin_helper::DeprecatedWrappable<Event>,
class Event final : public gin::Wrappable<Event>,
public gin_helper::Constructible<Event> {
public:
// gin_helper::Constructible
static gin_helper::Handle<Event> New(v8::Isolate* isolate);
static Event* New(v8::Isolate* isolate);
static v8::Local<v8::ObjectTemplate> FillObjectTemplate(
v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype);
static const char* GetClassName() { return "Event"; }
// gin_helper::Wrappable
static gin::DeprecatedWrapperInfo kWrapperInfo;
const char* GetTypeName() override;
// gin::Wrappable
static gin::WrapperInfo kWrapperInfo;
const gin::WrapperInfo* wrapper_info() const override;
const char* GetHumanReadableName() const override;
Event();
~Event() override;
void PreventDefault() { default_prevented_ = true; }
@ -44,8 +33,6 @@ class Event final : public gin_helper::DeprecatedWrappable<Event>,
bool GetDefaultPrevented() { return default_prevented_; }
private:
Event();
bool default_prevented_ = false;
};

View file

@ -31,10 +31,13 @@ class EventEmitter : public gin_helper::Wrappable<T> {
v8::Local<v8::Object> wrapper = this->GetWrapper();
if (wrapper.IsEmpty())
return false;
gin_helper::Handle<internal::Event> event = internal::Event::New(isolate);
internal::Event* event = internal::Event::New(isolate);
v8::Local<v8::Object> event_object =
event->GetWrapper(isolate).ToLocalChecked();
// It's possible that |this| will be deleted by EmitEvent, so save anything
// we need from |this| before calling EmitEvent.
EmitEvent(isolate, wrapper, name, event, std::forward<Args>(args)...);
EmitEvent(isolate, wrapper, name, event_object,
std::forward<Args>(args)...);
return event->GetDefaultPrevented();
}

View file

@ -644,7 +644,8 @@ void NodeBindings::Initialize(v8::Isolate* const isolate,
SetErrorMode(GetErrorMode() & ~SEM_NOGPFAULTERRORBOX);
#endif
gin_helper::internal::Event::GetConstructor(isolate, context);
gin_helper::internal::Event::GetConstructor(
isolate, context, &gin_helper::internal::Event::kWrapperInfo);
g_is_initialized = true;
}

View file

@ -76,4 +76,30 @@ describe('cpp heap', () => {
expect(result).to.equal(true);
});
});
describe('internal event', () => {
it('should record as node in heap snapshot', async () => {
const { remotely } = await startRemoteControlApp(['--expose-internals']);
const result = await remotely(async (heap: string, snapshotHelper: string) => {
const { BrowserWindow } = require('electron');
const { once } = require('node:events');
const { recordState } = require(heap);
const { containsRetainingPath } = require(snapshotHelper);
const w = new BrowserWindow({
show: false
});
await w.loadURL('about:blank');
const state = recordState();
const isClosed = once(w, 'closed');
w.destroy();
await isClosed;
const eventNativeStackReference = containsRetainingPath(state.snapshot, ['C++ native stack roots', 'Electron / Event']);
const noPersistentReference = !containsRetainingPath(state.snapshot, ['C++ Persistent roots', 'Electron / Event']);
return eventNativeStackReference && noPersistentReference;
}, path.join(__dirname, '../../third_party/electron_node/test/common/heap'),
path.join(__dirname, 'lib', 'heapsnapshot-helpers.js'));
expect(result).to.equal(true);
});
});
});