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