Skip to content

Commit acf1789

Browse files
Copilotdadhi
andauthored
Refine FE child reuse reservation metadata
Agent-Logs-Url: https://github.com/dadhi/FastExpressionCompiler/sessions/628c76ba-460c-4a8d-b880-585db5217f72 Co-authored-by: dadhi <39516+dadhi@users.noreply.github.com>
1 parent f1fdc0e commit acf1789

1 file changed

Lines changed: 18 additions & 7 deletions

File tree

src/FastExpressionCompiler.LightExpression/FlatExpression.cs

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ public struct ExprNode
6161
private const int CountShift = 16;
6262
private const ulong IndexMask = 0xFFFF;
6363
private const ulong KindMask = 0x0F;
64+
private const byte NextReservedFlag = 0x4;
6465
private const byte NextPointsParentFlag = 0x8;
6566
private const ulong TagMask = 0xFFUL << TagShift;
6667
private const ulong NextMask = IndexMask << NextShift;
@@ -93,7 +94,7 @@ public struct ExprNode
9394

9495
internal bool IsParentLink => (Flags & NextPointsParentFlag) != 0;
9596

96-
internal bool HasNextLink => (_data & NextMask) != 0 || IsParentLink;
97+
internal bool HasNextLink => (_data & NextMask) != 0 || (Flags & (NextPointsParentFlag | NextReservedFlag)) != 0;
9798

9899
/// <summary>Gets the number of direct children linked from this node.</summary>
99100
public int ChildCount => (int)((_data >> CountShift) & IndexMask);
@@ -117,16 +118,14 @@ internal ExprNode(Type type, object obj, ExpressionType nodeType, ExprNodeKind k
117118
internal void SetNextSiblingIdx(int nextIdx)
118119
{
119120
_data = (_data & KeepWithoutNextMask) | ((ulong)(ushort)nextIdx << NextShift);
120-
if (IsParentLink)
121-
SetFlags((byte)(Flags & ~NextPointsParentFlag));
121+
SetFlags((byte)(Flags & ~(NextPointsParentFlag | NextReservedFlag)));
122122
}
123123

124124
[MethodImpl(MethodImplOptions.AggressiveInlining)]
125125
internal void SetParentIdx(int parentIdx)
126126
{
127127
_data = (_data & KeepWithoutNextMask) | ((ulong)(ushort)parentIdx << NextShift);
128-
if (!IsParentLink)
129-
SetFlags((byte)(Flags | NextPointsParentFlag));
128+
SetFlags((byte)((Flags | NextPointsParentFlag) & ~NextReservedFlag));
130129
}
131130

132131
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -145,7 +144,10 @@ internal bool IsExpression() =>
145144
[MethodImpl(MethodImplOptions.AggressiveInlining)]
146145
internal bool HasFlag(byte flag) => (Flags & flag) != 0;
147146

148-
internal byte CopyableFlags => (byte)(Flags & ~NextPointsParentFlag);
147+
internal byte CopyableFlags => (byte)(Flags & ~(NextPointsParentFlag | NextReservedFlag));
148+
149+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
150+
internal void ReserveAsLinked() => SetFlags((byte)(Flags | NextReservedFlag));
149151

150152
[MethodImpl(MethodImplOptions.AggressiveInlining)]
151153
private void SetFlags(byte flags)
@@ -1305,10 +1307,19 @@ private int CloneChild(int index)
13051307
if (node.HasNextLink)
13061308
return AddNodeReference(index);
13071309

1308-
node.SetParentIdx(index); // reserve first use so repeated child arguments in the same parent become references
1310+
ReserveChildLinkForReuse(ref node);
13091311
return index;
13101312
}
13111313

1314+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
1315+
private static void ReserveChildLinkForReuse(ref ExprNode node)
1316+
{
1317+
// Mark the node as "already linked" before wiring siblings/parent on the enclosing AddNode call.
1318+
// This ensures that repeated use of the same index in a single parent (e.g. Add(x, x))
1319+
// keeps the first occurrence in-place and emits a reference node for later occurrences.
1320+
node.ReserveAsLinked();
1321+
}
1322+
13121323
private ChildList CloneChildren(int[] children)
13131324
{
13141325
ChildList cloned = default;

0 commit comments

Comments
 (0)