Skip to content

Commit 0d82d79

Browse files
committed
In JavaScriptEngineSwitcher.ChakraCore optimized a memory usage in the ReflectionHelpers.GetBestFitMethod method
1 parent be0daef commit 0d82d79

File tree

3 files changed

+79
-52
lines changed

3 files changed

+79
-52
lines changed

src/JavaScriptEngineSwitcher.ChakraCore/Helpers/ReflectionHelpers.cs

Lines changed: 77 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
using System;
2+
#if NET45_OR_GREATER || NETSTANDARD
3+
using System.Buffers;
4+
#endif
25
using System.Collections.Generic;
36
using System.Linq;
47
using System.Reflection;
8+
#if NET40
9+
10+
using PolyfillsForOldDotNet.System.Buffers;
11+
#endif
512

613
using JavaScriptEngineSwitcher.Core.Utilities;
714

@@ -113,6 +120,11 @@ public static void FixPropertyValueType(ref object value, PropertyInfo property)
113120
public static void FixArgumentTypes(ref object[] argValues, ParameterInfo[] parameters)
114121
{
115122
int argCount = argValues.Length;
123+
if (argCount == 0)
124+
{
125+
return;
126+
}
127+
116128
int parameterCount = parameters.Length;
117129

118130
for (int argIndex = 0; argIndex < argCount; argIndex++)
@@ -147,54 +159,72 @@ public static void FixArgumentTypes(ref object[] argValues, ParameterInfo[] para
147159

148160
public static MethodBase GetBestFitMethod(MethodBase[] methods, object[] argValues)
149161
{
150-
MethodWithMetadata[] methodCandidates = methods
151-
.Select(m => new MethodWithMetadata
152-
{
153-
Method = m,
154-
ParameterTypes = m.GetParameters()
155-
.Select(p => p.ParameterType)
156-
.ToArray()
157-
})
158-
.ToArray()
159-
;
160-
int argCount = argValues.Length;
161-
MethodWithMetadata[] sameArityMethods = methodCandidates
162-
.Where(m => m.ParameterTypes.Length == argCount)
163-
.ToArray()
164-
;
165-
166-
int sameArityMethodCount = sameArityMethods.Length;
167-
if (sameArityMethodCount == 0)
162+
int methodCount = methods.Length;
163+
if (methodCount == 0)
168164
{
169165
return null;
170166
}
171167

172-
Type[] argTypes = argValues
173-
.Select(a => a != null ? a.GetType() : typeof(object))
174-
.ToArray()
175-
;
176-
var compatibleMethods = new List<MethodWithMetadata>();
177-
178-
for (int methodIndex = 0; methodIndex < sameArityMethodCount; methodIndex++)
168+
if (methodCount == 1)
179169
{
180-
MethodWithMetadata method = sameArityMethods[methodIndex];
181-
ushort compatibilityScore;
170+
MethodBase method = methods[0];
171+
ParameterInfo[] parameters = method.GetParameters();
182172

183-
if (CompareParameterTypes(argValues, argTypes, method.ParameterTypes, out compatibilityScore))
173+
MethodBase bestFitMethod = null;
174+
if (CompareParameterTypes(argValues, parameters, out _))
184175
{
185-
method.CompatibilityScore = compatibilityScore;
186-
compatibleMethods.Add(method);
176+
bestFitMethod = method;
187177
}
178+
179+
return bestFitMethod;
188180
}
189181

190-
int compatibleMethodCount = compatibleMethods.Count;
191-
if (compatibleMethodCount > 0)
182+
MethodWithMetadata[] compatibleMethods = null;
183+
int compatibleMethodCount = 0;
184+
185+
var methodArrayPool = ArrayPool<MethodWithMetadata>.Shared;
186+
MethodWithMetadata[] buffer = methodArrayPool.Rent(methodCount);
187+
188+
try
192189
{
193-
if (compatibleMethodCount == 1)
190+
for (int methodIndex = 0; methodIndex < methodCount; methodIndex++)
191+
{
192+
MethodBase method = methods[methodIndex];
193+
ParameterInfo[] parameters = method.GetParameters();
194+
ushort compatibilityScore;
195+
196+
if (CompareParameterTypes(argValues, parameters, out compatibilityScore))
197+
{
198+
compatibleMethodCount++;
199+
200+
int compatibleMethodIndex = compatibleMethodCount - 1;
201+
buffer[compatibleMethodIndex] = new MethodWithMetadata
202+
{
203+
Method = method,
204+
CompatibilityScore = compatibilityScore
205+
};
206+
}
207+
}
208+
209+
if (compatibleMethodCount > 0)
194210
{
195-
return compatibleMethods[0].Method;
211+
if (compatibleMethodCount == 1)
212+
{
213+
return buffer[0].Method;
214+
}
215+
216+
compatibleMethods = new MethodWithMetadata[compatibleMethodCount];
217+
Array.Copy(buffer, compatibleMethods, compatibleMethodCount);
196218
}
219+
}
220+
finally
221+
{
222+
bool clearArray = compatibleMethodCount > 0;
223+
methodArrayPool.Return(buffer, clearArray);
224+
}
197225

226+
if (compatibleMethods != null)
227+
{
198228
MethodWithMetadata bestFitMethod = compatibleMethods
199229
.OrderByDescending(m => m.CompatibilityScore)
200230
.First()
@@ -206,24 +236,29 @@ public static MethodBase GetBestFitMethod(MethodBase[] methods, object[] argValu
206236
return null;
207237
}
208238

209-
private static bool CompareParameterTypes(object[] argValues, Type[] argTypes, Type[] parameterTypes,
239+
private static bool CompareParameterTypes(object[] argValues, ParameterInfo[] parameters,
210240
out ushort compatibilityScore)
211241
{
212-
int argValueCount = argValues.Length;
213-
int argTypeCount = argTypes.Length;
214-
int parameterCount = parameterTypes.Length;
242+
int argCount = argValues.Length;
243+
int parameterCount = parameters.Length;
215244
compatibilityScore = 0;
216245

217-
if (argValueCount != argTypeCount || argTypeCount != parameterCount)
246+
if (argCount != parameterCount)
218247
{
219248
return false;
220249
}
250+
else if (argCount == 0)
251+
{
252+
compatibilityScore = ushort.MaxValue;
253+
return true;
254+
}
221255

222-
for (int argIndex = 0; argIndex < argValueCount; argIndex++)
256+
for (int argIndex = 0; argIndex < argCount; argIndex++)
223257
{
224258
object argValue = argValues[argIndex];
225-
Type argType = argTypes[argIndex];
226-
Type parameterType = parameterTypes[argIndex];
259+
Type argType = argValue != null ? argValue.GetType() : typeof(object);
260+
ParameterInfo parameter = parameters[argIndex];
261+
Type parameterType = parameter.ParameterType;
227262

228263
if (argType == parameterType)
229264
{
@@ -239,8 +274,6 @@ private static bool CompareParameterTypes(object[] argValues, Type[] argTypes, T
239274
{
240275
return false;
241276
}
242-
243-
continue;
244277
}
245278
}
246279

@@ -297,12 +330,6 @@ public MethodBase Method
297330
set;
298331
}
299332

300-
public Type[] ParameterTypes
301-
{
302-
get;
303-
set;
304-
}
305-
306333
/// TODO: In future will need to change type to <c>double</c>
307334
public ushort CompatibilityScore
308335
{

src/JavaScriptEngineSwitcher.ChakraCore/JavaScriptEngineSwitcher.ChakraCore.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
<PackageIconFullPath>../../Icons/JavaScriptEngineSwitcher_ChakraCore_Logo128x128.png</PackageIconFullPath>
2525
<Description>JavaScriptEngineSwitcher.ChakraCore contains a `ChakraCoreJsEngine` adapter (wrapper for the ChakraCore).</Description>
2626
<PackageTags>$(PackageCommonTags);ChakraCore</PackageTags>
27-
<PackageReleaseNotes>ChakraCore was updated to version of August 1, 2024.</PackageReleaseNotes>
27+
<PackageReleaseNotes>Optimized a memory usage in the `ReflectionHelpers.GetBestFitMethod` method.</PackageReleaseNotes>
2828
</PropertyGroup>
2929

3030
<ItemGroup>

src/JavaScriptEngineSwitcher.ChakraCore/readme.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
=============
3232
RELEASE NOTES
3333
=============
34-
ChakraCore was updated to version of August 1, 2024.
34+
Optimized a memory usage in the `ReflectionHelpers.GetBestFitMethod` method.
3535

3636
=============
3737
DOCUMENTATION

0 commit comments

Comments
 (0)