001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 /* 019 * $Id: ParentLocationPath.java 468650 2006-10-28 07:03:30Z minchau $ 020 */ 021 022 package org.apache.xalan.xsltc.compiler; 023 024 import org.apache.bcel.generic.ALOAD; 025 import org.apache.bcel.generic.ASTORE; 026 import org.apache.bcel.generic.ConstantPoolGen; 027 import org.apache.bcel.generic.INVOKEINTERFACE; 028 import org.apache.bcel.generic.INVOKESPECIAL; 029 import org.apache.bcel.generic.INVOKEVIRTUAL; 030 import org.apache.bcel.generic.InstructionList; 031 import org.apache.bcel.generic.LocalVariableGen; 032 import org.apache.bcel.generic.NEW; 033 import org.apache.xalan.xsltc.compiler.util.ClassGenerator; 034 import org.apache.xalan.xsltc.compiler.util.MethodGenerator; 035 import org.apache.xalan.xsltc.compiler.util.Type; 036 import org.apache.xalan.xsltc.compiler.util.TypeCheckError; 037 import org.apache.xalan.xsltc.compiler.util.Util; 038 import org.apache.xml.dtm.Axis; 039 import org.apache.xml.dtm.DTM; 040 041 /** 042 * @author Jacek Ambroziak 043 * @author Santiago Pericas-Geertsen 044 */ 045 final class ParentLocationPath extends RelativeLocationPath { 046 private Expression _step; 047 private final RelativeLocationPath _path; 048 private Type stype; 049 private boolean _orderNodes = false; 050 private boolean _axisMismatch = false; 051 052 public ParentLocationPath(RelativeLocationPath path, Expression step) { 053 _path = path; 054 _step = step; 055 _path.setParent(this); 056 _step.setParent(this); 057 058 if (_step instanceof Step) { 059 _axisMismatch = checkAxisMismatch(); 060 } 061 } 062 063 public void setAxis(int axis) { 064 _path.setAxis(axis); 065 } 066 067 public int getAxis() { 068 return _path.getAxis(); 069 } 070 071 public RelativeLocationPath getPath() { 072 return(_path); 073 } 074 075 public Expression getStep() { 076 return(_step); 077 } 078 079 public void setParser(Parser parser) { 080 super.setParser(parser); 081 _step.setParser(parser); 082 _path.setParser(parser); 083 } 084 085 public String toString() { 086 return "ParentLocationPath(" + _path + ", " + _step + ')'; 087 } 088 089 public Type typeCheck(SymbolTable stable) throws TypeCheckError { 090 stype = _step.typeCheck(stable); 091 _path.typeCheck(stable); 092 093 if (_axisMismatch) enableNodeOrdering(); 094 095 return _type = Type.NodeSet; 096 } 097 098 public void enableNodeOrdering() { 099 SyntaxTreeNode parent = getParent(); 100 if (parent instanceof ParentLocationPath) 101 ((ParentLocationPath)parent).enableNodeOrdering(); 102 else { 103 _orderNodes = true; 104 } 105 } 106 107 /** 108 * This method is used to determine if this parent location path is a 109 * combination of two step's with axes that will create duplicate or 110 * unordered nodes. 111 */ 112 public boolean checkAxisMismatch() { 113 114 int left = _path.getAxis(); 115 int right = ((Step)_step).getAxis(); 116 117 if (((left == Axis.ANCESTOR) || (left == Axis.ANCESTORORSELF)) && 118 ((right == Axis.CHILD) || 119 (right == Axis.DESCENDANT) || 120 (right == Axis.DESCENDANTORSELF) || 121 (right == Axis.PARENT) || 122 (right == Axis.PRECEDING) || 123 (right == Axis.PRECEDINGSIBLING))) 124 return true; 125 126 if ((left == Axis.CHILD) && 127 (right == Axis.ANCESTOR) || 128 (right == Axis.ANCESTORORSELF) || 129 (right == Axis.PARENT) || 130 (right == Axis.PRECEDING)) 131 return true; 132 133 if ((left == Axis.DESCENDANT) || (left == Axis.DESCENDANTORSELF)) 134 return true; 135 136 if (((left == Axis.FOLLOWING) || (left == Axis.FOLLOWINGSIBLING)) && 137 ((right == Axis.FOLLOWING) || 138 (right == Axis.PARENT) || 139 (right == Axis.PRECEDING) || 140 (right == Axis.PRECEDINGSIBLING))) 141 return true; 142 143 if (((left == Axis.PRECEDING) || (left == Axis.PRECEDINGSIBLING)) && 144 ((right == Axis.DESCENDANT) || 145 (right == Axis.DESCENDANTORSELF) || 146 (right == Axis.FOLLOWING) || 147 (right == Axis.FOLLOWINGSIBLING) || 148 (right == Axis.PARENT) || 149 (right == Axis.PRECEDING) || 150 (right == Axis.PRECEDINGSIBLING))) 151 return true; 152 153 if ((right == Axis.FOLLOWING) && (left == Axis.CHILD)) { 154 // Special case for '@*/following::*' expressions. The resulting 155 // iterator is initialised with the parent's first child, and this 156 // can cause duplicates in the output if the parent has more than 157 // one attribute that matches the left step. 158 if (_path instanceof Step) { 159 int type = ((Step)_path).getNodeType(); 160 if (type == DTM.ATTRIBUTE_NODE) return true; 161 } 162 } 163 164 return false; 165 } 166 167 public void translate(ClassGenerator classGen, MethodGenerator methodGen) { 168 final ConstantPoolGen cpg = classGen.getConstantPool(); 169 final InstructionList il = methodGen.getInstructionList(); 170 171 // Backwards branches are prohibited if an uninitialized object is 172 // on the stack by section 4.9.4 of the JVM Specification, 2nd Ed. 173 // We don't know whether this code might contain backwards branches 174 // so we mustn't create the new object until after we've created 175 // the suspect arguments to its constructor. Instead we calculate 176 // the values of the arguments to the constructor first, store them 177 // in temporary variables, create the object and reload the 178 // arguments from the temporaries to avoid the problem. 179 180 // Compile path iterator 181 _path.translate(classGen, methodGen); // iterator on stack.... 182 LocalVariableGen pathTemp 183 = methodGen.addLocalVariable("parent_location_path_tmp1", 184 Util.getJCRefType(NODE_ITERATOR_SIG), 185 null, null); 186 pathTemp.setStart(il.append(new ASTORE(pathTemp.getIndex()))); 187 188 _step.translate(classGen, methodGen); 189 LocalVariableGen stepTemp 190 = methodGen.addLocalVariable("parent_location_path_tmp2", 191 Util.getJCRefType(NODE_ITERATOR_SIG), 192 null, null); 193 stepTemp.setStart(il.append(new ASTORE(stepTemp.getIndex()))); 194 195 // Create new StepIterator 196 final int initSI = cpg.addMethodref(STEP_ITERATOR_CLASS, 197 "<init>", 198 "(" 199 +NODE_ITERATOR_SIG 200 +NODE_ITERATOR_SIG 201 +")V"); 202 il.append(new NEW(cpg.addClass(STEP_ITERATOR_CLASS))); 203 il.append(DUP); 204 205 pathTemp.setEnd(il.append(new ALOAD(pathTemp.getIndex()))); 206 stepTemp.setEnd(il.append(new ALOAD(stepTemp.getIndex()))); 207 208 // Initialize StepIterator with iterators from the stack 209 il.append(new INVOKESPECIAL(initSI)); 210 211 // This is a special case for the //* path with or without predicates 212 Expression stp = _step; 213 if (stp instanceof ParentLocationPath) 214 stp = ((ParentLocationPath)stp).getStep(); 215 216 if ((_path instanceof Step) && (stp instanceof Step)) { 217 final int path = ((Step)_path).getAxis(); 218 final int step = ((Step)stp).getAxis(); 219 if ((path == Axis.DESCENDANTORSELF && step == Axis.CHILD) || 220 (path == Axis.PRECEDING && step == Axis.PARENT)) { 221 final int incl = cpg.addMethodref(NODE_ITERATOR_BASE, 222 "includeSelf", 223 "()" + NODE_ITERATOR_SIG); 224 il.append(new INVOKEVIRTUAL(incl)); 225 } 226 } 227 228 /* 229 * If this pattern contains a sequence of descendant iterators we 230 * run the risk of returning the same node several times. We put 231 * a new iterator on top of the existing one to assure node order 232 * and prevent returning a single node multiple times. 233 */ 234 if (_orderNodes) { 235 final int order = cpg.addInterfaceMethodref(DOM_INTF, 236 ORDER_ITERATOR, 237 ORDER_ITERATOR_SIG); 238 il.append(methodGen.loadDOM()); 239 il.append(SWAP); 240 il.append(methodGen.loadContextNode()); 241 il.append(new INVOKEINTERFACE(order, 3)); 242 } 243 } 244 }