-
-
Notifications
You must be signed in to change notification settings - Fork 990
/
Copy pathDeclarationsProvider.cs
163 lines (115 loc) · 6.72 KB
/
DeclarationsProvider.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
using System;
using System.Reflection;
using System.Threading.Tasks;
using BenchmarkDotNet.Engines;
using BenchmarkDotNet.Extensions;
using BenchmarkDotNet.Helpers;
using BenchmarkDotNet.Running;
namespace BenchmarkDotNet.Code
{
internal abstract class DeclarationsProvider
{
protected readonly Descriptor Descriptor;
internal DeclarationsProvider(Descriptor descriptor) => Descriptor = descriptor;
public string OperationsPerInvoke => Descriptor.OperationsPerInvoke.ToString();
public string WorkloadTypeName => Descriptor.Type.GetCorrectCSharpTypeName();
public string GlobalSetupMethodName => GetMethodName(Descriptor.GlobalSetupMethod);
public string GlobalCleanupMethodName => GetMethodName(Descriptor.GlobalCleanupMethod);
public string IterationSetupMethodName => GetMethodName(Descriptor.IterationSetupMethod);
public string IterationCleanupMethodName => GetMethodName(Descriptor.IterationCleanupMethod);
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 virtual string AwaiterTypeName => string.Empty;
public virtual void OverrideUnrollFactor(BenchmarkCase benchmarkCase) { }
public abstract string OverheadImplementation { get; }
private string GetMethodName(MethodInfo method)
{
// "Setup" or "Cleanup" methods are optional, so default to a simple delegate, so there is always something that can be invoked
if (method == null)
{
return "() => new System.Threading.Tasks.ValueTask()";
}
if (method.ReturnType == typeof(Task) ||
method.ReturnType == typeof(ValueTask) ||
(method.ReturnType.IsGenericType &&
(method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>) ||
method.ReturnType.GetGenericTypeDefinition() == typeof(ValueTask<>))))
{
return $"() => BenchmarkDotNet.Helpers.AwaitHelper.ToValueTaskVoid({method.Name}())";
}
return $"() => {{ {method.Name}(); return new System.Threading.Tasks.ValueTask(); }}";
}
}
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
{
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";
}
internal class ByReadOnlyRefDeclarationsProvider : ByRefDeclarationsProvider
{
public ByReadOnlyRefDeclarationsProvider(Descriptor descriptor) : base(descriptor) { }
public override string ReturnsDefinition => "RETURNS_BYREF_READONLY";
public override string WorkloadMethodReturnTypeModifiers => "ref readonly";
}
internal class TaskDeclarationsProvider : DeclarationsProvider
{
public TaskDeclarationsProvider(Descriptor descriptor) : base(descriptor) { }
public override string ReturnsDefinition => "RETURNS_AWAITABLE";
public override string AwaiterTypeName => WorkloadMethodReturnType.GetMethod(nameof(Task.GetAwaiter), BindingFlags.Public | BindingFlags.Instance).ReturnType.GetCorrectCSharpTypeName();
public override string OverheadImplementation => $"return default({OverheadMethodReturnType.GetCorrectCSharpTypeName()});";
protected override Type OverheadMethodReturnType => WorkloadMethodReturnType;
public override void OverrideUnrollFactor(BenchmarkCase benchmarkCase) => benchmarkCase.ForceUnrollFactorForAsync();
}
}