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