ClearScript 7.0 RC2: Fixed task-promise conversion issues (GitHub Issue #198).

This commit is contained in:
ClearScript 2020-10-21 07:21:12 -07:00
Родитель d4ac519b4c
Коммит 03038deb57
14 изменённых файлов: 107 добавлений и 25 удалений

Просмотреть файл

@ -7,5 +7,5 @@
#define CLEARSCRIPT_VERSION_STRING "7.0.0"
#define CLEARSCRIPT_VERSION_COMMA_SEPARATED 7,0,0
#define CLEARSCRIPT_VERSION_STRING_INFORMATIONAL "7.0.0-rc"
#define CLEARSCRIPT_VERSION_STRING_INFORMATIONAL "7.0.0-rc2"
#define CLEARSCRIPT_FILE_FLAGS VS_FF_PRERELEASE

Просмотреть файл

@ -1,7 +1,12 @@
namespace Microsoft.ClearScript.JavaScript
using System.Threading.Tasks;
namespace Microsoft.ClearScript.JavaScript
{
internal interface IJavaScriptEngine
{
uint BaseLanguageVersion { get; }
void CompletePromiseWithResult<T>(Task<T> task, object resolve, object reject);
void CompletePromise(Task task, object resolve, object reject);
}
}

Просмотреть файл

@ -49,7 +49,7 @@ namespace Microsoft.ClearScript.JavaScript
return engine.Script.EngineInternal.createPromise(new Executor((resolve, reject) =>
{
Action<Task> continuation = thisTask => engine.Script.EngineInternal.onTaskWithResultCompleted(thisTask, resolve, reject);
Action<Task<TResult>> continuation = thisTask => javaScriptEngine.CompletePromiseWithResult(thisTask, resolve, reject);
task.ContinueWith(continuation, TaskContinuationOptions.ExecuteSynchronously);
}));
}
@ -87,7 +87,7 @@ namespace Microsoft.ClearScript.JavaScript
return engine.Script.EngineInternal.createPromise(new Executor((resolve, reject) =>
{
Action<Task> continuation = thisTask => engine.Script.EngineInternal.onTaskCompleted(thisTask, resolve, reject);
Action<Task> continuation = thisTask => javaScriptEngine.CompletePromise(thisTask, resolve, reject);
task.ContinueWith(continuation, TaskContinuationOptions.ExecuteSynchronously);
}));
}

Просмотреть файл

@ -17,13 +17,13 @@ using System.Runtime.InteropServices;
[assembly: ComVisible(false)]
[assembly: AssemblyVersion("7.0.0")]
[assembly: AssemblyFileVersion("7.0.0")]
[assembly: AssemblyInformationalVersion("7.0.0-rc")]
[assembly: AssemblyInformationalVersion("7.0.0-rc2")]
namespace Microsoft.ClearScript.Properties
{
internal static class ClearScriptVersion
{
public const string Triad = "7.0.0";
public const string Informational = "7.0.0-rc";
public const string Informational = "7.0.0-rc2";
}
}

Просмотреть файл

@ -288,7 +288,7 @@ namespace Microsoft.ClearScript.V8
return value instanceof savedPromise;
},
onTaskWithResultCompleted: function (task, resolve, reject) {
completePromiseWithResult: function (task, resolve, reject) {
try {
resolve(task.Result);
}
@ -297,7 +297,7 @@ namespace Microsoft.ClearScript.V8
}
},
onTaskCompleted: function (task, resolve, reject) {
completePromise: function (task, resolve, reject) {
try {
task.Wait();
resolve();
@ -1291,18 +1291,29 @@ namespace Microsoft.ClearScript.V8
if (engineFlags.HasFlag(V8ScriptEngineFlags.EnableTaskPromiseConversion) && !bypassTaskPromiseConversion)
{
if (obj.GetType().IsAssignableToGenericType(typeof(Task<>), out var typeArgs))
// .NET Core async functions return Task subclass instances that trigger result wrapping
var testObject = obj;
if (testObject is HostObject testHostObject)
{
using (Scope.Create(() => bypassTaskPromiseConversion = true, () => bypassTaskPromiseConversion = false))
{
obj = typeof(TaskConverter<>).MakeSpecificType(typeArgs).InvokeMember("ToPromise", BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Static, null, null, new[] { obj, this });
}
testObject = testHostObject.Target;
}
else if (obj is Task task)
if (testObject != null)
{
using (Scope.Create(() => bypassTaskPromiseConversion = true, () => bypassTaskPromiseConversion = false))
if (testObject.GetType().IsAssignableToGenericType(typeof(Task<>), out var typeArgs))
{
obj = task.ToPromise(this);
using (Scope.Create(() => MiscHelpers.Exchange(ref bypassTaskPromiseConversion, true), oldValue => bypassTaskPromiseConversion = oldValue))
{
obj = typeof(TaskConverter<>).MakeSpecificType(typeArgs).InvokeMember("ToPromise", BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Static, null, null, new[] {testObject, this});
}
}
else if (testObject is Task task)
{
using (Scope.Create(() => MiscHelpers.Exchange(ref bypassTaskPromiseConversion, true), oldValue => bypassTaskPromiseConversion = oldValue))
{
obj = task.ToPromise(this);
}
}
}
}
@ -1369,7 +1380,7 @@ namespace Microsoft.ClearScript.V8
var scriptItem = V8ScriptItem.Wrap(this, obj);
if (engineFlags.HasFlag(V8ScriptEngineFlags.EnableTaskPromiseConversion) && !bypassTaskPromiseConversion && (obj is IV8Object v8Object) && v8Object.IsPromise())
{
using (Scope.Create(() => bypassTaskPromiseConversion = true, () => bypassTaskPromiseConversion = false))
using (Scope.Create(() => MiscHelpers.Exchange(ref bypassTaskPromiseConversion, true), oldValue => bypassTaskPromiseConversion = oldValue))
{
return scriptItem.ToTask();
}
@ -1494,6 +1505,22 @@ namespace Microsoft.ClearScript.V8
uint IJavaScriptEngine.BaseLanguageVersion => 8;
void IJavaScriptEngine.CompletePromiseWithResult<T>(Task<T> task, object resolve, object reject)
{
using (Scope.Create(() => MiscHelpers.Exchange(ref bypassTaskPromiseConversion, true), oldValue => bypassTaskPromiseConversion = oldValue))
{
Script.EngineInternal.completePromiseWithResult(task, resolve, reject);
}
}
void IJavaScriptEngine.CompletePromise(Task task, object resolve, object reject)
{
using (Scope.Create(() => MiscHelpers.Exchange(ref bypassTaskPromiseConversion, true), oldValue => bypassTaskPromiseConversion = oldValue))
{
Script.EngineInternal.completePromise(task, resolve, reject);
}
}
#endregion
#region unit test support

Просмотреть файл

@ -1,6 +1,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
using System;
using System.Threading.Tasks;
using Microsoft.ClearScript.JavaScript;
namespace Microsoft.ClearScript.Windows
@ -88,6 +90,16 @@ namespace Microsoft.ClearScript.Windows
uint IJavaScriptEngine.BaseLanguageVersion => 3;
void IJavaScriptEngine.CompletePromiseWithResult<T>(Task<T> task, object resolve, object reject)
{
throw new NotImplementedException();
}
void IJavaScriptEngine.CompletePromise(Task task, object resolve, object reject)
{
throw new NotImplementedException();
}
#endregion
}
}

Просмотреть файл

@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.ClearScript.JavaScript;
using Microsoft.ClearScript.Util;
@ -298,6 +299,16 @@ namespace Microsoft.ClearScript.Windows
uint IJavaScriptEngine.BaseLanguageVersion => 3;
void IJavaScriptEngine.CompletePromiseWithResult<T>(Task<T> task, object resolve, object reject)
{
throw new NotImplementedException();
}
void IJavaScriptEngine.CompletePromise(Task task, object resolve, object reject)
{
throw new NotImplementedException();
}
#endregion
}
}

Просмотреть файл

@ -13,4 +13,4 @@ using System.Runtime.InteropServices;
[assembly: ComVisible(false)]
[assembly: AssemblyVersion("7.0.0")]
[assembly: AssemblyFileVersion("7.0.0")]
[assembly: AssemblyInformationalVersion("7.0.0-rc")]
[assembly: AssemblyInformationalVersion("7.0.0-rc2")]

Просмотреть файл

@ -13,4 +13,4 @@ using System.Runtime.InteropServices;
[assembly: ComVisible(false)]
[assembly: AssemblyVersion("7.0.0")]
[assembly: AssemblyFileVersion("7.0.0")]
[assembly: AssemblyInformationalVersion("7.0.0-rc")]
[assembly: AssemblyInformationalVersion("7.0.0-rc2")]

Просмотреть файл

@ -13,6 +13,7 @@ using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;
using Microsoft.ClearScript.V8;
using Microsoft.ClearScript.Util;
@ -1383,6 +1384,21 @@ namespace Microsoft.ClearScript.Test
testObject.FireEvent(456);
}
[TestMethod, TestCategory("BugFix")]
public void BugFix_V8ScriptEngine_TaskPromiseConversion()
{
engine.Dispose();
engine = new V8ScriptEngine(V8ScriptEngineFlags.EnableDebugging | V8ScriptEngineFlags.EnableTaskPromiseConversion);
engine.AddHostType(typeof(TaskPromiseConversionTest));
engine.Execute("value = TaskPromiseConversionTest.GetStringAsync();");
Assert.AreEqual("Promise", engine.Evaluate("value.constructor.name"));
Task.Delay(200).Wait();
engine.Execute("value.then(value => result = value);");
Assert.AreEqual("foo", engine.Script.result);
}
// ReSharper restore InconsistentNaming
#endregion
@ -1688,6 +1704,15 @@ namespace Microsoft.ClearScript.Test
public bool IsValid { get; set; }
}
public class TaskPromiseConversionTest
{
public static async Task<string> GetStringAsync()
{
await Task.Delay(100);
return "foo";
}
}
#endregion
}
}

Просмотреть файл

@ -13,4 +13,4 @@ using System.Runtime.InteropServices;
[assembly: ComVisible(false)]
[assembly: AssemblyVersion("7.0.0")]
[assembly: AssemblyFileVersion("7.0.0")]
[assembly: AssemblyInformationalVersion("7.0.0-rc")]
[assembly: AssemblyInformationalVersion("7.0.0-rc2")]

Просмотреть файл

@ -173,10 +173,10 @@
<Compile Include="..\..\ClearScript\V8\SplitProxy\V8ScriptImpl.cs" Link="V8\SplitProxy\V8ScriptImpl.cs" />
<Compile Include="..\..\ClearScript\V8\SplitProxy\V8SplitProxyHelpers.cs" Link="V8\SplitProxy\V8SplitProxyHelpers.cs" />
<Compile Include="..\..\ClearScript\V8\SplitProxy\V8SplitProxyManaged.cs" Link="V8\SplitProxy\V8SplitProxyManaged.cs" />
<Compile Include="..\..\ClearScript\V8\SplitProxy\V8SplitProxyNative.cs" Link="V8\SplitProxy\SplitProxyNative.cs" />
<Compile Include="..\..\ClearScript\V8\SplitProxy\V8SplitProxyNative.cs" Link="V8\SplitProxy\V8SplitProxyNative.cs" />
<Compile Include="..\..\ClearScript\V8\SplitProxy\V8SplitProxyNative.Windows.32.cs" Link="V8\SplitProxy\V8SplitProxyNative.Windows.32.cs" />
<Compile Include="..\..\ClearScript\V8\SplitProxy\V8SplitProxyNative.Windows.64.cs" Link="V8\SplitProxy\V8SplitProxyNative.Windows.64.cs" />
<Compile Include="..\..\ClearScript\V8\SplitProxy\V8SplitProxyNative.Windows.cs" Link="V8\SplitProxy\SplitProxyNative.Windows.cs" />
<Compile Include="..\..\ClearScript\V8\SplitProxy\V8SplitProxyNative.Windows.cs" Link="V8\SplitProxy\V8SplitProxyNative.Windows.cs" />
<Compile Include="..\..\ClearScript\V8\SplitProxy\V8ContextProxyImpl.cs" Link="V8\SplitProxy\V8ContextProxyImpl.cs" />
<Compile Include="..\..\ClearScript\V8\SplitProxy\V8IsolateProxyImpl.cs" Link="V8\SplitProxy\V8IsolateProxyImpl.cs" />
<Compile Include="..\..\ClearScript\V8\SplitProxy\V8ObjectImpl.cs" Link="V8\SplitProxy\V8ObjectImpl.cs" />
@ -224,6 +224,7 @@
<Folder Include="Util\COM\" />
<Folder Include="Util\Test\" />
<Folder Include="Util\Web\" />
<Folder Include="V8\SplitProxy\" />
<Folder Include="Windows\" />
</ItemGroup>

Просмотреть файл

@ -167,8 +167,8 @@
<Compile Include="..\..\ClearScript\V8\SplitProxy\V8ScriptImpl.cs" Link="V8\SplitProxy\V8ScriptImpl.cs" />
<Compile Include="..\..\ClearScript\V8\SplitProxy\V8SplitProxyHelpers.cs" Link="V8\SplitProxy\V8SplitProxyHelpers.cs" />
<Compile Include="..\..\ClearScript\V8\SplitProxy\V8SplitProxyManaged.cs" Link="V8\SplitProxy\V8SplitProxyManaged.cs" />
<Compile Include="..\..\ClearScript\V8\SplitProxy\V8SplitProxyNative.cs" Link="V8\SplitProxy\SplitProxyNative.cs" />
<Compile Include="..\..\ClearScript\V8\SplitProxy\V8SplitProxyNative.Unix.cs" Link="V8\SplitProxy\SplitProxyNative.Unix.cs" />
<Compile Include="..\..\ClearScript\V8\SplitProxy\V8SplitProxyNative.cs" Link="V8\SplitProxy\V8SplitProxyNative.cs" />
<Compile Include="..\..\ClearScript\V8\SplitProxy\V8SplitProxyNative.Unix.cs" Link="V8\SplitProxy\V8SplitProxyNative.Unix.cs" />
<Compile Include="..\..\ClearScript\V8\SplitProxy\V8ContextProxyImpl.cs" Link="V8\SplitProxy\V8ContextProxyImpl.cs" />
<Compile Include="..\..\ClearScript\V8\SplitProxy\V8IsolateProxyImpl.cs" Link="V8\SplitProxy\V8IsolateProxyImpl.cs" />
<Compile Include="..\..\ClearScript\V8\SplitProxy\V8ObjectImpl.cs" Link="V8\SplitProxy\V8ObjectImpl.cs" />
@ -211,6 +211,7 @@
<Folder Include="Util\COM\" />
<Folder Include="Util\Test\" />
<Folder Include="Util\Web\" />
<Folder Include="V8\SplitProxy\" />
<Folder Include="Windows\" />
</ItemGroup>

Просмотреть файл

@ -1,5 +1,5 @@
<#
var version = new Version(7, 0, 0);
var versionSuffix = "-rc";
var versionSuffix = "-rc2";
new Random(versionSuffix.Length); // suppress "versionSuffix not used" warning
#>