|  | // Copyright (c) 2024, 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. | 
|  |  | 
|  | import 'package:benchmark_harness/benchmark_harness.dart'; | 
|  |  | 
|  | // Micro-benchmark for taking tear-off of instance method multiple | 
|  | // times and in a loop. | 
|  |  | 
|  | class BenchTearOffInlined extends BenchmarkBase { | 
|  | BenchTearOffInlined() : super('TearOff.Inlined'); | 
|  |  | 
|  | int sum = 0; | 
|  |  | 
|  | @pragma('vm:prefer-inline') | 
|  | @pragma('wasm:prefer-inline') | 
|  | @pragma('dart2js:prefer-inline') | 
|  | void foo(int arg) { | 
|  | sum += arg; | 
|  | } | 
|  |  | 
|  | @pragma('vm:prefer-inline') | 
|  | @pragma('wasm:prefer-inline') | 
|  | @pragma('dart2js:prefer-inline') | 
|  | void callIt(void Function(int) func, int arg) { | 
|  | func(arg); | 
|  | } | 
|  |  | 
|  | @override | 
|  | @pragma('vm:never-inline') | 
|  | @pragma('wasm:never-inline') | 
|  | @pragma('dart2js:never-inline') | 
|  | void run() { | 
|  | sum = 0; | 
|  | callIt(foo, 1); | 
|  | callIt(foo, 2); | 
|  | callIt(foo, 3); | 
|  | callIt(foo, 4); | 
|  | callIt(foo, 5); | 
|  | for (int i = 11; i < 20; ++i) { | 
|  | callIt(foo, i); | 
|  | } | 
|  | callIt(foo, 6); | 
|  | callIt(foo, 7); | 
|  | callIt(foo, 8); | 
|  | callIt(foo, 9); | 
|  | callIt(foo, 10); | 
|  |  | 
|  | const int expectedSum = 20 * (20 - 1) ~/ 2; | 
|  | if (sum != expectedSum) throw 'Bad result: $sum'; | 
|  | } | 
|  | } | 
|  |  | 
|  | class BenchTearOffInlinedInTry extends BenchmarkBase { | 
|  | BenchTearOffInlinedInTry() : super('TearOff.Inlined.InTry'); | 
|  |  | 
|  | int sum = 0; | 
|  |  | 
|  | @pragma('vm:prefer-inline') | 
|  | @pragma('wasm:prefer-inline') | 
|  | @pragma('dart2js:prefer-inline') | 
|  | void foo(int arg) { | 
|  | sum += arg; | 
|  | } | 
|  |  | 
|  | @pragma('vm:prefer-inline') | 
|  | @pragma('wasm:prefer-inline') | 
|  | @pragma('dart2js:prefer-inline') | 
|  | void callIt(void Function(int) func, int arg) { | 
|  | func(arg); | 
|  | } | 
|  |  | 
|  | @override | 
|  | @pragma('vm:never-inline') | 
|  | @pragma('wasm:never-inline') | 
|  | @pragma('dart2js:never-inline') | 
|  | void run() { | 
|  | sum = 0; | 
|  | try { | 
|  | callIt(foo, 1); | 
|  | callIt(foo, 2); | 
|  | callIt(foo, 3); | 
|  | callIt(foo, 4); | 
|  | callIt(foo, 5); | 
|  | for (int i = 11; i < 20; ++i) { | 
|  | callIt(foo, i); | 
|  | } | 
|  | callIt(foo, 6); | 
|  | callIt(foo, 7); | 
|  | callIt(foo, 8); | 
|  | callIt(foo, 9); | 
|  | callIt(foo, 10); | 
|  | } finally { | 
|  | const int expectedSum = 20 * (20 - 1) ~/ 2; | 
|  | sum -= expectedSum; | 
|  | } | 
|  | if (sum != 0) throw 'Bad result: $sum'; | 
|  | } | 
|  | } | 
|  |  | 
|  | class BenchTearOffNotInlined extends BenchmarkBase { | 
|  | BenchTearOffNotInlined() : super('TearOff.NotInlined'); | 
|  |  | 
|  | int sum = 0; | 
|  |  | 
|  | @pragma('vm:never-inline') | 
|  | @pragma('wasm:never-inline') | 
|  | @pragma('dart2js:never-inline') | 
|  | void foo(int arg) { | 
|  | sum += arg; | 
|  | } | 
|  |  | 
|  | @pragma('vm:never-inline') | 
|  | @pragma('wasm:never-inline') | 
|  | @pragma('dart2js:never-inline') | 
|  | void callIt(void Function(int) func, int arg) { | 
|  | func(arg); | 
|  | } | 
|  |  | 
|  | @override | 
|  | @pragma('vm:never-inline') | 
|  | @pragma('wasm:never-inline') | 
|  | @pragma('dart2js:never-inline') | 
|  | void run() { | 
|  | sum = 0; | 
|  | callIt(foo, 1); | 
|  | callIt(foo, 2); | 
|  | callIt(foo, 3); | 
|  | callIt(foo, 4); | 
|  | callIt(foo, 5); | 
|  | for (int i = 11; i < 20; ++i) { | 
|  | callIt(foo, i); | 
|  | } | 
|  | callIt(foo, 6); | 
|  | callIt(foo, 7); | 
|  | callIt(foo, 8); | 
|  | callIt(foo, 9); | 
|  | callIt(foo, 10); | 
|  |  | 
|  | const int expectedSum = 20 * (20 - 1) ~/ 2; | 
|  | if (sum != expectedSum) throw 'Bad result: $sum'; | 
|  | } | 
|  | } | 
|  |  | 
|  | class BenchTearOffNotInlinedInTry extends BenchmarkBase { | 
|  | BenchTearOffNotInlinedInTry() : super('TearOff.NotInlined.InTry'); | 
|  |  | 
|  | int sum = 0; | 
|  |  | 
|  | @pragma('vm:never-inline') | 
|  | @pragma('wasm:never-inline') | 
|  | @pragma('dart2js:never-inline') | 
|  | void foo(int arg) { | 
|  | sum += arg; | 
|  | } | 
|  |  | 
|  | @pragma('vm:never-inline') | 
|  | @pragma('wasm:never-inline') | 
|  | @pragma('dart2js:never-inline') | 
|  | void callIt(void Function(int) func, int arg) { | 
|  | func(arg); | 
|  | } | 
|  |  | 
|  | @override | 
|  | @pragma('vm:never-inline') | 
|  | @pragma('wasm:never-inline') | 
|  | @pragma('dart2js:never-inline') | 
|  | void run() { | 
|  | sum = 0; | 
|  | try { | 
|  | callIt(foo, 1); | 
|  | callIt(foo, 2); | 
|  | callIt(foo, 3); | 
|  | callIt(foo, 4); | 
|  | callIt(foo, 5); | 
|  | for (int i = 11; i < 20; ++i) { | 
|  | callIt(foo, i); | 
|  | } | 
|  | callIt(foo, 6); | 
|  | callIt(foo, 7); | 
|  | callIt(foo, 8); | 
|  | callIt(foo, 9); | 
|  | callIt(foo, 10); | 
|  | } finally { | 
|  | const int expectedSum = 20 * (20 - 1) ~/ 2; | 
|  | sum -= expectedSum; | 
|  | } | 
|  | if (sum != 0) throw 'Bad result: $sum'; | 
|  | } | 
|  | } | 
|  |  | 
|  | void main() { | 
|  | final benchmarks = [ | 
|  | BenchTearOffInlined(), | 
|  | BenchTearOffInlinedInTry(), | 
|  | BenchTearOffNotInlined(), | 
|  | BenchTearOffNotInlinedInTry(), | 
|  | ]; | 
|  |  | 
|  | for (final benchmark in benchmarks) { | 
|  | benchmark.warmup(); | 
|  | } | 
|  | for (final benchmark in benchmarks) { | 
|  | benchmark.report(); | 
|  | } | 
|  | } |