View Javadoc
1   /*
2    * reserved comment block
3    * DO NOT REMOVE OR ALTER!
4    */
5   /*
6    * Copyright 2001-2004 The Apache Software Foundation.
7    *
8    * Licensed under the Apache License, Version 2.0 (the "License");
9    * you may not use this file except in compliance with the License.
10   * You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  /*
21   * $Id: Mode.java,v 1.2.4.1 2005/09/19 05:18:11 pvedula Exp $
22   */
23  
24  package com.sun.org.apache.xalan.internal.xsltc.compiler;
25  
26  import java.util.Enumeration;
27  import java.util.Hashtable;
28  import java.util.Iterator;
29  import java.util.Vector;
30  
31  import com.sun.org.apache.bcel.internal.generic.Instruction;
32  import com.sun.org.apache.bcel.internal.generic.BranchHandle;
33  import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
34  import com.sun.org.apache.bcel.internal.generic.DUP;
35  import com.sun.org.apache.bcel.internal.generic.GOTO_W;
36  import com.sun.org.apache.bcel.internal.generic.IFLT;
37  import com.sun.org.apache.bcel.internal.generic.ILOAD;
38  import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
39  import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
40  import com.sun.org.apache.bcel.internal.generic.ISTORE;
41  import com.sun.org.apache.bcel.internal.generic.InstructionHandle;
42  import com.sun.org.apache.bcel.internal.generic.InstructionList;
43  import com.sun.org.apache.bcel.internal.generic.LocalVariableGen;
44  import com.sun.org.apache.bcel.internal.generic.SWITCH;
45  import com.sun.org.apache.bcel.internal.generic.TargetLostException;
46  import com.sun.org.apache.bcel.internal.util.InstructionFinder;
47  import com.sun.org.apache.xalan.internal.xsltc.DOM;
48  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
49  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
50  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NamedMethodGenerator;
51  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;
52  import com.sun.org.apache.xml.internal.dtm.Axis;
53  import com.sun.org.apache.xml.internal.dtm.DTM;
54  
55  /**
56   * Mode gathers all the templates belonging to a given mode;
57   * it is responsible for generating an appropriate
58   * applyTemplates + (mode name) method in the translet.
59   * @author Jacek Ambroziak
60   * @author Santiago Pericas-Geertsen
61   * @author Morten Jorgensen
62   * @author Erwin Bolwidt <ejb@klomp.org>
63   * @author G. Todd Miller
64   */
65  final class Mode implements Constants {
66  
67      /**
68       * The name of this mode as defined in the stylesheet.
69       */
70      private final QName _name;
71  
72      /**
73       * A reference to the stylesheet object that owns this mode.
74       */
75      private final Stylesheet _stylesheet;
76  
77      /**
78       * The name of the method in which this mode is compiled.
79       */
80      private final String _methodName;
81  
82      /**
83       * A vector of all the templates in this mode.
84       */
85      private Vector _templates;
86  
87      /**
88       * Group for patterns with node()-type kernel and child axis.
89       */
90      private Vector _childNodeGroup = null;
91  
92      /**
93       * Test sequence for patterns with node()-type kernel and child axis.
94       */
95      private TestSeq _childNodeTestSeq = null;
96  
97      /**
98       * Group for patterns with node()-type kernel and attribute axis.
99       */
100     private Vector _attribNodeGroup = null;
101 
102     /**
103      * Test sequence for patterns with node()-type kernel and attribute axis.
104      */
105     private TestSeq _attribNodeTestSeq = null;
106 
107     /**
108      * Group for patterns with id() or key()-type kernel.
109      */
110     private Vector _idxGroup = null;
111 
112     /**
113      * Test sequence for patterns with id() or key()-type kernel.
114      */
115     private TestSeq _idxTestSeq = null;
116 
117     /**
118      * Group for patterns with any other kernel type.
119      */
120     private Vector[] _patternGroups;
121 
122     /**
123      * Test sequence for patterns with any other kernel type.
124      */
125     private TestSeq[] _testSeq;
126 
127 
128     /**
129      * A mapping between templates and test sequences.
130      */
131     private Hashtable _neededTemplates = new Hashtable();
132 
133     /**
134      * A mapping between named templates and Mode objects.
135      */
136     private Hashtable _namedTemplates = new Hashtable();
137 
138     /**
139      * A mapping between templates and instruction handles.
140      */
141     private Hashtable _templateIHs = new Hashtable();
142 
143     /**
144      * A mapping between templates and instruction lists.
145      */
146     private Hashtable _templateILs = new Hashtable();
147 
148     /**
149      * A reference to the pattern matching the root node.
150      */
151     private LocationPathPattern _rootPattern = null;
152 
153     /**
154      * Stores ranges of template precendences for the compilation
155      * of apply-imports (a Hashtable for historical reasons).
156      */
157     private Hashtable _importLevels = null;
158 
159     /**
160      * A mapping between key names and keys.
161      */
162     private Hashtable _keys = null;
163 
164     /**
165      * Variable index for the current node used in code generation.
166      */
167     private int _currentIndex;
168 
169     /**
170      * Creates a new Mode.
171      *
172      * @param name A textual representation of the mode's QName
173      * @param stylesheet The Stylesheet in which the mode occured
174      * @param suffix A suffix to append to the method name for this mode
175      *               (normally a sequence number - still in a String).
176      */
177     public Mode(QName name, Stylesheet stylesheet, String suffix) {
178         _name = name;
179         _stylesheet = stylesheet;
180         _methodName = APPLY_TEMPLATES + suffix;
181         _templates = new Vector();
182         _patternGroups = new Vector[32];
183     }
184 
185     /**
186      * Returns the name of the method (_not_ function) that will be
187      * compiled for this mode. Normally takes the form 'applyTemplates()'
188      * or * 'applyTemplates2()'.
189      *
190      * @return Method name for this mode
191      */
192     public String functionName() {
193         return _methodName;
194     }
195 
196     public String functionName(int min, int max) {
197         if (_importLevels == null) {
198             _importLevels = new Hashtable();
199         }
200         _importLevels.put(new Integer(max), new Integer(min));
201         return _methodName + '_' + max;
202     }
203 
204     /**
205      * Shortcut to get the class compiled for this mode (will be inlined).
206      */
207     private String getClassName() {
208         return _stylesheet.getClassName();
209     }
210 
211     public Stylesheet getStylesheet() {
212         return _stylesheet;
213     }
214 
215     public void addTemplate(Template template) {
216         _templates.addElement(template);
217     }
218 
219     private Vector quicksort(Vector templates, int p, int r) {
220         if (p < r) {
221             final int q = partition(templates, p, r);
222             quicksort(templates, p, q);
223             quicksort(templates, q + 1, r);
224         }
225         return templates;
226     }
227 
228     private int partition(Vector templates, int p, int r) {
229         final Template x = (Template)templates.elementAt(p);
230         int i = p - 1;
231         int j = r + 1;
232         while (true) {
233             while (x.compareTo((Template)templates.elementAt(--j)) > 0);
234             while (x.compareTo((Template)templates.elementAt(++i)) < 0);
235             if (i < j) {
236                 templates.set(j, templates.set(i, templates.elementAt(j)));
237             }
238             else {
239                 return j;
240             }
241         }
242     }
243 
244     /**
245      * Process all the test patterns in this mode
246      */
247     public void processPatterns(Hashtable keys) {
248         _keys = keys;
249 
250 /*
251 System.out.println("Before Sort " + _name);
252 for (int i = 0; i < _templates.size(); i++) {
253     System.out.println("name = " + ((Template)_templates.elementAt(i)).getName());
254     System.out.println("pattern = " + ((Template)_templates.elementAt(i)).getPattern());
255     System.out.println("priority = " + ((Template)_templates.elementAt(i)).getPriority());
256     System.out.println("position = " + ((Template)_templates.elementAt(i)).getPosition());
257 }
258 */
259 
260         _templates = quicksort(_templates, 0, _templates.size() - 1);
261 
262 /*
263 System.out.println("\n After Sort " + _name);
264 for (int i = 0; i < _templates.size(); i++) {
265     System.out.println("name = " + ((Template)_templates.elementAt(i)).getName());
266     System.out.println("pattern = " + ((Template)_templates.elementAt(i)).getPattern());
267     System.out.println("priority = " + ((Template)_templates.elementAt(i)).getPriority());
268     System.out.println("position = " + ((Template)_templates.elementAt(i)).getPosition());
269 }
270 */
271 
272         // Traverse all templates
273         final Enumeration templates = _templates.elements();
274         while (templates.hasMoreElements()) {
275             // Get the next template
276             final Template template = (Template)templates.nextElement();
277 
278             /*
279              * Add this template to a table of named templates if it has a name.
280              * If there are multiple templates with the same name, all but one
281              * (the one with highest priority) will be disabled.
282              */
283             if (template.isNamed() && !template.disabled()) {
284                 _namedTemplates.put(template, this);
285             }
286 
287             // Add this template to a test sequence if it has a pattern
288             final Pattern pattern = template.getPattern();
289             if (pattern != null) {
290                 flattenAlternative(pattern, template, keys);
291             }
292         }
293         prepareTestSequences();
294     }
295 
296     /**
297      * This method will break up alternative patterns (ie. unions of patterns,
298      * such as match="A/B | C/B") and add the basic patterns to their
299      * respective pattern groups.
300      */
301     private void flattenAlternative(Pattern pattern,
302                                     Template template,
303                                     Hashtable keys) {
304         // Patterns on type id() and key() are special since they do not have
305         // any kernel node type (it can be anything as long as the node is in
306         // the id's or key's index).
307         if (pattern instanceof IdKeyPattern) {
308             final IdKeyPattern idkey = (IdKeyPattern)pattern;
309             idkey.setTemplate(template);
310             if (_idxGroup == null) _idxGroup = new Vector();
311             _idxGroup.add(pattern);
312         }
313         // Alternative patterns are broken up and re-processed recursively
314         else if (pattern instanceof AlternativePattern) {
315             final AlternativePattern alt = (AlternativePattern)pattern;
316             flattenAlternative(alt.getLeft(), template, keys);
317             flattenAlternative(alt.getRight(), template, keys);
318         }
319         // Finally we have a pattern that can be added to a test sequence!
320         else if (pattern instanceof LocationPathPattern) {
321             final LocationPathPattern lpp = (LocationPathPattern)pattern;
322             lpp.setTemplate(template);
323             addPatternToGroup(lpp);
324         }
325     }
326 
327     /**
328      * Group patterns by NodeTests of their last Step
329      * Keep them sorted by priority within group
330      */
331     private void addPatternToGroup(final LocationPathPattern lpp) {
332         // id() and key()-type patterns do not have a kernel type
333         if (lpp instanceof IdKeyPattern) {
334             addPattern(-1, lpp);
335         }
336         // Otherwise get the kernel pattern from the LPP
337         else {
338             // kernel pattern is the last (maybe only) Step
339             final StepPattern kernel = lpp.getKernelPattern();
340             if (kernel != null) {
341                 addPattern(kernel.getNodeType(), lpp);
342             }
343             else if (_rootPattern == null ||
344                      lpp.noSmallerThan(_rootPattern)) {
345                 _rootPattern = lpp;
346             }
347         }
348     }
349 
350     /**
351      * Adds a pattern to a pattern group
352      */
353     private void addPattern(int kernelType, LocationPathPattern pattern) {
354         // Make sure the array of pattern groups is long enough
355         final int oldLength = _patternGroups.length;
356         if (kernelType >= oldLength) {
357             Vector[] newGroups = new Vector[kernelType * 2];
358             System.arraycopy(_patternGroups, 0, newGroups, 0, oldLength);
359             _patternGroups = newGroups;
360         }
361 
362         // Find the vector to put this pattern into
363         Vector patterns;
364 
365         if (kernelType == DOM.NO_TYPE) {
366             if (pattern.getAxis() == Axis.ATTRIBUTE) {
367                 patterns = (_attribNodeGroup == null) ?
368                     (_attribNodeGroup = new Vector(2)) : _attribNodeGroup;
369             }
370             else {
371                 patterns = (_childNodeGroup == null) ?
372                     (_childNodeGroup = new Vector(2)) : _childNodeGroup;
373             }
374         }
375         else {
376             patterns = (_patternGroups[kernelType] == null) ?
377                 (_patternGroups[kernelType] = new Vector(2)) :
378                 _patternGroups[kernelType];
379         }
380 
381         if (patterns.size() == 0) {
382             patterns.addElement(pattern);
383         }
384         else {
385             boolean inserted = false;
386             for (int i = 0; i < patterns.size(); i++) {
387                 final LocationPathPattern lppToCompare =
388                     (LocationPathPattern)patterns.elementAt(i);
389 
390                 if (pattern.noSmallerThan(lppToCompare)) {
391                     inserted = true;
392                     patterns.insertElementAt(pattern, i);
393                     break;
394                 }
395             }
396             if (inserted == false) {
397                 patterns.addElement(pattern);
398             }
399         }
400     }
401 
402     /**
403      * Complete test sequences of a given type by adding all patterns
404      * from a given group.
405      */
406     private void completeTestSequences(int nodeType, Vector patterns) {
407         if (patterns != null) {
408             if (_patternGroups[nodeType] == null) {
409                 _patternGroups[nodeType] = patterns;
410             }
411             else {
412                 final int m = patterns.size();
413                 for (int j = 0; j < m; j++) {
414                     addPattern(nodeType,
415                         (LocationPathPattern) patterns.elementAt(j));
416                 }
417             }
418         }
419     }
420 
421     /**
422      * Build test sequences. The first step is to complete the test sequences
423      * by including patterns of "*" and "node()" kernel to all element test
424      * sequences, and of "@*" to all attribute test sequences.
425      */
426     private void prepareTestSequences() {
427         final Vector starGroup = _patternGroups[DTM.ELEMENT_NODE];
428         final Vector atStarGroup = _patternGroups[DTM.ATTRIBUTE_NODE];
429 
430         // Complete test sequence for "text()" with "child::node()"
431         completeTestSequences(DTM.TEXT_NODE, _childNodeGroup);
432 
433         // Complete test sequence for "*" with "child::node()"
434         completeTestSequences(DTM.ELEMENT_NODE, _childNodeGroup);
435 
436         // Complete test sequence for "pi()" with "child::node()"
437         completeTestSequences(DTM.PROCESSING_INSTRUCTION_NODE, _childNodeGroup);
438 
439         // Complete test sequence for "comment()" with "child::node()"
440         completeTestSequences(DTM.COMMENT_NODE, _childNodeGroup);
441 
442         // Complete test sequence for "@*" with "attribute::node()"
443         completeTestSequences(DTM.ATTRIBUTE_NODE, _attribNodeGroup);
444 
445         final Vector names = _stylesheet.getXSLTC().getNamesIndex();
446         if (starGroup != null || atStarGroup != null ||
447             _childNodeGroup != null || _attribNodeGroup != null)
448         {
449             final int n = _patternGroups.length;
450 
451             // Complete test sequence for user-defined types
452             for (int i = DTM.NTYPES; i < n; i++) {
453                 if (_patternGroups[i] == null) continue;
454 
455                 final String name = (String) names.elementAt(i - DTM.NTYPES);
456 
457                 if (isAttributeName(name)) {
458                     // If an attribute then copy "@*" to its test sequence
459                     completeTestSequences(i, atStarGroup);
460 
461                     // And also copy "attribute::node()" to its test sequence
462                     completeTestSequences(i, _attribNodeGroup);
463                 }
464                 else {
465                     // If an element then copy "*" to its test sequence
466                     completeTestSequences(i, starGroup);
467 
468                     // And also copy "child::node()" to its test sequence
469                     completeTestSequences(i, _childNodeGroup);
470                 }
471             }
472         }
473 
474         _testSeq = new TestSeq[DTM.NTYPES + names.size()];
475 
476         final int n = _patternGroups.length;
477         for (int i = 0; i < n; i++) {
478             final Vector patterns = _patternGroups[i];
479             if (patterns != null) {
480                 final TestSeq testSeq = new TestSeq(patterns, i, this);
481 // System.out.println("testSeq[" + i + "] = " + testSeq);
482                 testSeq.reduce();
483                 _testSeq[i] = testSeq;
484                 testSeq.findTemplates(_neededTemplates);
485             }
486         }
487 
488         if (_childNodeGroup != null && _childNodeGroup.size() > 0) {
489             _childNodeTestSeq = new TestSeq(_childNodeGroup, -1, this);
490             _childNodeTestSeq.reduce();
491             _childNodeTestSeq.findTemplates(_neededTemplates);
492         }
493 
494 /*
495         if (_attribNodeGroup != null && _attribNodeGroup.size() > 0) {
496             _attribNodeTestSeq = new TestSeq(_attribNodeGroup, -1, this);
497             _attribNodeTestSeq.reduce();
498             _attribNodeTestSeq.findTemplates(_neededTemplates);
499         }
500 */
501 
502         if (_idxGroup != null && _idxGroup.size() > 0) {
503             _idxTestSeq = new TestSeq(_idxGroup, this);
504             _idxTestSeq.reduce();
505             _idxTestSeq.findTemplates(_neededTemplates);
506         }
507 
508         if (_rootPattern != null) {
509             // doesn't matter what is 'put', only key matters
510             _neededTemplates.put(_rootPattern.getTemplate(), this);
511         }
512     }
513 
514     private void compileNamedTemplate(Template template,
515                                       ClassGenerator classGen) {
516         final ConstantPoolGen cpg = classGen.getConstantPool();
517         final InstructionList il = new InstructionList();
518         String methodName = Util.escape(template.getName().toString());
519 
520         int numParams = 0;
521         if (template.isSimpleNamedTemplate()) {
522             Vector parameters = template.getParameters();
523             numParams = parameters.size();
524         }
525 
526         // Initialize the types and names arrays for the NamedMethodGenerator.
527         com.sun.org.apache.bcel.internal.generic.Type[] types =
528             new com.sun.org.apache.bcel.internal.generic.Type[4 + numParams];
529         String[] names = new String[4 + numParams];
530         types[0] = Util.getJCRefType(DOM_INTF_SIG);
531         types[1] = Util.getJCRefType(NODE_ITERATOR_SIG);
532         types[2] = Util.getJCRefType(TRANSLET_OUTPUT_SIG);
533         types[3] = com.sun.org.apache.bcel.internal.generic.Type.INT;
534         names[0] = DOCUMENT_PNAME;
535         names[1] = ITERATOR_PNAME;
536         names[2] = TRANSLET_OUTPUT_PNAME;
537         names[3] = NODE_PNAME;
538 
539         // For simple named templates, the signature of the generated method
540         // is not fixed. It depends on the number of parameters declared in the
541         // template.
542         for (int i = 4; i < 4 + numParams; i++) {
543             types[i] = Util.getJCRefType(OBJECT_SIG);
544             names[i] = "param" + String.valueOf(i-4);
545         }
546 
547         NamedMethodGenerator methodGen =
548                 new NamedMethodGenerator(ACC_PUBLIC,
549                                      com.sun.org.apache.bcel.internal.generic.Type.VOID,
550                                      types, names, methodName,
551                                      getClassName(), il, cpg);
552 
553         il.append(template.compile(classGen, methodGen));
554         il.append(RETURN);
555 
556         classGen.addMethod(methodGen);
557     }
558 
559     private void compileTemplates(ClassGenerator classGen,
560                                   MethodGenerator methodGen,
561                                   InstructionHandle next)
562     {
563         Enumeration templates = _namedTemplates.keys();
564         while (templates.hasMoreElements()) {
565             final Template template = (Template)templates.nextElement();
566             compileNamedTemplate(template, classGen);
567         }
568 
569         templates = _neededTemplates.keys();
570         while (templates.hasMoreElements()) {
571             final Template template = (Template)templates.nextElement();
572             if (template.hasContents()) {
573                 // !!! TODO templates both named and matched
574                 InstructionList til = template.compile(classGen, methodGen);
575                 til.append(new GOTO_W(next));
576                 _templateILs.put(template, til);
577                 _templateIHs.put(template, til.getStart());
578             }
579             else {
580                 // empty template
581                 _templateIHs.put(template, next);
582             }
583         }
584     }
585 
586     private void appendTemplateCode(InstructionList body) {
587         final Enumeration templates = _neededTemplates.keys();
588         while (templates.hasMoreElements()) {
589             final Object iList =
590                 _templateILs.get(templates.nextElement());
591             if (iList != null) {
592                 body.append((InstructionList)iList);
593             }
594         }
595     }
596 
597     private void appendTestSequences(InstructionList body) {
598         final int n = _testSeq.length;
599         for (int i = 0; i < n; i++) {
600             final TestSeq testSeq = _testSeq[i];
601             if (testSeq != null) {
602                 InstructionList il = testSeq.getInstructionList();
603                 if (il != null)
604                     body.append(il);
605                 // else trivial TestSeq
606             }
607         }
608     }
609 
610     public static void compileGetChildren(ClassGenerator classGen,
611                                           MethodGenerator methodGen,
612                                           int node) {
613         final ConstantPoolGen cpg = classGen.getConstantPool();
614         final InstructionList il = methodGen.getInstructionList();
615         final int git = cpg.addInterfaceMethodref(DOM_INTF,
616                                                   GET_CHILDREN,
617                                                   GET_CHILDREN_SIG);
618         il.append(methodGen.loadDOM());
619         il.append(new ILOAD(node));
620         il.append(new INVOKEINTERFACE(git, 2));
621     }
622 
623     /**
624      * Compiles the default handling for DOM elements: traverse all children
625      */
626     private InstructionList compileDefaultRecursion(ClassGenerator classGen,
627                                                     MethodGenerator methodGen,
628                                                     InstructionHandle next) {
629         final ConstantPoolGen cpg = classGen.getConstantPool();
630         final InstructionList il = new InstructionList();
631         final String applyTemplatesSig = classGen.getApplyTemplatesSig();
632         final int git = cpg.addInterfaceMethodref(DOM_INTF,
633                                                   GET_CHILDREN,
634                                                   GET_CHILDREN_SIG);
635         final int applyTemplates = cpg.addMethodref(getClassName(),
636                                                     functionName(),
637                                                     applyTemplatesSig);
638         il.append(classGen.loadTranslet());
639         il.append(methodGen.loadDOM());
640 
641         il.append(methodGen.loadDOM());
642         il.append(new ILOAD(_currentIndex));
643         il.append(new INVOKEINTERFACE(git, 2));
644         il.append(methodGen.loadHandler());
645         il.append(new INVOKEVIRTUAL(applyTemplates));
646         il.append(new GOTO_W(next));
647         return il;
648     }
649 
650     /**
651      * Compiles the default action for DOM text nodes and attribute nodes:
652      * output the node's text value
653      */
654     private InstructionList compileDefaultText(ClassGenerator classGen,
655                                                MethodGenerator methodGen,
656                                                InstructionHandle next) {
657         final ConstantPoolGen cpg = classGen.getConstantPool();
658         final InstructionList il = new InstructionList();
659 
660         final int chars = cpg.addInterfaceMethodref(DOM_INTF,
661                                                     CHARACTERS,
662                                                     CHARACTERS_SIG);
663         il.append(methodGen.loadDOM());
664         il.append(new ILOAD(_currentIndex));
665         il.append(methodGen.loadHandler());
666         il.append(new INVOKEINTERFACE(chars, 3));
667         il.append(new GOTO_W(next));
668         return il;
669     }
670 
671     private InstructionList compileNamespaces(ClassGenerator classGen,
672                                               MethodGenerator methodGen,
673                                               boolean[] isNamespace,
674                                               boolean[] isAttribute,
675                                               boolean attrFlag,
676                                               InstructionHandle defaultTarget) {
677         final XSLTC xsltc = classGen.getParser().getXSLTC();
678         final ConstantPoolGen cpg = classGen.getConstantPool();
679 
680         // Append switch() statement - namespace test dispatch loop
681         final Vector namespaces = xsltc.getNamespaceIndex();
682         final Vector names = xsltc.getNamesIndex();
683         final int namespaceCount = namespaces.size() + 1;
684         final int namesCount = names.size();
685 
686         final InstructionList il = new InstructionList();
687         final int[] types = new int[namespaceCount];
688         final InstructionHandle[] targets = new InstructionHandle[types.length];
689 
690         if (namespaceCount > 0) {
691             boolean compiled = false;
692 
693             // Initialize targets for namespace() switch statement
694             for (int i = 0; i < namespaceCount; i++) {
695                 targets[i] = defaultTarget;
696                 types[i] = i;
697             }
698 
699             // Add test sequences for known namespace types
700             for (int i = DTM.NTYPES; i < (DTM.NTYPES+namesCount); i++) {
701                 if ((isNamespace[i]) && (isAttribute[i] == attrFlag)) {
702                     String name = (String)names.elementAt(i-DTM.NTYPES);
703                     String namespace = name.substring(0,name.lastIndexOf(':'));
704                     final int type = xsltc.registerNamespace(namespace);
705 
706                     if ((i < _testSeq.length) &&
707                         (_testSeq[i] != null)) {
708                         targets[type] =
709                             (_testSeq[i]).compile(classGen,
710                                                        methodGen,
711                                                        defaultTarget);
712                         compiled = true;
713                     }
714                 }
715             }
716 
717             // Return "null" if no test sequences were compiled
718             if (!compiled) return(null);
719 
720             // Append first code in applyTemplates() - get type of current node
721             final int getNS = cpg.addInterfaceMethodref(DOM_INTF,
722                                                         "getNamespaceType",
723                                                         "(I)I");
724             il.append(methodGen.loadDOM());
725             il.append(new ILOAD(_currentIndex));
726             il.append(new INVOKEINTERFACE(getNS, 2));
727             il.append(new SWITCH(types, targets, defaultTarget));
728             return(il);
729         }
730         else {
731             return(null);
732         }
733     }
734 
735    /**
736      * Compiles the applyTemplates() method and adds it to the translet.
737      * This is the main dispatch method.
738      */
739     public void compileApplyTemplates(ClassGenerator classGen) {
740         final XSLTC xsltc = classGen.getParser().getXSLTC();
741         final ConstantPoolGen cpg = classGen.getConstantPool();
742         final Vector names = xsltc.getNamesIndex();
743 
744         // Create the applyTemplates() method
745         final com.sun.org.apache.bcel.internal.generic.Type[] argTypes =
746             new com.sun.org.apache.bcel.internal.generic.Type[3];
747         argTypes[0] = Util.getJCRefType(DOM_INTF_SIG);
748         argTypes[1] = Util.getJCRefType(NODE_ITERATOR_SIG);
749         argTypes[2] = Util.getJCRefType(TRANSLET_OUTPUT_SIG);
750 
751         final String[] argNames = new String[3];
752         argNames[0] = DOCUMENT_PNAME;
753         argNames[1] = ITERATOR_PNAME;
754         argNames[2] = TRANSLET_OUTPUT_PNAME;
755 
756         final InstructionList mainIL = new InstructionList();
757         final MethodGenerator methodGen =
758             new MethodGenerator(ACC_PUBLIC | ACC_FINAL,
759                                 com.sun.org.apache.bcel.internal.generic.Type.VOID,
760                                 argTypes, argNames, functionName(),
761                                 getClassName(), mainIL,
762                                 classGen.getConstantPool());
763         methodGen.addException("com.sun.org.apache.xalan.internal.xsltc.TransletException");
764         // Insert an extra NOP just to keep "current" from appearing as if it
765         // has a value before the start of the loop.
766         mainIL.append(NOP);
767 
768 
769         // Create a local variable to hold the current node
770         final LocalVariableGen current;
771         current = methodGen.addLocalVariable2("current",
772                                               com.sun.org.apache.bcel.internal.generic.Type.INT,
773                                               null);
774         _currentIndex = current.getIndex();
775 
776         // Create the "body" instruction list that will eventually hold the
777         // code for the entire method (other ILs will be appended).
778         final InstructionList body = new InstructionList();
779         body.append(NOP);
780 
781         // Create an instruction list that contains the default next-node
782         // iteration
783         final InstructionList ilLoop = new InstructionList();
784         ilLoop.append(methodGen.loadIterator());
785         ilLoop.append(methodGen.nextNode());
786         ilLoop.append(DUP);
787         ilLoop.append(new ISTORE(_currentIndex));
788 
789         // The body of this code can get very large - large than can be handled
790         // by a single IFNE(body.getStart()) instruction - need workaround:
791         final BranchHandle ifeq = ilLoop.append(new IFLT(null));
792         final BranchHandle loop = ilLoop.append(new GOTO_W(null));
793         ifeq.setTarget(ilLoop.append(RETURN));  // applyTemplates() ends here!
794         final InstructionHandle ihLoop = ilLoop.getStart();
795 
796         current.setStart(mainIL.append(new GOTO_W(ihLoop)));
797 
798         // Live range of "current" ends at end of loop
799         current.setEnd(loop);
800 
801         // Compile default handling of elements (traverse children)
802         InstructionList ilRecurse =
803             compileDefaultRecursion(classGen, methodGen, ihLoop);
804         InstructionHandle ihRecurse = ilRecurse.getStart();
805 
806         // Compile default handling of text/attribute nodes (output text)
807         InstructionList ilText =
808             compileDefaultText(classGen, methodGen, ihLoop);
809         InstructionHandle ihText = ilText.getStart();
810 
811         // Distinguish attribute/element/namespace tests for further processing
812         final int[] types = new int[DTM.NTYPES + names.size()];
813         for (int i = 0; i < types.length; i++) {
814             types[i] = i;
815         }
816 
817         // Initialize isAttribute[] and isNamespace[] arrays
818         final boolean[] isAttribute = new boolean[types.length];
819         final boolean[] isNamespace = new boolean[types.length];
820         for (int i = 0; i < names.size(); i++) {
821             final String name = (String)names.elementAt(i);
822             isAttribute[i + DTM.NTYPES] = isAttributeName(name);
823             isNamespace[i + DTM.NTYPES] = isNamespaceName(name);
824         }
825 
826         // Compile all templates - regardless of pattern type
827         compileTemplates(classGen, methodGen, ihLoop);
828 
829         // Handle template with explicit "*" pattern
830         final TestSeq elemTest = _testSeq[DTM.ELEMENT_NODE];
831         InstructionHandle ihElem = ihRecurse;
832         if (elemTest != null)
833             ihElem = elemTest.compile(classGen, methodGen, ihRecurse);
834 
835         // Handle template with explicit "@*" pattern
836         final TestSeq attrTest = _testSeq[DTM.ATTRIBUTE_NODE];
837         InstructionHandle ihAttr = ihText;
838         if (attrTest != null)
839             ihAttr = attrTest.compile(classGen, methodGen, ihAttr);
840 
841         // Do tests for id() and key() patterns first
842         InstructionList ilKey = null;
843         if (_idxTestSeq != null) {
844             loop.setTarget(_idxTestSeq.compile(classGen, methodGen, body.getStart()));
845             ilKey = _idxTestSeq.getInstructionList();
846         }
847         else {
848             loop.setTarget(body.getStart());
849         }
850 
851         // If there is a match on node() we need to replace ihElem
852         // and ihText if the priority of node() is higher
853         if (_childNodeTestSeq != null) {
854             // Compare priorities of node() and "*"
855             double nodePrio = _childNodeTestSeq.getPriority();
856             int    nodePos  = _childNodeTestSeq.getPosition();
857             double elemPrio = (0 - Double.MAX_VALUE);
858             int    elemPos  = Integer.MIN_VALUE;
859 
860             if (elemTest != null) {
861                 elemPrio = elemTest.getPriority();
862                 elemPos  = elemTest.getPosition();
863             }
864             if (elemPrio == Double.NaN || elemPrio < nodePrio ||
865                 (elemPrio == nodePrio && elemPos < nodePos))
866             {
867                 ihElem = _childNodeTestSeq.compile(classGen, methodGen, ihLoop);
868             }
869 
870             // Compare priorities of node() and text()
871             final TestSeq textTest = _testSeq[DTM.TEXT_NODE];
872             double textPrio = (0 - Double.MAX_VALUE);
873             int    textPos  = Integer.MIN_VALUE;
874 
875             if (textTest != null) {
876                 textPrio = textTest.getPriority();
877                 textPos  = textTest.getPosition();
878             }
879             if (textPrio == Double.NaN || textPrio < nodePrio ||
880                 (textPrio == nodePrio && textPos < nodePos))
881             {
882                 ihText = _childNodeTestSeq.compile(classGen, methodGen, ihLoop);
883                 _testSeq[DTM.TEXT_NODE] = _childNodeTestSeq;
884             }
885         }
886 
887         // Handle templates with "ns:*" pattern
888         InstructionHandle elemNamespaceHandle = ihElem;
889         InstructionList nsElem = compileNamespaces(classGen, methodGen,
890                                                    isNamespace, isAttribute,
891                                                    false, ihElem);
892         if (nsElem != null) elemNamespaceHandle = nsElem.getStart();
893 
894         // Handle templates with "ns:@*" pattern
895         InstructionHandle attrNamespaceHandle = ihAttr;
896         InstructionList nsAttr = compileNamespaces(classGen, methodGen,
897                                                    isNamespace, isAttribute,
898                                                    true, ihAttr);
899         if (nsAttr != null) attrNamespaceHandle = nsAttr.getStart();
900 
901         // Handle templates with "ns:elem" or "ns:@attr" pattern
902         final InstructionHandle[] targets = new InstructionHandle[types.length];
903         for (int i = DTM.NTYPES; i < targets.length; i++) {
904             final TestSeq testSeq = _testSeq[i];
905             // Jump straight to namespace tests ?
906             if (isNamespace[i]) {
907                 if (isAttribute[i])
908                     targets[i] = attrNamespaceHandle;
909                 else
910                     targets[i] = elemNamespaceHandle;
911             }
912             // Test first, then jump to namespace tests
913             else if (testSeq != null) {
914                 if (isAttribute[i])
915                     targets[i] = testSeq.compile(classGen, methodGen,
916                                                  attrNamespaceHandle);
917                 else
918                     targets[i] = testSeq.compile(classGen, methodGen,
919                                                  elemNamespaceHandle);
920             }
921             else {
922                 targets[i] = ihLoop;
923             }
924         }
925 
926 
927         // Handle pattern with match on root node - default: traverse children
928         targets[DTM.ROOT_NODE] = _rootPattern != null
929             ? getTemplateInstructionHandle(_rootPattern.getTemplate())
930             : ihRecurse;
931 
932         // Handle pattern with match on root node - default: traverse children
933         targets[DTM.DOCUMENT_NODE] = _rootPattern != null
934             ? getTemplateInstructionHandle(_rootPattern.getTemplate())
935             : ihRecurse;
936 
937         // Handle any pattern with match on text nodes - default: output text
938         targets[DTM.TEXT_NODE] = _testSeq[DTM.TEXT_NODE] != null
939             ? _testSeq[DTM.TEXT_NODE].compile(classGen, methodGen, ihText)
940             : ihText;
941 
942         // This DOM-type is not in use - default: process next node
943         targets[DTM.NAMESPACE_NODE] = ihLoop;
944 
945         // Match unknown element in DOM - default: check for namespace match
946         targets[DTM.ELEMENT_NODE] = elemNamespaceHandle;
947 
948         // Match unknown attribute in DOM - default: check for namespace match
949         targets[DTM.ATTRIBUTE_NODE] = attrNamespaceHandle;
950 
951         // Match on processing instruction - default: process next node
952         InstructionHandle ihPI = ihLoop;
953         if (_childNodeTestSeq != null) ihPI = ihElem;
954         if (_testSeq[DTM.PROCESSING_INSTRUCTION_NODE] != null)
955             targets[DTM.PROCESSING_INSTRUCTION_NODE] =
956                 _testSeq[DTM.PROCESSING_INSTRUCTION_NODE].
957                 compile(classGen, methodGen, ihPI);
958         else
959             targets[DTM.PROCESSING_INSTRUCTION_NODE] = ihPI;
960 
961         // Match on comments - default: process next node
962         InstructionHandle ihComment = ihLoop;
963         if (_childNodeTestSeq != null) ihComment = ihElem;
964         targets[DTM.COMMENT_NODE] = _testSeq[DTM.COMMENT_NODE] != null
965             ? _testSeq[DTM.COMMENT_NODE].compile(classGen, methodGen, ihComment)
966             : ihComment;
967 
968             // This DOM-type is not in use - default: process next node
969         targets[DTM.CDATA_SECTION_NODE] = ihLoop;
970 
971         // This DOM-type is not in use - default: process next node
972         targets[DTM.DOCUMENT_FRAGMENT_NODE] = ihLoop;
973 
974         // This DOM-type is not in use - default: process next node
975         targets[DTM.DOCUMENT_TYPE_NODE] = ihLoop;
976 
977         // This DOM-type is not in use - default: process next node
978         targets[DTM.ENTITY_NODE] = ihLoop;
979 
980         // This DOM-type is not in use - default: process next node
981         targets[DTM.ENTITY_REFERENCE_NODE] = ihLoop;
982 
983         // This DOM-type is not in use - default: process next node
984         targets[DTM.NOTATION_NODE] = ihLoop;
985 
986 
987         // Now compile test sequences for various match patterns:
988         for (int i = DTM.NTYPES; i < targets.length; i++) {
989             final TestSeq testSeq = _testSeq[i];
990             // Jump straight to namespace tests ?
991             if ((testSeq == null) || (isNamespace[i])) {
992                 if (isAttribute[i])
993                     targets[i] = attrNamespaceHandle;
994                 else
995                     targets[i] = elemNamespaceHandle;
996             }
997             // Match on node type
998             else {
999                 if (isAttribute[i])
1000                     targets[i] = testSeq.compile(classGen, methodGen,
1001                                                  attrNamespaceHandle);
1002                 else
1003                     targets[i] = testSeq.compile(classGen, methodGen,
1004                                                  elemNamespaceHandle);
1005             }
1006         }
1007 
1008         if (ilKey != null) body.insert(ilKey);
1009 
1010         // Append first code in applyTemplates() - get type of current node
1011         final int getType = cpg.addInterfaceMethodref(DOM_INTF,
1012                                                       "getExpandedTypeID",
1013                                                       "(I)I");
1014         body.append(methodGen.loadDOM());
1015         body.append(new ILOAD(_currentIndex));
1016         body.append(new INVOKEINTERFACE(getType, 2));
1017 
1018         // Append switch() statement - main dispatch loop in applyTemplates()
1019         InstructionHandle disp = body.append(new SWITCH(types, targets, ihLoop));
1020 
1021         // Append all the "case:" statements
1022         appendTestSequences(body);
1023         // Append the actual template code
1024         appendTemplateCode(body);
1025 
1026         // Append NS:* node tests (if any)
1027         if (nsElem != null) body.append(nsElem);
1028         // Append NS:@* node tests (if any)
1029         if (nsAttr != null) body.append(nsAttr);
1030 
1031         // Append default action for element and root nodes
1032         body.append(ilRecurse);
1033         // Append default action for text and attribute nodes
1034         body.append(ilText);
1035 
1036         // putting together constituent instruction lists
1037         mainIL.append(body);
1038         // fall through to ilLoop
1039         mainIL.append(ilLoop);
1040 
1041         peepHoleOptimization(methodGen);
1042         classGen.addMethod(methodGen);
1043 
1044         // Compile method(s) for <xsl:apply-imports/> for this mode
1045         if (_importLevels != null) {
1046             Enumeration levels = _importLevels.keys();
1047             while (levels.hasMoreElements()) {
1048                 Integer max = (Integer)levels.nextElement();
1049                 Integer min = (Integer)_importLevels.get(max);
1050                 compileApplyImports(classGen, min.intValue(), max.intValue());
1051             }
1052         }
1053     }
1054 
1055     private void compileTemplateCalls(ClassGenerator classGen,
1056                                       MethodGenerator methodGen,
1057                                       InstructionHandle next, int min, int max){
1058         Enumeration templates = _neededTemplates.keys();
1059         while (templates.hasMoreElements()) {
1060             final Template template = (Template)templates.nextElement();
1061             final int prec = template.getImportPrecedence();
1062             if ((prec >= min) && (prec < max)) {
1063                 if (template.hasContents()) {
1064                     InstructionList til = template.compile(classGen, methodGen);
1065                     til.append(new GOTO_W(next));
1066                     _templateILs.put(template, til);
1067                     _templateIHs.put(template, til.getStart());
1068                 }
1069                 else {
1070                     // empty template
1071                     _templateIHs.put(template, next);
1072                 }
1073             }
1074         }
1075     }
1076 
1077 
1078     public void compileApplyImports(ClassGenerator classGen, int min, int max) {
1079         final XSLTC xsltc = classGen.getParser().getXSLTC();
1080         final ConstantPoolGen cpg = classGen.getConstantPool();
1081         final Vector names      = xsltc.getNamesIndex();
1082 
1083         // Clear some datastructures
1084         _namedTemplates = new Hashtable();
1085         _neededTemplates = new Hashtable();
1086         _templateIHs = new Hashtable();
1087         _templateILs = new Hashtable();
1088         _patternGroups = new Vector[32];
1089         _rootPattern = null;
1090 
1091         // IMPORTANT: Save orignal & complete set of templates!!!!
1092         Vector oldTemplates = _templates;
1093 
1094         // Gather templates that are within the scope of this import
1095         _templates = new Vector();
1096         final Enumeration templates = oldTemplates.elements();
1097         while (templates.hasMoreElements()) {
1098             final Template template = (Template)templates.nextElement();
1099             final int prec = template.getImportPrecedence();
1100             if ((prec >= min) && (prec < max)) addTemplate(template);
1101         }
1102 
1103         // Process all patterns from those templates
1104         processPatterns(_keys);
1105 
1106         // Create the applyTemplates() method
1107         final com.sun.org.apache.bcel.internal.generic.Type[] argTypes =
1108             new com.sun.org.apache.bcel.internal.generic.Type[4];
1109         argTypes[0] = Util.getJCRefType(DOM_INTF_SIG);
1110         argTypes[1] = Util.getJCRefType(NODE_ITERATOR_SIG);
1111         argTypes[2] = Util.getJCRefType(TRANSLET_OUTPUT_SIG);
1112         argTypes[3] = com.sun.org.apache.bcel.internal.generic.Type.INT;
1113 
1114         final String[] argNames = new String[4];
1115         argNames[0] = DOCUMENT_PNAME;
1116         argNames[1] = ITERATOR_PNAME;
1117         argNames[2] = TRANSLET_OUTPUT_PNAME;
1118         argNames[3] = NODE_PNAME;
1119 
1120         final InstructionList mainIL = new InstructionList();
1121         final MethodGenerator methodGen =
1122             new MethodGenerator(ACC_PUBLIC | ACC_FINAL,
1123                                 com.sun.org.apache.bcel.internal.generic.Type.VOID,
1124                                 argTypes, argNames, functionName()+'_'+max,
1125                                 getClassName(), mainIL,
1126                                 classGen.getConstantPool());
1127         methodGen.addException("com.sun.org.apache.xalan.internal.xsltc.TransletException");
1128 
1129         // Create the local variable to hold the current node
1130         final LocalVariableGen current;
1131         current = methodGen.addLocalVariable2("current",
1132                                               com.sun.org.apache.bcel.internal.generic.Type.INT,
1133                                               null);
1134         _currentIndex = current.getIndex();
1135 
1136         mainIL.append(new ILOAD(methodGen.getLocalIndex(NODE_PNAME)));
1137         current.setStart(mainIL.append(new ISTORE(_currentIndex)));
1138 
1139         // Create the "body" instruction list that will eventually hold the
1140         // code for the entire method (other ILs will be appended).
1141         final InstructionList body = new InstructionList();
1142         body.append(NOP);
1143 
1144         // Create an instruction list that contains the default next-node
1145         // iteration
1146         final InstructionList ilLoop = new InstructionList();
1147         ilLoop.append(RETURN);
1148         final InstructionHandle ihLoop = ilLoop.getStart();
1149 
1150         // Compile default handling of elements (traverse children)
1151         InstructionList ilRecurse =
1152             compileDefaultRecursion(classGen, methodGen, ihLoop);
1153         InstructionHandle ihRecurse = ilRecurse.getStart();
1154 
1155         // Compile default handling of text/attribute nodes (output text)
1156         InstructionList ilText =
1157             compileDefaultText(classGen, methodGen, ihLoop);
1158         InstructionHandle ihText = ilText.getStart();
1159 
1160         // Distinguish attribute/element/namespace tests for further processing
1161         final int[] types = new int[DTM.NTYPES + names.size()];
1162         for (int i = 0; i < types.length; i++) {
1163             types[i] = i;
1164         }
1165 
1166         final boolean[] isAttribute = new boolean[types.length];
1167         final boolean[] isNamespace = new boolean[types.length];
1168         for (int i = 0; i < names.size(); i++) {
1169             final String name = (String)names.elementAt(i);
1170             isAttribute[i+DTM.NTYPES] = isAttributeName(name);
1171             isNamespace[i+DTM.NTYPES] = isNamespaceName(name);
1172         }
1173 
1174         // Compile all templates - regardless of pattern type
1175         compileTemplateCalls(classGen, methodGen, ihLoop, min, max);
1176 
1177         // Handle template with explicit "*" pattern
1178         final TestSeq elemTest = _testSeq[DTM.ELEMENT_NODE];
1179         InstructionHandle ihElem = ihRecurse;
1180         if (elemTest != null) {
1181             ihElem = elemTest.compile(classGen, methodGen, ihLoop);
1182         }
1183 
1184         // Handle template with explicit "@*" pattern
1185         final TestSeq attrTest = _testSeq[DTM.ATTRIBUTE_NODE];
1186         InstructionHandle ihAttr = ihLoop;
1187         if (attrTest != null) {
1188             ihAttr = attrTest.compile(classGen, methodGen, ihAttr);
1189         }
1190 
1191         // Do tests for id() and key() patterns first
1192         InstructionList ilKey = null;
1193         if (_idxTestSeq != null) {
1194             ilKey = _idxTestSeq.getInstructionList();
1195         }
1196 
1197         // If there is a match on node() we need to replace ihElem
1198         // and ihText if the priority of node() is higher
1199         if (_childNodeTestSeq != null) {
1200             // Compare priorities of node() and "*"
1201             double nodePrio = _childNodeTestSeq.getPriority();
1202             int    nodePos  = _childNodeTestSeq.getPosition();
1203             double elemPrio = (0 - Double.MAX_VALUE);
1204             int    elemPos  = Integer.MIN_VALUE;
1205 
1206             if (elemTest != null) {
1207                 elemPrio = elemTest.getPriority();
1208                 elemPos  = elemTest.getPosition();
1209             }
1210 
1211             if (elemPrio == Double.NaN || elemPrio < nodePrio ||
1212                 (elemPrio == nodePrio && elemPos < nodePos))
1213             {
1214                 ihElem = _childNodeTestSeq.compile(classGen, methodGen, ihLoop);
1215             }
1216 
1217             // Compare priorities of node() and text()
1218             final TestSeq textTest = _testSeq[DTM.TEXT_NODE];
1219             double textPrio = (0 - Double.MAX_VALUE);
1220             int    textPos  = Integer.MIN_VALUE;
1221 
1222             if (textTest != null) {
1223                 textPrio = textTest.getPriority();
1224                 textPos  = textTest.getPosition();
1225             }
1226 
1227             if (textPrio == Double.NaN || textPrio < nodePrio ||
1228                 (textPrio == nodePrio && textPos < nodePos))
1229             {
1230                 ihText = _childNodeTestSeq.compile(classGen, methodGen, ihLoop);
1231                 _testSeq[DTM.TEXT_NODE] = _childNodeTestSeq;
1232             }
1233         }
1234 
1235         // Handle templates with "ns:*" pattern
1236         InstructionHandle elemNamespaceHandle = ihElem;
1237         InstructionList nsElem = compileNamespaces(classGen, methodGen,
1238                                                    isNamespace, isAttribute,
1239                                                    false, ihElem);
1240         if (nsElem != null) elemNamespaceHandle = nsElem.getStart();
1241 
1242         // Handle templates with "ns:@*" pattern
1243         InstructionList nsAttr = compileNamespaces(classGen, methodGen,
1244                                                    isNamespace, isAttribute,
1245                                                    true, ihAttr);
1246         InstructionHandle attrNamespaceHandle = ihAttr;
1247         if (nsAttr != null) attrNamespaceHandle = nsAttr.getStart();
1248 
1249         // Handle templates with "ns:elem" or "ns:@attr" pattern
1250         final InstructionHandle[] targets = new InstructionHandle[types.length];
1251         for (int i = DTM.NTYPES; i < targets.length; i++) {
1252             final TestSeq testSeq = _testSeq[i];
1253             // Jump straight to namespace tests ?
1254             if (isNamespace[i]) {
1255                 if (isAttribute[i])
1256                     targets[i] = attrNamespaceHandle;
1257                 else
1258                     targets[i] = elemNamespaceHandle;
1259             }
1260             // Test first, then jump to namespace tests
1261             else if (testSeq != null) {
1262                 if (isAttribute[i])
1263                     targets[i] = testSeq.compile(classGen, methodGen,
1264                                                  attrNamespaceHandle);
1265                 else
1266                     targets[i] = testSeq.compile(classGen, methodGen,
1267                                                  elemNamespaceHandle);
1268             }
1269             else {
1270                 targets[i] = ihLoop;
1271             }
1272         }
1273 
1274         // Handle pattern with match on root node - default: traverse children
1275         targets[DTM.ROOT_NODE] = _rootPattern != null
1276             ? getTemplateInstructionHandle(_rootPattern.getTemplate())
1277             : ihRecurse;
1278         // Handle pattern with match on root node - default: traverse children
1279         targets[DTM.DOCUMENT_NODE] = _rootPattern != null
1280             ? getTemplateInstructionHandle(_rootPattern.getTemplate())
1281             : ihRecurse;    // %HZ%:  Was ihLoop in XSLTC_DTM branch
1282 
1283         // Handle any pattern with match on text nodes - default: loop
1284         targets[DTM.TEXT_NODE] = _testSeq[DTM.TEXT_NODE] != null
1285             ? _testSeq[DTM.TEXT_NODE].compile(classGen, methodGen, ihText)
1286             : ihText;
1287 
1288         // This DOM-type is not in use - default: process next node
1289         targets[DTM.NAMESPACE_NODE] = ihLoop;
1290 
1291         // Match unknown element in DOM - default: check for namespace match
1292         targets[DTM.ELEMENT_NODE] = elemNamespaceHandle;
1293 
1294         // Match unknown attribute in DOM - default: check for namespace match
1295         targets[DTM.ATTRIBUTE_NODE] = attrNamespaceHandle;
1296 
1297         // Match on processing instruction - default: loop
1298         InstructionHandle ihPI = ihLoop;
1299         if (_childNodeTestSeq != null) ihPI = ihElem;
1300         if (_testSeq[DTM.PROCESSING_INSTRUCTION_NODE] != null) {
1301             targets[DTM.PROCESSING_INSTRUCTION_NODE] =
1302                 _testSeq[DTM.PROCESSING_INSTRUCTION_NODE].
1303                 compile(classGen, methodGen, ihPI);
1304         }
1305         else {
1306             targets[DTM.PROCESSING_INSTRUCTION_NODE] = ihPI;
1307         }
1308 
1309         // Match on comments - default: process next node
1310         InstructionHandle ihComment = ihLoop;
1311         if (_childNodeTestSeq != null) ihComment = ihElem;
1312         targets[DTM.COMMENT_NODE] = _testSeq[DTM.COMMENT_NODE] != null
1313             ? _testSeq[DTM.COMMENT_NODE].compile(classGen, methodGen, ihComment)
1314             : ihComment;
1315 
1316                 // This DOM-type is not in use - default: process next node
1317         targets[DTM.CDATA_SECTION_NODE] = ihLoop;
1318 
1319         // This DOM-type is not in use - default: process next node
1320         targets[DTM.DOCUMENT_FRAGMENT_NODE] = ihLoop;
1321 
1322         // This DOM-type is not in use - default: process next node
1323         targets[DTM.DOCUMENT_TYPE_NODE] = ihLoop;
1324 
1325         // This DOM-type is not in use - default: process next node
1326         targets[DTM.ENTITY_NODE] = ihLoop;
1327 
1328         // This DOM-type is not in use - default: process next node
1329         targets[DTM.ENTITY_REFERENCE_NODE] = ihLoop;
1330 
1331         // This DOM-type is not in use - default: process next node
1332         targets[DTM.NOTATION_NODE] = ihLoop;
1333 
1334 
1335 
1336         // Now compile test sequences for various match patterns:
1337         for (int i = DTM.NTYPES; i < targets.length; i++) {
1338             final TestSeq testSeq = _testSeq[i];
1339             // Jump straight to namespace tests ?
1340             if ((testSeq == null) || (isNamespace[i])) {
1341                 if (isAttribute[i])
1342                     targets[i] = attrNamespaceHandle;
1343                 else
1344                     targets[i] = elemNamespaceHandle;
1345             }
1346             // Match on node type
1347             else {
1348                 if (isAttribute[i])
1349                     targets[i] = testSeq.compile(classGen, methodGen,
1350                                                  attrNamespaceHandle);
1351                 else
1352                     targets[i] = testSeq.compile(classGen, methodGen,
1353                                                  elemNamespaceHandle);
1354             }
1355         }
1356 
1357         if (ilKey != null) body.insert(ilKey);
1358 
1359         // Append first code in applyTemplates() - get type of current node
1360         final int getType = cpg.addInterfaceMethodref(DOM_INTF,
1361                                                       "getExpandedTypeID",
1362                                                       "(I)I");
1363         body.append(methodGen.loadDOM());
1364         body.append(new ILOAD(_currentIndex));
1365         body.append(new INVOKEINTERFACE(getType, 2));
1366 
1367         // Append switch() statement - main dispatch loop in applyTemplates()
1368         InstructionHandle disp = body.append(new SWITCH(types,targets,ihLoop));
1369 
1370         // Append all the "case:" statements
1371         appendTestSequences(body);
1372         // Append the actual template code
1373         appendTemplateCode(body);
1374 
1375         // Append NS:* node tests (if any)
1376         if (nsElem != null) body.append(nsElem);
1377         // Append NS:@* node tests (if any)
1378         if (nsAttr != null) body.append(nsAttr);
1379 
1380         // Append default action for element and root nodes
1381         body.append(ilRecurse);
1382         // Append default action for text and attribute nodes
1383         body.append(ilText);
1384 
1385         // putting together constituent instruction lists
1386         mainIL.append(body);
1387 
1388         // Mark the end of the live range for the "current" variable
1389         current.setEnd(body.getEnd());
1390 
1391         // fall through to ilLoop
1392         mainIL.append(ilLoop);
1393 
1394         peepHoleOptimization(methodGen);
1395         classGen.addMethod(methodGen);
1396 
1397         // Restore original (complete) set of templates for this transformation
1398         _templates = oldTemplates;
1399     }
1400 
1401     /**
1402       * Peephole optimization.
1403       */
1404     private void peepHoleOptimization(MethodGenerator methodGen) {
1405         InstructionList il = methodGen.getInstructionList();
1406         InstructionFinder find = new InstructionFinder(il);
1407         InstructionHandle ih;
1408         String pattern;
1409 
1410         // LoadInstruction, POP => (removed)
1411         // pattern = "LoadInstruction POP";
1412         // changed to lower case - changing to all lower case although only the instruction with capital I
1413         // is creating a problem in the Turkish locale
1414         pattern = "loadinstruction pop";
1415 
1416         for (Iterator iter = find.search(pattern); iter.hasNext();) {
1417             InstructionHandle[] match = (InstructionHandle[]) iter.next();
1418             try {
1419                 if (!match[0].hasTargeters() && !match[1].hasTargeters()) {
1420                     il.delete(match[0], match[1]);
1421                 }
1422             }
1423             catch (TargetLostException e) {
1424                 // TODO: move target down into the list
1425             }
1426         }
1427 
1428         // ILOAD_N, ILOAD_N, SWAP, ISTORE_N => ILOAD_N
1429         // pattern = "ILOAD ILOAD SWAP ISTORE";
1430         // changed to lower case - changing to all lower case although only the instruction with capital I
1431         // is creating a problem in the Turkish locale
1432         pattern = "iload iload swap istore";
1433         for (Iterator iter = find.search(pattern); iter.hasNext();) {
1434             InstructionHandle[] match = (InstructionHandle[]) iter.next();
1435             try {
1436                 com.sun.org.apache.bcel.internal.generic.ILOAD iload1 =
1437                     (com.sun.org.apache.bcel.internal.generic.ILOAD) match[0].getInstruction();
1438                 com.sun.org.apache.bcel.internal.generic.ILOAD iload2 =
1439                     (com.sun.org.apache.bcel.internal.generic.ILOAD) match[1].getInstruction();
1440                 com.sun.org.apache.bcel.internal.generic.ISTORE istore =
1441                     (com.sun.org.apache.bcel.internal.generic.ISTORE) match[3].getInstruction();
1442 
1443                 if (!match[1].hasTargeters() &&
1444                     !match[2].hasTargeters() &&
1445                     !match[3].hasTargeters() &&
1446                     iload1.getIndex() == iload2.getIndex() &&
1447                     iload2.getIndex() == istore.getIndex())
1448                 {
1449                     il.delete(match[1], match[3]);
1450                 }
1451             }
1452             catch (TargetLostException e) {
1453                 // TODO: move target down into the list
1454             }
1455         }
1456 
1457         // LoadInstruction_N, LoadInstruction_M, SWAP => LoadInstruction_M, LoadInstruction_N
1458         // pattern = "LoadInstruction LoadInstruction SWAP";
1459         // changed to lower case - changing to all lower case although only the instruction with capital I
1460         // is creating a problem in the Turkish locale
1461         pattern = "loadinstruction loadinstruction swap";
1462         for (Iterator iter = find.search(pattern); iter.hasNext();) {
1463             InstructionHandle[] match = (InstructionHandle[])iter.next();
1464             try {
1465                 if (!match[0].hasTargeters() &&
1466                     !match[1].hasTargeters() &&
1467                     !match[2].hasTargeters())
1468                 {
1469                     Instruction load_m = match[1].getInstruction();
1470                     il.insert(match[0], load_m);
1471                     il.delete(match[1], match[2]);
1472                 }
1473             }
1474             catch (TargetLostException e) {
1475                 // TODO: move target down into the list
1476             }
1477         }
1478 
1479         // ALOAD_N ALOAD_N => ALOAD_N DUP
1480         // pattern = "ALOAD ALOAD";
1481         // changed to lower case - changing to all lower case although only the instruction with capital I
1482         // is creating a problem in the Turkish locale
1483         pattern = "aload aload";
1484         for (Iterator iter = find.search(pattern); iter.hasNext();) {
1485             InstructionHandle[] match = (InstructionHandle[])iter.next();
1486             try {
1487                 if (!match[1].hasTargeters()) {
1488                     com.sun.org.apache.bcel.internal.generic.ALOAD aload1 =
1489                         (com.sun.org.apache.bcel.internal.generic.ALOAD) match[0].getInstruction();
1490                     com.sun.org.apache.bcel.internal.generic.ALOAD aload2 =
1491                         (com.sun.org.apache.bcel.internal.generic.ALOAD) match[1].getInstruction();
1492 
1493                     if (aload1.getIndex() == aload2.getIndex()) {
1494                         il.insert(match[1], new DUP());
1495                         il.delete(match[1]);
1496                     }
1497                 }
1498             }
1499             catch (TargetLostException e) {
1500                 // TODO: move target down into the list
1501             }
1502         }
1503     }
1504 
1505     public InstructionHandle getTemplateInstructionHandle(Template template) {
1506         return (InstructionHandle)_templateIHs.get(template);
1507     }
1508 
1509     /**
1510      * Auxiliary method to determine if a qname is an attribute.
1511      */
1512     private static boolean isAttributeName(String qname) {
1513         final int col = qname.lastIndexOf(':') + 1;
1514         return (qname.charAt(col) == '@');
1515     }
1516 
1517     /**
1518      * Auxiliary method to determine if a qname is a namespace
1519      * qualified "*".
1520      */
1521     private static boolean isNamespaceName(String qname) {
1522         final int col = qname.lastIndexOf(':');
1523         return (col > -1 && qname.charAt(qname.length()-1) == '*');
1524     }
1525 }