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