Optimise DynamicProxyMetaObject (#1152)
* Remove unnecessary ToArray call. * Remove Value property. One use compares with null, so cast to T is a waste. This leaves just one other use, so it can be inlined. * Remove _dontFallbackFirst Is always true. Remove it and branches for it being false. * Don't use Expression.Convert to reference types to object. The end-result is a no-op, so don't waste the allocation.
This commit is contained in:
committed by
James Newton-King
parent
cad2ec3a09
commit
ea6a21c4f3
@@ -800,7 +800,7 @@ namespace Newtonsoft.Json.Linq
|
||||
/// </returns>
|
||||
protected override DynamicMetaObject GetMetaObject(Expression parameter)
|
||||
{
|
||||
return new DynamicProxyMetaObject<JObject>(parameter, this, new JObjectDynamicProxy(), true);
|
||||
return new DynamicProxyMetaObject<JObject>(parameter, this, new JObjectDynamicProxy());
|
||||
}
|
||||
|
||||
private class JObjectDynamicProxy : DynamicProxy<JObject>
|
||||
|
||||
@@ -2365,7 +2365,7 @@ namespace Newtonsoft.Json.Linq
|
||||
/// </returns>
|
||||
protected virtual DynamicMetaObject GetMetaObject(Expression parameter)
|
||||
{
|
||||
return new DynamicProxyMetaObject<JToken>(parameter, this, new DynamicProxy<JToken>(), true);
|
||||
return new DynamicProxyMetaObject<JToken>(parameter, this, new DynamicProxy<JToken>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -966,7 +966,7 @@ namespace Newtonsoft.Json.Linq
|
||||
/// </returns>
|
||||
protected override DynamicMetaObject GetMetaObject(Expression parameter)
|
||||
{
|
||||
return new DynamicProxyMetaObject<JValue>(parameter, this, new JValueDynamicProxy(), true);
|
||||
return new DynamicProxyMetaObject<JValue>(parameter, this, new JValueDynamicProxy());
|
||||
}
|
||||
|
||||
private class JValueDynamicProxy : DynamicProxy<JValue>
|
||||
|
||||
@@ -29,25 +29,17 @@ using System.Collections.Generic;
|
||||
using System.Dynamic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Newtonsoft.Json.Utilities
|
||||
{
|
||||
internal sealed class DynamicProxyMetaObject<T> : DynamicMetaObject
|
||||
{
|
||||
private readonly DynamicProxy<T> _proxy;
|
||||
private readonly bool _dontFallbackFirst;
|
||||
|
||||
internal DynamicProxyMetaObject(Expression expression, T value, DynamicProxy<T> proxy, bool dontFallbackFirst)
|
||||
internal DynamicProxyMetaObject(Expression expression, T value, DynamicProxy<T> proxy)
|
||||
: base(expression, BindingRestrictions.Empty, value)
|
||||
{
|
||||
_proxy = proxy;
|
||||
_dontFallbackFirst = dontFallbackFirst;
|
||||
}
|
||||
|
||||
private new T Value
|
||||
{
|
||||
get { return (T)base.Value; }
|
||||
}
|
||||
|
||||
private bool IsOverridden(string method)
|
||||
@@ -108,7 +100,7 @@ namespace Newtonsoft.Json.Utilities
|
||||
//
|
||||
Fallback fallback = e => binder.FallbackInvokeMember(this, args, e);
|
||||
|
||||
DynamicMetaObject call = BuildCallMethodWithResult(
|
||||
return BuildCallMethodWithResult(
|
||||
"TryInvokeMember",
|
||||
binder,
|
||||
GetArgArray(args),
|
||||
@@ -121,8 +113,6 @@ namespace Newtonsoft.Json.Utilities
|
||||
),
|
||||
null
|
||||
);
|
||||
|
||||
return _dontFallbackFirst ? call : fallback(call);
|
||||
}
|
||||
|
||||
public override DynamicMetaObject BindCreateInstance(CreateInstanceBinder binder, DynamicMetaObject[] args)
|
||||
@@ -178,9 +168,13 @@ namespace Newtonsoft.Json.Utilities
|
||||
|
||||
private static readonly Expression[] NoArgs = new Expression[0];
|
||||
|
||||
private static Expression[] GetArgs(params DynamicMetaObject[] args)
|
||||
private static IEnumerable<Expression> GetArgs(params DynamicMetaObject[] args)
|
||||
{
|
||||
return args.Select(arg => Expression.Convert(arg.Expression, typeof(object))).ToArray();
|
||||
return args.Select(arg =>
|
||||
{
|
||||
Expression exp = arg.Expression;
|
||||
return exp.Type.IsValueType() ? Expression.Convert(exp, typeof(object)) : exp;
|
||||
});
|
||||
}
|
||||
|
||||
private static Expression[] GetArgArray(DynamicMetaObject[] args)
|
||||
@@ -190,10 +184,11 @@ namespace Newtonsoft.Json.Utilities
|
||||
|
||||
private static Expression[] GetArgArray(DynamicMetaObject[] args, DynamicMetaObject value)
|
||||
{
|
||||
return new Expression[]
|
||||
var exp = value.Expression;
|
||||
return new[]
|
||||
{
|
||||
Expression.NewArrayInit(typeof(object), GetArgs(args)),
|
||||
Expression.Convert(value.Expression, typeof(object))
|
||||
exp.Type.IsValueType() ? Expression.Convert(exp, typeof(object)) : exp
|
||||
};
|
||||
}
|
||||
|
||||
@@ -211,7 +206,7 @@ namespace Newtonsoft.Json.Utilities
|
||||
/// Helper method for generating a MetaObject which calls a
|
||||
/// specific method on Dynamic that returns a result
|
||||
/// </summary>
|
||||
private DynamicMetaObject CallMethodWithResult(string methodName, DynamicMetaObjectBinder binder, Expression[] args, Fallback fallback, Fallback fallbackInvoke = null)
|
||||
private DynamicMetaObject CallMethodWithResult(string methodName, DynamicMetaObjectBinder binder, IEnumerable<Expression> args, Fallback fallback, Fallback fallbackInvoke = null)
|
||||
{
|
||||
//
|
||||
// First, call fallback to do default binding
|
||||
@@ -219,21 +214,10 @@ namespace Newtonsoft.Json.Utilities
|
||||
//
|
||||
DynamicMetaObject fallbackResult = fallback(null);
|
||||
|
||||
DynamicMetaObject callDynamic = BuildCallMethodWithResult(methodName, binder, args, fallbackResult, fallbackInvoke);
|
||||
|
||||
//
|
||||
// Now, call fallback again using our new MO as the error
|
||||
// When we do this, one of two things can happen:
|
||||
// 1. Binding will succeed, and it will ignore our call to
|
||||
// the dynamic method, OR
|
||||
// 2. Binding will fail, and it will use the MO we created
|
||||
// above.
|
||||
//
|
||||
|
||||
return _dontFallbackFirst ? callDynamic : fallback(callDynamic);
|
||||
return BuildCallMethodWithResult(methodName, binder, args, fallbackResult, fallbackInvoke);
|
||||
}
|
||||
|
||||
private DynamicMetaObject BuildCallMethodWithResult(string methodName, DynamicMetaObjectBinder binder, Expression[] args, DynamicMetaObject fallbackResult, Fallback fallbackInvoke)
|
||||
private DynamicMetaObject BuildCallMethodWithResult(string methodName, DynamicMetaObjectBinder binder, IEnumerable<Expression> args, DynamicMetaObject fallbackResult, Fallback fallbackInvoke)
|
||||
{
|
||||
//
|
||||
// Build a new expression like:
|
||||
@@ -291,7 +275,7 @@ namespace Newtonsoft.Json.Utilities
|
||||
/// specific method on Dynamic, but uses one of the arguments for
|
||||
/// the result.
|
||||
/// </summary>
|
||||
private DynamicMetaObject CallMethodReturnLast(string methodName, DynamicMetaObjectBinder binder, Expression[] args, Fallback fallback)
|
||||
private DynamicMetaObject CallMethodReturnLast(string methodName, DynamicMetaObjectBinder binder, IEnumerable<Expression> args, Fallback fallback)
|
||||
{
|
||||
//
|
||||
// First, call fallback to do default binding
|
||||
@@ -312,9 +296,9 @@ namespace Newtonsoft.Json.Utilities
|
||||
callArgs.Add(Expression.Convert(Expression, typeof(T)));
|
||||
callArgs.Add(Constant(binder));
|
||||
callArgs.AddRange(args);
|
||||
callArgs[args.Length + 1] = Expression.Assign(result, callArgs[args.Length + 1]);
|
||||
callArgs[callArgs.Count - 1] = Expression.Assign(result, callArgs[callArgs.Count - 1]);
|
||||
|
||||
DynamicMetaObject callDynamic = new DynamicMetaObject(
|
||||
return new DynamicMetaObject(
|
||||
Expression.Block(
|
||||
new[] { result },
|
||||
Expression.Condition(
|
||||
@@ -330,16 +314,6 @@ namespace Newtonsoft.Json.Utilities
|
||||
),
|
||||
GetRestrictions().Merge(fallbackResult.Restrictions)
|
||||
);
|
||||
|
||||
//
|
||||
// Now, call fallback again using our new MO as the error
|
||||
// When we do this, one of two things can happen:
|
||||
// 1. Binding will succeed, and it will ignore our call to
|
||||
// the dynamic method, OR
|
||||
// 2. Binding will fail, and it will use the MO we created
|
||||
// above.
|
||||
//
|
||||
return _dontFallbackFirst ? callDynamic : fallback(callDynamic);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -364,7 +338,7 @@ namespace Newtonsoft.Json.Utilities
|
||||
// Build a new expression like:
|
||||
// if (TryDeleteMember(payload)) { } else { fallbackResult }
|
||||
//
|
||||
DynamicMetaObject callDynamic = new DynamicMetaObject(
|
||||
return new DynamicMetaObject(
|
||||
Expression.Condition(
|
||||
Expression.Call(
|
||||
Expression.Constant(_proxy),
|
||||
@@ -377,16 +351,6 @@ namespace Newtonsoft.Json.Utilities
|
||||
),
|
||||
GetRestrictions().Merge(fallbackResult.Restrictions)
|
||||
);
|
||||
|
||||
//
|
||||
// Now, call fallback again using our new MO as the error
|
||||
// When we do this, one of two things can happen:
|
||||
// 1. Binding will succeed, and it will ignore our call to
|
||||
// the dynamic method, OR
|
||||
// 2. Binding will fail, and it will use the MO we created
|
||||
// above.
|
||||
//
|
||||
return _dontFallbackFirst ? callDynamic : fallback(callDynamic);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -402,7 +366,7 @@ namespace Newtonsoft.Json.Utilities
|
||||
|
||||
public override IEnumerable<string> GetDynamicMemberNames()
|
||||
{
|
||||
return _proxy.GetDynamicMemberNames(Value);
|
||||
return _proxy.GetDynamicMemberNames((T)Value);
|
||||
}
|
||||
|
||||
// It is okay to throw NotSupported from this binder. This object
|
||||
|
||||
Reference in New Issue
Block a user