Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update InProcessNoEmitToolchain #2315

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions src/BenchmarkDotNet/Extensions/ReflectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -185,9 +185,7 @@ internal static bool IsStackOnlyWithImplicitCast(this Type argumentType, object?
if (argumentInstance == null)
return false;

// IsByRefLikeAttribute is not exposed for older runtimes, so we need to check it in an ugly way ;)
bool isByRefLike = argumentType.GetCustomAttributes().Any(attribute => attribute.ToString()?.Contains("IsByRefLike") ?? false);
if (!isByRefLike)
if (!argumentType.IsByRefLike())
return false;

var instanceType = argumentInstance.GetType();
Expand All @@ -209,5 +207,9 @@ private static bool IsRunnableGenericType(TypeInfo typeInfo)
&& typeInfo.DeclaredConstructors.Any(ctor => ctor.IsPublic && ctor.GetParameters().Length == 0); // we need public parameterless ctor to create it

internal static bool IsLinqPad(this Assembly assembly) => assembly.FullName.IndexOf("LINQPAD", StringComparison.OrdinalIgnoreCase) >= 0;

internal static bool IsByRefLike(this Type type)
// Type.IsByRefLike is not available in netstandard2.0.
=> type.IsValueType && type.CustomAttributes.Any(attr => attr.AttributeType.FullName == "System.Runtime.CompilerServices.IsByRefLikeAttribute");
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
using System;

using JetBrains.Annotations;

namespace BenchmarkDotNet.Toolchains.InProcess.NoEmit
{
/// <summary>Common API to run the Setup/Clean/Idle/Run methods</summary>
[PublicAPI]
public abstract class BenchmarkAction
{
/// <summary>Gets or sets invoke single callback.</summary>
Expand All @@ -16,8 +13,7 @@ public abstract class BenchmarkAction
/// <value>Invoke multiple times callback.</value>
public Action<long> InvokeMultiple { get; protected set; }

/// <summary>Gets the last run result.</summary>
/// <value>The last run result.</value>
public virtual object LastRunResult => null;
[Obsolete("The result is no longer stored past the iteration.", true)]
public object LastRunResult => null;
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
using System;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;

using BenchmarkDotNet.Extensions;
using BenchmarkDotNet.Running;

using JetBrains.Annotations;

namespace BenchmarkDotNet.Toolchains.InProcess.NoEmit
{
/// <summary>Helper class that creates <see cref="BenchmarkAction"/> instances. </summary>
Expand All @@ -29,9 +28,40 @@ private static BenchmarkAction CreateCore(
if (resultType == typeof(void))
return new BenchmarkActionVoid(resultInstance, targetMethod, unrollFactor);

if (resultType == typeof(void*))
return new BenchmarkActionVoidPointer(resultInstance, targetMethod, unrollFactor);

if (resultType.IsPointer)
return Create(
typeof(BenchmarkActionPointer<>).MakeGenericType(resultType.GetElementType()),
resultInstance,
targetMethod,
unrollFactor);

if (resultType.IsByRef)
{
var returnParameter = targetMethod?.ReturnParameter ?? fallbackIdleSignature.ReturnParameter;
// System.Runtime.CompilerServices.IsReadOnlyAttribute is part of .NET Standard 2.1, we can't use it here..
if (returnParameter.GetCustomAttributes().Any(attribute => attribute.GetType().Name == "IsReadOnlyAttribute"))
return Create(
typeof(BenchmarkActionByRefReadonly<>).MakeGenericType(resultType.GetElementType()),
resultInstance,
targetMethod,
unrollFactor);

return Create(
typeof(BenchmarkActionByRef<>).MakeGenericType(resultType.GetElementType()),
resultInstance,
targetMethod,
unrollFactor);
}

if (resultType == typeof(Task))
return new BenchmarkActionTask(resultInstance, targetMethod, unrollFactor);

if (resultType == typeof(ValueTask))
return new BenchmarkActionValueTask(resultInstance, targetMethod, unrollFactor);

if (resultType.GetTypeInfo().IsGenericType)
{
var genericType = resultType.GetGenericTypeDefinition();
Expand All @@ -51,10 +81,6 @@ private static BenchmarkAction CreateCore(
unrollFactor);
}

if (targetMethod == null && resultType.GetTypeInfo().IsValueType)
// for Idle: we return int because creating bigger ValueType could take longer than benchmarked method itself.
resultType = typeof(int);

return Create(
typeof(BenchmarkAction<>).MakeGenericType(resultType),
resultInstance,
Expand Down Expand Up @@ -88,6 +114,10 @@ private static void PrepareInstanceAndResultType(
if (isUsingAsyncKeyword)
throw new NotSupportedException("Async void is not supported by design.");
}
else if (resultType.IsByRefLike() || resultType.GetElementType()?.IsByRefLike() == true)
{
throw new NotSupportedException("InProcessNoEmitToolchain does not support consuming ByRefLike return types.");
}
}

/// <summary>Helper to enforce .ctor signature.</summary>
Expand Down
Loading