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.
|
/// An object in the render tree.
|
||||||
///
|
///
|
||||||
/// The [RenderObject] class hierarchy is the core of the rendering
|
/// The [RenderObject] class hierarchy is the core of the rendering
|
||||||
@ -804,6 +807,7 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
|
|||||||
|
|
||||||
RenderObject() {
|
RenderObject() {
|
||||||
_needsCompositing = isRepaintBoundary || alwaysNeedsCompositing;
|
_needsCompositing = isRepaintBoundary || alwaysNeedsCompositing;
|
||||||
|
_performLayout = performLayout;
|
||||||
}
|
}
|
||||||
|
|
||||||
// LAYOUT
|
// LAYOUT
|
||||||
@ -1073,7 +1077,7 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
performLayout();
|
_performLayout();
|
||||||
markNeedsSemanticsUpdate();
|
markNeedsSemanticsUpdate();
|
||||||
} catch (e, stack) {
|
} catch (e, stack) {
|
||||||
_debugReportException('performLayout', e, stack);
|
_debugReportException('performLayout', e, stack);
|
||||||
@ -1168,7 +1172,7 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
performLayout();
|
_performLayout();
|
||||||
markNeedsSemanticsUpdate();
|
markNeedsSemanticsUpdate();
|
||||||
assert(() { debugAssertDoesMeetConstraints(); return true; });
|
assert(() { debugAssertDoesMeetConstraints(); return true; });
|
||||||
} catch (e, stack) {
|
} catch (e, stack) {
|
||||||
@ -1235,6 +1239,11 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
|
|||||||
/// information without informing this render object.
|
/// information without informing this render object.
|
||||||
void performLayout();
|
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
|
/// Allows this render object to mutate its child list during layout and
|
||||||
/// invokes callback.
|
/// invokes callback.
|
||||||
void invokeLayoutCallback(LayoutCallback callback) {
|
void invokeLayoutCallback(LayoutCallback callback) {
|
||||||
|
@ -1351,12 +1351,18 @@ abstract class BuildableElement extends Element {
|
|||||||
|
|
||||||
typedef Widget WidgetBuilder(BuildContext context);
|
typedef Widget WidgetBuilder(BuildContext context);
|
||||||
|
|
||||||
|
// See _builder.
|
||||||
|
Widget _buildNothing(BuildContext context) => null;
|
||||||
|
|
||||||
/// Base class for the instantiation of [StatelessWidget], [StatefulWidget],
|
/// Base class for the instantiation of [StatelessWidget], [StatefulWidget],
|
||||||
/// and [_ProxyWidget] widgets.
|
/// and [_ProxyWidget] widgets.
|
||||||
abstract class ComponentElement extends BuildableElement {
|
abstract class ComponentElement extends BuildableElement {
|
||||||
ComponentElement(Widget widget) : super(widget);
|
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;
|
Element _child;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -1456,7 +1462,7 @@ class StatefulElement extends ComponentElement {
|
|||||||
assert(_state._debugTypesAreRight(widget));
|
assert(_state._debugTypesAreRight(widget));
|
||||||
assert(_state._element == null);
|
assert(_state._element == null);
|
||||||
_state._element = this;
|
_state._element = this;
|
||||||
assert(_builder == null);
|
assert(_builder == _buildNothing);
|
||||||
_builder = _state.build;
|
_builder = _state.build;
|
||||||
assert(_state._config == null);
|
assert(_state._config == null);
|
||||||
_state._config = widget;
|
_state._config = widget;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user