Commit 622bec43 authored by Adam Barth's avatar Adam Barth

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.
parent 0be7a33b
...@@ -777,6 +777,9 @@ class PipelineOwner { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment