KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > org > apache > xalan > internal > 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 com.sun.org.apache.xalan.internal.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 com.sun.org.apache.bcel.internal.generic.Instruction;
28 import com.sun.org.apache.bcel.internal.generic.BranchHandle;
29 import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
30 import com.sun.org.apache.bcel.internal.generic.DUP;
31 import com.sun.org.apache.bcel.internal.generic.GOTO_W;
32 import com.sun.org.apache.bcel.internal.generic.IFLT;
33 import com.sun.org.apache.bcel.internal.generic.ILOAD;
34 import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
35 import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
36 import com.sun.org.apache.bcel.internal.generic.ISTORE;
37 import com.sun.org.apache.bcel.internal.generic.InstructionHandle;
38 import com.sun.org.apache.bcel.internal.generic.InstructionList;
39 import com.sun.org.apache.bcel.internal.generic.LocalVariableGen;
40 import com.sun.org.apache.bcel.internal.generic.SWITCH;
41 import com.sun.org.apache.bcel.internal.generic.TargetLostException;
42 import com.sun.org.apache.bcel.internal.util.InstructionFinder;
43 import com.sun.org.apache.xalan.internal.xsltc.DOM;
44 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
45 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
46 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NamedMethodGenerator;
47 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;
48 import com.sun.org.apache.xalan.internal.xsltc.dom.Axis;
49 import com.sun.org.apache.xml.internal.dtm.DTM;
50
51 /**
52  * Mode gathers all the templates belonging to a given mode;
53  * it is responsible for generating an appropriate
54  * applyTemplates + (mode name) method in the translet.
55  *
56  * @author Jacek Ambroziak
57  * @author Santiago Pericas-Geertsen
58  * @author Morten Jorgensen
59  * @author Erwin Bolwidt <ejb@klomp.org>
60  * @author G. Todd Miller
61  */

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1436    private void peepHoleOptimization(MethodGenerator methodGen) {
1437        InstructionList il = methodGen.getInstructionList();
1438        InstructionFinder find = new InstructionFinder(il);
1439    InstructionHandle ih;
1440    String JavaDoc pattern;
1441
1442    // LoadInstruction, POP => (removed)
1443
pattern = "LoadInstruction POP";
1444    for (Iterator JavaDoc iter = find.search(pattern); iter.hasNext();) {
1445        InstructionHandle[] match = (InstructionHandle[]) iter.next();
1446        try {
1447        if (!match[0].hasTargeters() && !match[1].hasTargeters()) {
1448                    il.delete(match[0], match[1]);
1449                }
1450        }
1451        catch (TargetLostException e) {
1452                // TODO: move target down into the list
1453
}
1454    }
1455        
1456    // ILOAD_N, ILOAD_N, SWAP, ISTORE_N => ILOAD_N
1457
pattern = "ILOAD ILOAD SWAP ISTORE";
1458    for (Iterator JavaDoc iter = find.search(pattern); iter.hasNext();) {
1459            InstructionHandle[] match = (InstructionHandle[]) iter.next();
1460            try {
1461                com.sun.org.apache.bcel.internal.generic.ILOAD iload1 =
1462                    (com.sun.org.apache.bcel.internal.generic.ILOAD) match[0].getInstruction();
1463                com.sun.org.apache.bcel.internal.generic.ILOAD iload2 =
1464                    (com.sun.org.apache.bcel.internal.generic.ILOAD) match[1].getInstruction();
1465                com.sun.org.apache.bcel.internal.generic.ISTORE istore =
1466                    (com.sun.org.apache.bcel.internal.generic.ISTORE) match[3].getInstruction();
1467                
1468                if (!match[1].hasTargeters() &&
1469                    !match[2].hasTargeters() &&
1470                    !match[3].hasTargeters() &&
1471                    iload1.getIndex() == iload2.getIndex() &&
1472                    iload2.getIndex() == istore.getIndex())
1473                {
1474                    il.delete(match[1], match[3]);
1475                }
1476            }
1477            catch (TargetLostException e) {
1478                // TODO: move target down into the list
1479
}
1480        }
1481
1482        // LoadInstruction_N, LoadInstruction_M, SWAP => LoadInstruction_M, LoadInstruction_N
1483
pattern = "LoadInstruction LoadInstruction SWAP";
1484    for (Iterator JavaDoc iter = find.search(pattern); iter.hasNext();) {
1485            InstructionHandle[] match = (InstructionHandle[])iter.next();
1486            try {
1487                if (!match[0].hasTargeters() &&
1488                    !match[1].hasTargeters() &&
1489                    !match[2].hasTargeters())
1490                {
1491                    Instruction load_m = match[1].getInstruction();
1492                    il.insert(match[0], load_m);
1493                    il.delete(match[1], match[2]);
1494                }
1495            }
1496            catch (TargetLostException e) {
1497                // TODO: move target down into the list
1498
}
1499        }
1500                       
1501        // ALOAD_N ALOAD_N => ALOAD_N DUP
1502
pattern = "ALOAD ALOAD";
1503        for (Iterator JavaDoc iter = find.search(pattern); iter.hasNext();) {
1504            InstructionHandle[] match = (InstructionHandle[])iter.next();
1505            try {
1506                if (!match[1].hasTargeters()) {
1507                    com.sun.org.apache.bcel.internal.generic.ALOAD aload1 =
1508                        (com.sun.org.apache.bcel.internal.generic.ALOAD) match[0].getInstruction();
1509                    com.sun.org.apache.bcel.internal.generic.ALOAD aload2 =
1510                        (com.sun.org.apache.bcel.internal.generic.ALOAD) match[1].getInstruction();
1511                    
1512                    if (aload1.getIndex() == aload2.getIndex()) {
1513                        il.insert(match[1], new DUP());
1514                        il.delete(match[1]);
1515                    }
1516                }
1517            }
1518            catch (TargetLostException e) {
1519                // TODO: move target down into the list
1520
}
1521        }
1522    }
1523
1524    public InstructionHandle getTemplateInstructionHandle(Template template) {
1525    return (InstructionHandle)_templateIHs.get(template);
1526    }
1527
1528    /**
1529     * Auxiliary method to determine if a qname is an attribute.
1530     */

1531    private static boolean isAttributeName(String JavaDoc qname) {
1532    final int col = qname.lastIndexOf(':') + 1;
1533    return (qname.charAt(col) == '@');
1534    }
1535
1536    /**
1537     * Auxiliary method to determine if a qname is a namespace
1538     * qualified "*".
1539     */

1540    private static boolean isNamespaceName(String JavaDoc qname) {
1541    final int col = qname.lastIndexOf(':');
1542    return (col > -1 && qname.charAt(qname.length()-1) == '*');
1543    }
1544}
1545
Popular Tags