@@ -247,6 +247,10 @@ private static void EmitNoArgsMethodCallPopReturn(
247
247
private TypeBuilder runnableBuilder ;
248
248
private ConsumableTypeInfo consumableInfo ;
249
249
private ConsumeEmitter consumeEmitter ;
250
+ private ConsumableTypeInfo globalSetupReturnInfo ;
251
+ private ConsumableTypeInfo globalCleanupReturnInfo ;
252
+ private ConsumableTypeInfo iterationSetupReturnInfo ;
253
+ private ConsumableTypeInfo iterationCleanupReturnInfo ;
250
254
251
255
private FieldBuilder globalSetupActionField ;
252
256
private FieldBuilder globalCleanupActionField ;
@@ -358,13 +362,22 @@ private void InitForEmitRunnable(BenchmarkBuildInfo newBenchmark)
358
362
359
363
consumableInfo = new ConsumableTypeInfo ( benchmark . BenchmarkCase . Descriptor . WorkloadMethod . ReturnType ) ;
360
364
consumeEmitter = ConsumeEmitter . GetConsumeEmitter ( consumableInfo ) ;
365
+ globalSetupReturnInfo = GetConsumableTypeInfo ( benchmark . BenchmarkCase . Descriptor . GlobalSetupMethod ? . ReturnType ) ;
366
+ globalCleanupReturnInfo = GetConsumableTypeInfo ( benchmark . BenchmarkCase . Descriptor . GlobalCleanupMethod ? . ReturnType ) ;
367
+ iterationSetupReturnInfo = GetConsumableTypeInfo ( benchmark . BenchmarkCase . Descriptor . IterationSetupMethod ? . ReturnType ) ;
368
+ iterationCleanupReturnInfo = GetConsumableTypeInfo ( benchmark . BenchmarkCase . Descriptor . IterationCleanupMethod ? . ReturnType ) ;
361
369
362
370
// Init types
363
371
runnableBuilder = DefineRunnableTypeBuilder ( benchmark , moduleBuilder ) ;
364
372
overheadDelegateType = EmitOverheadDelegateType ( ) ;
365
373
workloadDelegateType = EmitWorkloadDelegateType ( ) ;
366
374
}
367
375
376
+ private static ConsumableTypeInfo GetConsumableTypeInfo ( Type methodReturnType )
377
+ {
378
+ return methodReturnType == null ? null : new ConsumableTypeInfo ( methodReturnType ) ;
379
+ }
380
+
368
381
private Type EmitOverheadDelegateType ( )
369
382
{
370
383
// .class public auto ansi sealed BenchmarkDotNet.Autogenerated.Runnable_0OverheadDelegate
@@ -890,34 +903,84 @@ private void EmitSetupCleanupMethods()
890
903
{
891
904
// Emit Setup/Cleanup methods
892
905
// We emit empty method instead of EmptyAction = "() => { }"
893
- globalSetupMethod = EmitWrapperMethod (
894
- GlobalSetupMethodName ,
895
- Descriptor . GlobalSetupMethod ) ;
896
- globalCleanupMethod = EmitWrapperMethod (
897
- GlobalCleanupMethodName ,
898
- Descriptor . GlobalCleanupMethod ) ;
899
- iterationSetupMethod = EmitWrapperMethod (
900
- IterationSetupMethodName ,
901
- Descriptor . IterationSetupMethod ) ;
902
- iterationCleanupMethod = EmitWrapperMethod (
903
- IterationCleanupMethodName ,
904
- Descriptor . IterationCleanupMethod ) ;
906
+ globalSetupMethod = EmitWrapperMethod ( GlobalSetupMethodName , Descriptor . GlobalSetupMethod , globalSetupReturnInfo ) ;
907
+ globalCleanupMethod = EmitWrapperMethod ( GlobalCleanupMethodName , Descriptor . GlobalCleanupMethod , globalCleanupReturnInfo ) ;
908
+ iterationSetupMethod = EmitWrapperMethod ( IterationSetupMethodName , Descriptor . IterationSetupMethod , iterationSetupReturnInfo ) ;
909
+ iterationCleanupMethod = EmitWrapperMethod ( IterationCleanupMethodName , Descriptor . IterationCleanupMethod , iterationCleanupReturnInfo ) ;
905
910
}
906
911
907
- private MethodBuilder EmitWrapperMethod ( string methodName , MethodInfo optionalTargetMethod )
912
+ private MethodBuilder EmitWrapperMethod ( string methodName , MethodInfo optionalTargetMethod , ConsumableTypeInfo returnTypeInfo )
908
913
{
909
914
var methodBuilder = runnableBuilder . DefinePrivateVoidInstanceMethod ( methodName ) ;
910
915
911
916
var ilBuilder = methodBuilder . GetILGenerator ( ) ;
912
917
913
918
if ( optionalTargetMethod != null )
914
- EmitNoArgsMethodCallPopReturn ( methodBuilder , optionalTargetMethod , ilBuilder , forceDirectCall : true ) ;
919
+ {
920
+ if ( returnTypeInfo ? . IsAwaitable == true )
921
+ {
922
+ EmitAwaitableSetupTeardown ( methodBuilder , optionalTargetMethod , ilBuilder , returnTypeInfo ) ;
923
+ }
924
+ else
925
+ {
926
+ EmitNoArgsMethodCallPopReturn ( methodBuilder , optionalTargetMethod , ilBuilder , forceDirectCall : true ) ;
927
+ }
928
+ }
915
929
916
930
ilBuilder . EmitVoidReturn ( methodBuilder ) ;
917
931
918
932
return methodBuilder ;
919
933
}
920
934
935
+ private void EmitAwaitableSetupTeardown (
936
+ MethodBuilder methodBuilder ,
937
+ MethodInfo targetMethod ,
938
+ ILGenerator ilBuilder ,
939
+ ConsumableTypeInfo returnTypeInfo )
940
+ {
941
+ if ( targetMethod == null )
942
+ throw new ArgumentNullException ( nameof ( targetMethod ) ) ;
943
+
944
+ if ( returnTypeInfo . WorkloadMethodReturnType == typeof ( void ) )
945
+ {
946
+ ilBuilder . Emit ( OpCodes . Ldarg_0 ) ;
947
+ }
948
+ /*
949
+ // call for instance
950
+ // GlobalSetup();
951
+ IL_0006: ldarg.0
952
+ IL_0007: call instance void [BenchmarkDotNet]BenchmarkDotNet.Samples.SampleBenchmark::GlobalSetup()
953
+ */
954
+ /*
955
+ // call for static
956
+ // GlobalSetup();
957
+ IL_0006: call string [BenchmarkDotNet]BenchmarkDotNet.Samples.SampleBenchmark::GlobalCleanup()
958
+ */
959
+ if ( targetMethod . IsStatic )
960
+ {
961
+ ilBuilder . Emit ( OpCodes . Call , targetMethod ) ;
962
+
963
+ }
964
+ else if ( methodBuilder . IsStatic )
965
+ {
966
+ throw new InvalidOperationException (
967
+ $ "[BUG] Static method { methodBuilder . Name } tries to call instance member { targetMethod . Name } ") ;
968
+ }
969
+ else
970
+ {
971
+ ilBuilder . Emit ( OpCodes . Ldarg_0 ) ;
972
+ ilBuilder . Emit ( OpCodes . Call , targetMethod ) ;
973
+ }
974
+
975
+ /*
976
+ // BenchmarkDotNet.Helpers.AwaitHelper.GetResult(...);
977
+ IL_000e: call !!0 BenchmarkDotNet.Helpers.AwaitHelper::GetResult<int32>(valuetype [System.Runtime]System.Threading.Tasks.ValueTask`1<!!0>)
978
+ */
979
+
980
+ ilBuilder . Emit ( OpCodes . Call , returnTypeInfo . GetResultMethod ) ;
981
+ ilBuilder . Emit ( OpCodes . Pop ) ;
982
+ }
983
+
921
984
private void EmitCtorBody ( )
922
985
{
923
986
var ilBuilder = ctorMethod . GetILGenerator ( ) ;
0 commit comments