[dart2js] Return (almost) const [] when reading empty List<ir.DartType>

When running dart2js in its "linker scenario" on a large internal app
this saves something along the lines of 70MB of memory.

Note: Does not actually return a const object as that might introduce
polymorphism. See CL review for discussion/explanation.

Change-Id: I9f939a57d994139f0c08caab0871361c5ecd437a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/185828
Reviewed-by: Stephen Adams <sra@google.com>
Commit-Queue: Jens Johansen <jensj@google.com>
diff --git a/pkg/compiler/lib/src/serialization/abstract_source.dart b/pkg/compiler/lib/src/serialization/abstract_source.dart
index 8037da0..780642b 100644
--- a/pkg/compiler/lib/src/serialization/abstract_source.dart
+++ b/pkg/compiler/lib/src/serialization/abstract_source.dart
@@ -8,6 +8,9 @@
 /// convenience methods.
 abstract class AbstractDataSource extends DataSourceMixin
     implements DataSource {
+  static final List<ir.DartType> emptyListOfDartTypes =
+      List<ir.DartType>.filled(0, null, growable: false);
+
   final bool useDataKinds;
   EntityReader _entityReader = const EntityReader();
   ComponentLookup _componentLookup;
@@ -143,6 +146,7 @@
   List<ir.DartType> _readDartTypeNodes(
       List<ir.TypeParameter> functionTypeVariables) {
     int count = readInt();
+    if (count == 0) return emptyListOfDartTypes;
     List<ir.DartType> types = new List<ir.DartType>.filled(count, null);
     for (int index = 0; index < count; index++) {
       types[index] = _readDartTypeNode(functionTypeVariables);