Skip to content

Commit f214e54

Browse files
committed
Cached TupleParameter
1 parent 96cfe99 commit f214e54

3 files changed

Lines changed: 43 additions & 34 deletions

File tree

Orm/Xtensive.Orm/Orm/Linq/Materialization/ExpressionMaterializer.cs

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,14 @@ namespace Xtensive.Orm.Linq.Materialization
2626
[Serializable]
2727
internal class ExpressionMaterializer : PersistentExpressionVisitor
2828
{
29-
private static readonly MethodInfo BuildPersistentTupleMethod;
30-
private static readonly MethodInfo GetTupleSegmentMethod;
31-
private static readonly MethodInfo GetParameterValueMethod;
32-
private static readonly PropertyInfo ParameterContextProperty;
33-
private static readonly MethodInfo GetTupleParameterValueMethod;
29+
private static readonly MethodInfo BuildPersistentTupleMethod = typeof(ExpressionMaterializer).GetMethod(nameof(BuildPersistentTuple), BindingFlags.NonPublic | BindingFlags.Static);
30+
private static readonly MethodInfo GetTupleSegmentMethod = typeof(ExpressionMaterializer).GetMethod(nameof(GetTupleSegment), BindingFlags.NonPublic | BindingFlags.Static);
31+
private static readonly MethodInfo GetParameterValueMethod = WellKnownOrmTypes.ParameterContext.GetMethod(nameof(ParameterContext.GetValue));
32+
private static readonly PropertyInfo ParameterContextProperty = WellKnownOrmTypes.ItemMaterializationContext.GetProperty(nameof(ItemMaterializationContext.ParameterContext));
33+
private static readonly MethodInfo GetTupleParameterValueMethod = GetParameterValueMethod.MakeGenericMethod(WellKnownOrmTypes.Tuple);
3434

35-
private readonly TranslatorContext context;
36-
private readonly ParameterExpression tupleParameter;
37-
private readonly ParameterExpression itemMaterializationContextParameter;
38-
private readonly Dictionary<IEntityExpression, int> entityRegistry = new Dictionary<IEntityExpression, int>();
39-
private readonly HashSet<Parameter<Tuple>> tupleParameters;
35+
private static readonly ParameterExpression MaterializationContextParameter = Expression.Parameter(WellKnownOrmTypes.ItemMaterializationContext, "mc");
36+
private static readonly ConstantExpression TypeReferenceAccuracyConstantExpression = Expression.Constant(TypeReferenceAccuracy.BaseType);
4037

4138
private static readonly Type[] SubQueryConstructorArgumentTypes = {
4239
WellKnownOrmTypes.ProjectionExpression,
@@ -46,23 +43,35 @@ internal class ExpressionMaterializer : PersistentExpressionVisitor
4643
WellKnownOrmTypes.ItemMaterializationContext
4744
};
4845

46+
private static readonly Type[] GroupingConstructorArgumentTypesTemplate = new[] {
47+
WellKnownOrmTypes.ProjectionExpression,
48+
WellKnownOrmTypes.TranslatedQuery,
49+
WellKnownOrmTypes.ParameterOfTuple,
50+
WellKnownOrmTypes.Tuple,
51+
null,
52+
WellKnownOrmTypes.ItemMaterializationContext
53+
};
54+
55+
private readonly TranslatorContext context;
56+
private readonly ParameterExpression tupleParameter;
57+
private readonly ParameterExpression itemMaterializationContextParameter;
58+
private readonly Dictionary<IEntityExpression, int> entityRegistry = new Dictionary<IEntityExpression, int>();
59+
private readonly HashSet<Parameter<Tuple>> tupleParameters;
60+
4961
#region Public static methods
5062

5163
public static LambdaExpression MakeLambda(Expression expression, TranslatorContext context)
5264
{
53-
var tupleParameter = Expression.Parameter(WellKnownOrmTypes.Tuple, "tuple");
54-
var visitor = new ExpressionMaterializer(tupleParameter, context, null, EnumerableUtils<Parameter<Tuple>>.Empty);
65+
var visitor = new ExpressionMaterializer(QueryHelper.TupleParameter, context, null, EnumerableUtils<Parameter<Tuple>>.Empty);
5566
var processedExpression = OwnerRemover.RemoveOwner(expression);
56-
return FastExpression.Lambda(visitor.Visit(processedExpression), tupleParameter);
67+
return FastExpression.Lambda(visitor.Visit(processedExpression), QueryHelper.TupleParameter);
5768
}
5869

5970
public static MaterializationInfo MakeMaterialization(ItemProjectorExpression projector, TranslatorContext context,
6071
IEnumerable<Parameter<Tuple>> tupleParameters)
6172
{
62-
var tupleParameter = Expression.Parameter(WellKnownOrmTypes.Tuple, "tuple");
63-
var materializationContextParameter = Expression.Parameter(WellKnownOrmTypes.ItemMaterializationContext, "mc");
64-
var visitor = new ExpressionMaterializer(tupleParameter, context, materializationContextParameter, tupleParameters);
65-
var lambda = FastExpression.Lambda(visitor.Visit(projector.Item), tupleParameter, materializationContextParameter);
73+
var visitor = new ExpressionMaterializer(QueryHelper.TupleParameter, context, MaterializationContextParameter, tupleParameters);
74+
var lambda = FastExpression.Lambda(visitor.Visit(projector.Item), QueryHelper.TupleParameter, MaterializationContextParameter);
6675
var count = visitor.entityRegistry.Count;
6776
return new MaterializationInfo(count, lambda);
6877
}
@@ -110,16 +119,14 @@ protected override Expression VisitGroupingExpression(GroupingExpression groupin
110119
// 2. Create constructor
111120
var keyType = groupingExpression.KeyExpression.Type;
112121
var keyMaterializer = Visit(groupingExpression.KeyExpression);
122+
// Copying from template is 2x+ faster than instantiating an array with defined items
123+
var ctorParameterTypes = new Type[GroupingConstructorArgumentTypesTemplate.Length];
124+
Array.Copy(GroupingConstructorArgumentTypesTemplate, ctorParameterTypes, GroupingConstructorArgumentTypesTemplate.Length);
125+
ctorParameterTypes[4] = keyType;
126+
113127
var groupingCtor = WellKnownOrmTypes.GroupingOfTKeyTElement
114128
.MakeGenericType(keyType, elementType)
115-
.GetConstructor(new[] {
116-
WellKnownOrmTypes.ProjectionExpression,
117-
WellKnownOrmTypes.TranslatedQuery,
118-
WellKnownOrmTypes.ParameterOfTuple,
119-
WellKnownOrmTypes.Tuple,
120-
keyType,
121-
WellKnownOrmTypes.ItemMaterializationContext
122-
});
129+
.GetConstructor(ctorParameterTypes);
123130

124131
// 3. Create result expression.
125132
var resultExpression = Expression.New(
@@ -321,7 +328,7 @@ protected override Expression VisitKeyExpression(KeyExpression expression)
321328
Expression.Field(itemMaterializationContextParameter, ItemMaterializationContext.SessionFieldInfo),
322329
WellKnownMembers.SessionNodeId),
323330
Expression.Constant(expression.EntityType),
324-
Expression.Constant(TypeReferenceAccuracy.BaseType),
331+
TypeReferenceAccuracyConstantExpression,
325332
tupleExpression);
326333
}
327334

Orm/Xtensive.Orm/Orm/Linq/QueryHelper.cs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,19 @@ public OwnerWrapper(TOwner owner)
3333
}
3434
}
3535

36+
public static readonly ParameterExpression TupleParameter = Expression.Parameter(WellKnownOrmTypes.Tuple, "tuple");
37+
38+
private static readonly PropertyInfo TupleValueProperty = WellKnownOrmTypes.ParameterOfTuple
39+
.GetProperty(nameof(Parameter<Tuple>.Value), WellKnownOrmTypes.Tuple);
40+
3641
public static Expression<Func<Tuple, bool>> BuildFilterLambda(int startIndex, IReadOnlyList<Type> keyColumnTypes, Parameter<Tuple> keyParameter)
3742
{
3843
Expression filterExpression = null;
39-
var tupleParameter = Expression.Parameter(WellKnownOrmTypes.Tuple, "tuple");
40-
var valueProperty = WellKnownOrmTypes.ParameterOfTuple
41-
.GetProperty(nameof(Parameter<Tuple>.Value), WellKnownOrmTypes.Tuple);
42-
var keyValue = Expression.Property(Expression.Constant(keyParameter), valueProperty);
43-
for (var i = 0; i < keyColumnTypes.Count; i++) {
44+
var keyValue = Expression.Property(Expression.Constant(keyParameter), TupleValueProperty);
45+
for (int i = 0, count = keyColumnTypes.Count; i < count; i++) {
4446
var getValueMethod = WellKnownMembers.Tuple.GenericAccessor.MakeGenericMethod(keyColumnTypes[i]);
4547
var tupleParameterFieldAccess = Expression.Call(
46-
tupleParameter,
48+
TupleParameter,
4749
getValueMethod,
4850
Expression.Constant(startIndex + i));
4951
var keyParameterFieldAccess = Expression.Call(
@@ -56,7 +58,7 @@ public static Expression<Func<Tuple, bool>> BuildFilterLambda(int startIndex, IR
5658
filterExpression = Expression.And(filterExpression,
5759
Expression.Equal(tupleParameterFieldAccess, keyParameterFieldAccess));
5860
}
59-
return FastExpression.Lambda<Func<Tuple, bool>>(filterExpression, tupleParameter);
61+
return FastExpression.Lambda<Func<Tuple, bool>>(filterExpression, TupleParameter);
6062
}
6163

6264
private static Expression CreateEntityQuery(Type elementType)

Orm/Xtensive.Orm/Orm/Linq/Translator.Queryable.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -959,7 +959,7 @@ private ProjectionExpression VisitGroupBy(Type returnType, Expression source, La
959959
Type = keyDataSource.Header.Columns[groupIndex].Type.ToNullable()
960960
});
961961
var applyParameter = context.GetApplyParameter(groupingProjection);
962-
var tupleParameter = Expression.Parameter(WellKnownOrmTypes.Tuple, "tuple");
962+
var tupleParameter = QueryHelper.TupleParameter;
963963

964964
var filterBody = (nullableKeyColumns.Count == 0)
965965
? comparisonInfos.Aggregate(

0 commit comments

Comments
 (0)