[vm] Add TypeLiteral benchmark

This benchmark tests the performance of uninstantiated type literal
usages.

Issue https://github.com/dart-lang/sdk/issues/48757

TEST=ci

Change-Id: I5eb881a2b8e397997505af41b24240afcbe9d1ac
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/242104
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
diff --git a/benchmarks/TypeLiteral/dart/TypeLiteral.dart b/benchmarks/TypeLiteral/dart/TypeLiteral.dart
new file mode 100644
index 0000000..fb9f567
--- /dev/null
+++ b/benchmarks/TypeLiteral/dart/TypeLiteral.dart
@@ -0,0 +1,197 @@
+// Copyright (c) 2022, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+const int iterations = 100000;
+
+void main() {
+  SyncCallBenchmark('TypeLiteral.GenericFunction.T.dynamic', () {
+    for (int i = 0; i < iterations; ++i) {
+      getT<dynamic>();
+    }
+    return iterations;
+  }).report();
+  SyncCallBenchmark('TypeLiteral.GenericFunction.T.int', () {
+    for (int i = 0; i < iterations; ++i) {
+      getT<int>();
+    }
+    return iterations;
+  }).report();
+  SyncCallBenchmark('TypeLiteral.GenericFunction.T.nullableInt', () {
+    for (int i = 0; i < iterations; ++i) {
+      getT<int?>();
+    }
+    return iterations;
+  }).report();
+  SyncCallBenchmark('TypeLiteral.GenericFunction.ListOfT.int', () {
+    for (int i = 0; i < iterations; ++i) {
+      getListOfT<int>();
+    }
+    return iterations;
+  }).report();
+  SyncCallBenchmark('TypeLiteral.GenericFunction.ListOfT.nullableInt', () {
+    for (int i = 0; i < iterations; ++i) {
+      getListOfT<int?>();
+    }
+    return iterations;
+  }).report();
+  SyncCallBenchmark('TypeLiteral.GenericFunction.NullableT.int', () {
+    for (int i = 0; i < iterations; ++i) {
+      getNullableT<int>();
+    }
+    return iterations;
+  }).report();
+  SyncCallBenchmark('TypeLiteral.GenericFunction.NullableT.nullableInt', () {
+    for (int i = 0; i < iterations; ++i) {
+      getNullableT<int?>();
+    }
+    return iterations;
+  }).report();
+  SyncCallBenchmark('TypeLiteral.GenericFunction.ListOfNullableT.int', () {
+    for (int i = 0; i < iterations; ++i) {
+      getListOfT<int>();
+    }
+    return iterations;
+  }).report();
+  SyncCallBenchmark('TypeLiteral.GenericFunction.ListOfNullableT.nullableInt',
+      () {
+    for (int i = 0; i < iterations; ++i) {
+      getListOfNullableT<int?>();
+    }
+    return iterations;
+  }).report();
+  final foos = <Foo<Object?>>[
+    Foo<int>(),
+    Foo<int?>(),
+    Foo<dynamic>(),
+  ];
+  final Foo fooInt = foos[int.parse('0')];
+  final Foo fooNullableInt = foos[int.parse('1')];
+  final Foo fooDynamic = foos[int.parse('2')];
+  SyncCallBenchmark('TypeLiteral.GenericClass.T.dynamic', () {
+    for (int i = 0; i < iterations; ++i) {
+      fooDynamic.getT();
+    }
+    return iterations;
+  }).report();
+  SyncCallBenchmark('TypeLiteral.GenericClass.T.int', () {
+    for (int i = 0; i < iterations; ++i) {
+      fooInt.getT();
+    }
+    return iterations;
+  }).report();
+  SyncCallBenchmark('TypeLiteral.GenericClass.T.nullableInt', () {
+    for (int i = 0; i < iterations; ++i) {
+      fooNullableInt.getT();
+    }
+    return iterations;
+  }).report();
+  SyncCallBenchmark('TypeLiteral.GenericClass.ListOfT.int', () {
+    for (int i = 0; i < iterations; ++i) {
+      fooInt.getListOfT();
+    }
+    return iterations;
+  }).report();
+  SyncCallBenchmark('TypeLiteral.GenericClass.ListOfT.nullableInt', () {
+    for (int i = 0; i < iterations; ++i) {
+      fooNullableInt.getListOfT();
+    }
+    return iterations;
+  }).report();
+  SyncCallBenchmark('TypeLiteral.GenericClass.NullableT.int', () {
+    for (int i = 0; i < iterations; ++i) {
+      fooInt.getNullableT();
+    }
+    return iterations;
+  }).report();
+  SyncCallBenchmark('TypeLiteral.GenericClass.NullableT.nullableInt', () {
+    for (int i = 0; i < iterations; ++i) {
+      fooNullableInt.getNullableT();
+    }
+    return iterations;
+  }).report();
+  SyncCallBenchmark('TypeLiteral.GenericClass.ListOfNullableT.int', () {
+    for (int i = 0; i < iterations; ++i) {
+      fooInt.getListOfT();
+    }
+    return iterations;
+  }).report();
+  SyncCallBenchmark('TypeLiteral.GenericClass.ListOfNullableT.nullableInt', () {
+    for (int i = 0; i < iterations; ++i) {
+      fooNullableInt.getListOfNullableT();
+    }
+    return iterations;
+  }).report();
+}
+
+@pragma('vm:never-inline')
+@pragma('dart2js:noInline')
+Type getT<T>() => T;
+
+@pragma('vm:never-inline')
+@pragma('dart2js:noInline')
+Type getNullableT<T>() => MakeNullable<T?>;
+
+@pragma('vm:never-inline')
+@pragma('dart2js:noInline')
+Type getListOfT<T>() => List<T>;
+
+@pragma('vm:never-inline')
+@pragma('dart2js:noInline')
+Type getListOfNullableT<T>() => List<T?>;
+
+class Foo<T> {
+  @pragma('vm:never-inline')
+  @pragma('dart2js:noInline')
+  Type getT() => T;
+
+  @pragma('vm:never-inline')
+  @pragma('dart2js:noInline')
+  Type getNullableT() => MakeNullable<T?>;
+
+  @pragma('vm:never-inline')
+  @pragma('dart2js:noInline')
+  Type getListOfT() => List<T>;
+
+  @pragma('vm:never-inline')
+  @pragma('dart2js:noInline')
+  Type getListOfNullableT() => List<T?>;
+}
+
+typedef MakeNullable<X> = X?;
+
+// Same as from [Calls] benchmark.
+class SyncCallBenchmark {
+  final String name;
+  final int Function() performCalls;
+
+  SyncCallBenchmark(this.name, this.performCalls);
+
+  // Returns the number of nanoseconds per call.
+  double measureFor(Duration duration) {
+    final sw = Stopwatch()..start();
+    final durationInMicroseconds = duration.inMicroseconds;
+
+    int numberOfCalls = 0;
+    int totalMicroseconds = 0;
+    do {
+      numberOfCalls += performCalls();
+      totalMicroseconds = sw.elapsedMicroseconds;
+    } while (totalMicroseconds < durationInMicroseconds);
+
+    final int totalNanoseconds = sw.elapsed.inMicroseconds * 1000;
+    return totalNanoseconds / numberOfCalls;
+  }
+
+  // Runs warmup phase, runs benchmark and reports result.
+  void report() {
+    // Warmup for 100 ms.
+    measureFor(const Duration(milliseconds: 100));
+
+    // Run benchmark for 2 seconds.
+    final double nsPerCall = measureFor(const Duration(seconds: 2));
+
+    // Report result.
+    print('$name(RunTimeRaw): $nsPerCall ns.');
+  }
+}