Skip to content

Commit

Permalink
Keep track of MethodInfoFunctionInstance's target object (#1658)
Browse files Browse the repository at this point in the history
  • Loading branch information
lahma authored Oct 25, 2023
1 parent adeb772 commit 5ee35f1
Show file tree
Hide file tree
Showing 8 changed files with 30 additions and 12 deletions.
9 changes: 9 additions & 0 deletions Jint.Tests/Runtime/InteropTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3331,5 +3331,14 @@ public void AccessingInterfaceShouldContainExtendedInterfaces()
var result = engine.Evaluate("const strings = Utils.GetStrings(); strings.Count;").AsNumber();
Assert.Equal(3, result);
}

[Fact]
public void CanDestructureInteropTargetMethod()
{
var engine = new Engine();
engine.SetValue("test", new Utils());
var result = engine.Evaluate("const { getStrings } = test; getStrings().Count;");
Assert.Equal(3, result);
}
}
}
2 changes: 1 addition & 1 deletion Jint/Native/Error/ErrorInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,6 @@ internal void InstallErrorCause(JsValue options)

public override string ToString()
{
return Engine.Realm.Intrinsics.Error.PrototypeObject.ToString(this, Arguments.Empty).ToObject().ToString() ?? "";
return Engine.Realm.Intrinsics.Error.PrototypeObject.ToString(this, Arguments.Empty).ToObject()?.ToString() ?? "";
}
}
2 changes: 1 addition & 1 deletion Jint/Native/JsNull.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ internal JsNull() : base(Types.Null)
{
}

public override object ToObject() => null!;
public override object? ToObject() => null;

public override string ToString() => "null";

Expand Down
2 changes: 1 addition & 1 deletion Jint/Native/JsUndefined.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ internal JsUndefined() : base(Types.Undefined)
{
}

public override object ToObject() => null!;
public override object? ToObject() => null;

public override string ToString() => "undefined";

Expand Down
2 changes: 1 addition & 1 deletion Jint/Native/JsValue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ public static JsValue FromObjectWithType(Engine engine, object? value, Type? typ
/// Converts a <see cref="JsValue"/> to its underlying CLR value.
/// </summary>
/// <returns>The underlying CLR value of the <see cref="JsValue"/> instance.</returns>
public abstract object ToObject();
public abstract object? ToObject();

/// <summary>
/// Coerces boolean value from <see cref="JsValue"/> instance.
Expand Down
10 changes: 8 additions & 2 deletions Jint/Options.cs
Original file line number Diff line number Diff line change
Expand Up @@ -169,10 +169,16 @@ private static void AttachExtensionMethodsToPrototype(Engine engine, ObjectInsta

foreach (var overloads in methods.GroupBy(x => x.Name))
{
string name = overloads.Key;
PropertyDescriptor CreateMethodInstancePropertyDescriptor(ClrFunctionInstance? function)
{
var instance = new MethodInfoFunctionInstance(engine, objectType, name, MethodDescriptor.Build(overloads.ToList()), function);
var instance = new MethodInfoFunctionInstance(
engine,
objectType,
target: null,
overloads.Key,
methods: MethodDescriptor.Build(overloads.ToList()),
function);

return new PropertyDescriptor(instance, PropertyFlag.AllForbidden);
}

Expand Down
13 changes: 8 additions & 5 deletions Jint/Runtime/Interop/MethodInfoFunctionInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,29 @@ namespace Jint.Runtime.Interop
internal sealed class MethodInfoFunctionInstance : FunctionInstance
{
private readonly Type _targetType;
private readonly object? _target;
private readonly string _name;
private readonly MethodDescriptor[] _methods;
private readonly ClrFunctionInstance? _fallbackClrFunctionInstance;

public MethodInfoFunctionInstance(
Engine engine,
Type targetType,
object? target,
string name,
MethodDescriptor[] methods,
ClrFunctionInstance? fallbackClrFunctionInstance = null)
: base(engine, engine.Realm, new JsString(name))
{
_targetType = targetType;
_target = target;
_name = name;
_methods = methods;
_fallbackClrFunctionInstance = fallbackClrFunctionInstance;
_prototype = engine.Realm.Intrinsics.Function.PrototypeObject;
}

private static bool IsGenericParameter(object argObj, Type parameterType)
private static bool IsGenericParameter(object? argObj, Type parameterType)
{
if (argObj is null)
{
Expand All @@ -49,7 +52,7 @@ private static bool IsGenericParameter(object argObj, Type parameterType)
return false;
}

private static void HandleGenericParameter(object argObj, Type parameterType, Type[] genericArgTypes)
private static void HandleGenericParameter(object? argObj, Type parameterType, Type[] genericArgTypes)
{
if (argObj is null)
{
Expand Down Expand Up @@ -94,7 +97,7 @@ private static void HandleGenericParameter(object argObj, Type parameterType, Ty
}
}

private static MethodBase ResolveMethod(MethodBase method, ParameterInfo[] methodParameters, object thisObj, JsValue[] arguments)
private static MethodBase ResolveMethod(MethodBase method, ParameterInfo[] methodParameters, JsValue[] arguments)
{
if (!method.IsGenericMethod)
{
Expand Down Expand Up @@ -156,7 +159,7 @@ JsValue[] ArgumentProvider(MethodDescriptor method)
}

var converter = Engine.ClrTypeConverter;
var thisObj = thisObject.ToObject();
var thisObj = thisObject.ToObject() ?? _target;
object?[]? parameters = null;
foreach (var (method, arguments, _) in TypeConverter.FindBestMatch(_engine, _methods, ArgumentProvider))
{
Expand All @@ -167,7 +170,7 @@ JsValue[] ArgumentProvider(MethodDescriptor method)
}

var argumentsMatch = true;
var resolvedMethod = ResolveMethod(method.Method, methodParameters, thisObj, arguments);
var resolvedMethod = ResolveMethod(method.Method, methodParameters, arguments);
// TPC: if we're concerned about cost of MethodInfo.GetParameters() - we could only invoke it if this ends up being a generic method (i.e. they will be different in that scenario)
methodParameters = resolvedMethod.GetParameters();
for (var i = 0; i < parameters.Length; i++)
Expand Down
2 changes: 1 addition & 1 deletion Jint/Runtime/Interop/Reflection/MethodAccessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ protected override void DoSetValue(object target, object? value) { }

public override PropertyDescriptor CreatePropertyDescriptor(Engine engine, object target, bool enumerable = true)
{
return new(new MethodInfoFunctionInstance(engine, _targetType, _name, _methods), PropertyFlag.AllForbidden);
return new(new MethodInfoFunctionInstance(engine, _targetType, target, _name, _methods), PropertyFlag.AllForbidden);
}
}
}

0 comments on commit 5ee35f1

Please sign in to comment.