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