Skip to content

Commit 48c682a

Browse files
committed
In JavaScriptEngineSwitcher.ChakraCore fixed a errors that occurred when accessing to the external memory
1 parent 6753a71 commit 48c682a

File tree

12 files changed

+360
-397
lines changed

12 files changed

+360
-397
lines changed

src/JavaScriptEngineSwitcher.ChakraCore/ChakraCoreJsEngine.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1406,10 +1406,12 @@ protected override void InnerExecute(IPrecompiledScript precompiledScript)
14061406
{
14071407
throw WrapJsException(e);
14081408
}
1409+
finally
1410+
{
1411+
GC.KeepAlive(chakraCorePrecompiledScript);
1412+
}
14091413
}
14101414
});
1411-
1412-
GC.KeepAlive(chakraCorePrecompiledScript);
14131415
}
14141416

14151417
protected override object InnerCallFunction(string functionName, params object[] args)

src/JavaScriptEngineSwitcher.ChakraCore/ChakraCorePrecompiledScript.cs

Lines changed: 60 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
using System.Runtime.InteropServices;
2-
using System.Text;
1+
using System.Text;
32

43
using JavaScriptEngineSwitcher.Core;
54

@@ -14,53 +13,78 @@ namespace JavaScriptEngineSwitcher.ChakraCore
1413
internal sealed class ChakraCorePrecompiledScript : IPrecompiledScript
1514
{
1615
/// <summary>
17-
/// Callback for finalization of external buffer
16+
/// Source code of the script
1817
/// </summary>
19-
private JsObjectFinalizeCallback _externalBufferFinalizeCallback;
18+
private readonly string _code;
19+
20+
/// <summary>
21+
/// Attribute mask for parsing the script
22+
/// </summary>
23+
private readonly JsParseScriptAttributes _parseAttributes;
24+
25+
/// <summary>
26+
/// Cached data for accelerated recompilation
27+
/// </summary>
28+
private readonly byte[] _cachedBytes;
29+
30+
/// <summary>
31+
/// Document name
32+
/// </summary>
33+
private readonly string _documentName;
34+
35+
/// <summary>
36+
/// Callback to load the source code of the serialized script
37+
/// </summary>
38+
private readonly JsSerializedLoadScriptCallback _loadScriptSourceCodeCallback;
39+
40+
/// <summary>
41+
/// Source code of the script as an array of bytes
42+
/// </summary>
43+
private byte[] _codeBytes;
44+
45+
/// <summary>
46+
/// Synchronizer of the script source code loading
47+
/// </summary>
48+
private readonly object _scriptLoadingSynchronizer = new object();
2049

2150
/// <summary>
2251
/// Gets a source code of the script
2352
/// </summary>
2453
public string Code
2554
{
26-
get;
27-
private set;
55+
get { return _code; }
2856
}
2957

3058
/// <summary>
3159
/// Gets a attribute mask for parsing the script
3260
/// </summary>
3361
public JsParseScriptAttributes ParseAttributes
3462
{
35-
get;
36-
private set;
63+
get { return _parseAttributes; }
3764
}
3865

3966
/// <summary>
4067
/// Gets a cached data for accelerated recompilation
4168
/// </summary>
4269
public byte[] CachedBytes
4370
{
44-
get;
45-
private set;
71+
get { return _cachedBytes; }
4672
}
4773

4874
/// <summary>
4975
/// Gets a document name
5076
/// </summary>
5177
public string DocumentName
5278
{
53-
get;
54-
private set;
79+
get { return _documentName; }
5580
}
5681

5782
/// <summary>
5883
/// Gets a callback to load the source code of the serialized script
5984
/// </summary>
6085
public JsSerializedLoadScriptCallback LoadScriptSourceCodeCallback
6186
{
62-
get;
63-
private set;
87+
get { return _loadScriptSourceCodeCallback; }
6488
}
6589

6690

@@ -74,13 +98,11 @@ public JsSerializedLoadScriptCallback LoadScriptSourceCodeCallback
7498
public ChakraCorePrecompiledScript(string code, JsParseScriptAttributes parseAttributes, byte[] cachedBytes,
7599
string documentName)
76100
{
77-
_externalBufferFinalizeCallback = Marshal.FreeHGlobal;
78-
79-
Code = code;
80-
ParseAttributes = parseAttributes;
81-
CachedBytes = cachedBytes;
82-
DocumentName = documentName;
83-
LoadScriptSourceCodeCallback = LoadScriptSourceCode;
101+
_code = code;
102+
_parseAttributes = parseAttributes;
103+
_cachedBytes = cachedBytes;
104+
_documentName = documentName;
105+
_loadScriptSourceCodeCallback = LoadScriptSourceCode;
84106
}
85107

86108

@@ -92,17 +114,28 @@ public ChakraCorePrecompiledScript(string code, JsParseScriptAttributes parseAtt
92114
/// <param name="value">The script returned</param>
93115
/// <param name="parseAttributes">Attribute mask for parsing the script</param>
94116
/// <returns>true if the operation succeeded, false otherwise</returns>
95-
private bool LoadScriptSourceCode(JsSourceContext sourceContext,
96-
out JsValue value, out JsParseScriptAttributes parseAttributes)
117+
private bool LoadScriptSourceCode(JsSourceContext sourceContext, out JsValue value,
118+
out JsParseScriptAttributes parseAttributes)
97119
{
120+
if (_codeBytes == null)
121+
{
122+
lock (_scriptLoadingSynchronizer)
123+
{
124+
if (_codeBytes == null)
125+
{
126+
Encoding encoding = _parseAttributes.HasFlag(JsParseScriptAttributes.ArrayBufferIsUtf16Encoded) ?
127+
Encoding.Unicode : Encoding.UTF8;
128+
_codeBytes = encoding.GetBytes(_code);
129+
}
130+
}
131+
}
132+
98133
bool result;
99-
parseAttributes = ParseAttributes;
100-
Encoding encoding = parseAttributes.HasFlag(JsParseScriptAttributes.ArrayBufferIsUtf16Encoded) ?
101-
Encoding.Unicode : Encoding.UTF8;
134+
parseAttributes = _parseAttributes;
102135

103136
try
104137
{
105-
value = JsValue.CreateExternalArrayBuffer(Code, encoding, _externalBufferFinalizeCallback);
138+
value = JsValue.CreateExternalArrayBuffer(_codeBytes);
106139
result = true;
107140
}
108141
catch (OriginalException)

src/JavaScriptEngineSwitcher.ChakraCore/Helpers/EncodingHelpers.cs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,23 +22,35 @@ public static string UnicodeToAnsi(string value, out int byteCount)
2222
return value;
2323
}
2424

25+
int valueLength = value.Length;
2526
Encoding utf8Encoding = Encoding.UTF8;
2627
Encoding ansiEncoding = Encoding.GetEncoding(0);
2728

2829
var byteArrayPool = ArrayPool<byte>.Shared;
2930
int bufferLength = utf8Encoding.GetByteCount(value);
30-
byte[] buffer = byteArrayPool.Rent(bufferLength);
31+
byte[] buffer = byteArrayPool.Rent(bufferLength + 1);
32+
33+
string result;
34+
#if NET471 || NETSTANDARD || NETCOREAPP2_1
3135

3236
unsafe
3337
{
3438
fixed (char* pValue = value)
3539
fixed (byte* pBuffer = buffer)
3640
{
37-
utf8Encoding.GetBytes(pValue, value.Length, pBuffer, bufferLength);
41+
utf8Encoding.GetBytes(pValue, valueLength, pBuffer, bufferLength);
42+
pBuffer[bufferLength] = 0;
43+
44+
result = ansiEncoding.GetString(pBuffer, bufferLength);
3845
}
3946
}
4047

41-
string result = ansiEncoding.GetString(buffer, 0, bufferLength);
48+
#else
49+
utf8Encoding.GetBytes(value, 0, valueLength, buffer, 0);
50+
buffer[bufferLength] = 0;
51+
52+
result = ansiEncoding.GetString(buffer, 0, bufferLength);
53+
#endif
4254
byteCount = ansiEncoding.GetByteCount(result);
4355

4456
byteArrayPool.Return(buffer);

src/JavaScriptEngineSwitcher.ChakraCore/JavaScriptEngineSwitcher.ChakraCore.csproj

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,7 @@ This package does not contain the native implementations of ChakraCore. Therefor
2323
* JavaScriptEngineSwitcher.ChakraCore.Native.osx-x64</Description>
2424
<PackageIconUrl>https://raw.githubusercontent.com/Taritsyn/JavaScriptEngineSwitcher/master/Icons/JavaScriptEngineSwitcher_ChakraCore_Logo128x128.png</PackageIconUrl>
2525
<PackageTags>JavaScriptEngineSwitcher;JavaScript;ECMAScript;ChakraCore</PackageTags>
26-
<PackageReleaseNotes>1. ChakraCore was updated to version 1.11.4;
27-
2. Improved a performance of script pre-compilation.</PackageReleaseNotes>
26+
<PackageReleaseNotes>Fixed a errors that occurred when accessing to the external memory.</PackageReleaseNotes>
2827
</PropertyGroup>
2928

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

src/JavaScriptEngineSwitcher.ChakraCore/JsRt/JsContext.cs

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ public static uint Idle()
164164
public static JsValue ParseScript(string script, JsSourceContext sourceContext, string sourceUrl,
165165
ref JsParseScriptAttributes parseAttributes)
166166
{
167-
JsPooledArrayBuffer scriptBuffer = CreatePooledArrayBufferFromScriptCode(script, ref parseAttributes);
167+
JsExternalByteArrayBuffer scriptBuffer = CreateByteArrayBufferFromScriptCode(script, ref parseAttributes);
168168

169169
JsValue sourceUrlValue = JsValue.FromString(sourceUrl);
170170
sourceUrlValue.AddRef();
@@ -204,8 +204,7 @@ public static JsValue ParseScript(string script, JsSourceContext sourceContext,
204204
public static JsValue ParseSerializedScript(string script, byte[] buffer,
205205
JsSerializedLoadScriptCallback scriptLoadCallback, JsSourceContext sourceContext, string sourceUrl)
206206
{
207-
JsValue bufferValue = JsValue.CreateExternalArrayBuffer(buffer);
208-
bufferValue.AddRef();
207+
JsExternalByteArrayBuffer scriptBuffer = JsExternalByteArrayBuffer.FromBytes(buffer);
209208

210209
JsValue sourceUrlValue = JsValue.FromString(sourceUrl);
211210
sourceUrlValue.AddRef();
@@ -214,18 +213,16 @@ public static JsValue ParseSerializedScript(string script, byte[] buffer,
214213

215214
try
216215
{
217-
JsErrorCode errorCode = NativeMethods.JsParseSerialized(bufferValue, scriptLoadCallback, sourceContext,
218-
sourceUrlValue, out result);
216+
JsErrorCode errorCode = NativeMethods.JsParseSerialized(scriptBuffer.Value, scriptLoadCallback,
217+
sourceContext, sourceUrlValue, out result);
219218
JsErrorHelpers.ThrowIfError(errorCode);
220219
}
221220
finally
222221
{
223-
bufferValue.Release();
222+
scriptBuffer.Dispose();
224223
sourceUrlValue.Release();
225224
}
226225

227-
GC.KeepAlive(buffer);
228-
229226
return result;
230227
}
231228

@@ -244,7 +241,7 @@ public static JsValue ParseSerializedScript(string script, byte[] buffer,
244241
public static JsValue RunScript(string script, JsSourceContext sourceContext, string sourceUrl,
245242
ref JsParseScriptAttributes parseAttributes)
246243
{
247-
JsPooledArrayBuffer scriptBuffer = CreatePooledArrayBufferFromScriptCode(script, ref parseAttributes);
244+
JsExternalByteArrayBuffer scriptBuffer = CreateByteArrayBufferFromScriptCode(script, ref parseAttributes);
248245

249246
JsValue sourceUrlValue = JsValue.FromString(sourceUrl);
250247
sourceUrlValue.AddRef();
@@ -284,8 +281,7 @@ public static JsValue RunScript(string script, JsSourceContext sourceContext, st
284281
public static JsValue RunSerializedScript(string script, byte[] buffer,
285282
JsSerializedLoadScriptCallback scriptLoadCallback, JsSourceContext sourceContext, string sourceUrl)
286283
{
287-
JsValue bufferValue = JsValue.CreateExternalArrayBuffer(buffer);
288-
bufferValue.AddRef();
284+
JsExternalByteArrayBuffer scriptBuffer = JsExternalByteArrayBuffer.FromBytes(buffer);
289285

290286
JsValue sourceUrlValue = JsValue.FromString(sourceUrl);
291287
sourceUrlValue.AddRef();
@@ -294,18 +290,16 @@ public static JsValue RunSerializedScript(string script, byte[] buffer,
294290

295291
try
296292
{
297-
JsErrorCode errorCode = NativeMethods.JsRunSerialized(bufferValue, scriptLoadCallback, sourceContext,
298-
sourceUrlValue, out result);
293+
JsErrorCode errorCode = NativeMethods.JsRunSerialized(scriptBuffer.Value, scriptLoadCallback,
294+
sourceContext, sourceUrlValue, out result);
299295
JsErrorHelpers.ThrowIfError(errorCode);
300296
}
301297
finally
302298
{
303-
bufferValue.Release();
299+
scriptBuffer.Dispose();
304300
sourceUrlValue.Release();
305301
}
306302

307-
GC.KeepAlive(buffer);
308-
309303
return result;
310304
}
311305

@@ -327,7 +321,7 @@ public static JsValue RunSerializedScript(string script, byte[] buffer,
327321
/// <returns>The buffer to put the serialized script into</returns>
328322
public static byte[] SerializeScript(string script, ref JsParseScriptAttributes parseAttributes)
329323
{
330-
JsPooledArrayBuffer scriptBuffer = CreatePooledArrayBufferFromScriptCode(script, ref parseAttributes);
324+
JsExternalByteArrayBuffer scriptBuffer = CreateByteArrayBufferFromScriptCode(script, ref parseAttributes);
331325
JsValue bufferValue;
332326

333327
try
@@ -346,12 +340,12 @@ public static byte[] SerializeScript(string script, ref JsParseScriptAttributes
346340
}
347341

348342
/// <summary>
349-
/// Creates a pooled Javascript <c>ArrayBuffer</c> object from script code
343+
/// Creates a wrapper for the Javascript ArrayBuffer from script code
350344
/// </summary>
351345
/// <param name="script">Script code</param>
352346
/// <param name="parseAttributes">Attribute mask for parsing the script</param>
353-
/// <returns>Instance of <see cref="JsPooledArrayBuffer"/></returns>
354-
private static JsPooledArrayBuffer CreatePooledArrayBufferFromScriptCode(string script,
347+
/// <returns>Instance of wrapper for the Javascript ArrayBuffer</returns>
348+
private static JsExternalByteArrayBuffer CreateByteArrayBufferFromScriptCode(string script,
355349
ref JsParseScriptAttributes parseAttributes)
356350
{
357351
Encoding encoding;
@@ -366,7 +360,7 @@ private static JsPooledArrayBuffer CreatePooledArrayBufferFromScriptCode(string
366360
encoding = Encoding.UTF8;
367361
}
368362

369-
JsPooledArrayBuffer scriptBuffer = JsPooledArrayBuffer.Create(script, encoding);
363+
JsExternalByteArrayBuffer scriptBuffer = JsExternalByteArrayBuffer.FromString(script, encoding);
370364

371365
return scriptBuffer;
372366
}

0 commit comments

Comments
 (0)