KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xalan > xsltc > compiler > Mode


1 /*
2  * Copyright 2001-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 /*
17  * $Id: Mode.java,v 1.31 2004/02/16 22:24:29 minchau Exp $
18  */

19
20 package org.apache.xalan.xsltc.compiler;
21
22 import java.util.Enumeration JavaDoc;
23 import java.util.Hashtable JavaDoc;
24 import java.util.Iterator JavaDoc;
25 import java.util.Vector JavaDoc;
26
27 import org.apache.bcel.generic.BranchHandle;
28 import org.apache.bcel.generic.ConstantPoolGen;
29 import org.apache.bcel.generic.DUP;
30 import org.apache.bcel.generic.GOTO_W;
31 import org.apache.bcel.generic.IFLT;
32 import org.apache.bcel.generic.ILOAD;
33 import org.apache.bcel.generic.INVOKEINTERFACE;
34 import org.apache.bcel.generic.INVOKEVIRTUAL;
35 import org.apache.bcel.generic.ISTORE;
36 import org.apache.bcel.generic.InstructionHandle;
37 import org.apache.bcel.generic.InstructionList;
38 import org.apache.bcel.generic.LocalVariableGen;
39 import org.apache.bcel.generic.SWITCH;
40 import org.apache.bcel.generic.TargetLostException;
41 import org.apache.bcel.util.InstructionFinder;
42 import org.apache.xalan.xsltc.DOM;
43 import org.apache.xalan.xsltc.compiler.util.ClassGenerator;
44 import org.apache.xalan.xsltc.compiler.util.MethodGenerator;
45 import org.apache.xalan.xsltc.compiler.util.NamedMethodGenerator;
46 import org.apache.xalan.xsltc.compiler.util.Util;
47 import org.apache.xalan.xsltc.dom.Axis;
48 import org.apache.xml.dtm.DTM;
49
50 /**
51  * Mode gathers all the templates belonging to a given mode;
52  * it is responsible for generating an appropriate
53  * applyTemplates + (mode name) method in the translet.
54  * @author Jacek Ambroziak
55  * @author Santiago Pericas-Geertsen
56  * @author Morten Jorgensen
57  * @author Erwin Bolwidt <ejb@klomp.org>
58  * @author G. Todd Miller
59  */

60 final class Mode implements Constants {
61
62     /**
63      * The name of this mode as defined in the stylesheet.
64      */

65     private final QName _name;
66
67     /**
68      * A reference to the stylesheet object that owns this mode.
69      */

70     private final Stylesheet _stylesheet;
71
72     /**
73      * The name of the method in which this mode is compiled.
74      */

75     private final String JavaDoc _methodName;
76
77     /**
78      * A vector of all the templates in this mode.
79      */

80     private Vector JavaDoc _templates;
81
82     /**
83      * Group for patterns with node()-type kernel and child axis.
84      */

85     private Vector JavaDoc _childNodeGroup = null;
86
87     /**
88      * Test sequence for patterns with node()-type kernel and child axis.
89      */

90     private TestSeq _childNodeTestSeq = null;
91
92     /**
93      * Group for patterns with node()-type kernel and attribute axis.
94      */

95     private Vector JavaDoc _attribNodeGroup = null;
96
97     /**
98      * Test sequence for patterns with node()-type kernel and attribute axis.
99      */

100     private TestSeq _attribNodeTestSeq = null;
101     
102     /**
103      * Group for patterns with id() or key()-type kernel.
104      */

105     private Vector JavaDoc _idxGroup = null;
106
107     /**
108      * Test sequence for patterns with id() or key()-type kernel.
109      */

110     private TestSeq _idxTestSeq = null;
111
112     /**
113      * Group for patterns with any other kernel type.
114      */

115     private Vector JavaDoc[] _patternGroups;
116
117     /**
118      * Test sequence for patterns with any other kernel type.
119      */

120     private TestSeq[] _testSeq;
121
122     /**
123      * A mapping between patterns and instruction lists used by
124      * test sequences to avoid compiling the same pattern multiple
125      * times. Note that patterns whose kernels are "*", "node()"
126      * and "@*" can between shared by test sequences.
127      */

128     private Hashtable JavaDoc _preCompiled = new Hashtable JavaDoc();
129
130     /**
131      * A mapping between templates and test sequences.
132      */

133     private Hashtable JavaDoc _neededTemplates = new Hashtable JavaDoc();
134
135     /**
136      * A mapping between named templates and Mode objects.
137      */

138     private Hashtable JavaDoc _namedTemplates = new Hashtable JavaDoc();
139
140     /**
141      * A mapping between templates and instruction handles.
142      */

143     private Hashtable JavaDoc _templateIHs = new Hashtable JavaDoc();
144
145     /**
146      * A mapping between templates and instruction lists.
147      */

148     private Hashtable JavaDoc _templateILs = new Hashtable JavaDoc();
149
150     /**
151      * A reference to the pattern matching the root node.
152      */

153     private LocationPathPattern _rootPattern = null;
154
155     /**
156      * Stores ranges of template precendences for the compilation
157      * of apply-imports (a Hashtable for historical reasons).
158      */

159     private Hashtable JavaDoc _importLevels = null;
160
161     /**
162      * A mapping between key names and keys.
163      */

164     private Hashtable JavaDoc _keys = null;
165
166     /**
167      * Variable index for the current node used in code generation.
168      */

169     private int _currentIndex;
170
171     /**
172      * Creates a new Mode.
173      *
174      * @param name A textual representation of the mode's QName
175      * @param stylesheet The Stylesheet in which the mode occured
176      * @param suffix A suffix to append to the method name for this mode
177      * (normally a sequence number - still in a String).
178      */

179     public Mode(QName name, Stylesheet stylesheet, String JavaDoc suffix) {
180     _name = name;
181     _stylesheet = stylesheet;
182     _methodName = APPLY_TEMPLATES + suffix;
183     _templates = new Vector JavaDoc();
184     _patternGroups = new Vector JavaDoc[32];
185     }
186
187     /**
188      * Returns the name of the method (_not_ function) that will be
189      * compiled for this mode. Normally takes the form 'applyTemplates()'
190      * or * 'applyTemplates2()'.
191      *
192      * @return Method name for this mode
193      */

194     public String JavaDoc functionName() {
195     return _methodName;
196     }
197
198     public String JavaDoc functionName(int min, int max) {
199     if (_importLevels == null) {
200         _importLevels = new Hashtable JavaDoc();
201     }
202     _importLevels.put(new Integer JavaDoc(max), new Integer JavaDoc(min));
203     return _methodName + '_' + max;
204     }
205
206     /**
207      * Add a pre-compiled pattern to this mode.
208      */

209     public void addInstructionList(Pattern pattern,
210     InstructionList ilist)
211     {
212     _preCompiled.put(pattern, ilist);
213     }
214
215     /**
216      * Get the instruction list for a pre-compiled pattern. Used by
217      * test sequences to avoid compiling patterns more than once.
218      */

219     public InstructionList getInstructionList(Pattern pattern) {
220     return (InstructionList) _preCompiled.get(pattern);
221     }
222
223     /**
224      * Shortcut to get the class compiled for this mode (will be inlined).
225      */

226     private String JavaDoc getClassName() {
227     return _stylesheet.getClassName();
228     }
229
230     public Stylesheet getStylesheet() {
231     return _stylesheet;
232     }
233
234     public void addTemplate(Template template) {
235     _templates.addElement(template);
236     }
237
238     private Vector JavaDoc quicksort(Vector JavaDoc templates, int p, int r) {
239     if (p < r) {
240         final int q = partition(templates, p, r);
241         quicksort(templates, p, q);
242         quicksort(templates, q + 1, r);
243     }
244     return templates;
245     }
246     
247     private int partition(Vector JavaDoc templates, int p, int r) {
248     final Template x = (Template)templates.elementAt(p);
249     int i = p - 1;
250     int j = r + 1;
251     while (true) {
252         while (x.compareTo((Template)templates.elementAt(--j)) > 0);
253         while (x.compareTo((Template)templates.elementAt(++i)) < 0);
254         if (i < j) {
255         templates.set(j, templates.set(i, templates.elementAt(j)));
256         }
257         else {
258         return j;
259         }
260     }
261     }
262
263     /**
264      * Process all the test patterns in this mode
265      */

266     public void processPatterns(Hashtable JavaDoc keys) {
267     _keys = keys;
268
269 /*
270 System.out.println("Before Sort " + _name);
271 for (int i = 0; i < _templates.size(); i++) {
272     System.out.println("name = " + ((Template)_templates.elementAt(i)).getName());
273     System.out.println("pattern = " + ((Template)_templates.elementAt(i)).getPattern());
274     System.out.println("priority = " + ((Template)_templates.elementAt(i)).getPriority());
275     System.out.println("position = " + ((Template)_templates.elementAt(i)).getPosition());
276 }
277 */

278
279     _templates = quicksort(_templates, 0, _templates.size() - 1);
280
281 /*
282 System.out.println("\n After Sort " + _name);
283 for (int i = 0; i < _templates.size(); i++) {
284     System.out.println("name = " + ((Template)_templates.elementAt(i)).getName());
285     System.out.println("pattern = " + ((Template)_templates.elementAt(i)).getPattern());
286     System.out.println("priority = " + ((Template)_templates.elementAt(i)).getPriority());
287     System.out.println("position = " + ((Template)_templates.elementAt(i)).getPosition());
288 }
289 */

290
291     // Traverse all templates
292
final Enumeration JavaDoc templates = _templates.elements();
293     while (templates.hasMoreElements()) {
294         // Get the next template
295
final Template template = (Template)templates.nextElement();
296
297         /*
298          * Add this template to a table of named templates if it has a name.
299          * If there are multiple templates with the same name, all but one
300          * (the one with highest priority) will be disabled.
301          */

302         if (template.isNamed() && !template.disabled()) {
303         _namedTemplates.put(template, this);
304         }
305
306         // Add this template to a test sequence if it has a pattern
307
final Pattern pattern = template.getPattern();
308         if (pattern != null) {
309         flattenAlternative(pattern, template, keys);
310         }
311     }
312     prepareTestSequences();
313     }
314
315     /**
316      * This method will break up alternative patterns (ie. unions of patterns,
317      * such as match="A/B | C/B") and add the basic patterns to their
318      * respective pattern groups.
319      */

320     private void flattenAlternative(Pattern pattern,
321                     Template template,
322                     Hashtable JavaDoc keys) {
323     // Patterns on type id() and key() are special since they do not have
324
// any kernel node type (it can be anything as long as the node is in
325
// the id's or key's index).
326
if (pattern instanceof IdKeyPattern) {
327         final IdKeyPattern idkey = (IdKeyPattern)pattern;
328         idkey.setTemplate(template);
329         if (_idxGroup == null) _idxGroup = new Vector JavaDoc();
330         _idxGroup.add(pattern);
331     }
332     // Alternative patterns are broken up and re-processed recursively
333
else if (pattern instanceof AlternativePattern) {
334         final AlternativePattern alt = (AlternativePattern)pattern;
335         flattenAlternative(alt.getLeft(), template, keys);
336         flattenAlternative(alt.getRight(), template, keys);
337     }
338     // Finally we have a pattern that can be added to a test sequence!
339
else if (pattern instanceof LocationPathPattern) {
340         final LocationPathPattern lpp = (LocationPathPattern)pattern;
341         lpp.setTemplate(template);
342         addPatternToGroup(lpp);
343     }
344     }
345
346     /**
347      * Group patterns by NodeTests of their last Step
348      * Keep them sorted by priority within group
349      */

350     private void addPatternToGroup(final LocationPathPattern lpp) {
351     // id() and key()-type patterns do not have a kernel type
352
if (lpp instanceof IdKeyPattern) {
353         addPattern(-1, lpp);
354     }
355     // Otherwise get the kernel pattern from the LPP
356
else {
357         // kernel pattern is the last (maybe only) Step
358
final StepPattern kernel = lpp.getKernelPattern();
359         if (kernel != null) {
360         addPattern(kernel.getNodeType(), lpp);
361         }
362         else if (_rootPattern == null ||
363              lpp.noSmallerThan(_rootPattern)) {
364         _rootPattern = lpp;
365         }
366     }
367     }
368
369     /**
370      * Adds a pattern to a pattern group
371      */

372     private void addPattern(int kernelType, LocationPathPattern pattern) {
373     // Make sure the array of pattern groups is long enough
374
final int oldLength = _patternGroups.length;
375     if (kernelType >= oldLength) {
376         Vector JavaDoc[] newGroups = new Vector JavaDoc[kernelType * 2];
377         System.arraycopy(_patternGroups, 0, newGroups, 0, oldLength);
378         _patternGroups = newGroups;
379     }
380     
381     // Find the vector to put this pattern into
382
Vector JavaDoc patterns;
383
384     if (kernelType == DOM.NO_TYPE) {
385         if (pattern.getAxis() == Axis.ATTRIBUTE) {
386         patterns = (_attribNodeGroup == null) ?
387             (_attribNodeGroup = new Vector JavaDoc(2)) : _attribNodeGroup;
388         }
389         else {
390         patterns = (_childNodeGroup == null) ?
391             (_childNodeGroup = new Vector JavaDoc(2)) : _childNodeGroup;
392         }
393     }
394     else {
395         patterns = (_patternGroups[kernelType] == null) ?
396         (_patternGroups[kernelType] = new Vector JavaDoc(2)) :
397         _patternGroups[kernelType];
398     }
399
400     if (patterns.size() == 0) {
401         patterns.addElement(pattern);
402     }
403     else {
404         boolean inserted = false;
405         for (int i = 0; i < patterns.size(); i++) {
406         final LocationPathPattern lppToCompare =
407             (LocationPathPattern)patterns.elementAt(i);
408
409         if (pattern.noSmallerThan(lppToCompare)) {
410             inserted = true;
411             patterns.insertElementAt(pattern, i);
412             break;
413         }
414         }
415         if (inserted == false) {
416         patterns.addElement(pattern);
417         }
418     }
419     }
420     
421     /**
422      * Complete test sequences of a given type by adding all patterns
423      * from a given group.
424      */

425     private void completeTestSequences(int nodeType, Vector JavaDoc patterns) {
426     if (patterns != null) {
427         if (_patternGroups[nodeType] == null) {
428         _patternGroups[nodeType] = patterns;
429         }
430         else {
431         final int m = patterns.size();
432         for (int j = 0; j < m; j++) {
433             addPattern(nodeType,
434             (LocationPathPattern) patterns.elementAt(j));
435         }
436         }
437     }
438     }
439
440     /**
441      * Build test sequences. The first step is to complete the test sequences
442      * by including patterns of "*" and "node()" kernel to all element test
443      * sequences, and of "@*" to all attribute test sequences.
444      */

445     private void prepareTestSequences() {
446     final Vector JavaDoc starGroup = _patternGroups[DTM.ELEMENT_NODE];
447     final Vector JavaDoc atStarGroup = _patternGroups[DTM.ATTRIBUTE_NODE];
448
449     // Complete test sequence for "text()" with "child::node()"
450
completeTestSequences(DTM.TEXT_NODE, _childNodeGroup);
451     
452     // Complete test sequence for "*" with "child::node()"
453
completeTestSequences(DTM.ELEMENT_NODE, _childNodeGroup);
454     
455     // Complete test sequence for "pi()" with "child::node()"
456
completeTestSequences(DTM.PROCESSING_INSTRUCTION_NODE, _childNodeGroup);
457     
458     // Complete test sequence for "comment()" with "child::node()"
459
completeTestSequences(DTM.COMMENT_NODE, _childNodeGroup);
460     
461     // Complete test sequence for "@*" with "attribute::node()"
462
completeTestSequences(DTM.ATTRIBUTE_NODE, _attribNodeGroup);
463
464     final Vector JavaDoc names = _stylesheet.getXSLTC().getNamesIndex();
465     if (starGroup != null || atStarGroup != null ||
466         _childNodeGroup != null || _attribNodeGroup != null)
467     {
468         final int n = _patternGroups.length;
469
470         // Complete test sequence for user-defined types
471
for (int i = DTM.NTYPES; i < n; i++) {
472         if (_patternGroups[i] == null) continue;
473
474         final String JavaDoc name = (String JavaDoc) names.elementAt(i - DTM.NTYPES);
475
476         if (isAttributeName(name)) {
477             // If an attribute then copy "@*" to its test sequence
478
completeTestSequences(i, atStarGroup);
479
480             // And also copy "attribute::node()" to its test sequence
481
completeTestSequences(i, _attribNodeGroup);
482         }
483         else {
484             // If an element then copy "*" to its test sequence
485
completeTestSequences(i, starGroup);
486
487             // And also copy "child::node()" to its test sequence
488
completeTestSequences(i, _childNodeGroup);
489         }
490         }
491     }
492
493     _testSeq = new TestSeq[DTM.NTYPES + names.size()];
494     
495     final int n = _patternGroups.length;
496     for (int i = 0; i < n; i++) {
497         final Vector JavaDoc patterns = _patternGroups[i];
498         if (patterns != null) {
499         final TestSeq testSeq = new TestSeq(patterns, i, this);
500 // System.out.println("testSeq[" + i + "] = " + testSeq);
501
testSeq.reduce();
502         _testSeq[i] = testSeq;
503         testSeq.findTemplates(_neededTemplates);
504         }
505     }
506
507     if (_childNodeGroup != null && _childNodeGroup.size() > 0) {
508         _childNodeTestSeq = new TestSeq(_childNodeGroup, -1, this);
509         _childNodeTestSeq.reduce();
510         _childNodeTestSeq.findTemplates(_neededTemplates);
511     }
512
513 /*
514     if (_attribNodeGroup != null && _attribNodeGroup.size() > 0) {
515         _attribNodeTestSeq = new TestSeq(_attribNodeGroup, -1, this);
516         _attribNodeTestSeq.reduce();
517         _attribNodeTestSeq.findTemplates(_neededTemplates);
518     }
519 */

520
521     if (_idxGroup != null && _idxGroup.size() > 0) {
522         _idxTestSeq = new TestSeq(_idxGroup, this);
523         _idxTestSeq.reduce();
524         _idxTestSeq.findTemplates(_neededTemplates);
525     }
526     
527     if (_rootPattern != null) {
528         // doesn't matter what is 'put', only key matters
529
_neededTemplates.put(_rootPattern.getTemplate(), this);
530     }
531     }
532
533     private void compileNamedTemplate(Template template,
534                       ClassGenerator classGen) {
535     final ConstantPoolGen cpg = classGen.getConstantPool();
536     final InstructionList il = new InstructionList();
537     String JavaDoc methodName = Util.escape(template.getName().toString());
538
539     int numParams = 0;
540     if (template.isSimpleNamedTemplate()) {
541         Vector JavaDoc parameters = template.getParameters();
542         numParams = parameters.size();
543     }
544     
545     // Initialize the types and names arrays for the NamedMethodGenerator.
546
org.apache.bcel.generic.Type[] types =
547         new org.apache.bcel.generic.Type[4 + numParams];
548     String JavaDoc[] names = new String JavaDoc[4 + numParams];
549     types[0] = Util.getJCRefType(DOM_INTF_SIG);
550     types[1] = Util.getJCRefType(NODE_ITERATOR_SIG);
551     types[2] = Util.getJCRefType(TRANSLET_OUTPUT_SIG);
552     types[3] = org.apache.bcel.generic.Type.INT;
553     names[0] = DOCUMENT_PNAME;
554     names[1] = ITERATOR_PNAME;
555     names[2] = TRANSLET_OUTPUT_PNAME;
556     names[3] = NODE_PNAME;
557     
558     // For simple named templates, the signature of the generated method
559
// is not fixed. It depends on the number of parameters declared in the
560
// template.
561
for (int i = 4; i < 4 + numParams; i++) {
562         types[i] = Util.getJCRefType(OBJECT_SIG);
563         names[i] = "param" + String.valueOf(i-4);
564     }
565     
566     NamedMethodGenerator methodGen =
567             new NamedMethodGenerator(ACC_PUBLIC,
568                      org.apache.bcel.generic.Type.VOID,
569                      types, names, methodName,
570                      getClassName(), il, cpg);
571
572     il.append(template.compile(classGen, methodGen));
573     il.append(RETURN);
574     
575     methodGen.stripAttributes(true);
576     methodGen.setMaxLocals();
577     methodGen.setMaxStack();
578     methodGen.removeNOPs();
579     classGen.addMethod(methodGen.getMethod());
580     }
581
582     private void compileTemplates(ClassGenerator classGen,
583                   MethodGenerator methodGen,
584                   InstructionHandle next)
585     {
586         Enumeration JavaDoc templates = _namedTemplates.keys();
587         while (templates.hasMoreElements()) {
588             final Template template = (Template)templates.nextElement();
589             compileNamedTemplate(template, classGen);
590         }
591
592     templates = _neededTemplates.keys();
593     while (templates.hasMoreElements()) {
594         final Template template = (Template)templates.nextElement();
595         if (template.hasContents()) {
596         // !!! TODO templates both named and matched
597
InstructionList til = template.compile(classGen, methodGen);
598         til.append(new GOTO_W(next));
599         _templateILs.put(template, til);
600         _templateIHs.put(template, til.getStart());
601         }
602         else {
603         // empty template
604
_templateIHs.put(template, next);
605         }
606     }
607     }
608     
609     private void appendTemplateCode(InstructionList body) {
610     final Enumeration JavaDoc templates = _neededTemplates.keys();
611     while (templates.hasMoreElements()) {
612         final Object JavaDoc iList =
613         _templateILs.get(templates.nextElement());
614         if (iList != null) {
615         body.append((InstructionList)iList);
616         }
617     }
618     }
619
620     private void appendTestSequences(InstructionList body) {
621     final int n = _testSeq.length;
622     for (int i = 0; i < n; i++) {
623         final TestSeq testSeq = _testSeq[i];
624         if (testSeq != null) {
625         InstructionList il = testSeq.getInstructionList();
626         if (il != null)
627             body.append(il);
628         // else trivial TestSeq
629
}
630     }
631     }
632
633     public static void compileGetChildren(ClassGenerator classGen,
634                       MethodGenerator methodGen,
635                       int node) {
636     final ConstantPoolGen cpg = classGen.getConstantPool();
637     final InstructionList il = methodGen.getInstructionList();
638     final int git = cpg.addInterfaceMethodref(DOM_INTF,
639                           GET_CHILDREN,
640                           GET_CHILDREN_SIG);
641     il.append(methodGen.loadDOM());
642     il.append(new ILOAD(node));
643     il.append(new INVOKEINTERFACE(git, 2));
644     }
645
646     /**
647      * Compiles the default handling for DOM elements: traverse all children
648      */

649     private InstructionList compileDefaultRecursion(ClassGenerator classGen,
650                             MethodGenerator methodGen,
651                             InstructionHandle next) {
652     final ConstantPoolGen cpg = classGen.getConstantPool();
653     final InstructionList il = new InstructionList();
654     final String JavaDoc applyTemplatesSig = classGen.getApplyTemplatesSig();
655     final int git = cpg.addInterfaceMethodref(DOM_INTF,
656                           GET_CHILDREN,
657                           GET_CHILDREN_SIG);
658     final int applyTemplates = cpg.addMethodref(getClassName(),
659                             functionName(),
660                             applyTemplatesSig);
661     il.append(classGen.loadTranslet());
662     il.append(methodGen.loadDOM());
663     
664     il.append(methodGen.loadDOM());
665     il.append(new ILOAD(_currentIndex));
666     il.append(new INVOKEINTERFACE(git, 2));
667     il.append(methodGen.loadHandler());
668     il.append(new INVOKEVIRTUAL(applyTemplates));
669     il.append(new GOTO_W(next));
670     return il;
671     }
672
673     /**
674      * Compiles the default action for DOM text nodes and attribute nodes:
675      * output the node's text value
676      */

677     private InstructionList compileDefaultText(ClassGenerator classGen,
678                            MethodGenerator methodGen,
679                            InstructionHandle next) {
680     final ConstantPoolGen cpg = classGen.getConstantPool();
681     final InstructionList il = new InstructionList();
682
683     final int chars = cpg.addInterfaceMethodref(DOM_INTF,
684                             CHARACTERS,
685                             CHARACTERS_SIG);
686     il.append(methodGen.loadDOM());
687     il.append(new ILOAD(_currentIndex));
688     il.append(methodGen.loadHandler());
689     il.append(new INVOKEINTERFACE(chars, 3));
690     il.append(new GOTO_W(next));
691     return il;
692     }
693
694     private InstructionList compileNamespaces(ClassGenerator classGen,
695                           MethodGenerator methodGen,
696                           boolean[] isNamespace,
697                           boolean[] isAttribute,
698                           boolean attrFlag,
699                           InstructionHandle defaultTarget) {
700     final XSLTC xsltc = classGen.getParser().getXSLTC();
701     final ConstantPoolGen cpg = classGen.getConstantPool();
702
703     // Append switch() statement - namespace test dispatch loop
704
final Vector JavaDoc namespaces = xsltc.getNamespaceIndex();
705     final Vector JavaDoc names = xsltc.getNamesIndex();
706     final int namespaceCount = namespaces.size() + 1;
707     final int namesCount = names.size();
708
709     final InstructionList il = new InstructionList();
710     final int[] types = new int[namespaceCount];
711     final InstructionHandle[] targets = new InstructionHandle[types.length];
712
713     if (namespaceCount > 0) {
714         boolean compiled = false;
715
716         // Initialize targets for namespace() switch statement
717
for (int i = 0; i < namespaceCount; i++) {
718         targets[i] = defaultTarget;
719         types[i] = i;
720         }
721
722         // Add test sequences for known namespace types
723
for (int i = DTM.NTYPES; i < (DTM.NTYPES+namesCount); i++) {
724         if ((isNamespace[i]) && (isAttribute[i] == attrFlag)) {
725             String JavaDoc name = (String JavaDoc)names.elementAt(i-DTM.NTYPES);
726             String JavaDoc namespace = name.substring(0,name.lastIndexOf(':'));
727             final int type = xsltc.registerNamespace(namespace);
728             
729             if ((i < _testSeq.length) &&
730             (_testSeq[i] != null)) {
731             targets[type] =
732                 (_testSeq[i]).compile(classGen,
733                                methodGen,
734                                defaultTarget);
735             compiled = true;
736             }
737         }
738         }
739
740         // Return "null" if no test sequences were compiled
741
if (!compiled) return(null);
742         
743         // Append first code in applyTemplates() - get type of current node
744
final int getNS = cpg.addInterfaceMethodref(DOM_INTF,
745                             "getNamespaceType",
746                             "(I)I");
747         il.append(methodGen.loadDOM());
748         il.append(new ILOAD(_currentIndex));
749         il.append(new INVOKEINTERFACE(getNS, 2));
750         il.append(new SWITCH(types, targets, defaultTarget));
751         return(il);
752     }
753     else {
754         return(null);
755     }
756     }
757
758    /**
759      * Compiles the applyTemplates() method and adds it to the translet.
760      * This is the main dispatch method.
761      */

762     public void compileApplyTemplates(ClassGenerator classGen) {
763     final XSLTC xsltc = classGen.getParser().getXSLTC();
764     final ConstantPoolGen cpg = classGen.getConstantPool();
765     final Vector JavaDoc names = xsltc.getNamesIndex();
766
767     // Create the applyTemplates() method
768
final org.apache.bcel.generic.Type[] argTypes =
769         new org.apache.bcel.generic.Type[3];
770     argTypes[0] = Util.getJCRefType(DOM_INTF_SIG);
771     argTypes[1] = Util.getJCRefType(NODE_ITERATOR_SIG);
772     argTypes[2] = Util.getJCRefType(TRANSLET_OUTPUT_SIG);
773     
774     final String JavaDoc[] argNames = new String JavaDoc[3];
775     argNames[0] = DOCUMENT_PNAME;
776     argNames[1] = ITERATOR_PNAME;
777     argNames[2] = TRANSLET_OUTPUT_PNAME;
778
779     final InstructionList mainIL = new InstructionList();
780     final MethodGenerator methodGen =
781         new MethodGenerator(ACC_PUBLIC | ACC_FINAL,
782                 org.apache.bcel.generic.Type.VOID,
783                 argTypes, argNames, functionName(),
784                 getClassName(), mainIL,
785                 classGen.getConstantPool());
786     methodGen.addException("org.apache.xalan.xsltc.TransletException");
787
788     // Create a local variable to hold the current node
789
final LocalVariableGen current;
790     current = methodGen.addLocalVariable2("current",
791                           org.apache.bcel.generic.Type.INT,
792                           mainIL.getEnd());
793     _currentIndex = current.getIndex();
794
795     // Create the "body" instruction list that will eventually hold the
796
// code for the entire method (other ILs will be appended).
797
final InstructionList body = new InstructionList();
798     body.append(NOP);
799
800     // Create an instruction list that contains the default next-node
801
// iteration
802
final InstructionList ilLoop = new InstructionList();
803     ilLoop.append(methodGen.loadIterator());
804     ilLoop.append(methodGen.nextNode());
805     ilLoop.append(DUP);
806     ilLoop.append(new ISTORE(_currentIndex));
807
808     // The body of this code can get very large - large than can be handled
809
// by a single IFNE(body.getStart()) instruction - need workaround:
810
final BranchHandle ifeq = ilLoop.append(new IFLT(null));
811     final BranchHandle loop = ilLoop.append(new GOTO_W(null));
812     ifeq.setTarget(ilLoop.append(RETURN)); // applyTemplates() ends here!
813
final InstructionHandle ihLoop = ilLoop.getStart();
814
815     // Compile default handling of elements (traverse children)
816
InstructionList ilRecurse =
817         compileDefaultRecursion(classGen, methodGen, ihLoop);
818     InstructionHandle ihRecurse = ilRecurse.getStart();
819
820     // Compile default handling of text/attribute nodes (output text)
821
InstructionList ilText =
822         compileDefaultText(classGen, methodGen, ihLoop);
823     InstructionHandle ihText = ilText.getStart();
824
825     // Distinguish attribute/element/namespace tests for further processing
826
final int[] types = new int[DTM.NTYPES + names.size()];
827     for (int i = 0; i < types.length; i++) {
828         types[i] = i;
829     }
830
831     // Initialize isAttribute[] and isNamespace[] arrays
832
final boolean[] isAttribute = new boolean[types.length];
833     final boolean[] isNamespace = new boolean[types.length];
834     for (int i = 0; i < names.size(); i++) {
835         final String JavaDoc name = (String JavaDoc)names.elementAt(i);
836         isAttribute[i + DTM.NTYPES] = isAttributeName(name);
837         isNamespace[i + DTM.NTYPES] = isNamespaceName(name);
838     }
839
840     // Compile all templates - regardless of pattern type
841
compileTemplates(classGen, methodGen, ihLoop);
842
843     // Handle template with explicit "*" pattern
844
final TestSeq elemTest = _testSeq[DTM.ELEMENT_NODE];
845     InstructionHandle ihElem = ihRecurse;
846     if (elemTest != null)
847         ihElem = elemTest.compile(classGen, methodGen, ihRecurse);
848
849     // Handle template with explicit "@*" pattern
850
final TestSeq attrTest = _testSeq[DTM.ATTRIBUTE_NODE];
851     InstructionHandle ihAttr = ihText;
852     if (attrTest != null)
853         ihAttr = attrTest.compile(classGen, methodGen, ihAttr);
854
855     // Do tests for id() and key() patterns first
856
InstructionList ilKey = null;
857     if (_idxTestSeq != null) {
858         loop.setTarget(_idxTestSeq.compile(classGen, methodGen, body.getStart()));
859         ilKey = _idxTestSeq.getInstructionList();
860     }
861     else {
862         loop.setTarget(body.getStart());
863     }
864
865     // If there is a match on node() we need to replace ihElem
866
// and ihText if the priority of node() is higher
867
if (_childNodeTestSeq != null) {
868         // Compare priorities of node() and "*"
869
double nodePrio = _childNodeTestSeq.getPriority();
870         int nodePos = _childNodeTestSeq.getPosition();
871         double elemPrio = (0 - Double.MAX_VALUE);
872         int elemPos = Integer.MIN_VALUE;
873
874         if (elemTest != null) {
875         elemPrio = elemTest.getPriority();
876         elemPos = elemTest.getPosition();
877         }
878         if (elemPrio == Double.NaN || elemPrio < nodePrio ||
879         (elemPrio == nodePrio && elemPos < nodePos))
880         {
881         ihElem = _childNodeTestSeq.compile(classGen, methodGen, ihLoop);
882         }
883
884         // Compare priorities of node() and text()
885
final TestSeq textTest = _testSeq[DTM.TEXT_NODE];
886         double textPrio = (0 - Double.MAX_VALUE);
887         int textPos = Integer.MIN_VALUE;
888
889         if (textTest != null) {
890         textPrio = textTest.getPriority();
891         textPos = textTest.getPosition();
892         }
893         if (textPrio == Double.NaN || textPrio < nodePrio ||
894             (textPrio == nodePrio && textPos < nodePos))
895         {
896         ihText = _childNodeTestSeq.compile(classGen, methodGen, ihLoop);
897         _testSeq[DTM.TEXT_NODE] = _childNodeTestSeq;
898         }
899     }
900
901     // Handle templates with "ns:*" pattern
902
InstructionHandle elemNamespaceHandle = ihElem;
903     InstructionList nsElem = compileNamespaces(classGen, methodGen,
904                            isNamespace, isAttribute,
905                            false, ihElem);
906     if (nsElem != null) elemNamespaceHandle = nsElem.getStart();
907
908     // Handle templates with "ns:@*" pattern
909
InstructionHandle attrNamespaceHandle = ihAttr;
910     InstructionList nsAttr = compileNamespaces(classGen, methodGen,
911                            isNamespace, isAttribute,
912                            true, ihAttr);
913     if (nsAttr != null) attrNamespaceHandle = nsAttr.getStart();
914
915     // Handle templates with "ns:elem" or "ns:@attr" pattern
916
final InstructionHandle[] targets = new InstructionHandle[types.length];
917     for (int i = DTM.NTYPES; i < targets.length; i++) {
918         final TestSeq testSeq = _testSeq[i];
919         // Jump straight to namespace tests ?
920
if (isNamespace[i]) {
921         if (isAttribute[i])
922             targets[i] = attrNamespaceHandle;
923         else
924             targets[i] = elemNamespaceHandle;
925         }
926         // Test first, then jump to namespace tests
927
else if (testSeq != null) {
928         if (isAttribute[i])
929             targets[i] = testSeq.compile(classGen, methodGen,
930                          attrNamespaceHandle);
931         else
932             targets[i] = testSeq.compile(classGen, methodGen,
933                          elemNamespaceHandle);
934         }
935         else {
936         targets[i] = ihLoop;
937         }
938     }
939
940
941     // Handle pattern with match on root node - default: traverse children
942
targets[DTM.ROOT_NODE] = _rootPattern != null
943         ? getTemplateInstructionHandle(_rootPattern.getTemplate())
944         : ihRecurse;
945
946         // Handle pattern with match on root node - default: traverse children
947
targets[DTM.DOCUMENT_NODE] = _rootPattern != null
948         ? getTemplateInstructionHandle(_rootPattern.getTemplate())
949         : ihRecurse;
950
951     // Handle any pattern with match on text nodes - default: output text
952
targets[DTM.TEXT_NODE] = _testSeq[DTM.TEXT_NODE] != null
953         ? _testSeq[DTM.TEXT_NODE].compile(classGen, methodGen, ihText)
954         : ihText;
955
956     // This DOM-type is not in use - default: process next node
957
targets[DTM.NAMESPACE_NODE] = ihLoop;
958
959     // Match unknown element in DOM - default: check for namespace match
960
targets[DTM.ELEMENT_NODE] = elemNamespaceHandle;
961
962     // Match unknown attribute in DOM - default: check for namespace match
963
targets[DTM.ATTRIBUTE_NODE] = attrNamespaceHandle;
964
965     // Match on processing instruction - default: process next node
966
InstructionHandle ihPI = ihLoop;
967     if (_childNodeTestSeq != null) ihPI = ihElem;
968     if (_testSeq[DTM.PROCESSING_INSTRUCTION_NODE] != null)
969         targets[DTM.PROCESSING_INSTRUCTION_NODE] =
970         _testSeq[DTM.PROCESSING_INSTRUCTION_NODE].
971         compile(classGen, methodGen, ihPI);
972     else
973         targets[DTM.PROCESSING_INSTRUCTION_NODE] = ihPI;
974     
975     // Match on comments - default: process next node
976
InstructionHandle ihComment = ihLoop;
977     if (_childNodeTestSeq != null) ihComment = ihElem;
978     targets[DTM.COMMENT_NODE] = _testSeq[DTM.COMMENT_NODE] != null
979         ? _testSeq[DTM.COMMENT_NODE].compile(classGen, methodGen, ihComment)
980         : ihComment;
981         
982         // This DOM-type is not in use - default: process next node
983
targets[DTM.CDATA_SECTION_NODE] = ihLoop;
984
985     // This DOM-type is not in use - default: process next node
986
targets[DTM.DOCUMENT_FRAGMENT_NODE] = ihLoop;
987     
988     // This DOM-type is not in use - default: process next node
989
targets[DTM.DOCUMENT_TYPE_NODE] = ihLoop;
990
991     // This DOM-type is not in use - default: process next node
992
targets[DTM.ENTITY_NODE] = ihLoop;
993
994     // This DOM-type is not in use - default: process next node
995
targets[DTM.ENTITY_REFERENCE_NODE] = ihLoop;
996     
997     // This DOM-type is not in use - default: process next node
998
targets[DTM.NOTATION_NODE] = ihLoop;
999
1000
1001    // Now compile test sequences for various match patterns:
1002
for (int i = DTM.NTYPES; i < targets.length; i++) {
1003        final TestSeq testSeq = _testSeq[i];
1004        // Jump straight to namespace tests ?
1005
if ((testSeq == null) || (isNamespace[i])) {
1006        if (isAttribute[i])
1007            targets[i] = attrNamespaceHandle;
1008        else
1009            targets[i] = elemNamespaceHandle;
1010        }
1011        // Match on node type
1012
else {
1013        if (isAttribute[i])
1014            targets[i] = testSeq.compile(classGen, methodGen,
1015                         attrNamespaceHandle);
1016        else
1017            targets[i] = testSeq.compile(classGen, methodGen,
1018                         elemNamespaceHandle);
1019        }
1020    }
1021
1022    if (ilKey != null) body.insert(ilKey);
1023
1024    // Append first code in applyTemplates() - get type of current node
1025
final int getType = cpg.addInterfaceMethodref(DOM_INTF,
1026                              "getExpandedTypeID",
1027                                                      "(I)I");
1028    body.append(methodGen.loadDOM());
1029    body.append(new ILOAD(_currentIndex));
1030    body.append(new INVOKEINTERFACE(getType, 2));
1031
1032    // Append switch() statement - main dispatch loop in applyTemplates()
1033
InstructionHandle disp = body.append(new SWITCH(types, targets, ihLoop));
1034
1035    // Append all the "case:" statements
1036
appendTestSequences(body);
1037    // Append the actual template code
1038
appendTemplateCode(body);
1039
1040    // Append NS:* node tests (if any)
1041
if (nsElem != null) body.append(nsElem);
1042    // Append NS:@* node tests (if any)
1043
if (nsAttr != null) body.append(nsAttr);
1044
1045    // Append default action for element and root nodes
1046
body.append(ilRecurse);
1047    // Append default action for text and attribute nodes
1048
body.append(ilText);
1049
1050    // putting together constituent instruction lists
1051
mainIL.append(new GOTO_W(ihLoop));
1052    mainIL.append(body);
1053    // fall through to ilLoop
1054
mainIL.append(ilLoop);
1055
1056    peepHoleOptimization(methodGen);
1057    methodGen.stripAttributes(true);
1058    
1059    methodGen.setMaxLocals();
1060    methodGen.setMaxStack();
1061    methodGen.removeNOPs();
1062    classGen.addMethod(methodGen.getMethod());
1063
1064    // Compile method(s) for <xsl:apply-imports/> for this mode
1065
if (_importLevels != null) {
1066        Enumeration JavaDoc levels = _importLevels.keys();
1067        while (levels.hasMoreElements()) {
1068        Integer JavaDoc max = (Integer JavaDoc)levels.nextElement();
1069        Integer JavaDoc min = (Integer JavaDoc)_importLevels.get(max);
1070        compileApplyImports(classGen, min.intValue(), max.intValue());
1071        }
1072    }
1073    }
1074
1075    private void compileTemplateCalls(ClassGenerator classGen,
1076                      MethodGenerator methodGen,
1077                      InstructionHandle next, int min, int max){
1078        Enumeration JavaDoc templates = _neededTemplates.keys();
1079    while (templates.hasMoreElements()) {
1080        final Template template = (Template)templates.nextElement();
1081        final int prec = template.getImportPrecedence();
1082        if ((prec >= min) && (prec < max)) {
1083        if (template.hasContents()) {
1084            InstructionList til = template.compile(classGen, methodGen);
1085            til.append(new GOTO_W(next));
1086            _templateILs.put(template, til);
1087            _templateIHs.put(template, til.getStart());
1088        }
1089        else {
1090            // empty template
1091
_templateIHs.put(template, next);
1092        }
1093        }
1094    }
1095    }
1096
1097
1098    public void compileApplyImports(ClassGenerator classGen, int min, int max) {
1099    final XSLTC xsltc = classGen.getParser().getXSLTC();
1100    final ConstantPoolGen cpg = classGen.getConstantPool();
1101    final Vector JavaDoc names = xsltc.getNamesIndex();
1102
1103    // Clear some datastructures
1104
_namedTemplates = new Hashtable JavaDoc();
1105    _neededTemplates = new Hashtable JavaDoc();
1106    _templateIHs = new Hashtable JavaDoc();
1107    _templateILs = new Hashtable JavaDoc();
1108    _patternGroups = new Vector JavaDoc[32];
1109    _rootPattern = null;
1110
1111    // IMPORTANT: Save orignal & complete set of templates!!!!
1112
Vector JavaDoc oldTemplates = _templates;
1113
1114    // Gather templates that are within the scope of this import
1115
_templates = new Vector JavaDoc();
1116    final Enumeration JavaDoc templates = oldTemplates.elements();
1117    while (templates.hasMoreElements()) {
1118        final Template template = (Template)templates.nextElement();
1119        final int prec = template.getImportPrecedence();
1120        if ((prec >= min) && (prec < max)) addTemplate(template);
1121    }
1122
1123    // Process all patterns from those templates
1124
processPatterns(_keys);
1125
1126    // Create the applyTemplates() method
1127
final org.apache.bcel.generic.Type[] argTypes =
1128        new org.apache.bcel.generic.Type[3];
1129    argTypes[0] = Util.getJCRefType(DOM_INTF_SIG);
1130    argTypes[1] = Util.getJCRefType(NODE_ITERATOR_SIG);
1131    argTypes[2] = Util.getJCRefType(TRANSLET_OUTPUT_SIG);
1132
1133    final String JavaDoc[] argNames = new String JavaDoc[3];
1134    argNames[0] = DOCUMENT_PNAME;
1135    argNames[1] = ITERATOR_PNAME;
1136    argNames[2] = TRANSLET_OUTPUT_PNAME;
1137
1138    final InstructionList mainIL = new InstructionList();
1139    final MethodGenerator methodGen =
1140        new MethodGenerator(ACC_PUBLIC | ACC_FINAL,
1141                org.apache.bcel.generic.Type.VOID,
1142                argTypes, argNames, functionName()+'_'+max,
1143                getClassName(), mainIL,
1144                classGen.getConstantPool());
1145    methodGen.addException("org.apache.xalan.xsltc.TransletException");
1146
1147    // Create the local variable to hold the current node
1148
final LocalVariableGen current;
1149    current = methodGen.addLocalVariable2("current",
1150                          org.apache.bcel.generic.Type.INT,
1151                          mainIL.getEnd());
1152    _currentIndex = current.getIndex();
1153
1154    // Create the "body" instruction list that will eventually hold the
1155
// code for the entire method (other ILs will be appended).
1156
final InstructionList body = new InstructionList();
1157    body.append(NOP);
1158
1159    // Create an instruction list that contains the default next-node
1160
// iteration
1161
final InstructionList ilLoop = new InstructionList();
1162    ilLoop.append(methodGen.loadIterator());
1163    ilLoop.append(methodGen.nextNode());
1164    ilLoop.append(DUP);
1165    ilLoop.append(new ISTORE(_currentIndex));
1166
1167    // The body of this code can get very large - large than can be handled
1168
// by a single IFNE(body.getStart()) instruction - need workaround:
1169
final BranchHandle ifeq = ilLoop.append(new IFLT(null));
1170    final BranchHandle loop = ilLoop.append(new GOTO_W(null));
1171    ifeq.setTarget(ilLoop.append(RETURN)); // applyTemplates() ends here!
1172
final InstructionHandle ihLoop = ilLoop.getStart();
1173
1174    // Compile default handling of elements (traverse children)
1175
InstructionList ilRecurse =
1176        compileDefaultRecursion(classGen, methodGen, ihLoop);
1177    InstructionHandle ihRecurse = ilRecurse.getStart();
1178
1179    // Compile default handling of text/attribute nodes (output text)
1180
InstructionList ilText =
1181        compileDefaultText(classGen, methodGen, ihLoop);
1182    InstructionHandle ihText = ilText.getStart();
1183
1184    // Distinguish attribute/element/namespace tests for further processing
1185
final int[] types = new int[DTM.NTYPES + names.size()];
1186    for (int i = 0; i < types.length; i++) {
1187        types[i] = i;
1188    }
1189
1190    final boolean[] isAttribute = new boolean[types.length];
1191    final boolean[] isNamespace = new boolean[types.length];
1192    for (int i = 0; i < names.size(); i++) {
1193        final String JavaDoc name = (String JavaDoc)names.elementAt(i);
1194        isAttribute[i+DTM.NTYPES] = isAttributeName(name);
1195        isNamespace[i+DTM.NTYPES] = isNamespaceName(name);
1196    }
1197
1198    // Compile all templates - regardless of pattern type
1199
compileTemplateCalls(classGen, methodGen, ihLoop, min, max);
1200
1201    // Handle template with explicit "*" pattern
1202
final TestSeq elemTest = _testSeq[DTM.ELEMENT_NODE];
1203    InstructionHandle ihElem = ihRecurse;
1204    if (elemTest != null) {
1205        ihElem = elemTest.compile(classGen, methodGen, ihLoop);
1206    }
1207
1208    // Handle template with explicit "@*" pattern
1209
final TestSeq attrTest = _testSeq[DTM.ATTRIBUTE_NODE];
1210    InstructionHandle ihAttr = ihLoop;
1211    if (attrTest != null) {
1212        ihAttr = attrTest.compile(classGen, methodGen, ihAttr);
1213    }
1214
1215    // Do tests for id() and key() patterns first
1216
InstructionList ilKey = null;
1217    if (_idxTestSeq != null) {
1218        loop.setTarget(_idxTestSeq.compile(classGen, methodGen, body.getStart()));
1219        ilKey = _idxTestSeq.getInstructionList();
1220    }
1221    else {
1222        loop.setTarget(body.getStart());
1223    }
1224
1225    // If there is a match on node() we need to replace ihElem
1226
// and ihText if the priority of node() is higher
1227
if (_childNodeTestSeq != null) {
1228        // Compare priorities of node() and "*"
1229
double nodePrio = _childNodeTestSeq.getPriority();
1230        int nodePos = _childNodeTestSeq.getPosition();
1231        double elemPrio = (0 - Double.MAX_VALUE);
1232        int elemPos = Integer.MIN_VALUE;
1233
1234        if (elemTest != null) {
1235        elemPrio = elemTest.getPriority();
1236        elemPos = elemTest.getPosition();
1237        }
1238
1239        if (elemPrio == Double.NaN || elemPrio < nodePrio ||
1240        (elemPrio == nodePrio && elemPos < nodePos))
1241        {
1242        ihElem = _childNodeTestSeq.compile(classGen, methodGen, ihLoop);
1243        }
1244
1245        // Compare priorities of node() and text()
1246
final TestSeq textTest = _testSeq[DTM.TEXT_NODE];
1247        double textPrio = (0 - Double.MAX_VALUE);
1248        int textPos = Integer.MIN_VALUE;
1249
1250        if (textTest != null) {
1251        textPrio = textTest.getPriority();
1252        textPos = textTest.getPosition();
1253        }
1254
1255        if (textPrio == Double.NaN || textPrio < nodePrio ||
1256            (textPrio == nodePrio && textPos < nodePos))
1257        {
1258        ihText = _childNodeTestSeq.compile(classGen, methodGen, ihLoop);
1259        _testSeq[DTM.TEXT_NODE] = _childNodeTestSeq;
1260        }
1261    }
1262
1263    // Handle templates with "ns:*" pattern
1264
InstructionHandle elemNamespaceHandle = ihElem;
1265    InstructionList nsElem = compileNamespaces(classGen, methodGen,
1266                           isNamespace, isAttribute,
1267                           false, ihElem);
1268    if (nsElem != null) elemNamespaceHandle = nsElem.getStart();
1269
1270    // Handle templates with "ns:@*" pattern
1271
InstructionList nsAttr = compileNamespaces(classGen, methodGen,
1272                           isNamespace, isAttribute,
1273                           true, ihAttr);
1274    InstructionHandle attrNamespaceHandle = ihAttr;
1275    if (nsAttr != null) attrNamespaceHandle = nsAttr.getStart();
1276
1277    // Handle templates with "ns:elem" or "ns:@attr" pattern
1278
final InstructionHandle[] targets = new InstructionHandle[types.length];
1279    for (int i = DTM.NTYPES; i < targets.length; i++) {
1280        final TestSeq testSeq = _testSeq[i];
1281        // Jump straight to namespace tests ?
1282
if (isNamespace[i]) {
1283        if (isAttribute[i])
1284            targets[i] = attrNamespaceHandle;
1285        else
1286            targets[i] = elemNamespaceHandle;
1287        }
1288        // Test first, then jump to namespace tests
1289
else if (testSeq != null) {
1290        if (isAttribute[i])
1291            targets[i] = testSeq.compile(classGen, methodGen,
1292                         attrNamespaceHandle);
1293        else
1294            targets[i] = testSeq.compile(classGen, methodGen,
1295                         elemNamespaceHandle);
1296        }
1297        else {
1298        targets[i] = ihLoop;
1299        }
1300    }
1301
1302    // Handle pattern with match on root node - default: traverse children
1303
targets[DTM.ROOT_NODE] = _rootPattern != null
1304        ? getTemplateInstructionHandle(_rootPattern.getTemplate())
1305        : ihRecurse;
1306    // Handle pattern with match on root node - default: traverse children
1307
targets[DTM.DOCUMENT_NODE] = _rootPattern != null
1308        ? getTemplateInstructionHandle(_rootPattern.getTemplate())
1309        : ihRecurse; // %HZ%: Was ihLoop in XSLTC_DTM branch
1310

1311    // Handle any pattern with match on text nodes - default: loop
1312
targets[DTM.TEXT_NODE] = _testSeq[DTM.TEXT_NODE] != null
1313        ? _testSeq[DTM.TEXT_NODE].compile(classGen, methodGen, ihText)
1314        : ihText;
1315
1316    // This DOM-type is not in use - default: process next node
1317
targets[DTM.NAMESPACE_NODE] = ihLoop;
1318
1319    // Match unknown element in DOM - default: check for namespace match
1320
targets[DTM.ELEMENT_NODE] = elemNamespaceHandle;
1321
1322    // Match unknown attribute in DOM - default: check for namespace match
1323
targets[DTM.ATTRIBUTE_NODE] = attrNamespaceHandle;
1324
1325    // Match on processing instruction - default: loop
1326
InstructionHandle ihPI = ihLoop;
1327    if (_childNodeTestSeq != null) ihPI = ihElem;
1328    if (_testSeq[DTM.PROCESSING_INSTRUCTION_NODE] != null) {
1329        targets[DTM.PROCESSING_INSTRUCTION_NODE] =
1330        _testSeq[DTM.PROCESSING_INSTRUCTION_NODE].
1331        compile(classGen, methodGen, ihPI);
1332    }
1333    else {
1334        targets[DTM.PROCESSING_INSTRUCTION_NODE] = ihPI;
1335    }
1336    
1337    // Match on comments - default: process next node
1338
InstructionHandle ihComment = ihLoop;
1339    if (_childNodeTestSeq != null) ihComment = ihElem;
1340    targets[DTM.COMMENT_NODE] = _testSeq[DTM.COMMENT_NODE] != null
1341        ? _testSeq[DTM.COMMENT_NODE].compile(classGen, methodGen, ihComment)
1342        : ihComment;
1343        
1344            // This DOM-type is not in use - default: process next node
1345
targets[DTM.CDATA_SECTION_NODE] = ihLoop;
1346
1347    // This DOM-type is not in use - default: process next node
1348
targets[DTM.DOCUMENT_FRAGMENT_NODE] = ihLoop;
1349    
1350    // This DOM-type is not in use - default: process next node
1351
targets[DTM.DOCUMENT_TYPE_NODE] = ihLoop;
1352
1353    // This DOM-type is not in use - default: process next node
1354
targets[DTM.ENTITY_NODE] = ihLoop;
1355
1356    // This DOM-type is not in use - default: process next node
1357
targets[DTM.ENTITY_REFERENCE_NODE] = ihLoop;
1358    
1359    // This DOM-type is not in use - default: process next node
1360
targets[DTM.NOTATION_NODE] = ihLoop;
1361
1362
1363
1364    // Now compile test sequences for various match patterns:
1365
for (int i = DTM.NTYPES; i < targets.length; i++) {
1366        final TestSeq testSeq = _testSeq[i];
1367        // Jump straight to namespace tests ?
1368
if ((testSeq == null) || (isNamespace[i])) {
1369        if (isAttribute[i])
1370            targets[i] = attrNamespaceHandle;
1371        else
1372            targets[i] = elemNamespaceHandle;
1373        }
1374        // Match on node type
1375
else {
1376        if (isAttribute[i])
1377            targets[i] = testSeq.compile(classGen, methodGen,
1378                         attrNamespaceHandle);
1379        else
1380            targets[i] = testSeq.compile(classGen, methodGen,
1381                         elemNamespaceHandle);
1382        }
1383    }
1384
1385    if (ilKey != null) body.insert(ilKey);
1386
1387    // Append first code in applyTemplates() - get type of current node
1388
final int getType = cpg.addInterfaceMethodref(DOM_INTF,
1389                              "getExpandedTypeID",
1390                                                      "(I)I");
1391    body.append(methodGen.loadDOM());
1392    body.append(new ILOAD(_currentIndex));
1393    body.append(new INVOKEINTERFACE(getType, 2));
1394
1395    // Append switch() statement - main dispatch loop in applyTemplates()
1396
InstructionHandle disp = body.append(new SWITCH(types,targets,ihLoop));
1397
1398    // Append all the "case:" statements
1399
appendTestSequences(body);
1400    // Append the actual template code
1401
appendTemplateCode(body);
1402
1403    // Append NS:* node tests (if any)
1404
if (nsElem != null) body.append(nsElem);
1405    // Append NS:@* node tests (if any)
1406
if (nsAttr != null) body.append(nsAttr);
1407
1408    // Append default action for element and root nodes
1409
body.append(ilRecurse);
1410    // Append default action for text and attribute nodes
1411
body.append(ilText);
1412
1413    // putting together constituent instruction lists
1414
mainIL.append(new GOTO_W(ihLoop));
1415    mainIL.append(body);
1416    // fall through to ilLoop
1417
mainIL.append(ilLoop);
1418
1419    peepHoleOptimization(methodGen);
1420    methodGen.stripAttributes(true);
1421    
1422    methodGen.setMaxLocals();
1423    methodGen.setMaxStack();
1424    methodGen.removeNOPs();
1425    classGen.addMethod(methodGen.getMethod());
1426
1427    // Restore original (complete) set of templates for this transformation
1428
_templates = oldTemplates;
1429    }
1430
1431    /**
1432     * Peephole optimization: Remove sequences of [ALOAD, POP].
1433     */

1434    private void peepHoleOptimization(MethodGenerator methodGen) {
1435    InstructionList il = methodGen.getInstructionList();
1436    InstructionFinder find = new InstructionFinder(il);
1437    InstructionHandle ih;
1438    String JavaDoc pattern;
1439
1440    // Remove seqences of ALOAD, POP (GTM)
1441
pattern = "`ALOAD'`POP'`Instruction'";
1442    for(Iterator JavaDoc iter=find.search(pattern); iter.hasNext();){
1443        InstructionHandle[] match = (InstructionHandle[])iter.next();
1444        try {
1445        if ((!match[0].hasTargeters()) && (!match[1].hasTargeters())) {
1446                    il.delete(match[0], match[1]);
1447                }
1448        }
1449        catch (TargetLostException e) {
1450                // TODO: move target down into the list
1451
}
1452    }
1453    // Replace sequences of ILOAD_?, ALOAD_?, SWAP with ALOAD_?, ILOAD_?
1454
pattern = "`ILOAD'`ALOAD'`SWAP'`Instruction'";
1455    for(Iterator JavaDoc iter=find.search(pattern); iter.hasNext();){
1456            InstructionHandle[] match = (InstructionHandle[])iter.next();
1457            try {
1458                org.apache.bcel.generic.Instruction iload;
1459                org.apache.bcel.generic.Instruction aload;
1460                if ((!match[0].hasTargeters()) &&
1461                    (!match[1].hasTargeters()) &&
1462                    (!match[2].hasTargeters())) {
1463                    iload = match[0].getInstruction();
1464                    aload = match[1].getInstruction();
1465                    il.insert(match[0], aload);
1466                    il.insert(match[0], iload);
1467                    il.delete(match[0], match[2]);
1468                }
1469            }
1470            catch (TargetLostException e) {
1471                // TODO: move target down into the list
1472
}
1473        }
1474        
1475        // Replace sequences of ALOAD_1, ALOAD_1 with ALOAD_1, DUP
1476
pattern = "`ALOAD_1'`ALOAD_1'`Instruction'";
1477        for(Iterator JavaDoc iter=find.search(pattern); iter.hasNext();){
1478            InstructionHandle[] match = (InstructionHandle[])iter.next();
1479            try {
1480            org.apache.bcel.generic.Instruction iload;
1481                org.apache.bcel.generic.Instruction aload;
1482                if ((!match[0].hasTargeters()) && (!match[1].hasTargeters())) {
1483                    il.insert(match[1], new DUP());
1484                    il.delete(match[1]);
1485                }
1486            }
1487            catch (TargetLostException e) {
1488                // TODO: move target down into the list
1489
}
1490        }
1491        
1492    }
1493
1494    public InstructionHandle getTemplateInstructionHandle(Template template) {
1495    return (InstructionHandle)_templateIHs.get(template);
1496    }
1497
1498    /**
1499     * Auxiliary method to determine if a qname is an attribute.
1500     */

1501    private static boolean isAttributeName(String JavaDoc qname) {
1502    final int col = qname.lastIndexOf(':') + 1;
1503    return (qname.charAt(col) == '@');
1504    }
1505
1506    /**
1507     * Auxiliary method to determine if a qname is a namespace
1508     * qualified "*".
1509     */

1510    private static boolean isNamespaceName(String JavaDoc qname) {
1511    final int col = qname.lastIndexOf(':');
1512    return (col > -1 && qname.charAt(qname.length()-1) == '*');
1513    }
1514}
1515
Popular Tags