1 /* 2 * Copyright (c) 2007, 2017, 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 24 package com.sun.org.apache.xalan.internal.xsltc.compiler; 25 26 import com.sun.org.apache.bcel.internal.generic.ANEWARRAY; 27 import com.sun.org.apache.bcel.internal.generic.BasicType; 28 import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen; 29 import com.sun.org.apache.bcel.internal.generic.FieldGen; 30 import com.sun.org.apache.bcel.internal.generic.GETFIELD; 31 import com.sun.org.apache.bcel.internal.generic.GETSTATIC; 32 import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE; 33 import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL; 34 import com.sun.org.apache.bcel.internal.generic.INVOKESTATIC; 35 import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL; 36 import com.sun.org.apache.bcel.internal.generic.ISTORE; 37 import com.sun.org.apache.bcel.internal.generic.InstructionHandle; 38 import com.sun.org.apache.bcel.internal.generic.InstructionList; 39 import com.sun.org.apache.bcel.internal.generic.LocalVariableGen; 40 import com.sun.org.apache.bcel.internal.generic.NEW; 41 import com.sun.org.apache.bcel.internal.generic.NEWARRAY; 42 import com.sun.org.apache.bcel.internal.generic.PUSH; 43 import com.sun.org.apache.bcel.internal.generic.PUTFIELD; 44 import com.sun.org.apache.bcel.internal.generic.PUTSTATIC; 45 import com.sun.org.apache.bcel.internal.generic.TargetLostException; 46 import com.sun.org.apache.bcel.internal.util.InstructionFinder; 47 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator; 48 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg; 49 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator; 50 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type; 51 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError; 52 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util; 53 import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet; 54 import com.sun.org.apache.xml.internal.dtm.DTM; 55 import com.sun.org.apache.xml.internal.utils.SystemIDResolver; 56 import java.util.ArrayList; 57 import java.util.HashMap; 58 import java.util.Iterator; 59 import java.util.List; 60 import java.util.Map; 61 import java.util.Properties; 62 import java.util.StringTokenizer; 63 64 /** 65 * @author Jacek Ambroziak 66 * @author Santiago Pericas-Geertsen 67 * @author Morten Jorgensen 68 * @LastModified: Oct 2017 69 */ 70 public final class Stylesheet extends SyntaxTreeNode { 71 72 /** 73 * XSLT version defined in the stylesheet. 74 */ 75 private String _version; 76 77 /** 78 * Internal name of this stylesheet used as a key into the symbol table. 79 */ 80 private QName _name; 81 82 /** 83 * A URI that represents the system ID for this stylesheet. 84 */ 85 private String _systemId; 86 87 /** 88 * A reference to the parent stylesheet or null if topmost. 89 */ 90 private Stylesheet _parentStylesheet; 91 92 /** 93 * Contains global variables and parameters defined in the stylesheet. 94 */ 95 private List<VariableBase> _globals = new ArrayList<>(); 96 97 /** 98 * Used to cache the result returned by <code>hasLocalParams()</code>. 99 */ 100 private Boolean _hasLocalParams = null; 101 102 /** 103 * The name of the class being generated. 104 */ 105 private String _className; 106 107 /** 108 * Contains all templates defined in this stylesheet 109 */ 110 private final List<Template> _templates = new ArrayList<>(); 111 112 /** 113 * Used to cache result of <code>getAllValidTemplates()</code>. Only 114 * set in top-level stylesheets that include/import other stylesheets. 115 */ 116 private List<Template> _allValidTemplates = null; 117 118 /** 119 * Counter to generate unique mode suffixes. 120 */ 121 private int _nextModeSerial = 1; 122 123 /** 124 * Mapping between mode names and Mode instances. 125 */ 126 private final Map<String, Mode> _modes = new HashMap<>(); 127 128 /** 129 * A reference to the default Mode object. 130 */ 131 private Mode _defaultMode; 132 133 /** 134 * Mapping between extension URIs and their prefixes. 135 */ 136 private final Map<String, String> _extensions = new HashMap<>(); 137 138 /** 139 * Reference to the stylesheet from which this stylesheet was 140 * imported (if any). 141 */ 142 public Stylesheet _importedFrom = null; 143 144 /** 145 * Reference to the stylesheet from which this stylesheet was 146 * included (if any). 147 */ 148 public Stylesheet _includedFrom = null; 149 150 /** 151 * Array of all the stylesheets imported or included from this one. 152 */ 153 private List<Stylesheet> _includedStylesheets = null; 154 155 /** 156 * Import precendence for this stylesheet. 157 */ 158 private int _importPrecedence = 1; 159 160 /** 161 * Minimum precendence of any descendant stylesheet by inclusion or 162 * importation. 163 */ 164 private int _minimumDescendantPrecedence = -1; 165 166 /** 167 * Mapping between key names and Key objects (needed by Key/IdPattern). 168 */ 169 private Map<String, Key> _keys = new HashMap<>(); 170 171 /** 172 * A reference to the SourceLoader set by the user (a URIResolver 173 * if the JAXP API is being used). 174 */ 175 private SourceLoader _loader = null; 176 177 /** 178 * Flag indicating if format-number() is called. 179 */ 180 private boolean _numberFormattingUsed = false; 181 182 /** 183 * Flag indicating if this is a simplified stylesheets. A template 184 * matching on "/" must be added in this case. 185 */ 186 private boolean _simplified = false; 187 188 /** 189 * Flag indicating if multi-document support is needed. 190 */ 191 private boolean _multiDocument = false; 192 193 /** 194 * Flag indicating if nodset() is called. 195 */ 196 private boolean _callsNodeset = false; 197 198 /** 199 * Flag indicating if id() is called. 200 */ 201 private boolean _hasIdCall = false; 202 203 /** 204 * Set to true to enable template inlining optimization. 205 * @see XSLTC#_templateInlining 206 */ 207 private boolean _templateInlining = false; 208 209 /** 210 * A reference to the last xsl:output object found in the styleshet. 211 */ 212 private Output _lastOutputElement = null; 213 214 /** 215 * Output properties for this stylesheet. 216 */ 217 private Properties _outputProperties = null; 218 219 /** 220 * Output method for this stylesheet (must be set to one of 221 * the constants defined below). 222 */ 223 private int _outputMethod = UNKNOWN_OUTPUT; 224 225 // Output method constants 226 public static final int UNKNOWN_OUTPUT = 0; 227 public static final int XML_OUTPUT = 1; 228 public static final int HTML_OUTPUT = 2; 229 public static final int TEXT_OUTPUT = 3; 230 231 /** 232 * Return the output method 233 */ 234 public int getOutputMethod() { 235 return _outputMethod; 236 } 237 238 /** 239 * Check and set the output method 240 */ 241 private void checkOutputMethod() { 242 if (_lastOutputElement != null) { 243 String method = _lastOutputElement.getOutputMethod(); 244 if (method != null) { 245 if (method.equals("xml")) 246 _outputMethod = XML_OUTPUT; 247 else if (method.equals("html")) 248 _outputMethod = HTML_OUTPUT; 249 else if (method.equals("text")) 250 _outputMethod = TEXT_OUTPUT; 251 } 252 } 253 } 254 255 public boolean getTemplateInlining() { 256 return _templateInlining; 257 } 258 259 public void setTemplateInlining(boolean flag) { 260 _templateInlining = flag; 261 } 262 263 public boolean isSimplified() { 264 return(_simplified); 265 } 266 267 public void setSimplified() { 268 _simplified = true; 269 } 270 271 public void setHasIdCall(boolean flag) { 272 _hasIdCall = flag; 273 } 274 275 public void setOutputProperty(String key, String value) { 276 if (_outputProperties == null) { 277 _outputProperties = new Properties(); 278 } 279 _outputProperties.setProperty(key, value); 280 } 281 282 public void setOutputProperties(Properties props) { 283 _outputProperties = props; 284 } 285 286 public Properties getOutputProperties() { 287 return _outputProperties; 288 } 289 290 public Output getLastOutputElement() { 291 return _lastOutputElement; 292 } 293 294 public void setMultiDocument(boolean flag) { 295 _multiDocument = flag; 296 } 297 298 public boolean isMultiDocument() { 299 return _multiDocument; 300 } 301 302 public void setCallsNodeset(boolean flag) { 303 if (flag) setMultiDocument(flag); 304 _callsNodeset = flag; 305 } 306 307 public boolean callsNodeset() { 308 return _callsNodeset; 309 } 310 311 public void numberFormattingUsed() { 312 _numberFormattingUsed = true; 313 /* 314 * Fix for bug 23046, if the stylesheet is included, set the 315 * numberFormattingUsed flag to the parent stylesheet too. 316 * AbstractTranslet.addDecimalFormat() will be inlined once for the 317 * outer most stylesheet. 318 */ 319 Stylesheet parent = getParentStylesheet(); 320 if (null != parent) parent.numberFormattingUsed(); 321 } 322 323 public void setImportPrecedence(final int precedence) { 324 // Set import precedence for this stylesheet 325 _importPrecedence = precedence; 326 327 // Set import precedence for all included stylesheets 328 final Iterator<SyntaxTreeNode> elements = elements(); 329 while (elements.hasNext()) { 330 SyntaxTreeNode child = elements.next(); 331 if (child instanceof Include) { 332 Stylesheet included = ((Include)child).getIncludedStylesheet(); 333 if (included != null && included._includedFrom == this) { 334 included.setImportPrecedence(precedence); 335 } 336 } 337 } 338 339 // Set import precedence for the stylesheet that imported this one 340 if (_importedFrom != null) { 341 if (_importedFrom.getImportPrecedence() < precedence) { 342 final Parser parser = getParser(); 343 final int nextPrecedence = parser.getNextImportPrecedence(); 344 _importedFrom.setImportPrecedence(nextPrecedence); 345 } 346 } 347 // Set import precedence for the stylesheet that included this one 348 else if (_includedFrom != null) { 349 if (_includedFrom.getImportPrecedence() != precedence) 350 _includedFrom.setImportPrecedence(precedence); 351 } 352 } 353 354 public int getImportPrecedence() { 355 return _importPrecedence; 356 } 357 358 /** 359 * Get the minimum of the precedence of this stylesheet, any stylesheet 360 * imported by this stylesheet and any include/import descendant of this 361 * stylesheet. 362 */ 363 public int getMinimumDescendantPrecedence() { 364 if (_minimumDescendantPrecedence == -1) { 365 // Start with precedence of current stylesheet as a basis. 366 int min = getImportPrecedence(); 367 368 // Recursively examine all imported/included stylesheets. 369 final int inclImpCount = (_includedStylesheets != null) 370 ? _includedStylesheets.size() 371 : 0; 372 373 for (int i = 0; i < inclImpCount; i++) { 374 int prec = (_includedStylesheets.get(i)).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 ArrayList<>(); 424 } 425 _includedStylesheets.add(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 List<Template> templates = getAllValidTemplates(); 465 final int n = templates.size(); 466 for (int i = 0; i < n; i++) { 467 final Template template = templates.get(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 = _globals.get(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.add(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 List<String> 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 = namesIndex.get(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 List<String> 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 = namespaces.get(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 List<SyntaxTreeNode> varDepElements = new ArrayList<>(_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.get(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 List<Whitespace.WhitespaceRule> whitespaceRules = new ArrayList<>(); 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 List<SyntaxTreeNode> resolveDependencies(List<SyntaxTreeNode> input) { 1119 List<SyntaxTreeNode> result = new ArrayList<>(); 1120 while (input.size() > 0) { 1121 boolean changed = false; 1122 for (int i = 0; i < input.size(); ) { 1123 final TopLevelElement vde = (TopLevelElement) input.get(i); 1124 final List<SyntaxTreeNode> dep = vde.getDependencies(); 1125 if (dep == null || result.containsAll(dep)) { 1126 result.add(vde); 1127 input.remove(i); 1128 changed = true; 1129 } 1130 else { 1131 i++; 1132 } 1133 } 1134 1135 // If nothing was changed in this pass then we have a circular ref 1136 if (!changed) { 1137 ErrorMsg err = new ErrorMsg(ErrorMsg.CIRCULAR_VARIABLE_ERR, 1138 input.toString(), this); 1139 getParser().reportError(Constants.ERROR, err); 1140 return(result); 1141 } 1142 } 1143 1144 return result; 1145 } 1146 1147 /** 1148 * Compile a buildKeys() method into the output class. Note that keys 1149 * for the input document are created in topLevel(), not in this method. 1150 * However, we still need this method to create keys for documents loaded 1151 * via the XPath document() function. 1152 */ 1153 private String compileBuildKeys(ClassGenerator classGen) { 1154 final ConstantPoolGen cpg = classGen.getConstantPool(); 1155 1156 final com.sun.org.apache.bcel.internal.generic.Type[] argTypes = { 1157 Util.getJCRefType(DOM_INTF_SIG), 1158 Util.getJCRefType(NODE_ITERATOR_SIG), 1159 Util.getJCRefType(TRANSLET_OUTPUT_SIG), 1160 com.sun.org.apache.bcel.internal.generic.Type.INT 1161 }; 1162 1163 final String[] argNames = { 1164 DOCUMENT_PNAME, ITERATOR_PNAME, TRANSLET_OUTPUT_PNAME, "current" 1165 }; 1166 1167 final InstructionList il = new InstructionList(); 1168 1169 final MethodGenerator buildKeys = 1170 new MethodGenerator(ACC_PUBLIC, 1171 com.sun.org.apache.bcel.internal.generic.Type.VOID, 1172 argTypes, argNames, 1173 "buildKeys", _className, il, 1174 classGen.getConstantPool()); 1175 1176 buildKeys.addException("com.sun.org.apache.xalan.internal.xsltc.TransletException"); 1177 1178 final Iterator<SyntaxTreeNode> elements = elements(); 1179 while (elements.hasNext()) { 1180 // xsl:key 1181 final SyntaxTreeNode element = elements.next(); 1182 if (element instanceof Key) { 1183 final Key key = (Key)element; 1184 key.translate(classGen, buildKeys); 1185 _keys.put(key.getName(),key); 1186 } 1187 } 1188 1189 il.append(RETURN); 1190 1191 // Compute max locals + stack and add method to class 1192 buildKeys.stripAttributes(true); 1193 buildKeys.setMaxLocals(); 1194 buildKeys.setMaxStack(); 1195 buildKeys.removeNOPs(); 1196 1197 classGen.addMethod(buildKeys.getMethod()); 1198 1199 return("("+DOM_INTF_SIG+NODE_ITERATOR_SIG+TRANSLET_OUTPUT_SIG+"I)V"); 1200 } 1201 1202 /** 1203 * Compile transform() into the output class. This method is used to 1204 * initialize global variables and global parameters. The current node 1205 * is set to be the document's root node. 1206 */ 1207 private void compileTransform(ClassGenerator classGen) { 1208 final ConstantPoolGen cpg = classGen.getConstantPool(); 1209 1210 /* 1211 * Define the the method transform with the following signature: 1212 * void transform(DOM, NodeIterator, HandlerBase) 1213 */ 1214 final com.sun.org.apache.bcel.internal.generic.Type[] argTypes = 1215 new com.sun.org.apache.bcel.internal.generic.Type[3]; 1216 argTypes[0] = Util.getJCRefType(DOM_INTF_SIG); 1217 argTypes[1] = Util.getJCRefType(NODE_ITERATOR_SIG); 1218 argTypes[2] = Util.getJCRefType(TRANSLET_OUTPUT_SIG); 1219 1220 final String[] argNames = new String[3]; 1221 argNames[0] = DOCUMENT_PNAME; 1222 argNames[1] = ITERATOR_PNAME; 1223 argNames[2] = TRANSLET_OUTPUT_PNAME; 1224 1225 final InstructionList il = new InstructionList(); 1226 final MethodGenerator transf = 1227 new MethodGenerator(ACC_PUBLIC, 1228 com.sun.org.apache.bcel.internal.generic.Type.VOID, 1229 argTypes, argNames, 1230 "transform", 1231 _className, 1232 il, 1233 classGen.getConstantPool()); 1234 transf.addException("com.sun.org.apache.xalan.internal.xsltc.TransletException"); 1235 1236 // call resetPrefixIndex at the beginning of transform 1237 final int check = cpg.addMethodref(BASIS_LIBRARY_CLASS, "resetPrefixIndex", "()V"); 1238 il.append(new INVOKESTATIC(check)); 1239 1240 // Define and initialize current with the root node 1241 final LocalVariableGen current = 1242 transf.addLocalVariable("current", 1243 com.sun.org.apache.bcel.internal.generic.Type.INT, 1244 null, null); 1245 final String applyTemplatesSig = classGen.getApplyTemplatesSig(); 1246 final int applyTemplates = cpg.addMethodref(getClassName(), 1247 "applyTemplates", 1248 applyTemplatesSig); 1249 final int domField = cpg.addFieldref(getClassName(), 1250 DOM_FIELD, 1251 DOM_INTF_SIG); 1252 1253 // push translet for PUTFIELD 1254 il.append(classGen.loadTranslet()); 1255 // prepare appropriate DOM implementation 1256 1257 if (isMultiDocument()) { 1258 il.append(new NEW(cpg.addClass(MULTI_DOM_CLASS))); 1259 il.append(DUP); 1260 } 1261 1262 il.append(classGen.loadTranslet()); 1263 il.append(transf.loadDOM()); 1264 il.append(new INVOKEVIRTUAL(cpg.addMethodref(TRANSLET_CLASS, 1265 "makeDOMAdapter", 1266 "("+DOM_INTF_SIG+")"+ 1267 DOM_ADAPTER_SIG))); 1268 // DOMAdapter is on the stack 1269 1270 if (isMultiDocument()) { 1271 final int init = cpg.addMethodref(MULTI_DOM_CLASS, 1272 "<init>", 1273 "("+DOM_INTF_SIG+")V"); 1274 il.append(new INVOKESPECIAL(init)); 1275 // MultiDOM is on the stack 1276 } 1277 1278 //store to _dom variable 1279 il.append(new PUTFIELD(domField)); 1280 1281 // continue with globals initialization 1282 final int gitr = cpg.addInterfaceMethodref(DOM_INTF, 1283 "getIterator", 1284 "()"+NODE_ITERATOR_SIG); 1285 il.append(transf.loadDOM()); 1286 il.append(new INVOKEINTERFACE(gitr, 1)); 1287 il.append(transf.nextNode()); 1288 current.setStart(il.append(new ISTORE(current.getIndex()))); 1289 1290 // Transfer the output settings to the output post-processor 1291 il.append(classGen.loadTranslet()); 1292 il.append(transf.loadHandler()); 1293 final int index = cpg.addMethodref(TRANSLET_CLASS, 1294 "transferOutputSettings", 1295 "("+OUTPUT_HANDLER_SIG+")V"); 1296 il.append(new INVOKEVIRTUAL(index)); 1297 1298 /* 1299 * Compile buildKeys() method. Note that this method is not 1300 * invoked here as keys for the input document are now created 1301 * in topLevel(). However, this method is still needed by the 1302 * LoadDocument class. 1303 */ 1304 final String keySig = compileBuildKeys(classGen); 1305 final int keyIdx = cpg.addMethodref(getClassName(), 1306 "buildKeys", keySig); 1307 1308 // Look for top-level elements that need handling 1309 final Iterator<SyntaxTreeNode> toplevel = elements(); 1310 if (_globals.size() > 0 || toplevel.hasNext()) { 1311 // Compile method for handling top-level elements 1312 final String topLevelSig = compileTopLevel(classGen); 1313 // Get a reference to that method 1314 final int topLevelIdx = cpg.addMethodref(getClassName(), 1315 "topLevel", 1316 topLevelSig); 1317 // Push all parameters on the stack and call topLevel() 1318 il.append(classGen.loadTranslet()); // The 'this' pointer 1319 il.append(classGen.loadTranslet()); 1320 il.append(new GETFIELD(domField)); // The DOM reference 1321 il.append(transf.loadIterator()); 1322 il.append(transf.loadHandler()); // The output handler 1323 il.append(new INVOKEVIRTUAL(topLevelIdx)); 1324 } 1325 1326 // start document 1327 il.append(transf.loadHandler()); 1328 il.append(transf.startDocument()); 1329 1330 // push first arg for applyTemplates 1331 il.append(classGen.loadTranslet()); 1332 // push translet for GETFIELD to get DOM arg 1333 il.append(classGen.loadTranslet()); 1334 il.append(new GETFIELD(domField)); 1335 // push remaining 2 args 1336 il.append(transf.loadIterator()); 1337 il.append(transf.loadHandler()); 1338 il.append(new INVOKEVIRTUAL(applyTemplates)); 1339 // endDocument 1340 il.append(transf.loadHandler()); 1341 il.append(transf.endDocument()); 1342 1343 il.append(RETURN); 1344 1345 // Compute max locals + stack and add method to class 1346 classGen.addMethod(transf); 1347 1348 } 1349 1350 /** 1351 * Peephole optimization: Remove sequences of [ALOAD, POP]. 1352 */ 1353 private void peepHoleOptimization(MethodGenerator methodGen) { 1354 final String pattern = "`aload'`pop'`instruction'"; 1355 final InstructionList il = methodGen.getInstructionList(); 1356 final InstructionFinder find = new InstructionFinder(il); 1357 for(Iterator<InstructionHandle[]> iter=find.search(pattern); iter.hasNext(); ) { 1358 InstructionHandle[] match = iter.next(); 1359 try { 1360 il.delete(match[0], match[1]); 1361 } 1362 catch (TargetLostException e) { 1363 // TODO: move target down into the list 1364 } 1365 } 1366 } 1367 1368 public int addParam(Param param) { 1369 _globals.add(param); 1370 return _globals.size() - 1; 1371 } 1372 1373 public int addVariable(Variable global) { 1374 _globals.add(global); 1375 return _globals.size() - 1; 1376 } 1377 1378 public void display(int indent) { 1379 indent(indent); 1380 Util.println("Stylesheet"); 1381 displayContents(indent + IndentIncrement); 1382 } 1383 1384 // do we need this wrapper ????? 1385 public String getNamespace(String prefix) { 1386 return lookupNamespace(prefix); 1387 } 1388 1389 public String getClassName() { 1390 return _className; 1391 } 1392 1393 public List<Template> getTemplates() { 1394 return _templates; 1395 } 1396 1397 public List<Template> getAllValidTemplates() { 1398 // Return templates if no imported/included stylesheets 1399 if (_includedStylesheets == null) { 1400 return _templates; 1401 } 1402 1403 // Is returned value cached? 1404 if (_allValidTemplates == null) { 1405 List<Template> templates = new ArrayList<>(); 1406 templates.addAll(_templates); 1407 for (Stylesheet included : _includedStylesheets) { 1408 templates.addAll(included.getAllValidTemplates()); 1409 } 1410 //templates.addAll(_templates); 1411 1412 // Cache results in top-level stylesheet only 1413 if (_parentStylesheet != null) { 1414 return templates; 1415 } 1416 _allValidTemplates = templates; 1417 } 1418 1419 return _allValidTemplates; 1420 } 1421 1422 protected void addTemplate(Template template) { 1423 _templates.add(template); 1424 } 1425 }