Skip to content

Commit def9eb9

Browse files
Copilotdadhi
andauthored
Fix net472 throw helpers and restore closure constant policy
Agent-Logs-Url: https://github.com/dadhi/FastExpressionCompiler/sessions/e4fd589e-da46-45a0-877b-94c254d85cd8 Co-authored-by: dadhi <39516+dadhi@users.noreply.github.com>
1 parent c64ab98 commit def9eb9

2 files changed

Lines changed: 24 additions & 12 deletions

File tree

src/FastExpressionCompiler.LightExpression/FlatExpression.cs

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ internal bool ShouldCloneWhenLinked() =>
152152
/// <summary>Stores an expression tree as a flat node array plus out-of-line closure constants.</summary>
153153
public struct ExprTree
154154
{
155+
private static readonly object ClosureConstantMarker = new();
155156
internal const byte ParameterByRefFlag = 1;
156157
internal const byte ParameterDeclarationFlag = 2;
157158
private const byte ConstantInlineValue32Flag = 1;
@@ -201,6 +202,12 @@ public int Constant(object value, Type type)
201202
if (TryGetInlineConstantValue32(value, type, out var value32))
202203
return AddRawInlineConstantNode(type, value32);
203204

205+
if (ShouldStoreConstantInClosureConstants(value, type))
206+
{
207+
var constantIndex = ClosureConstants.Add(value);
208+
return AddRawExpressionNodeWithChildIndex(type, ClosureConstantMarker, ExpressionType.Constant, constantIndex);
209+
}
210+
204211
return AddRawExpressionNode(type, value, ExpressionType.Constant);
205212
}
206213

@@ -997,6 +1004,12 @@ private int AddConstant(System.Linq.Expressions.ConstantExpression constant)
9971004
if (TryGetInlineConstantValue32(constant.Value, constant.Type, out var value32))
9981005
return _tree.AddRawInlineConstantNode(constant.Type, value32);
9991006

1007+
if (ShouldStoreConstantInClosureConstants(constant.Value, constant.Type))
1008+
{
1009+
var constantIndex = _tree.ClosureConstants.Add(constant.Value);
1010+
return _tree.AddRawExpressionNodeWithChildIndex(constant.Type, ClosureConstantMarker, constant.NodeType, constantIndex);
1011+
}
1012+
10001013
return _tree.AddRawExpressionNode(constant.Type, constant.Value, constant.NodeType);
10011014
}
10021015

@@ -1307,6 +1320,10 @@ private static bool TryGetInlineConstantValue32(object value, Type type, out int
13071320
}
13081321
}
13091322

1323+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
1324+
private static bool ShouldStoreConstantInClosureConstants(object value, Type type) =>
1325+
value != null && value is not string && value is not Type && !type.IsEnum && Type.GetTypeCode(type) == TypeCode.Object;
1326+
13101327
private static object ReadInlineConstantValue32(Type type, int value32)
13111328
{
13121329
if (type.IsEnum)
@@ -1438,7 +1455,9 @@ public SysExpr ReadExpression(int index)
14381455
return SysExpr.Constant(
14391456
node.HasFlag(ConstantInlineValue32Flag)
14401457
? ReadInlineConstantValue32(node.Type, node.Value32)
1441-
: node.Obj,
1458+
: ReferenceEquals(node.Obj, ClosureConstantMarker)
1459+
? _tree.ClosureConstants[node.ChildIdx]
1460+
: node.Obj,
14421461
node.Type);
14431462
case ExpressionType.Default:
14441463
return SysExpr.Default(node.Type);
@@ -1790,44 +1809,36 @@ private SysExpr[] ReadExpressions(in ChildList childIndexes)
17901809

17911810
internal static class Throw
17921811
{
1793-
[DoesNotReturn]
17941812
public static void DuplicateParameterDeclaration(string name) =>
17951813
throw new ArgumentException($"The parameter or variable `{name ?? "?"}` is declared more than once.");
17961814

1797-
[DoesNotReturn]
17981815
public static void ParameterDeclarationExpected(int index) =>
17991816
throw new ArgumentException($"Expected a parameter declaration node at index {index}.");
18001817

1801-
[DoesNotReturn]
18021818
public static void UndeclaredParameterUsage(string name) =>
18031819
throw new InvalidOperationException($"The parameter or variable `{name ?? "?"}` is used before it is declared.");
18041820

1805-
[DoesNotReturn]
18061821
public static void UnsupportedInlineConstantType(Type type) =>
18071822
throw new NotSupportedException($"Inline 32-bit constant storage does not support `{type}`.");
18081823

1809-
[DoesNotReturn]
18101824
public static T DuplicateParameterDeclaration<T>(string name)
18111825
{
18121826
DuplicateParameterDeclaration(name);
18131827
return default;
18141828
}
18151829

1816-
[DoesNotReturn]
18171830
public static T ParameterDeclarationExpected<T>(int index)
18181831
{
18191832
ParameterDeclarationExpected(index);
18201833
return default;
18211834
}
18221835

1823-
[DoesNotReturn]
18241836
public static T UndeclaredParameterUsage<T>(string name)
18251837
{
18261838
UndeclaredParameterUsage(name);
18271839
return default;
18281840
}
18291841

1830-
[DoesNotReturn]
18311842
public static T UnsupportedInlineConstantType<T>(Type type)
18321843
{
18331844
UnsupportedInlineConstantType(type);

test/FastExpressionCompiler.LightExpression.UnitTests/LightExpressionTests.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public int Run()
2929
Expression_produced_by_ToExpressionString_should_compile();
3030
Multiple_methods_in_block_should_be_aligned_when_output_to_csharp();
3131
Can_roundtrip_light_expression_through_flat_expression();
32-
Flat_expression_preserves_parameter_and_label_identity_without_closure_constant_storage();
32+
Flat_expression_preserves_parameter_and_label_identity_and_collects_closure_constants();
3333
Flat_expression_uses_parameter_declarations_parent_links_and_inline_constants();
3434
Can_convert_dynamic_runtime_variables_and_debug_info_to_light_expression_and_flat_expression();
3535
Can_build_flat_expression_directly_with_light_expression_like_api();
@@ -390,14 +390,15 @@ public void Can_roundtrip_light_expression_through_flat_expression()
390390
Asserts.AreEqual(2, a.Dop.Count());
391391
}
392392

393-
public void Flat_expression_preserves_parameter_and_label_identity_without_closure_constant_storage()
393+
public void Flat_expression_preserves_parameter_and_label_identity_and_collects_closure_constants()
394394
{
395395
var valueHolder = new S();
396396
var valueField = typeof(S).GetField(nameof(S.Value));
397397
var constExpr = Lambda<Func<string>>(Field(Constant(valueHolder), valueField));
398398
var constFlat = constExpr.ToFlatExpression();
399399

400-
Asserts.AreEqual(0, constFlat.ClosureConstants.Count);
400+
Asserts.AreEqual(1, constFlat.ClosureConstants.Count);
401+
Asserts.AreSame(valueHolder, constFlat.ClosureConstants[0]);
401402
Asserts.AreEqual(null, ((LambdaExpression)constFlat.ToLightExpression()).CompileFast<Func<string>>(true)());
402403

403404
var p = SysExpr.Parameter(typeof(int), "p");

0 commit comments

Comments
 (0)