View Javadoc
1   /*
2    * reserved comment block
3    * DO NOT REMOVE OR ALTER!
4    */
5   /*
6    * Copyright 2001-2004 The Apache Software Foundation.
7    *
8    * Licensed under the Apache License, Version 2.0 (the "License");
9    * you may not use this file except in compliance with the License.
10   * You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  /*
21   * $Id: Stylesheet.java,v 1.5 2005/09/28 13:48:16 pvedula Exp $
22   */
23  
24  package com.sun.org.apache.xalan.internal.xsltc.compiler;
25  
26  import java.util.Vector;
27  import java.util.Enumeration;
28  import java.util.Hashtable;
29  import java.util.Iterator;
30  import java.util.Properties;
31  import java.util.StringTokenizer;
32  
33  import com.sun.org.apache.xml.internal.utils.SystemIDResolver;
34  import com.sun.org.apache.bcel.internal.generic.ANEWARRAY;
35  import com.sun.org.apache.bcel.internal.generic.BasicType;
36  import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
37  import com.sun.org.apache.bcel.internal.generic.FieldGen;
38  import com.sun.org.apache.bcel.internal.generic.GETFIELD;
39  import com.sun.org.apache.bcel.internal.generic.GETSTATIC;
40  import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
41  import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL;
42  import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
43  import com.sun.org.apache.bcel.internal.generic.ISTORE;
44  import com.sun.org.apache.bcel.internal.generic.InstructionHandle;
45  import com.sun.org.apache.bcel.internal.generic.InstructionList;
46  import com.sun.org.apache.bcel.internal.generic.LocalVariableGen;
47  import com.sun.org.apache.bcel.internal.generic.NEW;
48  import com.sun.org.apache.bcel.internal.generic.NEWARRAY;
49  import com.sun.org.apache.bcel.internal.generic.PUSH;
50  import com.sun.org.apache.bcel.internal.generic.PUTFIELD;
51  import com.sun.org.apache.bcel.internal.generic.PUTSTATIC;
52  import com.sun.org.apache.bcel.internal.generic.TargetLostException;
53  import com.sun.org.apache.bcel.internal.util.InstructionFinder;
54  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
55  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
56  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
57  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
58  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
59  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;
60  import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
61  import com.sun.org.apache.xml.internal.dtm.DTM;
62  
63  /**
64   * @author Jacek Ambroziak
65   * @author Santiago Pericas-Geertsen
66   * @author Morten Jorgensen
67   */
68  public final class Stylesheet extends SyntaxTreeNode {
69  
70      /**
71       * XSLT version defined in the stylesheet.
72       */
73      private String _version;
74  
75      /**
76       * Internal name of this stylesheet used as a key into the symbol table.
77       */
78      private QName _name;
79  
80      /**
81       * A URI that represents the system ID for this stylesheet.
82       */
83      private String _systemId;
84  
85      /**
86       * A reference to the parent stylesheet or null if topmost.
87       */
88      private Stylesheet _parentStylesheet;
89  
90      /**
91       * Contains global variables and parameters defined in the stylesheet.
92       */
93      private Vector _globals = new Vector();
94  
95      /**
96       * Used to cache the result returned by <code>hasLocalParams()</code>.
97       */
98      private Boolean _hasLocalParams = null;
99  
100     /**
101      * The name of the class being generated.
102      */
103     private String _className;
104 
105     /**
106       * Contains all templates defined in this stylesheet
107       */
108     private final Vector _templates = new Vector();
109 
110     /**
111      * Used to cache result of <code>getAllValidTemplates()</code>. Only
112      * set in top-level stylesheets that include/import other stylesheets.
113      */
114     private Vector _allValidTemplates = null;
115 
116     /**
117      * Counter to generate unique mode suffixes.
118      */
119     private int _nextModeSerial = 1;
120 
121     /**
122      * Mapping between mode names and Mode instances.
123      */
124     private final Hashtable _modes = new Hashtable();
125 
126     /**
127      * A reference to the default Mode object.
128      */
129     private Mode _defaultMode;
130 
131     /**
132      * Mapping between extension URIs and their prefixes.
133      */
134     private final Hashtable _extensions = new Hashtable();
135 
136     /**
137      * Reference to the stylesheet from which this stylesheet was
138      * imported (if any).
139      */
140     public Stylesheet _importedFrom = null;
141 
142     /**
143      * Reference to the stylesheet from which this stylesheet was
144      * included (if any).
145      */
146     public Stylesheet _includedFrom = null;
147 
148     /**
149      * Array of all the stylesheets imported or included from this one.
150      */
151     private Vector _includedStylesheets = null;
152 
153     /**
154      * Import precendence for this stylesheet.
155      */
156     private int _importPrecedence = 1;
157 
158     /**
159      * Minimum precendence of any descendant stylesheet by inclusion or
160      * importation.
161      */
162     private int _minimumDescendantPrecedence = -1;
163 
164     /**
165      * Mapping between key names and Key objects (needed by Key/IdPattern).
166      */
167     private Hashtable _keys = new Hashtable();
168 
169     /**
170      * A reference to the SourceLoader set by the user (a URIResolver
171      * if the JAXP API is being used).
172      */
173     private SourceLoader _loader = null;
174 
175     /**
176      * Flag indicating if format-number() is called.
177      */
178     private boolean _numberFormattingUsed = false;
179 
180     /**
181      * Flag indicating if this is a simplified stylesheets. A template
182      * matching on "/" must be added in this case.
183      */
184     private boolean _simplified = false;
185 
186     /**
187      * Flag indicating if multi-document support is needed.
188      */
189     private boolean _multiDocument = false;
190 
191     /**
192      * Flag indicating if nodset() is called.
193      */
194     private boolean _callsNodeset = false;
195 
196     /**
197      * Flag indicating if id() is called.
198      */
199     private boolean _hasIdCall = false;
200 
201     /**
202      * Set to true to enable template inlining optimization.
203      * @see XSLTC#_templateInlining
204      */
205     private boolean _templateInlining = false;
206 
207     /**
208      * A reference to the last xsl:output object found in the styleshet.
209      */
210     private Output  _lastOutputElement = null;
211 
212     /**
213      * Output properties for this stylesheet.
214      */
215     private Properties _outputProperties = null;
216 
217     /**
218      * Output method for this stylesheet (must be set to one of
219      * the constants defined below).
220      */
221     private int _outputMethod = UNKNOWN_OUTPUT;
222 
223     // Output method constants
224     public static final int UNKNOWN_OUTPUT = 0;
225     public static final int XML_OUTPUT     = 1;
226     public static final int HTML_OUTPUT    = 2;
227     public static final int TEXT_OUTPUT    = 3;
228 
229     /**
230      * Return the output method
231      */
232     public int getOutputMethod() {
233         return _outputMethod;
234     }
235 
236     /**
237      * Check and set the output method
238      */
239     private void checkOutputMethod() {
240         if (_lastOutputElement != null) {
241             String method = _lastOutputElement.getOutputMethod();
242             if (method != null) {
243                 if (method.equals("xml"))
244                     _outputMethod = XML_OUTPUT;
245                 else if (method.equals("html"))
246                     _outputMethod = HTML_OUTPUT;
247                 else if (method.equals("text"))
248                     _outputMethod = TEXT_OUTPUT;
249             }
250         }
251     }
252 
253     public boolean getTemplateInlining() {
254         return _templateInlining;
255     }
256 
257     public void setTemplateInlining(boolean flag) {
258         _templateInlining = flag;
259     }
260 
261     public boolean isSimplified() {
262         return(_simplified);
263     }
264 
265     public void setSimplified() {
266         _simplified = true;
267     }
268 
269     public void setHasIdCall(boolean flag) {
270         _hasIdCall = flag;
271     }
272 
273     public void setOutputProperty(String key, String value) {
274         if (_outputProperties == null) {
275             _outputProperties = new Properties();
276         }
277         _outputProperties.setProperty(key, value);
278     }
279 
280     public void setOutputProperties(Properties props) {
281         _outputProperties = props;
282     }
283 
284     public Properties getOutputProperties() {
285         return _outputProperties;
286     }
287 
288     public Output getLastOutputElement() {
289         return _lastOutputElement;
290     }
291 
292     public void setMultiDocument(boolean flag) {
293         _multiDocument = flag;
294     }
295 
296     public boolean isMultiDocument() {
297         return _multiDocument;
298     }
299 
300     public void setCallsNodeset(boolean flag) {
301         if (flag) setMultiDocument(flag);
302         _callsNodeset = flag;
303     }
304 
305     public boolean callsNodeset() {
306         return _callsNodeset;
307     }
308 
309     public void numberFormattingUsed() {
310         _numberFormattingUsed = true;
311         /*
312          * Fix for bug 23046, if the stylesheet is included, set the
313          * numberFormattingUsed flag to the parent stylesheet too.
314          * AbstractTranslet.addDecimalFormat() will be inlined once for the
315          * outer most stylesheet.
316          */
317         Stylesheet parent = getParentStylesheet();
318         if (null != parent) parent.numberFormattingUsed();
319     }
320 
321     public void setImportPrecedence(final int precedence) {
322         // Set import precedence for this stylesheet
323         _importPrecedence = precedence;
324 
325         // Set import precedence for all included stylesheets
326         final Enumeration elements = elements();
327         while (elements.hasMoreElements()) {
328             SyntaxTreeNode child = (SyntaxTreeNode)elements.nextElement();
329             if (child instanceof Include) {
330                 Stylesheet included = ((Include)child).getIncludedStylesheet();
331                 if (included != null && included._includedFrom == this) {
332                     included.setImportPrecedence(precedence);
333                 }
334             }
335         }
336 
337         // Set import precedence for the stylesheet that imported this one
338         if (_importedFrom != null) {
339             if (_importedFrom.getImportPrecedence() < precedence) {
340                 final Parser parser = getParser();
341                 final int nextPrecedence = parser.getNextImportPrecedence();
342                 _importedFrom.setImportPrecedence(nextPrecedence);
343             }
344         }
345         // Set import precedence for the stylesheet that included this one
346         else if (_includedFrom != null) {
347             if (_includedFrom.getImportPrecedence() != precedence)
348                 _includedFrom.setImportPrecedence(precedence);
349         }
350     }
351 
352     public int getImportPrecedence() {
353         return _importPrecedence;
354     }
355 
356     /**
357      * Get the minimum of the precedence of this stylesheet, any stylesheet
358      * imported by this stylesheet and any include/import descendant of this
359      * stylesheet.
360      */
361     public int getMinimumDescendantPrecedence() {
362         if (_minimumDescendantPrecedence == -1) {
363             // Start with precedence of current stylesheet as a basis.
364             int min = getImportPrecedence();
365 
366             // Recursively examine all imported/included stylesheets.
367             final int inclImpCount = (_includedStylesheets != null)
368                                           ? _includedStylesheets.size()
369                                           : 0;
370 
371             for (int i = 0; i < inclImpCount; i++) {
372                 int prec = ((Stylesheet)_includedStylesheets.elementAt(i))
373                                               .getMinimumDescendantPrecedence();
374 
375                 if (prec < min) {
376                     min = prec;
377                 }
378             }
379 
380             _minimumDescendantPrecedence = min;
381         }
382         return _minimumDescendantPrecedence;
383     }
384 
385     public boolean checkForLoop(String systemId) {
386         // Return true if this stylesheet includes/imports itself
387         if (_systemId != null && _systemId.equals(systemId)) {
388             return true;
389         }
390         // Then check with any stylesheets that included/imported this one
391         if (_parentStylesheet != null)
392             return _parentStylesheet.checkForLoop(systemId);
393         // Otherwise OK
394         return false;
395     }
396 
397     public void setParser(Parser parser) {
398         super.setParser(parser);
399         _name = makeStylesheetName("__stylesheet_");
400     }
401 
402     public void setParentStylesheet(Stylesheet parent) {
403         _parentStylesheet = parent;
404     }
405 
406     public Stylesheet getParentStylesheet() {
407         return _parentStylesheet;
408     }
409 
410     public void setImportingStylesheet(Stylesheet parent) {
411         _importedFrom = parent;
412         parent.addIncludedStylesheet(this);
413     }
414 
415     public void setIncludingStylesheet(Stylesheet parent) {
416         _includedFrom = parent;
417         parent.addIncludedStylesheet(this);
418     }
419 
420     public void addIncludedStylesheet(Stylesheet child) {
421         if (_includedStylesheets == null) {
422             _includedStylesheets = new Vector();
423         }
424         _includedStylesheets.addElement(child);
425     }
426 
427     public void setSystemId(String systemId) {
428         if (systemId != null) {
429             _systemId = SystemIDResolver.getAbsoluteURI(systemId);
430         }
431     }
432 
433     public String getSystemId() {
434         return _systemId;
435     }
436 
437     public void setSourceLoader(SourceLoader loader) {
438         _loader = loader;
439     }
440 
441     public SourceLoader getSourceLoader() {
442         return _loader;
443     }
444 
445     private QName makeStylesheetName(String prefix) {
446         return getParser().getQName(prefix+getXSLTC().nextStylesheetSerial());
447     }
448 
449     /**
450      * Returns true if this stylesheet has global vars or params.
451      */
452     public boolean hasGlobals() {
453         return _globals.size() > 0;
454     }
455 
456     /**
457      * Returns true if at least one template in the stylesheet has params
458      * defined. Uses the variable <code>_hasLocalParams</code> to cache the
459      * result.
460      */
461     public boolean hasLocalParams() {
462         if (_hasLocalParams == null) {
463             Vector templates = getAllValidTemplates();
464             final int n = templates.size();
465             for (int i = 0; i < n; i++) {
466                 final Template template = (Template)templates.elementAt(i);
467                 if (template.hasParams()) {
468                     _hasLocalParams = Boolean.TRUE;
469                     return true;
470                 }
471             }
472             _hasLocalParams = Boolean.FALSE;
473             return false;
474         }
475         else {
476             return _hasLocalParams.booleanValue();
477         }
478     }
479 
480     /**
481      * Adds a single prefix mapping to this syntax tree node.
482      * @param prefix Namespace prefix.
483      * @param uri Namespace URI.
484      */
485     protected void addPrefixMapping(String prefix, String uri) {
486         if (prefix.equals(EMPTYSTRING) && uri.equals(XHTML_URI)) return;
487         super.addPrefixMapping(prefix, uri);
488     }
489 
490     /**
491      * Store extension URIs
492      */
493     private void extensionURI(String prefixes, SymbolTable stable) {
494         if (prefixes != null) {
495             StringTokenizer tokens = new StringTokenizer(prefixes);
496             while (tokens.hasMoreTokens()) {
497                 final String prefix = tokens.nextToken();
498                 final String uri = lookupNamespace(prefix);
499                 if (uri != null) {
500                     _extensions.put(uri, prefix);
501                 }
502             }
503         }
504     }
505 
506     public boolean isExtension(String uri) {
507         return (_extensions.get(uri) != null);
508     }
509 
510     public void declareExtensionPrefixes(Parser parser) {
511         final SymbolTable stable = parser.getSymbolTable();
512         final String extensionPrefixes = getAttribute("extension-element-prefixes");
513         extensionURI(extensionPrefixes, stable);
514     }
515 
516     /**
517      * Parse the version and uri fields of the stylesheet and add an
518      * entry to the symbol table mapping the name <tt>__stylesheet_</tt>
519      * to an instance of this class.
520      */
521     public void parseContents(Parser parser) {
522         final SymbolTable stable = parser.getSymbolTable();
523 
524         /*
525         // Make sure the XSL version set in this stylesheet
526         if ((_version == null) || (_version.equals(EMPTYSTRING))) {
527             reportError(this, parser, ErrorMsg.REQUIRED_ATTR_ERR,"version");
528         }
529         // Verify that the version is 1.0 and nothing else
530         else if (!_version.equals("1.0")) {
531             reportError(this, parser, ErrorMsg.XSL_VERSION_ERR, _version);
532         }
533         */
534 
535         // Add the implicit mapping of 'xml' to the XML namespace URI
536         addPrefixMapping("xml", "http://www.w3.org/XML/1998/namespace");
537 
538         // Report and error if more than one stylesheet defined
539         final Stylesheet sheet = stable.addStylesheet(_name, this);
540         if (sheet != null) {
541             // Error: more that one stylesheet defined
542             ErrorMsg err = new ErrorMsg(ErrorMsg.MULTIPLE_STYLESHEET_ERR,this);
543             parser.reportError(Constants.ERROR, err);
544         }
545 
546         // If this is a simplified stylesheet we must create a template that
547         // grabs the root node of the input doc ( <xsl:template match="/"/> ).
548         // This template needs the current element (the one passed to this
549         // method) as its only child, so the Template class has a special
550         // method that handles this (parseSimplified()).
551         if (_simplified) {
552             stable.excludeURI(XSLT_URI);
553             Template template = new Template();
554             template.parseSimplified(this, parser);
555         }
556         // Parse the children of this node
557         else {
558             parseOwnChildren(parser);
559         }
560     }
561 
562     /**
563      * Parse all direct children of the <xsl:stylesheet/> element.
564      */
565     public final void parseOwnChildren(Parser parser) {
566         final SymbolTable stable = parser.getSymbolTable();
567         final String excludePrefixes = getAttribute("exclude-result-prefixes");
568         final String extensionPrefixes = getAttribute("extension-element-prefixes");
569 
570         // Exclude XSLT uri
571         stable.pushExcludedNamespacesContext();
572         stable.excludeURI(Constants.XSLT_URI);
573         stable.excludeNamespaces(excludePrefixes);
574         stable.excludeNamespaces(extensionPrefixes);
575 
576         final Vector contents = getContents();
577         final int count = contents.size();
578 
579         // We have to scan the stylesheet element's top-level elements for
580         // variables and/or parameters before we parse the other elements
581         for (int i = 0; i < count; i++) {
582             SyntaxTreeNode child = (SyntaxTreeNode)contents.elementAt(i);
583             if ((child instanceof VariableBase) ||
584                 (child instanceof NamespaceAlias)) {
585                 parser.getSymbolTable().setCurrentNode(child);
586                 child.parseContents(parser);
587             }
588         }
589 
590         // Now go through all the other top-level elements...
591         for (int i = 0; i < count; i++) {
592             SyntaxTreeNode child = (SyntaxTreeNode)contents.elementAt(i);
593             if (!(child instanceof VariableBase) &&
594                 !(child instanceof NamespaceAlias)) {
595                 parser.getSymbolTable().setCurrentNode(child);
596                 child.parseContents(parser);
597             }
598 
599             // All template code should be compiled as methods if the
600             // <xsl:apply-imports/> element was ever used in this stylesheet
601             if (!_templateInlining && (child instanceof Template)) {
602                 Template template = (Template)child;
603                 String name = "template$dot$" + template.getPosition();
604                 template.setName(parser.getQName(name));
605             }
606         }
607 
608         stable.popExcludedNamespacesContext();
609     }
610 
611     public void processModes() {
612         if (_defaultMode == null)
613             _defaultMode = new Mode(null, this, Constants.EMPTYSTRING);
614         _defaultMode.processPatterns(_keys);
615         final Enumeration modes = _modes.elements();
616         while (modes.hasMoreElements()) {
617             final Mode mode = (Mode)modes.nextElement();
618             mode.processPatterns(_keys);
619         }
620     }
621 
622     private void compileModes(ClassGenerator classGen) {
623         _defaultMode.compileApplyTemplates(classGen);
624         final Enumeration modes = _modes.elements();
625         while (modes.hasMoreElements()) {
626             final Mode mode = (Mode)modes.nextElement();
627             mode.compileApplyTemplates(classGen);
628         }
629     }
630 
631     public Mode getMode(QName modeName) {
632         if (modeName == null) {
633             if (_defaultMode == null) {
634                 _defaultMode = new Mode(null, this, Constants.EMPTYSTRING);
635             }
636             return _defaultMode;
637         }
638         else {
639             Mode mode = (Mode)_modes.get(modeName);
640             if (mode == null) {
641                 final String suffix = Integer.toString(_nextModeSerial++);
642                 _modes.put(modeName, mode = new Mode(modeName, this, suffix));
643             }
644             return mode;
645         }
646     }
647 
648     /**
649      * Type check all the children of this node.
650      */
651     public Type typeCheck(SymbolTable stable) throws TypeCheckError {
652         final int count = _globals.size();
653         for (int i = 0; i < count; i++) {
654             final VariableBase var = (VariableBase)_globals.elementAt(i);
655             var.typeCheck(stable);
656         }
657         return typeCheckContents(stable);
658     }
659 
660     /**
661      * Translate the stylesheet into JVM bytecodes.
662      */
663     public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
664         translate();
665     }
666 
667     private void addDOMField(ClassGenerator classGen) {
668         final FieldGen fgen = new FieldGen(ACC_PUBLIC,
669                                            Util.getJCRefType(DOM_INTF_SIG),
670                                            DOM_FIELD,
671                                            classGen.getConstantPool());
672         classGen.addField(fgen.getField());
673     }
674 
675     /**
676      * Add a static field
677      */
678     private void addStaticField(ClassGenerator classGen, String type,
679                                 String name)
680     {
681         final FieldGen fgen = new FieldGen(ACC_PROTECTED|ACC_STATIC,
682                                            Util.getJCRefType(type),
683                                            name,
684                                            classGen.getConstantPool());
685         classGen.addField(fgen.getField());
686 
687     }
688 
689     /**
690      * Translate the stylesheet into JVM bytecodes.
691      */
692     public void translate() {
693         _className = getXSLTC().getClassName();
694 
695         // Define a new class by extending TRANSLET_CLASS
696         final ClassGenerator classGen =
697             new ClassGenerator(_className,
698                                TRANSLET_CLASS,
699                                Constants.EMPTYSTRING,
700                                ACC_PUBLIC | ACC_SUPER,
701                                null, this);
702 
703         addDOMField(classGen);
704 
705         // Compile transform() to initialize parameters, globals & output
706         // and run the transformation
707         compileTransform(classGen);
708 
709         // Translate all non-template elements and filter out all templates
710         final Enumeration elements = elements();
711         while (elements.hasMoreElements()) {
712             Object element = elements.nextElement();
713             // xsl:template
714             if (element instanceof Template) {
715                 // Separate templates by modes
716                 final Template template = (Template)element;
717                 //_templates.addElement(template);
718                 getMode(template.getModeName()).addTemplate(template);
719             }
720             // xsl:attribute-set
721             else if (element instanceof AttributeSet) {
722                 ((AttributeSet)element).translate(classGen, null);
723             }
724             else if (element instanceof Output) {
725                 // save the element for later to pass to compileConstructor
726                 Output output = (Output)element;
727                 if (output.enabled()) _lastOutputElement = output;
728             }
729             else {
730                 // Global variables and parameters are handled elsewhere.
731                 // Other top-level non-template elements are ignored. Literal
732                 // elements outside of templates will never be output.
733             }
734         }
735 
736         checkOutputMethod();
737         processModes();
738         compileModes(classGen);
739         compileStaticInitializer(classGen);
740         compileConstructor(classGen, _lastOutputElement);
741 
742         if (!getParser().errorsFound()) {
743             getXSLTC().dumpClass(classGen.getJavaClass());
744         }
745     }
746 
747     /**
748      * Compile the namesArray, urisArray and typesArray into
749      * the static initializer. They are read-only from the
750      * translet. All translet instances can share a single
751      * copy of this informtion.
752      */
753     private void compileStaticInitializer(ClassGenerator classGen) {
754         final ConstantPoolGen cpg = classGen.getConstantPool();
755         final InstructionList il = new InstructionList();
756 
757         final MethodGenerator staticConst =
758             new MethodGenerator(ACC_PUBLIC|ACC_STATIC,
759                                 com.sun.org.apache.bcel.internal.generic.Type.VOID,
760                                 null, null, "<clinit>",
761                                 _className, il, cpg);
762 
763         addStaticField(classGen, "[" + STRING_SIG, STATIC_NAMES_ARRAY_FIELD);
764         addStaticField(classGen, "[" + STRING_SIG, STATIC_URIS_ARRAY_FIELD);
765         addStaticField(classGen, "[I", STATIC_TYPES_ARRAY_FIELD);
766         addStaticField(classGen, "[" + STRING_SIG, STATIC_NAMESPACE_ARRAY_FIELD);
767         // Create fields of type char[] that will contain literal text from
768         // the stylesheet.
769         final int charDataFieldCount = getXSLTC().getCharacterDataCount();
770         for (int i = 0; i < charDataFieldCount; i++) {
771             addStaticField(classGen, STATIC_CHAR_DATA_FIELD_SIG,
772                            STATIC_CHAR_DATA_FIELD+i);
773         }
774 
775         // Put the names array into the translet - used for dom/translet mapping
776         final Vector namesIndex = getXSLTC().getNamesIndex();
777         int size = namesIndex.size();
778         String[] namesArray = new String[size];
779         String[] urisArray = new String[size];
780         int[] typesArray = new int[size];
781 
782         int index;
783         for (int i = 0; i < size; i++) {
784             String encodedName = (String)namesIndex.elementAt(i);
785             if ((index = encodedName.lastIndexOf(':')) > -1) {
786                 urisArray[i] = encodedName.substring(0, index);
787             }
788 
789             index = index + 1;
790             if (encodedName.charAt(index) == '@') {
791                 typesArray[i] = DTM.ATTRIBUTE_NODE;
792                 index++;
793             } else if (encodedName.charAt(index) == '?') {
794                 typesArray[i] = DTM.NAMESPACE_NODE;
795                 index++;
796             } else {
797                 typesArray[i] = DTM.ELEMENT_NODE;
798             }
799 
800             if (index == 0) {
801                 namesArray[i] = encodedName;
802             }
803             else {
804                 namesArray[i] = encodedName.substring(index);
805             }
806         }
807 
808         staticConst.markChunkStart();
809         il.append(new PUSH(cpg, size));
810         il.append(new ANEWARRAY(cpg.addClass(STRING)));
811         int namesArrayRef = cpg.addFieldref(_className,
812                                             STATIC_NAMES_ARRAY_FIELD,
813                                             NAMES_INDEX_SIG);
814         il.append(new PUTSTATIC(namesArrayRef));
815         staticConst.markChunkEnd();
816 
817         for (int i = 0; i < size; i++) {
818             final String name = namesArray[i];
819             staticConst.markChunkStart();
820             il.append(new GETSTATIC(namesArrayRef));
821             il.append(new PUSH(cpg, i));
822             il.append(new PUSH(cpg, name));
823             il.append(AASTORE);
824             staticConst.markChunkEnd();
825         }
826 
827         staticConst.markChunkStart();
828         il.append(new PUSH(cpg, size));
829         il.append(new ANEWARRAY(cpg.addClass(STRING)));
830         int urisArrayRef = cpg.addFieldref(_className,
831                                            STATIC_URIS_ARRAY_FIELD,
832                                            URIS_INDEX_SIG);
833         il.append(new PUTSTATIC(urisArrayRef));
834         staticConst.markChunkEnd();
835 
836         for (int i = 0; i < size; i++) {
837             final String uri = urisArray[i];
838             staticConst.markChunkStart();
839             il.append(new GETSTATIC(urisArrayRef));
840             il.append(new PUSH(cpg, i));
841             il.append(new PUSH(cpg, uri));
842             il.append(AASTORE);
843             staticConst.markChunkEnd();
844         }
845 
846         staticConst.markChunkStart();
847         il.append(new PUSH(cpg, size));
848         il.append(new NEWARRAY(BasicType.INT));
849         int typesArrayRef = cpg.addFieldref(_className,
850                                             STATIC_TYPES_ARRAY_FIELD,
851                                             TYPES_INDEX_SIG);
852         il.append(new PUTSTATIC(typesArrayRef));
853         staticConst.markChunkEnd();
854 
855         for (int i = 0; i < size; i++) {
856             final int nodeType = typesArray[i];
857             staticConst.markChunkStart();
858             il.append(new GETSTATIC(typesArrayRef));
859             il.append(new PUSH(cpg, i));
860             il.append(new PUSH(cpg, nodeType));
861             il.append(IASTORE);
862         }
863 
864         // Put the namespace names array into the translet
865         final Vector namespaces = getXSLTC().getNamespaceIndex();
866         staticConst.markChunkStart();
867         il.append(new PUSH(cpg, namespaces.size()));
868         il.append(new ANEWARRAY(cpg.addClass(STRING)));
869         int namespaceArrayRef = cpg.addFieldref(_className,
870                                                 STATIC_NAMESPACE_ARRAY_FIELD,
871                                                 NAMESPACE_INDEX_SIG);
872         il.append(new PUTSTATIC(namespaceArrayRef));
873         staticConst.markChunkEnd();
874 
875         for (int i = 0; i < namespaces.size(); i++) {
876             final String ns = (String)namespaces.elementAt(i);
877             staticConst.markChunkStart();
878             il.append(new GETSTATIC(namespaceArrayRef));
879             il.append(new PUSH(cpg, i));
880             il.append(new PUSH(cpg, ns));
881             il.append(AASTORE);
882             staticConst.markChunkEnd();
883         }
884 
885         // Grab all the literal text in the stylesheet and put it in a char[]
886         final int charDataCount = getXSLTC().getCharacterDataCount();
887         final int toCharArray = cpg.addMethodref(STRING, "toCharArray", "()[C");
888         for (int i = 0; i < charDataCount; i++) {
889             staticConst.markChunkStart();
890             il.append(new PUSH(cpg, getXSLTC().getCharacterData(i)));
891             il.append(new INVOKEVIRTUAL(toCharArray));
892             il.append(new PUTSTATIC(cpg.addFieldref(_className,
893                                                STATIC_CHAR_DATA_FIELD+i,
894                                                STATIC_CHAR_DATA_FIELD_SIG)));
895             staticConst.markChunkEnd();
896         }
897 
898         il.append(RETURN);
899 
900         classGen.addMethod(staticConst);
901 
902     }
903 
904     /**
905      * Compile the translet's constructor
906      */
907     private void compileConstructor(ClassGenerator classGen, Output output) {
908 
909         final ConstantPoolGen cpg = classGen.getConstantPool();
910         final InstructionList il = new InstructionList();
911 
912         final MethodGenerator constructor =
913             new MethodGenerator(ACC_PUBLIC,
914                                 com.sun.org.apache.bcel.internal.generic.Type.VOID,
915                                 null, null, "<init>",
916                                 _className, il, cpg);
917 
918         // Call the constructor in the AbstractTranslet superclass
919         il.append(classGen.loadTranslet());
920         il.append(new INVOKESPECIAL(cpg.addMethodref(TRANSLET_CLASS,
921                                                      "<init>", "()V")));
922 
923         constructor.markChunkStart();
924         il.append(classGen.loadTranslet());
925         il.append(new GETSTATIC(cpg.addFieldref(_className,
926                                                 STATIC_NAMES_ARRAY_FIELD,
927                                                 NAMES_INDEX_SIG)));
928         il.append(new PUTFIELD(cpg.addFieldref(TRANSLET_CLASS,
929                                                NAMES_INDEX,
930                                                NAMES_INDEX_SIG)));
931 
932         il.append(classGen.loadTranslet());
933         il.append(new GETSTATIC(cpg.addFieldref(_className,
934                                                 STATIC_URIS_ARRAY_FIELD,
935                                                 URIS_INDEX_SIG)));
936         il.append(new PUTFIELD(cpg.addFieldref(TRANSLET_CLASS,
937                                                URIS_INDEX,
938                                                URIS_INDEX_SIG)));
939         constructor.markChunkEnd();
940 
941         constructor.markChunkStart();
942         il.append(classGen.loadTranslet());
943         il.append(new GETSTATIC(cpg.addFieldref(_className,
944                                                 STATIC_TYPES_ARRAY_FIELD,
945                                                 TYPES_INDEX_SIG)));
946         il.append(new PUTFIELD(cpg.addFieldref(TRANSLET_CLASS,
947                                                TYPES_INDEX,
948                                                TYPES_INDEX_SIG)));
949         constructor.markChunkEnd();
950 
951         constructor.markChunkStart();
952         il.append(classGen.loadTranslet());
953         il.append(new GETSTATIC(cpg.addFieldref(_className,
954                                                 STATIC_NAMESPACE_ARRAY_FIELD,
955                                                 NAMESPACE_INDEX_SIG)));
956         il.append(new PUTFIELD(cpg.addFieldref(TRANSLET_CLASS,
957                                                NAMESPACE_INDEX,
958                                                NAMESPACE_INDEX_SIG)));
959         constructor.markChunkEnd();
960 
961         constructor.markChunkStart();
962         il.append(classGen.loadTranslet());
963         il.append(new PUSH(cpg, AbstractTranslet.CURRENT_TRANSLET_VERSION));
964         il.append(new PUTFIELD(cpg.addFieldref(TRANSLET_CLASS,
965                                                TRANSLET_VERSION_INDEX,
966                                                TRANSLET_VERSION_INDEX_SIG)));
967         constructor.markChunkEnd();
968 
969         if (_hasIdCall) {
970             constructor.markChunkStart();
971             il.append(classGen.loadTranslet());
972             il.append(new PUSH(cpg, Boolean.TRUE));
973             il.append(new PUTFIELD(cpg.addFieldref(TRANSLET_CLASS,
974                                                    HASIDCALL_INDEX,
975                                                    HASIDCALL_INDEX_SIG)));
976             constructor.markChunkEnd();
977         }
978 
979         // Compile in code to set the output configuration from <xsl:output>
980         if (output != null) {
981             // Set all the output settings files in the translet
982             constructor.markChunkStart();
983             output.translate(classGen, constructor);
984             constructor.markChunkEnd();
985         }
986 
987         // Compile default decimal formatting symbols.
988         // This is an implicit, nameless xsl:decimal-format top-level element.
989         if (_numberFormattingUsed) {
990             constructor.markChunkStart();
991             DecimalFormatting.translateDefaultDFS(classGen, constructor);
992             constructor.markChunkEnd();
993         }
994 
995         il.append(RETURN);
996 
997         classGen.addMethod(constructor);
998     }
999 
1000     /**
1001      * Compile a topLevel() method into the output class. This method is
1002      * called from transform() to handle all non-template top-level elements.
1003      * Returns the signature of the topLevel() method.
1004      *
1005      * Global variables/params and keys are first sorted to resolve
1006      * dependencies between them. The XSLT 1.0 spec does not allow a key
1007      * to depend on a variable. However, for compatibility with Xalan
1008      * interpretive, that type of dependency is allowed. Note also that
1009      * the buildKeys() method is still generated as it is used by the
1010      * LoadDocument class, but it no longer called from transform().
1011      */
1012     private String compileTopLevel(ClassGenerator classGen) {
1013 
1014         final ConstantPoolGen cpg = classGen.getConstantPool();
1015 
1016         final com.sun.org.apache.bcel.internal.generic.Type[] argTypes = {
1017             Util.getJCRefType(DOM_INTF_SIG),
1018             Util.getJCRefType(NODE_ITERATOR_SIG),
1019             Util.getJCRefType(TRANSLET_OUTPUT_SIG)
1020         };
1021 
1022         final String[] argNames = {
1023             DOCUMENT_PNAME, ITERATOR_PNAME, TRANSLET_OUTPUT_PNAME
1024         };
1025 
1026         final InstructionList il = new InstructionList();
1027 
1028         final MethodGenerator toplevel =
1029             new MethodGenerator(ACC_PUBLIC,
1030                                 com.sun.org.apache.bcel.internal.generic.Type.VOID,
1031                                 argTypes, argNames,
1032                                 "topLevel", _className, il,
1033                                 classGen.getConstantPool());
1034 
1035         toplevel.addException("com.sun.org.apache.xalan.internal.xsltc.TransletException");
1036 
1037         // Define and initialize 'current' variable with the root node
1038         final LocalVariableGen current =
1039             toplevel.addLocalVariable("current",
1040                                       com.sun.org.apache.bcel.internal.generic.Type.INT,
1041                                       null, null);
1042 
1043         final int setFilter = cpg.addInterfaceMethodref(DOM_INTF,
1044                                "setFilter",
1045                                "(Lcom/sun/org/apache/xalan/internal/xsltc/StripFilter;)V");
1046 
1047         final int gitr = cpg.addInterfaceMethodref(DOM_INTF,
1048                                                         "getIterator",
1049                                                         "()"+NODE_ITERATOR_SIG);
1050         il.append(toplevel.loadDOM());
1051         il.append(new INVOKEINTERFACE(gitr, 1));
1052         il.append(toplevel.nextNode());
1053         current.setStart(il.append(new ISTORE(current.getIndex())));
1054 
1055         // Create a new list containing variables/params + keys
1056         Vector varDepElements = new Vector(_globals);
1057         Enumeration elements = elements();
1058         while (elements.hasMoreElements()) {
1059             final Object element = elements.nextElement();
1060             if (element instanceof Key) {
1061                 varDepElements.add(element);
1062             }
1063         }
1064 
1065         // Determine a partial order for the variables/params and keys
1066         varDepElements = resolveDependencies(varDepElements);
1067 
1068         // Translate vars/params and keys in the right order
1069         final int count = varDepElements.size();
1070         for (int i = 0; i < count; i++) {
1071             final TopLevelElement tle = (TopLevelElement) varDepElements.elementAt(i);
1072             tle.translate(classGen, toplevel);
1073             if (tle instanceof Key) {
1074                 final Key key = (Key) tle;
1075                 _keys.put(key.getName(), key);
1076             }
1077         }
1078 
1079         // Compile code for other top-level elements
1080         Vector whitespaceRules = new Vector();
1081         elements = elements();
1082         while (elements.hasMoreElements()) {
1083             final Object element = elements.nextElement();
1084             // xsl:decimal-format
1085             if (element instanceof DecimalFormatting) {
1086                 ((DecimalFormatting)element).translate(classGen,toplevel);
1087             }
1088             // xsl:strip/preserve-space
1089             else if (element instanceof Whitespace) {
1090                 whitespaceRules.addAll(((Whitespace)element).getRules());
1091             }
1092         }
1093 
1094         // Translate all whitespace strip/preserve rules
1095         if (whitespaceRules.size() > 0) {
1096             Whitespace.translateRules(whitespaceRules,classGen);
1097         }
1098 
1099         if (classGen.containsMethod(STRIP_SPACE, STRIP_SPACE_PARAMS) != null) {
1100             il.append(toplevel.loadDOM());
1101             il.append(classGen.loadTranslet());
1102             il.append(new INVOKEINTERFACE(setFilter, 2));
1103         }
1104 
1105         il.append(RETURN);
1106 
1107         // Compute max locals + stack and add method to class
1108         classGen.addMethod(toplevel);
1109 
1110         return("("+DOM_INTF_SIG+NODE_ITERATOR_SIG+TRANSLET_OUTPUT_SIG+")V");
1111     }
1112 
1113     /**
1114      * This method returns a vector with variables/params and keys in the
1115      * order in which they are to be compiled for initialization. The order
1116      * is determined by analyzing the dependencies between them. The XSLT 1.0
1117      * spec does not allow a key to depend on a variable. However, for
1118      * compatibility with Xalan interpretive, that type of dependency is
1119      * allowed and, therefore, consider to determine the partial order.
1120      */
1121     private Vector resolveDependencies(Vector input) {
1122         /* DEBUG CODE - INGORE
1123         for (int i = 0; i < input.size(); i++) {
1124             final TopLevelElement e = (TopLevelElement) input.elementAt(i);
1125             System.out.println("e = " + e + " depends on:");
1126             Vector dep = e.getDependencies();
1127             for (int j = 0; j < (dep != null ? dep.size() : 0); j++) {
1128                 System.out.println("\t" + dep.elementAt(j));
1129             }
1130         }
1131         System.out.println("=================================");
1132         */
1133 
1134         Vector result = new Vector();
1135         while (input.size() > 0) {
1136             boolean changed = false;
1137             for (int i = 0; i < input.size(); ) {
1138                 final TopLevelElement vde = (TopLevelElement) input.elementAt(i);
1139                 final Vector dep = vde.getDependencies();
1140                 if (dep == null || result.containsAll(dep)) {
1141                     result.addElement(vde);
1142                     input.remove(i);
1143                     changed = true;
1144                 }
1145                 else {
1146                     i++;
1147                 }
1148             }
1149 
1150             // If nothing was changed in this pass then we have a circular ref
1151             if (!changed) {
1152                 ErrorMsg err = new ErrorMsg(ErrorMsg.CIRCULAR_VARIABLE_ERR,
1153                                             input.toString(), this);
1154                 getParser().reportError(Constants.ERROR, err);
1155                 return(result);
1156             }
1157         }
1158 
1159         /* DEBUG CODE - INGORE
1160         System.out.println("=================================");
1161         for (int i = 0; i < result.size(); i++) {
1162             final TopLevelElement e = (TopLevelElement) result.elementAt(i);
1163             System.out.println("e = " + e);
1164         }
1165         */
1166 
1167         return result;
1168     }
1169 
1170     /**
1171      * Compile a buildKeys() method into the output class. Note that keys
1172      * for the input document are created in topLevel(), not in this method.
1173      * However, we still need this method to create keys for documents loaded
1174      * via the XPath document() function.
1175      */
1176     private String compileBuildKeys(ClassGenerator classGen) {
1177         final ConstantPoolGen cpg = classGen.getConstantPool();
1178 
1179         final com.sun.org.apache.bcel.internal.generic.Type[] argTypes = {
1180             Util.getJCRefType(DOM_INTF_SIG),
1181             Util.getJCRefType(NODE_ITERATOR_SIG),
1182             Util.getJCRefType(TRANSLET_OUTPUT_SIG),
1183             com.sun.org.apache.bcel.internal.generic.Type.INT
1184         };
1185 
1186         final String[] argNames = {
1187             DOCUMENT_PNAME, ITERATOR_PNAME, TRANSLET_OUTPUT_PNAME, "current"
1188         };
1189 
1190         final InstructionList il = new InstructionList();
1191 
1192         final MethodGenerator buildKeys =
1193             new MethodGenerator(ACC_PUBLIC,
1194                                 com.sun.org.apache.bcel.internal.generic.Type.VOID,
1195                                 argTypes, argNames,
1196                                 "buildKeys", _className, il,
1197                                 classGen.getConstantPool());
1198 
1199         buildKeys.addException("com.sun.org.apache.xalan.internal.xsltc.TransletException");
1200 
1201         final Enumeration elements = elements();
1202         while (elements.hasMoreElements()) {
1203             // xsl:key
1204             final Object element = elements.nextElement();
1205             if (element instanceof Key) {
1206                 final Key key = (Key)element;
1207                 key.translate(classGen, buildKeys);
1208                 _keys.put(key.getName(),key);
1209             }
1210         }
1211 
1212         il.append(RETURN);
1213 
1214         // Compute max locals + stack and add method to class
1215         buildKeys.stripAttributes(true);
1216         buildKeys.setMaxLocals();
1217         buildKeys.setMaxStack();
1218         buildKeys.removeNOPs();
1219 
1220         classGen.addMethod(buildKeys.getMethod());
1221 
1222         return("("+DOM_INTF_SIG+NODE_ITERATOR_SIG+TRANSLET_OUTPUT_SIG+"I)V");
1223     }
1224 
1225     /**
1226      * Compile transform() into the output class. This method is used to
1227      * initialize global variables and global parameters. The current node
1228      * is set to be the document's root node.
1229      */
1230     private void compileTransform(ClassGenerator classGen) {
1231         final ConstantPoolGen cpg = classGen.getConstantPool();
1232 
1233         /*
1234          * Define the the method transform with the following signature:
1235          * void transform(DOM, NodeIterator, HandlerBase)
1236          */
1237         final com.sun.org.apache.bcel.internal.generic.Type[] argTypes =
1238             new com.sun.org.apache.bcel.internal.generic.Type[3];
1239         argTypes[0] = Util.getJCRefType(DOM_INTF_SIG);
1240         argTypes[1] = Util.getJCRefType(NODE_ITERATOR_SIG);
1241         argTypes[2] = Util.getJCRefType(TRANSLET_OUTPUT_SIG);
1242 
1243         final String[] argNames = new String[3];
1244         argNames[0] = DOCUMENT_PNAME;
1245         argNames[1] = ITERATOR_PNAME;
1246         argNames[2] = TRANSLET_OUTPUT_PNAME;
1247 
1248         final InstructionList il = new InstructionList();
1249         final MethodGenerator transf =
1250             new MethodGenerator(ACC_PUBLIC,
1251                                 com.sun.org.apache.bcel.internal.generic.Type.VOID,
1252                                 argTypes, argNames,
1253                                 "transform",
1254                                 _className,
1255                                 il,
1256                                 classGen.getConstantPool());
1257         transf.addException("com.sun.org.apache.xalan.internal.xsltc.TransletException");
1258 
1259         // Define and initialize current with the root node
1260         final LocalVariableGen current =
1261             transf.addLocalVariable("current",
1262                                     com.sun.org.apache.bcel.internal.generic.Type.INT,
1263                                     null, null);
1264         final String applyTemplatesSig = classGen.getApplyTemplatesSig();
1265         final int applyTemplates = cpg.addMethodref(getClassName(),
1266                                                     "applyTemplates",
1267                                                     applyTemplatesSig);
1268         final int domField = cpg.addFieldref(getClassName(),
1269                                              DOM_FIELD,
1270                                              DOM_INTF_SIG);
1271 
1272         // push translet for PUTFIELD
1273         il.append(classGen.loadTranslet());
1274         // prepare appropriate DOM implementation
1275 
1276         if (isMultiDocument()) {
1277             il.append(new NEW(cpg.addClass(MULTI_DOM_CLASS)));
1278             il.append(DUP);
1279         }
1280 
1281         il.append(classGen.loadTranslet());
1282         il.append(transf.loadDOM());
1283         il.append(new INVOKEVIRTUAL(cpg.addMethodref(TRANSLET_CLASS,
1284                                                      "makeDOMAdapter",
1285                                                      "("+DOM_INTF_SIG+")"+
1286                                                      DOM_ADAPTER_SIG)));
1287         // DOMAdapter is on the stack
1288 
1289         if (isMultiDocument()) {
1290             final int init = cpg.addMethodref(MULTI_DOM_CLASS,
1291                                               "<init>",
1292                                               "("+DOM_INTF_SIG+")V");
1293             il.append(new INVOKESPECIAL(init));
1294             // MultiDOM is on the stack
1295         }
1296 
1297         //store to _dom variable
1298         il.append(new PUTFIELD(domField));
1299 
1300         // continue with globals initialization
1301         final int gitr = cpg.addInterfaceMethodref(DOM_INTF,
1302                                                         "getIterator",
1303                                                         "()"+NODE_ITERATOR_SIG);
1304         il.append(transf.loadDOM());
1305         il.append(new INVOKEINTERFACE(gitr, 1));
1306         il.append(transf.nextNode());
1307         current.setStart(il.append(new ISTORE(current.getIndex())));
1308 
1309         // Transfer the output settings to the output post-processor
1310         il.append(classGen.loadTranslet());
1311         il.append(transf.loadHandler());
1312         final int index = cpg.addMethodref(TRANSLET_CLASS,
1313                                            "transferOutputSettings",
1314                                            "("+OUTPUT_HANDLER_SIG+")V");
1315         il.append(new INVOKEVIRTUAL(index));
1316 
1317         /*
1318          * Compile buildKeys() method. Note that this method is not
1319          * invoked here as keys for the input document are now created
1320          * in topLevel(). However, this method is still needed by the
1321          * LoadDocument class.
1322          */
1323         final String keySig = compileBuildKeys(classGen);
1324         final int keyIdx = cpg.addMethodref(getClassName(),
1325                                                "buildKeys", keySig);
1326 
1327         // Look for top-level elements that need handling
1328         final Enumeration toplevel = elements();
1329         if (_globals.size() > 0 || toplevel.hasMoreElements()) {
1330             // Compile method for handling top-level elements
1331             final String topLevelSig = compileTopLevel(classGen);
1332             // Get a reference to that method
1333             final int topLevelIdx = cpg.addMethodref(getClassName(),
1334                                                      "topLevel",
1335                                                      topLevelSig);
1336             // Push all parameters on the stack and call topLevel()
1337             il.append(classGen.loadTranslet()); // The 'this' pointer
1338             il.append(classGen.loadTranslet());
1339             il.append(new GETFIELD(domField));  // The DOM reference
1340             il.append(transf.loadIterator());
1341             il.append(transf.loadHandler());    // The output handler
1342             il.append(new INVOKEVIRTUAL(topLevelIdx));
1343         }
1344 
1345         // start document
1346         il.append(transf.loadHandler());
1347         il.append(transf.startDocument());
1348 
1349         // push first arg for applyTemplates
1350         il.append(classGen.loadTranslet());
1351         // push translet for GETFIELD to get DOM arg
1352         il.append(classGen.loadTranslet());
1353         il.append(new GETFIELD(domField));
1354         // push remaining 2 args
1355         il.append(transf.loadIterator());
1356         il.append(transf.loadHandler());
1357         il.append(new INVOKEVIRTUAL(applyTemplates));
1358         // endDocument
1359         il.append(transf.loadHandler());
1360         il.append(transf.endDocument());
1361 
1362         il.append(RETURN);
1363 
1364         // Compute max locals + stack and add method to class
1365         classGen.addMethod(transf);
1366 
1367     }
1368 
1369     /**
1370      * Peephole optimization: Remove sequences of [ALOAD, POP].
1371      */
1372     private void peepHoleOptimization(MethodGenerator methodGen) {
1373         final String pattern = "`aload'`pop'`instruction'";
1374         final InstructionList il = methodGen.getInstructionList();
1375         final InstructionFinder find = new InstructionFinder(il);
1376         for(Iterator iter=find.search(pattern); iter.hasNext(); ) {
1377             InstructionHandle[] match = (InstructionHandle[])iter.next();
1378             try {
1379                 il.delete(match[0], match[1]);
1380             }
1381             catch (TargetLostException e) {
1382                 // TODO: move target down into the list
1383             }
1384         }
1385     }
1386 
1387     public int addParam(Param param) {
1388         _globals.addElement(param);
1389         return _globals.size() - 1;
1390     }
1391 
1392     public int addVariable(Variable global) {
1393         _globals.addElement(global);
1394         return _globals.size() - 1;
1395     }
1396 
1397     public void display(int indent) {
1398         indent(indent);
1399         Util.println("Stylesheet");
1400         displayContents(indent + IndentIncrement);
1401     }
1402 
1403     // do we need this wrapper ?????
1404     public String getNamespace(String prefix) {
1405         return lookupNamespace(prefix);
1406     }
1407 
1408     public String getClassName() {
1409         return _className;
1410     }
1411 
1412     public Vector getTemplates() {
1413         return _templates;
1414     }
1415 
1416     public Vector getAllValidTemplates() {
1417         // Return templates if no imported/included stylesheets
1418         if (_includedStylesheets == null) {
1419             return _templates;
1420         }
1421 
1422         // Is returned value cached?
1423         if (_allValidTemplates == null) {
1424            Vector templates = new Vector();
1425            templates.addAll(_templates);
1426             int size = _includedStylesheets.size();
1427             for (int i = 0; i < size; i++) {
1428                 Stylesheet included =(Stylesheet)_includedStylesheets.elementAt(i);
1429                 templates.addAll(included.getAllValidTemplates());
1430             }
1431             //templates.addAll(_templates);
1432 
1433             // Cache results in top-level stylesheet only
1434             if (_parentStylesheet != null) {
1435                 return templates;
1436             }
1437             _allValidTemplates = templates;
1438          }
1439 
1440         return _allValidTemplates;
1441     }
1442 
1443     protected void addTemplate(Template template) {
1444         _templates.addElement(template);
1445     }
1446 }