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{ ...@@ -410,5 +410,15 @@ const base::Feature kCompositeCrossOriginIframes{
const base::Feature kSetLowPriorityForBeacon{"SetLowPriorityForBeacon", const base::Feature kSetLowPriorityForBeacon{"SetLowPriorityForBeacon",
base::FEATURE_DISABLED_BY_DEFAULT}; 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 features
} // namespace blink } // namespace blink
...@@ -134,6 +134,13 @@ BLINK_COMMON_EXPORT extern const base::Feature kSubresourceRedirect; ...@@ -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 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 features
} // namespace blink } // namespace blink
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include "third_party/blink/renderer/bindings/core/v8/local_window_proxy.h" #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/isolated_world_csp.h"
#include "third_party/blink/renderer/bindings/core/v8/script_controller.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" #include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h"
...@@ -78,8 +79,29 @@ void LocalWindowProxy::Trace(blink::Visitor* visitor) { ...@@ -78,8 +79,29 @@ void LocalWindowProxy::Trace(blink::Visitor* visitor) {
WindowProxy::Trace(visitor); WindowProxy::Trace(visitor);
} }
void LocalWindowProxy::DisposeContext(Lifecycle next_status, bool LocalWindowProxy::IsSetDetachedWindowReasonEnabled(
FrameReuseStatus frame_reuse_status) { 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 || DCHECK(next_status == Lifecycle::kV8MemoryIsForciblyPurged ||
next_status == Lifecycle::kGlobalObjectIsDetached || next_status == Lifecycle::kGlobalObjectIsDetached ||
next_status == Lifecycle::kFrameIsDetached || next_status == Lifecycle::kFrameIsDetached ||
...@@ -126,6 +148,10 @@ void LocalWindowProxy::DisposeContext(Lifecycle next_status, ...@@ -126,6 +148,10 @@ void LocalWindowProxy::DisposeContext(Lifecycle next_status,
#endif #endif
} }
if (IsSetDetachedWindowReasonEnabled(reason)) {
context->SetDetachedWindowReason(reason);
}
script_state_->DisposePerContextData(); script_state_->DisposePerContextData();
// It's likely that disposing the context has created a lot of // 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 // garbage. Notify V8 about this so it'll have a chance of cleaning
......
...@@ -69,7 +69,11 @@ class LocalWindowProxy final : public WindowProxy { ...@@ -69,7 +69,11 @@ class LocalWindowProxy final : public WindowProxy {
private: private:
bool IsLocal() const override { return true; } bool IsLocal() const override { return true; }
void Initialize() override; 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 // 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 // object (aka the inner global). Note that the window wrapper and its
......
...@@ -49,7 +49,8 @@ RemoteWindowProxy::RemoteWindowProxy(v8::Isolate* isolate, ...@@ -49,7 +49,8 @@ RemoteWindowProxy::RemoteWindowProxy(v8::Isolate* isolate,
: WindowProxy(isolate, frame, std::move(world)) {} : WindowProxy(isolate, frame, std::move(world)) {}
void RemoteWindowProxy::DisposeContext(Lifecycle next_status, void RemoteWindowProxy::DisposeContext(Lifecycle next_status,
FrameReuseStatus) { FrameReuseStatus,
v8::Context::DetachedWindowReason) {
DCHECK(next_status == Lifecycle::kV8MemoryIsForciblyPurged || DCHECK(next_status == Lifecycle::kV8MemoryIsForciblyPurged ||
next_status == Lifecycle::kGlobalObjectIsDetached || next_status == Lifecycle::kGlobalObjectIsDetached ||
next_status == Lifecycle::kFrameIsDetached || next_status == Lifecycle::kFrameIsDetached ||
......
...@@ -49,7 +49,9 @@ class RemoteWindowProxy final : public WindowProxy { ...@@ -49,7 +49,9 @@ class RemoteWindowProxy final : public WindowProxy {
private: private:
void Initialize() override; 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 // 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 // object (aka the inner global). Note that the window wrapper and its
......
...@@ -65,19 +65,24 @@ void WindowProxy::ClearForClose() { ...@@ -65,19 +65,24 @@ void WindowProxy::ClearForClose() {
DisposeContext(lifecycle_ == Lifecycle::kV8MemoryIsForciblyPurged DisposeContext(lifecycle_ == Lifecycle::kV8MemoryIsForciblyPurged
? Lifecycle::kFrameIsDetachedAndV8MemoryIsPurged ? Lifecycle::kFrameIsDetachedAndV8MemoryIsPurged
: Lifecycle::kFrameIsDetached, : Lifecycle::kFrameIsDetached,
kFrameWillNotBeReused); kFrameWillNotBeReused,
v8::Context::DetachedWindowReason::kDetachedWindowByClosing);
} }
void WindowProxy::ClearForNavigation() { void WindowProxy::ClearForNavigation() {
DisposeContext(Lifecycle::kGlobalObjectIsDetached, kFrameWillBeReused); DisposeContext(Lifecycle::kGlobalObjectIsDetached, kFrameWillBeReused,
v8::Context::kDetachedWindowByNavigation);
} }
void WindowProxy::ClearForSwap() { 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() { void WindowProxy::ClearForV8MemoryPurge() {
DisposeContext(Lifecycle::kV8MemoryIsForciblyPurged, kFrameWillNotBeReused); DisposeContext(Lifecycle::kV8MemoryIsForciblyPurged, kFrameWillNotBeReused,
v8::Context::kDetachedWindowByOtherReason);
} }
v8::Local<v8::Object> WindowProxy::GlobalProxyIfNotDetached() { v8::Local<v8::Object> WindowProxy::GlobalProxyIfNotDetached() {
......
...@@ -256,7 +256,9 @@ class WindowProxy : public GarbageCollected<WindowProxy> { ...@@ -256,7 +256,9 @@ class WindowProxy : public GarbageCollected<WindowProxy> {
virtual void Initialize() = 0; 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( WARN_UNUSED_RESULT v8::Local<v8::Object> AssociateWithWrapper(
DOMWindow*, 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