The Labs \ Source Viewer \ SSCLI \ System.Xml.Xsl.IlGen \ TailCallAnalyzer

  1. //------------------------------------------------------------------------------
  2. // <copyright file="TailCallAnalyzer.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. //------------------------------------------------------------------------------
  15. using System;
  16. using System.Diagnostics;
  17. using System.Xml.Xsl.Qil;
  18. namespace System.Xml.Xsl.IlGen
  19. {
  20.    
  21.     /// <summary>
  22.     /// This analyzer walks each function in the graph and annotates Invoke nodes which can
  23.     /// be compiled using the IL .tailcall instruction. This instruction will discard the
  24.     /// current stack frame before calling the new function.
  25.     /// </summary>
  26.     static internal class TailCallAnalyzer
  27.     {
  28.        
  29.         /// <summary>
  30.         /// Perform tail-call analysis on the functions in the specified QilExpression.
  31.         /// </summary>
  32.         public static void Analyze(QilExpression qil)
  33.         {
  34.             foreach (QilFunction ndFunc in qil.FunctionList) {
  35.                 // Only analyze functions which are pushed to the writer, since otherwise code
  36.                 // is generated after the call instruction in order to process cached results
  37.                 if (XmlILConstructInfo.Read(ndFunc).ConstructMethod == XmlILConstructMethod.Writer)
  38.                     AnalyzeDefinition(ndFunc.Definition);
  39.             }
  40.         }
  41.        
  42.         /// <summary>
  43.         /// Recursively analyze the definition of a function.
  44.         /// </summary>
  45.         private static void AnalyzeDefinition(QilNode nd)
  46.         {
  47.             Debug.Assert(XmlILConstructInfo.Read(nd).PushToWriterLast, "Only need to analyze expressions which will be compiled in push mode.");
  48.            
  49.             switch (nd.NodeType) {
  50.                 case QilNodeType.Invoke:
  51.                     // Invoke node can either be compiled as IteratorThenWriter, or Writer.
  52.                     // Since IteratorThenWriter involves caching the results of the function call
  53.                     // and iterating over them, .tailcall cannot be used
  54.                     if (XmlILConstructInfo.Read(nd).ConstructMethod == XmlILConstructMethod.Writer)
  55.                         OptimizerPatterns.Write(nd).AddPattern(OptimizerPatternName.TailCall);
  56.                     break;
  57.                 case QilNodeType.Loop:
  58.                    
  59.                    
  60.                     {
  61.                         // Recursively analyze Loop return value
  62.                         QilLoop ndLoop = (QilLoop)nd;
  63.                         if (ndLoop.Variable.NodeType == QilNodeType.Let || !ndLoop.Variable.Binding.XmlType.MaybeMany)
  64.                             AnalyzeDefinition(ndLoop.Body);
  65.                         break;
  66.                     }
  67.                     break;
  68.                 case QilNodeType.Sequence:
  69.                    
  70.                    
  71.                     {
  72.                         // Recursively analyze last expression in Sequence
  73.                         QilList ndSeq = (QilList)nd;
  74.                         if (ndSeq.Count > 0)
  75.                             AnalyzeDefinition(ndSeq[ndSeq.Count - 1]);
  76.                         break;
  77.                     }
  78.                     break;
  79.                 case QilNodeType.Choice:
  80.                    
  81.                    
  82.                     {
  83.                         // Recursively analyze Choice branches
  84.                         QilChoice ndChoice = (QilChoice)nd;
  85.                         for (int i = 0; i < ndChoice.Branches.Count; i++)
  86.                             AnalyzeDefinition(ndChoice.Branches[i]);
  87.                         break;
  88.                     }
  89.                     break;
  90.                 case QilNodeType.Conditional:
  91.                    
  92.                    
  93.                     {
  94.                         // Recursively analyze Conditional branches
  95.                         QilTernary ndCond = (QilTernary)nd;
  96.                         AnalyzeDefinition(ndCond.Center);
  97.                         AnalyzeDefinition(ndCond.Right);
  98.                         break;
  99.                     }
  100.                     break;
  101.                 case QilNodeType.Nop:
  102.                    
  103.                     AnalyzeDefinition(((QilUnary)nd).Child);
  104.                     break;
  105.             }
  106.         }
  107.     }
  108. }

Developer Fusion