Skip to content

script: Use unrooted iterators for HTMLCollections - #45582

Merged
jdm merged 1 commit into
servo:mainfrom
Narfinger:faster-iterators
Jun 16, 2026
Merged

script: Use unrooted iterators for HTMLCollections#45582
jdm merged 1 commit into
servo:mainfrom
Narfinger:faster-iterators

Conversation

@Narfinger

@Narfinger Narfinger commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

This implements two new UnrootedIterators (PreceedingNodeIterator and FollowingNodeIterator) with the same schema as the other UnrootedIterators.
This also implements using these iterators for HTMLCollections (and their subtypes) and CollectionSource trait as well as a couple of downstream.

Special care should be given to check:

  • The correctness of the new iterators from the point of iterating.
  • The enum CollectioonKind not having the 'static lifetime anymore.
  • HTMLFormControlsCollection::NamedItem (which had to be rewritten to make the lifetimes work).
  • Bugfix in codegen.py to also check the cx._no_gcMethods for Length(cx).
  • Implementation of PartialEq for UnrootedDom and UnrootedDom==T

Most other changes are mechanical &JSContext adding or NoGC propagating.

Overall this seems to eliminate rooting overhead on amazon.com down from 1.8% runtime in a small unscientific test.

Testing: WPT tests should find any screwups.

@Narfinger Narfinger added the T-linux-wpt Do a try run of the WPT label Jun 11, 2026
@github-actions github-actions Bot removed the T-linux-wpt Do a try run of the WPT label Jun 11, 2026
@github-actions

Copy link
Copy Markdown

🔨 Triggering try run (#27345803471) for Linux (WPT)

@github-actions

Copy link
Copy Markdown

Test results for linux-wpt from try job (#27345803471):

Flaky unexpected result (54)
  • OK /IndexedDB/idbtransaction-oncomplete.any.worker.html (#42804)
    • FAIL [expected PASS] subtest: IDBTransaction - complete event

      assert_array_equals: lengths differ, expected array ["upgradeneeded", "complete", "success", "opencursor"] length 4, got ["upgradeneeded", "complete", "success"] length 3
      

  • CRASH [expected OK] /_mozilla/mozilla/focus-scroll-when-visible.html
  • CRASH [expected OK] /_webgl/conformance/glsl/implicit/divide_int_mat2.vert.html
  • TIMEOUT [expected CRASH] /content-security-policy/inheritance/blob-url-in-main-window-self-navigate-inherits.sub.html (#41490)
  • TIMEOUT [expected OK] /content-security-policy/inheritance/document-write-iframe.html (#41195)
    • TIMEOUT [expected PASS] subtest: document.open() keeps inherited CSPs on transient about:blank.

      Test timed out
      

  • OK [expected CRASH] /content-security-policy/meta/sandbox-iframe.html (#43478)
    • FAIL [expected PASS] subtest: img-src 'self' works when specified in a meta tag.

      assert_equals: expected "PASS" but got "FAIL"
      

  • FAIL [expected PASS] /css/css-backgrounds/background-size-042.html
  • OK [expected ERROR] /fetch/fetch-later/quota/same-origin-iframe/sandboxed-iframe.https.window.html (#41704)
  • TIMEOUT /fetch/metadata/generated/css-images.sub.tentative.html (#29047)
    • FAIL [expected PASS] subtest: content sec-fetch-site - HTTPS downgrade-upgrade

      assert_unreached: Reached unreachable code
      

  • OK /html/browsers/browsing-the-web/navigating-across-documents/navigation-unload-cross-origin.sub.window.html (#29056)
    • PASS [expected FAIL] subtest: Cross-origin navigation started from unload handler must be ignored
  • OK /html/browsers/history/the-history-interface/traverse_the_history_4.html (#21383)
    • PASS [expected FAIL] subtest: Multiple history traversals, last would be aborted
  • OK /html/browsers/history/the-history-interface/traverse_the_history_5.html (#21383)
    • PASS [expected FAIL] subtest: Multiple history traversals, last would be aborted
  • OK /html/browsers/origin/cross-origin-objects/cross-origin-objects.html
    • FAIL [expected PASS] subtest: Only certain properties are usable as cross-origin this objects (cross-origin)

      assert_throws_dom: Should throw when calling window.__wptrunner_testdriver_callback with cross-origin this object function "function() {
          [native code]
      }" did not throw
      

    • FAIL [expected PASS] subtest: Only certain properties are usable as cross-origin this objects (same-origin + document.domain)

      assert_throws_dom: Should throw when calling window.__wptrunner_testdriver_callback with cross-origin this object function "function() {
          [native code]
      }" did not throw
      

  • OK /html/browsers/windows/embedded-opener-remove-frame.html (#23867)
    • FAIL [expected PASS] subtest: opener of discarded auxiliary browsing context

      assert_object_equals: property "get" expected function "function opener() {
          [native code]
      }" got function "function opener() {
          [native code]
      }"
      

  • OK [expected TIMEOUT] /html/infrastructure/urls/base-url/document-base-url-window-initiator-is-not-opener.https.window.html (#30970)
  • TIMEOUT [expected OK] /html/interaction/focus/the-autofocus-attribute/autofocus-dialog.html (#29087)
    • TIMEOUT [expected FAIL] subtest: <dialog>-contained autofocus element gets focused when the dialog is shown

      Test timed out
      

  • OK [expected TIMEOUT] /html/semantics/embedded-content/media-elements/src_object_blob.html (#40340)
    • PASS [expected TIMEOUT] subtest: HTMLMediaElement.srcObject blob
  • CRASH [expected FAIL] /html/semantics/interestfor/interestfor-plain-inline-element.tentative.html
  • OK /html/semantics/scripting-1/the-script-element/module/dynamic-import/blob-url.any.html (#33948)
    • FAIL [expected PASS] subtest: Revoking a blob URL immediately after calling import will not fail

      promise_test: Unhandled rejection with value: object "TypeError: Module fetching failed"
      

  • OK /html/semantics/scripting-1/the-script-element/module/dynamic-import/blob-url.any.worker.html (#33909)
    • FAIL [expected PASS] subtest: Revoking a blob URL immediately after calling import will not fail

      promise_test: Unhandled rejection with value: object "TypeError: Module fetching failed"
      

  • OK /html/webappapis/user-prompts/print-during-unload.html (#35944)
    • FAIL [expected PASS] subtest: print() during unload

      assert_array_equals: expected property 1 to be "destination" but got "error: window.print is not a function" (expected array ["start", "destination"] got ["start", "error: window.print is not a function"])
      

  • CRASH [expected OK] /import-maps/csp/unsafe-inline.html
  • TIMEOUT [expected OK] /pointerevents/compat/pointerevent_touch-action_two-finger_interaction.html (#44693)
    • NOTRUN [expected PASS] subtest: touch two-finger pan on 'touch-action: pan-x pan-y'
    • NOTRUN [expected FAIL] subtest: touch two-finger pan on 'touch-action: pinch-zoom'
  • OK [expected TIMEOUT] /trusted-types/trusted-types-navigation.html?06-10 (#37920)
    • PASS [expected FAIL] subtest: Navigate a frame via anchor with javascript:-urls in report-only mode.
    • PASS [expected TIMEOUT] subtest: Navigate a frame via anchor with javascript:-urls w/ default policy in report-only mode.
    • FAIL [expected NOTRUN] subtest: Navigate a window via anchor with javascript:-urls w/ a default policy throwing an exception in enforcing mode.

      promise_test: Unhandled rejection with value: "Unexpected message received: \"No securitypolicyviolation reported!\""
      

    • FAIL [expected NOTRUN] subtest: Navigate a window via anchor with javascript:-urls w/ a default policy throwing an exception in report-only mode.

      promise_test: Unhandled rejection with value: "Unexpected message received: \"No securitypolicyviolation reported!\""
      

  • OK /webdriver/tests/classic/element_send_keys/interactability.py
    • FAIL [expected PASS] subtest: test_iframe_is_interactable

      AssertionError: assert 'oo' == 'foo'
      

  • CRASH [expected OK] /webxr/hit-test/ar_hittest_source_cancel.https.html
  • CRASH [expected ERROR] /workers/Worker-base64.any.serviceworker.html
  • CRASH [expected OK] /workers/Worker-multi-port.html
  • CRASH [expected ERROR] /workers/Worker-replace-self.any.sharedworker.html
  • CRASH [expected OK] /workers/Worker-terminate-forever-during-evaluation.html
  • CRASH [expected OK] /workers/Worker-timeout-increasing-order.html
  • CRASH [expected OK] /workers/WorkerNavigator_userAgentData.http.html
  • CRASH [expected OK] /workers/Worker_script_mimetype.htm
  • CRASH [expected OK] /workers/constructors/SharedWorker/global-members.html
  • CRASH [expected OK] /workers/constructors/SharedWorker/null-arguments.html
  • CRASH [expected OK] /workers/constructors/SharedWorker/number-arguments.html
  • CRASH [expected OK] /workers/constructors/SharedWorker/port-properties.html
  • CRASH [expected OK] /workers/constructors/SharedWorker/setting-port-members.html
  • CRASH [expected OK] /workers/constructors/SharedWorker/unresolvable-url.html
  • CRASH [expected OK] /workers/dedicated-worker-parse-error-failure.html
  • CRASH [expected OK] /workers/examples/general.worker.html
  • CRASH [expected ERROR] /workers/examples/onconnect.any.sharedworker.html
  • CRASH [expected OK] /workers/interfaces/DedicatedWorkerGlobalScope/postMessage/event-ports-dedicated.html
  • CRASH [expected OK] /workers/interfaces/WorkerGlobalScope/onerror/not-handled.html
  • CRASH [expected OK] /workers/interfaces/WorkerUtils/importScripts/002.worker.html
  • CRASH [expected OK] /workers/interfaces/WorkerUtils/importScripts/003.html
  • CRASH [expected OK] /workers/interfaces/WorkerUtils/importScripts/004.html
  • CRASH [expected ERROR] /workers/interfaces/WorkerUtils/importScripts/report-error-cross-origin.sub.any.sharedworker.html
  • CRASH [expected OK] /workers/interfaces/WorkerUtils/importScripts/report-error-setTimeout-same-origin.sub.any.worker.html
  • CRASH [expected OK] /workers/modules/dedicated-worker-import.any.html
  • CRASH [expected OK] /workers/semantics/encodings/004.worker.html
  • CRASH [expected OK] /workers/semantics/multiple-workers/003.html
  • CRASH [expected OK] /workers/shared-worker-from-blob-url.window.html
  • CRASH [expected OK] /xhr/abort-during-upload.any.html
Stable unexpected results that are known to be intermittent (13)
  • PASS [expected FAIL] /css/css-fonts/font-feature-settings-descriptor-01.html (#45418)
  • OK /html/browsers/browsing-the-web/navigating-across-documents/navigation-unload-same-origin-fragment.html (#20768)
    • FAIL [expected PASS] subtest: Tests that a fragment navigation in the unload handler will not block the initial navigation

      assert_equals: expected "" but got "#fragment"
      

  • OK /html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/a-click.html (#28697)
    • PASS [expected FAIL] subtest: aElement.click() before the load event must NOT replace
  • OK [expected TIMEOUT] /html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/form-requestsubmit.html (#44098)
    • FAIL [expected TIMEOUT] subtest: Replace before load, triggered by formElement.requestSubmit()

      assert_equals: expected "http://web-platform.test:8000/common/blank.html?thereplacement=" but got "http://web-platform.test:8000/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/resources/code-injector.html?pipe=sub(none)&code=%0A%20%20%20%20const%20form%20%3D%20document.createElement(%22form%22)%3B%0A%20%20%20%20form.action%20%3D%20%22%2Fcommon%2Fblank.html%22%3B%0A%0A%20%20%20%20const%20input%20%3D%20document.createElement(%22input%22)%3B%0A%20%20%20%20input.type%20%3D%20%22hidden%22%3B%0A%20%20%20%20input.name%20%3D%20%22thereplacement%22%3B%0A%20%20%20%20form.append(input)%3B%0A%0A%20%20%20%20document.currentScript.before(form)%3B%0A%20%20%20%20form.requestSubmit()%3B%0A%20%20"
      

  • TIMEOUT [expected OK] /html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/form-submit.html (#44028)
  • OK /html/semantics/scripting-1/the-script-element/module/choice-of-error-1.html (#44058)
    • FAIL [expected PASS] subtest: Parse errors in different files should be reported depending on different roots

      assert_not_equals: two different parse errors should be reported got disallowed value object "SyntaxError: expected expression, got '%'"
      

  • OK /html/semantics/scripting-1/the-script-element/module/dynamic-import/blob-url.any.worker-module.html (#43510)
    • FAIL [expected PASS] subtest: Revoking a blob URL immediately after calling import will not fail

      promise_test: Unhandled rejection with value: object "TypeError: Module fetching failed"
      

  • TIMEOUT [expected OK] /html/user-activation/navigation-state-reset-sameorigin.html (#45151)
    • TIMEOUT [expected PASS] subtest: Post-navigation state reset.

      Test timed out
      

  • OK /navigation-timing/test-navigation-type-reload.html (#33334)
    • PASS [expected FAIL] subtest: Reload domComplete > Original domComplete
    • PASS [expected FAIL] subtest: Reload domContentLoadedEventEnd > Original domContentLoadedEventEnd
    • PASS [expected FAIL] subtest: Reload domContentLoadedEventStart > Original domContentLoadedEventStart
    • PASS [expected FAIL] subtest: Reload fetchStart > Original fetchStart
    • PASS [expected FAIL] subtest: Reload loadEventEnd > Original loadEventEnd
    • PASS [expected FAIL] subtest: Reload loadEventStart > Original loadEventStart
  • CRASH [expected OK] /resource-timing/render-blocking-status-link.html (#41664)
  • TIMEOUT [expected OK] /trusted-types/trusted-types-navigation.html?16-20 (#44835)
    • TIMEOUT [expected PASS] subtest: Navigate a frame via area with javascript:-urls w/ default policy in enforcing mode.

      Test timed out
      

    • NOTRUN [expected PASS] subtest: Navigate a frame via area with javascript:-urls in report-only mode.
    • NOTRUN [expected PASS] subtest: Navigate a frame via area with javascript:-urls w/ default policy in report-only mode.
  • OK [expected TIMEOUT] /trusted-types/trusted-types-navigation.html?31-35 (#38034)
    • PASS [expected TIMEOUT] subtest: Navigate a frame via form-submission with javascript:-urls w/ default policy in report-only mode.
    • FAIL [expected NOTRUN] subtest: Navigate a window via form-submission with javascript:-urls w/ a default policy throwing an exception in enforcing mode.

      promise_test: Unhandled rejection with value: "Unexpected message received: \"No securitypolicyviolation reported!\""
      

    • FAIL [expected NOTRUN] subtest: Navigate a window via form-submission with javascript:-urls w/ a default policy throwing an exception in report-only mode.

      promise_test: Unhandled rejection with value: "Unexpected message received: \"No securitypolicyviolation reported!\""
      

    • FAIL [expected NOTRUN] subtest: Navigate a window via form-submission with javascript:-urls w/ a default policy making the URL invalid in enforcing mode.

      promise_test: Unhandled rejection with value: "Unexpected message received: \"No securitypolicyviolation reported!\""
      

  • OK /webdriver/tests/classic/accept_alert/accept.py (#43194)
    • FAIL [expected PASS] subtest: test_accept_in_popup_window

      AssertionError: no such alert (404): No user prompt is currently active.
      

@github-actions

Copy link
Copy Markdown

✨ Try run (#27345803471) succeeded.

@Narfinger
Narfinger marked this pull request as ready for review June 11, 2026 14:25
@servo-highfive servo-highfive added the S-awaiting-review There is new code that needs to be reviewed. label Jun 11, 2026
Signed-off-by: Narfinger <Narfinger@users.noreply.github.com>

@jdm jdm left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great! The fact that this is statically checked gives me a lot more confidence in reviewing changes like this one.

@servo-highfive servo-highfive removed the S-awaiting-review There is new code that needs to be reviewed. label Jun 16, 2026
@jdm
jdm added this pull request to the merge queue Jun 16, 2026
@servo-highfive servo-highfive added the S-awaiting-merge The PR is in the process of compiling and running tests on the automated CI. label Jun 16, 2026
Merged via the queue into servo:main with commit 728e768 Jun 16, 2026
31 checks passed
@servo-highfive servo-highfive removed the S-awaiting-merge The PR is in the process of compiling and running tests on the automated CI. label Jun 16, 2026
@Narfinger
Narfinger deleted the faster-iterators branch June 17, 2026 13:25
TG199 pushed a commit to TG199/servo that referenced this pull request Jun 21, 2026
This implements two new UnrootedIterators (PreceedingNodeIterator and
FollowingNodeIterator) with the same schema as the other
UnrootedIterators.
This also implements using these iterators for HTMLCollections (and
their subtypes) and CollectionSource trait as well as a couple of
downstream.

Special care should be given to check:
- The correctness of the new iterators from the point of iterating.
- The enum CollectioonKind not having the 'static lifetime anymore.
- HTMLFormControlsCollection::NamedItem (which had to be rewritten to
make the lifetimes work).
- Bugfix in codegen.py to also check the cx._no_gcMethods for
Length(cx).
- Implementation of PartialEq for UnrootedDom and UnrootedDom<T>==T

Most other changes are mechanical &JSContext adding or NoGC propagating.

Overall this seems to eliminate rooting overhead on amazon.com down from
1.8% runtime in a small unscientific test.

Testing: WPT tests should find any screwups.

Signed-off-by: Narfinger <Narfinger@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants