Skip to content

Commit 03038de

Browse files
ClearScript 7.0 RC2: Fixed task-promise conversion issues (GitHub Issue microsoft#198).
1 parent d4ac519 commit 03038de

File tree

14 files changed

+107
-25
lines changed

14 files changed

+107
-25
lines changed

ClearScript/Exports/VersionSymbols.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@
77

88
#define CLEARSCRIPT_VERSION_STRING "7.0.0"
99
#define CLEARSCRIPT_VERSION_COMMA_SEPARATED 7,0,0
10-
#define CLEARSCRIPT_VERSION_STRING_INFORMATIONAL "7.0.0-rc"
10+
#define CLEARSCRIPT_VERSION_STRING_INFORMATIONAL "7.0.0-rc2"
1111
#define CLEARSCRIPT_FILE_FLAGS VS_FF_PRERELEASE
Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
1-
namespace Microsoft.ClearScript.JavaScript
1+
using System.Threading.Tasks;
2+
3+
namespace Microsoft.ClearScript.JavaScript
24
{
35
internal interface IJavaScriptEngine
46
{
57
uint BaseLanguageVersion { get; }
8+
9+
void CompletePromiseWithResult<T>(Task<T> task, object resolve, object reject);
10+
void CompletePromise(Task task, object resolve, object reject);
611
}
712
}

ClearScript/JavaScript/JavaScriptExtensions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ public static object ToPromise<TResult>(this Task<TResult> task, ScriptEngine en
4949

5050
return engine.Script.EngineInternal.createPromise(new Executor((resolve, reject) =>
5151
{
52-
Action<Task> continuation = thisTask => engine.Script.EngineInternal.onTaskWithResultCompleted(thisTask, resolve, reject);
52+
Action<Task<TResult>> continuation = thisTask => javaScriptEngine.CompletePromiseWithResult(thisTask, resolve, reject);
5353
task.ContinueWith(continuation, TaskContinuationOptions.ExecuteSynchronously);
5454
}));
5555
}
@@ -87,7 +87,7 @@ public static object ToPromise(this Task task, ScriptEngine engine)
8787

8888
return engine.Script.EngineInternal.createPromise(new Executor((resolve, reject) =>
8989
{
90-
Action<Task> continuation = thisTask => engine.Script.EngineInternal.onTaskCompleted(thisTask, resolve, reject);
90+
Action<Task> continuation = thisTask => javaScriptEngine.CompletePromise(thisTask, resolve, reject);
9191
task.ContinueWith(continuation, TaskContinuationOptions.ExecuteSynchronously);
9292
}));
9393
}

ClearScript/Properties/AssemblyInfo.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@
1717
[assembly: ComVisible(false)]
1818
[assembly: AssemblyVersion("7.0.0")]
1919
[assembly: AssemblyFileVersion("7.0.0")]
20-
[assembly: AssemblyInformationalVersion("7.0.0-rc")]
20+
[assembly: AssemblyInformationalVersion("7.0.0-rc2")]
2121

2222
namespace Microsoft.ClearScript.Properties
2323
{
2424
internal static class ClearScriptVersion
2525
{
2626
public const string Triad = "7.0.0";
27-
public const string Informational = "7.0.0-rc";
27+
public const string Informational = "7.0.0-rc2";
2828
}
2929
}

ClearScript/V8/V8ScriptEngine.cs

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ function construct() {
288288
return value instanceof savedPromise;
289289
},
290290
291-
onTaskWithResultCompleted: function (task, resolve, reject) {
291+
completePromiseWithResult: function (task, resolve, reject) {
292292
try {
293293
resolve(task.Result);
294294
}
@@ -297,7 +297,7 @@ function construct() {
297297
}
298298
},
299299
300-
onTaskCompleted: function (task, resolve, reject) {
300+
completePromise: function (task, resolve, reject) {
301301
try {
302302
task.Wait();
303303
resolve();
@@ -1291,18 +1291,29 @@ internal override object MarshalToScript(object obj, HostItemFlags flags)
12911291

12921292
if (engineFlags.HasFlag(V8ScriptEngineFlags.EnableTaskPromiseConversion) && !bypassTaskPromiseConversion)
12931293
{
1294-
if (obj.GetType().IsAssignableToGenericType(typeof(Task<>), out var typeArgs))
1294+
// .NET Core async functions return Task subclass instances that trigger result wrapping
1295+
1296+
var testObject = obj;
1297+
if (testObject is HostObject testHostObject)
12951298
{
1296-
using (Scope.Create(() => bypassTaskPromiseConversion = true, () => bypassTaskPromiseConversion = false))
1297-
{
1298-
obj = typeof(TaskConverter<>).MakeSpecificType(typeArgs).InvokeMember("ToPromise", BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Static, null, null, new[] { obj, this });
1299-
}
1299+
testObject = testHostObject.Target;
13001300
}
1301-
else if (obj is Task task)
1301+
1302+
if (testObject != null)
13021303
{
1303-
using (Scope.Create(() => bypassTaskPromiseConversion = true, () => bypassTaskPromiseConversion = false))
1304+
if (testObject.GetType().IsAssignableToGenericType(typeof(Task<>), out var typeArgs))
1305+
{
1306+
using (Scope.Create(() => MiscHelpers.Exchange(ref bypassTaskPromiseConversion, true), oldValue => bypassTaskPromiseConversion = oldValue))
1307+
{
1308+
obj = typeof(TaskConverter<>).MakeSpecificType(typeArgs).InvokeMember("ToPromise", BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Static, null, null, new[] {testObject, this});
1309+
}
1310+
}
1311+
else if (testObject is Task task)
13041312
{
1305-
obj = task.ToPromise(this);
1313+
using (Scope.Create(() => MiscHelpers.Exchange(ref bypassTaskPromiseConversion, true), oldValue => bypassTaskPromiseConversion = oldValue))
1314+
{
1315+
obj = task.ToPromise(this);
1316+
}
13061317
}
13071318
}
13081319
}
@@ -1369,7 +1380,7 @@ internal override object MarshalToHost(object obj, bool preserveHostTarget)
13691380
var scriptItem = V8ScriptItem.Wrap(this, obj);
13701381
if (engineFlags.HasFlag(V8ScriptEngineFlags.EnableTaskPromiseConversion) && !bypassTaskPromiseConversion && (obj is IV8Object v8Object) && v8Object.IsPromise())
13711382
{
1372-
using (Scope.Create(() => bypassTaskPromiseConversion = true, () => bypassTaskPromiseConversion = false))
1383+
using (Scope.Create(() => MiscHelpers.Exchange(ref bypassTaskPromiseConversion, true), oldValue => bypassTaskPromiseConversion = oldValue))
13731384
{
13741385
return scriptItem.ToTask();
13751386
}
@@ -1494,6 +1505,22 @@ protected override void Dispose(bool disposing)
14941505

14951506
uint IJavaScriptEngine.BaseLanguageVersion => 8;
14961507

1508+
void IJavaScriptEngine.CompletePromiseWithResult<T>(Task<T> task, object resolve, object reject)
1509+
{
1510+
using (Scope.Create(() => MiscHelpers.Exchange(ref bypassTaskPromiseConversion, true), oldValue => bypassTaskPromiseConversion = oldValue))
1511+
{
1512+
Script.EngineInternal.completePromiseWithResult(task, resolve, reject);
1513+
}
1514+
}
1515+
1516+
void IJavaScriptEngine.CompletePromise(Task task, object resolve, object reject)
1517+
{
1518+
using (Scope.Create(() => MiscHelpers.Exchange(ref bypassTaskPromiseConversion, true), oldValue => bypassTaskPromiseConversion = oldValue))
1519+
{
1520+
Script.EngineInternal.completePromise(task, resolve, reject);
1521+
}
1522+
}
1523+
14971524
#endregion
14981525

14991526
#region unit test support

ClearScript/Windows/JScriptEngine.Unix.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT license.
33

4+
using System;
5+
using System.Threading.Tasks;
46
using Microsoft.ClearScript.JavaScript;
57

68
namespace Microsoft.ClearScript.Windows
@@ -88,6 +90,16 @@ protected JScriptEngine(string progID, string name, string fileNameExtensions, W
8890

8991
uint IJavaScriptEngine.BaseLanguageVersion => 3;
9092

93+
void IJavaScriptEngine.CompletePromiseWithResult<T>(Task<T> task, object resolve, object reject)
94+
{
95+
throw new NotImplementedException();
96+
}
97+
98+
void IJavaScriptEngine.CompletePromise(Task task, object resolve, object reject)
99+
{
100+
throw new NotImplementedException();
101+
}
102+
91103
#endregion
92104
}
93105
}

ClearScript/Windows/JScriptEngine.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System;
55
using System.Collections.Generic;
6+
using System.Threading.Tasks;
67
using Microsoft.ClearScript.JavaScript;
78
using Microsoft.ClearScript.Util;
89

@@ -298,6 +299,16 @@ internal override object Execute(UniqueDocumentInfo documentInfo, string code, b
298299

299300
uint IJavaScriptEngine.BaseLanguageVersion => 3;
300301

302+
void IJavaScriptEngine.CompletePromiseWithResult<T>(Task<T> task, object resolve, object reject)
303+
{
304+
throw new NotImplementedException();
305+
}
306+
307+
void IJavaScriptEngine.CompletePromise(Task task, object resolve, object reject)
308+
{
309+
throw new NotImplementedException();
310+
}
311+
301312
#endregion
302313
}
303314
}

ClearScriptBenchmarks/Properties/AssemblyInfo.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@
1313
[assembly: ComVisible(false)]
1414
[assembly: AssemblyVersion("7.0.0")]
1515
[assembly: AssemblyFileVersion("7.0.0")]
16-
[assembly: AssemblyInformationalVersion("7.0.0-rc")]
16+
[assembly: AssemblyInformationalVersion("7.0.0-rc2")]

ClearScriptConsole/Properties/AssemblyInfo.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@
1313
[assembly: ComVisible(false)]
1414
[assembly: AssemblyVersion("7.0.0")]
1515
[assembly: AssemblyFileVersion("7.0.0")]
16-
[assembly: AssemblyInformationalVersion("7.0.0-rc")]
16+
[assembly: AssemblyInformationalVersion("7.0.0-rc2")]

ClearScriptTest/BugFixTest.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
using System.Reflection;
1414
using System.Runtime.InteropServices;
1515
using System.Threading;
16+
using System.Threading.Tasks;
1617
using System.Xml.Linq;
1718
using Microsoft.ClearScript.V8;
1819
using Microsoft.ClearScript.Util;
@@ -1383,6 +1384,21 @@ public void BugFix_EventAfterEngineDispose()
13831384
testObject.FireEvent(456);
13841385
}
13851386

1387+
[TestMethod, TestCategory("BugFix")]
1388+
public void BugFix_V8ScriptEngine_TaskPromiseConversion()
1389+
{
1390+
engine.Dispose();
1391+
engine = new V8ScriptEngine(V8ScriptEngineFlags.EnableDebugging | V8ScriptEngineFlags.EnableTaskPromiseConversion);
1392+
1393+
engine.AddHostType(typeof(TaskPromiseConversionTest));
1394+
engine.Execute("value = TaskPromiseConversionTest.GetStringAsync();");
1395+
Assert.AreEqual("Promise", engine.Evaluate("value.constructor.name"));
1396+
Task.Delay(200).Wait();
1397+
1398+
engine.Execute("value.then(value => result = value);");
1399+
Assert.AreEqual("foo", engine.Script.result);
1400+
}
1401+
13861402
// ReSharper restore InconsistentNaming
13871403

13881404
#endregion
@@ -1688,6 +1704,15 @@ public class Variable
16881704
public bool IsValid { get; set; }
16891705
}
16901706

1707+
public class TaskPromiseConversionTest
1708+
{
1709+
public static async Task<string> GetStringAsync()
1710+
{
1711+
await Task.Delay(100);
1712+
return "foo";
1713+
}
1714+
}
1715+
16911716
#endregion
16921717
}
16931718
}

0 commit comments

Comments
 (0)