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 }
|