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:
Jon Hanna
2017-01-09 14:44:56 +13:00
committed by James Newton-King
parent cad2ec3a09
commit ea6a21c4f3
4 changed files with 22 additions and 58 deletions
+1 -1
View File
@@ -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>
+1 -1
View File
@@ -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>
+1 -1
View File
@@ -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