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