/// <summary> /// Performs funcletization on the given expression. Also returns a delegates that can be used /// to determine if the entire tree needs to be recompiled. /// </summary> internal Expression Funcletize(Expression expression, out Func <bool> recompileRequired) { DebugCheck.NotNull(expression); // Find all candidates for funcletization. Some sub-expressions are reduced to constants, // others are reduced to variables. The rules vary based on the _mode. Func <Expression, bool> isClientConstant; Func <Expression, bool> isClientVariable; expression = ReplaceRootContextParameter(expression); if (_mode == Mode.CompiledQueryEvaluation) { // We lock down closure expressions for compiled queries, so everything is either // a constant or a query parameter produced from the explicit parameters to the // compiled query delegate. isClientConstant = Nominate(expression, IsClosureExpression); isClientVariable = Nominate(expression, IsCompiledQueryParameterVariable); } else if (_mode == Mode.CompiledQueryLockdown) { // When locking down a compiled query, we can evaluate all closure expressions. isClientConstant = Nominate(expression, IsClosureExpression); isClientVariable = (exp) => false; } else { Debug.Assert(_mode == Mode.ConventionalQuery, "No other options..."); // There are no variable parameters outside of compiled queries, so everything is // either a constant or a closure expression. isClientConstant = Nominate(expression, IsImmutable); isClientVariable = Nominate(expression, IsClosureExpression); } // Now rewrite given nomination functions var visitor = new FuncletizingVisitor(this, isClientConstant, isClientVariable); var result = visitor.Visit(expression); recompileRequired = visitor.GetRecompileRequiredFunction(); return(result); }
/// <summary> /// Performs funcletization on the given expression. Also returns a delegates that can be used /// to determine if the entire tree needs to be recompiled. /// </summary> internal Expression Funcletize(Expression expression, out Func<bool> recompileRequired) { EntityUtil.CheckArgumentNull(expression, "expression"); // Find all candidates for funcletization. Some sub-expressions are reduced to constants, // others are reduced to variables. The rules vary based on the _mode. Func<Expression, bool> isClientConstant; Func<Expression, bool> isClientVariable; expression = ReplaceRootContextParameter(expression); if (_mode == Mode.CompiledQueryEvaluation) { // We lock down closure expressions for compiled queries, so everything is either // a constant or a query parameter produced from the explicit parameters to the // compiled query delegate. isClientConstant = Nominate(expression, this.IsClosureExpression); isClientVariable = Nominate(expression, this.IsCompiledQueryParameterVariable); } else if (_mode == Mode.CompiledQueryLockdown) { // When locking down a compiled query, we can evaluate all closure expressions. isClientConstant = Nominate(expression, this.IsClosureExpression); isClientVariable = (exp) => false; } else { Debug.Assert(_mode == Mode.ConventionalQuery, "No other options..."); // There are no variable parameters outside of compiled queries, so everything is // either a constant or a closure expression. isClientConstant = Nominate(expression, this.IsImmutable); isClientVariable = Nominate(expression, this.IsClosureExpression); } // Now rewrite given nomination functions FuncletizingVisitor visitor = new FuncletizingVisitor(this, isClientConstant, isClientVariable); Expression result = visitor.Visit(expression); recompileRequired = visitor.GetRecompileRequiredFunction(); return result; }