@@ -127,9 +127,9 @@ public static TDelegate CompileFast<TDelegate>(this LambdaExpression lambdaExpr,
127127 (TDelegate)(TryCompileBoundToFirstClosureParam(
128128 typeof(TDelegate) == typeof(Delegate) ? lambdaExpr.Type : typeof(TDelegate), lambdaExpr.Body,
129129#if LIGHT_EXPRESSION
130- lambdaExpr, RentOrNewClosureTypeToParamTypes(lambdaExpr),
130+ lambdaExpr,
131131#else
132- lambdaExpr.Parameters, RentOrNewClosureTypeToParamTypes(lambdaExpr.Parameters),
132+ lambdaExpr.Parameters,
133133#endif
134134 lambdaExpr.ReturnType, flags) ?? (ifFastFailedReturnNull ? null : lambdaExpr.CompileSys()));
135135
@@ -168,9 +168,9 @@ public static bool CompileFastToIL(this LambdaExpression lambdaExpr, ILGenerator
168168 public static Delegate CompileFast(this LambdaExpression lambdaExpr, bool ifFastFailedReturnNull = false, CompilerFlags flags = CompilerFlags.Default) =>
169169 (Delegate)TryCompileBoundToFirstClosureParam(lambdaExpr.Type, lambdaExpr.Body,
170170#if LIGHT_EXPRESSION
171- lambdaExpr, RentOrNewClosureTypeToParamTypes(lambdaExpr),
171+ lambdaExpr,
172172#else
173- lambdaExpr.Parameters, RentOrNewClosureTypeToParamTypes(lambdaExpr.Parameters),
173+ lambdaExpr.Parameters,
174174#endif
175175 lambdaExpr.ReturnType, flags) ?? (ifFastFailedReturnNull ? null : lambdaExpr.CompileSys());
176176
@@ -220,7 +220,7 @@ public static Func<R> CompileFast<R>(this Expression<Func<R>> lambdaExpr, bool i
220220#else
221221 lambdaExpr.Parameters,
222222#endif
223- _closureAsASingleParamType, typeof(R), flags) ?? (ifFastFailedReturnNull ? null : lambdaExpr.CompileSys());
223+ typeof(R), flags) ?? (ifFastFailedReturnNull ? null : lambdaExpr.CompileSys());
224224
225225 /// <summary>Compiles lambda expression to delegate. Use ifFastFailedReturnNull parameter to Not fallback to Expression.Compile, useful for testing.</summary>
226226 public static Func<T1, R> CompileFast<T1, R>(this Expression<Func<T1, R>> lambdaExpr,
@@ -231,7 +231,7 @@ public static Func<T1, R> CompileFast<T1, R>(this Expression<Func<T1, R>> lambda
231231#else
232232 lambdaExpr.Parameters,
233233#endif
234- new[] { typeof(ArrayClosure), typeof(T1) }, typeof(R), flags) ?? (ifFastFailedReturnNull ? null : lambdaExpr.CompileSys());
234+ typeof(R), flags) ?? (ifFastFailedReturnNull ? null : lambdaExpr.CompileSys());
235235
236236 /// <summary>Compiles lambda expression to TDelegate type. Use ifFastFailedReturnNull parameter to Not fallback to Expression.Compile, useful for testing.</summary>
237237 public static Func<T1, T2, R> CompileFast<T1, T2, R>(this Expression<Func<T1, T2, R>> lambdaExpr,
@@ -242,7 +242,6 @@ public static Func<T1, T2, R> CompileFast<T1, T2, R>(this Expression<Func<T1, T2
242242#else
243243 lambdaExpr.Parameters,
244244#endif
245- new[] { typeof(ArrayClosure), typeof(T1), typeof(T2) }, // todo: @perf rent and return the array of types to pool
246245 typeof(R), flags) ?? (ifFastFailedReturnNull ? null : lambdaExpr.CompileSys());
247246
248247 /// <summary>Compiles lambda expression to delegate. Use ifFastFailedReturnNull parameter to Not fallback to Expression.Compile, useful for testing.</summary>
@@ -254,7 +253,7 @@ public static Func<T1, T2, T3, R> CompileFast<T1, T2, T3, R>(
254253#else
255254 lambdaExpr.Parameters,
256255#endif
257- new[] { typeof(ArrayClosure), typeof(T1), typeof(T2), typeof(T3) }, typeof(R), flags)
256+ typeof(R), flags)
258257 ?? (ifFastFailedReturnNull ? null : lambdaExpr.CompileSys());
259258
260259 /// <summary>Compiles lambda expression to TDelegate type. Use ifFastFailedReturnNull parameter to Not fallback to Expression.Compile, useful for testing.</summary>
@@ -266,7 +265,7 @@ public static Func<T1, T2, T3, T4, R> CompileFast<T1, T2, T3, T4, R>(
266265#else
267266 lambdaExpr.Parameters,
268267#endif
269- new[] { typeof(ArrayClosure), typeof(T1), typeof(T2), typeof(T3), typeof(T4) }, typeof(R), flags)
268+ typeof(R), flags)
270269 ?? (ifFastFailedReturnNull ? null : lambdaExpr.CompileSys());
271270
272271 /// <summary>Compiles lambda expression to delegate. Use ifFastFailedReturnNull parameter to Not fallback to Expression.Compile, useful for testing.</summary>
@@ -278,7 +277,7 @@ public static Func<T1, T2, T3, T4, T5, R> CompileFast<T1, T2, T3, T4, T5, R>(
278277#else
279278 lambdaExpr.Parameters,
280279#endif
281- new[] { typeof(ArrayClosure), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5) }, typeof(R), flags)
280+ typeof(R), flags)
282281 ?? (ifFastFailedReturnNull ? null : lambdaExpr.CompileSys());
283282
284283 /// <summary>Compiles lambda expression to delegate. Use ifFastFailedReturnNull parameter to Not fallback to Expression.Compile, useful for testing.</summary>
@@ -290,7 +289,7 @@ public static Func<T1, T2, T3, T4, T5, T6, R> CompileFast<T1, T2, T3, T4, T5, T6
290289#else
291290 lambdaExpr.Parameters,
292291#endif
293- new[] { typeof(ArrayClosure), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6) }, typeof(R), flags)
292+ typeof(R), flags)
294293 ?? (ifFastFailedReturnNull ? null : lambdaExpr.CompileSys());
295294
296295 /// <summary>Compiles lambda expression to delegate. Use ifFastFailedReturnNull parameter to Not fallback to Expression.Compile, useful for testing.</summary>
@@ -301,7 +300,7 @@ public static Action CompileFast(this Expression<Action> lambdaExpr, bool ifFast
301300#else
302301 lambdaExpr.Parameters,
303302#endif
304- _closureAsASingleParamType, typeof(void), flags) ?? (ifFastFailedReturnNull ? null : lambdaExpr.CompileSys());
303+ typeof(void), flags) ?? (ifFastFailedReturnNull ? null : lambdaExpr.CompileSys());
305304
306305 /// <summary>Compiles lambda expression to delegate. Use ifFastFailedReturnNull parameter to Not fallback to Expression.Compile, useful for testing.</summary>
307306 public static Action<T1> CompileFast<T1>(this Expression<Action<T1>> lambdaExpr,
@@ -312,7 +311,7 @@ public static Action<T1> CompileFast<T1>(this Expression<Action<T1>> lambdaExpr,
312311#else
313312 lambdaExpr.Parameters,
314313#endif
315- new[] { typeof(ArrayClosure), typeof(T1) }, typeof(void), flags) ?? (ifFastFailedReturnNull ? null : lambdaExpr.CompileSys());
314+ typeof(void), flags) ?? (ifFastFailedReturnNull ? null : lambdaExpr.CompileSys());
316315
317316 /// <summary>Compiles lambda expression to delegate. Use ifFastFailedReturnNull parameter to Not fallback to Expression.Compile, useful for testing.</summary>
318317 public static Action<T1, T2> CompileFast<T1, T2>(this Expression<Action<T1, T2>> lambdaExpr,
@@ -323,7 +322,7 @@ public static Action<T1, T2> CompileFast<T1, T2>(this Expression<Action<T1, T2>>
323322#else
324323 lambdaExpr.Parameters,
325324#endif
326- new[] { typeof(ArrayClosure), typeof(T1), typeof(T2) }, typeof(void), flags) ?? (ifFastFailedReturnNull ? null : lambdaExpr.CompileSys());
325+ typeof(void), flags) ?? (ifFastFailedReturnNull ? null : lambdaExpr.CompileSys());
327326
328327 /// <summary>Compiles lambda expression to delegate. Use ifFastFailedReturnNull parameter to Not fallback to Expression.Compile, useful for testing.</summary>
329328 public static Action<T1, T2, T3> CompileFast<T1, T2, T3>(this Expression<Action<T1, T2, T3>> lambdaExpr,
@@ -334,7 +333,7 @@ public static Action<T1, T2, T3> CompileFast<T1, T2, T3>(this Expression<Action<
334333#else
335334 lambdaExpr.Parameters,
336335#endif
337- new[] { typeof(ArrayClosure), typeof(T1), typeof(T2), typeof(T3) }, typeof(void), flags)
336+ typeof(void), flags)
338337 ?? (ifFastFailedReturnNull ? null : lambdaExpr.CompileSys());
339338
340339 /// <summary>Compiles lambda expression to delegate. Use ifFastFailedReturnNull parameter to Not fallback to Expression.Compile, useful for testing.</summary>
@@ -346,7 +345,7 @@ public static Action<T1, T2, T3, T4> CompileFast<T1, T2, T3, T4>(
346345#else
347346 lambdaExpr.Parameters,
348347#endif
349- new[] { typeof(ArrayClosure), typeof(T1), typeof(T2), typeof(T3), typeof(T4) }, typeof(void), flags)
348+ typeof(void), flags)
350349 ?? (ifFastFailedReturnNull ? null : lambdaExpr.CompileSys());
351350
352351 /// <summary>Compiles lambda expression to delegate. Use ifFastFailedReturnNull parameter to Not fallback to Expression.Compile, useful for testing.</summary>
@@ -358,7 +357,7 @@ public static Action<T1, T2, T3, T4, T5> CompileFast<T1, T2, T3, T4, T5>(
358357#else
359358 lambdaExpr.Parameters,
360359#endif
361- new[] { typeof(ArrayClosure), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5) }, typeof(void), flags)
360+ typeof(void), flags)
362361 ?? (ifFastFailedReturnNull ? null : lambdaExpr.CompileSys());
363362
364363 /// <summary>Compiles lambda expression to delegate. Use ifFastFailedReturnNull parameter to Not fallback to Expression.Compile, useful for testing.</summary>
@@ -370,7 +369,7 @@ public static Action<T1, T2, T3, T4, T5, T6> CompileFast<T1, T2, T3, T4, T5, T6>
370369#else
371370 lambdaExpr.Parameters,
372371#endif
373- new[] { typeof(ArrayClosure), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6) }, typeof(void), flags)
372+ typeof(void), flags)
374373 ?? (ifFastFailedReturnNull ? null : lambdaExpr.CompileSys());
375374
376375 #endregion
@@ -380,9 +379,9 @@ public static TDelegate TryCompile<TDelegate>(this LambdaExpression lambdaExpr,
380379 where TDelegate : class =>
381380 (TDelegate)TryCompileBoundToFirstClosureParam(typeof(TDelegate) == typeof(Delegate) ? lambdaExpr.Type : typeof(TDelegate), lambdaExpr.Body,
382381#if LIGHT_EXPRESSION
383- lambdaExpr, RentOrNewClosureTypeToParamTypes(lambdaExpr),
382+ lambdaExpr,
384383#else
385- lambdaExpr.Parameters, RentOrNewClosureTypeToParamTypes(lambdaExpr.Parameters),
384+ lambdaExpr.Parameters,
386385#endif
387386 lambdaExpr.ReturnType, flags);
388387
@@ -486,14 +485,19 @@ private static Delegate CompileNoArgsNew(ConstructorInfo ctor, Type delegateType
486485
487486#if LIGHT_EXPRESSION
488487 internal static object TryCompileBoundToFirstClosureParam(Type delegateType, Expression bodyExpr, IParameterProvider paramExprs,
489- Type[] closurePlusParamTypes, Type returnType, CompilerFlags flags)
488+ Type returnType, CompilerFlags flags)
490489 {
490+ var closurePlusParamTypes = RentOrNewClosureTypeToParamTypes(paramExprs);
491491 if (bodyExpr is NoArgsNewClassIntrinsicExpression newNoArgs)
492+ {
493+ // there is no Return of the pooled parameter types here, because in the rarest case with the unused lambda arguments we may just exaust the pooled instance
492494 return CompileNoArgsNew(newNoArgs.Constructor, delegateType, closurePlusParamTypes, returnType);
495+ }
493496#else
494497 internal static object TryCompileBoundToFirstClosureParam(Type delegateType, Expression bodyExpr, IReadOnlyList<PE> paramExprs,
495- Type[] closurePlusParamTypes, Type returnType, CompilerFlags flags)
498+ Type returnType, CompilerFlags flags)
496499 {
500+ var closurePlusParamTypes = RentOrNewClosureTypeToParamTypes(paramExprs);
497501#endif
498502 // Try to avoid compilation altogether for Func<bool> delegates via Interpreter, see #468
499503 if (returnType == typeof(bool) & closurePlusParamTypes.Length == 1
@@ -541,13 +545,14 @@ internal static object TryCompileBoundToFirstClosureParam(Type delegateType, Exp
541545 return null;
542546 il.Demit(OpCodes.Ret);
543547
548+ ReturnClosureTypeToParamTypesToPool(closurePlusParamTypes);
549+
544550 return method.CreateDelegate(delegateType, closure);
545551 }
546552
547553 private static readonly Type[] _closureAsASingleParamType = { typeof(ArrayClosure) };
548554 private static readonly Type[][] _closureTypePlusParamTypesPool = new Type[8][]; // todo: @perf @mem could we use this for other Type arrays?
549555
550- // todo: @perf optimize
551556#if LIGHT_EXPRESSION
552557 private static Type[] RentOrNewClosureTypeToParamTypes(IParameterProvider paramExprs)
553558 {
@@ -560,37 +565,23 @@ private static Type[] RentOrNewClosureTypeToParamTypes(IReadOnlyList<PE> paramEx
560565 if (count == 0)
561566 return _closureAsASingleParamType;
562567
563- if (count < 8)
564- {
565- var pooledClosureAndParamTypes = Interlocked.Exchange(ref _closureTypePlusParamTypesPool[count], null);
566- if (pooledClosureAndParamTypes != null)
567- {
568- for (var i = 0; i < count; i++)
569- {
570- var parameterExpr = paramExprs.GetParameter(i); // todo: @perf can we avoid calling virtual GetParameter() and maybe use intrinsic with NoByRef?
571- pooledClosureAndParamTypes[i + 1] = parameterExpr.IsByRef ? parameterExpr.Type.MakeByRefType() : parameterExpr.Type;
572- }
573- return pooledClosureAndParamTypes;
574- }
575- }
576-
577- // todo: @perf the code maybe simplified and then will be the candidate for the inlining
578- var closureAndParamTypes = new Type[count + 1];
579- closureAndParamTypes[0] = typeof(ArrayClosure);
568+ var pooled = count < 8 ? Interlocked.Exchange(ref _closureTypePlusParamTypesPool[count], null) ?? new Type[count + 1] : new Type[count + 1];
569+ pooled[0] = typeof(ArrayClosure);
580570 for (var i = 0; i < count; i++)
581571 {
582- var parameterExpr = paramExprs.GetParameter(i);
583- closureAndParamTypes [i + 1] = parameterExpr .IsByRef ? parameterExpr .Type.MakeByRefType() : parameterExpr .Type;
572+ var paramExpr = paramExprs.GetParameter(i); // todo: @perf can we avoid calling virtual GetParameter() and maybe use intrinsic with NoByRef?
573+ pooled [i + 1] = !paramExpr .IsByRef ? paramExpr .Type : paramExpr .Type.MakeByRefType() ;
584574 }
585- return closureAndParamTypes;
575+
576+ return pooled;
586577 }
587578
588579 [MethodImpl((MethodImplOptions)256)]
589580 private static void ReturnClosureTypeToParamTypesToPool(Type[] closurePlusParamTypes)
590581 {
591- var paramCount = closurePlusParamTypes.Length - 1;
592- if (paramCount != 0 && paramCount < 8)
593- Interlocked.Exchange(ref _closureTypePlusParamTypesPool[paramCount ], closurePlusParamTypes); // todo: @perf we don't need the Interlocked here
582+ var paramCountOnly = closurePlusParamTypes.Length - 1;
583+ if (paramCountOnly != 0 & paramCountOnly < 8)
584+ Interlocked.Exchange(ref _closureTypePlusParamTypesPool[paramCountOnly ], closurePlusParamTypes); // todo: @perf we don't need the Interlocked here
594585 }
595586
596587#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
@@ -2105,7 +2096,7 @@ public static bool TryEmit(Expression expr,
21052096 || TryEmitArithmetic(((BinaryExpression)expr).Left, ((BinaryExpression)expr).Right, nodeType, exprType, paramExprs, il,
21062097 ref closure, setup, parent);
21072098 }
2108- // todo: @wip @ feature #472 add interpretation when those node types are supported
2099+ // todo: @feature #472 add interpretation when those node types are supported
21092100 case ExpressionType.AddChecked:
21102101 case ExpressionType.SubtractChecked:
21112102 case ExpressionType.MultiplyChecked:
0 commit comments