Skip to content

Commit 9bd973b

Browse files
committed
In JavaScriptEngineSwitcher.ChakraCore optimized a memory usage by using unsafe code
1 parent 8b1fe69 commit 9bd973b

File tree

7 files changed

+108
-14
lines changed

7 files changed

+108
-14
lines changed

src/JavaScriptEngineSwitcher.ChakraCore/ChakraCorePrecompiledScript.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,10 @@ private bool LoadScriptSourceCode(JsSourceContext sourceContext,
9191
parseAttributes = ParseAttributes;
9292
Encoding encoding = parseAttributes.HasFlag(JsParseScriptAttributes.ArrayBufferIsUtf16Encoded) ?
9393
Encoding.Unicode : Encoding.UTF8;
94-
byte[] bytes = encoding.GetBytes(Code);
9594

9695
try
9796
{
98-
value = JsValue.CreateExternalArrayBuffer(bytes);
97+
value = JsValue.CreateExternalArrayBuffer(Code, encoding);
9998
result = true;
10099
}
101100
catch (OriginalException)
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#if NET471 || NETSTANDARD
2+
using System;
3+
using System.Runtime.InteropServices;
4+
#endif
5+
using System.Text;
6+
7+
namespace JavaScriptEngineSwitcher.ChakraCore.Helpers
8+
{
9+
/// <summary>
10+
/// Encoding helpers
11+
/// </summary>
12+
internal static class EncodingHelpers
13+
{
14+
#if NET471 || NETSTANDARD
15+
public static unsafe string UnicodeToUtf8(string value, out int byteCount)
16+
#else
17+
public static string UnicodeToUtf8(string value, out int byteCount)
18+
#endif
19+
{
20+
if (string.IsNullOrEmpty(value))
21+
{
22+
byteCount = 0;
23+
return value;
24+
}
25+
26+
string result;
27+
#if NET471 || NETSTANDARD
28+
byteCount = Encoding.UTF8.GetByteCount(value);
29+
IntPtr bufferPtr = Marshal.AllocHGlobal(byteCount);
30+
31+
try
32+
{
33+
fixed (char* pValue = value)
34+
{
35+
Encoding.UTF8.GetBytes(pValue, value.Length, (byte*)bufferPtr, byteCount);
36+
}
37+
38+
result = Encoding.GetEncoding(0).GetString((byte*)bufferPtr, byteCount);
39+
}
40+
finally
41+
{
42+
Marshal.FreeHGlobal(bufferPtr);
43+
}
44+
#else
45+
byte[] bytes = Encoding.UTF8.GetBytes(value);
46+
byteCount = bytes.Length;
47+
result = Encoding.GetEncoding(0).GetString(bytes);
48+
#endif
49+
50+
return result;
51+
}
52+
}
53+
}

src/JavaScriptEngineSwitcher.ChakraCore/JavaScriptEngineSwitcher.ChakraCore.csproj

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
<TargetFrameworks>net40-client;net45;net471;netstandard1.3;netstandard2.0</TargetFrameworks>
88
<NetStandardImplicitPackageVersion Condition=" '$(TargetFramework)' == 'netstandard1.3' ">1.6.0</NetStandardImplicitPackageVersion>
99
<OutputType>Library</OutputType>
10+
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
1011
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
1112
<NoWarn>$(NoWarn);CS1591</NoWarn>
1213
<GenerateDocumentationFile>true</GenerateDocumentationFile>
@@ -22,7 +23,8 @@ This package does not contain the native implementations of ChakraCore. Therefor
2223
* JavaScriptEngineSwitcher.ChakraCore.Native.osx-x64</Description>
2324
<PackageIconUrl>https://raw.githubusercontent.com/Taritsyn/JavaScriptEngineSwitcher/master/Icons/JavaScriptEngineSwitcher_ChakraCore_Logo128x128.png</PackageIconUrl>
2425
<PackageTags>JavaScriptEngineSwitcher;JavaScript;ECMAScript;ChakraCore</PackageTags>
25-
<PackageReleaseNotes>No longer used the old ChakraCore API for Windows (Internet Explorer-like API).</PackageReleaseNotes>
26+
<PackageReleaseNotes>1. No longer used the old ChakraCore API for Windows (Internet Explorer-like API);
27+
2. Optimized a memory usage.</PackageReleaseNotes>
2628
</PropertyGroup>
2729

2830
<Import Project="../../build/common.props" />

src/JavaScriptEngineSwitcher.ChakraCore/JsRt/JsContext.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
using System;
2-
using System.Text;
3-
#if NET45 || NET471 || NETSTANDARD
42
using System.Runtime.InteropServices;
5-
#endif
3+
using System.Text;
64
#if NET40
75

86
using JavaScriptEngineSwitcher.Core.Polyfills.System.Runtime.InteropServices;
@@ -366,8 +364,7 @@ private static JsValue CreateExternalArrayBufferFromScriptCode(string script,
366364
encoding = Encoding.UTF8;
367365
}
368366

369-
byte[] scriptBytes = encoding.GetBytes(script);
370-
JsValue scriptValue = JsValue.CreateExternalArrayBuffer(scriptBytes);
367+
JsValue scriptValue = JsValue.CreateExternalArrayBuffer(script, encoding);
371368

372369
return scriptValue;
373370
}

src/JavaScriptEngineSwitcher.ChakraCore/JsRt/JsPropertyId.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
using JavaScriptEngineSwitcher.Core.Polyfills.System.Runtime.InteropServices;
99
#endif
1010

11+
using JavaScriptEngineSwitcher.ChakraCore.Helpers;
12+
1113
namespace JavaScriptEngineSwitcher.ChakraCore.JsRt
1214
{
1315
/// <summary>
@@ -93,16 +95,14 @@ public static JsPropertyId FromString(string name)
9395
string processedName;
9496
int byteCount;
9597

96-
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && !string.IsNullOrEmpty(name))
98+
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
9799
{
98-
byte[] bytes = Encoding.UTF8.GetBytes(name);
99-
processedName = Encoding.GetEncoding(0).GetString(bytes);
100-
byteCount = bytes.Length;
100+
processedName = EncodingHelpers.UnicodeToUtf8(name, out byteCount);
101101
}
102102
else
103103
{
104104
processedName = name;
105-
byteCount = Encoding.UTF8.GetByteCount(name);
105+
byteCount = Encoding.UTF8.GetByteCount(processedName);
106106
}
107107

108108
JsPropertyId id;

src/JavaScriptEngineSwitcher.ChakraCore/JsRt/JsValue.cs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,47 @@ public static JsValue CreateExternalArrayBuffer(byte[] buffer)
474474
return reference;
475475
}
476476

477+
/// <summary>
478+
/// Creates a Javascript <c>ArrayBuffer</c> object to access external memory
479+
/// </summary>
480+
/// <remarks>Requires an active script context.</remarks>
481+
/// <param name="value">String value</param>
482+
/// <param name="encoding">Character encoding</param>
483+
/// <returns>The new <c>ArrayBuffer</c> object</returns>
484+
public static unsafe JsValue CreateExternalArrayBuffer(string value, Encoding encoding)
485+
{
486+
int bufferLength;
487+
IntPtr bufferPtr;
488+
JsObjectFinalizeCallback finalizeCallback;
489+
490+
if (value != null)
491+
{
492+
bufferLength = encoding.GetByteCount(value);
493+
bufferPtr = Marshal.AllocHGlobal(bufferLength);
494+
495+
fixed (char* pScript = value)
496+
{
497+
encoding.GetBytes(pScript, value.Length, (byte*)bufferPtr, bufferLength);
498+
}
499+
500+
finalizeCallback = DefaultExternalBufferFinalizeCallback.Instance;
501+
}
502+
else
503+
{
504+
bufferLength = 0;
505+
bufferPtr = IntPtr.Zero;
506+
finalizeCallback = null;
507+
}
508+
509+
JsValue reference;
510+
JsErrorCode errorCode = NativeMethods.JsCreateExternalArrayBuffer(bufferPtr, (uint)bufferLength,
511+
finalizeCallback, bufferPtr, out reference);
512+
JsErrorHelpers.ThrowIfError(errorCode);
513+
514+
return reference;
515+
}
516+
517+
477518
/// <summary>
478519
/// Creates a new JavaScript error object
479520
/// </summary>

src/JavaScriptEngineSwitcher.ChakraCore/readme.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@
3030
=============
3131
RELEASE NOTES
3232
=============
33-
No longer used the old ChakraCore API for Windows (Internet Explorer-like API).
33+
1. No longer used the old ChakraCore API for Windows (Internet Explorer-like
34+
API);
35+
2. Optimized a memory usage.
3436

3537
=============
3638
DOCUMENTATION

0 commit comments

Comments
 (0)