1 /* ****************************************************************************
\r
3 * Copyright (c) Microsoft Corporation. All rights reserved.
\r
5 * This software is subject to the Microsoft Public License (Ms-PL).
\r
6 * A copy of the license can be found in the license.htm file included
\r
7 * in this distribution.
\r
9 * You must not remove this notice, or any other, from this software.
\r
11 * ***************************************************************************/
\r
13 namespace System.Web.Mvc.ExpressionUtil {
\r
15 using System.Linq.Expressions;
\r
17 internal static class CachedExpressionCompiler {
\r
19 // This is the entry point to the cached expression tree compiler. The processor will perform a series of checks
\r
20 // and optimizations in order to return a fully-compiled func as quickly as possible to the caller. If the
\r
21 // input expression is particularly obscure, the system will fall back to a slow but correct compilation step.
\r
22 public static Func<TModel, TValue> Process<TModel, TValue>(Expression<Func<TModel, TValue>> lambdaExpression) {
\r
23 return Processor<TModel, TValue>.GetFunc(lambdaExpression);
\r
26 private static class Processor<TModel, TValue> {
\r
28 private static readonly Cache _cache = new Cache();
\r
30 public static Func<TModel, TValue> GetFunc(Expression<Func<TModel, TValue>> lambdaExpression) {
\r
31 // look for common patterns that don't need to be fingerprinted
\r
32 Func<TModel, TValue> func = GetFuncFastTrack(lambdaExpression);
\r
37 // not a common pattern, so try fingerprinting (slower, but cached)
\r
38 func = GetFuncFingerprinted(lambdaExpression);
\r
43 // pattern not recognized by fingerprinting routine, so compile directly (slowest)
\r
44 return GetFuncSlow(lambdaExpression);
\r
47 private static Func<TModel, TValue> GetFuncFastTrack(Expression<Func<TModel, TValue>> lambdaExpression) {
\r
48 ParameterExpression modelParameter = lambdaExpression.Parameters[0];
\r
49 Expression body = lambdaExpression.Body;
\r
51 return FastTrack<TModel, TValue>.GetFunc(modelParameter, body);
\r
54 private static Func<TModel, TValue> GetFuncFingerprinted(Expression<Func<TModel, TValue>> lambdaExpression) {
\r
55 ParserContext context = ExpressionParser.Parse(lambdaExpression);
\r
56 if (context.Fingerprint == null) {
\r
57 // fingerprinting failed
\r
61 object[] hoistedValues = context.HoistedValues.ToArray();
\r
62 var del = _cache.GetDelegate(context);
\r
63 return model => del(model, hoistedValues);
\r
66 private static Func<TModel, TValue> GetFuncSlow(Expression<Func<TModel, TValue>> lambdaExpression) {
\r
67 Func<TModel, TValue> del = lambdaExpression.Compile();
\r
71 private sealed class Cache : ReaderWriterCache<ExpressionFingerprint, CompiledExpressionDelegate<TModel, TValue>> {
\r
72 private static CompiledExpressionDelegate<TModel, TValue> CreateDelegate(ParserContext context) {
\r
73 var bodyExpr = context.Fingerprint.ToExpression(context);
\r
74 var lambdaExpr = Expression.Lambda<CompiledExpressionDelegate<TModel, TValue>>(bodyExpr, context.ModelParameter, ParserContext.HoistedValuesParameter);
\r
75 var del = lambdaExpr.Compile();
\r
78 public CompiledExpressionDelegate<TModel, TValue> GetDelegate(ParserContext context) {
\r
79 return FetchOrCreateItem(context.Fingerprint, () => CreateDelegate(context));
\r