diff --git a/BenchmarkDotNet.sln b/BenchmarkDotNet.sln
index 1df6c0aabd..186fecb04b 100644
--- a/BenchmarkDotNet.sln
+++ b/BenchmarkDotNet.sln
@@ -59,6 +59,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BenchmarkDotNet.Exporters.P
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BenchmarkDotNet.Exporters.Plotting.Tests", "tests\BenchmarkDotNet.Exporters.Plotting.Tests\BenchmarkDotNet.Exporters.Plotting.Tests.csproj", "{199AC83E-30BD-40CD-87CE-0C838AC0320D}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BenchmarkDotNet.Weaver", "src\BenchmarkDotNet.Weaver\BenchmarkDotNet.Weaver.csproj", "{5731DE42-16FE-430E-BA90-0EBE714CB221}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -161,6 +163,10 @@ Global
 		{199AC83E-30BD-40CD-87CE-0C838AC0320D}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{199AC83E-30BD-40CD-87CE-0C838AC0320D}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{199AC83E-30BD-40CD-87CE-0C838AC0320D}.Release|Any CPU.Build.0 = Release|Any CPU
+		{5731DE42-16FE-430E-BA90-0EBE714CB221}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{5731DE42-16FE-430E-BA90-0EBE714CB221}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{5731DE42-16FE-430E-BA90-0EBE714CB221}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{5731DE42-16FE-430E-BA90-0EBE714CB221}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -190,6 +196,7 @@ Global
 		{2E2283A3-6DA6-4482-8518-99D6D9F689AB} = {D6597E3A-6892-4A68-8E14-042FC941FDA2}
 		{B92ECCEF-7C27-4012-9E19-679F3C40A6A6} = {D6597E3A-6892-4A68-8E14-042FC941FDA2}
 		{199AC83E-30BD-40CD-87CE-0C838AC0320D} = {14195214-591A-45B7-851A-19D3BA2413F9}
+		{5731DE42-16FE-430E-BA90-0EBE714CB221} = {D6597E3A-6892-4A68-8E14-042FC941FDA2}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {4D9AF12B-1F7F-45A7-9E8C-E4E46ADCBD1F}
diff --git a/NuGet.Config b/NuGet.Config
index 7507704b8b..ca58921f13 100644
--- a/NuGet.Config
+++ b/NuGet.Config
@@ -8,11 +8,13 @@
     
 
     
-    
+    
     
     
     
     
     
+
+    
   
 
diff --git a/build/BenchmarkDotNet.Build/Program.cs b/build/BenchmarkDotNet.Build/Program.cs
index 5fd25cc298..3b8743f178 100644
--- a/build/BenchmarkDotNet.Build/Program.cs
+++ b/build/BenchmarkDotNet.Build/Program.cs
@@ -16,8 +16,29 @@ public static int Main(string[] args)
     }
 }
 
+[TaskName(Name)]
+[TaskDescription("Pack Weaver")]
+public class PackWeaverTask : FrostingTask, IHelpProvider
+{
+    private const string Name = "pack-weaver";
+
+    public override void Run(BuildContext context) => context.BuildRunner.PackWeaver();
+
+    public HelpInfo GetHelp()
+    {
+        return new HelpInfo
+        {
+            Examples = new[]
+            {
+                new Example(Name)
+            }
+        };
+    }
+}
+
 [TaskName(Name)]
 [TaskDescription("Restore NuGet packages")]
+[IsDependentOn(typeof(PackWeaverTask))]
 public class RestoreTask : FrostingTask, IHelpProvider
 {
     private const string Name = "restore";
diff --git a/build/BenchmarkDotNet.Build/Runners/BuildRunner.cs b/build/BenchmarkDotNet.Build/Runners/BuildRunner.cs
index a38ce7e79d..c5a99c0727 100644
--- a/build/BenchmarkDotNet.Build/Runners/BuildRunner.cs
+++ b/build/BenchmarkDotNet.Build/Runners/BuildRunner.cs
@@ -8,6 +8,8 @@
 using Cake.Common.Tools.DotNet.Workload.Install;
 using Cake.Core;
 using Cake.Core.IO;
+using System.IO;
+using System.Linq;
 
 namespace BenchmarkDotNet.Build.Runners;
 
@@ -20,6 +22,41 @@ public BuildRunner(BuildContext context)
         this.context = context;
     }
 
+    public void PackWeaver()
+    {
+        var weaverPath = context.AllPackableSrcProjects.Single(p => p.GetFilename() == "BenchmarkDotNet.Weaver.csproj");
+        var outputPackageDir = weaverPath.GetDirectory().Combine("packages");
+
+        // Delete old package.
+        foreach (var file in Directory.EnumerateFiles(outputPackageDir.FullPath))
+        {
+            File.Delete(file);
+        }
+
+        context.DotNetRestore(weaverPath.GetDirectory().FullPath,
+            new DotNetRestoreSettings
+            {
+                MSBuildSettings = context.MsBuildSettingsRestore
+            });
+
+        context.Information("BuildSystemProvider: " + context.BuildSystem().Provider);
+        context.DotNetBuild(weaverPath.FullPath, new DotNetBuildSettings
+        {
+            NoRestore = true,
+            DiagnosticOutput = true,
+            MSBuildSettings = context.MsBuildSettingsBuild,
+            Configuration = context.BuildConfiguration,
+            Verbosity = context.BuildVerbosity
+        });
+
+        context.DotNetPack(weaverPath.FullPath, new DotNetPackSettings
+        {
+            OutputDirectory = outputPackageDir,
+            MSBuildSettings = context.MsBuildSettingsPack,
+            Configuration = context.BuildConfiguration
+        });
+    }
+
     public void Restore()
     {
         context.DotNetRestore(context.SolutionFile.FullPath,
@@ -71,7 +108,7 @@ public void Pack()
         var settingsSrc = new DotNetPackSettings
         {
             OutputDirectory = context.ArtifactsDirectory,
-            ArgumentCustomization = args => args.Append("--include-symbols").Append("-p:SymbolPackageFormat=snupkg"),
+            ArgumentCustomization = args => args.Append("--include-symbols").Append("-p:SymbolPackageFormat=snupkg").Append("-p:IsFullPack=true"),
             MSBuildSettings = context.MsBuildSettingsPack,
             Configuration = context.BuildConfiguration
         };
diff --git a/build/common.props b/build/common.props
index b33bc4d863..7683722474 100644
--- a/build/common.props
+++ b/build/common.props
@@ -45,6 +45,7 @@
   
 
   
+    
     0.15.3
   
 
@@ -60,6 +61,11 @@
     $(Version)
   
 
+  
+    
+    -1
+  
+
   
     
       all
diff --git a/samples/BenchmarkDotNet.Samples.FSharp/BenchmarkDotNet.Samples.FSharp.fsproj b/samples/BenchmarkDotNet.Samples.FSharp/BenchmarkDotNet.Samples.FSharp.fsproj
index 6359340234..4ace630724 100644
--- a/samples/BenchmarkDotNet.Samples.FSharp/BenchmarkDotNet.Samples.FSharp.fsproj
+++ b/samples/BenchmarkDotNet.Samples.FSharp/BenchmarkDotNet.Samples.FSharp.fsproj
@@ -3,6 +3,7 @@
     
     true
   
+  
   
     Exe
     net462;net8.0
diff --git a/samples/BenchmarkDotNet.Samples/IntroSmokeStringBuilder.cs b/samples/BenchmarkDotNet.Samples/IntroSmokeStringBuilder.cs
new file mode 100644
index 0000000000..65b9355095
--- /dev/null
+++ b/samples/BenchmarkDotNet.Samples/IntroSmokeStringBuilder.cs
@@ -0,0 +1,34 @@
+using BenchmarkDotNet.Attributes;
+using System.Text;
+
+namespace BenchmarkDotNet.Samples
+{
+    [MemoryDiagnoser(false)]
+    public class IntroSmokeStringBuilder
+    {
+        [Benchmark]
+        [Arguments(1)]
+        [Arguments(1_000)]
+        public StringBuilder Append_Strings(int repeat)
+        {
+            StringBuilder builder = new StringBuilder();
+
+            // strings are not sorted by length to mimic real input
+            for (int i = 0; i < repeat; i++)
+            {
+                builder.Append("12345");
+                builder.Append("1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMN");
+                builder.Append("1234567890abcdefghijklmnopqrstuvwxy");
+                builder.Append("1234567890");
+                builder.Append("1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHI");
+                builder.Append("1234567890abcde");
+                builder.Append("1234567890abcdefghijklmnopqrstuvwxyzABCD");
+                builder.Append("1234567890abcdefghijklmnopqrst");
+                builder.Append("1234567890abcdefghij");
+                builder.Append("1234567890abcdefghijklmno");
+            }
+
+            return builder;
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/BenchmarkDotNet.Annotations/BenchmarkDotNet.Annotations.csproj b/src/BenchmarkDotNet.Annotations/BenchmarkDotNet.Annotations.csproj
index ccc51bcd9a..ab73aaeb81 100644
--- a/src/BenchmarkDotNet.Annotations/BenchmarkDotNet.Annotations.csproj
+++ b/src/BenchmarkDotNet.Annotations/BenchmarkDotNet.Annotations.csproj
@@ -3,7 +3,7 @@
   
     Basic BenchmarkDotNet attributes that can be used to annotate your benchmarks
     netstandard2.0
-    $(NoWarn);1701;1702;1705;1591;3005;NU1702;CA1825
+    $(NoWarn);1701;1702;1705;1591;3005;NU1702;NU5100;CA1825
     BenchmarkDotNet.Annotations
     BenchmarkDotNet.Annotations
     BenchmarkDotNet
@@ -14,4 +14,20 @@
   
     
   
+
+  
+    
+      
+        
+        
+        
+      
+    
+    
+      
+      
+        
+      
+    
+  
 
\ No newline at end of file
diff --git a/src/BenchmarkDotNet.Annotations/buildTransitive/netstandard2.0/BenchmarkDotNet.Annotations.targets b/src/BenchmarkDotNet.Annotations/buildTransitive/netstandard2.0/BenchmarkDotNet.Annotations.targets
new file mode 100644
index 0000000000..42644f7b32
--- /dev/null
+++ b/src/BenchmarkDotNet.Annotations/buildTransitive/netstandard2.0/BenchmarkDotNet.Annotations.targets
@@ -0,0 +1,14 @@
+
+
+  
+    
+      $(MSBuildThisFileDirectory)..\..\lib\netstandard2.0\BenchmarkDotNet.Annotations.dll
+    
+  
+
+  
+
+  
+    
+  
+
\ No newline at end of file
diff --git a/src/BenchmarkDotNet.Weaver/.gitignore b/src/BenchmarkDotNet.Weaver/.gitignore
new file mode 100644
index 0000000000..ddb9a15db5
--- /dev/null
+++ b/src/BenchmarkDotNet.Weaver/.gitignore
@@ -0,0 +1 @@
+!packages/
\ No newline at end of file
diff --git a/src/BenchmarkDotNet.Weaver/BenchmarkDotNet.Weaver.csproj b/src/BenchmarkDotNet.Weaver/BenchmarkDotNet.Weaver.csproj
new file mode 100644
index 0000000000..adfb6921b3
--- /dev/null
+++ b/src/BenchmarkDotNet.Weaver/BenchmarkDotNet.Weaver.csproj
@@ -0,0 +1,34 @@
+
+
+
+  
+  
+    netstandard2.0
+    $(VersionSuffix)$(WeaverVersionSuffix)
+    $(MSBuildThisFileDirectory)bin\$(Configuration)
+    true
+    false
+    $(NoWarn);NU5100;NU5128
+    
+    false
+    false
+    
+    false
+  
+
+  
+    
+    
+    
+  
+
+  
+    
+    
+    
+    
+  
+
\ No newline at end of file
diff --git a/src/BenchmarkDotNet.Weaver/buildTransitive/netstandard2.0/BenchmarkDotNet.Weaver.targets b/src/BenchmarkDotNet.Weaver/buildTransitive/netstandard2.0/BenchmarkDotNet.Weaver.targets
new file mode 100644
index 0000000000..d51be29ec4
--- /dev/null
+++ b/src/BenchmarkDotNet.Weaver/buildTransitive/netstandard2.0/BenchmarkDotNet.Weaver.targets
@@ -0,0 +1,14 @@
+
+
+  
+
+  
+    
+      true
+    
+  
+
+  
+    
+  
+
\ No newline at end of file
diff --git a/src/BenchmarkDotNet.Weaver/packages/BenchmarkDotNet.Weaver.0.15.3-develop-1.nupkg b/src/BenchmarkDotNet.Weaver/packages/BenchmarkDotNet.Weaver.0.15.3-develop-1.nupkg
new file mode 100644
index 0000000000..e103b33394
Binary files /dev/null and b/src/BenchmarkDotNet.Weaver/packages/BenchmarkDotNet.Weaver.0.15.3-develop-1.nupkg differ
diff --git a/src/BenchmarkDotNet.Weaver/src/WeaveAssemblyTask.cs b/src/BenchmarkDotNet.Weaver/src/WeaveAssemblyTask.cs
new file mode 100644
index 0000000000..9fdff81cac
--- /dev/null
+++ b/src/BenchmarkDotNet.Weaver/src/WeaveAssemblyTask.cs
@@ -0,0 +1,110 @@
+// *****
+// If any changes are made to this file, increment the WeaverVersionSuffix in the common.props file,
+// then run `build.cmd pack-weaver`.
+// *****
+
+using AsmResolver.DotNet;
+using AsmResolver.PE.DotNet.Metadata.Tables;
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+using System;
+using System.IO;
+using System.Linq;
+
+namespace BenchmarkDotNet.Weaver;
+
+/// 
+/// The Task used by MSBuild to weave the assembly.
+/// 
+public sealed class WeaveAssemblyTask : Task
+{
+    /// 
+    /// The path of the target assembly.
+    /// 
+    [Required]
+    public string TargetAssembly { get; set; }
+
+    /// 
+    /// Runs the weave assembly task.
+    /// 
+    ///  if successful;  otherwise.
+    public override bool Execute()
+    {
+        if (!File.Exists(TargetAssembly))
+        {
+            Log.LogError($"Assembly not found: {TargetAssembly}");
+            return false;
+        }
+
+
+        bool benchmarkMethodsImplAdjusted = false;
+        try
+        {
+            var module = ModuleDefinition.FromFile(TargetAssembly);
+
+            foreach (var type in module.GetAllTypes())
+            {
+                // We can skip non-public types as they are not valid for benchmarks.
+                if (type.IsNotPublic)
+                {
+                    continue;
+                }
+
+                foreach (var method in type.Methods)
+                {
+                    if (method.CustomAttributes.Any(IsBenchmarkAttribute))
+                    {
+                        var oldImpl = method.ImplAttributes;
+                        // Remove AggressiveInlining and add NoInlining.
+                        method.ImplAttributes = (oldImpl & ~MethodImplAttributes.AggressiveInlining) | MethodImplAttributes.NoInlining;
+                        benchmarkMethodsImplAdjusted |= (oldImpl & MethodImplAttributes.NoInlining) == 0;
+                    }
+                }
+            }
+
+            if (benchmarkMethodsImplAdjusted)
+            {
+                // Write to a memory stream before overwriting the original file in case an exception occurs during the write (like unsupported platform).
+                // https://github.com/Washi1337/AsmResolver/issues/640
+                var memoryStream = new MemoryStream();
+                try
+                {
+                    module.Write(memoryStream);
+                    using var fileStream = new FileStream(TargetAssembly, FileMode.Truncate, FileAccess.Write);
+                    memoryStream.WriteTo(fileStream);
+                }
+                catch (OutOfMemoryException)
+                {
+                    // If there is not enough memory, fallback to write to null stream then write to file.
+                    memoryStream.Dispose();
+                    memoryStream = null;
+                    GC.Collect();
+                    module.Write(Stream.Null);
+                    module.Write(TargetAssembly);
+                }
+                finally
+                {
+                    memoryStream?.Dispose();
+                }
+            }
+        }
+        catch (Exception e)
+        {
+            Log.LogWarning($"Assembly weaving failed. Benchmark methods found requiring NoInlining: {benchmarkMethodsImplAdjusted}. Error:{Environment.NewLine}{e}");
+        }
+        return true;
+    }
+
+    private static bool IsBenchmarkAttribute(CustomAttribute attribute)
+    {
+        // BenchmarkAttribute is unsealed, so we need to walk its hierarchy.
+        for (var attr = attribute.Constructor.DeclaringType; attr != null; attr = attr.Resolve()?.BaseType)
+        {
+            if (attr.FullName == "BenchmarkDotNet.Attributes.BenchmarkAttribute")
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+}
\ No newline at end of file
diff --git a/src/BenchmarkDotNet/Code/CodeGenerator.cs b/src/BenchmarkDotNet/Code/CodeGenerator.cs
index 9a6228dd88..2664822f72 100644
--- a/src/BenchmarkDotNet/Code/CodeGenerator.cs
+++ b/src/BenchmarkDotNet/Code/CodeGenerator.cs
@@ -37,24 +37,16 @@ internal static string Generate(BuildPartition buildPartition)
 
                 string passArguments = GetPassArguments(benchmark);
 
-                string compilationId = $"{provider.ReturnsDefinition}_{buildInfo.Id}";
-
                 AddNonEmptyUnique(additionalLogic, benchmark.Descriptor.AdditionalLogic);
 
                 string benchmarkTypeCode = new SmartStringBuilder(ResourceHelper.LoadTemplate("BenchmarkType.txt"))
                     .Replace("$ID$", buildInfo.Id.ToString())
                     .Replace("$OperationsPerInvoke$", provider.OperationsPerInvoke)
                     .Replace("$WorkloadTypeName$", provider.WorkloadTypeName)
-                    .Replace("$WorkloadMethodDelegate$", provider.WorkloadMethodDelegate(passArguments))
-                    .Replace("$WorkloadMethodReturnType$", provider.WorkloadMethodReturnTypeName)
-                    .Replace("$WorkloadMethodReturnTypeModifiers$", provider.WorkloadMethodReturnTypeModifiers)
-                    .Replace("$OverheadMethodReturnTypeName$", provider.OverheadMethodReturnTypeName)
                     .Replace("$GlobalSetupMethodName$", provider.GlobalSetupMethodName)
                     .Replace("$GlobalCleanupMethodName$", provider.GlobalCleanupMethodName)
                     .Replace("$IterationSetupMethodName$", provider.IterationSetupMethodName)
                     .Replace("$IterationCleanupMethodName$", provider.IterationCleanupMethodName)
-                    .Replace("$OverheadImplementation$", provider.OverheadImplementation)
-                    .Replace("$ConsumeField$", provider.ConsumeField)
                     .Replace("$JobSetDefinition$", GetJobsSetDefinition(benchmark))
                     .Replace("$ParamsInitializer$", GetParamsInitializer(benchmark))
                     .Replace("$ParamsContent$", GetParamsContent(benchmark))
@@ -66,7 +58,7 @@ internal static string Generate(BuildPartition buildPartition)
                     .Replace("$MeasureExtraStats$", buildInfo.Config.HasExtraStatsDiagnoser() ? "true" : "false")
                     .Replace("$DisassemblerEntryMethodName$", DisassemblerConstants.DisassemblerEntryMethodName)
                     .Replace("$WorkloadMethodCall$", provider.GetWorkloadMethodCall(passArguments))
-                    .RemoveRedundantIfDefines(compilationId);
+                    .ToString();
 
                 benchmarkTypeCode = Unroll(benchmarkTypeCode, benchmark.Job.ResolveValue(RunMode.UnrollFactorCharacteristic, EnvironmentResolver.Instance));
 
@@ -155,36 +147,21 @@ private static DeclarationsProvider GetDeclarationsProvider(Descriptor descripto
 
             if (method.ReturnType == typeof(Task) || method.ReturnType == typeof(ValueTask))
             {
-                return new TaskDeclarationsProvider(descriptor);
+                return new AsyncDeclarationsProvider(descriptor);
             }
             if (method.ReturnType.GetTypeInfo().IsGenericType
                 && (method.ReturnType.GetTypeInfo().GetGenericTypeDefinition() == typeof(Task<>)
                     || method.ReturnType.GetTypeInfo().GetGenericTypeDefinition() == typeof(ValueTask<>)))
             {
-                return new GenericTaskDeclarationsProvider(descriptor);
-            }
-
-            if (method.ReturnType == typeof(void))
-            {
-                bool isUsingAsyncKeyword = method.HasAttribute();
-                if (isUsingAsyncKeyword)
-                {
-                    throw new NotSupportedException("async void is not supported by design");
-                }
-
-                return new VoidDeclarationsProvider(descriptor);
+                return new AsyncDeclarationsProvider(descriptor);
             }
 
-            if (method.ReturnType.IsByRef)
+            if (method.ReturnType == typeof(void) && method.HasAttribute())
             {
-                // System.Runtime.CompilerServices.IsReadOnlyAttribute is part of .NET Standard 2.1, we can't use it here..
-                if (method.ReturnParameter.GetCustomAttributes().Any(attribute => attribute.GetType().Name == "IsReadOnlyAttribute"))
-                    return new ByReadOnlyRefDeclarationsProvider(descriptor);
-                else
-                    return new ByRefDeclarationsProvider(descriptor);
+                throw new NotSupportedException("async void is not supported by design");
             }
 
-            return new NonVoidDeclarationsProvider(descriptor);
+            return new SyncDeclarationsProvider(descriptor);
         }
 
         private static string GetParamsInitializer(BenchmarkCase benchmarkCase)
@@ -314,31 +291,6 @@ public SmartStringBuilder Replace(string oldValue, string? newValue)
                 return this;
             }
 
-            public string RemoveRedundantIfDefines(string id)
-            {
-                var oldLines = builder.ToString().Split('\n');
-                var newLines = new List();
-                bool keepAdding = true;
-
-                foreach (string line in oldLines)
-                {
-                    if (line.StartsWith("#if RETURNS") || line.StartsWith("#elif RETURNS"))
-                    {
-                        keepAdding = line.Contains(id);
-                    }
-                    else if (line.StartsWith("#endif // RETURNS"))
-                    {
-                        keepAdding = true;
-                    }
-                    else if (keepAdding)
-                    {
-                        newLines.Add(line);
-                    }
-                }
-
-                return string.Join("\n", newLines);
-            }
-
             public override string ToString() => builder.ToString();
         }
     }
diff --git a/src/BenchmarkDotNet/Code/DeclarationsProvider.cs b/src/BenchmarkDotNet/Code/DeclarationsProvider.cs
index 7528e8ed62..0c9a8dce46 100644
--- a/src/BenchmarkDotNet/Code/DeclarationsProvider.cs
+++ b/src/BenchmarkDotNet/Code/DeclarationsProvider.cs
@@ -1,10 +1,6 @@
-using System;
-using System.Linq;
-using System.Reflection;
+using System.Reflection;
 using System.Threading.Tasks;
-using BenchmarkDotNet.Engines;
 using BenchmarkDotNet.Extensions;
-using BenchmarkDotNet.Helpers;
 using BenchmarkDotNet.Running;
 
 namespace BenchmarkDotNet.Code
@@ -30,26 +26,8 @@ internal abstract class DeclarationsProvider
 
         public string IterationCleanupMethodName => Descriptor.IterationCleanupMethod?.Name ?? EmptyAction;
 
-        public abstract string ReturnsDefinition { get; }
-
-        protected virtual Type WorkloadMethodReturnType => Descriptor.WorkloadMethod.ReturnType;
-
-        public virtual string WorkloadMethodReturnTypeName => WorkloadMethodReturnType.GetCorrectCSharpTypeName();
-
-        public virtual string WorkloadMethodDelegate(string passArguments) => Descriptor.WorkloadMethod.Name;
-
-        public virtual string WorkloadMethodReturnTypeModifiers => null;
-
         public virtual string GetWorkloadMethodCall(string passArguments) => $"{Descriptor.WorkloadMethod.Name}({passArguments})";
 
-        public virtual string ConsumeField => null;
-
-        protected abstract Type OverheadMethodReturnType { get; }
-
-        public string OverheadMethodReturnTypeName => OverheadMethodReturnType.GetCorrectCSharpTypeName();
-
-        public abstract string OverheadImplementation { get; }
-
         private string GetMethodName(MethodInfo method)
         {
             if (method == null)
@@ -70,104 +48,14 @@ private string GetMethodName(MethodInfo method)
         }
     }
 
-    internal class VoidDeclarationsProvider : DeclarationsProvider
-    {
-        public VoidDeclarationsProvider(Descriptor descriptor) : base(descriptor) { }
-
-        public override string ReturnsDefinition => "RETURNS_VOID";
-
-        protected override Type OverheadMethodReturnType => typeof(void);
-
-        public override string OverheadImplementation => string.Empty;
-    }
-
-    internal class NonVoidDeclarationsProvider : DeclarationsProvider
-    {
-        public NonVoidDeclarationsProvider(Descriptor descriptor) : base(descriptor) { }
-
-        public override string ConsumeField
-            => !Consumer.IsConsumable(WorkloadMethodReturnType) && Consumer.HasConsumableField(WorkloadMethodReturnType, out var field)
-                ? $".{field.Name}"
-                : null;
-
-        protected override Type OverheadMethodReturnType
-            => Consumer.IsConsumable(WorkloadMethodReturnType)
-                ? WorkloadMethodReturnType
-                : (Consumer.HasConsumableField(WorkloadMethodReturnType, out var field)
-                    ? field.FieldType
-                    : typeof(int)); // we return this simple type because creating bigger ValueType could take longer than benchmarked method itself
-
-        public override string OverheadImplementation
-        {
-            get
-            {
-                string value;
-                var type = OverheadMethodReturnType;
-                if (type.GetTypeInfo().IsPrimitive)
-                    value = $"default({type.GetCorrectCSharpTypeName()})";
-                else if (type.GetTypeInfo().IsClass || type.GetTypeInfo().IsInterface)
-                    value = "null";
-                else
-                    value = SourceCodeHelper.ToSourceCode(Activator.CreateInstance(type)) + ";";
-                return $"return {value};";
-            }
-        }
-
-        public override string ReturnsDefinition
-            => Consumer.IsConsumable(WorkloadMethodReturnType) || Consumer.HasConsumableField(WorkloadMethodReturnType, out _)
-                ? "RETURNS_CONSUMABLE"
-                : "RETURNS_NON_CONSUMABLE_STRUCT";
-    }
-
-    internal class ByRefDeclarationsProvider : NonVoidDeclarationsProvider
+    internal class SyncDeclarationsProvider : DeclarationsProvider
     {
-        public ByRefDeclarationsProvider(Descriptor descriptor) : base(descriptor) { }
-
-        protected override Type OverheadMethodReturnType => typeof(IntPtr);
-
-        public override string WorkloadMethodReturnTypeName => base.WorkloadMethodReturnTypeName.Replace("&", string.Empty);
-
-        public override string ConsumeField => null;
-
-        public override string OverheadImplementation => $"return default(System.{nameof(IntPtr)});";
-
-        public override string ReturnsDefinition => "RETURNS_BYREF";
-
-        public override string WorkloadMethodReturnTypeModifiers => "ref";
+        public SyncDeclarationsProvider(Descriptor descriptor) : base(descriptor) { }
     }
 
-    internal class ByReadOnlyRefDeclarationsProvider : ByRefDeclarationsProvider
+    internal class AsyncDeclarationsProvider : DeclarationsProvider
     {
-        public ByReadOnlyRefDeclarationsProvider(Descriptor descriptor) : base(descriptor) { }
-
-        public override string ReturnsDefinition => "RETURNS_BYREF_READONLY";
-
-        public override string WorkloadMethodReturnTypeModifiers => "ref readonly";
-    }
-
-    internal class TaskDeclarationsProvider : VoidDeclarationsProvider
-    {
-        public TaskDeclarationsProvider(Descriptor descriptor) : base(descriptor) { }
-
-        public override string WorkloadMethodDelegate(string passArguments)
-            => $"({passArguments}) => {{ BenchmarkDotNet.Helpers.AwaitHelper.GetResult({Descriptor.WorkloadMethod.Name}({passArguments})); }}";
-
-        public override string GetWorkloadMethodCall(string passArguments) => $"BenchmarkDotNet.Helpers.AwaitHelper.GetResult({Descriptor.WorkloadMethod.Name}({passArguments}))";
-
-        protected override Type WorkloadMethodReturnType => typeof(void);
-    }
-
-    /// 
-    /// declarations provider for  and 
-    /// 
-    internal class GenericTaskDeclarationsProvider : NonVoidDeclarationsProvider
-    {
-        public GenericTaskDeclarationsProvider(Descriptor descriptor) : base(descriptor) { }
-
-        protected override Type WorkloadMethodReturnType => Descriptor.WorkloadMethod.ReturnType.GetTypeInfo().GetGenericArguments().Single();
-
-        public override string WorkloadMethodDelegate(string passArguments)
-            => $"({passArguments}) => {{ return BenchmarkDotNet.Helpers.AwaitHelper.GetResult({Descriptor.WorkloadMethod.Name}({passArguments})); }}";
+        public AsyncDeclarationsProvider(Descriptor descriptor) : base(descriptor) { }
 
         public override string GetWorkloadMethodCall(string passArguments) => $"BenchmarkDotNet.Helpers.AwaitHelper.GetResult({Descriptor.WorkloadMethod.Name}({passArguments}))";
     }
diff --git a/src/BenchmarkDotNet/Engines/Consumer.cs b/src/BenchmarkDotNet/Engines/Consumer.cs
index 55f8e3b040..5c687f20e6 100644
--- a/src/BenchmarkDotNet/Engines/Consumer.cs
+++ b/src/BenchmarkDotNet/Engines/Consumer.cs
@@ -1,7 +1,4 @@
 using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Reflection;
 using System.Runtime.CompilerServices;
 using System.Threading;
 using JetBrains.Annotations;
@@ -11,13 +8,6 @@ namespace BenchmarkDotNet.Engines
 {
     public class Consumer
     {
-        private static readonly HashSet SupportedTypes
-            = new HashSet(
-                typeof(Consumer).GetTypeInfo()
-                                .DeclaredFields
-                                .Where(field => !field.IsStatic) // exclude this HashSet itself
-                                .Select(field => field.FieldType));
-
 #pragma warning disable IDE0052 // Remove unread private members
         private volatile byte byteHolder;
         private volatile sbyte sbyteHolder;
@@ -153,28 +143,5 @@ public void Consume(in T value)
             else
                 DeadCodeEliminationHelper.KeepAliveWithoutBoxingReadonly(value); // non-primitive and nullable value types
         }
-
-        internal static bool IsConsumable(Type type)
-            => SupportedTypes.Contains(type) || type.GetTypeInfo().IsClass || type.GetTypeInfo().IsInterface;
-
-        internal static bool HasConsumableField(Type type, out FieldInfo? consumableField)
-        {
-            var typeInfo = type.GetTypeInfo();
-
-            if (typeInfo.IsEnum)
-            {
-                // Enums are tricky bastards which report "value__" field, which is public for reflection, but inaccessible via C#
-                consumableField = null;
-                return false;
-            }
-
-            var publicInstanceFields = typeInfo.DeclaredFields
-                                               .Where(field => field.IsPublic && !field.IsStatic)
-                                               .ToArray();
-
-            consumableField = publicInstanceFields.FirstOrDefault(field => IsConsumable(field.FieldType));
-
-            return consumableField != null;
-        }
     }
 }
\ No newline at end of file
diff --git a/src/BenchmarkDotNet/Helpers/Reflection.Emit/IlGeneratorCallExtensions.cs b/src/BenchmarkDotNet/Helpers/Reflection.Emit/IlGeneratorCallExtensions.cs
index 6f9a794e01..214963dd78 100644
--- a/src/BenchmarkDotNet/Helpers/Reflection.Emit/IlGeneratorCallExtensions.cs
+++ b/src/BenchmarkDotNet/Helpers/Reflection.Emit/IlGeneratorCallExtensions.cs
@@ -7,25 +7,6 @@ namespace BenchmarkDotNet.Helpers.Reflection.Emit
 {
     internal static class IlGeneratorCallExtensions
     {
-        public static LocalBuilder DeclareOptionalLocalForInstanceCall(
-            this ILGenerator ilBuilder,
-            Type localType,
-            MethodInfo methodToCall)
-        {
-            if (methodToCall.DeclaringType == null)
-                throw new ArgumentException($"The {nameof(methodToCall)} should have non-null {nameof(methodToCall.DeclaringType)}.");
-
-            if (methodToCall.IsStatic)
-                return null;
-
-            if (!methodToCall.DeclaringType.IsAssignableFrom(localType))
-                throw new ArgumentException($"{methodToCall.DeclaringType} is not assignable from {localType}.");
-
-            return localType.IsValueType && localType != typeof(void)
-                ? ilBuilder.DeclareLocal(localType)
-                : null;
-        }
-
         public static void EmitStaticCall(
             this ILGenerator ilBuilder,
             MethodInfo methodToCall,
diff --git a/src/BenchmarkDotNet/Helpers/Reflection.Emit/IlGeneratorDefaultValueExtensions.cs b/src/BenchmarkDotNet/Helpers/Reflection.Emit/IlGeneratorDefaultValueExtensions.cs
deleted file mode 100644
index 4b23db0141..0000000000
--- a/src/BenchmarkDotNet/Helpers/Reflection.Emit/IlGeneratorDefaultValueExtensions.cs
+++ /dev/null
@@ -1,182 +0,0 @@
-using System;
-using System.Reflection.Emit;
-
-namespace BenchmarkDotNet.Helpers.Reflection.Emit
-{
-    internal static class IlGeneratorDefaultValueExtensions
-    {
-        public static LocalBuilder DeclareOptionalLocalForReturnDefault(this ILGenerator ilBuilder, Type resultType)
-        {
-            return resultType.UseInitObjForReturnDefault()
-                ? ilBuilder.DeclareLocal(resultType)
-                : null;
-        }
-
-        public static void EmitSetLocalToDefault(this ILGenerator ilBuilder, LocalBuilder local)
-        {
-            var resultType = local.LocalType;
-            switch (resultType)
-            {
-                case Type t when t == typeof(void):
-                    break;
-                case Type t when t.IsClass || t.IsInterface:
-                    ilBuilder.Emit(OpCodes.Ldnull);
-                    ilBuilder.EmitStloc(local);
-                    break;
-                case Type t when t.UseInitObjForInitLocal():
-                    EmitInitObj(ilBuilder, resultType, local);
-                    break;
-                default:
-                    EmitLoadDefaultPrimitive(ilBuilder, resultType);
-                    ilBuilder.EmitStloc(local);
-                    break;
-            }
-        }
-
-        public static void EmitReturnDefault(this ILGenerator ilBuilder, Type resultType, LocalBuilder optionalLocalForInitobj)
-        {
-            switch (resultType)
-            {
-                case Type t when t == typeof(void):
-                    break;
-                case Type t when t.IsClass || t.IsInterface:
-                    ilBuilder.Emit(OpCodes.Ldnull);
-                    break;
-                case Type t when t.UseInitObjForReturnDefault():
-                    EmitInitObj(ilBuilder, resultType, optionalLocalForInitobj);
-                    ilBuilder.EmitLdloc(optionalLocalForInitobj);
-                    break;
-                default:
-                    EmitLoadDefaultPrimitive(ilBuilder, resultType);
-                    break;
-            }
-            // IL_0000: ret
-            ilBuilder.Emit(OpCodes.Ret);
-        }
-
-        private static bool IsInitLocalPrimitive(this Type t)
-        {
-            // var x = default(T):
-            // C# compiler uses special logic for enum defaults and primitive defaults
-            // On init local case this logic does not apply for IntPtr & UIntPtr.
-
-            if (t == typeof(void))
-                return true;
-
-            if (t.IsEnum)
-                return true;
-
-            return t.IsPrimitive
-                   && t != typeof(IntPtr)
-                   && t != typeof(UIntPtr);
-        }
-
-        private static bool IsReturnDefaultPrimitive(this Type t)
-        {
-            // return default(T):
-            // C# compiler uses special logic for enum defaults and primitive defaults
-            // On return default special logic is applied for decimals too.
-
-
-            if (t == typeof(void))
-                return true;
-
-            if (t.IsEnum)
-                return true;
-
-            return t.IsPrimitive
-                   || t == typeof(decimal);
-        }
-
-        private static bool UseInitObjForInitLocal(this Type resultType)
-        {
-            return resultType.IsValueType && !resultType.IsInitLocalPrimitive();
-        }
-
-        private static bool UseInitObjForReturnDefault(this Type resultType)
-        {
-            return resultType.IsValueType && !resultType.IsReturnDefaultPrimitive();
-        }
-
-        private static void EmitInitObj(ILGenerator ilBuilder, Type resultType, LocalBuilder optionalLocalForInitobj)
-        {
-            if (optionalLocalForInitobj == null)
-                throw new ArgumentNullException(nameof(optionalLocalForInitobj));
-
-            /*
-                IL_0000: ldloca.s 0
-                IL_0002: initobj [mscorlib]System.DateTime
-            */
-            ilBuilder.EmitLdloca(optionalLocalForInitobj);
-            ilBuilder.Emit(OpCodes.Initobj, resultType);
-        }
-
-        private static void EmitLoadDefaultPrimitive(this ILGenerator ilBuilder, Type resultType)
-        {
-            var valueType = resultType;
-            if (valueType.IsEnum)
-                valueType = resultType.GetEnumUnderlyingType();
-
-            // The primitive types are Boolean, Byte, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64, IntPtr, UIntPtr, Char, Double, and Single
-            // + custom logic for decimal
-            switch (valueType)
-            {
-                case Type t0 when t0 == typeof(bool):
-                case Type t1 when t1 == typeof(byte):
-                case Type t2 when t2 == typeof(sbyte):
-                case Type t3 when t3 == typeof(short):
-                case Type t4 when t4 == typeof(ushort):
-                case Type t5 when t5 == typeof(int):
-                case Type t6 when t6 == typeof(uint):
-                case Type t7 when t7 == typeof(char):
-                    ilBuilder.Emit(OpCodes.Ldc_I4_0);
-                    break;
-                case Type t1 when t1 == typeof(ulong):
-                case Type t2 when t2 == typeof(long):
-                    /*
-                        // return 0L;
-                        IL_0000: ldc.i4.0
-                        IL_0001: conv.i8
-                        // return 0uL;
-                        IL_0000: ldc.i4.0
-                        IL_0001: conv.i8
-                     */
-                    ilBuilder.Emit(OpCodes.Ldc_I4_0);
-                    ilBuilder.Emit(OpCodes.Conv_I8);
-                    break;
-                case Type t when t == typeof(IntPtr):
-                    /*
-                        IL_0000: ldc.i4.0
-                        IL_0001: conv.i
-                     */
-                    ilBuilder.Emit(OpCodes.Ldc_I4_0);
-                    ilBuilder.Emit(OpCodes.Conv_I);
-                    break;
-                case Type t when t == typeof(UIntPtr):
-                    /*
-                        IL_0000: ldc.i4.0
-                        IL_0001: conv.u
-                     */
-                    ilBuilder.Emit(OpCodes.Ldc_I4_0);
-                    ilBuilder.Emit(OpCodes.Conv_U);
-                    break;
-                case Type t when t == typeof(double):
-                    ilBuilder.Emit(OpCodes.Ldc_R8, 0.0d);
-                    break;
-                case Type t when t == typeof(float):
-                    ilBuilder.Emit(OpCodes.Ldc_R4, 0.0f);
-                    break;
-                case Type t when t == typeof(decimal):
-                    /*
-                        // return decimal.Zero;
-                        IL_0011: ldsfld valuetype [mscorlib]System.Decimal [mscorlib]System.Decimal::Zero
-                     */
-                    var zeroField = typeof(decimal).GetField(nameof(decimal.Zero));
-                    ilBuilder.Emit(OpCodes.Ldsfld, zeroField);
-                    break;
-                default:
-                    throw new NotSupportedException($"Cannot emit default for {resultType}.");
-            }
-        }
-    }
-}
\ No newline at end of file
diff --git a/src/BenchmarkDotNet/Helpers/Reflection.Emit/IlGeneratorEmitOpExtensions.cs b/src/BenchmarkDotNet/Helpers/Reflection.Emit/IlGeneratorEmitOpExtensions.cs
index 50a3392f44..7763d59e91 100644
--- a/src/BenchmarkDotNet/Helpers/Reflection.Emit/IlGeneratorEmitOpExtensions.cs
+++ b/src/BenchmarkDotNet/Helpers/Reflection.Emit/IlGeneratorEmitOpExtensions.cs
@@ -116,127 +116,19 @@ public static void EmitLdarg(this ILGenerator ilBuilder, ParameterInfo argument)
             }
         }
 
-        public static void EmitLdindStind(this ILGenerator ilBuilder, Type resultType)
+        public static void EmitStarg(this ILGenerator ilBuilder, ParameterInfo argument)
         {
-            if (!resultType.IsByRef)
-                throw new NotSupportedException($"Cannot emit indirect op for non-reference {resultType}.");
-
-            // The primitive types are Boolean, Byte, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64, IntPtr, UIntPtr, Char, Double, and Single
-            var valueType = resultType.GetElementType();
-            if (valueType?.IsEnum ?? false)
-                valueType = valueType.GetEnumUnderlyingType();
+            var position = argument.Position;
+            if (!((MethodBase) argument.Member).IsStatic)
+                position++;
 
-            switch (valueType)
+            if (position < 255)
             {
-                case Type t when t == typeof(bool):
-                    /*
-                        IL_0018: ldind.u1
-                        IL_0019: stind.i1
-                     */
-                    ilBuilder.Emit(OpCodes.Ldind_U1);
-                    ilBuilder.Emit(OpCodes.Stind_I1);
-                    break;
-                case Type t when t == typeof(byte):
-                    /*
-                        IL_0018: ldind.u1
-                        IL_0019: stind.i1
-                     */
-                    ilBuilder.Emit(OpCodes.Ldind_U1);
-                    ilBuilder.Emit(OpCodes.Stind_I1);
-                    break;
-                case Type t when t == typeof(sbyte):
-                    /*
-                        IL_0018: ldind.i1
-                        IL_0019: stind.i1
-                     */
-                    ilBuilder.Emit(OpCodes.Ldind_I1);
-                    ilBuilder.Emit(OpCodes.Stind_I1);
-                    break;
-                case Type t when t == typeof(short):
-                    /*
-                        IL_0018: ldind.i2
-                        IL_0019: stind.i2
-                     */
-                    ilBuilder.Emit(OpCodes.Ldind_I2);
-                    ilBuilder.Emit(OpCodes.Stind_I2);
-                    break;
-                case Type t1 when t1 == typeof(ushort):
-                case Type t2 when t2 == typeof(char):
-                    /*
-                        IL_0018: ldind.u2
-                        IL_0019: stind.i2
-                     */
-                    ilBuilder.Emit(OpCodes.Ldind_U2);
-                    ilBuilder.Emit(OpCodes.Stind_I2);
-                    break;
-                case Type t when t == typeof(int):
-                    /*
-                        IL_0018: ldind.i4
-                        IL_0019: stind.i4
-                     */
-                    ilBuilder.Emit(OpCodes.Ldind_I4);
-                    ilBuilder.Emit(OpCodes.Stind_I4);
-                    break;
-                case Type t when t == typeof(uint):
-                    /*
-                        IL_0018: ldind.i4
-                        IL_0019: stind.i4
-                     */
-                    ilBuilder.Emit(OpCodes.Ldind_U4);
-                    ilBuilder.Emit(OpCodes.Stind_I4);
-                    break;
-                case Type t1 when t1 == typeof(ulong):
-                case Type t2 when t2 == typeof(long):
-                    /*
-                        IL_0018: ldind.i8
-                        IL_0019: stind.i8
-                     */
-                    ilBuilder.Emit(OpCodes.Ldind_I8);
-                    ilBuilder.Emit(OpCodes.Stind_I8);
-                    break;
-                case Type t1 when t1 == typeof(IntPtr):
-                case Type t2 when t2 == typeof(UIntPtr):
-                    /*
-                        IL_0018: ldind.i
-                        IL_0019: stind.i
-                     */
-                    ilBuilder.Emit(OpCodes.Ldind_I);
-                    ilBuilder.Emit(OpCodes.Stind_I);
-                    break;
-                case Type t when t == typeof(double):
-                    /*
-                        IL_0018: ldind.r8
-                        IL_0019: stind.i8
-                     */
-                    ilBuilder.Emit(OpCodes.Ldind_R8);
-                    ilBuilder.Emit(OpCodes.Stind_R8);
-                    break;
-                case Type t when t == typeof(float):
-                    /*
-                        IL_0018: ldind.r4
-                        IL_0019: stind.i4
-                     */
-                    ilBuilder.Emit(OpCodes.Ldind_R4);
-                    ilBuilder.Emit(OpCodes.Stind_R4);
-                    break;
-                case Type t when t.IsClass || t.IsInterface:
-                    /*
-                        IL_0018: ldind.ref
-                        IL_0019: stind.ref
-                     */
-                    ilBuilder.Emit(OpCodes.Ldind_Ref);
-                    ilBuilder.Emit(OpCodes.Stind_Ref);
-                    break;
-                case Type t when t.IsEnum || t.IsValueType:
-                    /*
-                        IL_0018: ldobj valuetype [mscorlib]System.Nullable`1
-                        IL_0019: stobj valuetype [mscorlib]System.Nullable`1
-                     */
-                    ilBuilder.Emit(OpCodes.Ldobj, valueType);
-                    ilBuilder.Emit(OpCodes.Stobj, valueType);
-                    break;
-                default:
-                    throw new NotSupportedException($"Cannot emit indirect store for {resultType}.");
+                ilBuilder.Emit(OpCodes.Starg_S, (byte) position);
+            }
+            else
+            {
+                ilBuilder.Emit(OpCodes.Starg, checked((short) position));
             }
         }
     }
diff --git a/src/BenchmarkDotNet/Helpers/Reflection.Emit/IlGeneratorStatementExtensions.cs b/src/BenchmarkDotNet/Helpers/Reflection.Emit/IlGeneratorStatementExtensions.cs
index 6d601e6495..4fd23e3ab8 100644
--- a/src/BenchmarkDotNet/Helpers/Reflection.Emit/IlGeneratorStatementExtensions.cs
+++ b/src/BenchmarkDotNet/Helpers/Reflection.Emit/IlGeneratorStatementExtensions.cs
@@ -84,64 +84,57 @@ public static void EmitSetDelegateToThisField(
             }
         }
 
-        public static void EmitLoopBeginFromLocToArg(
+        public static void EmitLoopBeginFromArgToZero(
             this ILGenerator ilBuilder,
-            Label loopStartLabel,
-            Label loopHeadLabel,
-            LocalBuilder indexLocal,
-            ParameterInfo toArg)
+            out Label loopStartLabel,
+            out Label loopHeadLabel)
         {
-            // loop counter stored as loc0, loop max passed as arg1
+            loopStartLabel = ilBuilder.DefineLabel();
+            loopHeadLabel = ilBuilder.DefineLabel();
+            // invokeCount passed as arg
             /*
-                // for (long i = 0L; i < invokeCount; i++)
-                IL_0000: ldc.i4.0
-                IL_0001: conv.i8
-                IL_0002: stloc.0
+                // while (--invokeCount >= 0)
             */
-            ilBuilder.Emit(OpCodes.Ldc_I4_0);
-            ilBuilder.Emit(OpCodes.Conv_I8);
-            ilBuilder.EmitStloc(indexLocal);
 
-            // IL_0003: br.s IL_0036 // loop head: IL_0036 // we use long jump
+            // IL_0000: br.s IL_000e // loop head: IL_000e // we use long jump
             ilBuilder.Emit(OpCodes.Br, loopHeadLabel);
 
-            // loop start (head: IL_0036)
+            // loop start (head: IL_000e)
             ilBuilder.MarkLabel(loopStartLabel);
         }
 
-        public static void EmitLoopEndFromLocToArg(
+        public static void EmitLoopEndFromArgToZero(
             this ILGenerator ilBuilder,
             Label loopStartLabel,
             Label loopHeadLabel,
-            LocalBuilder indexLocal,
-            ParameterInfo toArg)
+            ParameterInfo arg)
         {
-            // loop counter stored as loc0, loop max passed as arg1
-            /*
-                // for (long i = 0L; i < invokeCount; i++)
-                IL_0031: ldloc.0
-                IL_0032: ldc.i4.1
-                IL_0033: conv.i8
-                IL_0034: add
-                IL_0035: stloc.0
-             */
-            ilBuilder.EmitLdloc(indexLocal);
-            ilBuilder.Emit(OpCodes.Ldc_I4_1);
-            ilBuilder.Emit(OpCodes.Conv_I8);
-            ilBuilder.Emit(OpCodes.Add);
-            ilBuilder.EmitStloc(indexLocal);
-
+            // invokeCount passed as arg
             /*
-                // for (long i = 0L; i < invokeCount; i++)
-                IL_0036: ldloc.0 // loop head: IL_0036
-                IL_0037: ldarg.1
-                IL_0038: blt.s IL_0005 // we use long jump
+                // while (--invokeCount >= 0)
+                IL_0008: ldarg.1
+                IL_0009: ldc.i4.1
+                IL_000a: conv.i8
+                IL_000b: sub
+                IL_000c: dup
+                IL_000d: starg.s invokeCount
+                IL_000f: ldc.i4.0
+                IL_0010: conv.i8
+                IL_0011: bge.s IL_0002
                 // end loop
              */
+
+            // loop head
             ilBuilder.MarkLabel(loopHeadLabel);
-            ilBuilder.EmitLdloc(indexLocal);
-            ilBuilder.EmitLdarg(toArg);
-            ilBuilder.Emit(OpCodes.Blt, loopStartLabel);
+            ilBuilder.EmitLdarg(arg);
+            ilBuilder.Emit(OpCodes.Ldc_I4_1);
+            ilBuilder.Emit(OpCodes.Conv_I8);
+            ilBuilder.Emit(OpCodes.Sub);
+            ilBuilder.Emit(OpCodes.Dup);
+            ilBuilder.EmitStarg(arg);
+            ilBuilder.Emit(OpCodes.Ldc_I4_0);
+            ilBuilder.Emit(OpCodes.Conv_I8);
+            ilBuilder.Emit(OpCodes.Bge, loopStartLabel);
         }
     }
 }
\ No newline at end of file
diff --git a/src/BenchmarkDotNet/Helpers/Reflection.Emit/MethodBuilderExtensions.cs b/src/BenchmarkDotNet/Helpers/Reflection.Emit/MethodBuilderExtensions.cs
index c09a7d19c2..ae3890141b 100644
--- a/src/BenchmarkDotNet/Helpers/Reflection.Emit/MethodBuilderExtensions.cs
+++ b/src/BenchmarkDotNet/Helpers/Reflection.Emit/MethodBuilderExtensions.cs
@@ -1,5 +1,4 @@
 using BenchmarkDotNet.Portability;
-using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Reflection;
@@ -9,9 +8,6 @@ namespace BenchmarkDotNet.Helpers.Reflection.Emit
 {
     internal static class MethodBuilderExtensions
     {
-        public static Type[] GetParameterTypes(this MethodBase method) =>
-            method.GetParameters().Select(p => p.ParameterType).ToArray();
-
         public static ParameterInfo[] GetEmitParameters(this MethodBuilder method, IEnumerable signatureParameters) =>
             signatureParameters
                 .Select(p =>
diff --git a/src/BenchmarkDotNet/Helpers/Reflection.Emit/ModuleBuilderExtensions.cs b/src/BenchmarkDotNet/Helpers/Reflection.Emit/ModuleBuilderExtensions.cs
deleted file mode 100644
index c879bc1f46..0000000000
--- a/src/BenchmarkDotNet/Helpers/Reflection.Emit/ModuleBuilderExtensions.cs
+++ /dev/null
@@ -1,60 +0,0 @@
-using System;
-using System.Linq;
-using System.Reflection;
-using System.Reflection.Emit;
-
-namespace BenchmarkDotNet.Helpers.Reflection.Emit
-{
-    internal static class ModuleBuilderExtensions
-    {
-        public static Type EmitCustomDelegate(
-            this ModuleBuilder moduleBuilder,
-            string delegateTypeName,
-            ParameterInfo returnType,
-            ParameterInfo[] parameters)
-        {
-            // TODO: begin/end invoke ?
-            var delegatePatternType = typeof(Action);
-
-            var typeBuilder = moduleBuilder.DefineType(
-                delegateTypeName,
-                delegatePatternType.Attributes,
-                delegatePatternType.BaseType);
-
-            var ctorPattern = delegatePatternType.GetConstructors().Single();
-            var ctorBuilder = typeBuilder.DefineConstructor(
-                ctorPattern.Attributes,
-                ctorPattern.CallingConvention,
-                ctorPattern.GetParameterTypes());
-
-            foreach (var parameterInfo in ctorPattern.GetParameters())
-            {
-                ctorBuilder.DefineParameter(parameterInfo.Position + 1, parameterInfo.Attributes, parameterInfo.Name);
-            }
-
-            ctorBuilder.SetImplementationFlags(ctorPattern.GetMethodImplementationFlags());
-
-            var invokePatternMethod = TypeBuilderExtensions.GetDelegateInvokeMethod(delegatePatternType);
-
-            var invokeBuilder = typeBuilder.DefineMethod(
-                invokePatternMethod.Name,
-                invokePatternMethod.Attributes,
-                invokePatternMethod.CallingConvention,
-                returnType.ParameterType,
-                parameters.Select(p => p.ParameterType).ToArray());
-            foreach (var parameterInfo in parameters)
-            {
-                invokeBuilder.DefineParameter(parameterInfo.Position + 1, parameterInfo.Attributes, parameterInfo.Name);
-            }
-            invokeBuilder.DefineParameter(0, returnType.Attributes, "");
-
-            invokeBuilder.SetImplementationFlags(invokePatternMethod.GetMethodImplementationFlags());
-
-#if NETFRAMEWORK
-            return typeBuilder.CreateType();
-#else
-            return typeBuilder.CreateTypeInfo();
-#endif
-        }
-    }
-}
\ No newline at end of file
diff --git a/src/BenchmarkDotNet/Helpers/Reflection.Emit/TypeBuilderExtensions.cs b/src/BenchmarkDotNet/Helpers/Reflection.Emit/TypeBuilderExtensions.cs
index c71c19cd63..2e290be9ba 100644
--- a/src/BenchmarkDotNet/Helpers/Reflection.Emit/TypeBuilderExtensions.cs
+++ b/src/BenchmarkDotNet/Helpers/Reflection.Emit/TypeBuilderExtensions.cs
@@ -25,15 +25,6 @@ private static void DefineParameters(this MethodBuilder methodBuilder, Parameter
             methodBuilder.DefineParameter(0, returnType.Attributes, "");
         }
 
-        public static MethodInfo GetDelegateInvokeMethod(Type delegateType)
-        {
-            var result = delegateType.GetMethod(nameof(Action.Invoke));
-            if (result == null)
-                throw new ArgumentException($"The type {delegateType} nas no Invoke method.", nameof(delegateType));
-
-            return result;
-        }
-
         public static ConstructorBuilder DefinePublicInstanceCtor(this TypeBuilder typeBuilder, params ParameterInfo[] parameters)
         {
             // .method public hidebysig specialname rtspecialname
diff --git a/src/BenchmarkDotNet/Templates/BenchmarkType.txt b/src/BenchmarkDotNet/Templates/BenchmarkType.txt
index ea1bbaa858..6710702306 100644
--- a/src/BenchmarkDotNet/Templates/BenchmarkType.txt
+++ b/src/BenchmarkDotNet/Templates/BenchmarkType.txt
@@ -1,5 +1,5 @@
     // the type name must be in sync with WindowsDisassembler.BuildArguments
-    public unsafe class Runnable_$ID$ : global::$WorkloadTypeName$
+    public unsafe sealed class Runnable_$ID$ : global::$WorkloadTypeName$
     {
         public static void Run(BenchmarkDotNet.Engines.IHost host, System.String benchmarkName)
         {
@@ -51,18 +51,12 @@
             }
         }
 
-        public delegate $OverheadMethodReturnTypeName$ OverheadDelegate($ArgumentsDefinition$);
-
-        public delegate $WorkloadMethodReturnTypeModifiers$ $WorkloadMethodReturnType$ WorkloadDelegate($ArgumentsDefinition$);
-
         public Runnable_$ID$()
         {
             globalSetupAction = $GlobalSetupMethodName$;
             globalCleanupAction = $GlobalCleanupMethodName$;
             iterationSetupAction = $IterationSetupMethodName$;
             iterationCleanupAction = $IterationCleanupMethodName$;
-            overheadDelegate = __Overhead;
-            workloadDelegate = $WorkloadMethodDelegate$;
             $InitializeArgumentFields$
         }
 
@@ -70,8 +64,6 @@
         private System.Action globalCleanupAction;
         private System.Action iterationSetupAction;
         private System.Action iterationCleanupAction;
-        private BenchmarkDotNet.Autogenerated.Runnable_$ID$.OverheadDelegate overheadDelegate;
-        private BenchmarkDotNet.Autogenerated.Runnable_$ID$.WorkloadDelegate workloadDelegate;
         $DeclareArgumentFields$
 
         // this method is used only for the disassembly diagnoser purposes
@@ -84,6 +76,16 @@
             $DisassemblerEntryMethodName$();
         }
 
+        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoOptimization | System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
+        public void $DisassemblerEntryMethodName$()
+        {
+            if (NotEleven == 11)
+            {
+                $LoadArguments$
+                $WorkloadMethodCall$;
+            }
+        }
+
         private System.Int32 dummyVar;
 
         [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
@@ -104,310 +106,48 @@
             @DummyUnroll@
         }
 
-        private $OverheadMethodReturnTypeName$ __Overhead($ArgumentsDefinition$) // __ is to avoid possible name conflict
-        {
-            $OverheadImplementation$
-        }
-
-#if RETURNS_CONSUMABLE_$ID$
-
-        private BenchmarkDotNet.Engines.Consumer consumer = new BenchmarkDotNet.Engines.Consumer();
-
-        [System.Runtime.CompilerServices.MethodImpl(BenchmarkDotNet.Portability.CodeGenHelper.AggressiveOptimizationOption)]
-        private void OverheadActionUnroll(System.Int64 invokeCount)
-        {
-            $LoadArguments$
-            for (System.Int64 i = 0; i < invokeCount; i++)
-            {
-                consumer.Consume(overheadDelegate($PassArguments$));@Unroll@
-            }
-        }
-
-        [System.Runtime.CompilerServices.MethodImpl(BenchmarkDotNet.Portability.CodeGenHelper.AggressiveOptimizationOption)]
-        private void OverheadActionNoUnroll(System.Int64 invokeCount)
-        {
-            $LoadArguments$
-            for (System.Int64 i = 0; i < invokeCount; i++)
-            {
-                consumer.Consume(overheadDelegate($PassArguments$));
-            }
-        }
-
-        [System.Runtime.CompilerServices.MethodImpl(BenchmarkDotNet.Portability.CodeGenHelper.AggressiveOptimizationOption)]
-        private void WorkloadActionUnroll(System.Int64 invokeCount)
-        {
-            $LoadArguments$
-            for (System.Int64  i = 0; i < invokeCount; i++)
-            {
-                consumer.Consume(workloadDelegate($PassArguments$)$ConsumeField$);@Unroll@
-            }
-        }
-
-        [System.Runtime.CompilerServices.MethodImpl(BenchmarkDotNet.Portability.CodeGenHelper.AggressiveOptimizationOption)]
-        private void WorkloadActionNoUnroll(System.Int64 invokeCount)
-        {
-            $LoadArguments$
-            for (System.Int64 i = 0; i < invokeCount; i++)
-            {
-                consumer.Consume(workloadDelegate($PassArguments$)$ConsumeField$);
-            }
-        }
-        
-        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoOptimization | System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
-        public $WorkloadMethodReturnType$ $DisassemblerEntryMethodName$()
-        {
-            if (NotEleven == 11)
-            {
-                $LoadArguments$
-                return $WorkloadMethodCall$;
-            }
-            
-            return default($WorkloadMethodReturnType$);
-        }
-
-#elif RETURNS_NON_CONSUMABLE_STRUCT_$ID$
-
-        [System.Runtime.CompilerServices.MethodImpl(BenchmarkDotNet.Portability.CodeGenHelper.AggressiveOptimizationOption)]
-        private void OverheadActionUnroll(System.Int64 invokeCount)
-        {
-            $LoadArguments$
-            $OverheadMethodReturnTypeName$ result = default($OverheadMethodReturnTypeName$);
-            for (System.Int64 i = 0; i < invokeCount; i++)
-            {
-                result = overheadDelegate($PassArguments$);@Unroll@
-            }
-            BenchmarkDotNet.Engines.DeadCodeEliminationHelper.KeepAliveWithoutBoxing(result);
-        }
-
-        [System.Runtime.CompilerServices.MethodImpl(BenchmarkDotNet.Portability.CodeGenHelper.AggressiveOptimizationOption)]
-        private void OverheadActionNoUnroll(System.Int64 invokeCount)
-        {
-            $LoadArguments$
-            $OverheadMethodReturnTypeName$ result = default($OverheadMethodReturnTypeName$);
-            for (System.Int64 i = 0; i < invokeCount; i++)
-            {
-                result = overheadDelegate($PassArguments$);
-            }
-            BenchmarkDotNet.Engines.DeadCodeEliminationHelper.KeepAliveWithoutBoxing(result);
-        }
-
-        [System.Runtime.CompilerServices.MethodImpl(BenchmarkDotNet.Portability.CodeGenHelper.AggressiveOptimizationOption)]
-        private void WorkloadActionUnroll(System.Int64 invokeCount)
-        {
-            $LoadArguments$
-            $WorkloadMethodReturnType$ result = default($WorkloadMethodReturnType$);
-            for (System.Int64 i = 0; i < invokeCount; i++)
-            {
-                result = workloadDelegate($PassArguments$);@Unroll@
-            }
-            NonGenericKeepAliveWithoutBoxing(result);
-        }
-
-        [System.Runtime.CompilerServices.MethodImpl(BenchmarkDotNet.Portability.CodeGenHelper.AggressiveOptimizationOption)]
-        private void WorkloadActionNoUnroll(System.Int64 invokeCount)
-        {
-            $LoadArguments$
-            $WorkloadMethodReturnType$ result = default($WorkloadMethodReturnType$);
-            for (System.Int64 i = 0; i < invokeCount; i++)
-            {
-                result = workloadDelegate($PassArguments$);
-            }
-            NonGenericKeepAliveWithoutBoxing(result);
-        }
-
-        // we must not simply use DeadCodeEliminationHelper.KeepAliveWithoutBoxing because it's generic method
-        // and stack-only types like Span can not be generic type arguments http://adamsitnik.com/Span/#span-must-not-be-a-generic-type-argument
         [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
-        private void NonGenericKeepAliveWithoutBoxing($WorkloadMethodReturnType$ _) { }
-
-        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoOptimization | System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
-        public $WorkloadMethodReturnType$ $DisassemblerEntryMethodName$()
+        private void __Overhead($ArgumentsDefinition$) // __ is to avoid possible name conflict
         {
-            if (NotEleven == 11)
-            {
-                $LoadArguments$
-                return $WorkloadMethodCall$;
-            }
-            
-            return default($WorkloadMethodReturnType$);
         }
 
-#elif RETURNS_BYREF_$ID$
-
         [System.Runtime.CompilerServices.MethodImpl(BenchmarkDotNet.Portability.CodeGenHelper.AggressiveOptimizationOption)]
         private void OverheadActionUnroll(System.Int64 invokeCount)
         {
             $LoadArguments$
-            $OverheadMethodReturnTypeName$ value = default($OverheadMethodReturnTypeName$);
-            for (System.Int64 i = 0; i < invokeCount; i++)
+            while (--invokeCount >= 0)
             {
-                value = overheadDelegate($PassArguments$);@Unroll@
+                __Overhead($PassArguments$);@Unroll@
             }
-            BenchmarkDotNet.Engines.DeadCodeEliminationHelper.KeepAliveWithoutBoxing(value);
         }
 
         [System.Runtime.CompilerServices.MethodImpl(BenchmarkDotNet.Portability.CodeGenHelper.AggressiveOptimizationOption)]
         private void OverheadActionNoUnroll(System.Int64 invokeCount)
         {
             $LoadArguments$
-            $OverheadMethodReturnTypeName$ value = default($OverheadMethodReturnTypeName$);
-            for (System.Int64 i = 0; i < invokeCount; i++)
+            while (--invokeCount >= 0)
             {
-                value = overheadDelegate($PassArguments$);
+                __Overhead($PassArguments$);
             }
-            BenchmarkDotNet.Engines.DeadCodeEliminationHelper.KeepAliveWithoutBoxing(value);
         }
 
-        private $WorkloadMethodReturnType$ workloadDefaultValueHolder = default($WorkloadMethodReturnType$);
-
         [System.Runtime.CompilerServices.MethodImpl(BenchmarkDotNet.Portability.CodeGenHelper.AggressiveOptimizationOption)]
         private void WorkloadActionUnroll(System.Int64 invokeCount)
         {
             $LoadArguments$
-            ref $WorkloadMethodReturnType$ alias = ref workloadDefaultValueHolder;
-            for (System.Int64 i = 0; i < invokeCount; i++)
+            while (--invokeCount >= 0)
             {
-                alias = workloadDelegate($PassArguments$);@Unroll@
+                $WorkloadMethodCall$;@Unroll@
             }
-            BenchmarkDotNet.Engines.DeadCodeEliminationHelper.KeepAliveWithoutBoxing(ref alias);
         }
 
         [System.Runtime.CompilerServices.MethodImpl(BenchmarkDotNet.Portability.CodeGenHelper.AggressiveOptimizationOption)]
         private void WorkloadActionNoUnroll(System.Int64 invokeCount)
         {
             $LoadArguments$
-            ref $WorkloadMethodReturnType$ alias = ref workloadDefaultValueHolder;
-            for (System.Int64 i = 0; i < invokeCount; i++)
-            {
-                alias = workloadDelegate($PassArguments$);
-            }
-            BenchmarkDotNet.Engines.DeadCodeEliminationHelper.KeepAliveWithoutBoxing(ref alias);
-        }
-
-        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoOptimization | System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
-        public ref $WorkloadMethodReturnType$ $DisassemblerEntryMethodName$()
-        {
-            if (NotEleven == 11)
-            {
-                $LoadArguments$
-                return ref $WorkloadMethodCall$;
-            }
-            
-            return ref workloadDefaultValueHolder;
-        }
-#elif RETURNS_BYREF_READONLY_$ID$
-
-        [System.Runtime.CompilerServices.MethodImpl(BenchmarkDotNet.Portability.CodeGenHelper.AggressiveOptimizationOption)]
-        private void OverheadActionUnroll(System.Int64 invokeCount)
-        {
-            $LoadArguments$
-            $OverheadMethodReturnTypeName$ value = default($OverheadMethodReturnTypeName$);
-            for (System.Int64 i = 0; i < invokeCount; i++)
+            while (--invokeCount >= 0)
             {
-                value = overheadDelegate($PassArguments$);@Unroll@
-            }
-            BenchmarkDotNet.Engines.DeadCodeEliminationHelper.KeepAliveWithoutBoxing(value);
-        }
-
-        [System.Runtime.CompilerServices.MethodImpl(BenchmarkDotNet.Portability.CodeGenHelper.AggressiveOptimizationOption)]
-        private void OverheadActionNoUnroll(System.Int64 invokeCount)
-        {
-            $LoadArguments$
-            $OverheadMethodReturnTypeName$ value = default($OverheadMethodReturnTypeName$);
-            for (System.Int64 i = 0; i < invokeCount; i++)
-            {
-                value = overheadDelegate($PassArguments$);
-            }
-            BenchmarkDotNet.Engines.DeadCodeEliminationHelper.KeepAliveWithoutBoxing(value);
-        }
-
-        private $WorkloadMethodReturnType$ workloadDefaultValueHolder = default($WorkloadMethodReturnType$);
-
-        [System.Runtime.CompilerServices.MethodImpl(BenchmarkDotNet.Portability.CodeGenHelper.AggressiveOptimizationOption)]
-        private void WorkloadActionUnroll(System.Int64 invokeCount)
-        {
-            $LoadArguments$
-            ref $WorkloadMethodReturnType$ alias = ref workloadDefaultValueHolder;
-            for (System.Int64 i = 0; i < invokeCount; i++)
-            {
-                alias = workloadDelegate($PassArguments$);@Unroll@
-            }
-            BenchmarkDotNet.Engines.DeadCodeEliminationHelper.KeepAliveWithoutBoxingReadonly(alias);
-        }
-
-        [System.Runtime.CompilerServices.MethodImpl(BenchmarkDotNet.Portability.CodeGenHelper.AggressiveOptimizationOption)]
-        private void WorkloadActionNoUnroll(System.Int64 invokeCount)
-        {
-            $LoadArguments$
-            ref $WorkloadMethodReturnType$ alias = ref workloadDefaultValueHolder;
-            for (System.Int64 i = 0; i < invokeCount; i++)
-            {
-                alias = workloadDelegate($PassArguments$);
-            }
-            BenchmarkDotNet.Engines.DeadCodeEliminationHelper.KeepAliveWithoutBoxingReadonly(alias);
-        }
-
-        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoOptimization | System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
-        public ref readonly $WorkloadMethodReturnType$ $DisassemblerEntryMethodName$()
-        {
-            if (NotEleven == 11)
-            {
-                $LoadArguments$
-                return ref $WorkloadMethodCall$;
-            }
-            
-            return ref workloadDefaultValueHolder;
-        }
-#elif RETURNS_VOID_$ID$
-
-        [System.Runtime.CompilerServices.MethodImpl(BenchmarkDotNet.Portability.CodeGenHelper.AggressiveOptimizationOption)]
-        private void OverheadActionUnroll(System.Int64 invokeCount)
-        {
-            $LoadArguments$
-            for (System.Int64 i = 0; i < invokeCount; i++)
-            {
-                overheadDelegate($PassArguments$);@Unroll@
-            }
-        }
-
-        [System.Runtime.CompilerServices.MethodImpl(BenchmarkDotNet.Portability.CodeGenHelper.AggressiveOptimizationOption)]
-        private void OverheadActionNoUnroll(System.Int64 invokeCount)
-        {
-            $LoadArguments$
-            for (System.Int64 i = 0; i < invokeCount; i++)
-            {
-                overheadDelegate($PassArguments$);
-            }
-        }
-
-        [System.Runtime.CompilerServices.MethodImpl(BenchmarkDotNet.Portability.CodeGenHelper.AggressiveOptimizationOption)]
-        private void WorkloadActionUnroll(System.Int64 invokeCount)
-        {
-            $LoadArguments$
-            for (System.Int64 i = 0; i < invokeCount; i++)
-            {
-                workloadDelegate($PassArguments$);@Unroll@
-            }
-        }
-
-        [System.Runtime.CompilerServices.MethodImpl(BenchmarkDotNet.Portability.CodeGenHelper.AggressiveOptimizationOption)]
-        private void WorkloadActionNoUnroll(System.Int64 invokeCount)
-        {
-            $LoadArguments$
-            for (System.Int64 i = 0; i < invokeCount; i++)
-            {
-                workloadDelegate($PassArguments$);
-            }
-        }
-
-        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoOptimization | System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
-        public void $DisassemblerEntryMethodName$()
-        {
-            if (NotEleven == 11)
-            {
-                $LoadArguments$
                 $WorkloadMethodCall$;
             }
         }
-#endif // RETURNS
     }
\ No newline at end of file
diff --git a/src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/ConsumableTypeInfo.cs b/src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/ConsumableTypeInfo.cs
index 147a514058..123f07bf7a 100644
--- a/src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/ConsumableTypeInfo.cs
+++ b/src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/ConsumableTypeInfo.cs
@@ -1,7 +1,4 @@
-using BenchmarkDotNet.Engines;
-using System;
-using System.Collections.Generic;
-using System.Linq;
+using System;
 using System.Reflection;
 using System.Runtime.CompilerServices;
 using System.Threading.Tasks;
@@ -41,43 +38,23 @@ public ConsumableTypeInfo(Type methodReturnType)
             if (WorkloadMethodReturnType == null)
                 throw new InvalidOperationException("Bug: (WorkloadMethodReturnType == null");
 
-            var consumableField = default(FieldInfo);
             if (WorkloadMethodReturnType == typeof(void))
             {
                 IsVoid = true;
-                OverheadMethodReturnType = WorkloadMethodReturnType;
             }
             else if (WorkloadMethodReturnType.IsByRef)
             {
                 IsByRef = true;
-                OverheadMethodReturnType = typeof(IntPtr);
             }
-            else if (Consumer.IsConsumable(WorkloadMethodReturnType)
-                || Consumer.HasConsumableField(WorkloadMethodReturnType, out consumableField))
-            {
-                IsConsumable = true;
-                WorkloadConsumableField = consumableField;
-                OverheadMethodReturnType = consumableField?.FieldType ?? WorkloadMethodReturnType;
-            }
-            else
-            {
-                OverheadMethodReturnType = typeof(int); // we return this simple type because creating bigger ValueType could take longer than benchmarked method itself
-            }
-
-            if (OverheadMethodReturnType == null)
-                throw new InvalidOperationException("Bug: (OverheadResultType == null");
         }
 
         public Type OriginMethodReturnType { get; }
         public Type WorkloadMethodReturnType { get; }
-        public Type OverheadMethodReturnType { get; }
 
         public MethodInfo? GetResultMethod { get; }
 
         public bool IsVoid { get; }
         public bool IsByRef { get; }
-        public bool IsConsumable { get; }
-        public FieldInfo? WorkloadConsumableField { get; }
 
         public bool IsAwaitable { get; }
     }
diff --git a/src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/Emitters/ByRefConsumeEmitter.cs b/src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/Emitters/ByRefConsumeEmitter.cs
deleted file mode 100644
index 96ed6d9578..0000000000
--- a/src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/Emitters/ByRefConsumeEmitter.cs
+++ /dev/null
@@ -1,152 +0,0 @@
-using System;
-using System.Linq;
-using System.Reflection;
-using System.Reflection.Emit;
-using BenchmarkDotNet.Engines;
-using BenchmarkDotNet.Helpers.Reflection.Emit;
-using static BenchmarkDotNet.Toolchains.InProcess.Emit.Implementation.RunnableConstants;
-
-namespace BenchmarkDotNet.Toolchains.InProcess.Emit.Implementation
-{
-    internal class ByRefConsumeEmitter : ConsumeEmitter
-    {
-        private FieldBuilder workloadDefaultValueHolderField;
-        private MethodInfo overheadKeepAliveWithoutBoxingMethod;
-        private MethodInfo workloadKeepAliveWithoutBoxingMethod;
-        private LocalBuilder resultLocal;
-
-        public ByRefConsumeEmitter(ConsumableTypeInfo consumableTypeInfo) : base(consumableTypeInfo) { }
-
-        protected override void OnDefineFieldsOverride(TypeBuilder runnableBuilder)
-        {
-            var nonRefType = ConsumableInfo.WorkloadMethodReturnType.GetElementType();
-            if (nonRefType == null)
-                throw new InvalidOperationException($"Bug: type {ConsumableInfo.WorkloadMethodReturnType} is non-ref type.");
-
-            workloadDefaultValueHolderField = runnableBuilder.DefineField(
-                WorkloadDefaultValueHolderFieldName,
-                nonRefType, FieldAttributes.Private);
-        }
-
-        protected override void EmitDisassemblyDiagnoserReturnDefaultOverride(ILGenerator ilBuilder)
-        {
-            /*
-                // return ref workloadDefaultValueHolder;
-                IL_0031: ldarg.0
-                IL_0032: ldflda int32 BenchmarkDotNet.Autogenerated.Runnable_0::workloadDefaultValueHolder
-                IL_0037: ret
-             */
-            ilBuilder.Emit(OpCodes.Ldarg_0);
-            ilBuilder.Emit(OpCodes.Ldflda, workloadDefaultValueHolderField);
-            ilBuilder.Emit(OpCodes.Ret);
-        }
-
-        protected override void OnEmitMembersOverride(TypeBuilder runnableBuilder)
-        {
-            overheadKeepAliveWithoutBoxingMethod = typeof(DeadCodeEliminationHelper).GetMethods()
-                .First(m => m.Name == nameof(DeadCodeEliminationHelper.KeepAliveWithoutBoxing)
-                            && m.GetParameterTypes().First().IsByRef == false)
-                .MakeGenericMethod(ConsumableInfo.OverheadMethodReturnType);
-
-            workloadKeepAliveWithoutBoxingMethod = typeof(DeadCodeEliminationHelper).GetMethods()
-                .First(m => m.Name == nameof(DeadCodeEliminationHelper.KeepAliveWithoutBoxing)
-                            && m.GetParameterTypes().First().IsByRef)
-                .MakeGenericMethod(ConsumableInfo.WorkloadMethodReturnType.GetElementType());
-        }
-
-        protected override void DeclareActionLocalsOverride(ILGenerator ilBuilder)
-        {
-            /*
-                .locals init (
-                    [4] native int,
-                )
-                -or-
-                .locals init (
-                    [4] int32&,
-                )
-             */
-            if (ActionKind == RunnableActionKind.Overhead)
-                resultLocal = ilBuilder.DeclareLocal(ConsumableInfo.OverheadMethodReturnType);
-            else
-                resultLocal = ilBuilder.DeclareLocal(ConsumableInfo.WorkloadMethodReturnType);
-        }
-
-        /// Emits the action before loop override.
-        /// The il builder.
-        /// EmitActionKind - null
-        protected override void EmitActionBeforeLoopOverride(ILGenerator ilBuilder)
-        {
-            /*
-                // IntPtr value = default(IntPtr);
-                IL_001c: ldloca.s 4
-                IL_001e: initobj [mscorlib]System.IntPtr
-                -or-
-                // ref int reference = ref workloadDefaultValueHolder;
-                IL_001c: ldarg.0
-                IL_001d: ldflda int32 BenchmarkDotNet.Autogenerated.Runnable_0::workloadDefaultValueHolder
-                IL_0022: stloc.s 4
-             */
-            if (ActionKind == RunnableActionKind.Overhead)
-            {
-                ilBuilder.EmitLdloca(resultLocal);
-                ilBuilder.Emit(OpCodes.Initobj, ConsumableInfo.OverheadMethodReturnType);
-            }
-            else
-            {
-                ilBuilder.Emit(OpCodes.Ldarg_0);
-                ilBuilder.Emit(OpCodes.Ldflda, workloadDefaultValueHolderField);
-                ilBuilder.EmitStloc(resultLocal);
-            }
-        }
-
-        protected override void EmitActionBeforeCallOverride(ILGenerator ilBuilder)
-        {
-            /*
-                
-                -or-
-                // reference = ...
-                IL_002a: ldloc.s 4
-             */
-            if (ActionKind != RunnableActionKind.Overhead)
-            {
-                ilBuilder.EmitLdloc(resultLocal);
-            }
-        }
-
-        protected override void EmitActionAfterCallOverride(ILGenerator ilBuilder)
-        {
-            /*
-                IL_0039: stloc.s 4
-                -or-
-                // reference = ...
-                IL_003b: ldind.i4
-                IL_003c: stind.i4
-             */
-            if (ActionKind == RunnableActionKind.Overhead)
-            {
-                ilBuilder.EmitStloc(resultLocal);
-            }
-            else
-            {
-                ilBuilder.EmitLdindStind(resultLocal.LocalType);
-            }
-        }
-
-        protected override void EmitActionAfterLoopOverride(ILGenerator ilBuilder)
-        {
-            /*
-                // DeadCodeEliminationHelper.KeepAliveWithoutBoxing(value);
-                IL_007a: ldloc.s 4
-                IL_007c: call void [BenchmarkDotNet]BenchmarkDotNet.Engines.DeadCodeEliminationHelper::KeepAliveWithoutBoxing(!!0)
-                -or-
-                // DeadCodeEliminationHelper.KeepAliveWithoutBoxing(ref reference);
-                IL_0082: ldloc.s 4
-                IL_0084: call void [BenchmarkDotNet]BenchmarkDotNet.Engines.DeadCodeEliminationHelper::KeepAliveWithoutBoxing(!!0&)
-             */
-            if (ActionKind == RunnableActionKind.Overhead)
-                ilBuilder.EmitStaticCall(overheadKeepAliveWithoutBoxingMethod, resultLocal);
-            else
-                ilBuilder.EmitStaticCall(workloadKeepAliveWithoutBoxingMethod, resultLocal);
-        }
-    }
-}
\ No newline at end of file
diff --git a/src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/Emitters/ConsumableConsumeEmitter.cs b/src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/Emitters/ConsumableConsumeEmitter.cs
deleted file mode 100644
index 76a2a5f505..0000000000
--- a/src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/Emitters/ConsumableConsumeEmitter.cs
+++ /dev/null
@@ -1,135 +0,0 @@
-using System;
-using System.Linq;
-using System.Reflection;
-using System.Reflection.Emit;
-using BenchmarkDotNet.Engines;
-using BenchmarkDotNet.Helpers.Reflection.Emit;
-
-namespace BenchmarkDotNet.Toolchains.InProcess.Emit.Implementation
-{
-    internal class ConsumableConsumeEmitter : ConsumeEmitter
-    {
-        private static MethodInfo GetConsumeMethod(Type consumableType)
-        {
-            var consumeMethod = typeof(Consumer).GetMethod(nameof(Consumer.Consume), new[] { consumableType });
-
-            // Use generic method for ref types
-            if (consumeMethod == null || consumeMethod.GetParameterTypes().FirstOrDefault() == typeof(object))
-            {
-                if (consumableType.IsClass || consumableType.IsInterface)
-                {
-                    consumeMethod = typeof(Consumer)
-                        .GetMethods()
-                        .Single(m =>
-                        {
-                            Type argType = m.GetParameterTypes().FirstOrDefault();
-
-                            return m.Name == nameof(Consumer.Consume) && m.IsGenericMethodDefinition
-                                && !argType.IsByRef // we are not interested in "Consume(in T value)"
-                                && argType.IsPointer == consumableType.IsPointer; // use "Consume(T objectValue) where T : class" or "Consume(T* ptrValue) where T: unmanaged"
-                        });
-
-                    consumeMethod = consumableType.IsPointer
-                        ? consumeMethod.MakeGenericMethod(consumableType.GetElementType()) // consumableType is T*, we need T for Consume(T* ptrValue)
-                        : consumeMethod.MakeGenericMethod(consumableType);
-                }
-                else
-                {
-                    consumeMethod = null;
-                }
-            }
-
-            if (consumeMethod == null)
-            {
-                throw new InvalidOperationException($"Cannot consume result of {consumableType}.");
-            }
-
-            return consumeMethod;
-        }
-
-        private FieldBuilder consumerField;
-        private LocalBuilder disassemblyDiagnoserLocal;
-
-        public ConsumableConsumeEmitter(ConsumableTypeInfo consumableTypeInfo) : base(consumableTypeInfo)
-        {
-        }
-
-        protected override void OnDefineFieldsOverride(TypeBuilder runnableBuilder)
-        {
-            consumerField = runnableBuilder.DefineField(RunnableConstants.ConsumerFieldName, typeof(Consumer), FieldAttributes.Private);
-        }
-
-        protected override void DeclareDisassemblyDiagnoserLocalsOverride(ILGenerator ilBuilder)
-        {
-            // optional local if default(T) uses .initobj
-            disassemblyDiagnoserLocal = ilBuilder.DeclareOptionalLocalForReturnDefault(ConsumableInfo.WorkloadMethodReturnType);
-        }
-
-        protected override void EmitDisassemblyDiagnoserReturnDefaultOverride(ILGenerator ilBuilder)
-        {
-            ilBuilder.EmitReturnDefault(ConsumableInfo.WorkloadMethodReturnType, disassemblyDiagnoserLocal);
-        }
-
-        protected override void OnEmitCtorBodyOverride(ConstructorBuilder constructorBuilder, ILGenerator ilBuilder)
-        {
-            var ctor = typeof(Consumer).GetConstructor(Array.Empty());
-            if (ctor == null)
-                throw new InvalidOperationException($"Cannot get default .ctor for {typeof(Consumer)}");
-
-            /*
-                // consumer = new Consumer();
-                IL_0000: ldarg.0
-                IL_0001: newobj instance void [BenchmarkDotNet]BenchmarkDotNet.Engines.Consumer::.ctor()
-                IL_0006: stfld class [BenchmarkDotNet]BenchmarkDotNet.Engines.Consumer BenchmarkDotNet.Autogenerated.Runnable_0::consumer
-             */
-            ilBuilder.Emit(OpCodes.Ldarg_0);
-            ilBuilder.Emit(OpCodes.Newobj, ctor);
-            ilBuilder.Emit(OpCodes.Stfld, consumerField);
-        }
-
-        protected override void EmitActionBeforeCallOverride(ILGenerator ilBuilder)
-        {
-            /*
-                // consumer. ...;
-                IL_000c: ldarg.0
-                IL_000d: ldfld class [BenchmarkDotNet]BenchmarkDotNet.Engines.Consumer BenchmarkDotNet.Autogenerated.Runnable_0::consumer
-             */
-            ilBuilder.Emit(OpCodes.Ldarg_0);
-            ilBuilder.Emit(OpCodes.Ldfld, consumerField);
-        }
-
-        protected override void EmitActionAfterCallOverride(ILGenerator ilBuilder)
-        {
-            /*
-                // ... .Consume( ... )
-                IL_001e: callvirt instance void [BenchmarkDotNet]BenchmarkDotNet.Engines.Consumer::Consume(string)
-                -or-
-                // ... .Consume( ... .ConsumableField);
-                IL_001e: callvirt instance void [BenchmarkDotNet]BenchmarkDotNet.Engines.Consumer::Consume(int32)
-                // -or- .Consume( ... );
-                IL_001e: ldfld int32 BenchmarkDotNet.Samples.CustomWithConsumable::ConsumableField
-                IL_0023: callvirt instance void [BenchmarkDotNet]BenchmarkDotNet.Engines.Consumer::Consume(int32)
-             */
-            if (ActionKind == RunnableActionKind.Overhead)
-            {
-                var overheadConsumeMethod = GetConsumeMethod(ConsumableInfo.OverheadMethodReturnType);
-                ilBuilder.Emit(OpCodes.Callvirt, overheadConsumeMethod);
-            }
-            else
-            {
-                var consumeField = ConsumableInfo.WorkloadConsumableField;
-                if (consumeField == null)
-                {
-                    var consumeMethod = GetConsumeMethod(ConsumableInfo.WorkloadMethodReturnType);
-                    ilBuilder.Emit(OpCodes.Callvirt, consumeMethod);
-                }
-                else
-                {
-                    var consumeMethod = GetConsumeMethod(consumeField.FieldType);
-                    ilBuilder.Emit(OpCodes.Ldfld, consumeField);
-                    ilBuilder.Emit(OpCodes.Callvirt, consumeMethod);
-                }
-            }
-        }
-    }
-}
\ No newline at end of file
diff --git a/src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/Emitters/ConsumeEmitter.cs b/src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/Emitters/ConsumeEmitter.cs
deleted file mode 100644
index 9767cb8263..0000000000
--- a/src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/Emitters/ConsumeEmitter.cs
+++ /dev/null
@@ -1,227 +0,0 @@
-using System;
-using System.Reflection;
-using System.Reflection.Emit;
-using JetBrains.Annotations;
-
-namespace BenchmarkDotNet.Toolchains.InProcess.Emit.Implementation
-{
-    internal abstract class ConsumeEmitter
-    {
-        public static ConsumeEmitter GetConsumeEmitter(ConsumableTypeInfo consumableTypeInfo)
-        {
-            if (consumableTypeInfo == null)
-                throw new ArgumentNullException(nameof(consumableTypeInfo));
-
-            if (consumableTypeInfo.IsVoid)
-                return new VoidConsumeEmitter(consumableTypeInfo);
-            if (consumableTypeInfo.IsByRef)
-                return new ByRefConsumeEmitter(consumableTypeInfo);
-            if (consumableTypeInfo.IsConsumable)
-                return new ConsumableConsumeEmitter(consumableTypeInfo);
-            return new NonConsumableConsumeEmitter(consumableTypeInfo);
-        }
-
-        protected ConsumeEmitter(ConsumableTypeInfo consumableTypeInfo)
-        {
-            if (consumableTypeInfo == null)
-                throw new ArgumentNullException(nameof(consumableTypeInfo));
-
-            ConsumableInfo = consumableTypeInfo;
-        }
-
-        protected ConsumableTypeInfo ConsumableInfo { get; }
-
-        protected ILGenerator? IlBuilder { get; private set; }
-        protected MethodBuilder? ActionMethodBuilder { get; private set; }
-        protected MethodInfo? ActionInvokeMethod { get; private set; }
-        protected RunnableActionKind? ActionKind { get; private set; }
-
-        [AssertionMethod]
-        private void AssertNoBuilder()
-        {
-            if (IlBuilder != null)
-                throw new InvalidOperationException("Bug: emit action logic is broken. Expects that IlBuilder != null");
-
-            if (ActionMethodBuilder != null)
-                throw new InvalidOperationException(
-                    $"Bug: emit action logic is broken. {nameof(ActionMethodBuilder)} is not null.");
-
-            if (ActionInvokeMethod != null)
-                throw new InvalidOperationException(
-                    $"Bug: emit action logic is broken. {nameof(ActionInvokeMethod)} is not null.");
-
-            if (ActionKind != null)
-                throw new InvalidOperationException(
-                    $"Bug: emit action logic is broken. {nameof(ActionKind)} is not null.");
-        }
-
-        [AssertionMethod]
-        private void AssertHasBuilder(ILGenerator ilBuilder)
-        {
-            if (IlBuilder != ilBuilder)
-                throw new InvalidOperationException(
-                    "Bug: emit action logic is broken. Expects that IlBuilder is same as passed one.");
-
-            if (ActionMethodBuilder == null)
-                throw new InvalidOperationException(
-                    $"Bug: emit action logic is broken. {nameof(ActionMethodBuilder)} is null.");
-
-            if (ActionInvokeMethod == null)
-                throw new InvalidOperationException(
-                    $"Bug: emit action logic is broken. {nameof(ActionInvokeMethod)} is null.");
-
-            if (ActionKind != RunnableActionKind.Overhead && ActionKind != RunnableActionKind.Workload)
-                throw new InvalidOperationException(
-                    $"Bug: emit action logic is broken. Unknown {nameof(ActionKind)} value: {ActionKind}.");
-        }
-
-        public void OnDefineFields(TypeBuilder runnableBuilder)
-        {
-            AssertNoBuilder();
-
-            OnDefineFieldsOverride(runnableBuilder);
-        }
-
-        protected virtual void OnDefineFieldsOverride(TypeBuilder runnableBuilder)
-        {
-        }
-
-        public void OnEmitMembers(TypeBuilder runnableBuilder)
-        {
-            AssertNoBuilder();
-
-            OnEmitMembersOverride(runnableBuilder);
-        }
-
-        protected virtual void OnEmitMembersOverride(TypeBuilder runnableBuilder)
-        {
-        }
-
-        public void OnEmitCtorBody(ConstructorBuilder constructorBuilder, ILGenerator ilBuilder)
-        {
-            AssertNoBuilder();
-
-            OnEmitCtorBodyOverride(constructorBuilder, ilBuilder);
-        }
-
-        protected virtual void OnEmitCtorBodyOverride(ConstructorBuilder constructorBuilder, ILGenerator ilBuilder)
-        {
-        }
-
-        public void DeclareDisassemblyDiagnoserLocals(ILGenerator ilBuilder)
-        {
-            AssertNoBuilder();
-
-            DeclareDisassemblyDiagnoserLocalsOverride(ilBuilder);
-        }
-
-        protected virtual void DeclareDisassemblyDiagnoserLocalsOverride(ILGenerator ilBuilder)
-        {
-        }
-
-        public void EmitDisassemblyDiagnoserReturnDefault(ILGenerator ilBuilder)
-        {
-            AssertNoBuilder();
-
-            EmitDisassemblyDiagnoserReturnDefaultOverride(ilBuilder);
-        }
-
-        protected virtual void EmitDisassemblyDiagnoserReturnDefaultOverride(ILGenerator ilBuilder)
-        {
-        }
-
-        public void BeginEmitAction(
-            MethodBuilder actionMethodBuilder,
-            ILGenerator ilBuilder,
-            MethodInfo actionInvokeMethod,
-            RunnableActionKind actionKind)
-        {
-            if (actionMethodBuilder.IsStatic)
-                throw new NotSupportedException($"The {actionMethodBuilder} method should be instance method.");
-
-            AssertNoBuilder();
-
-            IlBuilder = ilBuilder;
-            ActionMethodBuilder = actionMethodBuilder;
-            ActionInvokeMethod = actionInvokeMethod;
-            ActionKind = actionKind;
-
-            BeginEmitActionOverride(IlBuilder);
-        }
-
-        protected virtual void BeginEmitActionOverride(ILGenerator ilBuilder)
-        {
-        }
-
-        public void CompleteEmitAction(ILGenerator ilBuilder)
-        {
-            AssertHasBuilder(ilBuilder);
-
-            CompleteEmitActionOverride(ilBuilder);
-
-            IlBuilder = null;
-            ActionMethodBuilder = null;
-            ActionInvokeMethod = null;
-            ActionKind = null;
-        }
-
-        protected virtual void CompleteEmitActionOverride(ILGenerator ilBuilder)
-        {
-        }
-
-        public void DeclareActionLocals(ILGenerator ilBuilder)
-        {
-            AssertHasBuilder(ilBuilder);
-
-            DeclareActionLocalsOverride(ilBuilder);
-        }
-
-        protected virtual void DeclareActionLocalsOverride(ILGenerator ilBuilder)
-        {
-        }
-
-        public void EmitActionBeforeLoop(ILGenerator ilBuilder)
-        {
-            AssertHasBuilder(ilBuilder);
-
-            EmitActionBeforeLoopOverride(ilBuilder);
-        }
-
-        protected virtual void EmitActionBeforeLoopOverride(ILGenerator ilBuilder)
-        {
-        }
-
-        public void EmitActionAfterLoop(ILGenerator ilBuilder)
-        {
-            AssertHasBuilder(ilBuilder);
-
-            EmitActionAfterLoopOverride(ilBuilder);
-        }
-
-        protected virtual void EmitActionAfterLoopOverride(ILGenerator ilBuilder)
-        {
-        }
-
-        public void EmitActionBeforeCall(ILGenerator ilBuilder)
-        {
-            AssertHasBuilder(ilBuilder);
-
-            EmitActionBeforeCallOverride(ilBuilder);
-        }
-
-        protected virtual void EmitActionBeforeCallOverride(ILGenerator ilBuilder)
-        {
-        }
-
-        public void EmitActionAfterCall(ILGenerator ilBuilder)
-        {
-            AssertHasBuilder(ilBuilder);
-
-            EmitActionAfterCallOverride(ilBuilder);
-        }
-
-        protected virtual void EmitActionAfterCallOverride(ILGenerator ilBuilder)
-        {
-        }
-    }
-}
\ No newline at end of file
diff --git a/src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/Emitters/NonConsumableConsumeEmitter.cs b/src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/Emitters/NonConsumableConsumeEmitter.cs
deleted file mode 100644
index 4087165f3b..0000000000
--- a/src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/Emitters/NonConsumableConsumeEmitter.cs
+++ /dev/null
@@ -1,145 +0,0 @@
-using System;
-using System.Linq;
-using System.Reflection;
-using System.Reflection.Emit;
-using BenchmarkDotNet.Engines;
-using BenchmarkDotNet.Helpers.Reflection.Emit;
-using static BenchmarkDotNet.Toolchains.InProcess.Emit.Implementation.RunnableConstants;
-
-namespace BenchmarkDotNet.Toolchains.InProcess.Emit.Implementation
-{
-    internal class NonConsumableConsumeEmitter : ConsumeEmitter
-    {
-        private MethodInfo overheadKeepAliveWithoutBoxingMethod;
-        private MethodInfo nonGenericKeepAliveWithoutBoxingMethod;
-        private LocalBuilder resultLocal;
-        private LocalBuilder disassemblyDiagnoserLocal;
-
-        public NonConsumableConsumeEmitter(ConsumableTypeInfo consumableTypeInfo) : base(consumableTypeInfo)
-        {
-        }
-
-        protected override void OnEmitMembersOverride(TypeBuilder runnableBuilder)
-        {
-            overheadKeepAliveWithoutBoxingMethod = typeof(DeadCodeEliminationHelper).GetMethods()
-                .First(m => m.Name == nameof(DeadCodeEliminationHelper.KeepAliveWithoutBoxing)
-                    && !m.GetParameterTypes().First().IsByRef)
-                .MakeGenericMethod(ConsumableInfo.OverheadMethodReturnType);
-
-            // we must not simply use DeadCodeEliminationHelper.KeepAliveWithoutBoxing because it's generic method
-            // and stack-only types like Span can not be generic type arguments http://adamsitnik.com/Span/#span-must-not-be-a-generic-type-argument
-            nonGenericKeepAliveWithoutBoxingMethod = EmitNonGenericKeepAliveWithoutBoxing(
-                NonGenericKeepAliveWithoutBoxingMethodName,
-                runnableBuilder);
-        }
-
-        protected override void DeclareDisassemblyDiagnoserLocalsOverride(ILGenerator ilBuilder)
-        {
-            // optional local if default(T) uses .initobj
-            disassemblyDiagnoserLocal = ilBuilder.DeclareOptionalLocalForReturnDefault(ConsumableInfo.WorkloadMethodReturnType);
-        }
-
-        protected override void EmitDisassemblyDiagnoserReturnDefaultOverride(ILGenerator ilBuilder)
-        {
-            ilBuilder.EmitReturnDefault(ConsumableInfo.WorkloadMethodReturnType, disassemblyDiagnoserLocal);
-        }
-
-        private MethodBuilder EmitNonGenericKeepAliveWithoutBoxing(string methodName, TypeBuilder runnableBuilder)
-        {
-            /*
-                method private hidebysig
-                instance void NonGenericKeepAliveWithoutBoxing(
-                    valuetype BenchmarkDotNet.Samples.CustomStructNonConsumable _
-                ) cil managed noinlining
-             */
-            var valueArg = new EmitParameterInfo(
-                0,
-                DummyParamName,
-                ConsumableInfo.WorkloadMethodReturnType);
-            var methodBuilder = runnableBuilder.DefineNonVirtualInstanceMethod(
-                methodName,
-                MethodAttributes.Private,
-                EmitParameterInfo.CreateReturnVoidParameter(),
-                valueArg)
-                .SetNoInliningImplementationFlag();
-            valueArg.SetMember(methodBuilder);
-
-            var ilBuilder = methodBuilder.GetILGenerator();
-
-            /*
-                IL_0001: ret
-             */
-            ilBuilder.EmitVoidReturn(methodBuilder);
-
-            return methodBuilder;
-        }
-
-
-        protected override void DeclareActionLocalsOverride(ILGenerator ilBuilder)
-        {
-            /*
-                .locals init (
-                    [2] int32
-                )
-                -or-
-                .locals init (
-                    [2] valuetype BenchmarkDotNet.Samples.CustomStructNonConsumable,
-                )
-             */
-            if (ActionKind == RunnableActionKind.Overhead)
-                resultLocal = ilBuilder.DeclareLocal(ConsumableInfo.OverheadMethodReturnType);
-            else
-                resultLocal = ilBuilder.DeclareLocal(ConsumableInfo.WorkloadMethodReturnType);
-        }
-
-        /// Emits the action before loop override.
-        /// The il builder.
-        /// EmitActionKind - null
-        protected override void EmitActionBeforeLoopOverride(ILGenerator ilBuilder)
-        {
-            /*
-                // int value = 0;
-                IL_000e: ldc.i4.0
-                IL_000f: stloc.2
-                -or-
-                // CustomStructNonConsumable _ = default(CustomStructNonConsumable);
-                IL_000e: ldloca.s 2
-                IL_0010: initobj BenchmarkDotNet.Samples.CustomStructNonConsumable
-             */
-            ilBuilder.EmitSetLocalToDefault(resultLocal);
-        }
-
-        protected override void EmitActionAfterCallOverride(ILGenerator ilBuilder)
-        {
-            // IL_0022: stloc.2
-            ilBuilder.EmitStloc(resultLocal);
-        }
-
-        protected override void EmitActionAfterLoopOverride(ILGenerator ilBuilder)
-        {
-            /*
-                // DeadCodeEliminationHelper.KeepAliveWithoutBoxing(value);
-                IL_002c: ldloc.2
-                IL_002d: call void [BenchmarkDotNet]BenchmarkDotNet.Engines.DeadCodeEliminationHelper::KeepAliveWithoutBoxing(!!0)
-                -or-
-                // NonGenericKeepAliveWithoutBoxing(_);
-                IL_0032: ldarg.0
-                IL_0033: ldloc.2
-                IL_0034: call instance void BenchmarkDotNet.Autogenerated.Runnable_0::NonGenericKeepAliveWithoutBoxing(valuetype BenchmarkDotNet.Samples.CustomStructNonConsumable)
-             */
-            if (ActionKind == RunnableActionKind.Overhead)
-            {
-                ilBuilder.EmitStaticCall(overheadKeepAliveWithoutBoxingMethod, resultLocal);
-            }
-            else
-            {
-                ilBuilder.Emit(OpCodes.Ldarg_0);
-                ilBuilder.EmitInstanceCallThisValueOnStack(
-                    null,
-                    nonGenericKeepAliveWithoutBoxingMethod,
-                    new[] { resultLocal },
-                    forceDirectCall: true);
-            }
-        }
-    }
-}
\ No newline at end of file
diff --git a/src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/Emitters/RunnableEmitter.cs b/src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/Emitters/RunnableEmitter.cs
index 4796c84a77..39667c9a22 100644
--- a/src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/Emitters/RunnableEmitter.cs
+++ b/src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/Emitters/RunnableEmitter.cs
@@ -170,7 +170,7 @@ private static TypeBuilder DefineRunnableTypeBuilder(
             BenchmarkBuildInfo benchmark,
             ModuleBuilder moduleBuilder)
         {
-            // .class public auto ansi beforefieldinit BenchmarkDotNet.Autogenerated.Runnable_0
+            // .class public auto ansi sealed beforefieldinit BenchmarkDotNet.Autogenerated.Runnable_0
             //    extends [BenchmarkDotNet]BenchmarkDotNet.Samples.SampleBenchmark
             var benchmarkDescriptor = benchmark.BenchmarkCase.Descriptor;
 
@@ -184,7 +184,7 @@ private static TypeBuilder DefineRunnableTypeBuilder(
             }
             var result = moduleBuilder.DefineType(
                 GetRunnableTypeName(benchmark),
-                workloadTypeAttributes,
+                workloadTypeAttributes | TypeAttributes.Sealed,
                 workloadType);
 
             return result;
@@ -242,11 +242,8 @@ private static void EmitNoArgsMethodCallPopReturn(
         private int jobUnrollFactor;
         private int dummyUnrollFactor;
 
-        private Type overheadDelegateType;
-        private Type workloadDelegateType;
         private TypeBuilder runnableBuilder;
         private ConsumableTypeInfo consumableInfo;
-        private ConsumeEmitter consumeEmitter;
         private ConsumableTypeInfo globalSetupReturnInfo;
         private ConsumableTypeInfo globalCleanupReturnInfo;
         private ConsumableTypeInfo iterationSetupReturnInfo;
@@ -256,8 +253,6 @@ private static void EmitNoArgsMethodCallPopReturn(
         private FieldBuilder globalCleanupActionField;
         private FieldBuilder iterationSetupActionField;
         private FieldBuilder iterationCleanupActionField;
-        private FieldBuilder overheadDelegateField;
-        private FieldBuilder workloadDelegateField;
         private FieldBuilder notElevenField;
         private FieldBuilder dummyVarField;
 
@@ -267,7 +262,6 @@ private static void EmitNoArgsMethodCallPopReturn(
         private MethodBuilder dummy1Method;
         private MethodBuilder dummy2Method;
         private MethodBuilder dummy3Method;
-        private MethodInfo workloadImplementationMethod;
         private MethodBuilder overheadImplementationMethod;
         private MethodBuilder overheadActionUnrollMethod;
         private MethodBuilder overheadActionNoUnrollMethod;
@@ -316,16 +310,12 @@ private Type EmitRunnableCore(BenchmarkBuildInfo newBenchmark)
             dummy2Method = EmitDummyMethod(Dummy2MethodName, dummyUnrollFactor);
             dummy3Method = EmitDummyMethod(Dummy3MethodName, dummyUnrollFactor);
 
-            // 3. Emit impl
-            consumeEmitter.OnEmitMembers(runnableBuilder);
-
             // Overhead impl
             overheadImplementationMethod = EmitOverheadImplementation(OverheadImplementationMethodName);
             overheadActionUnrollMethod = EmitOverheadAction(OverheadActionUnrollMethodName, jobUnrollFactor);
             overheadActionNoUnrollMethod = EmitOverheadAction(OverheadActionNoUnrollMethodName, 1);
 
             // Workload impl
-            workloadImplementationMethod = EmitWorkloadImplementation(WorkloadImplementationMethodName);
             workloadActionUnrollMethod = EmitWorkloadAction(WorkloadActionUnrollMethodName, jobUnrollFactor);
             workloadActionNoUnrollMethod = EmitWorkloadAction(WorkloadActionNoUnrollMethodName, 1);
 
@@ -361,16 +351,13 @@ private void InitForEmitRunnable(BenchmarkBuildInfo newBenchmark)
             dummyUnrollFactor = DummyUnrollFactor;
 
             consumableInfo = new ConsumableTypeInfo(benchmark.BenchmarkCase.Descriptor.WorkloadMethod.ReturnType);
-            consumeEmitter = ConsumeEmitter.GetConsumeEmitter(consumableInfo);
             globalSetupReturnInfo = GetConsumableTypeInfo(benchmark.BenchmarkCase.Descriptor.GlobalSetupMethod?.ReturnType);
             globalCleanupReturnInfo = GetConsumableTypeInfo(benchmark.BenchmarkCase.Descriptor.GlobalCleanupMethod?.ReturnType);
             iterationSetupReturnInfo = GetConsumableTypeInfo(benchmark.BenchmarkCase.Descriptor.IterationSetupMethod?.ReturnType);
             iterationCleanupReturnInfo = GetConsumableTypeInfo(benchmark.BenchmarkCase.Descriptor.IterationCleanupMethod?.ReturnType);
 
-            // Init types
+            // Init type
             runnableBuilder = DefineRunnableTypeBuilder(benchmark, moduleBuilder);
-            overheadDelegateType = EmitOverheadDelegateType();
-            workloadDelegateType = EmitWorkloadDelegateType();
         }
 
         private static ConsumableTypeInfo GetConsumableTypeInfo(Type methodReturnType)
@@ -378,52 +365,6 @@ private static ConsumableTypeInfo GetConsumableTypeInfo(Type methodReturnType)
             return methodReturnType == null ? null : new ConsumableTypeInfo(methodReturnType);
         }
 
-        private Type EmitOverheadDelegateType()
-        {
-            // .class public auto ansi sealed BenchmarkDotNet.Autogenerated.Runnable_0OverheadDelegate
-            //    extends[mscorlib]System.MulticastDelegate;
-            var overheadReturnType = EmitParameterInfo.CreateReturnParameter(consumableInfo.OverheadMethodReturnType);
-
-            // replace arg names
-            var overheadParameters = Descriptor.WorkloadMethod.GetParameters()
-                .Select(p =>
-                    (ParameterInfo)new EmitParameterInfo(
-                        p.Position,
-                        ArgParamPrefix + p.Position,
-                        p.ParameterType,
-                        p.Attributes,
-                        null))
-                .ToArray();
-
-            return moduleBuilder.EmitCustomDelegate(
-                GetRunnableTypeName(benchmark) + OverheadDelegateTypeSuffix,
-                overheadReturnType,
-                overheadParameters);
-        }
-
-        private Type EmitWorkloadDelegateType()
-        {
-            // .class public auto ansi sealed BenchmarkDotNet.Autogenerated.Runnable_0WorkloadDelegate
-            //    extends [mscorlib]System.MulticastDelegate
-            var workloadReturnType = EmitParameterInfo.CreateReturnParameter(consumableInfo.WorkloadMethodReturnType);
-
-            // Replace arg names
-            var workloadParameters = Descriptor.WorkloadMethod.GetParameters()
-                .Select(p =>
-                    (ParameterInfo)new EmitParameterInfo(
-                        p.Position,
-                        ArgParamPrefix + p.Position,
-                        p.ParameterType,
-                        p.Attributes,
-                        null))
-                .ToArray();
-
-            return moduleBuilder.EmitCustomDelegate(
-                GetRunnableTypeName(benchmark) + WorkloadDelegateTypeSuffix,
-                workloadReturnType,
-                workloadParameters);
-        }
-
         private void DefineFields()
         {
             globalSetupActionField =
@@ -434,10 +375,6 @@ private void DefineFields()
                 runnableBuilder.DefineField(IterationSetupActionFieldName, typeof(Action), FieldAttributes.Private);
             iterationCleanupActionField =
                 runnableBuilder.DefineField(IterationCleanupActionFieldName, typeof(Action), FieldAttributes.Private);
-            overheadDelegateField =
-                runnableBuilder.DefineField(OverheadDelegateFieldName, overheadDelegateType, FieldAttributes.Private);
-            workloadDelegateField =
-                runnableBuilder.DefineField(WorkloadDelegateFieldName, workloadDelegateType, FieldAttributes.Private);
 
             // Define arg fields
             foreach (var parameter in Descriptor.WorkloadMethod.GetParameters())
@@ -485,7 +422,6 @@ private void DefineFields()
 
             notElevenField = runnableBuilder.DefineField(NotElevenFieldName, typeof(int), FieldAttributes.Public);
             dummyVarField = runnableBuilder.DefineField(DummyVarFieldName, typeof(int), FieldAttributes.Private);
-            consumeEmitter.OnDefineFields(runnableBuilder);
         }
 
         private ConstructorBuilder DefineCtor()
@@ -553,166 +489,117 @@ private MethodBuilder EmitDummyMethod(string methodName, int unrollFactor)
 
         private MethodBuilder EmitOverheadImplementation(string methodName)
         {
-            var overheadInvokeMethod = TypeBuilderExtensions.GetDelegateInvokeMethod(overheadDelegateType);
-
             //.method private hidebysig
-            //    instance int32 __Overhead(int64 arg0) cil managed
+            //    instance void __Overhead(int64 arg0) cil managed
+
+            // Replace arg names
+            var parameters = Descriptor.WorkloadMethod.GetParameters()
+                .Select(p =>
+                    (ParameterInfo) new EmitParameterInfo(
+                        p.Position,
+                        ArgParamPrefix + p.Position,
+                        p.ParameterType,
+                        p.Attributes,
+                        null))
+                .ToArray();
+
             var methodBuilder = runnableBuilder.DefineNonVirtualInstanceMethod(
                 methodName,
                 MethodAttributes.Private,
-                overheadInvokeMethod.ReturnParameter,
-                overheadInvokeMethod.GetParameters());
+                EmitParameterInfo.CreateReturnVoidParameter(),
+                parameters)
+                .SetNoInliningImplementationFlag();
 
             var ilBuilder = methodBuilder.GetILGenerator();
-            var returnType = methodBuilder.ReturnType;
-
             /*
-                // return default;
-                IL_0000: ldc.i4.0
+                // return;
                 IL_0001: ret
              */
-            // optional local if default(T) uses .initobj
-            var optionalLocalForInitobj = ilBuilder.DeclareOptionalLocalForReturnDefault(returnType);
-            ilBuilder.EmitReturnDefault(returnType, optionalLocalForInitobj);
+            ilBuilder.EmitVoidReturn(methodBuilder);
 
             return methodBuilder;
         }
 
-        private MethodInfo EmitWorkloadImplementation(string methodName)
-        {
-            // Shortcut: DO NOT emit method if the result type is not awaitable
-            if (!consumableInfo.IsAwaitable)
-                return Descriptor.WorkloadMethod;
-
-            var workloadInvokeMethod = TypeBuilderExtensions.GetDelegateInvokeMethod(workloadDelegateType);
-
-            //.method private hidebysig
-            //   instance int32 __Workload(int64 arg0) cil managed
-            var args = workloadInvokeMethod.GetParameters();
-            var methodBuilder = runnableBuilder.DefineNonVirtualInstanceMethod(
-                methodName,
-                MethodAttributes.Private,
-                workloadInvokeMethod.ReturnParameter,
-                args);
-            args = methodBuilder.GetEmitParameters(args);
-
-            var ilBuilder = methodBuilder.GetILGenerator();
-
-            /*
-                IL_0026: ldarg.0
-                IL_0027: ldloc.0
-                IL_0028: ldloc.1
-                IL_0029: ldloc.2
-                IL_002a: ldloc.3
-                IL_002b: call instance class [System.Private.CoreLib]System.Threading.Tasks.Task`1