Skip to content

Commit 3709747

Browse files
committed
IL emit match behavior of FieldsContainer conditional emit.
1 parent 5524feb commit 3709747

2 files changed

Lines changed: 63 additions & 56 deletions

File tree

src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/Emitters/AsyncCoreEmitter.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ private sealed class AsyncCoreEmitter(BuildPartition buildPartition, ModuleBuild
2424
private FieldInfo clockField = null!;
2525
private FieldInfo invokeCountField = null!;
2626

27+
protected override int GetExtraFieldsCount() => 3;
28+
2729
protected override void EmitExtraFields(TypeBuilder fieldsContainerBuilder)
2830
{
2931
base.EmitExtraFields(fieldsContainerBuilder);

src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/Emitters/RunnableEmitter.cs

Lines changed: 61 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -258,72 +258,77 @@ private void EmitRunnableCore()
258258

259259
private void EmitFields()
260260
{
261-
/*
262-
private unsafe struct FieldsContainer
263-
{
264-
}
265-
*/
266-
var fieldsContainerBuilder = runnableBuilder.DefineNestedType(
267-
"FieldsContainer",
268-
TypeAttributes.NestedPrivate | TypeAttributes.AutoLayout | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit,
269-
typeof(ValueType));
270-
nestedTypeBuilders.Add(fieldsContainerBuilder);
271-
272-
// Define arg fields
273-
foreach (var parameter in Descriptor.WorkloadMethod.GetParameters())
261+
var parameters = Descriptor.WorkloadMethod.GetParameters();
262+
if (parameters.Length + GetExtraFieldsCount() > 0)
274263
{
275-
var argValue = benchmark.BenchmarkCase.Parameters.GetArgument(parameter.Name!);
276-
var parameterType = parameter.ParameterType;
277-
278-
Type argLocalsType;
279-
Type argFieldType;
280-
MethodInfo? opConversion = null;
281-
if (parameterType.IsByRef)
282-
{
283-
argLocalsType = parameterType;
284-
argFieldType = argLocalsType.GetElementType()
285-
?? throw new InvalidOperationException($"Bug: cannot get field type from {argLocalsType}");
286-
}
287-
else if (parameterType.IsByRefLike() && argValue.Value != null)
288-
{
289-
argLocalsType = parameterType;
290-
291-
// Use conversion on load; store passed value
292-
var passedArgType = argValue.Value.GetType();
293-
opConversion = GetImplicitConversionOpFromTo(passedArgType, argLocalsType) ??
294-
throw new InvalidOperationException($"Bug: No conversion from {passedArgType} to {argLocalsType}.");
295-
argFieldType = passedArgType;
296-
}
297-
else
264+
/*
265+
private unsafe struct FieldsContainer
266+
{
267+
}
268+
*/
269+
var fieldsContainerBuilder = runnableBuilder.DefineNestedType(
270+
"FieldsContainer",
271+
TypeAttributes.NestedPrivate | TypeAttributes.AutoLayout | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit,
272+
typeof(ValueType));
273+
nestedTypeBuilders.Add(fieldsContainerBuilder);
274+
275+
// Define arg fields
276+
foreach (var parameter in parameters)
298277
{
299-
// No conversion; load ref to arg field;
300-
argLocalsType = parameterType;
301-
argFieldType = parameterType;
278+
var argValue = benchmark.BenchmarkCase.Parameters.GetArgument(parameter.Name!);
279+
var parameterType = parameter.ParameterType;
280+
281+
Type argLocalsType;
282+
Type argFieldType;
283+
MethodInfo? opConversion = null;
284+
if (parameterType.IsByRef)
285+
{
286+
argLocalsType = parameterType;
287+
argFieldType = argLocalsType.GetElementType()
288+
?? throw new InvalidOperationException($"Bug: cannot get field type from {argLocalsType}");
289+
}
290+
else if (parameterType.IsByRefLike() && argValue.Value != null)
291+
{
292+
argLocalsType = parameterType;
293+
294+
// Use conversion on load; store passed value
295+
var passedArgType = argValue.Value.GetType();
296+
opConversion = GetImplicitConversionOpFromTo(passedArgType, argLocalsType)
297+
?? throw new InvalidOperationException($"Bug: No conversion from {passedArgType} to {argLocalsType}.");
298+
argFieldType = passedArgType;
299+
}
300+
else
301+
{
302+
// No conversion; load ref to arg field;
303+
argLocalsType = parameterType;
304+
argFieldType = parameterType;
305+
}
306+
307+
if (argFieldType.IsByRefLike())
308+
throw new NotSupportedException($"Passing ref readonly structs by ref is not supported (cannot store {argFieldType} as a class field).");
309+
310+
var argField = fieldsContainerBuilder.DefineField(
311+
ArgFieldPrefix + parameter.Position,
312+
argFieldType,
313+
FieldAttributes.Public);
314+
315+
argFields.Add(new(argField, argLocalsType, opConversion));
302316
}
303317

304-
if (argFieldType.IsByRefLike())
305-
throw new NotSupportedException(
306-
$"Passing ref readonly structs by ref is not supported (cannot store {argFieldType} as a class field).");
318+
EmitExtraFields(fieldsContainerBuilder);
307319

308-
var argField = fieldsContainerBuilder.DefineField(
309-
ArgFieldPrefix + parameter.Position,
310-
argFieldType,
311-
FieldAttributes.Public);
312-
313-
argFields.Add(new(argField, argLocalsType, opConversion));
320+
// private FieldsContainer __fieldsContainer;
321+
fieldsContainerField = runnableBuilder.DefineField(
322+
FieldsContainerName,
323+
fieldsContainerBuilder,
324+
FieldAttributes.Private);
314325
}
315326

316-
EmitExtraFields(fieldsContainerBuilder);
317-
318-
// private FieldsContainer __fieldsContainer;
319-
fieldsContainerField = runnableBuilder.DefineField(
320-
FieldsContainerName,
321-
fieldsContainerBuilder,
322-
FieldAttributes.Private);
323-
324327
notElevenField = runnableBuilder.DefineField(NotElevenFieldName, typeof(int), FieldAttributes.Public);
325328
}
326329

330+
protected virtual int GetExtraFieldsCount() => 0;
331+
327332
protected virtual void EmitExtraFields(TypeBuilder fieldsContainerBuilder) { }
328333

329334
private void EmitCtor()

0 commit comments

Comments
 (0)