Skip to content

Commit 447d73e

Browse files
committed
Reduced a memory allocation by using collection expressions
1 parent d1b5dae commit 447d73e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+322
-284
lines changed

samples/JavaScriptEngineSwitcher.Sample.Logic/Services/FileContentService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ private string GetPhysicalFilePath(string filePath)
8888
#endif
8989
string physicalFilePath = Path.Combine(
9090
applicationDirectoryPath,
91-
filePath.Replace('/', '\\').TrimStart(new char[] { '\\' })
91+
filePath.Replace('/', '\\').TrimStart(['\\'])
9292
);
9393

9494
return physicalFilePath;

src/JavaScriptEngineSwitcher.ChakraCore/ChakraCoreJsEngine.cs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -427,14 +427,11 @@ private WrapperException WrapJsException(OriginalException originalException,
427427
string messageWithTypeAndCallStack = stackPropertyValue.ValueType == JsValueType.String ?
428428
stackPropertyValue.ToString() : string.Empty;
429429
string messageWithType = errorValue.ConvertToString().ToString();
430-
string rawCallStack = messageWithTypeAndCallStack
431-
.TrimStart(messageWithType)
432-
.TrimStart("Error")
433-
.TrimStart(new char[] { '\n', '\r' })
434-
;
430+
string rawCallStack = CoreErrorHelpers.GetErrorLocationFromMessage(
431+
messageWithTypeAndCallStack, messageWithType);
435432
string callStackWithSourceFragment = string.Empty;
436-
437433
ErrorLocationItem[] callStackItems = CoreErrorHelpers.ParseErrorLocation(rawCallStack);
434+
438435
if (callStackItems.Length > 0)
439436
{
440437
ErrorLocationItem firstCallStackItem = callStackItems[0];

src/JavaScriptEngineSwitcher.ChakraCore/Helpers/ReflectionHelpers.cs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,16 @@ namespace JavaScriptEngineSwitcher.ChakraCore.Helpers
2020
internal static class ReflectionHelpers
2121
{
2222
private static readonly PropertyInfo[] _disallowedProperties =
23-
{
23+
[
2424
typeof(Delegate).GetProperty("Method"),
2525
typeof(Exception).GetProperty("TargetSite")
26-
};
26+
];
2727

2828
private static readonly MethodInfo[] _disallowedMethods =
29-
{
29+
[
3030
typeof(object).GetMethod("GetType"),
3131
typeof(Exception).GetMethod("GetType")
32-
};
32+
];
3333

3434

3535
public static BindingFlags GetDefaultBindingFlags(bool instance)
@@ -187,9 +187,8 @@ public static MethodBase GetBestFitMethod(MethodBase[] methods, object[] argValu
187187

188188
try
189189
{
190-
for (int methodIndex = 0; methodIndex < methodCount; methodIndex++)
190+
foreach (MethodBase method in methods)
191191
{
192-
MethodBase method = methods[methodIndex];
193192
ParameterInfo[] parameters = method.GetParameters();
194193
ushort compatibilityScore;
195194

src/JavaScriptEngineSwitcher.ChakraCore/JavaScriptEngineSwitcher.ChakraCore.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@
2727
<PackageReleaseNotes>1. The value of a read-only field in an embedded object or type can no longer be changed;
2828
2. Performed a migration to the modern C# null/not-null checks;
2929
3. Added support for .NET 10;
30-
4. In the `lock` statements for .NET 10 target now uses a instances of the `System.Threading.Lock` class.</PackageReleaseNotes>
30+
4. In the `lock` statements for .NET 10 target now uses a instances of the `System.Threading.Lock` class;
31+
5. Reduced a memory allocation by using collection expressions.</PackageReleaseNotes>
3132
</PropertyGroup>
3233

3334
<ItemGroup>

src/JavaScriptEngineSwitcher.ChakraCore/JsRt/JsValue.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ public byte[] ArrayBufferBytes
263263

264264
if (bufferLength == 0)
265265
{
266-
return new byte[0];
266+
return [];
267267
}
268268

269269
var buffer = new byte[bufferLength];

src/JavaScriptEngineSwitcher.ChakraCore/JsRt/TypeMapper.cs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -330,8 +330,7 @@ private EmbeddedObject CreateEmbeddedFunction(Delegate del)
330330
JsValue functionValue = JsValue.CreateFunction(nativeFunction);
331331
SetNonEnumerableProperty(functionValue, ExternalObjectPropertyName, objValue);
332332

333-
var embeddedObject = new EmbeddedObject(del, functionValue,
334-
new List<JsNativeFunction> { nativeFunction });
333+
var embeddedObject = new EmbeddedObject(del, functionValue, [nativeFunction]);
335334

336335
return embeddedObject;
337336
}
@@ -642,7 +641,7 @@ private void ProjectProperties(EmbeddedItem externalItem)
642641

643642
try
644643
{
645-
result = property.GetValue(obj, new object[0]);
644+
result = property.GetValue(obj, []);
646645
}
647646
catch (Exception e)
648647
{
@@ -698,7 +697,7 @@ private void ProjectProperties(EmbeddedItem externalItem)
698697

699698
try
700699
{
701-
property.SetValue(obj, value, new object[0]);
700+
property.SetValue(obj, value, []);
702701
}
703702
catch (Exception e)
704703
{
@@ -842,7 +841,7 @@ private Dictionary<string, List<MethodInfo>> GetAvailableMethodGroups(MethodInfo
842841
int methodCount = methods.Length;
843842
if (methodCount == 0)
844843
{
845-
return new Dictionary<string, List<MethodInfo>>();
844+
return [];
846845
}
847846

848847
var availableMethodGroups = new Dictionary<string, List<MethodInfo>>(methodCount);
@@ -864,7 +863,7 @@ private Dictionary<string, List<MethodInfo>> GetAvailableMethodGroups(MethodInfo
864863
}
865864
else
866865
{
867-
methodGroup = new List<MethodInfo> { method };
866+
methodGroup = [method];
868867
availableMethodGroups.Add(methodName, methodGroup);
869868
}
870869
}
@@ -899,7 +898,7 @@ private object[] GetHostItemMemberArguments(JsValue[] args, int maxArgCount = -1
899898
}
900899
else
901900
{
902-
processedArgs = new object[0];
901+
processedArgs = [];
903902
}
904903

905904
return processedArgs;

src/JavaScriptEngineSwitcher.ChakraCore/readme.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@
3636
2. Performed a migration to the modern C# null/not-null checks;
3737
3. Added support for .NET 10;
3838
4. In the `lock` statements for .NET 10 target now uses a instances of the
39-
`System.Threading.Lock` class.
39+
`System.Threading.Lock` class;
40+
5. Reduced a memory allocation by using collection expressions.
4041

4142
=============
4243
DOCUMENTATION

src/JavaScriptEngineSwitcher.Core/Extensions/StringExtensions.cs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ namespace JavaScriptEngineSwitcher.Core.Extensions
77
/// </summary>
88
public static class StringExtensions
99
{
10+
/// <summary>
11+
/// Array of strings used to find the newline
12+
/// </summary>
13+
private static readonly string[] _newLineStrings = ["\r\n", "\r", "\n"];
14+
15+
1016
/// <summary>
1117
/// Returns a value indicating whether the specified quoted string occurs within this string
1218
/// </summary>
@@ -68,14 +74,35 @@ public static string TrimStart(this string source, string trimString)
6874
/// </summary>
6975
/// <param name="source">Instance of <see cref="String"/></param>
7076
/// <returns>An array of lines</returns>
77+
[Obsolete]
7178
public static string[] SplitToLines(this string source)
7279
{
7380
if (source is null)
7481
{
7582
throw new ArgumentNullException(nameof(source));
7683
}
7784

78-
string[] result = source.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None);
85+
string[] result = source.Split(_newLineStrings, StringSplitOptions.None);
86+
87+
return result;
88+
}
89+
90+
/// <summary>
91+
/// Splits a string into lines
92+
/// </summary>
93+
/// <param name="source">Instance of <see cref="String"/></param>
94+
/// <param name="options"><see cref="StringSplitOptions.RemoveEmptyEntries"/> to omit empty array
95+
/// elements from the array returned; or <see cref="StringSplitOptions.None"/> to include empty
96+
/// array elements in the array returned</param>
97+
/// <returns>An array of lines</returns>
98+
internal static string[] SplitToLines(this string source, StringSplitOptions options)
99+
{
100+
if (source is null)
101+
{
102+
throw new ArgumentNullException(nameof(source));
103+
}
104+
105+
string[] result = source.Split(_newLineStrings, options);
79106

80107
return result;
81108
}

src/JavaScriptEngineSwitcher.Core/Helpers/JsErrorHelpers.cs

Lines changed: 75 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
using JavaScriptEngineSwitcher.Core.Extensions;
1111
using JavaScriptEngineSwitcher.Core.Resources;
12+
using JavaScriptEngineSwitcher.Core.Utilities;
1213

1314
namespace JavaScriptEngineSwitcher.Core.Helpers
1415
{
@@ -39,53 +40,107 @@ public static class JsErrorHelpers
3940
@")" +
4041
@"(?: -> (?<sourceFragment>[^\n\r]+))?$");
4142

43+
44+
/// <summary>
45+
/// Gets a string representation of the script error location
46+
/// </summary>
47+
/// <param name="message">Error message with the script error location</param>
48+
/// <param name="messageWithoutErrorLocation">Error message without the script error location</param>
49+
/// <returns>String representation of the script error location</returns>
50+
public static string GetErrorLocationFromMessage(string message, string messageWithoutErrorLocation)
51+
{
52+
if (string.IsNullOrWhiteSpace(message))
53+
{
54+
return string.Empty;
55+
}
56+
57+
if (string.IsNullOrWhiteSpace(messageWithoutErrorLocation))
58+
{
59+
return message;
60+
}
61+
62+
string errorLocation = message
63+
.TrimStart(messageWithoutErrorLocation)
64+
.TrimStart(EnvironmentShortcuts.NewLineChars)
65+
;
66+
67+
return errorLocation;
68+
}
69+
4270
/// <summary>
4371
/// Parses a string representation of the script error location to produce an array of
4472
/// <see cref="ErrorLocationItem"/> instances
4573
/// </summary>
4674
/// <param name="errorLocation">String representation of the script error location</param>
4775
/// <returns>An array of <see cref="ErrorLocationItem"/> instances</returns>
4876
public static ErrorLocationItem[] ParseErrorLocation(string errorLocation)
77+
{
78+
return ParseErrorLocation(errorLocation, MapErrorLocationItem);
79+
}
80+
81+
/// <summary>
82+
/// Parses a string representation of the script error location to produce an array of
83+
/// <see cref="ErrorLocationItem"/> instances
84+
/// </summary>
85+
/// <param name="errorLocation">String representation of the script error location</param>
86+
/// <param name="itemMapper">Error location item mapper</param>
87+
/// <returns>An array of <see cref="ErrorLocationItem"/> instances</returns>
88+
public static ErrorLocationItem[] ParseErrorLocation(string errorLocation,
89+
Func<string, ErrorLocationItem> itemMapper)
4990
{
5091
if (string.IsNullOrWhiteSpace(errorLocation))
5192
{
52-
return new ErrorLocationItem[0];
93+
return [];
5394
}
5495

55-
var errorLocationItems = new List<ErrorLocationItem>();
56-
string[] lines = errorLocation.SplitToLines();
96+
if (itemMapper is null)
97+
{
98+
throw new ArgumentNullException(nameof(itemMapper));
99+
}
100+
101+
string[] lines = errorLocation.SplitToLines(StringSplitOptions.RemoveEmptyEntries);
57102
int lineCount = lines.Length;
103+
var errorLocationItems = new List<ErrorLocationItem>(lineCount);
58104

59-
for (int lineIndex = 0; lineIndex < lineCount; lineIndex++)
105+
foreach (string line in lines)
60106
{
61-
string line = lines[lineIndex];
62-
Match lineMatch = _errorLocationLineRegex.Match(line);
63-
64-
if (lineMatch.Success)
107+
ErrorLocationItem errorLocationItem = itemMapper(line);
108+
if (errorLocationItem is not null)
65109
{
66-
GroupCollection lineGroups = lineMatch.Groups;
67-
68-
var errorLocationItem = new ErrorLocationItem
69-
{
70-
FunctionName = lineGroups["functionName"].Value,
71-
DocumentName = lineGroups["documentName"].Value,
72-
LineNumber = int.Parse(lineGroups["lineNumber"].Value),
73-
ColumnNumber = lineGroups["columnNumber"].Success ?
74-
int.Parse(lineGroups["columnNumber"].Value) : 0,
75-
SourceFragment = lineGroups["sourceFragment"].Value
76-
};
77110
errorLocationItems.Add(errorLocationItem);
78111
}
79112
else
80113
{
81114
Debug.WriteLine(string.Format(Strings.Runtime_InvalidErrorLocationLineFormat, line));
82-
return new ErrorLocationItem[0];
115+
return [];
83116
}
84117
}
85118

86119
return errorLocationItems.ToArray();
87120
}
88121

122+
private static ErrorLocationItem MapErrorLocationItem(string errorLocationLine)
123+
{
124+
ErrorLocationItem item = null;
125+
Match lineMatch = _errorLocationLineRegex.Match(errorLocationLine);
126+
127+
if (lineMatch.Success)
128+
{
129+
GroupCollection lineGroups = lineMatch.Groups;
130+
item = new ErrorLocationItem
131+
{
132+
FunctionName = lineGroups["functionName"].Value,
133+
DocumentName = lineGroups["documentName"].Value,
134+
LineNumber = int.Parse(lineGroups["lineNumber"].Value),
135+
ColumnNumber = lineGroups["columnNumber"].Success ?
136+
int.Parse(lineGroups["columnNumber"].Value) : 0,
137+
SourceFragment = lineGroups["sourceFragment"].Value
138+
};
139+
}
140+
141+
return item;
142+
}
143+
89144
/// <summary>
90145
/// Produces a string representation of the script error location from array of
91146
/// <see cref="ErrorLocationItem"/> instances

src/JavaScriptEngineSwitcher.Core/Helpers/TextHelpers.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using AdvancedStringBuilder;
55

66
using JavaScriptEngineSwitcher.Core.Extensions;
7+
using JavaScriptEngineSwitcher.Core.Utilities;
78

89
namespace JavaScriptEngineSwitcher.Core.Helpers
910
{
@@ -15,7 +16,7 @@ public static class TextHelpers
1516
/// <summary>
1617
/// Array of characters used to find the next line break
1718
/// </summary>
18-
private static readonly char[] _nextLineBreakChars = new char[] { '\r', '\n' };
19+
private static readonly char[] _nextLineBreakChars = EnvironmentShortcuts.NewLineChars;
1920

2021

2122
/// <summary>

0 commit comments

Comments
 (0)