Capture closures around megamorphic dispatches
The performLayout and build callsite are highly megamorphic because they dispatch into a large number of clients. However, for a given caller, the callee is always of the same type, which means the megamorphic lookup exactly factors by the caller. We can speed up the dispatch by capturing a closure at initialization and then monomorphically dispatching through the closure.
This commit is contained in:
parent
0be7a33b14
commit
622bec43be
@ -777,6 +777,9 @@ class PipelineOwner {
|
||||
|
||||
}
|
||||
|
||||
// See _performLayout.
|
||||
void _doNothing() { }
|
||||
|
||||
/// An object in the render tree.
|
||||
///
|
||||
/// The [RenderObject] class hierarchy is the core of the rendering
|
||||
@ -804,6 +807,7 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
|
||||
|
||||
RenderObject() {
|
||||
_needsCompositing = isRepaintBoundary || alwaysNeedsCompositing;
|
||||
_performLayout = performLayout;
|
||||
}
|
||||
|
||||
// LAYOUT
|
||||
@ -1073,7 +1077,7 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
|
||||
return true;
|
||||
});
|
||||
try {
|
||||
performLayout();
|
||||
_performLayout();
|
||||
markNeedsSemanticsUpdate();
|
||||
} catch (e, stack) {
|
||||
_debugReportException('performLayout', e, stack);
|
||||
@ -1168,7 +1172,7 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
|
||||
return true;
|
||||
});
|
||||
try {
|
||||
performLayout();
|
||||
_performLayout();
|
||||
markNeedsSemanticsUpdate();
|
||||
assert(() { debugAssertDoesMeetConstraints(); return true; });
|
||||
} catch (e, stack) {
|
||||
@ -1235,6 +1239,11 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
|
||||
/// information without informing this render object.
|
||||
void performLayout();
|
||||
|
||||
// We cache a closure to performLayout so that the callsite is monomorphic.
|
||||
// Initializing this field with _buildNothing helps the compiler prove that
|
||||
// this field always holds a closure.
|
||||
VoidCallback _performLayout = _doNothing;
|
||||
|
||||
/// Allows this render object to mutate its child list during layout and
|
||||
/// invokes callback.
|
||||
void invokeLayoutCallback(LayoutCallback callback) {
|
||||
|
@ -1351,12 +1351,18 @@ abstract class BuildableElement extends Element {
|
||||
|
||||
typedef Widget WidgetBuilder(BuildContext context);
|
||||
|
||||
// See _builder.
|
||||
Widget _buildNothing(BuildContext context) => null;
|
||||
|
||||
/// Base class for the instantiation of [StatelessWidget], [StatefulWidget],
|
||||
/// and [_ProxyWidget] widgets.
|
||||
abstract class ComponentElement extends BuildableElement {
|
||||
ComponentElement(Widget widget) : super(widget);
|
||||
|
||||
WidgetBuilder _builder;
|
||||
// Initializing this field with _buildNothing helps the compiler prove that
|
||||
// this field always holds a closure.
|
||||
WidgetBuilder _builder = _buildNothing;
|
||||
|
||||
Element _child;
|
||||
|
||||
@override
|
||||
@ -1456,7 +1462,7 @@ class StatefulElement extends ComponentElement {
|
||||
assert(_state._debugTypesAreRight(widget));
|
||||
assert(_state._element == null);
|
||||
_state._element = this;
|
||||
assert(_builder == null);
|
||||
assert(_builder == _buildNothing);
|
||||
_builder = _state.build;
|
||||
assert(_state._config == null);
|
||||
_state._config = widget;
|
||||
|
Loading…
x
Reference in New Issue
Block a user