@@ -245,6 +245,10 @@ private static void EmitNoArgsMethodCallPopReturn(
245245 private TypeBuilder runnableBuilder ;
246246 private ConsumableTypeInfo consumableInfo ;
247247 private ConsumeEmitter consumeEmitter ;
248+ private ConsumableTypeInfo globalSetupReturnInfo ;
249+ private ConsumableTypeInfo globalCleanupReturnInfo ;
250+ private ConsumableTypeInfo iterationSetupReturnInfo ;
251+ private ConsumableTypeInfo iterationCleanupReturnInfo ;
248252
249253 private FieldBuilder globalSetupActionField ;
250254 private FieldBuilder globalCleanupActionField ;
@@ -356,13 +360,22 @@ private void InitForEmitRunnable(BenchmarkBuildInfo newBenchmark)
356360
357361 consumableInfo = new ConsumableTypeInfo ( benchmark . BenchmarkCase . Descriptor . WorkloadMethod . ReturnType ) ;
358362 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 ) ;
359367
360368 // Init types
361369 runnableBuilder = DefineRunnableTypeBuilder ( benchmark , moduleBuilder ) ;
362370 overheadDelegateType = EmitOverheadDelegateType ( ) ;
363371 workloadDelegateType = EmitWorkloadDelegateType ( ) ;
364372 }
365373
374+ private static ConsumableTypeInfo GetConsumableTypeInfo ( Type methodReturnType )
375+ {
376+ return methodReturnType == null ? null : new ConsumableTypeInfo ( methodReturnType ) ;
377+ }
378+
366379 private Type EmitOverheadDelegateType ( )
367380 {
368381 // .class public auto ansi sealed BenchmarkDotNet.Autogenerated.Runnable_0OverheadDelegate
@@ -887,34 +900,84 @@ private void EmitSetupCleanupMethods()
887900 {
888901 // Emit Setup/Cleanup methods
889902 // 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 ) ;
902907 }
903908
904- private MethodBuilder EmitWrapperMethod ( string methodName , MethodInfo optionalTargetMethod )
909+ private MethodBuilder EmitWrapperMethod ( string methodName , MethodInfo optionalTargetMethod , ConsumableTypeInfo returnTypeInfo )
905910 {
906911 var methodBuilder = runnableBuilder . DefinePrivateVoidInstanceMethod ( methodName ) ;
907912
908913 var ilBuilder = methodBuilder . GetILGenerator ( ) ;
909914
910915 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+ }
912926
913927 ilBuilder . EmitVoidReturn ( methodBuilder ) ;
914928
915929 return methodBuilder ;
916930 }
917931
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+
918981 private void EmitCtorBody ( )
919982 {
920983 var ilBuilder = ctorMethod . GetILGenerator ( ) ;
0 commit comments