Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
<PackageVersion Include="SourceMaps" Version="0.3.0" />
<PackageVersion Include="Spectre.Console.Cli" Version="0.45.0" />
<PackageVersion Include="System.Text.Json" Version="9.0.1" />
<PackageVersion Include="System.Threading.Tasks.Extensions" Version="4.6.0" />
<PackageVersion Include="System.ValueTuple" Version="4.5.0" />
<PackageVersion Include="Test262Harness" Version="1.0.1" />
<PackageVersion Include="xunit" Version="2.9.3" />
<PackageVersion Include="xunit.runner.visualstudio" Version="3.0.1" PrivateAssets="all" />
Expand Down
1 change: 1 addition & 0 deletions Jint.AotExample/Jint.AotExample.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<PublishAot>true</PublishAot>
<NoWarn>$(NoWarn);NU1507</NoWarn>
</PropertyGroup>

<ItemGroup>
Expand Down
1 change: 1 addition & 0 deletions Jint.Repl/Jint.Repl.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<OutputType>Exe</OutputType>
<IsPackable>false</IsPackable>
<PublishAot>true</PublishAot>
<NoWarn>$(NoWarn);NU1507</NoWarn>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Jint\Jint.csproj" />
Expand Down
1 change: 1 addition & 0 deletions Jint.Tests.CommonScripts/Jint.Tests.CommonScripts.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<TargetFrameworks>net9.0</TargetFrameworks>
<TargetFrameworks Condition="'$(OS)' == 'Windows_NT'">$(TargetFrameworks);net472</TargetFrameworks>
<IsPackable>false</IsPackable>
<NoWarn>$(NoWarn);NU1507</NoWarn>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<TargetFrameworks Condition="'$(OS)' == 'Windows_NT'">$(TargetFrameworks);net472</TargetFrameworks>
<IsPackable>false</IsPackable>
<NoWarn>612</NoWarn>
<NoWarn>$(NoWarn);NU1507</NoWarn>
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
</PropertyGroup>

Expand Down
1 change: 1 addition & 0 deletions Jint.Tests.Test262/Jint.Tests.Test262.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<SignAssembly>true</SignAssembly>
<IsPackable>false</IsPackable>
<NoWarn>$(NoWarn);CS8002</NoWarn>
<NoWarn>$(NoWarn);NU1507</NoWarn>
<GeneratedTestSuiteDir>Generated</GeneratedTestSuiteDir>
</PropertyGroup>

Expand Down
1 change: 1 addition & 0 deletions Jint.Tests/Jint.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<SignAssembly>true</SignAssembly>
<IsPackable>false</IsPackable>
<NoWarn>$(NoWarn);612</NoWarn>
<NoWarn>$(NoWarn);NU1507</NoWarn>
</PropertyGroup>

<ItemGroup>
Expand Down
194 changes: 194 additions & 0 deletions Jint/Engine.Async.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
using System.Runtime.CompilerServices;
using Jint.Native;
using Jint.Native.Function;
using Jint.Runtime;
using Jint.Runtime.Interpreter;
using Jint.Runtime.Interpreter.Expressions;

namespace Jint;

public partial class Engine
{
/// <summary>
/// Invoke the current value as function.
/// </summary>
/// <param name="propertyName">The name of the function to call.</param>
/// <param name="arguments">The arguments of the function call.</param>
/// <returns>The value returned by the function call.</returns>
public ValueTask<JsValue> InvokeAsync(string propertyName, params object?[] arguments)
{
return InvokeAsync(propertyName, thisObj: null, arguments);
}

/// <summary>
/// Invoke the current value as function.
/// </summary>
/// <param name="propertyName">The name of the function to call.</param>
/// <param name="thisObj">The this value inside the function call.</param>
/// <param name="arguments">The arguments of the function call.</param>
/// <returns>The value returned by the function call.</returns>
public ValueTask<JsValue> InvokeAsync(string propertyName, object? thisObj, object?[] arguments)
{
var value = GetValue(propertyName);

return InvokeAsync(value, thisObj, arguments);
}

/// <summary>
/// Invoke the current value as function.
/// </summary>
/// <param name="value">The function to call.</param>
/// <param name="arguments">The arguments of the function call.</param>
/// <returns>The value returned by the function call.</returns>
public ValueTask<JsValue> InvokeAsync(JsValue value, params object?[] arguments)
{
return InvokeAsync(value, thisObj: null, arguments);
}

/// <summary>
/// Invoke the current value as function.
/// </summary>
/// <param name="value">The function to call.</param>
/// <param name="thisObj">The this value inside the function call.</param>
/// <param name="arguments">The arguments of the function call.</param>
/// <returns>The value returned by the function call.</returns>
public async ValueTask<JsValue> InvokeAsync(JsValue value, object? thisObj, object?[] arguments)
{
var callable = value as ICallable;
if (callable is null)
{
ExceptionHelper.ThrowJavaScriptException(Realm.Intrinsics.TypeError, "Can only invoke functions");
}

async ValueTask<JsValue> DoInvokeAsync()
{
var items = _jsValueArrayPool.RentArray(arguments.Length);
for (var i = 0; i < arguments.Length; ++i)
{
items[i] = JsValue.FromObject(this, arguments[i]);
}

// ensure logic is in sync between Call, Construct, engine.Invoke and JintCallExpression!
JsValue result;
var thisObject = JsValue.FromObject(this, thisObj);
if (callable is Function functionInstance)
{
var callStack = CallStack;
callStack.Push(functionInstance, expression: null, ExecutionContext);
try
{
result = await callable.CallAsync(thisObject, items).ConfigureAwait(false);
}
finally
{
// if call stack was reset due to recursive call to engine or similar, we might not have it anymore
if (callStack.Count > 0)
{
callStack.Pop();
}
}
}
else
{
result = await callable.CallAsync(thisObject, items).ConfigureAwait(false);
}

_jsValueArrayPool.ReturnArray(items);
return result;
}

return await ExecuteWithConstraintsAsync(Options.Strict, DoInvokeAsync).ConfigureAwait(false);
}

/// <summary>
/// Invokes the callable and returns the resulting object.
/// </summary>
/// <param name="callable">The callable.</param>
/// <param name="thisObject">Value bound as this.</param>
/// <param name="arguments">The arguments of the call.</param>
/// <returns>The value returned by the call.</returns>
public ValueTask<JsValue> CallAsync(JsValue callable, JsValue thisObject, JsValue[] arguments)
{
ValueTask<JsValue> Callback()
{
if (!callable.IsCallable)
{
ExceptionHelper.ThrowArgumentException(callable + " is not callable");
}

return CallAsync((ICallable) callable, thisObject, arguments, null);
}

return ExecuteWithConstraintsAsync(Options.Strict, Callback);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal ValueTask<JsValue> CallAsync(ICallable callable, JsValue thisObject, JsValue[] arguments, JintExpression? expression)
{
if (callable is Function functionInstance)
{
return CallAsync(functionInstance, thisObject, arguments, expression);
}

return callable.CallAsync(thisObject, arguments);
}

internal async ValueTask<JsValue> CallAsync(
Function function,
JsValue thisObject,
JsValue[] arguments,
JintExpression? expression)
{
// ensure logic is in sync between Call, Construct, engine.Invoke and JintCallExpression!

var recursionDepth = CallStack.Push(function, expression, ExecutionContext);

if (recursionDepth > Options.Constraints.MaxRecursionDepth)
{
// automatically pops the current element as it was never reached
ExceptionHelper.ThrowRecursionDepthOverflowException(CallStack);
}

JsValue result;
try
{
result = await function.CallAsync(thisObject, arguments).ConfigureAwait(false);
}
finally
{
// if call stack was reset due to recursive call to engine or similar, we might not have it anymore
if (CallStack.Count > 0)
{
CallStack.Pop();
}
}

return result;
}

internal async ValueTask<T> ExecuteWithConstraintsAsync<T>(bool strict, Func<ValueTask<T>> callback)
{
ResetConstraints();

var ownsContext = _activeEvaluationContext is null;
_activeEvaluationContext ??= new EvaluationContext(this);

try
{
using (new StrictModeScope(strict))
{
return await callback().ConfigureAwait(false);
}
}
finally
{
if (ownsContext)
{
_activeEvaluationContext = null!;
}
ResetConstraints();
_agent.ClearKeptObjects();
}
}

}
98 changes: 5 additions & 93 deletions Jint/Engine.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using System.Diagnostics;
using System.Collections.Concurrent;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using Jint.Collections;
Expand Down Expand Up @@ -759,50 +759,7 @@ public JsValue Invoke(JsValue value, params object?[] arguments)
/// <returns>The value returned by the function call.</returns>
public JsValue Invoke(JsValue value, object? thisObj, object?[] arguments)
{
var callable = value as ICallable;
if (callable is null)
{
ExceptionHelper.ThrowJavaScriptException(Realm.Intrinsics.TypeError, "Can only invoke functions");
}

JsValue DoInvoke()
{
var items = _jsValueArrayPool.RentArray(arguments.Length);
for (var i = 0; i < arguments.Length; ++i)
{
items[i] = JsValue.FromObject(this, arguments[i]);
}

// ensure logic is in sync between Call, Construct, engine.Invoke and JintCallExpression!
JsValue result;
var thisObject = JsValue.FromObject(this, thisObj);
if (callable is Function functionInstance)
{
var callStack = CallStack;
callStack.Push(functionInstance, expression: null, ExecutionContext);
try
{
result = functionInstance.Call(thisObject, items);
}
finally
{
// if call stack was reset due to recursive call to engine or similar, we might not have it anymore
if (callStack.Count > 0)
{
callStack.Pop();
}
}
}
else
{
result = callable.Call(thisObject, items);
}

_jsValueArrayPool.ReturnArray(items);
return result;
}

return ExecuteWithConstraints(Options.Strict, DoInvoke);
return InvokeAsync(value, thisObj, arguments).Preserve().GetAwaiter().GetResult();
}

internal T ExecuteWithConstraints<T>(bool strict, Func<T> callback)
Expand Down Expand Up @@ -1448,28 +1405,7 @@ public JsValue Call(JsValue callable, params JsValue[] arguments)
/// <returns>The value returned by the call.</returns>
public JsValue Call(JsValue callable, JsValue thisObject, JsValue[] arguments)
{
JsValue Callback()
{
if (!callable.IsCallable)
{
ExceptionHelper.ThrowArgumentException(callable + " is not callable");
}

return Call((ICallable) callable, thisObject, arguments, null);
}

return ExecuteWithConstraints(Options.Strict, Callback);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal JsValue Call(ICallable callable, JsValue thisObject, JsValue[] arguments, JintExpression? expression)
{
if (callable is Function functionInstance)
{
return Call(functionInstance, thisObject, arguments, expression);
}

return callable.Call(thisObject, arguments);
return CallAsync(callable, thisObject, arguments).Preserve().GetAwaiter().GetResult();
}

/// <summary>
Expand Down Expand Up @@ -1528,31 +1464,7 @@ internal JsValue Call(
JsValue[] arguments,
JintExpression? expression)
{
// ensure logic is in sync between Call, Construct, engine.Invoke and JintCallExpression!

var recursionDepth = CallStack.Push(function, expression, ExecutionContext);

if (recursionDepth > Options.Constraints.MaxRecursionDepth)
{
// automatically pops the current element as it was never reached
ExceptionHelper.ThrowRecursionDepthOverflowException(CallStack);
}

JsValue result;
try
{
result = function.Call(thisObject, arguments);
}
finally
{
// if call stack was reset due to recursive call to engine or similar, we might not have it anymore
if (CallStack.Count > 0)
{
CallStack.Pop();
}
}

return result;
return CallAsync(function, thisObject, arguments, expression).Preserve().GetAwaiter().GetResult();
}

private ObjectInstance Construct(
Expand Down
5 changes: 4 additions & 1 deletion Jint/Jint.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
<PackageReadmeFile>README.md</PackageReadmeFile>

<NoWarn>$(NoWarn);1591</NoWarn>
<NoWarn>$(NoWarn);NU1507</NoWarn>

<IsAotCompatible Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net7.0'))">true</IsAotCompatible>

Expand All @@ -33,12 +34,14 @@
</PropertyGroup>

<ItemGroup>
<None Include="../README.md" Pack="true" PackagePath="\"/>
<None Include="../README.md" Pack="true" PackagePath="\" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Acornima" />
<PackageReference Include="Meziantou.Analyzer" PrivateAssets="all" />
<PackageReference Include="System.Threading.Tasks.Extensions" />
<PackageReference Include="System.ValueTuple" />
</ItemGroup>

<ItemGroup>
Expand Down
Loading