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 22 package com.sun.org.apache.xalan.internal.xsltc.compiler; 23 24 import com.sun.org.apache.bcel.internal.classfile.Field; 25 import com.sun.org.apache.bcel.internal.generic.BranchHandle; 26 import com.sun.org.apache.bcel.internal.generic.CHECKCAST; 27 import com.sun.org.apache.bcel.internal.generic.IFNONNULL; 28 import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen; 29 import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL; 30 import com.sun.org.apache.bcel.internal.generic.Instruction; 31 import com.sun.org.apache.bcel.internal.generic.InstructionList; 32 import com.sun.org.apache.bcel.internal.generic.PUSH; 33 import com.sun.org.apache.bcel.internal.generic.PUTFIELD; 34 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator; 35 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg; 36 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator; 37 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ReferenceType; 38 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type; 39 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ObjectType; 40 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError; 41 import com.sun.org.apache.xalan.internal.xsltc.runtime.BasisLibrary; 42 43 /** 44 * @author Jacek Ambroziak 45 * @author Santiago Pericas-Geertsen 46 * @author Morten Jorgensen 47 * @author Erwin Bolwidt <ejb@klomp.org> 48 * @author John Howard <JohnH@schemasoft.com> 49 */ 50 final class Param extends VariableBase { 51 52 /** 53 * True if this Param is declared in a simple named template. 54 * This is used to optimize codegen for parameter passing 55 * in named templates. 56 */ 57 private boolean _isInSimpleNamedTemplate = false; 58 59 /** 60 * Display variable as single string 61 */ toString()62 public String toString() { 63 return "param(" + _name + ")"; 64 } 65 66 /** 67 * Set the instruction for loading the value of this variable onto the 68 * JVM stack and returns the old instruction. 69 */ setLoadInstruction(Instruction instruction)70 public Instruction setLoadInstruction(Instruction instruction) { 71 Instruction tmp = _loadInstruction; 72 _loadInstruction = instruction; 73 return tmp; 74 } 75 76 /** 77 * Set the instruction for storing a value from the stack into this 78 * variable and returns the old instruction. 79 */ setStoreInstruction(Instruction instruction)80 public Instruction setStoreInstruction(Instruction instruction) { 81 Instruction tmp = _storeInstruction; 82 _storeInstruction = instruction; 83 return tmp; 84 } 85 86 /** 87 * Display variable in a full AST dump 88 */ display(int indent)89 public void display(int indent) { 90 indent(indent); 91 System.out.println("param " + _name); 92 if (_select != null) { 93 indent(indent + IndentIncrement); 94 System.out.println("select " + _select.toString()); 95 } 96 displayContents(indent + IndentIncrement); 97 } 98 99 /** 100 * Parse the contents of the <xsl:param> element. This method must read 101 * the 'name' (required) and 'select' (optional) attributes. 102 */ parseContents(Parser parser)103 public void parseContents(Parser parser) { 104 105 // Parse 'name' and 'select' attributes plus parameter contents 106 super.parseContents(parser); 107 108 // Add a ref to this param to its enclosing construct 109 final SyntaxTreeNode parent = getParent(); 110 if (parent instanceof Stylesheet) { 111 // Mark this as a global parameter 112 _isLocal = false; 113 // Check if a global variable with this name already exists... 114 Param param = parser.getSymbolTable().lookupParam(_name); 115 // ...and if it does we need to check import precedence 116 if (param != null) { 117 final int us = this.getImportPrecedence(); 118 final int them = param.getImportPrecedence(); 119 // It is an error if the two have the same import precedence 120 if (us == them) { 121 final String name = _name.toString(); 122 reportError(this, parser, ErrorMsg.VARIABLE_REDEF_ERR,name); 123 } 124 // Ignore this if previous definition has higher precedence 125 else if (them > us) { 126 _ignore = true; 127 copyReferences(param); 128 return; 129 } 130 else { 131 param.copyReferences(this); 132 param.disable(); 133 } 134 } 135 // Add this variable if we have higher precedence 136 ((Stylesheet)parent).addParam(this); 137 parser.getSymbolTable().addParam(this); 138 } 139 else if (parent instanceof Template) { 140 Template template = (Template) parent; 141 _isLocal = true; 142 template.addParameter(this); 143 if (template.isSimpleNamedTemplate()) { 144 _isInSimpleNamedTemplate = true; 145 } 146 } 147 } 148 149 /** 150 * Type-checks the parameter. The parameter type is determined by the 151 * 'select' expression (if present) or is a result tree if the parameter 152 * element has a body and no 'select' expression. 153 */ typeCheck(SymbolTable stable)154 public Type typeCheck(SymbolTable stable) throws TypeCheckError { 155 if (_select != null) { 156 _type = _select.typeCheck(stable); 157 if (_type instanceof ReferenceType == false && !(_type instanceof ObjectType)) { 158 _select = new CastExpr(_select, Type.Reference); 159 } 160 } 161 else if (hasContents()) { 162 typeCheckContents(stable); 163 } 164 _type = Type.Reference; 165 166 // This element has no type (the parameter does, but the parameter 167 // element itself does not). 168 return Type.Void; 169 } 170 translate(ClassGenerator classGen, MethodGenerator methodGen)171 public void translate(ClassGenerator classGen, MethodGenerator methodGen) { 172 final ConstantPoolGen cpg = classGen.getConstantPool(); 173 final InstructionList il = methodGen.getInstructionList(); 174 175 if (_ignore) return; 176 _ignore = true; 177 178 /* 179 * To fix bug 24518 related to setting parameters of the form 180 * {namespaceuri}localName which will get mapped to an instance 181 * variable in the class. 182 */ 183 final String name = BasisLibrary.mapQNameToJavaName(_name.toString()); 184 final String signature = _type.toSignature(); 185 final String className = _type.getClassName(); 186 187 if (isLocal()) { 188 /* 189 * If simple named template then generate a conditional init of the 190 * param using its default value: 191 * if (param == null) param = <default-value> 192 */ 193 if (_isInSimpleNamedTemplate) { 194 il.append(loadInstruction()); 195 BranchHandle ifBlock = il.append(new IFNONNULL(null)); 196 translateValue(classGen, methodGen); 197 il.append(storeInstruction()); 198 ifBlock.setTarget(il.append(NOP)); 199 return; 200 } 201 202 il.append(classGen.loadTranslet()); 203 il.append(new PUSH(cpg, name)); 204 translateValue(classGen, methodGen); 205 il.append(new PUSH(cpg, true)); 206 207 // Call addParameter() from this class 208 il.append(new INVOKEVIRTUAL(cpg.addMethodref(TRANSLET_CLASS, 209 ADD_PARAMETER, 210 ADD_PARAMETER_SIG))); 211 if (className != EMPTYSTRING) { 212 il.append(new CHECKCAST(cpg.addClass(className))); 213 } 214 215 _type.translateUnBox(classGen, methodGen); 216 217 if (_refs.isEmpty()) { // nobody uses the value 218 il.append(_type.POP()); 219 _local = null; 220 } 221 else { // normal case 222 _local = methodGen.addLocalVariable2(name, 223 _type.toJCType(), 224 il.getEnd()); 225 // Cache the result of addParameter() in a local variable 226 il.append(_type.STORE(_local.getIndex())); 227 } 228 } 229 else { 230 if (classGen.containsField(name) == null) { 231 classGen.addField(new Field(ACC_PUBLIC, cpg.addUtf8(name), 232 cpg.addUtf8(signature), 233 null, cpg.getConstantPool())); 234 il.append(classGen.loadTranslet()); 235 il.append(DUP); 236 il.append(new PUSH(cpg, name)); 237 translateValue(classGen, methodGen); 238 il.append(new PUSH(cpg, true)); 239 240 // Call addParameter() from this class 241 il.append(new INVOKEVIRTUAL(cpg.addMethodref(TRANSLET_CLASS, 242 ADD_PARAMETER, 243 ADD_PARAMETER_SIG))); 244 245 _type.translateUnBox(classGen, methodGen); 246 247 // Cache the result of addParameter() in a field 248 if (className != EMPTYSTRING) { 249 il.append(new CHECKCAST(cpg.addClass(className))); 250 } 251 il.append(new PUTFIELD(cpg.addFieldref(classGen.getClassName(), 252 name, signature))); 253 } 254 } 255 } 256 } 257