Skip to content

Make GC for document with Inactive activity state less aggressive #41138

@tharkum

Description

@tharkum

Describe the bug:
If activity state of the document is change to Inactive the user agent is calling garbage collection for the JSContext unconditionally for the associated script thread and for some specific WPT test cases it leads to unexpected results there are some created video objects (which is not attached to DOM document) is immediately gone (GCed).

The tests started failing with TIMEOUT results after the following PR was published #41131 (a media element can be GC-ed).

Example html/semantics/embedded-content/media-elements/autoplay-allowed-by-feature-policy.https.sub.html

Top-level frame window (+ documents)
- `video` 0 (not attached to document)
- `iframe` 0
- - Sub-level window (+document)
- - -  `video` 1 (not attached to document)
- `iframe` 1
- - Sub-level window (+document)
- - -  `video` 2 (not attached to document)

When an iframe is first inserted into the document, an "about:blank" document is created, and synchronously processed by the script thread and on short later on processing the iframe attributes loading new document and replace the previous one.

See the following log with detailed information which show how video 0 from (top-level frame document) is GC-ed on the iframe document loading (about:blank -> https://web-platform.test:8443/feature-policy/resources/feature-policy-autoplay.html)

  • pipeline_id: 1.3 -> 1.4 (top-level window documents)
  • pipeline_id: 5.4 -> 5.5 (iframe 0 window documents)
TEST_START: /html/semantics/embedded-content/media-elements/autoplay-allowed-by-feature-policy.https.sub.html

ScriptThread::spawn_pipeline webview_id = WebViewId(PainterId(1), (0,2)) new_pipeline_id = (1,3) loadURL = "about:blank"
DOM Window::new webview_id = WebViewId(PainterId(1), (0,2)) pipeline_id = (1,3) creation_url = "about:blank"
ScriptThread handle_set_document_activity_msg activity of Pipeline(1,3) to be FullyActive in Some("Script#3").

Script Thread START ScriptEventLoopId(4)
ScriptThread::spawn_pipeline webview_id = WebViewId(PainterId(1), (0,2)) new_pipeline_id = (1,4) loadURL = "https://web-platform.test:8443/html/semantics/embedded-content/media-elements/autoplay-allowed-by-feature-policy.https.sub.html"
DOM Window::new webview_id = WebViewId(PainterId(1), (0,2)) pipeline_id = (1,4) creation_url = "https://web-platform.test:8443/html/semantics/embedded-content/media-elements/autoplay-allowed-by-feature-policy.https.sub.html"
ScriptThread handle_set_document_activity_msg activity of Pipeline(1,3) to be Inactive in Some("Script#3").
Document set_activity (0x7cc01f47d000)  activity = Inactive
Window::Gc webview_id = WebViewId(PainterId(1), (0,2)), pipeline_id = (1,3)
ScriptThread handle_set_document_activity_msg activity of Pipeline(1,4) to be FullyActive in Some("Script#4").

 --- GC --- (Nothing...)

HTMLMediaElement (0x7cc01ecba000) create_media_player gen_id = 1 client_context_id = ClientContextId(1, 4)

HTMLIFrame::start_new_pipeline:  about:blank
ScriptThread::spawn_pipeline webview_id = WebViewId(PainterId(1), (0,2)) new_pipeline_id = (5,4) loadURL = "about:blank"
DOM Window::new webview_id = WebViewId(PainterId(1), (0,2)) pipeline_id = (5,4) creation_url = "about:blank"
HTMLIFrame::start_new_pipeline: "https://web-platform.test:8443/feature-policy/resources/feature-policy-autoplay.html"

ScriptThread::spawn_pipeline webview_id = WebViewId(PainterId(1), (0,2)) new_pipeline_id = (5,5) loadURL = "https://web-platform.test:8443/feature-policy/resources/feature-policy-autoplay.html"
ScriptThread handle_set_document_activity_msg activity of Pipeline(5,4) to be FullyActive in Some("Script#4").
Window::new webview_id = WebViewId(PainterId(1), (0,2)) pipeline_id = (5,5) creation_url = "https://web-platform.test:8443/feature-policy/resources/feature-policy-autoplay.html"

ScriptThread handle_set_document_activity_msg activity of Pipeline(5,4) to be Inactive in Some("Script#4").
Document set_activity (0x7cc01ec87e00)  activity = Inactive
Window::Gc webview_id = WebViewId(PainterId(1), (0,2)), pipeline_id = (5,4)

--- GC--- (`video` 0 from top-level frame window is gone!)

HTMLMediaElement::drop (0x7cc01ecba000) client_context_id = ClientContextId(1, 4)

ScriptThread handle_set_document_activity_msg activity of Pipeline(5,5) to be FullyActive in Some("Script#4").

So the proposal is to add condition then GC should be called

  1. It is top-level frame (document URL is NOT "about:blank")
  2. It is top-level frame (document URL is not restricted)
  3. It is top-level frame or iframe (document URL is NOT "about:blank")
  4. It is top-level frame (document URL is not restricted) or iframe (document URL is NOT "about:blank")

Or as an option is modify the WPT tests to pass them but I assume that it not right choice...

To Reproduce:
Run any test from the list below:

Example ./mach test-wpt tests/wpt/tests/html/semantics/embedded-content/media-elements/autoplay-allowed-by-feature-policy.https.sub.html -r

Platform:
Ubuntu 22.04

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions