@@ -437,7 +437,7 @@ internal static TDelegate TryCompileWithPreCreatedClosure<TDelegate>(
437437
438438 var delegateType = typeof(TDelegate) != typeof(Delegate) ? typeof(TDelegate) : lambdaExpr.Type;
439439 var @delegate = (TDelegate)(object)method.CreateDelegate(delegateType, new ArrayClosure(closureInfo.Constants.Items));
440- ReturnClosureTypeToParamTypesToPool (closurePlusParamTypes);
440+ FreeClosureTypeToParamTypesToPool (closurePlusParamTypes);
441441 return @delegate;
442442 }
443443
@@ -468,7 +468,7 @@ public static TDelegate TryCompileWithoutClosure<TDelegate>(this LambdaExpressio
468468
469469 var delegateType = typeof(TDelegate) != typeof(Delegate) ? typeof(TDelegate) : lambdaExpr.Type;
470470 var @delegate = (TDelegate)(object)method.CreateDelegate(delegateType, EmptyArrayClosure);
471- ReturnClosureTypeToParamTypesToPool (closurePlusParamTypes);
471+ FreeClosureTypeToParamTypesToPool (closurePlusParamTypes);
472472 return @delegate;
473473 }
474474
@@ -545,43 +545,70 @@ internal static object TryCompileBoundToFirstClosureParam(Type delegateType, Exp
545545 return null;
546546 il.Demit(OpCodes.Ret);
547547
548- ReturnClosureTypeToParamTypesToPool (closurePlusParamTypes);
548+ FreeClosureTypeToParamTypesToPool (closurePlusParamTypes);
549549
550550 return method.CreateDelegate(delegateType, closure);
551551 }
552552
553553 private static readonly Type[] _closureAsASingleParamType = { typeof(ArrayClosure) };
554- private static readonly Type[][] _closureTypePlusParamTypesPool = new Type[8][]; // todo: @perf @mem could we use this for other Type arrays?
554+ private static readonly Type[][] _paramTypesPoolWithElem0OfLength1 = new Type[8][]; // todo: @perf @mem could we use this for other Type arrays?
555555
556556#if LIGHT_EXPRESSION
557- private static Type[] RentOrNewClosureTypeToParamTypes(IParameterProvider paramExprs)
557+ internal static Type[] RentOrNewClosureTypeToParamTypes(IParameterProvider paramExprs)
558558 {
559559 var count = paramExprs.ParameterCount;
560560#else
561- private static Type[] RentOrNewClosureTypeToParamTypes(IReadOnlyList<PE> paramExprs)
561+ internal static Type[] RentOrNewClosureTypeToParamTypes(IReadOnlyList<PE> paramExprs)
562562 {
563563 var count = paramExprs.Count;
564564#endif
565565 if (count == 0)
566566 return _closureAsASingleParamType;
567567
568- var pooled = count < 8 ? Interlocked.Exchange(ref _closureTypePlusParamTypesPool [count], null) ?? new Type[count + 1] : new Type[count + 1];
569- pooled [0] = typeof(ArrayClosure);
568+ var pooledOrNew = count < 8 ? Interlocked.Exchange(ref _paramTypesPoolWithElem0OfLength1 [count], null) ?? new Type[count + 1] : new Type[count + 1];
569+ pooledOrNew [0] = typeof(ArrayClosure);
570570 for (var i = 0; i < count; i++)
571571 {
572572 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();
573+ pooledOrNew [i + 1] = !paramExpr.IsByRef ? paramExpr.Type : paramExpr.Type.MakeByRefType();
574574 }
575575
576- return pooled ;
576+ return pooledOrNew ;
577577 }
578578
579579 [MethodImpl((MethodImplOptions)256)]
580- private static void ReturnClosureTypeToParamTypesToPool(Type[] closurePlusParamTypes)
580+ internal static Type[] RentOrNewClosureTypeToParamTypes(Type p1, Type p2)
581+ {
582+ var pooledOrNew = Interlocked.Exchange(ref _paramTypesPoolWithElem0OfLength1[2], null) ?? new Type[3];
583+ pooledOrNew[0] = typeof(ArrayClosure);
584+ pooledOrNew[1] = p1;
585+ pooledOrNew[2] = p2;
586+ return pooledOrNew;
587+ }
588+
589+ [MethodImpl((MethodImplOptions)256)]
590+ internal static Type[] RentParamTypes(Type p0, Type p1)
591+ {
592+ var pooledOrNew = Interlocked.Exchange(ref _paramTypesPoolWithElem0OfLength1[1], null) ?? new Type[2];
593+ pooledOrNew[0] = p0;
594+ pooledOrNew[1] = p1;
595+ return pooledOrNew;
596+ }
597+
598+ [MethodImpl((MethodImplOptions)256)]
599+ internal static void FreeClosureTypeToParamTypesToPool(Type[] closurePlusParamTypes)
581600 {
582601 var paramCountOnly = closurePlusParamTypes.Length - 1;
583602 if (paramCountOnly != 0 & paramCountOnly < 8)
584- Interlocked.Exchange(ref _closureTypePlusParamTypesPool[paramCountOnly], closurePlusParamTypes); // todo: @perf we don't need the Interlocked here
603+ Interlocked.Exchange(ref _paramTypesPoolWithElem0OfLength1[paramCountOnly], closurePlusParamTypes); // todo: @perf we don't need the Interlocked here
604+ }
605+
606+ [MethodImpl((MethodImplOptions)256)]
607+ internal static void FreeParamTypes(Type[] paramTypes)
608+ {
609+ var paramCount = paramTypes.Length;
610+ if (paramCount != 0 & paramCount < 8)
611+ Interlocked.Exchange(ref _paramTypesPoolWithElem0OfLength1[paramCount - 1], paramTypes); // todo: @perf we don't need the Interlocked here
585612 }
586613
587614#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
@@ -1735,7 +1762,7 @@ private static bool TryCompileNestedLambda(ref ClosureInfo nestedClosureInfo, Ne
17351762 {
17361763 var paramTypes = RentOrNewClosureTypeToParamTypes(nestedLambdaParamExprs);
17371764 nestedLambdaInfo.Lambda = CompileNoArgsNew(newNoArgs.Constructor, nestedLambdaExpr.Type, paramTypes, nestedReturnType);
1738- ReturnClosureTypeToParamTypesToPool (paramTypes);
1765+ FreeClosureTypeToParamTypesToPool (paramTypes);
17391766 return true;
17401767 }
17411768#else
@@ -1780,7 +1807,7 @@ private static bool TryCompileNestedLambda(ref ClosureInfo nestedClosureInfo, Ne
17801807 : nestedConstsAndLambdas == null ? new NestedLambdaForNonPassedParams(nestedLambda)
17811808 : new NestedLambdaForNonPassedParamsWithConstants(nestedLambda, nestedConstsAndLambdas);
17821809
1783- ReturnClosureTypeToParamTypesToPool (closurePlusParamTypes);
1810+ FreeClosureTypeToParamTypesToPool (closurePlusParamTypes);
17841811 return true;
17851812 }
17861813
@@ -8325,7 +8352,7 @@ public virtual LocalBuilder DeclareLocal(Type localType, bool pinned)
83258352 }
83268353 */
83278354
8328- private static readonly Func<ILGenerator, Type, int> _getNextLocalVarIndex;
8355+ internal static readonly Func<ILGenerator, Type, int> _getNextLocalVarIndex;
83298356
83308357 internal static int PostInc(ref int i) => i++;
83318358
@@ -8345,26 +8372,18 @@ static ILGeneratorHacks()
83458372 return;
83468373
83478374 // looking for the `SignatureHelper.AddArgument(Type argument, bool pinned)`
8348- MethodInfo addArgumentMethod = null;
8349- foreach (var m in typeof(SignatureHelper).GetTypeInfo().GetDeclaredMethods("AddArgument"))
8350- {
8351- var ps = m.GetParameters();
8352- if (ps.Length == 2 && ps[0].ParameterType == typeof(Type) && ps[1].ParameterType == typeof(bool))
8353- {
8354- addArgumentMethod = m;
8355- break;
8356- }
8357- }
8358-
8375+ var typeAndBoolParamTypes = ExpressionCompiler.RentParamTypes(typeof(Type), typeof(bool));
8376+ var addArgumentMethod = typeof(SignatureHelper).GetMethod("AddArgument", typeAndBoolParamTypes);
83598377 if (addArgumentMethod == null)
83608378 return;
8379+ ExpressionCompiler.FreeParamTypes(typeAndBoolParamTypes);
83618380
83628381 // our own helper - always available
8363- var postIncMethod = typeof(ILGeneratorHacks).GetTypeInfo().GetDeclaredMethod(nameof(PostInc));
8382+ var postIncMethod = typeof(ILGeneratorHacks).GetMethod(nameof(PostInc), BindingFlags.Static | BindingFlags.NonPublic);
8383+ Debug.Assert(postIncMethod != null, "PostInc method not found!");
83648384
8365- var efficientMethod = new DynamicMethod(string.Empty,
8366- typeof(int), new[] { typeof(ExpressionCompiler.ArrayClosure), typeof(ILGenerator), typeof(Type) },
8367- typeof(ExpressionCompiler.ArrayClosure), skipVisibility: true);
8385+ var paramTypes = ExpressionCompiler.RentOrNewClosureTypeToParamTypes(typeof(ILGenerator), typeof(Type));
8386+ var efficientMethod = new DynamicMethod(string.Empty, typeof(int), paramTypes, typeof(ExpressionCompiler.ArrayClosure), true);
83688387 var il = efficientMethod.GetILGenerator();
83698388
83708389 // emitting `il.m_localSignature.AddArgument(type);`
@@ -8384,6 +8403,8 @@ static ILGeneratorHacks()
83848403 _getNextLocalVarIndex = (Func<ILGenerator, Type, int>)efficientMethod.CreateDelegate(
83858404 typeof(Func<ILGenerator, Type, int>), ExpressionCompiler.EmptyArrayClosure);
83868405
8406+ ExpressionCompiler.FreeClosureTypeToParamTypesToPool(paramTypes);
8407+
83878408 // todo: @perf do batch Emit by manually calling `EnsureCapacity` once then `InternalEmit` multiple times
83888409 // todo: @perf Replace the `Emit(opcode, int)` with the more specialized `Emit(opcode)`, `Emit(opcode, byte)` or `Emit(opcode, short)`
83898410 // avoiding internal check for Ldc_I4, Ldarg, Ldarga, Starg then call `PutInteger4` only if needed see https://source.dot.net/#System.Private.CoreLib/src/System/Reflection/Emit/ILGenerator.cs,690f350859394132
0 commit comments