-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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
Handling byref-like types in LINQ expression interpreter #96160
Comments
Tagging subscribers to this area: @cston Issue DetailsDescriptionWhen upgraded an existing application that uses C# expression tree and AOT to use dotnet 8 some unit tests failed. After some investigation and few tests with expression tree in apart console application and got the same error using the following code: seems the problems only happens if the parameter of the function is a Reproduction StepsIn a .NET 8 app with Native AOT enabled ( using System;
using System.Linq.Expressions;
public class Program
{
delegate T Parse<T>(ReadOnlySpan<char> text);
private static Parse<T> ReturnDefault<T>()
{
var line = Expression.Parameter(typeof(ReadOnlySpan<char>), "span");
var result = Expression.Lambda<Parse<T>>(Expression.Default(typeof(T)), line);
return result.Compile();
}
public static void Main()
{
var func = ReturnDefault<(int age, bool isAlive, DateTime date)>();
var yy = func("foo bar");
Console.WriteLine(yy);
return;
}
} Expected behavioroutput Actual behavior
Regression?it works in net 7.0 + AOT Known WorkaroundsNo response ConfigurationNo response Other informationNo response
|
This can be reproduced without NativeAOT if you change |
This repro doesn't work in .NET 7 either:
I agree with @hez2010 - this looks like an expression interpreter bug. But it's likely the fix for this will be just to generate a better exception message (instead of trying to box a span and hope the runtime will not allow it). LINQ expressions on Native AOT run on top of an interpreter because it's fundamentally not possible to generate new code at runtime. If you're using expressions for perf, on native AOT you'd be better off using reflection. The expression interpreter uses reflection, but with extra steps. |
@MichalStrehovsky strange it doesnt work on your computer... I and @EvanMulawski could reproduce the code with success using dotnet 7 (calling my csproj:
|
@MichalStrehovsky @hez2010 I cant figure out why/where the span is being boxed. and, if it really is, why the code works when not using AOT since the runtime is the same for both? |
ExpressionTree without NAOT is using il emit to generate code for jitting at runtime dynamically thus the boxing can be avoided, but with NAOT it doesn't support runtime code generation so instead an interpreter is used and which is boxing the type. You may see the code path here: https://source.dot.net/#System.Linq.Expressions/System/Linq/Expressions/LambdaExpression.cs,137 where I'm not sure about if the boxing here can be avoided in the interpreter. |
@hez2010 since the code works (calling |
I don't think you're actually running the program with native AOT. The exception stack trace posted above is a JIT-based stack trace (you'll not see the
What is happening is:
The issue has always existed. You'll definitely see this repro with .NET 7 PublishAot once you actually publish the app with |
@MichalStrehovsky thank you for your detailed explanation! I was not aware of some things you said. If I understand correctly, the problem is: when my expression tree is going to be interpreted in AOT, the interpreter, which uses reflection, can not do it for
If my understanding is correctly, I can not use reflection directly neither, since root of the problem is the boxing done by reflection. What I think could solve the problem, is introduce new specific methods/APIs for reflection to handler |
Correct.
This reflection feature request is tracked by #10057. You can comment about your scenarios there. cc @steveharter The ref struct support for the expression tree interpreter would be a new major feature that conflicts with |
Wouldn't it be considered as a bug since it works with the ILEmit implementation but not the interpreter one? |
Yes, this specific issue is a bug that still requires major changes to fix. Support for new language/runtimes features like byref-like structs is generally non-existent in the expression interpreter (e.g. see #27499). |
I'd at least leave the bug open so that the area owners can consider adding a better failure mode ("But it's likely the fix for this will be just to generate a better exception message"). It is not the first time a new feature was added to the C# language without looking at how it behaves in this library (see e.g. #86629). Looks like we have a pattern here that the library owners (who also happen to be C# compiler devs) should look at. |
Description
When upgraded an existing application that uses C# expression tree and AOT to use dotnet 8 some unit tests failed. After some investigation and few tests with expression tree in apart console application I could reproduce the same error using the following code:
seems the problems only happens if the parameter of the function is a
ReadOnlySpan<char>
AND if building using dotnet 8. If I change any of these things (replace span by string or building using dotnet 7) everything work as expected.Reproduction Steps
In a .NET 8 app with Native AOT enabled (
<PublishAot>true</PublishAot>
) run the following code:Expected behavior
output
(0, False, 01/01/0001 00:00:00)
Actual behavior
Regression?
it works in net 7.0 + AOT
Known Workarounds
No response
Configuration
No response
Other information
No response
The text was updated successfully, but these errors were encountered: