Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Native async implementation of ExecuteAsync and InvokeAsync #731

Open
wants to merge 39 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
1218f89
ExecuteAsync initial commit
Ellested May 6, 2020
d8f9bfa
Merge branch 'dev' into Async
Ellested May 6, 2020
1638a88
Cleanup
Ellested May 6, 2020
ac53bd3
Merged ellested
Ellested May 8, 2020
03732ae
Fixed AssignToIdentifier to use async path
Ellested May 12, 2020
8051a87
Fixed async clr method as argument
Ellested May 12, 2020
f8b8239
Merge pull request #1 from Ellested/Async
russlank May 15, 2020
c7de3a5
Fixed a typo
May 23, 2020
bbe2dea
Fix spotted by Russlan
Ellested May 24, 2020
7a17178
Improved AsyncHelpers in handling of Task results
Ellested May 24, 2020
a59c4de
Small fix for the for-loop body code execution; un-awaited CLR calls
May 24, 2020
5d1efec
Merge pull request #2 from Ellested/Async
russlank May 24, 2020
898b094
Merge remote-tracking branch 'origin/contributions/async' into mycont…
May 24, 2020
a89c43d
Added more tests for async execution
May 25, 2020
aa5c14a
Added async variants to Switch, While and With statements
Ellested Jul 7, 2020
68c741e
Merged upstream dev
Ellested Jul 7, 2020
2d23e63
Merged dev into Async, resolving conflicts by using the soucre file
Ellested Jul 7, 2020
962caf7
Fixed merge errors and Async variants. Included async "shadow" tests.…
Ellested Jul 7, 2020
18ec7c6
Merge pull request #5 from Ellested/Async
russlank Jul 7, 2020
f3fb68f
Merge with recent Ellested's changes and fixes ing merges with upstre…
Jul 7, 2020
04badae
Fixed this.property assignment of async result
Ellested Jul 16, 2020
0531689
Merge pull request #7 from Ellested/Async
russlank Jul 17, 2020
aa0667a
Merge branch 'contributions/async' into mycontributions/async
Jul 17, 2020
dddfb9f
Bugfix for the case when async invocation is on left side of assignme…
Jul 17, 2020
c24a85b
Merge pull request #1 from russlank/mycontributions/async
russlank Jul 17, 2020
d465009
Fixing reentrancy problem on the execution context, when an async CLR…
Ellested Aug 13, 2020
120ac91
Merge branch 'Async' of https://github.com/Ellested/jint into Async
Ellested Aug 13, 2020
67c800a
Merged origin/dev
Ellested Aug 13, 2020
14ec401
Fixed conflicts and new async variants
Ellested Aug 13, 2020
1c21786
Removed duplicate code in AsyncTests with SetupClrDelegates()
Ellested Aug 13, 2020
ce56f65
Added Async variant to ClrFunctionInstance
Ellested Oct 3, 2020
02c915a
Merged from dev
Ellested Oct 3, 2020
8fbbc00
Added async guard to MethodInfoFunctionInstance
Ellested Feb 28, 2021
871808f
Added Async GetValue to JintExpression
Ellested Feb 28, 2021
4101101
Moved Async implementation to .Async files and added DynamicFileNesti…
Ellested Feb 28, 2021
2d5d340
Merged with latest dev
Ellested Mar 1, 2021
e918a78
Added new async variants, fixes and tests
Ellested Mar 1, 2021
3943e01
Updated Engine async method variants (wasn't updated)
Ellested Mar 2, 2021
55076d2
Missing await Call in ClrFunctionInstance
Ellested Mar 3, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
502 changes: 502 additions & 0 deletions Jint.Tests/Runtime/AsyncDelegateTests.cs

Large diffs are not rendered by default.

203 changes: 203 additions & 0 deletions Jint.Tests/Runtime/AsyncTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
using Jint.Native;
using System;
using System.Linq;
using System.Threading.Tasks;
using Xunit;

namespace Jint.Tests.Runtime
{
/// <summary>
/// Setup new async tests here, and call echoAsync to return a result that matches the input, asynchroneosly.
/// Debug by setting a breakpoint in EchoAsync and run the test.
/// When the breakpoint hits, check the call stack and see where the Async execution path was swithed over to the synchroneos code path.
/// </summary>
public class AsyncTests
{
private static async Task<object> EchoAsync(object input)
{
await Task.Delay(1).ConfigureAwait(true);
return input;
}

private static async Task<JsValue> RunTest(string expression)
{
var engine = new Engine();
engine.SetValue("echoAsync", new Func<object, Task<object>>(obj => EchoAsync(obj)));
return (await engine.ExecuteAsync(expression)).GetCompletionValue();
}

[Fact]
public async void GetPropertyIsAwaited()
{
var code = @"
var obj = {};
Object.defineProperty(obj, 'value', {
get: function() { return echoAsync(42) },
});
return obj.value;
";

var result = await RunTest(code);

Assert.Equal(42, result);
}

[Fact]
public async void SpreadParametersAreAwaited()
{
var code = @"
function addSpread(...values) {
var result = 0;
for (var i=0; i<values.length; i++) {
result+=values[i];
}
return result;
}
return addSpread(...[echoAsync(10), echoAsync(20), echoAsync(30)]);
";

var result = await RunTest(code);

Assert.Equal(10 + 20 + 30, result);
}

[Fact]
public async void FunctionArrayParameterAreAwaited()
{
var code = @"
function addArray(values) {
var result = 0;
for (var i=0; i<values.length; i++) {
result+=values[i];
}
return result;
}
return addArray([echoAsync(10), echoAsync(20), echoAsync(30)]);
";

var result = await RunTest(code);

Assert.Equal(10 + 20 + 30, result);
}

[Fact]
public async void FunctionParametersAreAwaited()
{
var code = @"
function addValues(a, b, c) {
return a + b + c;
}
return addValues(echoAsync(10), echoAsync(20), echoAsync(30));
";

var result = await RunTest(code);

Assert.Equal(10 + 20 + 30, result);
}

[Fact]
public async void BinaryExpressionsAwaits()
{
Assert.True((await RunTest("42 == echoAsync(42)")).AsBoolean());
Assert.True((await RunTest("echoAsync(42) == 42")).AsBoolean());
Assert.True((await RunTest("echoAsync(42) == echoAsync(42)")).AsBoolean());
}

[Fact]
public async void AssignmentExpressionsAwaits()
{
Assert.Equal(42, await RunTest("var x = echoAsync(42); return x;"));
Assert.Equal(52, await RunTest("var x = echoAsync(42) + 10; return x;"));
Assert.Equal(62, await RunTest("var x = 20 + echoAsync(42); return x;"));
}

[Fact]
public async void AssignmentThisExpressionsAwaits()
{
Assert.Equal(42, await RunTest("this.x = echoAsync(42); return this.x;"));
Assert.Equal(52, await RunTest("this.x = echoAsync(42) + 10; return this.x;"));
Assert.Equal(62, await RunTest("this.x = 20 + echoAsync(42); return this.x;"));
}

[Fact]
public async void ObjectInitializerAwaits()
{
Assert.Equal(42, await RunTest("var x = { value: echoAsync(42) }; return x.value;"));
Assert.Equal(52, await RunTest("var x = { value: echoAsync(42) + 10 }; return x.value;"));
Assert.Equal(62, await RunTest("var x = { value: 20 + echoAsync(42) }; return x.value;"));
}

[Fact]
public async void IfConditionAwaits()
{
Assert.Equal(42, await RunTest("if (echoAsync(42)==42) return 42;"));
Assert.Equal(42, await RunTest("if (42 == echoAsync(42)) return 42;"));
Assert.Equal(52, await RunTest("if (52 == echoAsync(42) + 10) return 52;"));
}

[Fact]
public async void IfElseBodyStatementAwaits()
{
Assert.Equal(42, await RunTest("if (true) return echoAsync(42); else return null;"));
Assert.Equal(42, await RunTest("if (false) return null; else return echoAsync(42);"));
Assert.Equal(42, await RunTest("if (true) { return echoAsync(42); } else {return null; }"));
Assert.Equal(42, await RunTest("if (false) { return null } else { return echoAsync(42); }"));
}

[Fact]
public async void ForStatementAwaits()
{
Assert.Equal(10, await RunTest("for (var i=0; i<echoAsync(10); i++) ; return i;"));
Assert.Equal(20, await RunTest("for (var i=0; i<10+echoAsync(10); i++) ; return i;"));
Assert.Equal(30, await RunTest("for (var i=0; i<echoAsync(10)+20; i++) ; return i;"));
}

[Fact]
public async void ArrayIndexAwaits()
{
Assert.Equal(20, await RunTest("var x = [echoAsync(10), echoAsync(20), echoAsync(30)][1]; return x;"));
}

[Fact]
public async void ObjectPropertyNameIndexerAwaits()
{
Assert.Equal(42, await RunTest("var x = { value: 42 }; return x[echoAsync('value')];"));
}

[Fact]
public async void DoWhileConditionAwaits()
{
Assert.Equal(42, await RunTest("var result = null; do {{ result = echoAsync(42); }} while (false) ; result;"));
}

[Fact]
public async void FunctionBodyAwaits()
{
Assert.Equal(42, await RunTest("function foo() {{ return echoAsync(42); }} foo();"));
}

[Fact]
public async void SwitchCondtionAwaits()
{
Assert.Equal(42, await RunTest("switch (echoAsync('a')) { case 'a': return 42; default: return null; };"));
}

[Fact]
public async void SwitchCaseAwaits()
{
Assert.Equal(42, await RunTest("switch ('a') { case 'a': return echoAsync(42); default: return null; };"));
}

[Fact]
public async void WhileConditionAwaits()
{
Assert.Equal(42, await RunTest("index = 0; result = 0; while (echoAsync(index++) < 42) { result++}; return result;"));
}

[Fact]
public async void WhileBodyAwaits()
{
Assert.Equal(42, await RunTest("index = 0; result = 0; while (index++ < 42) { result = echoAsync(index) }; return result;"));
}
}
}
2 changes: 2 additions & 0 deletions Jint.Tests/Runtime/Domain/UuidConstructor.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Threading.Tasks;
using Jint.Native;
using Jint.Native.Function;
using Jint.Native.Object;
Expand Down Expand Up @@ -56,6 +57,7 @@ public static UuidConstructor CreateUuidConstructor(Engine engine)
}

public override JsValue Call(JsValue thisObject, JsValue[] arguments) => Construct(arguments, null);
public override Task<JsValue> CallAsync(JsValue thisObject, JsValue[] arguments) => Task.FromResult<JsValue>(Construct(arguments, null));

public void Configure()
{
Expand Down
19 changes: 13 additions & 6 deletions Jint.Tests/Runtime/EngineTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,26 +18,33 @@ namespace Jint.Tests.Runtime
public class EngineTests : IDisposable
{
private readonly Engine _engine;
private readonly Engine _asyncEngine;
private int countBreak = 0;
private StepMode stepMode;

public EngineTests(ITestOutputHelper output)
{
_engine = new Engine()
.SetValue("log", new Action<object>( o => output.WriteLine(o.ToString())))
.SetValue("assert", new Action<bool>(Assert.True))
.SetValue("equal", new Action<object, object>(Assert.Equal))
;
_engine = CreateEngine(output);
_asyncEngine = CreateEngine(output);
}

void IDisposable.Dispose()
{
}


private void RunTest(string source)
private Engine CreateEngine(ITestOutputHelper output)
{
return new Engine()
.SetValue("log", new Action<object>(o => output.WriteLine(o.ToString())))
.SetValue("assert", new Action<bool>(Assert.True))
.SetValue("equal", new Action<object, object>(Assert.Equal));
}

private async void RunTest(string source)
{
_engine.Execute(source);
await _asyncEngine.ExecuteAsync(source);
}

private string GetEmbeddedFile(string filename)
Expand Down
3 changes: 2 additions & 1 deletion Jint.Tests/Runtime/InteropTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,10 @@ void IDisposable.Dispose()
{
}

private void RunTest(string source)
private async void RunTest(string source)
{
_engine.Execute(source);
//await _engine.ExecuteAsync(source);
}

[Fact]
Expand Down
5 changes: 5 additions & 0 deletions Jint/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,9 @@
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All"/>
</ItemGroup>


<ItemGroup>
<ProjectCapability Include="DynamicDependentFile" />
<ProjectCapability Include="DynamicFileNesting" />
</ItemGroup>
</Project>
Loading