Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Conversation

@cbracken
Copy link
Member

@cbracken cbracken commented Nov 16, 2024

FlutterEngineGroup keeps an array of all live FlutterEngine instances it has created such that after the first engine, it can spawn further engines using the first.

Previously we manually managed this array by adding engines to it upon creation, then having [FlutterEngine dealloc] emit a notification such that FlutterEngineGroup can listen for it, and remove instances from the array upon reception of the notification.

Instead, we now use an NSPointerArray of of weak pointers such that pointers are automatically nilled out by ARC after the last strong reference is collected. This eliminates the need for the manual notification during dealloc.

Unfortunately, NSPointerArray is "clever" and assumes that if the array has not been mutated to store a nil pointer since its last compact call, it must not contain a nil pointer and can thus skip compaction. Under ARC, weak pointers are automatically nilled out when the last strong reference is released, so the above heuristic is no longer valid. We work around the issue by storing a nil pointer before calling compact.

See http://www.openradar.me/15396578 for the radar tracking this bug.

I'm not thrilled with the fact that we're replacing one sort of TODO with another, but the code is much simpler and avoids relying on a trip through the notification center, which seems objectively better.

Issue: flutter/flutter#155943
Issue: flutter/flutter#137801

Pre-launch Checklist

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • I read the Tree Hygiene wiki page, which explains my responsibilities.
  • I read and followed the Flutter Style Guide and the C++, Objective-C, Java style guides.
  • I listed at least one issue that this PR fixes in the description above.
  • I added new tests to check the change I am making or feature I am adding, or the PR is test-exempt. See testing the engine for instructions on writing and running engine tests.
  • I updated/added relevant documentation (doc comments with ///).
  • I signed the CLA.
  • All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel on Discord.

// That's reasonable behaviour on a regular NSPointerArray but not for a weakObjectPointerArray.
// As a workaround, we mutate it first. See: http://www.openradar.me/15396578
[self.engines addPointer:nil];
[self.engines compact];
Copy link
Member Author

@cbracken cbracken Nov 16, 2024

Choose a reason for hiding this comment

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

I won't comment on just how much time I spent staring at and debugging this line to arrive at the comment above. Thanks, noble OpenRadar submitter, for saving my sanity.

Copy link
Member

Choose a reason for hiding this comment

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

😭

XCTAssertNotNil(spawner);
XCTAssertNotNil(weakSpawner);
}
XCTAssertNil(weakSpawner);
Copy link
Member Author

@cbracken cbracken Nov 16, 2024

Choose a reason for hiding this comment

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

I could probably get rid of this additional check, but it's arguably useful for avoiding any future accidents wherein someone updates the implementation to hold a strong reference that retains the engine instead of a weak reference. :/

Copy link
Contributor

@stuartmorgan-g stuartmorgan-g left a comment

Choose a reason for hiding this comment

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

LGTM

FlutterEngineGroup keeps an array of all live FlutterEngine instances it
has created such that after the first engine, it can spawn further
engines using the first.

Previously we manually managed this array by adding engines to it upon
creation, then having [FlutterEngine dealloc] emit a notification such
that FlutterEngineGroup can listen for it, and remove instances from the
array upon dealloc.

Instead, we now use an NSPointerArray of of weak pointers such that
pointers are automatically nilled out by ARC after the last strong
reference is collected. This eliminates the need for the manual
notification during dealloc.

Unfortunately, NSPointerArray is "clever" and assumes that if the array
has not been mutated to store a nil pointer since its last compact call,
it must must contain a nil pointer and can thus skip compaction. When
holding weak pointers under ARC, this is no longer the case and so we
work around the issue by storing a nil pointer before calling compact.

See: http://www.openradar.me/15396578

I'm not thrilled with the fact that we're replacing one sort of TODO
with another, but the code is much simpler and avoids relying on a trip
through the notification center, which seems objectively better.

Issue: flutter/flutter#155943
@cbracken cbracken added the autosubmit Merge PR when tree becomes green via auto submit App label Nov 17, 2024
@auto-submit auto-submit bot merged commit 4f6a261 into flutter:main Nov 17, 2024
31 checks passed
@auto-submit auto-submit bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Nov 17, 2024
@cbracken cbracken deleted the eliminate-bridge-cast branch November 17, 2024 03:50
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Nov 17, 2024
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Nov 17, 2024
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Nov 17, 2024
github-merge-queue bot pushed a commit to flutter/flutter that referenced this pull request Nov 17, 2024
…159047)

flutter/engine@6f9854a...9d0720a

2024-11-17 skia-flutter-autoroll@skia.org Roll Skia from b88c7b03a838 to
1086e39c04cf (1 revision) (flutter/engine#56654)
2024-11-17 chris@bracken.jp iOS: Eliminate FlutterEngine dealloc
notification (flutter/engine#56650)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-engine-flutter-autoroll
Please CC jimgraham@google.com,zra@google.com on the revert to ensure
that a human
is aware of the problem.

To file a bug in Flutter:
https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
nick9822 pushed a commit to nick9822/flutter that referenced this pull request Dec 18, 2024
FlutterEngineGroup keeps an array of all live FlutterEngine instances it has created such that after the first engine, it can spawn further engines using the first.

Previously we manually managed this array by adding engines to it upon creation, then having [FlutterEngine dealloc] emit a notification such that FlutterEngineGroup can listen for it, and remove instances from the array upon reception of the notification.

Instead, we now use an NSPointerArray of of weak pointers such that pointers are automatically nilled out by ARC after the last strong reference is collected. This eliminates the need for the manual notification during dealloc.

Unfortunately, NSPointerArray is "clever" and assumes that if the array has not been mutated to store a nil pointer since its last compact call, it must not contain a nil pointer and can thus skip compaction. Under ARC, weak pointers are automatically nilled out when the last strong reference is released, so the above heuristic is no longer valid. We work around the issue by storing a nil pointer before calling compact.

See http://www.openradar.me/15396578 for the radar tracking this bug.

I'm not thrilled with the fact that we're replacing one sort of TODO with another, but the code is much simpler and avoids relying on a trip through the notification center, which seems objectively better.

Issue: flutter#155943
Issue: flutter#137801

[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants