Commit a4168673 authored by Bartek Nowierski's avatar Bartek Nowierski Committed by Commit Bot

Start calling v8 API SetDetachedWindowReason

This enables v8-side tracking of JS function calls made within a context
of a detached window.

Such calls should be rare, but if our predictions are incorrect, the
tracking code may impact performance of function calls. Therefore,
this is implemented behind finch experiments SetDetachedWindowReasonBy*
(enabled by default, but it'll give as an opportunity to disable
tracking or limit % of participating users, if needed).

Bug: 1018156
Change-Id: I878e6f1fabdeb229531af688fea0a5bc7412a145
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1895017
Commit-Queue: Bartek Nowierski <bartekn@chromium.org>
Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Reviewed-by: default avatarYuki Shiino <yukishiino@chromium.org>
Reviewed-by: default avatarKeishi Hattori <keishi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#712517}
parent 5fd0e6ed
......@@ -410,5 +410,15 @@ const base::Feature kCompositeCrossOriginIframes{
const base::Feature kSetLowPriorityForBeacon{"SetLowPriorityForBeacon",
base::FEATURE_DISABLED_BY_DEFAULT};
// When enabled, JS function calls in a detached window will be reported.
// Reporting has a non-zero probability of a performance impact, hence an easy
// way to disable it may come in handy.
const base::Feature kSetDetachedWindowReasonByNavigation{
"SetDetachedWindowReasonByNavigation", base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kSetDetachedWindowReasonByClosing{
"SetDetachedWindowReasonByClosing", base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kSetDetachedWindowReasonByOtherReason{
"SetDetachedWindowReasonByOtherReason", base::FEATURE_ENABLED_BY_DEFAULT};
} // namespace features
} // namespace blink
......@@ -134,6 +134,13 @@ BLINK_COMMON_EXPORT extern const base::Feature kSubresourceRedirect;
BLINK_COMMON_EXPORT extern const base::Feature kSetLowPriorityForBeacon;
BLINK_COMMON_EXPORT extern const base::Feature
kSetDetachedWindowReasonByNavigation;
BLINK_COMMON_EXPORT extern const base::Feature
kSetDetachedWindowReasonByClosing;
BLINK_COMMON_EXPORT extern const base::Feature
kSetDetachedWindowReasonByOtherReason;
} // namespace features
} // namespace blink
......
......@@ -30,6 +30,7 @@
#include "third_party/blink/renderer/bindings/core/v8/local_window_proxy.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/renderer/bindings/core/v8/isolated_world_csp.h"
#include "third_party/blink/renderer/bindings/core/v8/script_controller.h"
#include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h"
......@@ -78,8 +79,29 @@ void LocalWindowProxy::Trace(blink::Visitor* visitor) {
WindowProxy::Trace(visitor);
}
void LocalWindowProxy::DisposeContext(Lifecycle next_status,
FrameReuseStatus frame_reuse_status) {
bool LocalWindowProxy::IsSetDetachedWindowReasonEnabled(
v8::Context::DetachedWindowReason reason) {
switch (reason) {
case v8::Context::DetachedWindowReason::kWindowNotDetached:
// This shouldn't happen, but if it does, it's always safe to clear the
// reason.
return true;
case v8::Context::DetachedWindowReason::kDetachedWindowByNavigation:
return base::FeatureList::IsEnabled(
features::kSetDetachedWindowReasonByNavigation);
case v8::Context::DetachedWindowReason::kDetachedWindowByClosing:
return base::FeatureList::IsEnabled(
features::kSetDetachedWindowReasonByClosing);
case v8::Context::DetachedWindowReason::kDetachedWindowByOtherReason:
return base::FeatureList::IsEnabled(
features::kSetDetachedWindowReasonByOtherReason);
}
}
void LocalWindowProxy::DisposeContext(
Lifecycle next_status,
FrameReuseStatus frame_reuse_status,
v8::Context::DetachedWindowReason reason) {
DCHECK(next_status == Lifecycle::kV8MemoryIsForciblyPurged ||
next_status == Lifecycle::kGlobalObjectIsDetached ||
next_status == Lifecycle::kFrameIsDetached ||
......@@ -126,6 +148,10 @@ void LocalWindowProxy::DisposeContext(Lifecycle next_status,
#endif
}
if (IsSetDetachedWindowReasonEnabled(reason)) {
context->SetDetachedWindowReason(reason);
}
script_state_->DisposePerContextData();
// It's likely that disposing the context has created a lot of
// garbage. Notify V8 about this so it'll have a chance of cleaning
......
......@@ -69,7 +69,11 @@ class LocalWindowProxy final : public WindowProxy {
private:
bool IsLocal() const override { return true; }
void Initialize() override;
void DisposeContext(Lifecycle next_status, FrameReuseStatus) override;
void DisposeContext(Lifecycle next_status,
FrameReuseStatus,
v8::Context::DetachedWindowReason) override;
static bool IsSetDetachedWindowReasonEnabled(
v8::Context::DetachedWindowReason reason);
// Creates a new v8::Context with the window wrapper object as the global
// object (aka the inner global). Note that the window wrapper and its
......
......@@ -49,7 +49,8 @@ RemoteWindowProxy::RemoteWindowProxy(v8::Isolate* isolate,
: WindowProxy(isolate, frame, std::move(world)) {}
void RemoteWindowProxy::DisposeContext(Lifecycle next_status,
FrameReuseStatus) {
FrameReuseStatus,
v8::Context::DetachedWindowReason) {
DCHECK(next_status == Lifecycle::kV8MemoryIsForciblyPurged ||
next_status == Lifecycle::kGlobalObjectIsDetached ||
next_status == Lifecycle::kFrameIsDetached ||
......
......@@ -49,7 +49,9 @@ class RemoteWindowProxy final : public WindowProxy {
private:
void Initialize() override;
void DisposeContext(Lifecycle next_status, FrameReuseStatus) override;
void DisposeContext(Lifecycle next_status,
FrameReuseStatus,
v8::Context::DetachedWindowReason) override;
// Creates a new v8::Context with the window wrapper object as the global
// object (aka the inner global). Note that the window wrapper and its
......
......@@ -65,19 +65,24 @@ void WindowProxy::ClearForClose() {
DisposeContext(lifecycle_ == Lifecycle::kV8MemoryIsForciblyPurged
? Lifecycle::kFrameIsDetachedAndV8MemoryIsPurged
: Lifecycle::kFrameIsDetached,
kFrameWillNotBeReused);
kFrameWillNotBeReused,
v8::Context::DetachedWindowReason::kDetachedWindowByClosing);
}
void WindowProxy::ClearForNavigation() {
DisposeContext(Lifecycle::kGlobalObjectIsDetached, kFrameWillBeReused);
DisposeContext(Lifecycle::kGlobalObjectIsDetached, kFrameWillBeReused,
v8::Context::kDetachedWindowByNavigation);
}
void WindowProxy::ClearForSwap() {
DisposeContext(Lifecycle::kGlobalObjectIsDetached, kFrameWillNotBeReused);
// This happens on a navigation between local/remote source.
DisposeContext(Lifecycle::kGlobalObjectIsDetached, kFrameWillNotBeReused,
v8::Context::kDetachedWindowByNavigation);
}
void WindowProxy::ClearForV8MemoryPurge() {
DisposeContext(Lifecycle::kV8MemoryIsForciblyPurged, kFrameWillNotBeReused);
DisposeContext(Lifecycle::kV8MemoryIsForciblyPurged, kFrameWillNotBeReused,
v8::Context::kDetachedWindowByOtherReason);
}
v8::Local<v8::Object> WindowProxy::GlobalProxyIfNotDetached() {
......
......@@ -256,7 +256,9 @@ class WindowProxy : public GarbageCollected<WindowProxy> {
virtual void Initialize() = 0;
virtual void DisposeContext(Lifecycle next_status, FrameReuseStatus) = 0;
virtual void DisposeContext(Lifecycle next_status,
FrameReuseStatus,
v8::Context::DetachedWindowReason) = 0;
WARN_UNUSED_RESULT v8::Local<v8::Object> AssociateWithWrapper(
DOMWindow*,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment