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: FilterExpr.java,v 1.2.4.1 2005/09/12 10:22:50 pvedula Exp $ 22 */ 23 24 package com.sun.org.apache.xalan.internal.xsltc.compiler; 25 26 import java.util.Vector; 27 28 import com.sun.org.apache.bcel.internal.generic.ALOAD; 29 import com.sun.org.apache.bcel.internal.generic.ASTORE; 30 import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen; 31 import com.sun.org.apache.bcel.internal.generic.ILOAD; 32 import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE; 33 import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL; 34 import com.sun.org.apache.bcel.internal.generic.INVOKESTATIC; 35 import com.sun.org.apache.bcel.internal.generic.InstructionList; 36 import com.sun.org.apache.bcel.internal.generic.ISTORE; 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.xalan.internal.xsltc.compiler.util.ClassGenerator; 40 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator; 41 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeSetType; 42 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ReferenceType; 43 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type; 44 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError; 45 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util; 46 47 /** 48 * @author Jacek Ambroziak 49 * @author Santiago Pericas-Geertsen 50 * @author Morten Jorgensen 51 */ 52 class FilterExpr extends Expression { 53 54 /** 55 * Primary expression of this filter. I.e., 'e' in '(e)[p1]...[pn]'. 56 */ 57 private Expression _primary; 58 59 /** 60 * Array of predicates in '(e)[p1]...[pn]'. 61 */ 62 private final Vector _predicates; 63 64 public FilterExpr(Expression primary, Vector predicates) { 65 _primary = primary; 66 _predicates = predicates; 67 primary.setParent(this); 68 } 69 70 protected Expression getExpr() { 71 if (_primary instanceof CastExpr) 72 return ((CastExpr)_primary).getExpr(); 73 else 74 return _primary; 75 } 76 77 public void setParser(Parser parser) { 78 super.setParser(parser); 79 _primary.setParser(parser); 80 if (_predicates != null) { 81 final int n = _predicates.size(); 82 for (int i = 0; i < n; i++) { 83 final Expression exp = (Expression)_predicates.elementAt(i); 84 exp.setParser(parser); 85 exp.setParent(this); 86 } 87 } 88 } 89 90 public String toString() { 91 return "filter-expr(" + _primary + ", " + _predicates + ")"; 92 } 93 94 /** 95 * Type check a FilterParentPath. If the filter is not a node-set add a 96 * cast to node-set only if it is of reference type. This type coercion 97 * is needed for expressions like $x where $x is a parameter reference. 98 * All optimizations are turned off before type checking underlying 99 * predicates. 100 */ 101 public Type typeCheck(SymbolTable stable) throws TypeCheckError { 102 Type ptype = _primary.typeCheck(stable); 103 boolean canOptimize = _primary instanceof KeyCall; 104 105 if (ptype instanceof NodeSetType == false) { 106 if (ptype instanceof ReferenceType) { 107 _primary = new CastExpr(_primary, Type.NodeSet); 108 } 109 else { 110 throw new TypeCheckError(this); 111 } 112 } 113 114 // Type check predicates and turn all optimizations off if appropriate 115 int n = _predicates.size(); 116 for (int i = 0; i < n; i++) { 117 Predicate pred = (Predicate) _predicates.elementAt(i); 118 119 if (!canOptimize) { 120 pred.dontOptimize(); 121 } 122 pred.typeCheck(stable); 123 } 124 return _type = Type.NodeSet; 125 } 126 127 /** 128 * Translate a filter expression by pushing the appropriate iterator 129 * onto the stack. 130 */ 131 public void translate(ClassGenerator classGen, MethodGenerator methodGen) { 132 translateFilterExpr(classGen, methodGen, _predicates == null ? -1 : _predicates.size() - 1); 133 } 134 135 private void translateFilterExpr(ClassGenerator classGen, 136 MethodGenerator methodGen, 137 int predicateIndex) { 138 if (predicateIndex >= 0) { 139 translatePredicates(classGen, methodGen, predicateIndex); 140 } 141 else { 142 _primary.translate(classGen, methodGen); 143 } 144 } 145 146 /** 147 * Translate a sequence of predicates. Each predicate is translated 148 * by constructing an instance of <code>CurrentNodeListIterator</code> 149 * which is initialized from another iterator (recursive call), a 150 * filter and a closure (call to translate on the predicate) and "this". 151 */ 152 public void translatePredicates(ClassGenerator classGen, 153 MethodGenerator methodGen, 154 int predicateIndex) { 155 final ConstantPoolGen cpg = classGen.getConstantPool(); 156 final InstructionList il = methodGen.getInstructionList(); 157 158 // If not predicates left, translate primary expression 159 if (predicateIndex < 0) { 160 translateFilterExpr(classGen, methodGen, predicateIndex); 161 } 162 else { 163 // Get the next predicate to be translated 164 Predicate predicate = (Predicate) _predicates.get(predicateIndex--); 165 166 // Translate the rest of the predicates from right to left 167 translatePredicates(classGen, methodGen, predicateIndex); 168 169 if (predicate.isNthPositionFilter()) { 170 int nthIteratorIdx = cpg.addMethodref(NTH_ITERATOR_CLASS, 171 "<init>", 172 "("+NODE_ITERATOR_SIG+"I)V"); 173 174 // Backwards branches are prohibited if an uninitialized object 175 // is on the stack by section 4.9.4 of the JVM Specification, 176 // 2nd Ed. We don't know whether this code might contain 177 // backwards branches, so we mustn't create the new object unti 178 179 // after we've created the suspect arguments to its constructor 180 181 // Instead we calculate the values of the arguments to the 182 // constructor first, store them in temporary variables, create 183 // the object and reload the arguments from the temporaries to 184 // avoid the problem. 185 LocalVariableGen iteratorTemp 186 = methodGen.addLocalVariable("filter_expr_tmp1", 187 Util.getJCRefType(NODE_ITERATOR_SIG), 188 null, null); 189 iteratorTemp.setStart( 190 il.append(new ASTORE(iteratorTemp.getIndex()))); 191 192 predicate.translate(classGen, methodGen); 193 LocalVariableGen predicateValueTemp 194 = methodGen.addLocalVariable("filter_expr_tmp2", 195 Util.getJCRefType("I"), 196 null, null); 197 predicateValueTemp.setStart( 198 il.append(new ISTORE(predicateValueTemp.getIndex()))); 199 200 il.append(new NEW(cpg.addClass(NTH_ITERATOR_CLASS))); 201 il.append(DUP); 202 iteratorTemp.setEnd( 203 il.append(new ALOAD(iteratorTemp.getIndex()))); 204 predicateValueTemp.setEnd( 205 il.append(new ILOAD(predicateValueTemp.getIndex()))); 206 il.append(new INVOKESPECIAL(nthIteratorIdx)); 207 } else { 208 // Translate predicates from right to left 209 final int initCNLI = cpg.addMethodref(CURRENT_NODE_LIST_ITERATOR, 210 "<init>", 211 "("+NODE_ITERATOR_SIG+"Z"+ 212 CURRENT_NODE_LIST_FILTER_SIG + 213 NODE_SIG+TRANSLET_SIG+")V"); 214 215 // Backwards branches are prohibited if an uninitialized object is 216 // on the stack by section 4.9.4 of the JVM Specification, 2nd Ed. 217 // We don't know whether this code might contain backwards branches, 218 // so we mustn't create the new object until after we've created 219 // the suspect arguments to its constructor. Instead we calculate 220 // the values of the arguments to the constructor first, store them 221 // in temporary variables, create the object and reload the 222 // arguments from the temporaries to avoid the problem. 223 224 225 LocalVariableGen nodeIteratorTemp = 226 methodGen.addLocalVariable("filter_expr_tmp1", 227 Util.getJCRefType(NODE_ITERATOR_SIG), 228 null, null); 229 nodeIteratorTemp.setStart( 230 il.append(new ASTORE(nodeIteratorTemp.getIndex()))); 231 232 predicate.translate(classGen, methodGen); 233 LocalVariableGen filterTemp = 234 methodGen.addLocalVariable("filter_expr_tmp2", 235 Util.getJCRefType(CURRENT_NODE_LIST_FILTER_SIG), 236 null, null); 237 filterTemp.setStart(il.append(new ASTORE(filterTemp.getIndex()))); 238 239 // Create a CurrentNodeListIterator 240 il.append(new NEW(cpg.addClass(CURRENT_NODE_LIST_ITERATOR))); 241 il.append(DUP); 242 243 // Initialize CurrentNodeListIterator 244 nodeIteratorTemp.setEnd( 245 il.append(new ALOAD(nodeIteratorTemp.getIndex()))); 246 il.append(ICONST_1); 247 filterTemp.setEnd(il.append(new ALOAD(filterTemp.getIndex()))); 248 il.append(methodGen.loadCurrentNode()); 249 il.append(classGen.loadTranslet()); 250 il.append(new INVOKESPECIAL(initCNLI)); 251 } 252 } 253 } 254 }