Repository: flutter
Issue: Deeply nested widget trees with simple closure invocations have a high performance penalty
Labels: framework,c: performance,customer: money (g3),perf: speed,P2,team-framework,triaged-framework

Internal: b/292548521

Sample app:

```dart
import 'package:flutter/material.dart';

void main() {
  debugProfileBuildsEnabled = true;
  runApp(
    MaterialApp(
      routes: {
        '/two': (context) {
          return Material(child: Builder(builder: _getNestedBuilders(250)));
        }
      },
      home: Scaffold(
        body: Builder(builder: _getNestedBuilders(300)),
        floatingActionButton: Builder(
          builder: (context) {
            return FloatingActionButton(
              onPressed: () {
                Navigator.of(context).pushNamed('/two');
              },
            );
          },
        ),
      ),
    ),
  );
}

WidgetBuilder _getNestedBuilders(int count) {
  if (count == 0) {
    return (context) {
      return Container(
        width: 100,
        height: 100,
        color: Colors.red,
        child: IconButton(
          icon: const Icon(Icons.arrow_back_sharp),
          onPressed: () {
            Navigator.of(context).pop();
          },
        ),
      );
    };
  }
  return (context) => Builder(builder: _getNestedBuilders(count - 1));
}
```

A recorded timeline of this app on an Android Go device:
[nested_builders.json.txt](https://github.com/flutter/flutter/files/7645882/nested_builders.json.txt)

This more-or-less mimics (and exaggerates) a common pattern in larger apps, where building the whole route can trigger a deeply nested widget heirarchy many of which are just `Builder` (or effectively `Builder`) widgets.

Initial build times on these routes on an Android Go device takes several milliseconds (compared to a fraction of a millisecond with much lower values in the `_getNestedBuilders` calls, or even compared to subsequent builds where they are not all marked as dirty).

I tried the following Dart program thinking it might replicate this issue, but it seems to just inline the calls:

```dart
import 'dart:developer';

class BuildContext {}

class Widget {}

typedef WidgetBuilder = Widget Function(BuildContext);

class Builder extends Widget {
  Builder({required this.builder});

  final WidgetBuilder builder;

  Widget _doBuild(BuildContext context) {
    try {
      return builder(context);
    } catch (e) {
      return Widget();
    }
  }

  Widget build(BuildContext context) {
    // Seems to defeat inlining, although I have not been able to replicate that
    // with simpler try catches.
    // return Timeline.timeSync('builder callback', () => builder(context));

    // Does not defeat inlining.
    // return _doBuild(context);

    // Seems to just inline and is fast.
    return builder(context);
  }
}

void main() {
  Timeline.timeSync('a', () {
    Builder(builder: (_) {
      print('hello, world!');
      return Widget();
    }).build(BuildContext());
  });

  Timeline.timeSync('b', () {
    Builder(builder: _getNestedBuilders(300)).build(BuildContext());
  });
}

WidgetBuilder _getNestedBuilders(int count) {
  if (count == 0) {
    return (_) {
      print('goodbye, world!');
      return Widget();
    };
  }
  return (_) => Builder(builder: _getNestedBuilders(count - 1)).build(_);
}
```