diff --git a/lib/linqnhibernate/NHibernate.Linq.dll b/lib/linqnhibernate/NHibernate.Linq.dll index 47d6d1303..682351e37 100644 Binary files a/lib/linqnhibernate/NHibernate.Linq.dll and b/lib/linqnhibernate/NHibernate.Linq.dll differ diff --git a/lib/linqnhibernate/NHibernate.Linq.xml b/lib/linqnhibernate/NHibernate.Linq.xml index 7fc5d350e..65b1765f1 100644 --- a/lib/linqnhibernate/NHibernate.Linq.xml +++ b/lib/linqnhibernate/NHibernate.Linq.xml @@ -486,6 +486,12 @@ + + + Brings certain basic expression patterns closer to the surface to + avoid a lambda compile and dynamic invoke in simple cases + + Performs bottom-up analysis to determine which nodes can possibly diff --git a/lib/linqnhibernate/condensing-constant-expressions.patch b/lib/linqnhibernate/condensing-constant-expressions.patch new file mode 100644 index 000000000..051176fee --- /dev/null +++ b/lib/linqnhibernate/condensing-constant-expressions.patch @@ -0,0 +1,156 @@ +Index: src/NHibernate.Linq/src/NHibernate.Linq/Visitors/Evaluator.cs +=================================================================== +--- src/NHibernate.Linq/src/NHibernate.Linq/Visitors/Evaluator.cs (revision 1432) ++++ src/NHibernate.Linq/src/NHibernate.Linq/Visitors/Evaluator.cs (working copy) +@@ -2,6 +2,7 @@ + using System.Collections.Generic; + using System.Linq; + using System.Linq.Expressions; ++using System.Reflection; + + namespace NHibernate.Linq.Visitors + { +@@ -76,12 +77,143 @@ + if (e.NodeType == ExpressionType.Lambda) + return e; + ++ Expression condensed = new Condensor().Visit(e); ++ if (condensed.NodeType == ExpressionType.Constant) ++ return condensed; ++ + LambdaExpression lambda = Expression.Lambda(e); + Delegate fn = lambda.Compile(); + return Expression.Constant(fn.DynamicInvoke(null), e.Type); + } + } + ++ /// ++ /// Brings certain basic expression patterns closer to the surface to ++ /// avoid a lambda compile and dynamic invoke in simple cases ++ /// ++ class Condensor : ExpressionVisitor ++ { ++ protected override Expression VisitMemberAccess(MemberExpression m) ++ { ++ Expression exp = Visit(m.Expression); ++ ++ object constant; ++ if (m.NodeType== ExpressionType.MemberAccess && TryGetConstant(exp, out constant)) ++ { ++ if (m.Member.MemberType == MemberTypes.Field) ++ { ++ FieldInfo field = (FieldInfo) m.Member; ++ object value = field.GetValue(constant); ++ return Expression.Constant(value, m.Type); ++ } ++ } ++ ++ if (exp != m.Expression) ++ { ++ return Expression.MakeMemberAccess(exp, m.Member); ++ } ++ return m; ++ } ++ ++ ++ protected override Expression VisitUnary(UnaryExpression u) { ++ Expression operand = Visit(u.Operand); ++ ++ object constant; ++ if (u.NodeType== ExpressionType.Convert && TryGetConstant(operand, out constant)) ++ { ++ if (u.Method == null) ++ { ++ Func converter = BindConverter(operand.Type, u.Type); ++ object value = converter(constant); ++ return Expression.Constant(value, u.Type); ++ } ++ } ++ ++ if (operand != u.Operand) { ++ return Expression.MakeUnary(u.NodeType, operand, u.Type, u.Method); ++ } ++ return u; ++ } ++ ++ private static bool TryGetConstant(Expression expression, out object constant) { ++ if (expression == null) { ++ constant = null; ++ return true; ++ } ++ ++ if (expression.NodeType == ExpressionType.Constant) { ++ constant = ((ConstantExpression)expression).Value; ++ return true; ++ } ++ ++ if (expression.NodeType == ExpressionType.New) { ++ NewExpression nex = (NewExpression)expression; ++ object[] constants; ++ if (nex.Members == null && TryGetConstants(nex.Arguments, out constants)) { ++ constant = nex.Constructor.Invoke(constants); ++ return true; ++ } ++ } ++ ++ constant = null; ++ return false; ++ } ++ ++ private static bool TryGetConstants(IList expressions, out object[] constants) { ++ if (expressions == null) { ++ constants = null; ++ return false; ++ } ++ ++ object[] results = new object[expressions.Count]; ++ for (int index = 0; index != expressions.Count; ++index) { ++ if (!TryGetConstant(expressions[index], out results[index])) { ++ constants = null; ++ return false; ++ } ++ } ++ ++ constants = results; ++ return true; ++ } ++ ++ ++ private static readonly IDictionary>> _converterGroups = new Dictionary>>(); ++ ++ private static Func BindConverter(System.Type inType, System.Type outType) ++ { ++ IDictionary> converterGroup; ++ lock(_converterGroups) ++ { ++ if (!_converterGroups.TryGetValue(inType, out converterGroup)) ++ { ++ converterGroup = new Dictionary>(); ++ _converterGroups[inType] = converterGroup; ++ } ++ } ++ ++ Func converter; ++ lock (converterGroup) ++ { ++ if (!converterGroup.TryGetValue(outType, out converter)) ++ { ++ var arg0 = Expression.Parameter(typeof(object), "arg0"); ++ var lambda = Expression.Lambda>( ++ Expression.ConvertChecked( ++ Expression.Convert( ++ Expression.ConvertChecked(arg0, inType), ++ outType), ++ typeof(object)), ++ arg0); ++ converter = lambda.Compile(); ++ converterGroup[outType] = converter; ++ } ++ } ++ return converter; ++ } ++ } ++ + /// + /// Performs bottom-up analysis to determine which nodes can possibly + /// be part of an evaluated sub-tree. diff --git a/lib/linqnhibernate/orchard-buildnotes.txt b/lib/linqnhibernate/orchard-buildnotes.txt new file mode 100644 index 000000000..dffb973d7 --- /dev/null +++ b/lib/linqnhibernate/orchard-buildnotes.txt @@ -0,0 +1,5 @@ + +https://nhcontrib.svn.sourceforge.net/svnroot/nhcontrib/trunk/src/NHibernate.Linq +at revision #1432 +applied condensing-constant-expressions.patch +nant -D:project.config=release