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