Skip to content

Commit

Permalink
fixed: #320 and fixed the CompileFastToIL
Browse files Browse the repository at this point in the history
  • Loading branch information
dadhi committed Jan 31, 2022
1 parent 4f44384 commit e6b9498
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 27 deletions.
43 changes: 26 additions & 17 deletions src/FastExpressionCompiler/FastExpressionCompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -142,21 +142,30 @@ public static TDelegate CompileFast<TDelegate>(this LambdaExpression lambdaExpr,
#endif
lambdaExpr.ReturnType, flags) ?? (ifFastFailedReturnNull ? null : lambdaExpr.CompileSys()));

/// Compiles a static method to the passed IL Generator.
/// <summary>Compiles a static method to the passed IL Generator.
/// Could be used as alternative for `CompileToMethod` like this <code><![CDATA[funcExpr.CompileFastToIL(methodBuilder.GetILGenerator())]]></code>.
/// Check `IssueTests.Issue179_Add_something_like_LambdaExpression_CompileToMethod.cs` for example.
public static bool CompileFastToIL(this LambdaExpression lambdaExpr, ILGenerator il, bool ifFastFailedReturnNull = false,
CompilerFlags flags = CompilerFlags.Default)
/// Check `IssueTests.Issue179_Add_something_like_LambdaExpression_CompileToMethod.cs` for example.</summary>
public static bool CompileFastToIL(this LambdaExpression lambdaExpr, ILGenerator il, CompilerFlags flags = CompilerFlags.Default)
{
var closureInfo = new ClosureInfo(ClosureStatus.ShouldBeStaticMethod);
if ((flags & CompilerFlags.EnableDelegateDebugInfo) != 0)
throw new NotSupportedException("The `CompilerFlags.EnableDelegateDebugInfo` is not supported because the debug info is gathered into the closure object which is not allowed for static lambda to be compiled to method.");

if (!EmittingVisitor.TryEmit(lambdaExpr.Body,
#if LIGHT_EXPRESSION
lambdaExpr,
var paramExprs = lambdaExpr;
#else
lambdaExpr.Parameters,
var paramExprs = lambdaExpr.Parameters;
#endif
il, ref closureInfo, flags, lambdaExpr.ReturnType == typeof(void) ? ParentFlags.IgnoreResult : ParentFlags.Empty))
var bodyExpr = lambdaExpr.Body;

var closureInfo = new ClosureInfo(ClosureStatus.ShouldBeStaticMethod);
if (!TryCollectBoundConstants(ref closureInfo, bodyExpr, paramExprs, false, ref closureInfo, flags))
return false;

if ((closureInfo.Status & ClosureStatus.HasClosure) != 0)
return false;

var parent = lambdaExpr.ReturnType == typeof(void) ? ParentFlags.IgnoreResult : ParentFlags.Empty;
if (!EmittingVisitor.TryEmit(bodyExpr, paramExprs, il, ref closureInfo, flags, parent))
return false;

il.Emit(OpCodes.Ret);
Expand Down Expand Up @@ -3027,10 +3036,6 @@ private static bool TryEmitConstantOfNotNullValue(
return true;
}

// get raw enum type to light
if (constValueType.IsEnum)
constValueType = Enum.GetUnderlyingType(constValueType);

if (!TryEmitNumberConstant(il, constantValue, constValueType))
return false;
}
Expand All @@ -3049,10 +3054,18 @@ private static bool TryEmitConstantOfNotNullValue(
// todo: @perf can we do something about boxing?
private static bool TryEmitNumberConstant(ILGenerator il, object constantValue, Type constValueType)
{
if (constValueType.IsEnum)
constValueType = Enum.GetUnderlyingType(constValueType);

// more "commonly" used constants are higher in comparison
if (constValueType == typeof(int))
{
EmitLoadConstantInt(il, (int)constantValue);
}
else if (constValueType == typeof(bool))
{
il.Emit((bool)constantValue ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
}
else if (constValueType == typeof(char))
{
EmitLoadConstantInt(il, (char)constantValue);
Expand Down Expand Up @@ -3099,10 +3112,6 @@ private static bool TryEmitNumberConstant(ILGenerator il, object constantValue,
{
il.Emit(OpCodes.Ldc_R8, (double)constantValue);
}
else if (constValueType == typeof(bool))
{
il.Emit((bool)constantValue ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
}
else if (constValueType == typeof(IntPtr))
{
il.Emit(OpCodes.Ldc_I8, ((IntPtr)constantValue).ToInt64());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ public void Test()

var funcExpr = Lambda<Func<int, int, int>>(Add(paramA, paramB), paramA, paramB);

funcExpr.CompileFastToIL(methodBuilder.GetILGenerator(), true);
var success = funcExpr.CompileFastToIL(methodBuilder.GetILGenerator());
Assert.IsTrue(success);

var dynamicType = typeBuilder.CreateType();
var myAddMethod = dynamicType.GetTypeInfo().GetDeclaredMethod("MyAdd");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ public class Issue320_Bad_label_content_in_ILGenerator_when_creating_through_Dyn
{
public int Run()
{
Test_instance_call_without_ifthen();
Test_instance_call();
Test_instance_call_without_ifthen();
return 2;
}

//[Test] // todo: @fix
[Test]
public void Test_instance_call()
{
var expr = CreateExpression();
Expand Down Expand Up @@ -53,12 +53,11 @@ public void Test_instance_call()
GenerateAssemblyManually(expr);
}

//[Test]
[Test]
public void Test_instance_call_without_ifthen()
{
var expr = CreateNonIfThenExpression();


var f = expr.CompileFast(true);
Assert.IsNotNull(f);

Expand Down Expand Up @@ -91,8 +90,11 @@ class TestMethods

private Expression<Func<int>> CreateExpression()
{
var instance = new TestMethods(314);
var call = Expression.Call(Expression.Constant(instance), typeof(TestMethods).GetMethod("InstanceMethod")!);
// var instance = new TestMethods(314);
// var instanceExpr = Expression.Constant(instance);
var instanceExpr = Expression.New(typeof(TestMethods).GetConstructors()[0], Expression.Constant(314));

var call = Expression.Call(instanceExpr, typeof(TestMethods).GetMethod("InstanceMethod")!);

var localint = Expression.Variable(typeof(int), "ret");
var setlocaltocall = Expression.Assign(localint, call);
Expand All @@ -109,8 +111,11 @@ private Expression<Func<int>> CreateExpression()

private Expression<Func<int>> CreateNonIfThenExpression()
{
var instance = new TestMethods(8675309);
var call = Expression.Call(Expression.Constant(instance), typeof(TestMethods).GetMethod("InstanceMethod")!);
// var instance = new TestMethods(8675309);
// var instanceExpr = Expression.Constant(instance);
var instanceExpr = Expression.New(typeof(TestMethods).GetConstructors()[0], Expression.Constant(8675309));

var call = Expression.Call(instanceExpr, typeof(TestMethods).GetMethod("InstanceMethod")!);

var localint = Expression.Variable(typeof(int), "ret");
var setlocaltocall = Expression.Assign(localint, call);
Expand Down
3 changes: 3 additions & 0 deletions test/FastExpressionCompiler.TestsRunner.Net472/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,9 @@ void Run(Func<int> run, string name = null)
Run(new Issue314_LiftToNull_ToExpressionString().Run);
Run(new FastExpressionCompiler.LightExpression.IssueTests.Issue314_LiftToNull_ToExpressionString().Run);

Run(new Issue320_Bad_label_content_in_ILGenerator_when_creating_through_DynamicModule().Run);
Run(new FastExpressionCompiler.LightExpression.IssueTests.Issue320_Bad_label_content_in_ILGenerator_when_creating_through_DynamicModule().Run);

Run(new Issue321_Call_with_out_parameter_to_field_type_that_is_not_value_type_fails().Run);
Run(new FastExpressionCompiler.LightExpression.IssueTests.Issue321_Call_with_out_parameter_to_field_type_that_is_not_value_type_fails().Run);

Expand Down
5 changes: 4 additions & 1 deletion test/FastExpressionCompiler.TestsRunner/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public static void Main()
{
RunAllTests();

// new FastExpressionCompiler.LightExpression.IssueTests.Issue321_Call_with_out_parameter_to_field_type_that_is_not_value_type_fails().Run();
//new FastExpressionCompiler.LightExpression.IssueTests.Issue320_Bad_label_content_in_ILGenerator_when_creating_through_DynamicModule().Run();

// new Issue314_LiftToNull_ToExpressionString().Run();
// new FastExpressionCompiler.LightExpression.IssueTests.Issue314_LiftToNull_ToExpressionString().Run();
Expand Down Expand Up @@ -242,6 +242,9 @@ void Run(Func<int> run, string name = null)
Run(new Issue314_LiftToNull_ToExpressionString().Run);
Run(new FastExpressionCompiler.LightExpression.IssueTests.Issue314_LiftToNull_ToExpressionString().Run);

Run(new Issue320_Bad_label_content_in_ILGenerator_when_creating_through_DynamicModule().Run);
Run(new FastExpressionCompiler.LightExpression.IssueTests.Issue320_Bad_label_content_in_ILGenerator_when_creating_through_DynamicModule().Run);

Run(new Issue321_Call_with_out_parameter_to_field_type_that_is_not_value_type_fails().Run);
Run(new FastExpressionCompiler.LightExpression.IssueTests.Issue321_Call_with_out_parameter_to_field_type_that_is_not_value_type_fails().Run);

Expand Down

0 comments on commit e6b9498

Please sign in to comment.