Skip to content

Commit 3cd1b16

Browse files
committed
In JavaScriptEngineSwitcher.ChakraCore:
1. Changed a implementation of the `Dispose` method; 2. Prevented a early destruction of delegates, which have been passed to the native methods.
1 parent a65ad2a commit 3cd1b16

File tree

8 files changed

+113
-114
lines changed

8 files changed

+113
-114
lines changed

global.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
22
"sdk": {
3-
"version": "2.1.200"
3+
"version": "2.1.300"
44
}
55
}

src/JavaScriptEngineSwitcher.ChakraCore/ChakraCoreJsEngine.cs

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ public sealed class ChakraCoreJsEngine : JsEngineBase
7373
/// <summary>
7474
/// Set of external objects
7575
/// </summary>
76-
private readonly HashSet<object> _externalObjects = new HashSet<object>();
76+
private HashSet<object> _externalObjects = new HashSet<object>();
7777

7878
/// <summary>
7979
/// Callback for finalization of external object
@@ -88,7 +88,7 @@ public sealed class ChakraCoreJsEngine : JsEngineBase
8888
/// <summary>
8989
/// List of native function callbacks
9090
/// </summary>
91-
private readonly HashSet<JsNativeFunction> _nativeFunctions = new HashSet<JsNativeFunction>();
91+
private HashSet<JsNativeFunction> _nativeFunctions = new HashSet<JsNativeFunction>();
9292

9393
/// <summary>
9494
/// Script dispatcher
@@ -476,15 +476,12 @@ private void ExternalObjectFinalizeCallback(IntPtr data)
476476
GCHandle handle = GCHandle.FromIntPtr(data);
477477
object obj = handle.Target;
478478

479-
if (obj == null)
480-
{
481-
return;
482-
}
483-
484-
if (_externalObjects != null)
479+
if (obj != null && _externalObjects != null)
485480
{
486481
_externalObjects.Remove(obj);
487482
}
483+
484+
handle.Free();
488485
}
489486

490487
private JsValue CreateObjectFromType(Type type)
@@ -1379,7 +1376,8 @@ protected override void InnerExecute(IPrecompiledScript precompiledScript)
13791376
try
13801377
{
13811378
JsContext.RunSerializedScript(chakraCorePrecompiledScript.Code,
1382-
chakraCorePrecompiledScript.CachedBytes, _jsSourceContext++,
1379+
chakraCorePrecompiledScript.CachedBytes,
1380+
chakraCorePrecompiledScript.LoadScriptSourceCodeCallback, _jsSourceContext++,
13831381
chakraCorePrecompiledScript.DocumentName);
13841382
}
13851383
catch (OriginalException e)
@@ -1388,6 +1386,8 @@ protected override void InnerExecute(IPrecompiledScript precompiledScript)
13881386
}
13891387
}
13901388
});
1389+
1390+
GC.KeepAlive(chakraCorePrecompiledScript);
13911391
}
13921392

13931393
protected override object InnerCallFunction(string functionName, params object[] args)
@@ -1687,27 +1687,45 @@ private void Dispose(bool disposing)
16871687
{
16881688
if (_disposedFlag.Set())
16891689
{
1690-
if (_dispatcher != null)
1690+
if (disposing)
16911691
{
1692-
_dispatcher.Dispose();
1693-
_dispatcher = null;
1694-
}
1692+
if (_dispatcher != null)
1693+
{
1694+
_dispatcher.Invoke(DisposeUnmanagedResources);
16951695

1696-
if (_jsContext.IsValid)
1697-
{
1698-
_jsContext.Release();
1699-
}
1700-
_jsRuntime.Dispose();
1696+
_dispatcher.Dispose();
1697+
_dispatcher = null;
1698+
}
17011699

1702-
if (disposing)
1703-
{
1704-
_externalObjects?.Clear();
1705-
_nativeFunctions?.Clear();
1700+
if (_externalObjects != null)
1701+
{
1702+
_externalObjects.Clear();
1703+
_externalObjects = null;
1704+
}
1705+
1706+
if (_nativeFunctions != null)
1707+
{
1708+
_nativeFunctions.Clear();
1709+
_nativeFunctions = null;
1710+
}
17061711

17071712
_promiseContinuationCallback = null;
17081713
_externalObjectFinalizeCallback = null;
17091714
}
1715+
else
1716+
{
1717+
DisposeUnmanagedResources();
1718+
}
1719+
}
1720+
}
1721+
1722+
private void DisposeUnmanagedResources()
1723+
{
1724+
if (_jsContext.IsValid)
1725+
{
1726+
_jsContext.Release();
17101727
}
1728+
_jsRuntime.Dispose();
17111729
}
17121730

17131731
#endregion

src/JavaScriptEngineSwitcher.ChakraCore/ChakraCorePrecompiledScript.cs

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
using JavaScriptEngineSwitcher.Core;
1+
using System.Text;
2+
3+
using JavaScriptEngineSwitcher.Core;
4+
5+
using JavaScriptEngineSwitcher.ChakraCore.JsRt;
6+
using OriginalException = JavaScriptEngineSwitcher.ChakraCore.JsRt.JsException;
27

38
namespace JavaScriptEngineSwitcher.ChakraCore
49
{
@@ -34,6 +39,15 @@ public string DocumentName
3439
private set;
3540
}
3641

42+
/// <summary>
43+
/// Gets a callback to load the source code of the serialized script
44+
/// </summary>
45+
public JsSerializedLoadScriptCallback LoadScriptSourceCodeCallback
46+
{
47+
get;
48+
private set;
49+
}
50+
3751

3852
/// <summary>
3953
/// Constructs an instance of pre-compiled script
@@ -46,9 +60,39 @@ public ChakraCorePrecompiledScript(string code, byte[] cachedBytes, string docum
4660
Code = code;
4761
CachedBytes = cachedBytes;
4862
DocumentName = documentName;
63+
LoadScriptSourceCodeCallback = LoadScriptSourceCode;
4964
}
5065

5166

67+
/// <summary>
68+
/// Loads a source code of the serialized script
69+
/// </summary>
70+
/// <param name="sourceContext">A cookie identifying the script that can be used
71+
/// by debuggable script contexts</param>
72+
/// <param name="value">The script returned</param>
73+
/// <param name="parseAttributes">Attribute mask for parsing the script</param>
74+
/// <returns>true if the operation succeeded, false otherwise</returns>
75+
private bool LoadScriptSourceCode(JsSourceContext sourceContext,
76+
out JsValue value, out JsParseScriptAttributes parseAttributes)
77+
{
78+
bool result;
79+
parseAttributes = JsParseScriptAttributes.None;
80+
byte[] bytes = Encoding.GetEncoding(0).GetBytes(Code);
81+
82+
try
83+
{
84+
value = JsValue.CreateExternalArrayBuffer(bytes);
85+
result = true;
86+
}
87+
catch (OriginalException)
88+
{
89+
value = JsValue.Invalid;
90+
result = false;
91+
}
92+
93+
return result;
94+
}
95+
5296
#region IPrecompiledScript implementation
5397

5498
/// <summary>

src/JavaScriptEngineSwitcher.ChakraCore/JavaScriptEngineSwitcher.ChakraCore.csproj

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,8 @@ This package does not contain the native implementations of ChakraCore. Therefor
2222
* JavaScriptEngineSwitcher.ChakraCore.Native.osx-x64</Description>
2323
<PackageIconUrl>https://raw.githubusercontent.com/Taritsyn/JavaScriptEngineSwitcher/master/Icons/JavaScriptEngineSwitcher_ChakraCore_Logo128x128.png</PackageIconUrl>
2424
<PackageTags>JavaScriptEngineSwitcher;JavaScript;ECMAScript;ChakraCore</PackageTags>
25-
<PackageReleaseNotes>1. Added support of .NET Framework 4.7.1;
26-
2. Fixed a implementation of the `JsSerializedLoadScriptCallback` delegate;
27-
3. Fixed a error #34 “Finalazier thread is blocked because of JavaScriptEngineSwitcher.ChakraCore.ChakraCoreJsEngine”.</PackageReleaseNotes>
25+
<PackageReleaseNotes>1. Changed a implementation of the `Dispose` method;
26+
2. Prevented a early destruction of delegates, which have been passed to the native methods.</PackageReleaseNotes>
2827
</PropertyGroup>
2928

3029
<Import Project="../../build/common.props" />
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using System.Runtime.InteropServices;
2+
3+
namespace JavaScriptEngineSwitcher.ChakraCore.JsRt
4+
{
5+
/// <summary>
6+
/// Default callback for finalization of external buffer
7+
/// </summary>
8+
internal static class DefaultExternalBufferFinalizeCallback
9+
{
10+
/// <summary>
11+
/// Gets a instance of default callback for finalization of external buffer
12+
/// </summary>
13+
public static readonly JsObjectFinalizeCallback Instance = Marshal.FreeHGlobal;
14+
}
15+
}

src/JavaScriptEngineSwitcher.ChakraCore/JsRt/JsContext.cs

Lines changed: 6 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -149,19 +149,6 @@ public static uint Idle()
149149
return ticks;
150150
}
151151

152-
/// <summary>
153-
/// Parses a script and returns a function representing the script
154-
/// </summary>
155-
/// <remarks>
156-
/// Requires an active script context.
157-
/// </remarks>
158-
/// <param name="script">The script to parse</param>
159-
/// <returns>A function representing the script code</returns>
160-
public static JsValue ParseScript(string script)
161-
{
162-
return ParseScript(script, JsSourceContext.None, string.Empty);
163-
}
164-
165152
/// <summary>
166153
/// Parses a script and returns a function representing the script
167154
/// </summary>
@@ -218,28 +205,13 @@ public static JsValue ParseScript(string script, JsSourceContext sourceContext,
218205
/// </remarks>
219206
/// <param name="script">The script to parse</param>
220207
/// <param name="buffer">The serialized script</param>
221-
/// <returns>A function representing the script code</returns>
222-
public static JsValue ParseSerializedScript(string script, byte[] buffer)
223-
{
224-
return ParseSerializedScript(script, buffer, JsSourceContext.None, string.Empty);
225-
}
226-
227-
/// <summary>
228-
/// Parses a serialized script and returns a function representing the script
229-
/// </summary>
230-
/// <remarks>
231-
/// <para>Requires an active script context.</para>
232-
/// <para>The runtime will hold on to the buffer until all instances of any functions created from
233-
/// the buffer are garbage collected.</para>
234-
/// </remarks>
235-
/// <param name="script">The script to parse</param>
236-
/// <param name="buffer">The serialized script</param>
208+
/// <param name="scriptLoadCallback">Callback to load the source code of the serialized script</param>
237209
/// <param name="sourceContext">A cookie identifying the script that can be used
238210
/// by debuggable script contexts</param>
239211
/// <param name="sourceUrl">The location the script came from</param>
240212
/// <returns>A function representing the script code</returns>
241-
public static JsValue ParseSerializedScript(string script, byte[] buffer, JsSourceContext sourceContext,
242-
string sourceUrl)
213+
public static JsValue ParseSerializedScript(string script, byte[] buffer,
214+
JsSerializedLoadScriptCallback scriptLoadCallback, JsSourceContext sourceContext, string sourceUrl)
243215
{
244216
JsValue result;
245217
JsErrorCode errorCode;
@@ -254,16 +226,6 @@ public static JsValue ParseSerializedScript(string script, byte[] buffer, JsSour
254226
JsValue bufferValue = JsValue.CreateExternalArrayBuffer(buffer);
255227
bufferValue.AddRef();
256228

257-
JsSerializedLoadScriptCallback scriptLoadCallback = (JsSourceContext context,
258-
out JsValue value, out JsParseScriptAttributes parseAttributes) =>
259-
{
260-
byte[] bytes = Encoding.GetEncoding(0).GetBytes(script);
261-
value = JsValue.CreateExternalArrayBuffer(bytes);
262-
parseAttributes = JsParseScriptAttributes.None;
263-
264-
return true;
265-
};
266-
267229
JsValue sourceUrlValue = JsValue.FromString(sourceUrl);
268230
sourceUrlValue.AddRef();
269231

@@ -283,19 +245,6 @@ public static JsValue ParseSerializedScript(string script, byte[] buffer, JsSour
283245
return result;
284246
}
285247

286-
/// <summary>
287-
/// Executes a script
288-
/// </summary>
289-
/// <remarks>
290-
/// Requires an active script context
291-
/// </remarks>
292-
/// <param name="script">The script to run</param>
293-
/// <returns>The result of the script, if any</returns>
294-
public static JsValue RunScript(string script)
295-
{
296-
return RunScript(script, JsSourceContext.None, string.Empty);
297-
}
298-
299248
/// <summary>
300249
/// Executes a script
301250
/// </summary>
@@ -352,28 +301,13 @@ public static JsValue RunScript(string script, JsSourceContext sourceContext, st
352301
/// </remarks>
353302
/// <param name="script">The source code of the serialized script</param>
354303
/// <param name="buffer">The serialized script</param>
355-
/// <returns>The result of running the script, if any</returns>
356-
public static JsValue RunSerializedScript(string script, byte[] buffer)
357-
{
358-
return RunSerializedScript(script, buffer, JsSourceContext.None, string.Empty);
359-
}
360-
361-
/// <summary>
362-
/// Runs a serialized script
363-
/// </summary>
364-
/// <remarks>
365-
/// <para>Requires an active script context.</para>
366-
/// <para>The runtime will hold on to the buffer until all instances of any functions created from
367-
/// the buffer are garbage collected.</para>
368-
/// </remarks>
369-
/// <param name="script">The source code of the serialized script</param>
370-
/// <param name="buffer">The serialized script</param>
304+
/// <param name="scriptLoadCallback">Callback to load the source code of the serialized script</param>
371305
/// <param name="sourceContext">A cookie identifying the script that can be used
372306
/// by debuggable script contexts</param>
373307
/// <param name="sourceUrl">The location the script came from</param>
374308
/// <returns>The result of running the script, if any</returns>
375-
public static JsValue RunSerializedScript(string script, byte[] buffer, JsSourceContext sourceContext,
376-
string sourceUrl)
309+
public static JsValue RunSerializedScript(string script, byte[] buffer,
310+
JsSerializedLoadScriptCallback scriptLoadCallback, JsSourceContext sourceContext, string sourceUrl)
377311
{
378312
JsValue result;
379313
JsErrorCode errorCode;
@@ -388,16 +322,6 @@ public static JsValue RunSerializedScript(string script, byte[] buffer, JsSource
388322
JsValue bufferValue = JsValue.CreateExternalArrayBuffer(buffer);
389323
bufferValue.AddRef();
390324

391-
JsSerializedLoadScriptCallback scriptLoadCallback = (JsSourceContext context,
392-
out JsValue value, out JsParseScriptAttributes parseAttributes) =>
393-
{
394-
byte[] bytes = Encoding.GetEncoding(0).GetBytes(script);
395-
value = JsValue.CreateExternalArrayBuffer(bytes);
396-
parseAttributes = JsParseScriptAttributes.None;
397-
398-
return true;
399-
};
400-
401325
JsValue sourceUrlValue = JsValue.FromString(sourceUrl);
402326
sourceUrlValue.AddRef();
403327

src/JavaScriptEngineSwitcher.ChakraCore/JsRt/JsValue.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,7 @@ public static JsValue CreateExternalArrayBuffer(byte[] buffer)
457457
bufferPtr = Marshal.AllocHGlobal(bufferLength);
458458
Marshal.Copy(buffer, 0, bufferPtr, bufferLength);
459459

460-
finalizeCallback = Marshal.FreeHGlobal;
460+
finalizeCallback = DefaultExternalBufferFinalizeCallback.Instance;
461461
}
462462
else
463463
{

src/JavaScriptEngineSwitcher.ChakraCore/readme.txt

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,9 @@
3030
=============
3131
RELEASE NOTES
3232
=============
33-
1. Added support of .NET Framework 4.7.1;
34-
2. Fixed a implementation of the `JsSerializedLoadScriptCallback` delegate;
35-
3. Fixed a error #34 “Finalazier thread is blocked because of
36-
JavaScriptEngineSwitcher.ChakraCore.ChakraCoreJsEngine”.
33+
1. Changed a implementation of the `Dispose` method;
34+
2. Prevented a early destruction of delegates, which have been passed to the
35+
native methods.
3736

3837
=============
3938
DOCUMENTATION

0 commit comments

Comments
 (0)