1/* 2 * Copyright (c) 2015, 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: Mode.java,v 1.2.4.1 2005/09/19 05:18:11 pvedula Exp $ 22 */ 23 24package com.sun.org.apache.xalan.internal.xsltc.compiler; 25 26import com.sun.org.apache.bcel.internal.generic.BranchHandle; 27import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen; 28import com.sun.org.apache.bcel.internal.generic.DUP; 29import com.sun.org.apache.bcel.internal.generic.GOTO_W; 30import com.sun.org.apache.bcel.internal.generic.IFLT; 31import com.sun.org.apache.bcel.internal.generic.ILOAD; 32import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE; 33import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL; 34import com.sun.org.apache.bcel.internal.generic.ISTORE; 35import com.sun.org.apache.bcel.internal.generic.Instruction; 36import com.sun.org.apache.bcel.internal.generic.InstructionHandle; 37import com.sun.org.apache.bcel.internal.generic.InstructionList; 38import com.sun.org.apache.bcel.internal.generic.LocalVariableGen; 39import com.sun.org.apache.bcel.internal.generic.SWITCH; 40import com.sun.org.apache.bcel.internal.generic.TargetLostException; 41import com.sun.org.apache.bcel.internal.util.InstructionFinder; 42import com.sun.org.apache.xalan.internal.xsltc.DOM; 43import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator; 44import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator; 45import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NamedMethodGenerator; 46import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util; 47import com.sun.org.apache.xml.internal.dtm.Axis; 48import com.sun.org.apache.xml.internal.dtm.DTM; 49import java.util.Enumeration; 50import java.util.HashMap; 51import java.util.Iterator; 52import java.util.Map; 53import java.util.Set; 54import java.util.Vector; 55 56/** 57 * Mode gathers all the templates belonging to a given mode; 58 * it is responsible for generating an appropriate 59 * applyTemplates + (mode name) method in the translet. 60 * @author Jacek Ambroziak 61 * @author Santiago Pericas-Geertsen 62 * @author Morten Jorgensen 63 * @author Erwin Bolwidt <ejb@klomp.org> 64 * @author G. Todd Miller 65 */ 66final class Mode implements Constants { 67 68 /** 69 * The name of this mode as defined in the stylesheet. 70 */ 71 private final QName _name; 72 73 /** 74 * A reference to the stylesheet object that owns this mode. 75 */ 76 private final Stylesheet _stylesheet; 77 78 /** 79 * The name of the method in which this mode is compiled. 80 */ 81 private final String _methodName; 82 83 /** 84 * A vector of all the templates in this mode. 85 */ 86 private Vector _templates; 87 88 /** 89 * Group for patterns with node()-type kernel and child axis. 90 */ 91 private Vector _childNodeGroup = null; 92 93 /** 94 * Test sequence for patterns with node()-type kernel and child axis. 95 */ 96 private TestSeq _childNodeTestSeq = null; 97 98 /** 99 * Group for patterns with node()-type kernel and attribute axis. 100 */ 101 private Vector _attribNodeGroup = null; 102 103 /** 104 * Test sequence for patterns with node()-type kernel and attribute axis. 105 */ 106 private TestSeq _attribNodeTestSeq = null; 107 108 /** 109 * Group for patterns with id() or key()-type kernel. 110 */ 111 private Vector _idxGroup = null; 112 113 /** 114 * Test sequence for patterns with id() or key()-type kernel. 115 */ 116 private TestSeq _idxTestSeq = null; 117 118 /** 119 * Group for patterns with any other kernel type. 120 */ 121 private Vector[] _patternGroups; 122 123 /** 124 * Test sequence for patterns with any other kernel type. 125 */ 126 private TestSeq[] _testSeq; 127 128 129 /** 130 * A mapping between templates and test sequences. 131 */ 132 private Map<Template, Object> _neededTemplates = new HashMap<>(); 133 134 /** 135 * A mapping between named templates and Mode objects. 136 */ 137 private Map<Template, Mode> _namedTemplates = new HashMap<>(); 138 139 /** 140 * A mapping between templates and instruction handles. 141 */ 142 private Map<Template, InstructionHandle> _templateIHs = new HashMap<>(); 143 144 /** 145 * A mapping between templates and instruction lists. 146 */ 147 private Map<Template, InstructionList> _templateILs = new HashMap<>(); 148 149 /** 150 * A reference to the pattern matching the root node. 151 */ 152 private LocationPathPattern _rootPattern = null; 153 154 /** 155 * Stores ranges of template precendences for the compilation 156 * of apply-imports. 157 */ 158 private Map<Integer, Integer> _importLevels = null; 159 160 /** 161 * A mapping between key names and keys. 162 */ 163 private Map<String, Key> _keys = null; 164 165 /** 166 * Variable index for the current node used in code generation. 167 */ 168 private int _currentIndex; 169 170 /** 171 * Creates a new Mode. 172 * 173 * @param name A textual representation of the mode's QName 174 * @param stylesheet The Stylesheet in which the mode occured 175 * @param suffix A suffix to append to the method name for this mode 176 * (normally a sequence number - still in a String). 177 */ 178 public Mode(QName name, Stylesheet stylesheet, String suffix) { 179 _name = name; 180 _stylesheet = stylesheet; 181 _methodName = APPLY_TEMPLATES + suffix; 182 _templates = new Vector(); 183 _patternGroups = new Vector[32]; 184 } 185 186 /** 187 * Returns the name of the method (_not_ function) that will be 188 * compiled for this mode. Normally takes the form 'applyTemplates()' 189 * or * 'applyTemplates2()'. 190 * 191 * @return Method name for this mode 192 */ 193 public String functionName() { 194 return _methodName; 195 } 196 197 public String functionName(int min, int max) { 198 if (_importLevels == null) { 199 _importLevels = new HashMap<>(); 200 } 201 _importLevels.put(max, min); 202 return _methodName + '_' + max; 203 } 204 205 /** 206 * Shortcut to get the class compiled for this mode (will be inlined). 207 */ 208 private String getClassName() { 209 return _stylesheet.getClassName(); 210 } 211 212 public Stylesheet getStylesheet() { 213 return _stylesheet; 214 } 215 216 public void addTemplate(Template template) { 217 _templates.addElement(template); 218 } 219 220 private Vector quicksort(Vector templates, int p, int r) { 221 if (p < r) { 222 final int q = partition(templates, p, r); 223 quicksort(templates, p, q); 224 quicksort(templates, q + 1, r); 225 } 226 return templates; 227 } 228 229 private int partition(Vector templates, int p, int r) { 230 final Template x = (Template)templates.elementAt(p); 231 int i = p - 1; 232 int j = r + 1; 233 while (true) { 234 while (x.compareTo((Template)templates.elementAt(--j)) > 0); 235 while (x.compareTo((Template)templates.elementAt(++i)) < 0); 236 if (i < j) { 237 templates.set(j, templates.set(i, templates.elementAt(j))); 238 } 239 else { 240 return j; 241 } 242 } 243 } 244 245 /** 246 * Process all the test patterns in this mode 247 */ 248 public void processPatterns(Map<String, Key> keys) { 249 _keys = keys; 250 251/* 252System.out.println("Before Sort " + _name); 253for (int i = 0; i < _templates.size(); i++) { 254 System.out.println("name = " + ((Template)_templates.elementAt(i)).getName()); 255 System.out.println("pattern = " + ((Template)_templates.elementAt(i)).getPattern()); 256 System.out.println("priority = " + ((Template)_templates.elementAt(i)).getPriority()); 257 System.out.println("position = " + ((Template)_templates.elementAt(i)).getPosition()); 258} 259*/ 260 261 _templates = quicksort(_templates, 0, _templates.size() - 1); 262 263/* 264System.out.println("\n After Sort " + _name); 265for (int i = 0; i < _templates.size(); i++) { 266 System.out.println("name = " + ((Template)_templates.elementAt(i)).getName()); 267 System.out.println("pattern = " + ((Template)_templates.elementAt(i)).getPattern()); 268 System.out.println("priority = " + ((Template)_templates.elementAt(i)).getPriority()); 269 System.out.println("position = " + ((Template)_templates.elementAt(i)).getPosition()); 270} 271*/ 272 273 // Traverse all templates 274 final Enumeration templates = _templates.elements(); 275 while (templates.hasMoreElements()) { 276 // Get the next template 277 final Template template = (Template)templates.nextElement(); 278 279 /* 280 * Add this template to a table of named templates if it has a name. 281 * If there are multiple templates with the same name, all but one 282 * (the one with highest priority) will be disabled. 283 */ 284 if (template.isNamed() && !template.disabled()) { 285 _namedTemplates.put(template, this); 286 } 287 288 // Add this template to a test sequence if it has a pattern 289 final Pattern pattern = template.getPattern(); 290 if (pattern != null) { 291 flattenAlternative(pattern, template, keys); 292 } 293 } 294 prepareTestSequences(); 295 } 296 297 /** 298 * This method will break up alternative patterns (ie. unions of patterns, 299 * such as match="A/B | C/B") and add the basic patterns to their 300 * respective pattern groups. 301 */ 302 private void flattenAlternative(Pattern pattern, 303 Template template, 304 Map<String, Key> keys) { 305 // Patterns on type id() and key() are special since they do not have 306 // any kernel node type (it can be anything as long as the node is in 307 // the id's or key's index). 308 if (pattern instanceof IdKeyPattern) { 309 final IdKeyPattern idkey = (IdKeyPattern)pattern; 310 idkey.setTemplate(template); 311 if (_idxGroup == null) _idxGroup = new Vector(); 312 _idxGroup.add(pattern); 313 } 314 // Alternative patterns are broken up and re-processed recursively 315 else if (pattern instanceof AlternativePattern) { 316 final AlternativePattern alt = (AlternativePattern)pattern; 317 flattenAlternative(alt.getLeft(), template, keys); 318 flattenAlternative(alt.getRight(), template, keys); 319 } 320 // Finally we have a pattern that can be added to a test sequence! 321 else if (pattern instanceof LocationPathPattern) { 322 final LocationPathPattern lpp = (LocationPathPattern)pattern; 323 lpp.setTemplate(template); 324 addPatternToGroup(lpp); 325 } 326 } 327 328 /** 329 * Group patterns by NodeTests of their last Step 330 * Keep them sorted by priority within group 331 */ 332 private void addPatternToGroup(final LocationPathPattern lpp) { 333 // id() and key()-type patterns do not have a kernel type 334 if (lpp instanceof IdKeyPattern) { 335 addPattern(-1, lpp); 336 } 337 // Otherwise get the kernel pattern from the LPP 338 else { 339 // kernel pattern is the last (maybe only) Step 340 final StepPattern kernel = lpp.getKernelPattern(); 341 if (kernel != null) { 342 addPattern(kernel.getNodeType(), lpp); 343 } 344 else if (_rootPattern == null || 345 lpp.noSmallerThan(_rootPattern)) { 346 _rootPattern = lpp; 347 } 348 } 349 } 350 351 /** 352 * Adds a pattern to a pattern group 353 */ 354 private void addPattern(int kernelType, LocationPathPattern pattern) { 355 // Make sure the array of pattern groups is long enough 356 final int oldLength = _patternGroups.length; 357 if (kernelType >= oldLength) { 358 Vector[] newGroups = new Vector[kernelType * 2]; 359 System.arraycopy(_patternGroups, 0, newGroups, 0, oldLength); 360 _patternGroups = newGroups; 361 } 362 363 // Find the vector to put this pattern into 364 Vector patterns; 365 366 if (kernelType == DOM.NO_TYPE) { 367 if (pattern.getAxis() == Axis.ATTRIBUTE) { 368 patterns = (_attribNodeGroup == null) ? 369 (_attribNodeGroup = new Vector(2)) : _attribNodeGroup; 370 } 371 else { 372 patterns = (_childNodeGroup == null) ? 373 (_childNodeGroup = new Vector(2)) : _childNodeGroup; 374 } 375 } 376 else { 377 patterns = (_patternGroups[kernelType] == null) ? 378 (_patternGroups[kernelType] = new Vector(2)) : 379 _patternGroups[kernelType]; 380 } 381 382 if (patterns.size() == 0) { 383 patterns.addElement(pattern); 384 } 385 else { 386 boolean inserted = false; 387 for (int i = 0; i < patterns.size(); i++) { 388 final LocationPathPattern lppToCompare = 389 (LocationPathPattern)patterns.elementAt(i); 390 391 if (pattern.noSmallerThan(lppToCompare)) { 392 inserted = true; 393 patterns.insertElementAt(pattern, i); 394 break; 395 } 396 } 397 if (inserted == false) { 398 patterns.addElement(pattern); 399 } 400 } 401 } 402 403 /** 404 * Complete test sequences of a given type by adding all patterns 405 * from a given group. 406 */ 407 private void completeTestSequences(int nodeType, Vector patterns) { 408 if (patterns != null) { 409 if (_patternGroups[nodeType] == null) { 410 _patternGroups[nodeType] = patterns; 411 } 412 else { 413 final int m = patterns.size(); 414 for (int j = 0; j < m; j++) { 415 addPattern(nodeType, 416 (LocationPathPattern) patterns.elementAt(j)); 417 } 418 } 419 } 420 } 421 422 /** 423 * Build test sequences. The first step is to complete the test sequences 424 * by including patterns of "*" and "node()" kernel to all element test 425 * sequences, and of "@*" to all attribute test sequences. 426 */ 427 private void prepareTestSequences() { 428 final Vector starGroup = _patternGroups[DTM.ELEMENT_NODE]; 429 final Vector atStarGroup = _patternGroups[DTM.ATTRIBUTE_NODE]; 430 431 // Complete test sequence for "text()" with "child::node()" 432 completeTestSequences(DTM.TEXT_NODE, _childNodeGroup); 433 434 // Complete test sequence for "*" with "child::node()" 435 completeTestSequences(DTM.ELEMENT_NODE, _childNodeGroup); 436 437 // Complete test sequence for "pi()" with "child::node()" 438 completeTestSequences(DTM.PROCESSING_INSTRUCTION_NODE, _childNodeGroup); 439 440 // Complete test sequence for "comment()" with "child::node()" 441 completeTestSequences(DTM.COMMENT_NODE, _childNodeGroup); 442 443 // Complete test sequence for "@*" with "attribute::node()" 444 completeTestSequences(DTM.ATTRIBUTE_NODE, _attribNodeGroup); 445 446 final Vector names = _stylesheet.getXSLTC().getNamesIndex(); 447 if (starGroup != null || atStarGroup != null || 448 _childNodeGroup != null || _attribNodeGroup != null) 449 { 450 final int n = _patternGroups.length; 451 452 // Complete test sequence for user-defined types 453 for (int i = DTM.NTYPES; i < n; i++) { 454 if (_patternGroups[i] == null) continue; 455 456 final String name = (String) names.elementAt(i - DTM.NTYPES); 457 458 if (isAttributeName(name)) { 459 // If an attribute then copy "@*" to its test sequence 460 completeTestSequences(i, atStarGroup); 461 462 // And also copy "attribute::node()" to its test sequence 463 completeTestSequences(i, _attribNodeGroup); 464 } 465 else { 466 // If an element then copy "*" to its test sequence 467 completeTestSequences(i, starGroup); 468 469 // And also copy "child::node()" to its test sequence 470 completeTestSequences(i, _childNodeGroup); 471 } 472 } 473 } 474 475 _testSeq = new TestSeq[DTM.NTYPES + names.size()]; 476 477 final int n = _patternGroups.length; 478 for (int i = 0; i < n; i++) { 479 final Vector patterns = _patternGroups[i]; 480 if (patterns != null) { 481 final TestSeq testSeq = new TestSeq(patterns, i, this); 482// System.out.println("testSeq[" + i + "] = " + testSeq); 483 testSeq.reduce(); 484 _testSeq[i] = testSeq; 485 testSeq.findTemplates(_neededTemplates); 486 } 487 } 488 489 if (_childNodeGroup != null && _childNodeGroup.size() > 0) { 490 _childNodeTestSeq = new TestSeq(_childNodeGroup, -1, this); 491 _childNodeTestSeq.reduce(); 492 _childNodeTestSeq.findTemplates(_neededTemplates); 493 } 494 495/* 496 if (_attribNodeGroup != null && _attribNodeGroup.size() > 0) { 497 _attribNodeTestSeq = new TestSeq(_attribNodeGroup, -1, this); 498 _attribNodeTestSeq.reduce(); 499 _attribNodeTestSeq.findTemplates(_neededTemplates); 500 } 501*/ 502 503 if (_idxGroup != null && _idxGroup.size() > 0) { 504 _idxTestSeq = new TestSeq(_idxGroup, this); 505 _idxTestSeq.reduce(); 506 _idxTestSeq.findTemplates(_neededTemplates); 507 } 508 509 if (_rootPattern != null) { 510 // doesn't matter what is 'put', only key matters 511 _neededTemplates.put(_rootPattern.getTemplate(), this); 512 } 513 } 514 515 private void compileNamedTemplate(Template template, 516 ClassGenerator classGen) { 517 final ConstantPoolGen cpg = classGen.getConstantPool(); 518 final InstructionList il = new InstructionList(); 519 String methodName = Util.escape(template.getName().toString()); 520 521 int numParams = 0; 522 if (template.isSimpleNamedTemplate()) { 523 Vector parameters = template.getParameters(); 524 numParams = parameters.size(); 525 } 526 527 // Initialize the types and names arrays for the NamedMethodGenerator. 528 com.sun.org.apache.bcel.internal.generic.Type[] types = 529 new com.sun.org.apache.bcel.internal.generic.Type[4 + numParams]; 530 String[] names = new String[4 + numParams]; 531 types[0] = Util.getJCRefType(DOM_INTF_SIG); 532 types[1] = Util.getJCRefType(NODE_ITERATOR_SIG); 533 types[2] = Util.getJCRefType(TRANSLET_OUTPUT_SIG); 534 types[3] = com.sun.org.apache.bcel.internal.generic.Type.INT; 535 names[0] = DOCUMENT_PNAME; 536 names[1] = ITERATOR_PNAME; 537 names[2] = TRANSLET_OUTPUT_PNAME; 538 names[3] = NODE_PNAME; 539 540 // For simple named templates, the signature of the generated method 541 // is not fixed. It depends on the number of parameters declared in the 542 // template. 543 for (int i = 4; i < 4 + numParams; i++) { 544 types[i] = Util.getJCRefType(OBJECT_SIG); 545 names[i] = "param" + String.valueOf(i-4); 546 } 547 548 NamedMethodGenerator methodGen = 549 new NamedMethodGenerator(ACC_PUBLIC, 550 com.sun.org.apache.bcel.internal.generic.Type.VOID, 551 types, names, methodName, 552 getClassName(), il, cpg); 553 554 il.append(template.compile(classGen, methodGen)); 555 il.append(RETURN); 556 557 classGen.addMethod(methodGen); 558 } 559 560 private void compileTemplates(ClassGenerator classGen, 561 MethodGenerator methodGen, 562 InstructionHandle next) 563 { 564 Set<Template> templates = _namedTemplates.keySet(); 565 for (Template template : templates) { 566 compileNamedTemplate(template, classGen); 567 } 568 569 templates = _neededTemplates.keySet(); 570 for (Template template : templates) { 571 if (template.hasContents()) { 572 // !!! TODO templates both named and matched 573 InstructionList til = template.compile(classGen, methodGen); 574 til.append(new GOTO_W(next)); 575 _templateILs.put(template, til); 576 _templateIHs.put(template, til.getStart()); 577 } 578 else { 579 // empty template 580 _templateIHs.put(template, next); 581 } 582 } 583 } 584 585 private void appendTemplateCode(InstructionList body) { 586 for (Template template : _neededTemplates.keySet()) { 587 final InstructionList iList = _templateILs.get(template); 588 if (iList != null) { 589 body.append(iList); 590 } 591 592 } 593 } 594 595 private void appendTestSequences(InstructionList body) { 596 final int n = _testSeq.length; 597 for (int i = 0; i < n; i++) { 598 final TestSeq testSeq = _testSeq[i]; 599 if (testSeq != null) { 600 InstructionList il = testSeq.getInstructionList(); 601 if (il != null) 602 body.append(il); 603 // else trivial TestSeq 604 } 605 } 606 } 607 608 public static void compileGetChildren(ClassGenerator classGen, 609 MethodGenerator methodGen, 610 int node) { 611 final ConstantPoolGen cpg = classGen.getConstantPool(); 612 final InstructionList il = methodGen.getInstructionList(); 613 final int git = cpg.addInterfaceMethodref(DOM_INTF, 614 GET_CHILDREN, 615 GET_CHILDREN_SIG); 616 il.append(methodGen.loadDOM()); 617 il.append(new ILOAD(node)); 618 il.append(new INVOKEINTERFACE(git, 2)); 619 } 620 621 /** 622 * Compiles the default handling for DOM elements: traverse all children 623 */ 624 private InstructionList compileDefaultRecursion(ClassGenerator classGen, 625 MethodGenerator methodGen, 626 InstructionHandle next) { 627 final ConstantPoolGen cpg = classGen.getConstantPool(); 628 final InstructionList il = new InstructionList(); 629 final String applyTemplatesSig = classGen.getApplyTemplatesSig(); 630 final int git = cpg.addInterfaceMethodref(DOM_INTF, 631 GET_CHILDREN, 632 GET_CHILDREN_SIG); 633 final int applyTemplates = cpg.addMethodref(getClassName(), 634 functionName(), 635 applyTemplatesSig); 636 il.append(classGen.loadTranslet()); 637 il.append(methodGen.loadDOM()); 638 639 il.append(methodGen.loadDOM()); 640 il.append(new ILOAD(_currentIndex)); 641 il.append(new INVOKEINTERFACE(git, 2)); 642 il.append(methodGen.loadHandler()); 643 il.append(new INVOKEVIRTUAL(applyTemplates)); 644 il.append(new GOTO_W(next)); 645 return il; 646 } 647 648 /** 649 * Compiles the default action for DOM text nodes and attribute nodes: 650 * output the node's text value 651 */ 652 private InstructionList compileDefaultText(ClassGenerator classGen, 653 MethodGenerator methodGen, 654 InstructionHandle next) { 655 final ConstantPoolGen cpg = classGen.getConstantPool(); 656 final InstructionList il = new InstructionList(); 657 658 final int chars = cpg.addInterfaceMethodref(DOM_INTF, 659 CHARACTERS, 660 CHARACTERS_SIG); 661 il.append(methodGen.loadDOM()); 662 il.append(new ILOAD(_currentIndex)); 663 il.append(methodGen.loadHandler()); 664 il.append(new INVOKEINTERFACE(chars, 3)); 665 il.append(new GOTO_W(next)); 666 return il; 667 } 668 669 private InstructionList compileNamespaces(ClassGenerator classGen, 670 MethodGenerator methodGen, 671 boolean[] isNamespace, 672 boolean[] isAttribute, 673 boolean attrFlag, 674 InstructionHandle defaultTarget) { 675 final XSLTC xsltc = classGen.getParser().getXSLTC(); 676 final ConstantPoolGen cpg = classGen.getConstantPool(); 677 678 // Append switch() statement - namespace test dispatch loop 679 final Vector namespaces = xsltc.getNamespaceIndex(); 680 final Vector names = xsltc.getNamesIndex(); 681 final int namespaceCount = namespaces.size() + 1; 682 final int namesCount = names.size(); 683 684 final InstructionList il = new InstructionList(); 685 final int[] types = new int[namespaceCount]; 686 final InstructionHandle[] targets = new InstructionHandle[types.length]; 687 688 if (namespaceCount > 0) { 689 boolean compiled = false; 690 691 // Initialize targets for namespace() switch statement 692 for (int i = 0; i < namespaceCount; i++) { 693 targets[i] = defaultTarget; 694 types[i] = i; 695 } 696 697 // Add test sequences for known namespace types 698 for (int i = DTM.NTYPES; i < (DTM.NTYPES+namesCount); i++) { 699 if ((isNamespace[i]) && (isAttribute[i] == attrFlag)) { 700 String name = (String)names.elementAt(i-DTM.NTYPES); 701 String namespace = name.substring(0,name.lastIndexOf(':')); 702 final int type = xsltc.registerNamespace(namespace); 703 704 if ((i < _testSeq.length) && 705 (_testSeq[i] != null)) { 706 targets[type] = 707 (_testSeq[i]).compile(classGen, 708 methodGen, 709 defaultTarget); 710 compiled = true; 711 } 712 } 713 } 714 715 // Return "null" if no test sequences were compiled 716 if (!compiled) return(null); 717 718 // Append first code in applyTemplates() - get type of current node 719 final int getNS = cpg.addInterfaceMethodref(DOM_INTF, 720 "getNamespaceType", 721 "(I)I"); 722 il.append(methodGen.loadDOM()); 723 il.append(new ILOAD(_currentIndex)); 724 il.append(new INVOKEINTERFACE(getNS, 2)); 725 il.append(new SWITCH(types, targets, defaultTarget)); 726 return(il); 727 } 728 else { 729 return(null); 730 } 731 } 732 733 /** 734 * Compiles the applyTemplates() method and adds it to the translet. 735 * This is the main dispatch method. 736 */ 737 public void compileApplyTemplates(ClassGenerator classGen) { 738 final XSLTC xsltc = classGen.getParser().getXSLTC(); 739 final ConstantPoolGen cpg = classGen.getConstantPool(); 740 final Vector names = xsltc.getNamesIndex(); 741 742 // Create the applyTemplates() method 743 final com.sun.org.apache.bcel.internal.generic.Type[] argTypes = 744 new com.sun.org.apache.bcel.internal.generic.Type[3]; 745 argTypes[0] = Util.getJCRefType(DOM_INTF_SIG); 746 argTypes[1] = Util.getJCRefType(NODE_ITERATOR_SIG); 747 argTypes[2] = Util.getJCRefType(TRANSLET_OUTPUT_SIG); 748 749 final String[] argNames = new String[3]; 750 argNames[0] = DOCUMENT_PNAME; 751 argNames[1] = ITERATOR_PNAME; 752 argNames[2] = TRANSLET_OUTPUT_PNAME; 753 754 final InstructionList mainIL = new InstructionList(); 755 final MethodGenerator methodGen = 756 new MethodGenerator(ACC_PUBLIC | ACC_FINAL, 757 com.sun.org.apache.bcel.internal.generic.Type.VOID, 758 argTypes, argNames, functionName(), 759 getClassName(), mainIL, 760 classGen.getConstantPool()); 761 methodGen.addException("com.sun.org.apache.xalan.internal.xsltc.TransletException"); 762 // Insert an extra NOP just to keep "current" from appearing as if it 763 // has a value before the start of the loop. 764 mainIL.append(NOP); 765 766 767 // Create a local variable to hold the current node 768 final LocalVariableGen current; 769 current = methodGen.addLocalVariable2("current", 770 com.sun.org.apache.bcel.internal.generic.Type.INT, 771 null); 772 _currentIndex = current.getIndex(); 773 774 // Create the "body" instruction list that will eventually hold the 775 // code for the entire method (other ILs will be appended). 776 final InstructionList body = new InstructionList(); 777 body.append(NOP); 778 779 // Create an instruction list that contains the default next-node 780 // iteration 781 final InstructionList ilLoop = new InstructionList(); 782 ilLoop.append(methodGen.loadIterator()); 783 ilLoop.append(methodGen.nextNode()); 784 ilLoop.append(DUP); 785 ilLoop.append(new ISTORE(_currentIndex)); 786 787 // The body of this code can get very large - large than can be handled 788 // by a single IFNE(body.getStart()) instruction - need workaround: 789 final BranchHandle ifeq = ilLoop.append(new IFLT(null)); 790 final BranchHandle loop = ilLoop.append(new GOTO_W(null)); 791 ifeq.setTarget(ilLoop.append(RETURN)); // applyTemplates() ends here! 792 final InstructionHandle ihLoop = ilLoop.getStart(); 793 794 current.setStart(mainIL.append(new GOTO_W(ihLoop))); 795 796 // Live range of "current" ends at end of loop 797 current.setEnd(loop); 798 799 // Compile default handling of elements (traverse children) 800 InstructionList ilRecurse = 801 compileDefaultRecursion(classGen, methodGen, ihLoop); 802 InstructionHandle ihRecurse = ilRecurse.getStart(); 803 804 // Compile default handling of text/attribute nodes (output text) 805 InstructionList ilText = 806 compileDefaultText(classGen, methodGen, ihLoop); 807 InstructionHandle ihText = ilText.getStart(); 808 809 // Distinguish attribute/element/namespace tests for further processing 810 final int[] types = new int[DTM.NTYPES + names.size()]; 811 for (int i = 0; i < types.length; i++) { 812 types[i] = i; 813 } 814 815 // Initialize isAttribute[] and isNamespace[] arrays 816 final boolean[] isAttribute = new boolean[types.length]; 817 final boolean[] isNamespace = new boolean[types.length]; 818 for (int i = 0; i < names.size(); i++) { 819 final String name = (String)names.elementAt(i); 820 isAttribute[i + DTM.NTYPES] = isAttributeName(name); 821 isNamespace[i + DTM.NTYPES] = isNamespaceName(name); 822 } 823 824 // Compile all templates - regardless of pattern type 825 compileTemplates(classGen, methodGen, ihLoop); 826 827 // Handle template with explicit "*" pattern 828 final TestSeq elemTest = _testSeq[DTM.ELEMENT_NODE]; 829 InstructionHandle ihElem = ihRecurse; 830 if (elemTest != null) 831 ihElem = elemTest.compile(classGen, methodGen, ihRecurse); 832 833 // Handle template with explicit "@*" pattern 834 final TestSeq attrTest = _testSeq[DTM.ATTRIBUTE_NODE]; 835 InstructionHandle ihAttr = ihText; 836 if (attrTest != null) 837 ihAttr = attrTest.compile(classGen, methodGen, ihAttr); 838 839 // Do tests for id() and key() patterns first 840 InstructionList ilKey = null; 841 if (_idxTestSeq != null) { 842 loop.setTarget(_idxTestSeq.compile(classGen, methodGen, body.getStart())); 843 ilKey = _idxTestSeq.getInstructionList(); 844 } 845 else { 846 loop.setTarget(body.getStart()); 847 } 848 849 // If there is a match on node() we need to replace ihElem 850 // and ihText if the priority of node() is higher 851 if (_childNodeTestSeq != null) { 852 // Compare priorities of node() and "*" 853 double nodePrio = _childNodeTestSeq.getPriority(); 854 int nodePos = _childNodeTestSeq.getPosition(); 855 double elemPrio = (0 - Double.MAX_VALUE); 856 int elemPos = Integer.MIN_VALUE; 857 858 if (elemTest != null) { 859 elemPrio = elemTest.getPriority(); 860 elemPos = elemTest.getPosition(); 861 } 862 if (elemPrio == Double.NaN || elemPrio < nodePrio || 863 (elemPrio == nodePrio && elemPos < nodePos)) 864 { 865 ihElem = _childNodeTestSeq.compile(classGen, methodGen, ihLoop); 866 } 867 868 // Compare priorities of node() and text() 869 final TestSeq textTest = _testSeq[DTM.TEXT_NODE]; 870 double textPrio = (0 - Double.MAX_VALUE); 871 int textPos = Integer.MIN_VALUE; 872 873 if (textTest != null) { 874 textPrio = textTest.getPriority(); 875 textPos = textTest.getPosition(); 876 } 877 if (textPrio == Double.NaN || textPrio < nodePrio || 878 (textPrio == nodePrio && textPos < nodePos)) 879 { 880 ihText = _childNodeTestSeq.compile(classGen, methodGen, ihLoop); 881 _testSeq[DTM.TEXT_NODE] = _childNodeTestSeq; 882 } 883 } 884 885 // Handle templates with "ns:*" pattern 886 InstructionHandle elemNamespaceHandle = ihElem; 887 InstructionList nsElem = compileNamespaces(classGen, methodGen, 888 isNamespace, isAttribute, 889 false, ihElem); 890 if (nsElem != null) elemNamespaceHandle = nsElem.getStart(); 891 892 // Handle templates with "ns:@*" pattern 893 InstructionHandle attrNamespaceHandle = ihAttr; 894 InstructionList nsAttr = compileNamespaces(classGen, methodGen, 895 isNamespace, isAttribute, 896 true, ihAttr); 897 if (nsAttr != null) attrNamespaceHandle = nsAttr.getStart(); 898 899 // Handle templates with "ns:elem" or "ns:@attr" pattern 900 final InstructionHandle[] targets = new InstructionHandle[types.length]; 901 for (int i = DTM.NTYPES; i < targets.length; i++) { 902 final TestSeq testSeq = _testSeq[i]; 903 // Jump straight to namespace tests ? 904 if (isNamespace[i]) { 905 if (isAttribute[i]) 906 targets[i] = attrNamespaceHandle; 907 else 908 targets[i] = elemNamespaceHandle; 909 } 910 // Test first, then jump to namespace tests 911 else if (testSeq != null) { 912 if (isAttribute[i]) 913 targets[i] = testSeq.compile(classGen, methodGen, 914 attrNamespaceHandle); 915 else 916 targets[i] = testSeq.compile(classGen, methodGen, 917 elemNamespaceHandle); 918 } 919 else { 920 targets[i] = ihLoop; 921 } 922 } 923 924 925 // Handle pattern with match on root node - default: traverse children 926 targets[DTM.ROOT_NODE] = _rootPattern != null 927 ? getTemplateInstructionHandle(_rootPattern.getTemplate()) 928 : ihRecurse; 929 930 // Handle pattern with match on root node - default: traverse children 931 targets[DTM.DOCUMENT_NODE] = _rootPattern != null 932 ? getTemplateInstructionHandle(_rootPattern.getTemplate()) 933 : ihRecurse; 934 935 // Handle any pattern with match on text nodes - default: output text 936 targets[DTM.TEXT_NODE] = _testSeq[DTM.TEXT_NODE] != null 937 ? _testSeq[DTM.TEXT_NODE].compile(classGen, methodGen, ihText) 938 : ihText; 939 940 // This DOM-type is not in use - default: process next node 941 targets[DTM.NAMESPACE_NODE] = ihLoop; 942 943 // Match unknown element in DOM - default: check for namespace match 944 targets[DTM.ELEMENT_NODE] = elemNamespaceHandle; 945 946 // Match unknown attribute in DOM - default: check for namespace match 947 targets[DTM.ATTRIBUTE_NODE] = attrNamespaceHandle; 948 949 // Match on processing instruction - default: process next node 950 InstructionHandle ihPI = ihLoop; 951 if (_childNodeTestSeq != null) ihPI = ihElem; 952 if (_testSeq[DTM.PROCESSING_INSTRUCTION_NODE] != null) 953 targets[DTM.PROCESSING_INSTRUCTION_NODE] = 954 _testSeq[DTM.PROCESSING_INSTRUCTION_NODE]. 955 compile(classGen, methodGen, ihPI); 956 else 957 targets[DTM.PROCESSING_INSTRUCTION_NODE] = ihPI; 958 959 // Match on comments - default: process next node 960 InstructionHandle ihComment = ihLoop; 961 if (_childNodeTestSeq != null) ihComment = ihElem; 962 targets[DTM.COMMENT_NODE] = _testSeq[DTM.COMMENT_NODE] != null 963 ? _testSeq[DTM.COMMENT_NODE].compile(classGen, methodGen, ihComment) 964 : ihComment; 965 966 // This DOM-type is not in use - default: process next node 967 targets[DTM.CDATA_SECTION_NODE] = ihLoop; 968 969 // This DOM-type is not in use - default: process next node 970 targets[DTM.DOCUMENT_FRAGMENT_NODE] = ihLoop; 971 972 // This DOM-type is not in use - default: process next node 973 targets[DTM.DOCUMENT_TYPE_NODE] = ihLoop; 974 975 // This DOM-type is not in use - default: process next node 976 targets[DTM.ENTITY_NODE] = ihLoop; 977 978 // This DOM-type is not in use - default: process next node 979 targets[DTM.ENTITY_REFERENCE_NODE] = ihLoop; 980 981 // This DOM-type is not in use - default: process next node 982 targets[DTM.NOTATION_NODE] = ihLoop; 983 984 985 // Now compile test sequences for various match patterns: 986 for (int i = DTM.NTYPES; i < targets.length; i++) { 987 final TestSeq testSeq = _testSeq[i]; 988 // Jump straight to namespace tests ? 989 if ((testSeq == null) || (isNamespace[i])) { 990 if (isAttribute[i]) 991 targets[i] = attrNamespaceHandle; 992 else 993 targets[i] = elemNamespaceHandle; 994 } 995 // Match on node type 996 else { 997 if (isAttribute[i]) 998 targets[i] = testSeq.compile(classGen, methodGen, 999 attrNamespaceHandle); 1000 else 1001 targets[i] = testSeq.compile(classGen, methodGen, 1002 elemNamespaceHandle); 1003 } 1004 } 1005 1006 if (ilKey != null) body.insert(ilKey); 1007 1008 // Append first code in applyTemplates() - get type of current node 1009 final int getType = cpg.addInterfaceMethodref(DOM_INTF, 1010 "getExpandedTypeID", 1011 "(I)I"); 1012 body.append(methodGen.loadDOM()); 1013 body.append(new ILOAD(_currentIndex)); 1014 body.append(new INVOKEINTERFACE(getType, 2)); 1015 1016 // Append switch() statement - main dispatch loop in applyTemplates() 1017 InstructionHandle disp = body.append(new SWITCH(types, targets, ihLoop)); 1018 1019 // Append all the "case:" statements 1020 appendTestSequences(body); 1021 // Append the actual template code 1022 appendTemplateCode(body); 1023 1024 // Append NS:* node tests (if any) 1025 if (nsElem != null) body.append(nsElem); 1026 // Append NS:@* node tests (if any) 1027 if (nsAttr != null) body.append(nsAttr); 1028 1029 // Append default action for element and root nodes 1030 body.append(ilRecurse); 1031 // Append default action for text and attribute nodes 1032 body.append(ilText); 1033 1034 // putting together constituent instruction lists 1035 mainIL.append(body); 1036 // fall through to ilLoop 1037 mainIL.append(ilLoop); 1038 1039 peepHoleOptimization(methodGen); 1040 classGen.addMethod(methodGen); 1041 1042 // Compile method(s) for <xsl:apply-imports/> for this mode 1043 if (_importLevels != null) { 1044 for (Map.Entry<Integer, Integer> entry : _importLevels.entrySet()) { 1045 compileApplyImports(classGen, entry.getValue(), entry.getKey()); 1046 } 1047 } 1048 } 1049 1050 private void compileTemplateCalls(ClassGenerator classGen, 1051 MethodGenerator methodGen, 1052 InstructionHandle next, int min, int max){ 1053 _neededTemplates.keySet().stream().forEach((template) -> { 1054 final int prec = template.getImportPrecedence(); 1055 if ((prec >= min) && (prec < max)) { 1056 if (template.hasContents()) { 1057 InstructionList til = template.compile(classGen, methodGen); 1058 til.append(new GOTO_W(next)); 1059 _templateILs.put(template, til); 1060 _templateIHs.put(template, til.getStart()); 1061 } 1062 else { 1063 // empty template 1064 _templateIHs.put(template, next); 1065 } 1066 } 1067 }); 1068 } 1069 1070 1071 public void compileApplyImports(ClassGenerator classGen, int min, int max) { 1072 final XSLTC xsltc = classGen.getParser().getXSLTC(); 1073 final ConstantPoolGen cpg = classGen.getConstantPool(); 1074 final Vector names = xsltc.getNamesIndex(); 1075 1076 // Clear some datastructures 1077 _namedTemplates = new HashMap<>(); 1078 _neededTemplates = new HashMap<>(); 1079 _templateIHs = new HashMap<>(); 1080 _templateILs = new HashMap<>(); 1081 _patternGroups = new Vector[32]; 1082 _rootPattern = null; 1083 1084 // IMPORTANT: Save orignal & complete set of templates!!!! 1085 Vector oldTemplates = _templates; 1086 1087 // Gather templates that are within the scope of this import 1088 _templates = new Vector(); 1089 final Enumeration templates = oldTemplates.elements(); 1090 while (templates.hasMoreElements()) { 1091 final Template template = (Template)templates.nextElement(); 1092 final int prec = template.getImportPrecedence(); 1093 if ((prec >= min) && (prec < max)) addTemplate(template); 1094 } 1095 1096 // Process all patterns from those templates 1097 processPatterns(_keys); 1098 1099 // Create the applyTemplates() method 1100 final com.sun.org.apache.bcel.internal.generic.Type[] argTypes = 1101 new com.sun.org.apache.bcel.internal.generic.Type[4]; 1102 argTypes[0] = Util.getJCRefType(DOM_INTF_SIG); 1103 argTypes[1] = Util.getJCRefType(NODE_ITERATOR_SIG); 1104 argTypes[2] = Util.getJCRefType(TRANSLET_OUTPUT_SIG); 1105 argTypes[3] = com.sun.org.apache.bcel.internal.generic.Type.INT; 1106 1107 final String[] argNames = new String[4]; 1108 argNames[0] = DOCUMENT_PNAME; 1109 argNames[1] = ITERATOR_PNAME; 1110 argNames[2] = TRANSLET_OUTPUT_PNAME; 1111 argNames[3] = NODE_PNAME; 1112 1113 final InstructionList mainIL = new InstructionList(); 1114 final MethodGenerator methodGen = 1115 new MethodGenerator(ACC_PUBLIC | ACC_FINAL, 1116 com.sun.org.apache.bcel.internal.generic.Type.VOID, 1117 argTypes, argNames, functionName()+'_'+max, 1118 getClassName(), mainIL, 1119 classGen.getConstantPool()); 1120 methodGen.addException("com.sun.org.apache.xalan.internal.xsltc.TransletException"); 1121 1122 // Create the local variable to hold the current node 1123 final LocalVariableGen current; 1124 current = methodGen.addLocalVariable2("current", 1125 com.sun.org.apache.bcel.internal.generic.Type.INT, 1126 null); 1127 _currentIndex = current.getIndex(); 1128 1129 mainIL.append(new ILOAD(methodGen.getLocalIndex(NODE_PNAME))); 1130 current.setStart(mainIL.append(new ISTORE(_currentIndex))); 1131 1132 // Create the "body" instruction list that will eventually hold the 1133 // code for the entire method (other ILs will be appended). 1134 final InstructionList body = new InstructionList(); 1135 body.append(NOP); 1136 1137 // Create an instruction list that contains the default next-node 1138 // iteration 1139 final InstructionList ilLoop = new InstructionList(); 1140 ilLoop.append(RETURN); 1141 final InstructionHandle ihLoop = ilLoop.getStart(); 1142 1143 // Compile default handling of elements (traverse children) 1144 InstructionList ilRecurse = 1145 compileDefaultRecursion(classGen, methodGen, ihLoop); 1146 InstructionHandle ihRecurse = ilRecurse.getStart(); 1147 1148 // Compile default handling of text/attribute nodes (output text) 1149 InstructionList ilText = 1150 compileDefaultText(classGen, methodGen, ihLoop); 1151 InstructionHandle ihText = ilText.getStart(); 1152 1153 // Distinguish attribute/element/namespace tests for further processing 1154 final int[] types = new int[DTM.NTYPES + names.size()]; 1155 for (int i = 0; i < types.length; i++) { 1156 types[i] = i; 1157 } 1158 1159 final boolean[] isAttribute = new boolean[types.length]; 1160 final boolean[] isNamespace = new boolean[types.length]; 1161 for (int i = 0; i < names.size(); i++) { 1162 final String name = (String)names.elementAt(i); 1163 isAttribute[i+DTM.NTYPES] = isAttributeName(name); 1164 isNamespace[i+DTM.NTYPES] = isNamespaceName(name); 1165 } 1166 1167 // Compile all templates - regardless of pattern type 1168 compileTemplateCalls(classGen, methodGen, ihLoop, min, max); 1169 1170 // Handle template with explicit "*" pattern 1171 final TestSeq elemTest = _testSeq[DTM.ELEMENT_NODE]; 1172 InstructionHandle ihElem = ihRecurse; 1173 if (elemTest != null) { 1174 ihElem = elemTest.compile(classGen, methodGen, ihLoop); 1175 } 1176 1177 // Handle template with explicit "@*" pattern 1178 final TestSeq attrTest = _testSeq[DTM.ATTRIBUTE_NODE]; 1179 InstructionHandle ihAttr = ihLoop; 1180 if (attrTest != null) { 1181 ihAttr = attrTest.compile(classGen, methodGen, ihAttr); 1182 } 1183 1184 // Do tests for id() and key() patterns first 1185 InstructionList ilKey = null; 1186 if (_idxTestSeq != null) { 1187 ilKey = _idxTestSeq.getInstructionList(); 1188 } 1189 1190 // If there is a match on node() we need to replace ihElem 1191 // and ihText if the priority of node() is higher 1192 if (_childNodeTestSeq != null) { 1193 // Compare priorities of node() and "*" 1194 double nodePrio = _childNodeTestSeq.getPriority(); 1195 int nodePos = _childNodeTestSeq.getPosition(); 1196 double elemPrio = (0 - Double.MAX_VALUE); 1197 int elemPos = Integer.MIN_VALUE; 1198 1199 if (elemTest != null) { 1200 elemPrio = elemTest.getPriority(); 1201 elemPos = elemTest.getPosition(); 1202 } 1203 1204 if (elemPrio == Double.NaN || elemPrio < nodePrio || 1205 (elemPrio == nodePrio && elemPos < nodePos)) 1206 { 1207 ihElem = _childNodeTestSeq.compile(classGen, methodGen, ihLoop); 1208 } 1209 1210 // Compare priorities of node() and text() 1211 final TestSeq textTest = _testSeq[DTM.TEXT_NODE]; 1212 double textPrio = (0 - Double.MAX_VALUE); 1213 int textPos = Integer.MIN_VALUE; 1214 1215 if (textTest != null) { 1216 textPrio = textTest.getPriority(); 1217 textPos = textTest.getPosition(); 1218 } 1219 1220 if (textPrio == Double.NaN || textPrio < nodePrio || 1221 (textPrio == nodePrio && textPos < nodePos)) 1222 { 1223 ihText = _childNodeTestSeq.compile(classGen, methodGen, ihLoop); 1224 _testSeq[DTM.TEXT_NODE] = _childNodeTestSeq; 1225 } 1226 } 1227 1228 // Handle templates with "ns:*" pattern 1229 InstructionHandle elemNamespaceHandle = ihElem; 1230 InstructionList nsElem = compileNamespaces(classGen, methodGen, 1231 isNamespace, isAttribute, 1232 false, ihElem); 1233 if (nsElem != null) elemNamespaceHandle = nsElem.getStart(); 1234 1235 // Handle templates with "ns:@*" pattern 1236 InstructionList nsAttr = compileNamespaces(classGen, methodGen, 1237 isNamespace, isAttribute, 1238 true, ihAttr); 1239 InstructionHandle attrNamespaceHandle = ihAttr; 1240 if (nsAttr != null) attrNamespaceHandle = nsAttr.getStart(); 1241 1242 // Handle templates with "ns:elem" or "ns:@attr" pattern 1243 final InstructionHandle[] targets = new InstructionHandle[types.length]; 1244 for (int i = DTM.NTYPES; i < targets.length; i++) { 1245 final TestSeq testSeq = _testSeq[i]; 1246 // Jump straight to namespace tests ? 1247 if (isNamespace[i]) { 1248 if (isAttribute[i]) 1249 targets[i] = attrNamespaceHandle; 1250 else 1251 targets[i] = elemNamespaceHandle; 1252 } 1253 // Test first, then jump to namespace tests 1254 else if (testSeq != null) { 1255 if (isAttribute[i]) 1256 targets[i] = testSeq.compile(classGen, methodGen, 1257 attrNamespaceHandle); 1258 else 1259 targets[i] = testSeq.compile(classGen, methodGen, 1260 elemNamespaceHandle); 1261 } 1262 else { 1263 targets[i] = ihLoop; 1264 } 1265 } 1266 1267 // Handle pattern with match on root node - default: traverse children 1268 targets[DTM.ROOT_NODE] = _rootPattern != null 1269 ? getTemplateInstructionHandle(_rootPattern.getTemplate()) 1270 : ihRecurse; 1271 // Handle pattern with match on root node - default: traverse children 1272 targets[DTM.DOCUMENT_NODE] = _rootPattern != null 1273 ? getTemplateInstructionHandle(_rootPattern.getTemplate()) 1274 : ihRecurse; // %HZ%: Was ihLoop in XSLTC_DTM branch 1275 1276 // Handle any pattern with match on text nodes - default: loop 1277 targets[DTM.TEXT_NODE] = _testSeq[DTM.TEXT_NODE] != null 1278 ? _testSeq[DTM.TEXT_NODE].compile(classGen, methodGen, ihText) 1279 : ihText; 1280 1281 // This DOM-type is not in use - default: process next node 1282 targets[DTM.NAMESPACE_NODE] = ihLoop; 1283 1284 // Match unknown element in DOM - default: check for namespace match 1285 targets[DTM.ELEMENT_NODE] = elemNamespaceHandle; 1286 1287 // Match unknown attribute in DOM - default: check for namespace match 1288 targets[DTM.ATTRIBUTE_NODE] = attrNamespaceHandle; 1289 1290 // Match on processing instruction - default: loop 1291 InstructionHandle ihPI = ihLoop; 1292 if (_childNodeTestSeq != null) ihPI = ihElem; 1293 if (_testSeq[DTM.PROCESSING_INSTRUCTION_NODE] != null) { 1294 targets[DTM.PROCESSING_INSTRUCTION_NODE] = 1295 _testSeq[DTM.PROCESSING_INSTRUCTION_NODE]. 1296 compile(classGen, methodGen, ihPI); 1297 } 1298 else { 1299 targets[DTM.PROCESSING_INSTRUCTION_NODE] = ihPI; 1300 } 1301 1302 // Match on comments - default: process next node 1303 InstructionHandle ihComment = ihLoop; 1304 if (_childNodeTestSeq != null) ihComment = ihElem; 1305 targets[DTM.COMMENT_NODE] = _testSeq[DTM.COMMENT_NODE] != null 1306 ? _testSeq[DTM.COMMENT_NODE].compile(classGen, methodGen, ihComment) 1307 : ihComment; 1308 1309 // This DOM-type is not in use - default: process next node 1310 targets[DTM.CDATA_SECTION_NODE] = ihLoop; 1311 1312 // This DOM-type is not in use - default: process next node 1313 targets[DTM.DOCUMENT_FRAGMENT_NODE] = ihLoop; 1314 1315 // This DOM-type is not in use - default: process next node 1316 targets[DTM.DOCUMENT_TYPE_NODE] = ihLoop; 1317 1318 // This DOM-type is not in use - default: process next node 1319 targets[DTM.ENTITY_NODE] = ihLoop; 1320 1321 // This DOM-type is not in use - default: process next node 1322 targets[DTM.ENTITY_REFERENCE_NODE] = ihLoop; 1323 1324 // This DOM-type is not in use - default: process next node 1325 targets[DTM.NOTATION_NODE] = ihLoop; 1326 1327 1328 1329 // Now compile test sequences for various match patterns: 1330 for (int i = DTM.NTYPES; i < targets.length; i++) { 1331 final TestSeq testSeq = _testSeq[i]; 1332 // Jump straight to namespace tests ? 1333 if ((testSeq == null) || (isNamespace[i])) { 1334 if (isAttribute[i]) 1335 targets[i] = attrNamespaceHandle; 1336 else 1337 targets[i] = elemNamespaceHandle; 1338 } 1339 // Match on node type 1340 else { 1341 if (isAttribute[i]) 1342 targets[i] = testSeq.compile(classGen, methodGen, 1343 attrNamespaceHandle); 1344 else 1345 targets[i] = testSeq.compile(classGen, methodGen, 1346 elemNamespaceHandle); 1347 } 1348 } 1349 1350 if (ilKey != null) body.insert(ilKey); 1351 1352 // Append first code in applyTemplates() - get type of current node 1353 final int getType = cpg.addInterfaceMethodref(DOM_INTF, 1354 "getExpandedTypeID", 1355 "(I)I"); 1356 body.append(methodGen.loadDOM()); 1357 body.append(new ILOAD(_currentIndex)); 1358 body.append(new INVOKEINTERFACE(getType, 2)); 1359 1360 // Append switch() statement - main dispatch loop in applyTemplates() 1361 InstructionHandle disp = body.append(new SWITCH(types,targets,ihLoop)); 1362 1363 // Append all the "case:" statements 1364 appendTestSequences(body); 1365 // Append the actual template code 1366 appendTemplateCode(body); 1367 1368 // Append NS:* node tests (if any) 1369 if (nsElem != null) body.append(nsElem); 1370 // Append NS:@* node tests (if any) 1371 if (nsAttr != null) body.append(nsAttr); 1372 1373 // Append default action for element and root nodes 1374 body.append(ilRecurse); 1375 // Append default action for text and attribute nodes 1376 body.append(ilText); 1377 1378 // putting together constituent instruction lists 1379 mainIL.append(body); 1380 1381 // Mark the end of the live range for the "current" variable 1382 current.setEnd(body.getEnd()); 1383 1384 // fall through to ilLoop 1385 mainIL.append(ilLoop); 1386 1387 peepHoleOptimization(methodGen); 1388 classGen.addMethod(methodGen); 1389 1390 // Restore original (complete) set of templates for this transformation 1391 _templates = oldTemplates; 1392 } 1393 1394 /** 1395 * Peephole optimization. 1396 */ 1397 private void peepHoleOptimization(MethodGenerator methodGen) { 1398 InstructionList il = methodGen.getInstructionList(); 1399 InstructionFinder find = new InstructionFinder(il); 1400 InstructionHandle ih; 1401 String pattern; 1402 1403 // LoadInstruction, POP => (removed) 1404 // pattern = "LoadInstruction POP"; 1405 // changed to lower case - changing to all lower case although only the instruction with capital I 1406 // is creating a problem in the Turkish locale 1407 pattern = "loadinstruction pop"; 1408 1409 for (Iterator iter = find.search(pattern); iter.hasNext();) { 1410 InstructionHandle[] match = (InstructionHandle[]) iter.next(); 1411 try { 1412 if (!match[0].hasTargeters() && !match[1].hasTargeters()) { 1413 il.delete(match[0], match[1]); 1414 } 1415 } 1416 catch (TargetLostException e) { 1417 // TODO: move target down into the list 1418 } 1419 } 1420 1421 // ILOAD_N, ILOAD_N, SWAP, ISTORE_N => ILOAD_N 1422 // pattern = "ILOAD ILOAD SWAP ISTORE"; 1423 // changed to lower case - changing to all lower case although only the instruction with capital I 1424 // is creating a problem in the Turkish locale 1425 pattern = "iload iload swap istore"; 1426 for (Iterator iter = find.search(pattern); iter.hasNext();) { 1427 InstructionHandle[] match = (InstructionHandle[]) iter.next(); 1428 try { 1429 com.sun.org.apache.bcel.internal.generic.ILOAD iload1 = 1430 (com.sun.org.apache.bcel.internal.generic.ILOAD) match[0].getInstruction(); 1431 com.sun.org.apache.bcel.internal.generic.ILOAD iload2 = 1432 (com.sun.org.apache.bcel.internal.generic.ILOAD) match[1].getInstruction(); 1433 com.sun.org.apache.bcel.internal.generic.ISTORE istore = 1434 (com.sun.org.apache.bcel.internal.generic.ISTORE) match[3].getInstruction(); 1435 1436 if (!match[1].hasTargeters() && 1437 !match[2].hasTargeters() && 1438 !match[3].hasTargeters() && 1439 iload1.getIndex() == iload2.getIndex() && 1440 iload2.getIndex() == istore.getIndex()) 1441 { 1442 il.delete(match[1], match[3]); 1443 } 1444 } 1445 catch (TargetLostException e) { 1446 // TODO: move target down into the list 1447 } 1448 } 1449 1450 // LoadInstruction_N, LoadInstruction_M, SWAP => LoadInstruction_M, LoadInstruction_N 1451 // pattern = "LoadInstruction LoadInstruction SWAP"; 1452 // changed to lower case - changing to all lower case although only the instruction with capital I 1453 // is creating a problem in the Turkish locale 1454 pattern = "loadinstruction loadinstruction swap"; 1455 for (Iterator iter = find.search(pattern); iter.hasNext();) { 1456 InstructionHandle[] match = (InstructionHandle[])iter.next(); 1457 try { 1458 if (!match[0].hasTargeters() && 1459 !match[1].hasTargeters() && 1460 !match[2].hasTargeters()) 1461 { 1462 Instruction load_m = match[1].getInstruction(); 1463 il.insert(match[0], load_m); 1464 il.delete(match[1], match[2]); 1465 } 1466 } 1467 catch (TargetLostException e) { 1468 // TODO: move target down into the list 1469 } 1470 } 1471 1472 // ALOAD_N ALOAD_N => ALOAD_N DUP 1473 // pattern = "ALOAD ALOAD"; 1474 // changed to lower case - changing to all lower case although only the instruction with capital I 1475 // is creating a problem in the Turkish locale 1476 pattern = "aload aload"; 1477 for (Iterator iter = find.search(pattern); iter.hasNext();) { 1478 InstructionHandle[] match = (InstructionHandle[])iter.next(); 1479 try { 1480 if (!match[1].hasTargeters()) { 1481 com.sun.org.apache.bcel.internal.generic.ALOAD aload1 = 1482 (com.sun.org.apache.bcel.internal.generic.ALOAD) match[0].getInstruction(); 1483 com.sun.org.apache.bcel.internal.generic.ALOAD aload2 = 1484 (com.sun.org.apache.bcel.internal.generic.ALOAD) match[1].getInstruction(); 1485 1486 if (aload1.getIndex() == aload2.getIndex()) { 1487 il.insert(match[1], new DUP()); 1488 il.delete(match[1]); 1489 } 1490 } 1491 } 1492 catch (TargetLostException e) { 1493 // TODO: move target down into the list 1494 } 1495 } 1496 } 1497 1498 public InstructionHandle getTemplateInstructionHandle(Template template) { 1499 return _templateIHs.get(template); 1500 } 1501 1502 /** 1503 * Auxiliary method to determine if a qname is an attribute. 1504 */ 1505 private static boolean isAttributeName(String qname) { 1506 final int col = qname.lastIndexOf(':') + 1; 1507 return (qname.charAt(col) == '@'); 1508 } 1509 1510 /** 1511 * Auxiliary method to determine if a qname is a namespace 1512 * qualified "*". 1513 */ 1514 private static boolean isNamespaceName(String qname) { 1515 final int col = qname.lastIndexOf(':'); 1516 return (col > -1 && qname.charAt(qname.length()-1) == '*'); 1517 } 1518} 1519