private static Delegate CompileImpl(LambdaExpression expression, ICompiledDelegateCache cache, bool outliningEnabled, IConstantHoister hoister)
        {
            //
            // E.g. xs => xs.Bar(x => x > 0).Foo(x => x * 2)
            //
            var expr = expression;

            if (outliningEnabled)
            {
                //
                // E.g. xs => xs.Bar(delegate1).Foo(delegate2)  where delegate1 and delegate2 are constants
                //
                expr = Outline(expression, cache, hoister);
            }

            var template = ExpressionTemplatizer.Templatize(expr, hoister ?? SimpleHoister.Instance);

            //
            // E.g.  outline |                                  template expressions
            //      ---------+------------------------------------------------------------------------------------------
            //          Y    | (a, b) => xs => xs.Bar(a).Foo(b)  and recursively  c => x => x > c  and  d => x => x * d
            //          N    | (c, d) => xs => xs.Bar(x => x > c).Foo(x => x * d)
            //
            var lambda   = template.Template;
            var argument = template.Argument;

            Delegate res;

            if (lambda.Parameters.Count == 0)
            {
                //
                // No template parameters, hence no tuple packing required.
                //
                res = cache.GetOrAdd(expr);
            }
            else
            {
                //
                // E.g. without outlining:  t => xs => xs.Bar(x => x > t.Item1).Foo(x => x * t.Item2)
                //
                var cachedDelegate = cache.GetOrAdd(lambda);

                //
                // E.g. new Tuple<int, int>(0, 2)
                //
                var tupleArgument = TupleEvaluator.Instance.Visit(argument);

                res = (Delegate)cachedDelegate.DynamicInvoke(new object[] { tupleArgument });
            }

            return(res);
        }
Exemple #2
0
        /// <summary>
        /// Evaluates the specified expression tree.
        /// If the specified expression has unbound parameters, an exception will be thrown.
        /// </summary>
        /// <typeparam name="TResult">Type of the evaluation result.</typeparam>
        /// <param name="expression">Expression to evaluate.</param>
        /// <param name="cache">Compiled delegate cache.</param>
        /// <returns>Result of evaluating the expression tree.</returns>
        public static TResult Evaluate <TResult>(this Expression expression, ICompiledDelegateCache cache)
        {
            if (expression == null)
            {
                throw new ArgumentNullException(nameof(expression));
            }
            if (cache == null)
            {
                throw new ArgumentNullException(nameof(cache));
            }

            return(EvalImpl <TResult>(expression, cache));
        }
        /// <summary>
        /// Compiles the specified lambda expression by hoisting constants from the expression and consulting
        /// the cache for the resulting templatized lambda expression. This technique increases the likelihood
        /// for a cache hit.
        /// </summary>
        /// <param name="expression">Lambda expression to compile.</param>
        /// <param name="cache">Cache to hold the compiled delegate.</param>
        /// <param name="outliningEnabled">Specifies whether nested lambda expressions should be outlined into delegate constants by recursive compilation using the cache.</param>
        /// <returns>Compiled delegate for the specified lambda expression.</returns>
        public static Delegate Compile(this LambdaExpression expression, ICompiledDelegateCache cache, bool outliningEnabled)
        {
            if (expression == null)
            {
                throw new ArgumentNullException(nameof(expression));
            }
            if (cache == null)
            {
                throw new ArgumentNullException(nameof(cache));
            }

            return(CompileImpl(expression, cache, outliningEnabled, hoister: null));
        }
        /// <summary>
        /// Compiles the specified lambda expression by hoisting constants from the expression and consulting
        /// the cache for the resulting templatized lambda expression. This technique increases the likelihood
        /// for a cache hit.
        /// </summary>
        /// <typeparam name="T">Delegate type of the lambda expression.</typeparam>
        /// <param name="expression">Lambda expression to compile.</param>
        /// <param name="cache">Cache to hold the compiled delegate.</param>
        /// <param name="outliningEnabled">Specifies whether nested lambda expressions should be outlined into delegate constants by recursive compilation using the cache.</param>
        /// <returns>Compiled delegate for the specified lambda expression.</returns>
        public static T Compile <T>(this Expression <T> expression, ICompiledDelegateCache cache, bool outliningEnabled)
        {
            if (expression == null)
            {
                throw new ArgumentNullException(nameof(expression));
            }
            if (cache == null)
            {
                throw new ArgumentNullException(nameof(cache));
            }

            return((T)(object)CompileImpl(expression, cache, outliningEnabled, hoister: null));
        }
        /// <summary>
        /// Outlines nested lambda expressions for consideration in the constant hoisting step. Only non-quoted
        /// lambda expressions without a closure will be considered for hoisting and subsequent caching.
        /// </summary>
        /// <param name="lambda">Lambda expression to perform outlining of inner lambda expressions on.</param>
        /// <param name="cache">Cache to hold any recursively compiled delegates.</param>
        /// <param name="hoister">Constant hoister used to selectively hoist constants in the specified expression.</param>
        /// <returns>Original lambda expression with outlined inner lambda expressions substituted for constant delegate expressions.</returns>
        /// <remarks>Future extensions can provide for a means to control the outlining policy, e.g. to insert a thunk to defer recursive compilation.</remarks>
        private static LambdaExpression Outline(LambdaExpression lambda, ICompiledDelegateCache cache, IConstantHoister hoister)
        {
            var oldBody = lambda.Body;

            var newBody = ExpressionOutliner.Outline(oldBody, cache, hoister);

            if (ReferenceEquals(oldBody, newBody))
            {
                return(lambda);
            }

            var result = Expression.Lambda(lambda.Type, newBody, lambda.Name, lambda.TailCall, lambda.Parameters);

            return(result);
        }
Exemple #6
0
        public void CachedLambdaCompiler_AllSortsOfCaches()
        {
            var cs = new ICompiledDelegateCache[]
            {
                VoidCompiledDelegateCache.Instance,
                new SimpleCompiledDelegateCache(),
                new LeastRecentlyUsedCompiledDelegateCache(4)
            };

            var es = new LambdaExpression[]
            {
#pragma warning disable IDE0004 // Remove Unnecessary Cast. (Only unnecessary on C# 10 or later.)
                (Expression <Func <int> >)(() => 42),
                (Expression <Func <int, int> >)(x => x),
                (Expression <Func <int, int> >)(x => x * 2),
                (Expression <Func <int, int> >)(y => y),
                (Expression <Func <int, int, int> >)((a, b) => a * 2 + b * 3),
                (Expression <Func <int> >)(() => 43),
                (Expression <Func <int, int> >)(x => x * 17),
                (Expression <Func <int, int, int> >)((a, b) => a * 7 + b * 4),
                (Expression <Func <int, int, int> >)((a, b) => a * 8 + b * 5),
                (Expression <Func <int, int> >)(x => 3 * x),
                (Expression <Func <int> >)(() => 44),
                (Expression <Func <int, int> >)(x => 1 + x),
                (Expression <Func <int, int> >)(x => 2 + x),
#pragma warning restore IDE0004
            };

            var nums = new[] { 7, 12, 64, 49, 18 };

            foreach (var e in es)
            {
                var d0 = e.Compile();

                var args = nums.Take(e.Parameters.Count).Cast <object>().ToArray();

                var r = d0.DynamicInvoke(args);

                foreach (var c in cs)
                {
                    var d = e.Compile(c);

                    var s = d.DynamicInvoke(args);

                    Assert.AreEqual(s, r);
                }
            }
        }
Exemple #7
0
        private static TResult EvalImpl <TResult>(Expression expression, ICompiledDelegateCache cache)
        {
            // Adding the case for ExpressionType.Default turns out to be a bit tricky
            // when dealing with value types that don't have a default constructor (e.g.
            // the decimal type). See EmitDefault in ILGen.

            switch (expression.NodeType)
            {
            case ExpressionType.Constant:
                if (typeof(TResult).IsAssignableFrom(expression.Type))
                {
                    return((TResult)((ConstantExpression)expression).Value);
                }
                break;
            }

            var funcletized = FuncletizeImpl <TResult>(expression);

            return(cache != null?funcletized.Compile(cache)() : funcletized.Compile()());
        }
 public CheckpointingQueryEngine(Uri uri, IReactiveServiceResolver serviceResolver, IScheduler scheduler, IReactiveMetadata metadataRegistry, IKeyValueStore keyValueStore, IQuotedTypeConversionTargets quotedTypeConversionTargets, TraceSource traceSource, ICompiledDelegateCache delegateCache)
     : base(uri, serviceResolver, scheduler, metadataRegistry, keyValueStore, SerializationPolicy.Default, quotedTypeConversionTargets, traceSource, delegateCache)
 {
     _objectSpace = new PersistedObjectSpace(new SerializationFactory());
 }
Exemple #9
0
        private static TResult EvalImpl <TResult>(Expression <Func <TResult> > expression, ICompiledDelegateCache cache)
        {
            var funcletized = FuncletizeImpl <TResult>(expression);

            return(cache != null?funcletized.Compile(cache)() : funcletized.Compile()());
        }
 public Visitor(ICompiledDelegateCache cache, IConstantHoister hoister)
 {
     _cache   = cache;
     _hoister = hoister;
 }
 /// <summary>
 /// Outlines nested lambda expressions in the specified expression. If the expression is a
 /// lambda expression itself, it will be considered for rewriting as well. Care should be
 /// taken when calling this method as not to trigger a stack overflow.
 /// </summary>
 /// <param name="expression">Expression to apply nested lambda expression outlining on.</param>
 /// <param name="cache">Cache to hold any recursively compiled delegates.</param>
 /// <param name="hoister">Constant hoister used to selectively hoist constants in the specified expression.</param>
 /// <returns>Original expression with outlining steps applied.</returns>
 public static Expression Outline(Expression expression, ICompiledDelegateCache cache, IConstantHoister hoister) => new Visitor(cache, hoister).Visit(expression);