refactor: allocate api::Session on cpp heap (#48141)
This commit is contained in:
parent
0917ed5f6f
commit
3ccb1bc0a8
32 changed files with 632 additions and 293 deletions
|
@ -99,6 +99,7 @@
|
|||
#include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
#include "url/origin.h"
|
||||
#include "v8/include/v8-traced-handle.h"
|
||||
|
||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||
#include "shell/browser/api/electron_api_extensions.h"
|
||||
|
@ -544,23 +545,27 @@ class DictionaryObserver final : public SpellcheckCustomDictionary::Observer {
|
|||
#endif // BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
|
||||
|
||||
struct UserDataLink : base::SupportsUserData::Data {
|
||||
explicit UserDataLink(base::WeakPtr<Session> session_in)
|
||||
: session{std::move(session_in)} {}
|
||||
explicit UserDataLink(
|
||||
cppgc::WeakPersistent<gin::WeakCell<Session>> session_in)
|
||||
: session{session_in} {}
|
||||
|
||||
base::WeakPtr<Session> session;
|
||||
cppgc::WeakPersistent<gin::WeakCell<Session>> session;
|
||||
};
|
||||
|
||||
const void* kElectronApiSessionKey = &kElectronApiSessionKey;
|
||||
|
||||
} // namespace
|
||||
|
||||
gin::DeprecatedWrapperInfo Session::kWrapperInfo = {gin::kEmbedderNativeGin};
|
||||
gin::WrapperInfo Session::kWrapperInfo = {{gin::kEmbedderNativeGin},
|
||||
gin::kElectronSession};
|
||||
|
||||
Session::Session(v8::Isolate* isolate, ElectronBrowserContext* browser_context)
|
||||
: isolate_(isolate),
|
||||
network_emulation_token_(base::UnguessableToken::Create()),
|
||||
browser_context_{
|
||||
raw_ref<ElectronBrowserContext>::from_ptr(browser_context)} {
|
||||
gin::PerIsolateData* data = gin::PerIsolateData::From(isolate);
|
||||
data->AddDisposeObserver(this);
|
||||
// Observe DownloadManager to get download notifications.
|
||||
browser_context->GetDownloadManager()->AddObserver(this);
|
||||
|
||||
|
@ -572,7 +577,10 @@ Session::Session(v8::Isolate* isolate, ElectronBrowserContext* browser_context)
|
|||
|
||||
browser_context->SetUserData(
|
||||
kElectronApiSessionKey,
|
||||
std::make_unique<UserDataLink>(weak_factory_.GetWeakPtr()));
|
||||
std::make_unique<UserDataLink>(
|
||||
cppgc::WeakPersistent<gin::WeakCell<Session>>(
|
||||
weak_factory_.GetWeakCell(
|
||||
isolate->GetCppHeap()->GetAllocationHandle()))));
|
||||
|
||||
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
|
||||
if (auto* service =
|
||||
|
@ -583,14 +591,20 @@ Session::Session(v8::Isolate* isolate, ElectronBrowserContext* browser_context)
|
|||
}
|
||||
|
||||
Session::~Session() {
|
||||
browser_context()->GetDownloadManager()->RemoveObserver(this);
|
||||
Dispose();
|
||||
}
|
||||
|
||||
void Session::Dispose() {
|
||||
if (keep_alive_) {
|
||||
browser_context()->GetDownloadManager()->RemoveObserver(this);
|
||||
|
||||
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
|
||||
if (auto* service =
|
||||
SpellcheckServiceFactory::GetForContext(browser_context())) {
|
||||
service->SetHunspellObserver(nullptr);
|
||||
}
|
||||
if (auto* service =
|
||||
SpellcheckServiceFactory::GetForContext(browser_context())) {
|
||||
service->SetHunspellObserver(nullptr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void Session::OnDownloadCreated(content::DownloadManager* manager,
|
||||
|
@ -1307,7 +1321,7 @@ v8::Local<v8::Promise> Session::GetSharedDictionaryUsageInfo() {
|
|||
}
|
||||
|
||||
v8::Local<v8::Value> Session::Cookies(v8::Isolate* isolate) {
|
||||
if (cookies_.IsEmpty()) {
|
||||
if (cookies_.IsEmptyThreadSafe()) {
|
||||
auto handle = Cookies::Create(isolate, browser_context());
|
||||
cookies_.Reset(isolate, handle.ToV8());
|
||||
}
|
||||
|
@ -1316,7 +1330,7 @@ v8::Local<v8::Value> Session::Cookies(v8::Isolate* isolate) {
|
|||
|
||||
v8::Local<v8::Value> Session::Extensions(v8::Isolate* isolate) {
|
||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||
if (extensions_.IsEmpty()) {
|
||||
if (extensions_.IsEmptyThreadSafe()) {
|
||||
v8::Local<v8::Value> handle;
|
||||
handle = Extensions::Create(isolate, browser_context()).ToV8();
|
||||
extensions_.Reset(isolate, handle);
|
||||
|
@ -1330,7 +1344,7 @@ v8::Local<v8::Value> Session::Protocol(v8::Isolate* isolate) {
|
|||
}
|
||||
|
||||
v8::Local<v8::Value> Session::ServiceWorkerContext(v8::Isolate* isolate) {
|
||||
if (service_worker_context_.IsEmpty()) {
|
||||
if (service_worker_context_.IsEmptyThreadSafe()) {
|
||||
v8::Local<v8::Value> handle;
|
||||
handle = ServiceWorkerContext::Create(isolate, browser_context()).ToV8();
|
||||
service_worker_context_.Reset(isolate, handle);
|
||||
|
@ -1339,7 +1353,7 @@ v8::Local<v8::Value> Session::ServiceWorkerContext(v8::Isolate* isolate) {
|
|||
}
|
||||
|
||||
v8::Local<v8::Value> Session::WebRequest(v8::Isolate* isolate) {
|
||||
if (web_request_.IsEmpty()) {
|
||||
if (web_request_.IsEmptyThreadSafe()) {
|
||||
auto handle = WebRequest::Create(isolate, browser_context());
|
||||
web_request_.Reset(isolate, handle.ToV8());
|
||||
}
|
||||
|
@ -1347,7 +1361,7 @@ v8::Local<v8::Value> Session::WebRequest(v8::Isolate* isolate) {
|
|||
}
|
||||
|
||||
v8::Local<v8::Value> Session::NetLog(v8::Isolate* isolate) {
|
||||
if (net_log_.IsEmpty()) {
|
||||
if (net_log_.IsEmptyThreadSafe()) {
|
||||
auto handle = NetLog::Create(isolate, browser_context());
|
||||
net_log_.Reset(isolate, handle.ToV8());
|
||||
}
|
||||
|
@ -1656,42 +1670,49 @@ bool Session::IsSpellCheckerEnabled() const {
|
|||
#endif // BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
|
||||
|
||||
// static
|
||||
Session* Session::FromBrowserContext(content::BrowserContext* context) {
|
||||
gin::WeakCell<Session>* Session::FromBrowserContext(
|
||||
content::BrowserContext* context) {
|
||||
auto* data =
|
||||
static_cast<UserDataLink*>(context->GetUserData(kElectronApiSessionKey));
|
||||
return data ? data->session.get() : nullptr;
|
||||
if (data && data->session)
|
||||
return data->session.Get();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// static
|
||||
gin_helper::Handle<Session> Session::CreateFrom(
|
||||
v8::Isolate* isolate,
|
||||
ElectronBrowserContext* browser_context) {
|
||||
Session* existing = FromBrowserContext(browser_context);
|
||||
if (existing)
|
||||
return gin_helper::CreateHandle(isolate, existing);
|
||||
|
||||
auto handle =
|
||||
gin_helper::CreateHandle(isolate, new Session(isolate, browser_context));
|
||||
|
||||
// The Sessions should never be garbage collected, since the common pattern is
|
||||
// to use partition strings, instead of using the Session object directly.
|
||||
handle->Pin(isolate);
|
||||
|
||||
v8::TryCatch try_catch(isolate);
|
||||
gin_helper::CallMethod(isolate, handle.get(), "_init");
|
||||
if (try_catch.HasCaught()) {
|
||||
node::errors::TriggerUncaughtException(isolate, try_catch);
|
||||
Session* Session::CreateFrom(v8::Isolate* isolate,
|
||||
ElectronBrowserContext* browser_context) {
|
||||
gin::WeakCell<Session>* existing = FromBrowserContext(browser_context);
|
||||
if (existing && existing->Get()) {
|
||||
return existing->Get();
|
||||
}
|
||||
|
||||
App::Get()->EmitWithoutEvent("session-created", handle);
|
||||
auto* session = cppgc::MakeGarbageCollected<Session>(
|
||||
isolate->GetCppHeap()->GetAllocationHandle(), isolate, browser_context);
|
||||
|
||||
return handle;
|
||||
v8::TryCatch try_catch(isolate);
|
||||
gin_helper::CallMethod(isolate, session, "_init");
|
||||
if (try_catch.HasCaught()) {
|
||||
node::errors::TriggerUncaughtException(isolate, try_catch);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
{
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Local<v8::Object> wrapper;
|
||||
if (!session->GetWrapper(isolate).ToLocal(&wrapper)) {
|
||||
return nullptr;
|
||||
}
|
||||
App::Get()->EmitWithoutEvent("session-created", wrapper);
|
||||
}
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
// static
|
||||
gin_helper::Handle<Session> Session::FromPartition(v8::Isolate* isolate,
|
||||
const std::string& partition,
|
||||
base::Value::Dict options) {
|
||||
Session* Session::FromPartition(v8::Isolate* isolate,
|
||||
const std::string& partition,
|
||||
base::Value::Dict options) {
|
||||
ElectronBrowserContext* browser_context;
|
||||
if (partition.empty()) {
|
||||
browser_context =
|
||||
|
@ -1708,34 +1729,30 @@ gin_helper::Handle<Session> Session::FromPartition(v8::Isolate* isolate,
|
|||
}
|
||||
|
||||
// static
|
||||
std::optional<gin_helper::Handle<Session>> Session::FromPath(
|
||||
v8::Isolate* isolate,
|
||||
const base::FilePath& path,
|
||||
base::Value::Dict options) {
|
||||
Session* Session::FromPath(gin::Arguments* args,
|
||||
const base::FilePath& path,
|
||||
base::Value::Dict options) {
|
||||
ElectronBrowserContext* browser_context;
|
||||
|
||||
if (path.empty()) {
|
||||
gin_helper::Promise<v8::Local<v8::Value>> promise(isolate);
|
||||
promise.RejectWithErrorMessage("An empty path was specified");
|
||||
return std::nullopt;
|
||||
args->ThrowTypeError("An empty path was specified");
|
||||
return nullptr;
|
||||
}
|
||||
if (!path.IsAbsolute()) {
|
||||
gin_helper::Promise<v8::Local<v8::Value>> promise(isolate);
|
||||
promise.RejectWithErrorMessage("An absolute path was not provided");
|
||||
return std::nullopt;
|
||||
args->ThrowTypeError("An absolute path was not provided");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
browser_context =
|
||||
ElectronBrowserContext::FromPath(std::move(path), std::move(options));
|
||||
|
||||
return CreateFrom(isolate, browser_context);
|
||||
return CreateFrom(args->isolate(), browser_context);
|
||||
}
|
||||
|
||||
// static
|
||||
gin_helper::Handle<Session> Session::New() {
|
||||
void Session::New() {
|
||||
gin_helper::ErrorThrower(JavascriptEnvironment::GetIsolate())
|
||||
.ThrowError("Session objects cannot be created with 'new'");
|
||||
return {};
|
||||
}
|
||||
|
||||
void Session::FillObjectTemplate(v8::Isolate* isolate,
|
||||
|
@ -1821,12 +1838,31 @@ void Session::FillObjectTemplate(v8::Isolate* isolate,
|
|||
.Build();
|
||||
}
|
||||
|
||||
const char* Session::GetTypeName() {
|
||||
return GetClassName();
|
||||
void Session::Trace(cppgc::Visitor* visitor) const {
|
||||
gin::Wrappable<Session>::Trace(visitor);
|
||||
visitor->Trace(cookies_);
|
||||
visitor->Trace(extensions_);
|
||||
visitor->Trace(protocol_);
|
||||
visitor->Trace(net_log_);
|
||||
visitor->Trace(service_worker_context_);
|
||||
visitor->Trace(web_request_);
|
||||
visitor->Trace(weak_factory_);
|
||||
}
|
||||
|
||||
void Session::WillBeDestroyed() {
|
||||
ClearWeak();
|
||||
const gin::WrapperInfo* Session::wrapper_info() const {
|
||||
return &kWrapperInfo;
|
||||
}
|
||||
|
||||
const char* Session::GetHumanReadableName() const {
|
||||
return "Electron / Session";
|
||||
}
|
||||
|
||||
void Session::OnBeforeMicrotasksRunnerDispose(v8::Isolate* isolate) {
|
||||
gin::PerIsolateData* data = gin::PerIsolateData::From(isolate);
|
||||
data->RemoveDisposeObserver(this);
|
||||
Dispose();
|
||||
weak_factory_.Invalidate();
|
||||
keep_alive_.Clear();
|
||||
}
|
||||
|
||||
} // namespace electron::api
|
||||
|
@ -1843,8 +1879,19 @@ v8::Local<v8::Value> FromPartition(const std::string& partition,
|
|||
}
|
||||
base::Value::Dict options;
|
||||
args->GetNext(&options);
|
||||
return Session::FromPartition(args->isolate(), partition, std::move(options))
|
||||
.ToV8();
|
||||
Session* session =
|
||||
Session::FromPartition(args->isolate(), partition, std::move(options));
|
||||
|
||||
if (session) {
|
||||
v8::HandleScope handle_scope(args->isolate());
|
||||
v8::Local<v8::Object> wrapper;
|
||||
if (!session->GetWrapper(args->isolate()).ToLocal(&wrapper)) {
|
||||
return v8::Null(args->isolate());
|
||||
}
|
||||
return wrapper;
|
||||
} else {
|
||||
return v8::Null(args->isolate());
|
||||
}
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> FromPath(const base::FilePath& path,
|
||||
|
@ -1855,13 +1902,18 @@ v8::Local<v8::Value> FromPath(const base::FilePath& path,
|
|||
}
|
||||
base::Value::Dict options;
|
||||
args->GetNext(&options);
|
||||
std::optional<gin_helper::Handle<Session>> session_handle =
|
||||
Session::FromPath(args->isolate(), path, std::move(options));
|
||||
Session* session = Session::FromPath(args, path, std::move(options));
|
||||
|
||||
if (session_handle)
|
||||
return session_handle.value().ToV8();
|
||||
else
|
||||
if (session) {
|
||||
v8::HandleScope handle_scope(args->isolate());
|
||||
v8::Local<v8::Object> wrapper;
|
||||
if (!session->GetWrapper(args->isolate()).ToLocal(&wrapper)) {
|
||||
return v8::Null(args->isolate());
|
||||
}
|
||||
return wrapper;
|
||||
} else {
|
||||
return v8::Null(args->isolate());
|
||||
}
|
||||
}
|
||||
|
||||
void Initialize(v8::Local<v8::Object> exports,
|
||||
|
@ -1870,7 +1922,8 @@ void Initialize(v8::Local<v8::Object> exports,
|
|||
void* priv) {
|
||||
v8::Isolate* const isolate = electron::JavascriptEnvironment::GetIsolate();
|
||||
gin_helper::Dictionary dict(isolate, exports);
|
||||
dict.Set("Session", Session::GetConstructor(isolate, context));
|
||||
dict.Set("Session",
|
||||
Session::GetConstructor(isolate, context, &Session::kWrapperInfo));
|
||||
dict.SetMethod("fromPartition", &FromPartition);
|
||||
dict.SetMethod("fromPath", &FromPath);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue