@@ -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