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: Param.java 468650 2006-10-28 07:03:30Z minchau $ 020 */ 021 022 package org.apache.xalan.xsltc.compiler; 023 024 import org.apache.bcel.classfile.Field; 025 import org.apache.bcel.generic.BranchHandle; 026 import org.apache.bcel.generic.CHECKCAST; 027 import org.apache.bcel.generic.IFNONNULL; 028 import org.apache.bcel.generic.ConstantPoolGen; 029 import org.apache.bcel.generic.INVOKEVIRTUAL; 030 import org.apache.bcel.generic.Instruction; 031 import org.apache.bcel.generic.InstructionList; 032 import org.apache.bcel.generic.PUSH; 033 import org.apache.bcel.generic.PUTFIELD; 034 import org.apache.xalan.xsltc.compiler.util.ClassGenerator; 035 import org.apache.xalan.xsltc.compiler.util.ErrorMsg; 036 import org.apache.xalan.xsltc.compiler.util.MethodGenerator; 037 import org.apache.xalan.xsltc.compiler.util.ReferenceType; 038 import org.apache.xalan.xsltc.compiler.util.Type; 039 import org.apache.xalan.xsltc.compiler.util.ObjectType; 040 import org.apache.xalan.xsltc.compiler.util.TypeCheckError; 041 import org.apache.xalan.xsltc.runtime.BasisLibrary; 042 043 /** 044 * @author Jacek Ambroziak 045 * @author Santiago Pericas-Geertsen 046 * @author Morten Jorgensen 047 * @author Erwin Bolwidt <ejb@klomp.org> 048 * @author John Howard <JohnH@schemasoft.com> 049 */ 050 final class Param extends VariableBase { 051 052 /** 053 * True if this Param is declared in a simple named template. 054 * This is used to optimize codegen for parameter passing 055 * in named templates. 056 */ 057 private boolean _isInSimpleNamedTemplate = false; 058 059 /** 060 * Display variable as single string 061 */ 062 public String toString() { 063 return "param(" + _name + ")"; 064 } 065 066 /** 067 * Set the instruction for loading the value of this variable onto the 068 * JVM stack and returns the old instruction. 069 */ 070 public Instruction setLoadInstruction(Instruction instruction) { 071 Instruction tmp = _loadInstruction; 072 _loadInstruction = instruction; 073 return tmp; 074 } 075 076 /** 077 * Set the instruction for storing a value from the stack into this 078 * variable and returns the old instruction. 079 */ 080 public Instruction setStoreInstruction(Instruction instruction) { 081 Instruction tmp = _storeInstruction; 082 _storeInstruction = instruction; 083 return tmp; 084 } 085 086 /** 087 * Display variable in a full AST dump 088 */ 089 public void display(int indent) { 090 indent(indent); 091 System.out.println("param " + _name); 092 if (_select != null) { 093 indent(indent + IndentIncrement); 094 System.out.println("select " + _select.toString()); 095 } 096 displayContents(indent + IndentIncrement); 097 } 098 099 /** 100 * Parse the contents of the <xsl:param> element. This method must read 101 * the 'name' (required) and 'select' (optional) attributes. 102 */ 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 return; 128 } 129 else { 130 param.disable(); 131 } 132 } 133 // Add this variable if we have higher precedence 134 ((Stylesheet)parent).addParam(this); 135 parser.getSymbolTable().addParam(this); 136 } 137 else if (parent instanceof Template) { 138 Template template = (Template) parent; 139 _isLocal = true; 140 template.addParameter(this); 141 if (template.isSimpleNamedTemplate()) { 142 _isInSimpleNamedTemplate = true; 143 } 144 } 145 } 146 147 /** 148 * Type-checks the parameter. The parameter type is determined by the 149 * 'select' expression (if present) or is a result tree if the parameter 150 * element has a body and no 'select' expression. 151 */ 152 public Type typeCheck(SymbolTable stable) throws TypeCheckError { 153 if (_select != null) { 154 _type = _select.typeCheck(stable); 155 if (_type instanceof ReferenceType == false && !(_type instanceof ObjectType)) { 156 _select = new CastExpr(_select, Type.Reference); 157 } 158 } 159 else if (hasContents()) { 160 typeCheckContents(stable); 161 } 162 _type = Type.Reference; 163 164 // This element has no type (the parameter does, but the parameter 165 // element itself does not). 166 return Type.Void; 167 } 168 169 public void translate(ClassGenerator classGen, MethodGenerator methodGen) { 170 final ConstantPoolGen cpg = classGen.getConstantPool(); 171 final InstructionList il = methodGen.getInstructionList(); 172 173 if (_ignore) return; 174 _ignore = true; 175 176 /* 177 * To fix bug 24518 related to setting parameters of the form 178 * {namespaceuri}localName which will get mapped to an instance 179 * variable in the class. 180 */ 181 final String name = BasisLibrary.mapQNameToJavaName(_name.toString()); 182 final String signature = _type.toSignature(); 183 final String className = _type.getClassName(); 184 185 if (isLocal()) { 186 /* 187 * If simple named template then generate a conditional init of the 188 * param using its default value: 189 * if (param == null) param = <default-value> 190 */ 191 if (_isInSimpleNamedTemplate) { 192 il.append(loadInstruction()); 193 BranchHandle ifBlock = il.append(new IFNONNULL(null)); 194 translateValue(classGen, methodGen); 195 il.append(storeInstruction()); 196 ifBlock.setTarget(il.append(NOP)); 197 return; 198 } 199 200 il.append(classGen.loadTranslet()); 201 il.append(new PUSH(cpg, name)); 202 translateValue(classGen, methodGen); 203 il.append(new PUSH(cpg, true)); 204 205 // Call addParameter() from this class 206 il.append(new INVOKEVIRTUAL(cpg.addMethodref(TRANSLET_CLASS, 207 ADD_PARAMETER, 208 ADD_PARAMETER_SIG))); 209 if (className != EMPTYSTRING) { 210 il.append(new CHECKCAST(cpg.addClass(className))); 211 } 212 213 _type.translateUnBox(classGen, methodGen); 214 215 if (_refs.isEmpty()) { // nobody uses the value 216 il.append(_type.POP()); 217 _local = null; 218 } 219 else { // normal case 220 _local = methodGen.addLocalVariable2(name, 221 _type.toJCType(), 222 null); 223 // Cache the result of addParameter() in a local variable 224 _local.setStart(il.append(_type.STORE(_local.getIndex()))); 225 } 226 } 227 else { 228 if (classGen.containsField(name) == null) { 229 classGen.addField(new Field(ACC_PUBLIC, cpg.addUtf8(name), 230 cpg.addUtf8(signature), 231 null, cpg.getConstantPool())); 232 il.append(classGen.loadTranslet()); 233 il.append(DUP); 234 il.append(new PUSH(cpg, name)); 235 translateValue(classGen, methodGen); 236 il.append(new PUSH(cpg, true)); 237 238 // Call addParameter() from this class 239 il.append(new INVOKEVIRTUAL(cpg.addMethodref(TRANSLET_CLASS, 240 ADD_PARAMETER, 241 ADD_PARAMETER_SIG))); 242 243 _type.translateUnBox(classGen, methodGen); 244 245 // Cache the result of addParameter() in a field 246 if (className != EMPTYSTRING) { 247 il.append(new CHECKCAST(cpg.addClass(className))); 248 } 249 il.append(new PUTFIELD(cpg.addFieldref(classGen.getClassName(), 250 name, signature))); 251 } 252 } 253 } 254 }