/// <summary> /// Recursively analyze the definition of a function. /// </summary> private static void AnalyzeDefinition(QilNode nd) { Debug.Assert(XmlILConstructInfo.Read(nd).PushToWriterLast, "Only need to analyze expressions which will be compiled in push mode."); switch (nd.NodeType) { case QilNodeType.Invoke: // Invoke node can either be compiled as IteratorThenWriter, or Writer. // Since IteratorThenWriter involves caching the results of the function call // and iterating over them, .tailcall cannot be used if (XmlILConstructInfo.Read(nd).ConstructMethod == XmlILConstructMethod.Writer) { OptimizerPatterns.Write(nd).AddPattern(OptimizerPatternName.TailCall); } break; case QilNodeType.Loop: { // Recursively analyze Loop return value QilLoop ndLoop = (QilLoop)nd; if (ndLoop.Variable.NodeType == QilNodeType.Let || !ndLoop.Variable.Binding.XmlType.MaybeMany) { AnalyzeDefinition(ndLoop.Body); } break; } case QilNodeType.Sequence: { // Recursively analyze last expression in Sequence QilList ndSeq = (QilList)nd; if (ndSeq.Count > 0) { AnalyzeDefinition(ndSeq[ndSeq.Count - 1]); } break; } case QilNodeType.Choice: { // Recursively analyze Choice branches QilChoice ndChoice = (QilChoice)nd; for (int i = 0; i < ndChoice.Branches.Count; i++) { AnalyzeDefinition(ndChoice.Branches[i]); } break; } case QilNodeType.Conditional: { // Recursively analyze Conditional branches QilTernary ndCond = (QilTernary)nd; AnalyzeDefinition(ndCond.Center); AnalyzeDefinition(ndCond.Right); break; } case QilNodeType.Nop: AnalyzeDefinition(((QilUnary)nd).Child); break; } }
/// <summary> /// Get OptimizerPatterns annotation for the specified node. Lazily create if necessary. /// </summary> public static OptimizerPatterns Read(QilNode nd) { XmlILAnnotation ann = nd.Annotation as XmlILAnnotation; OptimizerPatterns optPatt = (ann != null) ? ann.Patterns : null; if (optPatt == null) { if (!nd.XmlType.MaybeMany) { // Expressions with ZeroOrOne cardinality should always report IsDocOrderDistinct and NoContainedNodes if (s_zeroOrOneDefault == null) { optPatt = new OptimizerPatterns(); optPatt.AddPattern(OptimizerPatternName.IsDocOrderDistinct); optPatt.AddPattern(OptimizerPatternName.SameDepth); optPatt._isReadOnly = true; s_zeroOrOneDefault = optPatt; } else { optPatt = s_zeroOrOneDefault; } } else if (nd.XmlType.IsDod) { if (s_dodDefault == null) { optPatt = new OptimizerPatterns(); optPatt.AddPattern(OptimizerPatternName.IsDocOrderDistinct); optPatt._isReadOnly = true; s_dodDefault = optPatt; } else { optPatt = s_dodDefault; } } else { if (s_maybeManyDefault == null) { optPatt = new OptimizerPatterns(); optPatt._isReadOnly = true; s_maybeManyDefault = optPatt; } else { optPatt = s_maybeManyDefault; } } } return(optPatt); }
/// <summary> /// Get OptimizerPatterns annotation for the specified node. Lazily create if necessary. /// </summary> public static OptimizerPatterns Read(QilNode nd) { XmlILAnnotation ann = nd.Annotation as XmlILAnnotation; OptimizerPatterns optPatt = (ann != null) ? ann.Patterns : null; if (optPatt == null) { if (!nd.XmlType.MaybeMany) { // Expressions with ZeroOrOne cardinality should always report IsDocOrderDistinct and NoContainedNodes if (s_zeroOrOneDefault == null) { optPatt = new OptimizerPatterns(); optPatt.AddPattern(OptimizerPatternName.IsDocOrderDistinct); optPatt.AddPattern(OptimizerPatternName.SameDepth); optPatt._isReadOnly = true; s_zeroOrOneDefault = optPatt; } else { optPatt = s_zeroOrOneDefault; } } else if (nd.XmlType.IsDod) { if (s_dodDefault == null) { optPatt = new OptimizerPatterns(); optPatt.AddPattern(OptimizerPatternName.IsDocOrderDistinct); optPatt._isReadOnly = true; s_dodDefault = optPatt; } else { optPatt = s_dodDefault; } } else { if (s_maybeManyDefault == null) { optPatt = new OptimizerPatterns(); optPatt._isReadOnly = true; s_maybeManyDefault = optPatt; } else { optPatt = s_maybeManyDefault; } } } return optPatt; }
/// <summary> /// Create and initialize OptimizerPatterns annotation for the specified node. /// </summary> public static void Inherit(QilNode ndSrc, QilNode ndDst, OptimizerPatternName pattern) { OptimizerPatterns annSrc = OptimizerPatterns.Read(ndSrc); if (annSrc.MatchesPattern(pattern)) { OptimizerPatterns annDst = OptimizerPatterns.Write(ndDst); annDst.AddPattern(pattern); // Inherit pattern arguments switch (pattern) { case OptimizerPatternName.Step: annDst.AddArgument(OptimizerPatternArgument.StepNode, annSrc.GetArgument(OptimizerPatternArgument.StepNode)); annDst.AddArgument(OptimizerPatternArgument.StepInput, annSrc.GetArgument(OptimizerPatternArgument.StepInput)); break; case OptimizerPatternName.FilterElements: annDst.AddArgument(OptimizerPatternArgument.ElementQName, annSrc.GetArgument(OptimizerPatternArgument.ElementQName)); break; case OptimizerPatternName.FilterContentKind: annDst.AddArgument(OptimizerPatternArgument.KindTestType, annSrc.GetArgument(OptimizerPatternArgument.KindTestType)); break; case OptimizerPatternName.EqualityIndex: annDst.AddArgument(OptimizerPatternArgument.IndexedNodes, annSrc.GetArgument(OptimizerPatternArgument.IndexedNodes)); annDst.AddArgument(OptimizerPatternArgument.KeyExpression, annSrc.GetArgument(OptimizerPatternArgument.KeyExpression)); break; case OptimizerPatternName.DodReverse: case OptimizerPatternName.JoinAndDod: annDst.AddArgument(OptimizerPatternArgument.DodStep, annSrc.GetArgument(OptimizerPatternArgument.DodStep)); break; case OptimizerPatternName.MaxPosition: annDst.AddArgument(OptimizerPatternArgument.MaxPosition, annSrc.GetArgument(OptimizerPatternArgument.MaxPosition)); break; case OptimizerPatternName.SingleTextRtf: annDst.AddArgument(OptimizerPatternArgument.RtfText, annSrc.GetArgument(OptimizerPatternArgument.RtfText)); break; } } }
/// <summary> /// Create and initialize OptimizerPatterns annotation for the specified node. /// </summary> public static OptimizerPatterns Write(QilNode nd) { XmlILAnnotation ann = XmlILAnnotation.Write(nd); OptimizerPatterns optPatt = ann.Patterns; if (optPatt == null || optPatt._isReadOnly) { optPatt = new OptimizerPatterns(); ann.Patterns = optPatt; if (!nd.XmlType.MaybeMany) { optPatt.AddPattern(OptimizerPatternName.IsDocOrderDistinct); optPatt.AddPattern(OptimizerPatternName.SameDepth); } else if (nd.XmlType.IsDod) { optPatt.AddPattern(OptimizerPatternName.IsDocOrderDistinct); } } return(optPatt); }
/// <summary> /// Create and initialize OptimizerPatterns annotation for the specified node. /// </summary> public static OptimizerPatterns Write(QilNode nd) { XmlILAnnotation ann = XmlILAnnotation.Write(nd); OptimizerPatterns optPatt = ann.Patterns; if (optPatt == null || optPatt.isReadOnly) { optPatt = new OptimizerPatterns(); ann.Patterns = optPatt; if (!nd.XmlType.MaybeMany) { optPatt.AddPattern(OptimizerPatternName.IsDocOrderDistinct); optPatt.AddPattern(OptimizerPatternName.SameDepth); } else if (nd.XmlType.IsDod) { optPatt.AddPattern(OptimizerPatternName.IsDocOrderDistinct); } } return optPatt; }
/// <summary> /// Return true if "patt" matches the Step pattern and the StepType argument is equal to "stepType". /// </summary> private bool IsStepPattern(OptimizerPatterns patt, QilNodeType stepType) { return patt.MatchesPattern(OptimizerPatternName.Step) && ((QilNode) patt.GetArgument(OptimizerPatternArgument.StepNode)).NodeType == stepType; }
/// <summary> /// Bind values produced by the "ndFor" expression to a non-stack location that can later /// be referenced. /// </summary> private void StartForBinding(QilIterator ndFor, OptimizerPatterns patt) { LocalBuilder locPos = null; Debug.Assert(ndFor.XmlType.IsSingleton); // For expression iterator will be unnested as part of parent iterator if (_iterCurr.HasLabelNext) StartNestedIterator(ndFor.Binding, _iterCurr.GetLabelNext()); else StartNestedIterator(ndFor.Binding); if (patt.MatchesPattern(OptimizerPatternName.IsPositional)) { // Need to track loop index so initialize it to 0 before starting loop locPos = _helper.DeclareLocal("$$$pos", typeof(int)); _helper.Emit(OpCodes.Ldc_I4_0); _helper.Emit(OpCodes.Stloc, locPos); } // Allow base internal class to dispatch based on QilExpression node type Visit(ndFor.Binding); // DebugInfo: Open variable scope // DebugInfo: Ensure that for variable is stored in a local and tag it with the user-defined name if (_qil.IsDebug && ndFor.DebugName != null) { _helper.DebugStartScope(); // Ensure that values are stored in a local variable with a user-defined name _iterCurr.EnsureLocalNoCache("$$$for"); } else { // Ensure that values are not stored on the stack _iterCurr.EnsureNoStackNoCache("$$$for"); } if (patt.MatchesPattern(OptimizerPatternName.IsPositional)) { // Increment position _helper.Emit(OpCodes.Ldloc, locPos); _helper.Emit(OpCodes.Ldc_I4_1); _helper.Emit(OpCodes.Add); _helper.Emit(OpCodes.Stloc, locPos); if (patt.MatchesPattern(OptimizerPatternName.MaxPosition)) { // Short-circuit rest of loop if max position has already been reached _helper.Emit(OpCodes.Ldloc, locPos); _helper.LoadInteger((int)patt.GetArgument(OptimizerPatternArgument.MaxPosition)); _helper.Emit(OpCodes.Bgt, _iterCurr.ParentIterator.GetLabelNext()); } _iterCurr.LocalPosition = locPos; } EndNestedIterator(ndFor.Binding); _iterCurr.SetIterator(_iterNested); }