< prev index next >

src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Sort.java

Print this page
rev 886 : 8150704: XALAN: ERROR: 'No more DTM IDs are available' when transforming with lots of temporary result trees
   1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   4  */
   5 /*
   6  * Copyright 2001-2005 The Apache Software Foundation.
   7  *
   8  * Licensed under the Apache License, Version 2.0 (the "License");
   9  * you may not use this file except in compliance with the License.
  10  * You may obtain a copy of the License at
  11  *
  12  *     http://www.apache.org/licenses/LICENSE-2.0
  13  *
  14  * Unless required by applicable law or agreed to in writing, software
  15  * distributed under the License is distributed on an "AS IS" BASIS,
  16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17  * See the License for the specific language governing permissions and
  18  * limitations under the License.
  19  */
  20 /*
  21  * $Id: Sort.java,v 1.2.4.1 2005/09/12 11:08:12 pvedula Exp $
  22  */
  23 
  24 package com.sun.org.apache.xalan.internal.xsltc.compiler;
  25 
  26 import java.text.Collator;
  27 import java.util.ArrayList;
  28 import java.util.NoSuchElementException;
  29 import java.util.StringTokenizer;
  30 import java.util.Vector;
  31 
  32 import com.sun.org.apache.bcel.internal.classfile.Field;
  33 import com.sun.org.apache.bcel.internal.classfile.Method;
  34 import com.sun.org.apache.bcel.internal.generic.ALOAD;
  35 import com.sun.org.apache.bcel.internal.generic.ANEWARRAY;
  36 import com.sun.org.apache.bcel.internal.generic.ASTORE;
  37 import com.sun.org.apache.bcel.internal.generic.CHECKCAST;
  38 import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
  39 import com.sun.org.apache.bcel.internal.generic.GETFIELD;
  40 import com.sun.org.apache.bcel.internal.generic.ICONST;
  41 import com.sun.org.apache.bcel.internal.generic.ILOAD;
  42 import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
  43 import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL;
  44 import com.sun.org.apache.bcel.internal.generic.INVOKESTATIC;
  45 import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
  46 import com.sun.org.apache.bcel.internal.generic.InstructionHandle;
  47 import com.sun.org.apache.bcel.internal.generic.InstructionList;
  48 import com.sun.org.apache.bcel.internal.generic.LocalVariableGen;
  49 import com.sun.org.apache.bcel.internal.generic.NEW;
  50 import com.sun.org.apache.bcel.internal.generic.NOP;
  51 import com.sun.org.apache.bcel.internal.generic.PUSH;
  52 import com.sun.org.apache.bcel.internal.generic.PUTFIELD;
  53 import com.sun.org.apache.bcel.internal.generic.TABLESWITCH;
  54 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
  55 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.CompareGenerator;
  56 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
  57 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.IntType;
  58 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
  59 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeSortRecordFactGenerator;
  60 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeSortRecordGenerator;
  61 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.StringType;
  62 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
  63 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
  64 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;
  65 import com.sun.org.apache.xml.internal.dtm.Axis;
  66 
  67 
  68 /**
  69  * @author Jacek Ambroziak
  70  * @author Santiago Pericas-Geertsen
  71  * @author Morten Jorgensen
  72  */
  73 final class Sort extends Instruction implements Closure {
  74 
  75     private Expression     _select;
  76     private AttributeValue _order;
  77     private AttributeValue _caseOrder;
  78     private AttributeValue _dataType;
  79     private String  _lang; // bug! see 26869
  80 
  81     private String         _data = null;
  82 
  83 
  84     private String _className = null;
  85     private ArrayList _closureVars = null;
  86     private boolean _needsSortRecordFactory = false;
  87 
  88     // -- Begin Closure interface --------------------
  89 
  90     /**
  91      * Returns true if this closure is compiled in an inner class (i.e.
  92      * if this is a real closure).
  93      */
  94     public boolean inInnerClass() {
  95         return (_className != null);
  96     }
  97 
  98     /**
  99      * Returns a reference to its parent closure or null if outermost.
 100      */
 101     public Closure getParentClosure() {
 102         return null;
 103     }
 104 
 105     /**
 106      * Returns the name of the auxiliary class or null if this predicate
 107      * is compiled inside the Translet.
 108      */
 109     public String getInnerClassName() {
 110         return _className;
 111     }
 112 
 113     /**
 114      * Add new variable to the closure.
 115      */
 116     public void addVariable(VariableRefBase variableRef) {
 117         if (_closureVars == null) {
 118             _closureVars = new ArrayList();
 119         }
 120 
 121         // Only one reference per variable
 122         if (!_closureVars.contains(variableRef)) {
 123             _closureVars.add(variableRef);
 124             _needsSortRecordFactory = true;
 125         }
 126     }
 127 
 128     // -- End Closure interface ----------------------
 129 
 130     private void setInnerClassName(String className) {
 131         _className = className;
 132     }
 133 
 134     /**
 135      * Parse the attributes of the xsl:sort element
 136      */
 137     public void parseContents(Parser parser) {
 138 


 229     public void translateSelect(ClassGenerator classGen,
 230                                 MethodGenerator methodGen) {
 231         _select.translate(classGen,methodGen);
 232     }
 233 
 234     /**
 235      * This method should not produce any code
 236      */
 237     public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
 238         // empty
 239     }
 240 
 241     /**
 242      * Compiles code that instantiates a SortingIterator object.
 243      * This object's constructor needs referencdes to the current iterator
 244      * and a node sort record producing objects as its parameters.
 245      */
 246     public static void translateSortIterator(ClassGenerator classGen,
 247                                       MethodGenerator methodGen,
 248                                       Expression nodeSet,
 249                                       Vector sortObjects)
 250     {
 251         final ConstantPoolGen cpg = classGen.getConstantPool();
 252         final InstructionList il = methodGen.getInstructionList();
 253 
 254         // SortingIterator.SortingIterator(NodeIterator,NodeSortRecordFactory);
 255         final int init = cpg.addMethodref(SORT_ITERATOR, "<init>",
 256                                           "("
 257                                           + NODE_ITERATOR_SIG
 258                                           + NODE_SORT_FACTORY_SIG
 259                                           + ")V");
 260 
 261         // Backwards branches are prohibited if an uninitialized object is
 262         // on the stack by section 4.9.4 of the JVM Specification, 2nd Ed.
 263         // We don't know whether this code might contain backwards branches
 264         // so we mustn't create the new object until after we've created
 265         // the suspect arguments to its constructor.  Instead we calculate
 266         // the values of the arguments to the constructor first, store them
 267         // in temporary variables, create the object and reload the
 268         // arguments from the temporaries to avoid the problem.
 269 


 295 
 296         // Compile the code for the NodeSortRecord producing class and pass
 297         // that as the last argument to the SortingIterator constructor.
 298         compileSortRecordFactory(sortObjects, classGen, methodGen);
 299         sortRecordFactoryTemp.setStart(
 300                 il.append(new ASTORE(sortRecordFactoryTemp.getIndex())));
 301 
 302         il.append(new NEW(cpg.addClass(SORT_ITERATOR)));
 303         il.append(DUP);
 304         nodesTemp.setEnd(il.append(new ALOAD(nodesTemp.getIndex())));
 305         sortRecordFactoryTemp.setEnd(
 306                 il.append(new ALOAD(sortRecordFactoryTemp.getIndex())));
 307         il.append(new INVOKESPECIAL(init));
 308     }
 309 
 310 
 311     /**
 312      * Compiles code that instantiates a NodeSortRecordFactory object which
 313      * will produce NodeSortRecord objects of a specific type.
 314      */
 315     public static void compileSortRecordFactory(Vector sortObjects,
 316         ClassGenerator classGen, MethodGenerator methodGen)
 317     {
 318         String sortRecordClass =
 319             compileSortRecord(sortObjects, classGen, methodGen);
 320 
 321         boolean needsSortRecordFactory = false;
 322         final int nsorts = sortObjects.size();
 323         for (int i = 0; i < nsorts; i++) {
 324             final Sort sort = (Sort) sortObjects.elementAt(i);
 325             needsSortRecordFactory |= sort._needsSortRecordFactory;
 326         }
 327 
 328         String sortRecordFactoryClass = NODE_SORT_FACTORY;
 329         if (needsSortRecordFactory) {
 330             sortRecordFactoryClass =
 331                 compileSortRecordFactory(sortObjects, classGen, methodGen,
 332                     sortRecordClass);
 333         }
 334 
 335         final ConstantPoolGen cpg = classGen.getConstantPool();
 336         final InstructionList il = methodGen.getInstructionList();
 337 
 338         // Backwards branches are prohibited if an uninitialized object is
 339         // on the stack by section 4.9.4 of the JVM Specification, 2nd Ed.
 340         // We don't know whether this code might contain backwards branches
 341         // so we mustn't create the new object until after we've created
 342         // the suspect arguments to its constructor.  Instead we calculate
 343         // the values of the arguments to the constructor first, store them
 344         // in temporary variables, create the object and reload the


 412         il.append(new PUSH(cpg, sortRecordClass));
 413         il.append(classGen.loadTranslet());
 414 
 415         sortOrderTemp.setEnd(il.append(new ALOAD(sortOrderTemp.getIndex())));
 416         sortTypeTemp.setEnd(il.append(new ALOAD(sortTypeTemp.getIndex())));
 417         sortLangTemp.setEnd(il.append(new ALOAD(sortLangTemp.getIndex())));
 418         sortCaseOrderTemp.setEnd(
 419                 il.append(new ALOAD(sortCaseOrderTemp.getIndex())));
 420 
 421         il.append(new INVOKESPECIAL(
 422             cpg.addMethodref(sortRecordFactoryClass, "<init>",
 423                 "(" + DOM_INTF_SIG
 424                     + STRING_SIG
 425                     + TRANSLET_INTF_SIG
 426                     + "[" + STRING_SIG
 427                     + "[" + STRING_SIG
 428                     + "[" + STRING_SIG
 429                     + "[" + STRING_SIG + ")V")));
 430 
 431         // Initialize closure variables in sortRecordFactory
 432         final ArrayList dups = new ArrayList();
 433 
 434         for (int j = 0; j < nsorts; j++) {
 435             final Sort sort = (Sort) sortObjects.get(j);
 436             final int length = (sort._closureVars == null) ? 0 :
 437                 sort._closureVars.size();
 438 
 439             for (int i = 0; i < length; i++) {
 440                 VariableRefBase varRef = (VariableRefBase) sort._closureVars.get(i);
 441 
 442                 // Discard duplicate variable references
 443                 if (dups.contains(varRef)) continue;
 444 
 445                 final VariableBase var = varRef.getVariable();
 446 
 447                 // Store variable in new closure
 448                 il.append(DUP);
 449                 il.append(var.loadInstruction());
 450                 il.append(new PUTFIELD(
 451                         cpg.addFieldref(sortRecordFactoryClass, var.getEscapedName(),
 452                             var.getType().toSignature())));
 453                 dups.add(varRef);
 454             }
 455         }
 456     }
 457 
 458     public static String compileSortRecordFactory(Vector sortObjects,
 459         ClassGenerator classGen, MethodGenerator methodGen,
 460         String sortRecordClass)
 461     {
 462         final XSLTC  xsltc = ((Sort)sortObjects.firstElement()).getXSLTC();
 463         final String className = xsltc.getHelperClassName();
 464 
 465         final NodeSortRecordFactGenerator sortRecordFactory =
 466             new NodeSortRecordFactGenerator(className,
 467                                         NODE_SORT_FACTORY,
 468                                         className + ".java",
 469                                         ACC_PUBLIC | ACC_SUPER | ACC_FINAL,
 470                                         new String[] {},
 471                                         classGen.getStylesheet());
 472 
 473         ConstantPoolGen cpg = sortRecordFactory.getConstantPool();
 474 
 475         // Add a new instance variable for each var in closure
 476         final int nsorts = sortObjects.size();
 477         final ArrayList dups = new ArrayList();
 478 
 479         for (int j = 0; j < nsorts; j++) {
 480             final Sort sort = (Sort) sortObjects.get(j);
 481             final int length = (sort._closureVars == null) ? 0 :
 482                 sort._closureVars.size();
 483 
 484             for (int i = 0; i < length; i++) {
 485                 final VariableRefBase varRef = (VariableRefBase) sort._closureVars.get(i);
 486 
 487                 // Discard duplicate variable references
 488                 if (dups.contains(varRef)) continue;
 489 
 490                 final VariableBase var = varRef.getVariable();
 491                 sortRecordFactory.addField(new Field(ACC_PUBLIC,
 492                                            cpg.addUtf8(var.getEscapedName()),
 493                                            cpg.addUtf8(var.getType().toSignature()),
 494                                            null, cpg.getConstantPool()));
 495                 dups.add(varRef);
 496             }
 497         }
 498 
 499         // Define a constructor for this class
 500         final com.sun.org.apache.bcel.internal.generic.Type[] argTypes =
 501             new com.sun.org.apache.bcel.internal.generic.Type[7];
 502         argTypes[0] = Util.getJCRefType(DOM_INTF_SIG);
 503         argTypes[1] = Util.getJCRefType(STRING_SIG);
 504         argTypes[2] = Util.getJCRefType(TRANSLET_INTF_SIG);
 505         argTypes[3] = Util.getJCRefType("[" + STRING_SIG);


 583                 cpg.addFieldref(sortRecordClass,
 584                     var.getEscapedName(), varType.toSignature())));
 585         }
 586         il.append(POP);
 587         il.append(ARETURN);
 588 
 589         constructor.setMaxLocals();
 590         constructor.setMaxStack();
 591         sortRecordFactory.addMethod(constructor);
 592         makeNodeSortRecord.setMaxLocals();
 593         makeNodeSortRecord.setMaxStack();
 594         sortRecordFactory.addMethod(makeNodeSortRecord);
 595         xsltc.dumpClass(sortRecordFactory.getJavaClass());
 596 
 597         return className;
 598     }
 599 
 600     /**
 601      * Create a new auxillary class extending NodeSortRecord.
 602      */
 603     private static String compileSortRecord(Vector sortObjects,
 604                                             ClassGenerator classGen,
 605                                             MethodGenerator methodGen) {
 606         final XSLTC  xsltc = ((Sort)sortObjects.firstElement()).getXSLTC();
 607         final String className = xsltc.getHelperClassName();
 608 
 609         // This generates a new class for handling this specific sort
 610         final NodeSortRecordGenerator sortRecord =
 611             new NodeSortRecordGenerator(className,
 612                                         NODE_SORT_RECORD,
 613                                         "sort$0.java",
 614                                         ACC_PUBLIC | ACC_SUPER | ACC_FINAL,
 615                                         new String[] {},
 616                                         classGen.getStylesheet());
 617 
 618         final ConstantPoolGen cpg = sortRecord.getConstantPool();
 619 
 620         // Add a new instance variable for each var in closure
 621         final int nsorts = sortObjects.size();
 622         final ArrayList dups = new ArrayList();
 623 
 624         for (int j = 0; j < nsorts; j++) {
 625             final Sort sort = (Sort) sortObjects.get(j);
 626 
 627             // Set the name of the inner class in this sort object
 628             sort.setInnerClassName(className);
 629 
 630             final int length = (sort._closureVars == null) ? 0 :
 631                 sort._closureVars.size();
 632             for (int i = 0; i < length; i++) {
 633                 final VariableRefBase varRef = (VariableRefBase) sort._closureVars.get(i);
 634 
 635                 // Discard duplicate variable references
 636                 if (dups.contains(varRef)) continue;
 637 
 638                 final VariableBase var = varRef.getVariable();
 639                 sortRecord.addField(new Field(ACC_PUBLIC,
 640                                     cpg.addUtf8(var.getEscapedName()),
 641                                     cpg.addUtf8(var.getType().toSignature()),
 642                                     null, cpg.getConstantPool()));
 643                 dups.add(varRef);
 644             }
 645         }
 646 
 647         MethodGenerator init = compileInit(sortObjects, sortRecord,
 648                                          cpg, className);
 649         MethodGenerator extract = compileExtract(sortObjects, sortRecord,
 650                                         cpg, className);
 651         sortRecord.addMethod(init);
 652         sortRecord.addMethod(extract);
 653 
 654         xsltc.dumpClass(sortRecord.getJavaClass());
 655         return className;
 656     }
 657 
 658     /**
 659      * Create a constructor for the new class. Updates the reference to the
 660      * collator in the super calls only when the stylesheet specifies a new
 661      * language in xsl:sort.
 662      */
 663     private static MethodGenerator compileInit(Vector sortObjects,
 664                                            NodeSortRecordGenerator sortRecord,
 665                                            ConstantPoolGen cpg,
 666                                            String className)
 667     {
 668         final InstructionList il = new InstructionList();
 669         final MethodGenerator init =
 670             new MethodGenerator(ACC_PUBLIC,
 671                                 com.sun.org.apache.bcel.internal.generic.Type.VOID,
 672                                 null, null, "<init>", className,
 673                                 il, cpg);
 674 
 675         // Call the constructor in the NodeSortRecord superclass
 676         il.append(ALOAD_0);
 677         il.append(new INVOKESPECIAL(cpg.addMethodref(NODE_SORT_RECORD,
 678                                                      "<init>", "()V")));
 679 
 680 
 681 
 682         il.append(RETURN);
 683 
 684         return init;
 685     }
 686 
 687 
 688     /**
 689      * Compiles a method that overloads NodeSortRecord.extractValueFromDOM()
 690      */
 691     private static MethodGenerator compileExtract(Vector sortObjects,
 692                                          NodeSortRecordGenerator sortRecord,
 693                                          ConstantPoolGen cpg,
 694                                          String className) {
 695         final InstructionList il = new InstructionList();
 696 
 697         // String NodeSortRecord.extractValueFromDOM(dom,node,level);
 698         final CompareGenerator extractMethod =
 699             new CompareGenerator(ACC_PUBLIC | ACC_FINAL,
 700                                  com.sun.org.apache.bcel.internal.generic.Type.STRING,
 701                                  new com.sun.org.apache.bcel.internal.generic.Type[] {
 702                                      Util.getJCRefType(DOM_INTF_SIG),
 703                                      com.sun.org.apache.bcel.internal.generic.Type.INT,
 704                                      com.sun.org.apache.bcel.internal.generic.Type.INT,
 705                                      Util.getJCRefType(TRANSLET_SIG),
 706                                      com.sun.org.apache.bcel.internal.generic.Type.INT
 707                                  },
 708                                  new String[] { "dom",
 709                                                 "current",
 710                                                 "level",
 711                                                 "translet",


 713                                  },
 714                                  "extractValueFromDOM", className, il, cpg);
 715 
 716         // Values needed for the switch statement
 717         final int levels = sortObjects.size();
 718         final int match[] = new int[levels];
 719         final InstructionHandle target[] = new InstructionHandle[levels];
 720         InstructionHandle tblswitch = null;
 721 
 722         // Compile switch statement only if the key has multiple levels
 723         if (levels > 1) {
 724             // Put the parameter to the swtich statement on the stack
 725             il.append(new ILOAD(extractMethod.getLocalIndex("level")));
 726             // Append the switch statement here later on
 727             tblswitch = il.append(new NOP());
 728         }
 729 
 730         // Append all the cases for the switch statment
 731         for (int level = 0; level < levels; level++) {
 732             match[level] = level;
 733             final Sort sort = (Sort)sortObjects.elementAt(level);
 734             target[level] = il.append(NOP);
 735             sort.translateSelect(sortRecord, extractMethod);
 736             il.append(ARETURN);
 737         }
 738 
 739         // Compile def. target for switch statement if key has multiple levels
 740         if (levels > 1) {
 741             // Append the default target - it will _NEVER_ be reached
 742             InstructionHandle defaultTarget =
 743                 il.append(new PUSH(cpg, EMPTYSTRING));
 744             il.insert(tblswitch,new TABLESWITCH(match, target, defaultTarget));
 745             il.append(ARETURN);
 746         }
 747 
 748         return extractMethod;
 749     }
 750 }
   1 /*
   2  * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.

   3  */
   4 /*
   5  * Copyright 2001-2005 The Apache Software Foundation.
   6  *
   7  * Licensed under the Apache License, Version 2.0 (the "License");
   8  * you may not use this file except in compliance with the License.
   9  * You may obtain a copy of the License at
  10  *
  11  *     http://www.apache.org/licenses/LICENSE-2.0
  12  *
  13  * Unless required by applicable law or agreed to in writing, software
  14  * distributed under the License is distributed on an "AS IS" BASIS,
  15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16  * See the License for the specific language governing permissions and
  17  * limitations under the License.
  18  */



  19 
  20 package com.sun.org.apache.xalan.internal.xsltc.compiler;
  21 

  22 import java.util.ArrayList;


  23 import java.util.Vector;
  24 
  25 import com.sun.org.apache.bcel.internal.classfile.Field;

  26 import com.sun.org.apache.bcel.internal.generic.ALOAD;
  27 import com.sun.org.apache.bcel.internal.generic.ANEWARRAY;
  28 import com.sun.org.apache.bcel.internal.generic.ASTORE;
  29 import com.sun.org.apache.bcel.internal.generic.CHECKCAST;
  30 import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
  31 import com.sun.org.apache.bcel.internal.generic.GETFIELD;

  32 import com.sun.org.apache.bcel.internal.generic.ILOAD;
  33 import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
  34 import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL;


  35 import com.sun.org.apache.bcel.internal.generic.InstructionHandle;
  36 import com.sun.org.apache.bcel.internal.generic.InstructionList;
  37 import com.sun.org.apache.bcel.internal.generic.LocalVariableGen;
  38 import com.sun.org.apache.bcel.internal.generic.NEW;
  39 import com.sun.org.apache.bcel.internal.generic.NOP;
  40 import com.sun.org.apache.bcel.internal.generic.PUSH;
  41 import com.sun.org.apache.bcel.internal.generic.PUTFIELD;
  42 import com.sun.org.apache.bcel.internal.generic.TABLESWITCH;
  43 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
  44 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.CompareGenerator;
  45 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
  46 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.IntType;
  47 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
  48 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeSortRecordFactGenerator;
  49 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeSortRecordGenerator;
  50 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.StringType;
  51 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
  52 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
  53 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;
  54 import com.sun.org.apache.xml.internal.dtm.Axis;
  55 
  56 
  57 /**
  58  * @author Jacek Ambroziak
  59  * @author Santiago Pericas-Geertsen
  60  * @author Morten Jorgensen
  61  */
  62 final class Sort extends Instruction implements Closure {
  63 
  64     private Expression     _select;
  65     private AttributeValue _order;
  66     private AttributeValue _caseOrder;
  67     private AttributeValue _dataType;
  68     private String         _lang; // bug! see 26869



  69 
  70     private String _className = null;
  71     private ArrayList<VariableRefBase> _closureVars = null;
  72     private boolean _needsSortRecordFactory = false;
  73 
  74     // -- Begin Closure interface --------------------
  75 
  76     /**
  77      * Returns true if this closure is compiled in an inner class (i.e.
  78      * if this is a real closure).
  79      */
  80     public boolean inInnerClass() {
  81         return (_className != null);
  82     }
  83 
  84     /**
  85      * Returns a reference to its parent closure or null if outermost.
  86      */
  87     public Closure getParentClosure() {
  88         return null;
  89     }
  90 
  91     /**
  92      * Returns the name of the auxiliary class or null if this predicate
  93      * is compiled inside the Translet.
  94      */
  95     public String getInnerClassName() {
  96         return _className;
  97     }
  98 
  99     /**
 100      * Add new variable to the closure.
 101      */
 102     public void addVariable(VariableRefBase variableRef) {
 103         if (_closureVars == null) {
 104             _closureVars = new ArrayList<>();
 105         }
 106 
 107         // Only one reference per variable
 108         if (!_closureVars.contains(variableRef)) {
 109             _closureVars.add(variableRef);
 110             _needsSortRecordFactory = true;
 111         }
 112     }
 113 
 114     // -- End Closure interface ----------------------
 115 
 116     private void setInnerClassName(String className) {
 117         _className = className;
 118     }
 119 
 120     /**
 121      * Parse the attributes of the xsl:sort element
 122      */
 123     public void parseContents(Parser parser) {
 124 


 215     public void translateSelect(ClassGenerator classGen,
 216                                 MethodGenerator methodGen) {
 217         _select.translate(classGen,methodGen);
 218     }
 219 
 220     /**
 221      * This method should not produce any code
 222      */
 223     public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
 224         // empty
 225     }
 226 
 227     /**
 228      * Compiles code that instantiates a SortingIterator object.
 229      * This object's constructor needs referencdes to the current iterator
 230      * and a node sort record producing objects as its parameters.
 231      */
 232     public static void translateSortIterator(ClassGenerator classGen,
 233                                       MethodGenerator methodGen,
 234                                       Expression nodeSet,
 235                                       Vector<Sort> sortObjects)
 236     {
 237         final ConstantPoolGen cpg = classGen.getConstantPool();
 238         final InstructionList il = methodGen.getInstructionList();
 239 
 240         // SortingIterator.SortingIterator(NodeIterator,NodeSortRecordFactory);
 241         final int init = cpg.addMethodref(SORT_ITERATOR, "<init>",
 242                                           "("
 243                                           + NODE_ITERATOR_SIG
 244                                           + NODE_SORT_FACTORY_SIG
 245                                           + ")V");
 246 
 247         // Backwards branches are prohibited if an uninitialized object is
 248         // on the stack by section 4.9.4 of the JVM Specification, 2nd Ed.
 249         // We don't know whether this code might contain backwards branches
 250         // so we mustn't create the new object until after we've created
 251         // the suspect arguments to its constructor.  Instead we calculate
 252         // the values of the arguments to the constructor first, store them
 253         // in temporary variables, create the object and reload the
 254         // arguments from the temporaries to avoid the problem.
 255 


 281 
 282         // Compile the code for the NodeSortRecord producing class and pass
 283         // that as the last argument to the SortingIterator constructor.
 284         compileSortRecordFactory(sortObjects, classGen, methodGen);
 285         sortRecordFactoryTemp.setStart(
 286                 il.append(new ASTORE(sortRecordFactoryTemp.getIndex())));
 287 
 288         il.append(new NEW(cpg.addClass(SORT_ITERATOR)));
 289         il.append(DUP);
 290         nodesTemp.setEnd(il.append(new ALOAD(nodesTemp.getIndex())));
 291         sortRecordFactoryTemp.setEnd(
 292                 il.append(new ALOAD(sortRecordFactoryTemp.getIndex())));
 293         il.append(new INVOKESPECIAL(init));
 294     }
 295 
 296 
 297     /**
 298      * Compiles code that instantiates a NodeSortRecordFactory object which
 299      * will produce NodeSortRecord objects of a specific type.
 300      */
 301     public static void compileSortRecordFactory(Vector<Sort> sortObjects,
 302         ClassGenerator classGen, MethodGenerator methodGen)
 303     {
 304         String sortRecordClass =
 305             compileSortRecord(sortObjects, classGen, methodGen);
 306 
 307         boolean needsSortRecordFactory = false;
 308         final int nsorts = sortObjects.size();
 309         for (int i = 0; i < nsorts; i++) {
 310             final Sort sort = sortObjects.elementAt(i);
 311             needsSortRecordFactory |= sort._needsSortRecordFactory;
 312         }
 313 
 314         String sortRecordFactoryClass = NODE_SORT_FACTORY;
 315         if (needsSortRecordFactory) {
 316             sortRecordFactoryClass =
 317                 compileSortRecordFactory(sortObjects, classGen, methodGen,
 318                     sortRecordClass);
 319         }
 320 
 321         final ConstantPoolGen cpg = classGen.getConstantPool();
 322         final InstructionList il = methodGen.getInstructionList();
 323 
 324         // Backwards branches are prohibited if an uninitialized object is
 325         // on the stack by section 4.9.4 of the JVM Specification, 2nd Ed.
 326         // We don't know whether this code might contain backwards branches
 327         // so we mustn't create the new object until after we've created
 328         // the suspect arguments to its constructor.  Instead we calculate
 329         // the values of the arguments to the constructor first, store them
 330         // in temporary variables, create the object and reload the


 398         il.append(new PUSH(cpg, sortRecordClass));
 399         il.append(classGen.loadTranslet());
 400 
 401         sortOrderTemp.setEnd(il.append(new ALOAD(sortOrderTemp.getIndex())));
 402         sortTypeTemp.setEnd(il.append(new ALOAD(sortTypeTemp.getIndex())));
 403         sortLangTemp.setEnd(il.append(new ALOAD(sortLangTemp.getIndex())));
 404         sortCaseOrderTemp.setEnd(
 405                 il.append(new ALOAD(sortCaseOrderTemp.getIndex())));
 406 
 407         il.append(new INVOKESPECIAL(
 408             cpg.addMethodref(sortRecordFactoryClass, "<init>",
 409                 "(" + DOM_INTF_SIG
 410                     + STRING_SIG
 411                     + TRANSLET_INTF_SIG
 412                     + "[" + STRING_SIG
 413                     + "[" + STRING_SIG
 414                     + "[" + STRING_SIG
 415                     + "[" + STRING_SIG + ")V")));
 416 
 417         // Initialize closure variables in sortRecordFactory
 418         final ArrayList<VariableRefBase> dups = new ArrayList<>();
 419 
 420         for (int j = 0; j < nsorts; j++) {
 421             final Sort sort = (Sort) sortObjects.get(j);
 422             final int length = (sort._closureVars == null) ? 0 :
 423                 sort._closureVars.size();
 424 
 425             for (int i = 0; i < length; i++) {
 426                 VariableRefBase varRef = sort._closureVars.get(i);
 427 
 428                 // Discard duplicate variable references
 429                 if (dups.contains(varRef)) continue;
 430 
 431                 final VariableBase var = varRef.getVariable();
 432 
 433                 // Store variable in new closure
 434                 il.append(DUP);
 435                 il.append(var.loadInstruction());
 436                 il.append(new PUTFIELD(
 437                         cpg.addFieldref(sortRecordFactoryClass, var.getEscapedName(),
 438                             var.getType().toSignature())));
 439                 dups.add(varRef);
 440             }
 441         }
 442     }
 443 
 444     public static String compileSortRecordFactory(Vector<Sort> sortObjects,
 445         ClassGenerator classGen, MethodGenerator methodGen,
 446         String sortRecordClass)
 447     {
 448         final XSLTC xsltc = (sortObjects.firstElement()).getXSLTC();
 449         final String className = xsltc.getHelperClassName();
 450 
 451         final NodeSortRecordFactGenerator sortRecordFactory =
 452             new NodeSortRecordFactGenerator(className,
 453                                         NODE_SORT_FACTORY,
 454                                         className + ".java",
 455                                         ACC_PUBLIC | ACC_SUPER | ACC_FINAL,
 456                                         new String[] {},
 457                                         classGen.getStylesheet());
 458 
 459         ConstantPoolGen cpg = sortRecordFactory.getConstantPool();
 460 
 461         // Add a new instance variable for each var in closure
 462         final int nsorts = sortObjects.size();
 463         final ArrayList<VariableRefBase> dups = new ArrayList<>();
 464 
 465         for (int j = 0; j < nsorts; j++) {
 466             final Sort sort = sortObjects.get(j);
 467             final int length = (sort._closureVars == null) ? 0 :
 468                 sort._closureVars.size();
 469 
 470             for (int i = 0; i < length; i++) {
 471                 final VariableRefBase varRef = sort._closureVars.get(i);
 472 
 473                 // Discard duplicate variable references
 474                 if (dups.contains(varRef)) continue;
 475 
 476                 final VariableBase var = varRef.getVariable();
 477                 sortRecordFactory.addField(new Field(ACC_PUBLIC,
 478                                            cpg.addUtf8(var.getEscapedName()),
 479                                            cpg.addUtf8(var.getType().toSignature()),
 480                                            null, cpg.getConstantPool()));
 481                 dups.add(varRef);
 482             }
 483         }
 484 
 485         // Define a constructor for this class
 486         final com.sun.org.apache.bcel.internal.generic.Type[] argTypes =
 487             new com.sun.org.apache.bcel.internal.generic.Type[7];
 488         argTypes[0] = Util.getJCRefType(DOM_INTF_SIG);
 489         argTypes[1] = Util.getJCRefType(STRING_SIG);
 490         argTypes[2] = Util.getJCRefType(TRANSLET_INTF_SIG);
 491         argTypes[3] = Util.getJCRefType("[" + STRING_SIG);


 569                 cpg.addFieldref(sortRecordClass,
 570                     var.getEscapedName(), varType.toSignature())));
 571         }
 572         il.append(POP);
 573         il.append(ARETURN);
 574 
 575         constructor.setMaxLocals();
 576         constructor.setMaxStack();
 577         sortRecordFactory.addMethod(constructor);
 578         makeNodeSortRecord.setMaxLocals();
 579         makeNodeSortRecord.setMaxStack();
 580         sortRecordFactory.addMethod(makeNodeSortRecord);
 581         xsltc.dumpClass(sortRecordFactory.getJavaClass());
 582 
 583         return className;
 584     }
 585 
 586     /**
 587      * Create a new auxillary class extending NodeSortRecord.
 588      */
 589     private static String compileSortRecord(Vector<Sort> sortObjects,
 590                                             ClassGenerator classGen,
 591                                             MethodGenerator methodGen) {
 592         final XSLTC  xsltc = sortObjects.firstElement().getXSLTC();
 593         final String className = xsltc.getHelperClassName();
 594 
 595         // This generates a new class for handling this specific sort
 596         final NodeSortRecordGenerator sortRecord =
 597             new NodeSortRecordGenerator(className,
 598                                         NODE_SORT_RECORD,
 599                                         "sort$0.java",
 600                                         ACC_PUBLIC | ACC_SUPER | ACC_FINAL,
 601                                         new String[] {},
 602                                         classGen.getStylesheet());
 603 
 604         final ConstantPoolGen cpg = sortRecord.getConstantPool();
 605 
 606         // Add a new instance variable for each var in closure
 607         final int nsorts = sortObjects.size();
 608         final ArrayList<VariableRefBase> dups = new ArrayList<>();
 609 
 610         for (int j = 0; j < nsorts; j++) {
 611             final Sort sort = sortObjects.get(j);
 612 
 613             // Set the name of the inner class in this sort object
 614             sort.setInnerClassName(className);
 615 
 616             final int length = (sort._closureVars == null) ? 0 :
 617                 sort._closureVars.size();
 618             for (int i = 0; i < length; i++) {
 619                 final VariableRefBase varRef = (VariableRefBase) sort._closureVars.get(i);
 620 
 621                 // Discard duplicate variable references
 622                 if (dups.contains(varRef)) continue;
 623 
 624                 final VariableBase var = varRef.getVariable();
 625                 sortRecord.addField(new Field(ACC_PUBLIC,
 626                                     cpg.addUtf8(var.getEscapedName()),
 627                                     cpg.addUtf8(var.getType().toSignature()),
 628                                     null, cpg.getConstantPool()));
 629                 dups.add(varRef);
 630             }
 631         }
 632 
 633         MethodGenerator init = compileInit(sortRecord, cpg, className);

 634         MethodGenerator extract = compileExtract(sortObjects, sortRecord,
 635                                         cpg, className);
 636         sortRecord.addMethod(init);
 637         sortRecord.addMethod(extract);
 638 
 639         xsltc.dumpClass(sortRecord.getJavaClass());
 640         return className;
 641     }
 642 
 643     /**
 644      * Create a constructor for the new class. Updates the reference to the
 645      * collator in the super calls only when the stylesheet specifies a new
 646      * language in xsl:sort.
 647      */
 648     private static MethodGenerator compileInit(NodeSortRecordGenerator sortRecord,

 649                                            ConstantPoolGen cpg,
 650                                            String className)
 651     {
 652         final InstructionList il = new InstructionList();
 653         final MethodGenerator init =
 654             new MethodGenerator(ACC_PUBLIC,
 655                                 com.sun.org.apache.bcel.internal.generic.Type.VOID,
 656                                 null, null, "<init>", className,
 657                                 il, cpg);
 658 
 659         // Call the constructor in the NodeSortRecord superclass
 660         il.append(ALOAD_0);
 661         il.append(new INVOKESPECIAL(cpg.addMethodref(NODE_SORT_RECORD,
 662                                                      "<init>", "()V")));
 663 
 664 
 665 
 666         il.append(RETURN);
 667 
 668         return init;
 669     }
 670 
 671 
 672     /**
 673      * Compiles a method that overloads NodeSortRecord.extractValueFromDOM()
 674      */
 675     private static MethodGenerator compileExtract(Vector<Sort> sortObjects,
 676                                          NodeSortRecordGenerator sortRecord,
 677                                          ConstantPoolGen cpg,
 678                                          String className) {
 679         final InstructionList il = new InstructionList();
 680 
 681         // String NodeSortRecord.extractValueFromDOM(dom,node,level);
 682         final CompareGenerator extractMethod =
 683             new CompareGenerator(ACC_PUBLIC | ACC_FINAL,
 684                                  com.sun.org.apache.bcel.internal.generic.Type.STRING,
 685                                  new com.sun.org.apache.bcel.internal.generic.Type[] {
 686                                      Util.getJCRefType(DOM_INTF_SIG),
 687                                      com.sun.org.apache.bcel.internal.generic.Type.INT,
 688                                      com.sun.org.apache.bcel.internal.generic.Type.INT,
 689                                      Util.getJCRefType(TRANSLET_SIG),
 690                                      com.sun.org.apache.bcel.internal.generic.Type.INT
 691                                  },
 692                                  new String[] { "dom",
 693                                                 "current",
 694                                                 "level",
 695                                                 "translet",


 697                                  },
 698                                  "extractValueFromDOM", className, il, cpg);
 699 
 700         // Values needed for the switch statement
 701         final int levels = sortObjects.size();
 702         final int match[] = new int[levels];
 703         final InstructionHandle target[] = new InstructionHandle[levels];
 704         InstructionHandle tblswitch = null;
 705 
 706         // Compile switch statement only if the key has multiple levels
 707         if (levels > 1) {
 708             // Put the parameter to the swtich statement on the stack
 709             il.append(new ILOAD(extractMethod.getLocalIndex("level")));
 710             // Append the switch statement here later on
 711             tblswitch = il.append(new NOP());
 712         }
 713 
 714         // Append all the cases for the switch statment
 715         for (int level = 0; level < levels; level++) {
 716             match[level] = level;
 717             final Sort sort = sortObjects.elementAt(level);
 718             target[level] = il.append(NOP);
 719             sort.translateSelect(sortRecord, extractMethod);
 720             il.append(ARETURN);
 721         }
 722 
 723         // Compile def. target for switch statement if key has multiple levels
 724         if (levels > 1) {
 725             // Append the default target - it will _NEVER_ be reached
 726             InstructionHandle defaultTarget =
 727                 il.append(new PUSH(cpg, EMPTYSTRING));
 728             il.insert(tblswitch,new TABLESWITCH(match, target, defaultTarget));
 729             il.append(ARETURN);
 730         }
 731 
 732         return extractMethod;
 733     }
 734 }
< prev index next >