Skip to content

Commit

Permalink
Add fast path without try-catch for CLR function call (#1651)
Browse files Browse the repository at this point in the history
  • Loading branch information
lahma authored Oct 21, 2023
1 parent 1a6aa38 commit 8794aa0
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 53 deletions.
4 changes: 3 additions & 1 deletion Jint/Options.cs
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ public class InteropOptions
/// to the CLR host and interrupt the script execution. If handler returns true these exceptions are converted
/// to JS errors that can be caught by the script.
/// </summary>
public ExceptionHandlerDelegate ExceptionHandler { get; set; } = static exception => false;
public ExceptionHandlerDelegate ExceptionHandler { get; set; } = _defaultExceptionHandler;

/// <summary>
/// Assemblies to allow scripts to call CLR types directly like <example>System.IO.File</example>.
Expand Down Expand Up @@ -328,6 +328,8 @@ public class InteropOptions
/// </summary>
public Func<Engine, Type, JsValue[], object?> CreateTypeReferenceObject = (_, _, _) => null;

internal static readonly ExceptionHandlerDelegate _defaultExceptionHandler = static exception => false;

/// <summary>
/// When not null, is used to serialize any CLR object in an
/// <see cref="IObjectWrapper"/> passing through 'JSON.stringify'.
Expand Down
107 changes: 55 additions & 52 deletions Jint/Runtime/Interop/ClrFunctionInstance.cs
Original file line number Diff line number Diff line change
@@ -1,78 +1,81 @@
using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;
using Jint.Native;
using Jint.Native.Function;
using Jint.Runtime.Descriptors;

namespace Jint.Runtime.Interop
namespace Jint.Runtime.Interop;

/// <summary>
/// Wraps a Clr method into a FunctionInstance
/// </summary>
public sealed class ClrFunctionInstance : FunctionInstance, IEquatable<ClrFunctionInstance>
{
/// <summary>
/// Wraps a Clr method into a FunctionInstance
/// </summary>
public sealed class ClrFunctionInstance : FunctionInstance, IEquatable<ClrFunctionInstance>
internal readonly Func<JsValue, JsValue[], JsValue> _func;
private readonly bool _bubbleExceptions;

public ClrFunctionInstance(
Engine engine,
string name,
Func<JsValue, JsValue[], JsValue> func,
int length = 0,
PropertyFlag lengthFlags = PropertyFlag.AllForbidden)
: base(engine, engine.Realm, new JsString(name))
{
internal readonly Func<JsValue, JsValue[], JsValue> _func;
_func = func;

public ClrFunctionInstance(
Engine engine,
string name,
Func<JsValue, JsValue[], JsValue> func,
int length = 0,
PropertyFlag lengthFlags = PropertyFlag.AllForbidden)
: base(engine, engine.Realm, new JsString(name))
{
_func = func;
_prototype = engine._originalIntrinsics.Function.PrototypeObject;

_prototype = engine._originalIntrinsics.Function.PrototypeObject;
_length = lengthFlags == PropertyFlag.AllForbidden
? PropertyDescriptor.AllForbiddenDescriptor.ForNumber(length)
: new PropertyDescriptor(JsNumber.Create(length), lengthFlags);

_length = lengthFlags == PropertyFlag.AllForbidden
? PropertyDescriptor.AllForbiddenDescriptor.ForNumber(length)
: new PropertyDescriptor(JsNumber.Create(length), lengthFlags);
}
_bubbleExceptions = _engine.Options.Interop.ExceptionHandler == InteropOptions._defaultExceptionHandler;
}

protected internal override JsValue Call(JsValue thisObject, JsValue[] arguments) => _bubbleExceptions ? _func(thisObject, arguments) : CallSlow(thisObject, arguments);

protected internal override JsValue Call(JsValue thisObject, JsValue[] arguments)
[MethodImpl(MethodImplOptions.NoInlining)]
private JsValue CallSlow(JsValue thisObject, JsValue[] arguments)
{
try
{
try
return _func(thisObject, arguments);
}
catch (Exception e) when (e is not JavaScriptException)
{
if (_engine.Options.Interop.ExceptionHandler(e))
{
return _func(thisObject, arguments);
ExceptionHelper.ThrowJavaScriptException(_realm.Intrinsics.Error, e.Message);
}
catch (Exception e) when (e is not JavaScriptException)
else
{
if (_engine.Options.Interop.ExceptionHandler(e))
{
ExceptionHelper.ThrowJavaScriptException(_realm.Intrinsics.Error, e.Message);
}
else
{
ExceptionDispatchInfo.Capture(e).Throw();
}

return Undefined;
ExceptionDispatchInfo.Capture(e).Throw();
}

return Undefined;
}
}

public override bool Equals(JsValue? obj) => Equals(obj as ClrFunctionInstance);

public override bool Equals(JsValue? obj)
public bool Equals(ClrFunctionInstance? other)
{
if (ReferenceEquals(null, other))
{
return Equals(obj as ClrFunctionInstance);
return false;
}

public bool Equals(ClrFunctionInstance? other)
if (ReferenceEquals(this, other))
{
if (ReferenceEquals(null, other))
{
return false;
}

if (ReferenceEquals(this, other))
{
return true;
}

if (_func == other._func)
{
return true;
}
return true;
}

return false;
if (_func == other._func)
{
return true;
}

return false;
}
}

0 comments on commit 8794aa0

Please sign in to comment.