content: /*
   *  This file is part of AndroidIDE.
   *
   *  AndroidIDE is free software: you can redistribute it and/or modify
   *  it under the terms of the GNU General Public License as published by
   *  the Free Software Foundation, either version 3 of the License, or
   *  (at your option) any later version.
   *
   *  AndroidIDE is distributed in the hope that it will be useful,
   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *  GNU General Public License for more details.
   *
   *  You should have received a copy of the GNU General Public License
   *   along with AndroidIDE.  If not, see <https://www.gnu.org/licenses/>.
   */
  
  /*
   * reserved comment block
   * DO NOT REMOVE OR ALTER!
   */
  /*
   * Copyright 2001-2004 The Apache Software Foundation.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  /*
   * $Id: Mode.java,v 1.2.4.1 2005/09/19 05:18:11 pvedula Exp $
   */
  
  package jaxp.sun.org.apache.xalan.internal.xsltc.compiler;
  
  import java.util.Enumeration;
  import java.util.Hashtable;
  import java.util.Iterator;
  import java.util.Vector;
  
  import jaxp.sun.org.apache.bcel.internal.generic.ALOAD;
  import jaxp.sun.org.apache.bcel.internal.generic.Instruction;
  import jaxp.sun.org.apache.bcel.internal.generic.BranchHandle;
  import jaxp.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
  import jaxp.sun.org.apache.bcel.internal.generic.DUP;
  import jaxp.sun.org.apache.bcel.internal.generic.GOTO_W;
  import jaxp.sun.org.apache.bcel.internal.generic.IFLT;
  import jaxp.sun.org.apache.bcel.internal.generic.ILOAD;
  import jaxp.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
  import jaxp.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
  import jaxp.sun.org.apache.bcel.internal.generic.ISTORE;
  import jaxp.sun.org.apache.bcel.internal.generic.InstructionHandle;
  import jaxp.sun.org.apache.bcel.internal.generic.InstructionList;
  import jaxp.sun.org.apache.bcel.internal.generic.LocalVariableGen;
  import jaxp.sun.org.apache.bcel.internal.generic.SWITCH;
  import jaxp.sun.org.apache.bcel.internal.generic.TargetLostException;
  import jaxp.sun.org.apache.bcel.internal.util.InstructionFinder;
  import jaxp.sun.org.apache.xalan.internal.xsltc.DOM;
  import jaxp.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
  import jaxp.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
  import jaxp.sun.org.apache.xalan.internal.xsltc.compiler.util.NamedMethodGenerator;
  import jaxp.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;
  
  import jaxp.sun.org.apache.bcel.internal.generic.Type;
  import jaxp.sun.org.apache.xml.internal.dtm.Axis;
  import jaxp.sun.org.apache.xml.internal.dtm.DTM;
  
  /**
   * Mode gathers all the templates belonging to a given mode;
   * it is responsible for generating an appropriate
   * applyTemplates + (mode name) method in the translet.
   * @author Jacek Ambroziak
   * @author Santiago Pericas-Geertsen
   * @author Morten Jorgensen
   * @author Erwin Bolwidt <ejb@klomp.org>
   * @author G. Todd Miller
   */
  final class Mode implements Constants {
  
      /**
       * The name of this mode as defined in the stylesheet.
       */
      private final QName _name;
  
      /**
       * A reference to the stylesheet object that owns this mode.
       */
      private final Stylesheet _stylesheet;
  
      /**
       * The name of the method in which this mode is compiled.
       */
      private final String _methodName;
  
      /**
       * A vector of all the templates in this mode.
       */
      private Vector _templates;
  
      /**
       * Group for patterns with node()-type kernel and child axis.
       */
      private Vector _childNodeGroup = null;
  
      /**
       * Test sequence for patterns with node()-type kernel and child axis.
       */
      private TestSeq _childNodeTestSeq = null;
  
      /**
       * Group for patterns with node()-type kernel and attribute axis.
       */
      private Vector _attribNodeGroup = null;
  
      /**
       * Test sequence for patterns with node()-type kernel and attribute axis.
       */
      private TestSeq _attribNodeTestSeq = null;
  
      /**
       * Group for patterns with id() or key()-type kernel.
       */
      private Vector _idxGroup = null;
  
      /**
       * Test sequence for patterns with id() or key()-type kernel.
       */
      private TestSeq _idxTestSeq = null;
  
      /**
       * Group for patterns with any other kernel type.
       */
      private Vector[] _patternGroups;
  
      /**
       * Test sequence for patterns with any other kernel type.
       */
      private TestSeq[] _testSeq;
  
  
      /**
       * A mapping between templates and test sequences.
       */
      private Hashtable _neededTemplates = new Hashtable();
  
      /**
       * A mapping between named templates and Mode objects.
       */
      private Hashtable _namedTemplates = new Hashtable();
  
      /**
       * A mapping between templates and instruction handles.
       */
      private Hashtable _templateIHs = new Hashtable();
  
      /**
       * A mapping between templates and instruction lists.
       */
      private Hashtable _templateILs = new Hashtable();
  
      /**
       * A reference to the pattern matching the root node.
       */
      private LocationPathPattern _rootPattern = null;
  
      /**
       * Stores ranges of template precendences for the compilation
       * of apply-imports (a Hashtable for historical reasons).
       */
      private Hashtable _importLevels = null;
  
      /**
       * A mapping between key names and keys.
       */
      private Hashtable _keys = null;
  
      /**
       * Variable index for the current node used in code generation.
       */
      private int _currentIndex;
  
      /**
       * Creates a new Mode.
       *
       * @param name A textual representation of the mode's QName
       * @param stylesheet The Stylesheet in which the mode occured
       * @param suffix A suffix to append to the method name for this mode
       *               (normally a sequence number - still in a String).
       */
      public Mode(QName name, Stylesheet stylesheet, String suffix) {
          _name = name;
          _stylesheet = stylesheet;
          _methodName = APPLY_TEMPLATES + suffix;
          _templates = new Vector();
          _patternGroups = new Vector[32];
      }
  
      /**
       * Returns the name of the method (_not_ function) that will be
       * compiled for this mode. Normally takes the form 'applyTemplates()'
       * or * 'applyTemplates2()'.
       *
       * @return Method name for this mode
       */
      public String functionName() {
          return _methodName;
      }
  
      public String functionName(int min, int max) {
          if (_importLevels == null) {
              _importLevels = new Hashtable();
          }
          _importLevels.put(new Integer(max), new Integer(min));
          return _methodName + '_' + max;
      }
  
      /**
       * Shortcut to get the class compiled for this mode (will be inlined).
       */
      private String getClassName() {
          return _stylesheet.getClassName();
      }
  
      public Stylesheet getStylesheet() {
          return _stylesheet;
      }
  
      public void addTemplate(Template template) {
          _templates.addElement(template);
      }
  
      private Vector quicksort(Vector templates, int p, int r) {
          if (p < r) {
              final int q = partition(templates, p, r);
              quicksort(templates, p, q);
              quicksort(templates, q + 1, r);
          }
          return templates;
      }
  
      private int partition(Vector templates, int p, int r) {
          final Template x = (Template)templates.elementAt(p);
          int i = p - 1;
          int j = r + 1;
          while (true) {
              while (x.compareTo((Template)templates.elementAt(--j)) > 0);
              while (x.compareTo((Template)templates.elementAt(++i)) < 0);
              if (i < j) {
                  templates.set(j, templates.set(i, templates.elementAt(j)));
              }
              else {
                  return j;
              }
          }
      }
  
      /**
       * Process all the test patterns in this mode
       */
      public void processPatterns(Hashtable keys) {
          _keys = keys;
  
  /*
  System.out.println("Before Sort " + _name);
  for (int i = 0; i < _templates.size(); i++) {
      System.out.println("name = " + ((Template)_templates.elementAt(i)).getName());
      System.out.println("pattern = " + ((Template)_templates.elementAt(i)).getPattern());
      System.out.println("priority = " + ((Template)_templates.elementAt(i)).getPriority());
      System.out.println("position = " + ((Template)_templates.elementAt(i)).getPosition());
  }
  */
  
          _templates = quicksort(_templates, 0, _templates.size() - 1);
  
  /*
  System.out.println("\n After Sort " + _name);
  for (int i = 0; i < _templates.size(); i++) {
      System.out.println("name = " + ((Template)_templates.elementAt(i)).getName());
      System.out.println("pattern = " + ((Template)_templates.elementAt(i)).getPattern());
      System.out.println("priority = " + ((Template)_templates.elementAt(i)).getPriority());
      System.out.println("position = " + ((Template)_templates.elementAt(i)).getPosition());
  }
  */
  
          // Traverse all templates
          final Enumeration templates = _templates.elements();
          while (templates.hasMoreElements()) {
              // Get the next template
              final Template template = (Template)templates.nextElement();
  
              /*
               * Add this template to a table of named templates if it has a name.
               * If there are multiple templates with the same name, all but one
               * (the one with highest priority) will be disabled.
               */
              if (template.isNamed() && !template.disabled()) {
                  _namedTemplates.put(template, this);
              }
  
              // Add this template to a test sequence if it has a pattern
              final Pattern pattern = template.getPattern();
              if (pattern != null) {
                  flattenAlternative(pattern, template, keys);
              }
          }
          prepareTestSequences();
      }
  
      /**
       * This method will break up alternative patterns (ie. unions of patterns,
       * such as match="A/B | C/B") and add the basic patterns to their
       * respective pattern groups.
       */
      private void flattenAlternative(Pattern pattern,
                                      Template template,
                                      Hashtable keys) {
          // Patterns on type id() and key() are special since they do not have
          // any kernel node type (it can be anything as long as the node is in
          // the id's or key's index).
          if (pattern instanceof IdKeyPattern) {
              final IdKeyPattern idkey = (IdKeyPattern)pattern;
              idkey.setTemplate(template);
              if (_idxGroup == null) _idxGroup = new Vector();
              _idxGroup.add(pattern);
          }
          // Alternative patterns are broken up and re-processed recursively
          else if (pattern instanceof AlternativePattern) {
              final AlternativePattern alt = (AlternativePattern)pattern;
              flattenAlternative(alt.getLeft(), template, keys);
              flattenAlternative(alt.getRight(), template, keys);
          }
          // Finally we have a pattern that can be added to a test sequence!
          else if (pattern instanceof LocationPathPattern) {
              final LocationPathPattern lpp = (LocationPathPattern)pattern;
              lpp.setTemplate(template);
              addPatternToGroup(lpp);
          }
      }
  
      /**
       * Group patterns by NodeTests of their last Step
       * Keep them sorted by priority within group
       */
      private void addPatternToGroup(final LocationPathPattern lpp) {
          // id() and key()-type patterns do not have a kernel type
          if (lpp instanceof IdKeyPattern) {
              addPattern(-1, lpp);
          }
          // Otherwise get the kernel pattern from the LPP
          else {
              // kernel pattern is the last (maybe only) Step
              final StepPattern kernel = lpp.getKernelPattern();
              if (kernel != null) {
                  addPattern(kernel.getNodeType(), lpp);
              }
              else if (_rootPattern == null ||
                       lpp.noSmallerThan(_rootPattern)) {
                  _rootPattern = lpp;
              }
          }
      }
  
      /**
       * Adds a pattern to a pattern group
       */
      private void addPattern(int kernelType, LocationPathPattern pattern) {
          // Make sure the array of pattern groups is long enough
          final int oldLength = _patternGroups.length;
          if (kernelType >= oldLength) {
              Vector[] newGroups = new Vector[kernelType * 2];
              System.arraycopy(_patternGroups, 0, newGroups, 0, oldLength);
              _patternGroups = newGroups;
          }
  
          // Find the vector to put this pattern into
          Vector patterns;
  
          if (kernelType == DOM.NO_TYPE) {
              if (pattern.getAxis() == Axis.ATTRIBUTE) {
                  patterns = (_attribNodeGroup == null) ?
                      (_attribNodeGroup = new Vector(2)) : _attribNodeGroup;
              }
              else {
                  patterns = (_childNodeGroup == null) ?
                      (_childNodeGroup = new Vector(2)) : _childNodeGroup;
              }
          }
          else {
              patterns = (_patternGroups[kernelType] == null) ?
                  (_patternGroups[kernelType] = new Vector(2)) :
                  _patternGroups[kernelType];
          }
  
          if (patterns.size() == 0) {
              patterns.addElement(pattern);
          }
          else {
              boolean inserted = false;
              for (int i = 0; i < patterns.size(); i++) {
                  final LocationPathPattern lppToCompare =
                      (LocationPathPattern)patterns.elementAt(i);
  
                  if (pattern.noSmallerThan(lppToCompare)) {
                      inserted = true;
                      patterns.insertElementAt(pattern, i);
                      break;
                  }
              }
              if (inserted == false) {
                  patterns.addElement(pattern);
              }
          }
      }
  
      /**
       * Complete test sequences of a given type by adding all patterns
       * from a given group.
       */
      private void completeTestSequences(int nodeType, Vector patterns) {
          if (patterns != null) {
              if (_patternGroups[nodeType] == null) {
                  _patternGroups[nodeType] = patterns;
              }
              else {
                  final int m = patterns.size();
                  for (int j = 0; j < m; j++) {
                      addPattern(nodeType,
                          (LocationPathPattern) patterns.elementAt(j));
                  }
              }
          }
      }
  
      /**
       * Build test sequences. The first step is to complete the test sequences
       * by including patterns of "*" and "node()" kernel to all element test
       * sequences, and of "@*" to all attribute test sequences.
       */
      private void prepareTestSequences() {
          final Vector starGroup = _patternGroups[DTM.ELEMENT_NODE];
          final Vector atStarGroup = _patternGroups[DTM.ATTRIBUTE_NODE];
  
          // Complete test sequence for "text()" with "child::node()"
          completeTestSequences(DTM.TEXT_NODE, _childNodeGroup);
  
          // Complete test sequence for "*" with "child::node()"
          completeTestSequences(DTM.ELEMENT_NODE, _childNodeGroup);
  
          // Complete test sequence for "pi()" with "child::node()"
          completeTestSequences(DTM.PROCESSING_INSTRUCTION_NODE, _childNodeGroup);
  
          // Complete test sequence for "comment()" with "child::node()"
          completeTestSequences(DTM.COMMENT_NODE, _childNodeGroup);
  
          // Complete test sequence for "@*" with "attribute::node()"
          completeTestSequences(DTM.ATTRIBUTE_NODE, _attribNodeGroup);
  
          final Vector names = _stylesheet.getXSLTC().getNamesIndex();
          if (starGroup != null || atStarGroup != null ||
              _childNodeGroup != null || _attribNodeGroup != null)
          {
              final int n = _patternGroups.length;
  
              // Complete test sequence for user-defined types
              for (int i = DTM.NTYPES; i < n; i++) {
                  if (_patternGroups[i] == null) continue;
  
                  final String name = (String) names.elementAt(i - DTM.NTYPES);
  
                  if (isAttributeName(name)) {
                      // If an attribute then copy "@*" to its test sequence
                      completeTestSequences(i, atStarGroup);
  
                      // And also copy "attribute::node()" to its test sequence
                      completeTestSequences(i, _attribNodeGroup);
                  }
                  else {
                      // If an element then copy "*" to its test sequence
                      completeTestSequences(i, starGroup);
  
                      // And also copy "child::node()" to its test sequence
                      completeTestSequences(i, _childNodeGroup);
                  }
              }
          }
  
          _testSeq = new TestSeq[DTM.NTYPES + names.size()];
  
          final int n = _patternGroups.length;
          for (int i = 0; i < n; i++) {
              final Vector patterns = _patternGroups[i];
              if (patterns != null) {
                  final TestSeq testSeq = new TestSeq(patterns, i, this);
  // System.out.println("testSeq[" + i + "] = " + testSeq);
                  testSeq.reduce();
                  _testSeq[i] = testSeq;
                  testSeq.findTemplates(_neededTemplates);
              }
          }
  
          if (_childNodeGroup != null && _childNodeGroup.size() > 0) {
              _childNodeTestSeq = new TestSeq(_childNodeGroup, -1, this);
              _childNodeTestSeq.reduce();
              _childNodeTestSeq.findTemplates(_neededTemplates);
          }
  
  /*
          if (_attribNodeGroup != null && _attribNodeGroup.size() > 0) {
              _attribNodeTestSeq = new TestSeq(_attribNodeGroup, -1, this);
              _attribNodeTestSeq.reduce();
              _attribNodeTestSeq.findTemplates(_neededTemplates);
          }
  */
  
          if (_idxGroup != null && _idxGroup.size() > 0) {
              _idxTestSeq = new TestSeq(_idxGroup, this);
              _idxTestSeq.reduce();
              _idxTestSeq.findTemplates(_neededTemplates);
          }
  
          if (_rootPattern != null) {
              // doesn't matter what is 'put', only key matters
              _neededTemplates.put(_rootPattern.getTemplate(), this);
          }
      }
  
      private void compileNamedTemplate(Template template,
                                        ClassGenerator classGen) {
          final ConstantPoolGen cpg = classGen.getConstantPool();
          final InstructionList il = new InstructionList();
          String methodName = Util.escape(template.getName().toString());
  
          int numParams = 0;
          if (template.isSimpleNamedTemplate()) {
              Vector parameters = template.getParameters();
              numParams = parameters.size();
          }
  
          // Initialize the types and names arrays for the NamedMethodGenerator.
          Type[] types =
              new Type[4 + numParams];
          String[] names = new String[4 + numParams];
          types[0] = Util.getJCRefType(DOM_INTF_SIG);
          types[1] = Util.getJCRefType(NODE_ITERATOR_SIG);
          types[2] = Util.getJCRefType(TRANSLET_OUTPUT_SIG);
          types[3] = Type.INT;
          names[0] = DOCUMENT_PNAME;
          names[1] = ITERATOR_PNAME;
          names[2] = TRANSLET_OUTPUT_PNAME;
          names[3] = NODE_PNAME;
  
          // For simple named templates, the signature of the generated method
          // is not fixed. It depends on the number of parameters declared in the
          // template.
          for (int i = 4; i < 4 + numParams; i++) {
              types[i] = Util.getJCRefType(OBJECT_SIG);
              names[i] = "param" + String.valueOf(i-4);
          }
  
          NamedMethodGenerator methodGen =
                  new NamedMethodGenerator(ACC_PUBLIC,
                                       Type.VOID,
                                       types, names, methodName,
                                       getClassName(), il, cpg);
  
          il.append(template.compile(classGen, methodGen));
          il.append(RETURN);
  
          classGen.addMethod(methodGen);
      }
  
      private void compileTemplates(ClassGenerator classGen,
                                    MethodGenerator methodGen,
                                    InstructionHandle next)
      {
          Enumeration templates = _namedTemplates.keys();
          while (templates.hasMoreElements()) {
              final Template template = (Template)templates.nextElement();
              compileNamedTemplate(template, classGen);
          }
  
          templates = _neededTemplates.keys();
          while (templates.hasMoreElements()) {
              final Template template = (Template)templates.nextElement();
              if (template.hasContents()) {
                  // !!! TODO templates both named and matched
                  InstructionList til = template.compile(classGen, methodGen);
                  til.append(new GOTO_W(next));
                  _templateILs.put(template, til);
                  _templateIHs.put(template, til.getStart());
              }
              else {
                  // empty template
                  _templateIHs.put(template, next);
              }
          }
      }
  
      private void appendTemplateCode(InstructionList body) {
          final Enumeration templates = _neededTemplates.keys();
          while (templates.hasMoreElements()) {
              final Object iList =
                  _templateILs.get(templates.nextElement());
              if (iList != null) {
                  body.append((InstructionList)iList);
              }
          }
      }
  
      private void appendTestSequences(InstructionList body) {
          final int n = _testSeq.length;
          for (int i = 0; i < n; i++) {
              final TestSeq testSeq = _testSeq[i];
              if (testSeq != null) {
                  InstructionList il = testSeq.getInstructionList();
                  if (il != null)
                      body.append(il);
                  // else trivial TestSeq
              }
          }
      }
  
      public static void compileGetChildren(ClassGenerator classGen,
                                            MethodGenerator methodGen,
                                            int node) {
          final ConstantPoolGen cpg = classGen.getConstantPool();
          final InstructionList il = methodGen.getInstructionList();
          final int git = cpg.addInterfaceMethodref(DOM_INTF,
                                                    GET_CHILDREN,
                                                    GET_CHILDREN_SIG);
          il.append(methodGen.loadDOM());
          il.append(new ILOAD(node));
          il.append(new INVOKEINTERFACE(git, 2));
      }
  
      /**
       * Compiles the default handling for DOM elements: traverse all children
       */
      private InstructionList compileDefaultRecursion(ClassGenerator classGen,
                                                      MethodGenerator methodGen,
                                                      InstructionHandle next) {
          final ConstantPoolGen cpg = classGen.getConstantPool();
          final InstructionList il = new InstructionList();
          final String applyTemplatesSig = classGen.getApplyTemplatesSig();
          final int git = cpg.addInterfaceMethodref(DOM_INTF,
                                                    GET_CHILDREN,
                                                    GET_CHILDREN_SIG);
          final int applyTemplates = cpg.addMethodref(getClassName(),
                                                      functionName(),
                                                      applyTemplatesSig);
          il.append(classGen.loadTranslet());
          il.append(methodGen.loadDOM());
  
          il.append(methodGen.loadDOM());
          il.append(new ILOAD(_currentIndex));
          il.append(new INVOKEINTERFACE(git, 2));
          il.append(methodGen.loadHandler());
          il.append(new INVOKEVIRTUAL(applyTemplates));
          il.append(new GOTO_W(next));
          return il;
      }
  
      /**
       * Compiles the default action for DOM text nodes and attribute nodes:
       * output the node's text value
       */
      private InstructionList compileDefaultText(ClassGenerator classGen,
                                                 MethodGenerator methodGen,
                                                 InstructionHandle next) {
          final ConstantPoolGen cpg = classGen.getConstantPool();
          final InstructionList il = new InstructionList();
  
          final int chars = cpg.addInterfaceMethodref(DOM_INTF,
                                                      CHARACTERS,
                                                      CHARACTERS_SIG);
          il.append(methodGen.loadDOM());
          il.append(new ILOAD(_currentIndex));
          il.append(methodGen.loadHandler());
          il.append(new INVOKEINTERFACE(chars, 3));
          il.append(new GOTO_W(next));
          return il;
      }
  
      private InstructionList compileNamespaces(ClassGenerator classGen,
                                                MethodGenerator methodGen,
                                                boolean[] isNamespace,
                                                boolean[] isAttribute,
                                                boolean attrFlag,
                                                InstructionHandle defaultTarget) {
          final XSLTC xsltc = classGen.getParser().getXSLTC();
          final ConstantPoolGen cpg = classGen.getConstantPool();
  
          // Append switch() statement - namespace test dispatch loop
          final Vector namespaces = xsltc.getNamespaceIndex();
          final Vector names = xsltc.getNamesIndex();
          final int namespaceCount = namespaces.size() + 1;
          final int namesCount = names.size();
  
          final InstructionList il = new InstructionList();
          final int[] types = new int[namespaceCount];
          final InstructionHandle[] targets = new InstructionHandle[types.length];
  
          if (namespaceCount > 0) {
              boolean compiled = false;
  
              // Initialize targets for namespace() switch statement
              for (int i = 0; i < namespaceCount; i++) {
                  targets[i] = defaultTarget;
                  types[i] = i;
              }
  
              // Add test sequences for known namespace types
              for (int i = DTM.NTYPES; i < (DTM.NTYPES+namesCount); i++) {
                  if ((isNamespace[i]) && (isAttribute[i] == attrFlag)) {
                      String name = (String)names.elementAt(i-DTM.NTYPES);
                      String namespace = name.substring(0,name.lastIndexOf(':'));
                      final int type = xsltc.registerNamespace(namespace);
  
                      if ((i < _testSeq.length) &&
                          (_testSeq[i] != null)) {
                          targets[type] =
                              (_testSeq[i]).compile(classGen,
                                                         methodGen,
                                                         defaultTarget);
                          compiled = true;
                      }
                  }
              }
  
              // Return "null" if no test sequences were compiled
              if (!compiled) return(null);
  
              // Append first code in applyTemplates() - get type of current node
              final int getNS = cpg.addInterfaceMethodref(DOM_INTF,
                                                          "getNamespaceType",
                                                          "(I)I");
              il.append(methodGen.loadDOM());
              il.append(new ILOAD(_currentIndex));
              il.append(new INVOKEINTERFACE(getNS, 2));
              il.append(new SWITCH(types, targets, defaultTarget));
              return(il);
          }
          else {
              return(null);
          }
      }
  
     /**
       * Compiles the applyTemplates() method and adds it to the translet.
       * This is the main dispatch method.
       */
      public void compileApplyTemplates(ClassGenerator classGen) {
          final XSLTC xsltc = classGen.getParser().getXSLTC();
          final ConstantPoolGen cpg = classGen.getConstantPool();
          final Vector names = xsltc.getNamesIndex();
  
          // Create the applyTemplates() method
          final Type[] argTypes =
              new Type[3];
          argTypes[0] = Util.getJCRefType(DOM_INTF_SIG);
          argTypes[1] = Util.getJCRefType(NODE_ITERATOR_SIG);
          argTypes[2] = Util.getJCRefType(TRANSLET_OUTPUT_SIG);
  
          final String[] argNames = new String[3];
          argNames[0] = DOCUMENT_PNAME;
          argNames[1] = ITERATOR_PNAME;
          argNames[2] = TRANSLET_OUTPUT_PNAME;
  
          final InstructionList mainIL = new InstructionList();
          final MethodGenerator methodGen =
              new MethodGenerator(ACC_PUBLIC | ACC_FINAL,
                                  Type.VOID,
                                  argTypes, argNames, functionName(),
                                  getClassName(), mainIL,
                                  classGen.getConstantPool());
          methodGen.addException("jaxp.sun.org.apache.xalan.internal.xsltc.TransletException");
          // Insert an extra NOP just to keep "current" from appearing as if it
          // has a value before the start of the loop.
          mainIL.append(NOP);
  
  
          // Create a local variable to hold the current node
          final LocalVariableGen current;
          current = methodGen.addLocalVariable2("current",
                                                Type.INT,
                                                null);
          _currentIndex = current.getIndex();
  
          // Create the "body" instruction list that will eventually hold the
          // code for the entire method (other ILs will be appended).
          final InstructionList body = new InstructionList();
          body.append(NOP);
  
          // Create an instruction list that contains the default next-node
          // iteration
          final InstructionList ilLoop = new InstructionList();
          ilLoop.append(methodGen.loadIterator());
          ilLoop.append(methodGen.nextNode());
          ilLoop.append(DUP);
          ilLoop.append(new ISTORE(_currentIndex));
  
          // The body of this code can get very large - large than can be handled
          // by a single IFNE(body.getStart()) instruction - need workaround:
          final BranchHandle ifeq = ilLoop.append(new IFLT(null));
          final BranchHandle loop = ilLoop.append(new GOTO_W(null));
          ifeq.setTarget(ilLoop.append(RETURN));  // applyTemplates() ends here!
          final InstructionHandle ihLoop = ilLoop.getStart();
  
          current.setStart(mainIL.append(new GOTO_W(ihLoop)));
  
          // Live range of "current" ends at end of loop
          current.setEnd(loop);
  
          // Compile default handling of elements (traverse children)
          InstructionList ilRecurse =
              compileDefaultRecursion(classGen, methodGen, ihLoop);
          InstructionHandle ihRecurse = ilRecurse.getStart();
  
          // Compile default handling of text/attribute nodes (output text)
          InstructionList ilText =
              compileDefaultText(classGen, methodGen, ihLoop);
          InstructionHandle ihText = ilText.getStart();
  
          // Distinguish attribute/element/namespace tests for further processing
          final int[] types = new int[DTM.NTYPES + names.size()];
          for (int i = 0; i < types.length; i++) {
              types[i] = i;
          }
  
          // Initialize isAttribute[] and isNamespace[] arrays
          final boolean[] isAttribute = new boolean[types.length];
          final boolean[] isNamespace = new boolean[types.length];
          for (int i = 0; i < names.size(); i++) {
              final String name = (String)names.elementAt(i);
              isAttribute[i + DTM.NTYPES] = isAttributeName(name);
              isNamespace[i + DTM.NTYPES] = isNamespaceName(name);
          }
  
          // Compile all templates - regardless of pattern type
          compileTemplates(classGen, methodGen, ihLoop);
  
          // Handle template with explicit "*" pattern
          final TestSeq elemTest = _testSeq[DTM.ELEMENT_NODE];
          InstructionHandle ihElem = ihRecurse;
          if (elemTest != null)
              ihElem = elemTest.compile(classGen, methodGen, ihRecurse);
  
          // Handle template with explicit "@*" pattern
          final TestSeq attrTest = _testSeq[DTM.ATTRIBUTE_NODE];
          InstructionHandle ihAttr = ihText;
          if (attrTest != null)
              ihAttr = attrTest.compile(classGen, methodGen, ihAttr);
  
          // Do tests for id() and key() patterns first
          InstructionList ilKey = null;
          if (_idxTestSeq != null) {
              loop.setTarget(_idxTestSeq.compile(classGen, methodGen, body.getStart()));
              ilKey = _idxTestSeq.getInstructionList();
          }
          else {
              loop.setTarget(body.getStart());
          }
  
          // If there is a match on node() we need to replace ihElem
          // and ihText if the priority of node() is higher
          if (_childNodeTestSeq != null) {
              // Compare priorities of node() and "*"
              double nodePrio = _childNodeTestSeq.getPriority();
              int    nodePos  = _childNodeTestSeq.getPosition();
              double elemPrio = (0 - Double.MAX_VALUE);
              int    elemPos  = Integer.MIN_VALUE;
  
              if (elemTest != null) {
                  elemPrio = elemTest.getPriority();
                  elemPos  = elemTest.getPosition();
              }
              if (elemPrio == Double.NaN || elemPrio < nodePrio ||
                  (elemPrio == nodePrio && elemPos < nodePos))
              {
                  ihElem = _childNodeTestSeq.compile(classGen, methodGen, ihLoop);
              }
  
              // Compare priorities of node() and text()
              final TestSeq textTest = _testSeq[DTM.TEXT_NODE];
              double textPrio = (0 - Double.MAX_VALUE);
              int    textPos  = Integer.MIN_VALUE;
  
              if (textTest != null) {
                  textPrio = textTest.getPriority();
                  textPos  = textTest.getPosition();
              }
              if (textPrio == Double.NaN || textPrio < nodePrio ||
                  (textPrio == nodePrio && textPos < nodePos))
              {
                  ihText = _childNodeTestSeq.compile(classGen, methodGen, ihLoop);
                  _testSeq[DTM.TEXT_NODE] = _childNodeTestSeq;
              }
          }
  
          // Handle templates with "ns:*" pattern
          InstructionHandle elemNamespaceHandle = ihElem;
          InstructionList nsElem = compileNamespaces(classGen, methodGen,
                                                     isNamespace, isAttribute,
                                                     false, ihElem);
          if (nsElem != null) elemNamespaceHandle = nsElem.getStart();
  
          // Handle templates with "ns:@*" pattern
          InstructionHandle attrNamespaceHandle = ihAttr;
          InstructionList nsAttr = compileNamespaces(classGen, methodGen,
                                                     isNamespace, isAttribute,
                                                     true, ihAttr);
          if (nsAttr != null) attrNamespaceHandle = nsAttr.getStart();
  
          // Handle templates with "ns:elem" or "ns:@attr" pattern
          final InstructionHandle[] targets = new InstructionHandle[types.length];
          for (int i = DTM.NTYPES; i < targets.length; i++) {
              final TestSeq testSeq = _testSeq[i];
              // Jump straight to namespace tests ?
              if (isNamespace[i]) {
                  if (isAttribute[i])
                      targets[i] = attrNamespaceHandle;
                  else
                      targets[i] = elemNamespaceHandle;
              }
              // Test first, then jump to namespace tests
              else if (testSeq != null) {
                  if (isAttribute[i])
                      targets[i] = testSeq.compile(classGen, methodGen,
                                                   attrNamespaceHandle);
                  else
                      targets[i] = testSeq.compile(classGen, methodGen,
                                                   elemNamespaceHandle);
              }
              else {
                  targets[i] = ihLoop;
              }
          }
  
  
          // Handle pattern with match on root node - default: traverse children
          targets[DTM.ROOT_NODE] = _rootPattern != null
              ? getTemplateInstructionHandle(_rootPattern.getTemplate())
              : ihRecurse;
  
          // Handle pattern with match on root node - default: traverse children
          targets[DTM.DOCUMENT_NODE] = _rootPattern != null
              ? getTemplateInstructionHandle(_rootPattern.getTemplate())
              : ihRecurse;
  
          // Handle any pattern with match on text nodes - default: output text
          targets[DTM.TEXT_NODE] = _testSeq[DTM.TEXT_NODE] != null
              ? _testSeq[DTM.TEXT_NODE].compile(classGen, methodGen, ihText)
              : ihText;
  
          // This DOM-type is not in use - default: process next node
          targets[DTM.NAMESPACE_NODE] = ihLoop;
  
          // Match unknown element in DOM - default: check for namespace match
          targets[DTM.ELEMENT_NODE] = elemNamespaceHandle;
  
          // Match unknown attribute in DOM - default: check for namespace match
          targets[DTM.ATTRIBUTE_NODE] = attrNamespaceHandle;
  
          // Match on processing instruction - default: process next node
          InstructionHandle ihPI = ihLoop;
          if (_childNodeTestSeq != null) ihPI = ihElem;
          if (_testSeq[DTM.PROCESSING_INSTRUCTION_NODE] != null)
              targets[DTM.PROCESSING_INSTRUCTION_NODE] =
                  _testSeq[DTM.PROCESSING_INSTRUCTION_NODE].
                  compile(classGen, methodGen, ihPI);
          else
              targets[DTM.PROCESSING_INSTRUCTION_NODE] = ihPI;
  
          // Match on comments - default: process next node
          InstructionHandle ihComment = ihLoop;
          if (_childNodeTestSeq != null) ihComment = ihElem;
          targets[DTM.COMMENT_NODE] = _testSeq[DTM.COMMENT_NODE] != null
              ? _testSeq[DTM.COMMENT_NODE].compile(classGen, methodGen, ihComment)
              : ihComment;
  
              // This DOM-type is not in use - default: process next node
          targets[DTM.CDATA_SECTION_NODE] = ihLoop;
  
          // This DOM-type is not in use - default: process next node
          targets[DTM.DOCUMENT_FRAGMENT_NODE] = ihLoop;
  
          // This DOM-type is not in use - default: process next node
          targets[DTM.DOCUMENT_TYPE_NODE] = ihLoop;
  
          // This DOM-type is not in use - default: process next node
          targets[DTM.ENTITY_NODE] = ihLoop;
  
          // This DOM-type is not in use - default: process next node
          targets[DTM.ENTITY_REFERENCE_NODE] = ihLoop;
  
          // This DOM-type is not in use - default: process next node
          targets[DTM.NOTATION_NODE] = ihLoop;
  
  
          // Now compile test sequences for various match patterns:
          for (int i = DTM.NTYPES; i < targets.length; i++) {
              final TestSeq testSeq = _testSeq[i];
              // Jump straight to namespace tests ?
              if ((testSeq == null) || (isNamespace[i])) {
                  if (isAttribute[i])
                      targets[i] = attrNamespaceHandle;
                  else
                      targets[i] = elemNamespaceHandle;
              }
              // Match on node type
              else {
                  if (isAttribute[i])
                      targets[i] = testSeq.compile(classGen, methodGen,
                                                   attrNamespaceHandle);
                  else
                      targets[i] = testSeq.compile(classGen, methodGen,
                                                   elemNamespaceHandle);
              }
          }
  
          if (ilKey != null) body.insert(ilKey);
  
          // Append first code in applyTemplates() - get type of current node
          final int getType = cpg.addInterfaceMethodref(DOM_INTF,
                                                        "getExpandedTypeID",
                                                        "(I)I");
          body.append(methodGen.loadDOM());
          body.append(new ILOAD(_currentIndex));
          body.append(new INVOKEINTERFACE(getType, 2));
  
          // Append switch() statement - main dispatch loop in applyTemplates()
          InstructionHandle disp = body.append(new SWITCH(types, targets, ihLoop));
  
          // Append all the "case:" statements
          appendTestSequences(body);
          // Append the actual template code
          appendTemplateCode(body);
  
          // Append NS:* node tests (if any)
          if (nsElem != null) body.append(nsElem);
          // Append NS:@* node tests (if any)
          if (nsAttr != null) body.append(nsAttr);
  
          // Append default action for element and root nodes
          body.append(ilRecurse);
          // Append default action for text and attribute nodes
          body.append(ilText);
  
          // putting together constituent instruction lists
          mainIL.append(body);
          // fall through to ilLoop
          mainIL.append(ilLoop);
  
          peepHoleOptimization(methodGen);
          classGen.addMethod(methodGen);
  
          // Compile method(s) for <xsl:apply-imports/> for this mode
          if (_importLevels != null) {
              Enumeration levels = _importLevels.keys();
              while (levels.hasMoreElements()) {
                  Integer max = (Integer)levels.nextElement();
                  Integer min = (Integer)_importLevels.get(max);
                  compileApplyImports(classGen, min.intValue(), max.intValue());
              }
          }
      }
  
      private void compileTemplateCalls(ClassGenerator classGen,
                                        MethodGenerator methodGen,
                                        InstructionHandle next, int min, int max){
          Enumeration templates = _neededTemplates.keys();
          while (templates.hasMoreElements()) {
              final Template template = (Template)templates.nextElement();
              final int prec = template.getImportPrecedence();
              if ((prec >= min) && (prec < max)) {
                  if (template.hasContents()) {
                      InstructionList til = template.compile(classGen, methodGen);
                      til.append(new GOTO_W(next));
                      _templateILs.put(template, til);
                      _templateIHs.put(template, til.getStart());
                  }
                  else {
                      // empty template
                      _templateIHs.put(template, next);
                  }
              }
          }
      }
  
  
      public void compileApplyImports(ClassGenerator classGen, int min, int max) {
          final XSLTC xsltc = classGen.getParser().getXSLTC();
          final ConstantPoolGen cpg = classGen.getConstantPool();
          final Vector names      = xsltc.getNamesIndex();
  
          // Clear some datastructures
          _namedTemplates = new Hashtable();
          _neededTemplates = new Hashtable();
          _templateIHs = new Hashtable();
          _templateILs = new Hashtable();
          _patternGroups = new Vector[32];
          _rootPattern = null;
  
          // IMPORTANT: Save orignal & complete set of templates!!!!
          Vector oldTemplates = _templates;
  
          // Gather templates that are within the scope of this import
          _templates = new Vector();
          final Enumeration templates = oldTemplates.elements();
          while (templates.hasMoreElements()) {
              final Template template = (Template)templates.nextElement();
              final int prec = template.getImportPrecedence();
              if ((prec >= min) && (prec < max)) addTemplate(template);
          }
  
          // Process all patterns from those templates
          processPatterns(_keys);
  
          // Create the applyTemplates() method
          final Type[] argTypes =
              new Type[4];
          argTypes[0] = Util.getJCRefType(DOM_INTF_SIG);
          argTypes[1] = Util.getJCRefType(NODE_ITERATOR_SIG);
          argTypes[2] = Util.getJCRefType(TRANSLET_OUTPUT_SIG);
          argTypes[3] = Type.INT;
  
          final String[] argNames = new String[4];
          argNames[0] = DOCUMENT_PNAME;
          argNames[1] = ITERATOR_PNAME;
          argNames[2] = TRANSLET_OUTPUT_PNAME;
          argNames[3] = NODE_PNAME;
  
          final InstructionList mainIL = new InstructionList();
          final MethodGenerator methodGen =
              new MethodGenerator(ACC_PUBLIC | ACC_FINAL,
                                  Type.VOID,
                                  argTypes, argNames, functionName()+'_'+max,
                                  getClassName(), mainIL,
                                  classGen.getConstantPool());
          methodGen.addException("jaxp.sun.org.apache.xalan.internal.xsltc.TransletException");
  
          // Create the local variable to hold the current node
          final LocalVariableGen current;
          current = methodGen.addLocalVariable2("current",
                                                Type.INT,
                                                null);
          _currentIndex = current.getIndex();
  
          mainIL.append(new ILOAD(methodGen.getLocalIndex(NODE_PNAME)));
          current.setStart(mainIL.append(new ISTORE(_currentIndex)));
  
          // Create the "body" instruction list that will eventually hold the
          // code for the entire method (other ILs will be appended).
          final InstructionList body = new InstructionList();
          body.append(NOP);
  
          // Create an instruction list that contains the default next-node
          // iteration
          final InstructionList ilLoop = new InstructionList();
          ilLoop.append(RETURN);
          final InstructionHandle ihLoop = ilLoop.getStart();
  
          // Compile default handling of elements (traverse children)
          InstructionList ilRecurse =
              compileDefaultRecursion(classGen, methodGen, ihLoop);
          InstructionHandle ihRecurse = ilRecurse.getStart();
  
          // Compile default handling of text/attribute nodes (output text)
          InstructionList ilText =
              compileDefaultText(classGen, methodGen, ihLoop);
          InstructionHandle ihText = ilText.getStart();
  
          // Distinguish attribute/element/namespace tests for further processing
          final int[] types = new int[DTM.NTYPES + names.size()];
          for (int i = 0; i < types.length; i++) {
              types[i] = i;
          }
  
          final boolean[] isAttribute = new boolean[types.length];
          final boolean[] isNamespace = new boolean[types.length];
          for (int i = 0; i < names.size(); i++) {
              final String name = (String)names.elementAt(i);
              isAttribute[i+DTM.NTYPES] = isAttributeName(name);
              isNamespace[i+DTM.NTYPES] = isNamespaceName(name);
          }
  
          // Compile all templates - regardless of pattern type
          compileTemplateCalls(classGen, methodGen, ihLoop, min, max);
  
          // Handle template with explicit "*" pattern
          final TestSeq elemTest = _testSeq[DTM.ELEMENT_NODE];
          InstructionHandle ihElem = ihRecurse;
          if (elemTest != null) {
              ihElem = elemTest.compile(classGen, methodGen, ihLoop);
          }
  
          // Handle template with explicit "@*" pattern
          final TestSeq attrTest = _testSeq[DTM.ATTRIBUTE_NODE];
          InstructionHandle ihAttr = ihLoop;
          if (attrTest != null) {
              ihAttr = attrTest.compile(classGen, methodGen, ihAttr);
          }
  
          // Do tests for id() and key() patterns first
          InstructionList ilKey = null;
          if (_idxTestSeq != null) {
              ilKey = _idxTestSeq.getInstructionList();
          }
  
          // If there is a match on node() we need to replace ihElem
          // and ihText if the priority of node() is higher
          if (_childNodeTestSeq != null) {
              // Compare priorities of node() and "*"
              double nodePrio = _childNodeTestSeq.getPriority();
              int    nodePos  = _childNodeTestSeq.getPosition();
              double elemPrio = (0 - Double.MAX_VALUE);
              int    elemPos  = Integer.MIN_VALUE;
  
              if (elemTest != null) {
                  elemPrio = elemTest.getPriority();
                  elemPos  = elemTest.getPosition();
              }
  
              if (elemPrio == Double.NaN || elemPrio < nodePrio ||
                  (elemPrio == nodePrio && elemPos < nodePos))
              {
                  ihElem = _childNodeTestSeq.compile(classGen, methodGen, ihLoop);
              }
  
              // Compare priorities of node() and text()
              final TestSeq textTest = _testSeq[DTM.TEXT_NODE];
              double textPrio = (0 - Double.MAX_VALUE);
              int    textPos  = Integer.MIN_VALUE;
  
              if (textTest != null) {
                  textPrio = textTest.getPriority();
                  textPos  = textTest.getPosition();
              }
  
              if (textPrio == Double.NaN || textPrio < nodePrio ||
                  (textPrio == nodePrio && textPos < nodePos))
              {
                  ihText = _childNodeTestSeq.compile(classGen, methodGen, ihLoop);
                  _testSeq[DTM.TEXT_NODE] = _childNodeTestSeq;
              }
          }
  
          // Handle templates with "ns:*" pattern
          InstructionHandle elemNamespaceHandle = ihElem;
          InstructionList nsElem = compileNamespaces(classGen, methodGen,
                                                     isNamespace, isAttribute,
                                                     false, ihElem);
          if (nsElem != null) elemNamespaceHandle = nsElem.getStart();
  
          // Handle templates with "ns:@*" pattern
          InstructionList nsAttr = compileNamespaces(classGen, methodGen,
                                                     isNamespace, isAttribute,
                                                     true, ihAttr);
          InstructionHandle attrNamespaceHandle = ihAttr;
          if (nsAttr != null) attrNamespaceHandle = nsAttr.getStart();
  
          // Handle templates with "ns:elem" or "ns:@attr" pattern
          final InstructionHandle[] targets = new InstructionHandle[types.length];
          for (int i = DTM.NTYPES; i < targets.length; i++) {
              final TestSeq testSeq = _testSeq[i];
              // Jump straight to namespace tests ?
              if (isNamespace[i]) {
                  if (isAttribute[i])
                      targets[i] = attrNamespaceHandle;
                  else
                      targets[i] = elemNamespaceHandle;
              }
              // Test first, then jump to namespace tests
              else if (testSeq != null) {
                  if (isAttribute[i])
                      targets[i] = testSeq.compile(classGen, methodGen,
                                                   attrNamespaceHandle);
                  else
                      targets[i] = testSeq.compile(classGen, methodGen,
                                                   elemNamespaceHandle);
              }
              else {
                  targets[i] = ihLoop;
              }
          }
  
          // Handle pattern with match on root node - default: traverse children
          targets[DTM.ROOT_NODE] = _rootPattern != null
              ? getTemplateInstructionHandle(_rootPattern.getTemplate())
              : ihRecurse;
          // Handle pattern with match on root node - default: traverse children
          targets[DTM.DOCUMENT_NODE] = _rootPattern != null
              ? getTemplateInstructionHandle(_rootPattern.getTemplate())
              : ihRecurse;    // %HZ%:  Was ihLoop in XSLTC_DTM branch
  
          // Handle any pattern with match on text nodes - default: loop
          targets[DTM.TEXT_NODE] = _testSeq[DTM.TEXT_NODE] != null
              ? _testSeq[DTM.TEXT_NODE].compile(classGen, methodGen, ihText)
              : ihText;
  
          // This DOM-type is not in use - default: process next node
          targets[DTM.NAMESPACE_NODE] = ihLoop;
  
          // Match unknown element in DOM - default: check for namespace match
          targets[DTM.ELEMENT_NODE] = elemNamespaceHandle;
  
          // Match unknown attribute in DOM - default: check for namespace match
          targets[DTM.ATTRIBUTE_NODE] = attrNamespaceHandle;
  
          // Match on processing instruction - default: loop
          InstructionHandle ihPI = ihLoop;
          if (_childNodeTestSeq != null) ihPI = ihElem;
          if (_testSeq[DTM.PROCESSING_INSTRUCTION_NODE] != null) {
              targets[DTM.PROCESSING_INSTRUCTION_NODE] =
                  _testSeq[DTM.PROCESSING_INSTRUCTION_NODE].
                  compile(classGen, methodGen, ihPI);
          }
          else {
              targets[DTM.PROCESSING_INSTRUCTION_NODE] = ihPI;
          }
  
          // Match on comments - default: process next node
          InstructionHandle ihComment = ihLoop;
          if (_childNodeTestSeq != null) ihComment = ihElem;
          targets[DTM.COMMENT_NODE] = _testSeq[DTM.COMMENT_NODE] != null
              ? _testSeq[DTM.COMMENT_NODE].compile(classGen, methodGen, ihComment)
              : ihComment;
  
                  // This DOM-type is not in use - default: process next node
          targets[DTM.CDATA_SECTION_NODE] = ihLoop;
  
          // This DOM-type is not in use - default: process next node
          targets[DTM.DOCUMENT_FRAGMENT_NODE] = ihLoop;
  
          // This DOM-type is not in use - default: process next node
          targets[DTM.DOCUMENT_TYPE_NODE] = ihLoop;
  
          // This DOM-type is not in use - default: process next node
          targets[DTM.ENTITY_NODE] = ihLoop;
  
          // This DOM-type is not in use - default: process next node
          targets[DTM.ENTITY_REFERENCE_NODE] = ihLoop;
  
          // This DOM-type is not in use - default: process next node
          targets[DTM.NOTATION_NODE] = ihLoop;
  
  
  
          // Now compile test sequences for various match patterns:
          for (int i = DTM.NTYPES; i < targets.length; i++) {
              final TestSeq testSeq = _testSeq[i];
              // Jump straight to namespace tests ?
              if ((testSeq == null) || (isNamespace[i])) {
                  if (isAttribute[i])
                      targets[i] = attrNamespaceHandle;
                  else
                      targets[i] = elemNamespaceHandle;
              }
              // Match on node type
              else {
                  if (isAttribute[i])
                      targets[i] = testSeq.compile(classGen, methodGen,
                                                   attrNamespaceHandle);
                  else
                      targets[i] = testSeq.compile(classGen, methodGen,
                                                   elemNamespaceHandle);
              }
          }
  
          if (ilKey != null) body.insert(ilKey);
  
          // Append first code in applyTemplates() - get type of current node
          final int getType = cpg.addInterfaceMethodref(DOM_INTF,
                                                        "getExpandedTypeID",
                                                        "(I)I");
          body.append(methodGen.loadDOM());
          body.append(new ILOAD(_currentIndex));
          body.append(new INVOKEINTERFACE(getType, 2));
  
          // Append switch() statement - main dispatch loop in applyTemplates()
          InstructionHandle disp = body.append(new SWITCH(types,targets,ihLoop));
  
          // Append all the "case:" statements
          appendTestSequences(body);
          // Append the actual template code
          appendTemplateCode(body);
  
          // Append NS:* node tests (if any)
          if (nsElem != null) body.append(nsElem);
          // Append NS:@* node tests (if any)
          if (nsAttr != null) body.append(nsAttr);
  
          // Append default action for element and root nodes
          body.append(ilRecurse);
          // Append default action for text and attribute nodes
          body.append(ilText);
  
          // putting together constituent instruction lists
          mainIL.append(body);
  
          // Mark the end of the live range for the "current" variable
          current.setEnd(body.getEnd());
  
          // fall through to ilLoop
          mainIL.append(ilLoop);
  
          peepHoleOptimization(methodGen);
          classGen.addMethod(methodGen);
  
          // Restore original (complete) set of templates for this transformation
          _templates = oldTemplates;
      }
  
      /**
        * Peephole optimization.
        */
      private void peepHoleOptimization(MethodGenerator methodGen) {
          InstructionList il = methodGen.getInstructionList();
          InstructionFinder find = new InstructionFinder(il);
          InstructionHandle ih;
          String pattern;
  
          // LoadInstruction, POP => (removed)
          // pattern = "LoadInstruction POP";
          // changed to lower case - changing to all lower case although only the instruction with capital I
          // is creating a problem in the Turkish locale
          pattern = "loadinstruction pop";
  
          for (Iterator iter = find.search(pattern); iter.hasNext();) {
              InstructionHandle[] match = (InstructionHandle[]) iter.next();
              try {
                  if (!match[0].hasTargeters() && !match[1].hasTargeters()) {
                      il.delete(match[0], match[1]);
                  }
              }
              catch (TargetLostException e) {
                  // TODO: move target down into the list
              }
          }
  
          // ILOAD_N, ILOAD_N, SWAP, ISTORE_N => ILOAD_N
          // pattern = "ILOAD ILOAD SWAP ISTORE";
          // changed to lower case - changing to all lower case although only the instruction with capital I
          // is creating a problem in the Turkish locale
          pattern = "iload iload swap istore";
          for (Iterator iter = find.search(pattern); iter.hasNext();) {
              InstructionHandle[] match = (InstructionHandle[]) iter.next();
              try {
                  ILOAD iload1 =
                      (ILOAD) match[0].getInstruction();
                  ILOAD iload2 =
                      (ILOAD) match[1].getInstruction();
                  ISTORE istore =
                      (ISTORE) match[3].getInstruction();
  
                  if (!match[1].hasTargeters() &&
                      !match[2].hasTargeters() &&
                      !match[3].hasTargeters() &&
                      iload1.getIndex() == iload2.getIndex() &&
                      iload2.getIndex() == istore.getIndex())
                  {
                      il.delete(match[1], match[3]);
                  }
              }
              catch (TargetLostException e) {
                  // TODO: move target down into the list
              }
          }
  
          // LoadInstruction_N, LoadInstruction_M, SWAP => LoadInstruction_M, LoadInstruction_N
          // pattern = "LoadInstruction LoadInstruction SWAP";
          // changed to lower case - changing to all lower case although only the instruction with capital I
          // is creating a problem in the Turkish locale
          pattern = "loadinstruction loadinstruction swap";
          for (Iterator iter = find.search(pattern); iter.hasNext();) {
              InstructionHandle[] match = (InstructionHandle[])iter.next();
              try {
                  if (!match[0].hasTargeters() &&
                      !match[1].hasTargeters() &&
                      !match[2].hasTargeters())
                  {
                      Instruction load_m = match[1].getInstruction();
                      il.insert(match[0], load_m);
                      il.delete(match[1], match[2]);
                  }
              }
              catch (TargetLostException e) {
                  // TODO: move target down into the list
              }
          }
  
          // ALOAD_N ALOAD_N => ALOAD_N DUP
          // pattern = "ALOAD ALOAD";
          // changed to lower case - changing to all lower case although only the instruction with capital I
          // is creating a problem in the Turkish locale
          pattern = "aload aload";
          for (Iterator iter = find.search(pattern); iter.hasNext();) {
              InstructionHandle[] match = (InstructionHandle[])iter.next();
              try {
                  if (!match[1].hasTargeters()) {
                      ALOAD aload1 =
                          (ALOAD) match[0].getInstruction();
                      ALOAD aload2 =
                          (ALOAD) match[1].getInstruction();
  
                      if (aload1.getIndex() == aload2.getIndex()) {
                          il.insert(match[1], new DUP());
                          il.delete(match[1]);
                      }
                  }
              }
              catch (TargetLostException e) {
                  // TODO: move target down into the list
              }
          }
      }
  
      public InstructionHandle getTemplateInstructionHandle(Template template) {
          return (InstructionHandle)_templateIHs.get(template);
      }
  
      /**
       * Auxiliary method to determine if a qname is an attribute.
       */
      private static boolean isAttributeName(String qname) {
          final int col = qname.lastIndexOf(':') + 1;
          return (qname.charAt(col) == '@');
      }
  
      /**
       * Auxiliary method to determine if a qname is a namespace
       * qualified "*".
       */
      private static boolean isNamespaceName(String qname) {
          final int col = qname.lastIndexOf(':');
          return (col > -1 && qname.charAt(qname.length()-1) == '*');
      }
  }
  