@@ -101,31 +101,46 @@ public struct ExprNode
101101 /// <summary>Gets the first child idx or an auxiliary payload idx (parameter/label id, closure constant idx).</summary>
102102 public ushort ChildIdx => ( ushort ) ( _child & FirstChildIdxMask ) ;
103103
104+ /// <summary>Gets the raw 32-bit value for inline primitive constants. Only valid when <see cref="Obj"/> == <see cref="InlineValueMarker"/>.</summary>
105+ internal uint InlineValue => _child ;
106+
107+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
108+ internal static void Set ( ref ExprNode n , ExpressionType nodeType , Type type , object obj = null )
109+ {
110+ n . Type = type ;
111+ n . Obj = obj ;
112+ n . _nodeType = ( byte ) nodeType ;
113+ }
114+
104115 /// <summary>Sets the child-link metadata for the node.</summary>
105116 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
106117 public void SetChildrenInfo ( ushort childCount , ushort childIdx ) => _child = ( ( uint ) childCount << ChildCountShift ) | childIdx ;
107118
108- /// <summary>Gets the raw 32-bit value for inline primitive constants. Only valid when <see cref="Obj"/> == <see cref="InlineValueMarker"/>.</summary>
109- internal uint InlineValue => _child ;
119+ /// <summary>Sets the child-link metadata for the node.</summary>
120+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
121+ public static void SetChildrenInfo ( ref ExprNode n , ushort childCount , ushort childIdx ) =>
122+ n . _child = ( ( uint ) childCount << ChildCountShift ) | childIdx ;
110123
111- internal ExprNode ( ExpressionType nodeType , Type type , object obj , byte flags , ExprNodeKind kind ,
124+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
125+ internal static void Set ( ref ExprNode n , ExpressionType nodeType , Type type , object obj , byte flags , ExprNodeKind kind ,
112126 ushort childIdx = 0 , ushort childCount = 0 , ushort nextIdx = 0 )
113127 {
114- Type = type ;
115- Obj = obj ;
116- _child = ( ( uint ) childCount << ChildCountShift ) | childIdx ;
117- NextIdx = nextIdx ;
118- _nodeType = ( byte ) nodeType ;
119- FlagsAndKind = ( byte ) ( ( flags << 4 ) | ( ( byte ) kind & 0b1111 ) ) ;
128+ n . Type = type ;
129+ n . Obj = obj ;
130+ n . _child = ( ( uint ) childCount << ChildCountShift ) | childIdx ;
131+ n . NextIdx = nextIdx ;
132+ n . _nodeType = ( byte ) nodeType ;
133+ n . FlagsAndKind = ( byte ) ( ( flags << 4 ) | ( ( byte ) kind & 0b1111 ) ) ;
120134 }
121135
122136 /// <summary>Constructs an inline primitive constant node, <see cref="Obj"/> is set to <see cref="InlineValueMarker"/>.</summary>
123- internal ExprNode ( Type type , uint inlineValue )
137+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
138+ internal static void Set ( ref ExprNode n , Type type , uint inlineValue )
124139 {
125- Type = type ;
126- Obj = InlineValueMarker ;
127- _nodeType = ( byte ) ExpressionType . Constant ;
128- _child = inlineValue ;
140+ n . Type = type ;
141+ n . Obj = InlineValueMarker ;
142+ n . _nodeType = ( byte ) ExpressionType . Constant ;
143+ n . _child = inlineValue ;
129144 }
130145
131146 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
@@ -240,12 +255,31 @@ private void EnsureIndexZeroSentinel()
240255 }
241256
242257 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
243- private ushort AddNode ( ExpressionType nodType , Type type , object obj = null , byte flags = 0 , ExprNodeKind kind = default ,
258+ private ushort LastNodeIdx ( ) => checked ( ( ushort ) ( Nodes . Count - 1 ) ) ;
259+
260+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
261+ private ushort AddNode ( ExpressionType nodeType , Type type , object obj = null )
262+ {
263+ EnsureIndexZeroSentinel ( ) ;
264+ ExprNode . Set ( ref Nodes . AddDefaultAndGetRef ( out var idx ) , nodeType , type , obj ) ;
265+ return ( ushort ) idx ;
266+ }
267+
268+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
269+ private ushort AddNode ( ExpressionType nodeType , Type type , object obj , byte flags = 0 , ExprNodeKind kind = default ,
270+ ushort childIdx = 0 , ushort childCount = 0 )
271+ {
272+ EnsureIndexZeroSentinel ( ) ;
273+ ExprNode . Set ( ref Nodes . AddDefaultAndGetRef ( out var idx ) , nodeType , type , obj , flags , kind , childIdx , childCount ) ;
274+ return ( ushort ) idx ;
275+ }
276+
277+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
278+ private void AddNode ( ref ExprNode n , ExpressionType nodeType , Type type , object obj , byte flags = 0 , ExprNodeKind kind = default ,
244279 ushort childIdx = 0 , ushort childCount = 0 )
245280 {
246281 EnsureIndexZeroSentinel ( ) ;
247- var node = new ExprNode ( nodType , type , obj , flags , kind , childIdx , childCount ) ;
248- return checked ( ( ushort ) Nodes . Add ( in node ) ) ;
282+ ExprNode . Set ( ref n , nodeType , type , obj , flags , kind , childIdx , childCount ) ;
249283 }
250284
251285 /// <summary>Adds a parameter node and returns its idx.</summary>
@@ -281,7 +315,9 @@ public ushort Constant(object value, Type type)
281315 if ( ! In32BitRange ( Type . GetTypeCode ( Enum . GetUnderlyingType ( type ) ) ) )
282316 return AddNode ( ExpressionType . Constant , type , value ) ;
283317 EnsureIndexZeroSentinel ( ) ;
284- return checked ( ( ushort ) Nodes . Add ( new ExprNode ( type , unchecked ( ( uint ) System . Convert . ToInt64 ( value ) ) ) ) ) ;
318+ ref var n = ref Nodes . AddDefaultAndGetRef ( ) ;
319+ ExprNode . Set ( ref n , type , unchecked ( ( uint ) System . Convert . ToInt64 ( value ) ) ) ;
320+ return LastNodeIdx ( ) ;
285321 }
286322
287323 if ( type . IsPrimitive )
@@ -290,11 +326,12 @@ public ushort Constant(object value, Type type)
290326 if ( ! In32BitRange ( tc ) )
291327 return AddNode ( ExpressionType . Constant , type , value ) ;
292328 EnsureIndexZeroSentinel ( ) ;
293- return checked ( ( ushort ) Nodes . Add ( new ExprNode ( type , ToInlineValue ( value , tc ) ) ) ) ;
329+ ref var n = ref Nodes . AddDefaultAndGetRef ( ) ;
330+ ExprNode . Set ( ref n , type , ToInlineValue ( value , tc ) ) ;
331+ return LastNodeIdx ( ) ;
294332 }
295333
296- return AddNode ( ExpressionType . Constant , type , ClosureConstantMarker ,
297- childIdx : checked ( ( ushort ) ClosureConstants . Add ( value ) ) ) ;
334+ return AddNode ( ExpressionType . Constant , type , ClosureConstantMarker , childIdx : checked ( ( ushort ) ClosureConstants . Add ( value ) ) ) ;
298335 }
299336
300337 /// <summary>Adds a constant node using the runtime type of the supplied value.</summary>
@@ -310,7 +347,9 @@ public ushort Constant(object value, Type type)
310347 public ushort ConstantInt ( int value )
311348 {
312349 EnsureIndexZeroSentinel ( ) ;
313- return checked ( ( ushort ) Nodes . Add ( new ExprNode ( typeof ( int ) , unchecked ( ( uint ) value ) ) ) ) ;
350+ ref var n = ref Nodes . AddDefaultAndGetRef ( ) ;
351+ ExprNode . Set ( ref n , typeof ( int ) , unchecked ( ( uint ) value ) ) ;
352+ return LastNodeIdx ( ) ;
314353 }
315354
316355 /// <summary>Adds a typed constant node.</summary>
@@ -374,15 +413,18 @@ private void AppendPreparedChild(ushort childIdx, ref ushort firstChildIdx, ref
374413 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
375414 private ushort WithOneChild ( ExpressionType nodeType , Type type , object obj , byte flags , ExprNodeKind kind , ushort ch0 )
376415 {
377- var ownerIdx = AddNode ( nodeType , type , obj , flags , kind ) ;
416+ ref var ownerRef = ref Nodes . AddDefaultAndGetRef ( out var idx ) ;
417+ var ownerIdx = ( ushort ) idx ;
418+ AddNode ( ref ownerRef , nodeType , type , obj , flags , kind ) ;
419+
378420 ushort first = 0 ;
379421 ushort count = 0 ;
380422 if ( ch0 != 0 )
381423 {
382424 first = MayBeCloneChildForOwner ( ch0 , ownerIdx ) ;
383425 count = 1 ;
384426 }
385- Nodes . GetSurePresentRef ( ownerIdx ) . SetChildrenInfo ( count , first ) ;
427+ ExprNode . SetChildrenInfo ( ref ownerRef , count , first ) ;
386428 return ownerIdx ;
387429 }
388430
@@ -486,7 +528,11 @@ public ushort New(ConstructorInfo ctor, params ushort[] args) =>
486528
487529 /// <summary>Adds an array initialization node.</summary>
488530 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
531+ #if NET10_0_OR_GREATER
532+ public ushort NewArrayInit ( Type elementType , params ReadOnlySpan < ushort > expressions ) =>
533+ #else
489534 public ushort NewArrayInit ( Type elementType , params ushort [ ] expressions ) =>
535+ #endif
490536 WithChildren ( ExpressionType . NewArrayInit , elementType . MakeArrayType ( ) , null , default , default , expressions ) ;
491537
492538 /// <summary>Adds an array-bounds node.</summary>
@@ -616,7 +662,7 @@ public ushort Block(Type type, ushort[] vars, params ushort[] exprs)
616662 type ??= Nodes [ exprs [ exprs . Length - 1 ] ] . Type ;
617663 var blockIdx = WithOneOrMoreChildren ( ExpressionType . Block , type , null , default , default , exprsSubNode , vars ) ;
618664 if ( vars != null && vars . Length != 0 )
619- BlocksWithVariables . Add ( blockIdx ) ;
665+ BlocksWithVariables . Add ( blockIdx ) ;
620666 return blockIdx ;
621667 }
622668
@@ -629,14 +675,56 @@ public ushort Block(params ushort[] exprs) =>
629675 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
630676#if NET10_0_OR_GREATER
631677 public ushort Lambda ( Type delegateType , ushort bodyIdx , params ReadOnlySpan < ushort > pars )
678+ {
632679#else
633680 public ushort Lambda ( Type delegateType , ushort bodyIdx , params ushort [ ] pars )
634- #endif
635681 {
636- var idx = WithOneOrMoreChildren ( ExpressionType . Lambda , delegateType , null , default , default , bodyIdx , pars ) ;
637- LambdaNodes . Add ( idx ) ;
638- CollectLambdaClosureParameterUsages ( idx ) ;
639- return idx ;
682+ pars ??= Array . Empty < ushort > ( ) ;
683+ #endif
684+ EnsureIndexZeroSentinel ( ) ;
685+ ref var lambdaRef = ref Nodes . AddDefaultAndGetRef ( out var idx ) ;
686+ ExprNode . Set ( ref lambdaRef , ExpressionType . Lambda , delegateType ) ;
687+ var lambdaIdx = ( ushort ) idx ;
688+
689+ ushort firstIdx = 0 ;
690+
691+ ref var prevRef = ref Nodes . GetSurePresentRef ( bodyIdx ) ;
692+ if ( bodyIdx != 0 )
693+ {
694+ if ( prevRef . NextIdx != 0 || prevRef . NodeType == ExpressionType . Parameter )
695+ {
696+ var bodyCopyRef = prevRef ;
697+ prevRef = ref Nodes . AddDefaultAndGetRef ( out var bodyCopyIdx ) ;
698+ prevRef = bodyCopyRef ;
699+ bodyIdx = ( ushort ) bodyCopyIdx ;
700+ }
701+ prevRef . NextIdx = lambdaIdx ; // set next to lambda by default, then it can be overridden by the first parameter if present
702+ firstIdx = bodyIdx ;
703+ }
704+ else
705+ {
706+ ref var defaultRef = ref Nodes . AddDefaultAndGetRef ( out var defaultIdx ) ;
707+ ExprNode . Set ( ref defaultRef , ExpressionType . Default , typeof ( void ) ) ;
708+ firstIdx = ( ushort ) defaultIdx ;
709+ }
710+
711+ var count = ( ushort ) ( pars . Length + 1 ) ;
712+ ExprNode . SetChildrenInfo ( ref lambdaRef , count , firstIdx ) ;
713+
714+ foreach ( var parIdx in pars )
715+ {
716+ Debug . Assert ( parIdx != 0 , "The parameter should be defined - otherwise what is the matter" ) ;
717+ // We do not clone the parameters defined in the Lambda, because this the place where they are defined
718+ prevRef . NextIdx = parIdx ;
719+ prevRef = ref Nodes . GetSurePresentRef ( parIdx ) ;
720+ Debug . Assert ( prevRef . NextIdx == 0 , "The parameter should not be linked to any other node - otherwise what is the matter" ) ;
721+ }
722+
723+ prevRef . NextIdx = lambdaIdx ; // close the child chain with a link back to the lambda node
724+
725+ LambdaNodes . Add ( lambdaIdx ) ;
726+ CollectLambdaClosureParameterUsages ( lambdaIdx ) ;
727+ return lambdaIdx ;
640728 }
641729
642730 /// <summary>Adds a typed lambda node.</summary>
0 commit comments