Variable.java revision 628:2bfaf29cc90b
1/* 2 * reserved comment block 3 * DO NOT REMOVE OR ALTER! 4 */ 5/* 6 * Copyright 2001-2004 The Apache Software Foundation. 7 * 8 * Licensed under the Apache License, Version 2.0 (the "License"); 9 * you may not use this file except in compliance with the License. 10 * You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 */ 20/* 21 * $Id: Variable.java,v 1.2.4.1 2005/09/12 11:36:46 pvedula Exp $ 22 */ 23 24package com.sun.org.apache.xalan.internal.xsltc.compiler; 25 26import com.sun.org.apache.bcel.internal.classfile.Field; 27import com.sun.org.apache.bcel.internal.generic.ACONST_NULL; 28import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen; 29import com.sun.org.apache.bcel.internal.generic.DCONST; 30import com.sun.org.apache.bcel.internal.generic.ICONST; 31import com.sun.org.apache.bcel.internal.generic.InstructionHandle; 32import com.sun.org.apache.bcel.internal.generic.InstructionList; 33import com.sun.org.apache.bcel.internal.generic.PUTFIELD; 34import com.sun.org.apache.xalan.internal.xsltc.compiler.util.BooleanType; 35import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator; 36import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg; 37import com.sun.org.apache.xalan.internal.xsltc.compiler.util.IntType; 38import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator; 39import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeType; 40import com.sun.org.apache.xalan.internal.xsltc.compiler.util.RealType; 41import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type; 42import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError; 43 44final class Variable extends VariableBase { 45 46 public int getIndex() { 47 return (_local != null) ? _local.getIndex() : -1; 48 } 49 50 /** 51 * Parse the contents of the variable 52 */ 53 public void parseContents(Parser parser) { 54 // Parse 'name' and 'select' attributes plus parameter contents 55 super.parseContents(parser); 56 57 // Add a ref to this var to its enclosing construct 58 SyntaxTreeNode parent = getParent(); 59 if (parent instanceof Stylesheet) { 60 // Mark this as a global variable 61 _isLocal = false; 62 // Check if a global variable with this name already exists... 63 Variable var = parser.getSymbolTable().lookupVariable(_name); 64 // ...and if it does we need to check import precedence 65 if (var != null) { 66 final int us = this.getImportPrecedence(); 67 final int them = var.getImportPrecedence(); 68 // It is an error if the two have the same import precedence 69 if (us == them) { 70 final String name = _name.toString(); 71 reportError(this, parser, ErrorMsg.VARIABLE_REDEF_ERR,name); 72 } 73 // Ignore this if previous definition has higher precedence 74 else if (them > us) { 75 _ignore = true; 76 copyReferences(var); 77 return; 78 } 79 else { 80 var.copyReferences(this); 81 var.disable(); 82 } 83 // Add this variable if we have higher precedence 84 } 85 ((Stylesheet)parent).addVariable(this); 86 parser.getSymbolTable().addVariable(this); 87 } 88 else { 89 _isLocal = true; 90 } 91 } 92 93 /** 94 * Runs a type check on either the variable element body or the 95 * expression in the 'select' attribute 96 */ 97 public Type typeCheck(SymbolTable stable) throws TypeCheckError { 98 99 // Type check the 'select' expression if present 100 if (_select != null) { 101 _type = _select.typeCheck(stable); 102 } 103 // Type check the element contents otherwise 104 else if (hasContents()) { 105 typeCheckContents(stable); 106 _type = Type.ResultTree; 107 } 108 else { 109 _type = Type.Reference; 110 } 111 // The return type is void as the variable element does not leave 112 // anything on the JVM's stack. The '_type' global will be returned 113 // by the references to this variable, and not by the variable itself. 114 return Type.Void; 115 } 116 117 /** 118 * This method is part of a little trick that is needed to use local 119 * variables inside nested for-each loops. See the initializeVariables() 120 * method in the ForEach class for an explanation 121 */ 122 public void initialize(ClassGenerator classGen, MethodGenerator methodGen) { 123 final ConstantPoolGen cpg = classGen.getConstantPool(); 124 final InstructionList il = methodGen.getInstructionList(); 125 126 // This is only done for local variables that are actually used 127 if (isLocal() && !_refs.isEmpty()) { 128 // Create a variable slot if none is allocated 129 if (_local == null) { 130 _local = methodGen.addLocalVariable2(getEscapedName(), 131 _type.toJCType(), 132 null); 133 } 134 // Push the default value on the JVM's stack 135 if ((_type instanceof IntType) || 136 (_type instanceof NodeType) || 137 (_type instanceof BooleanType)) 138 il.append(new ICONST(0)); // 0 for node-id, integer and boolean 139 else if (_type instanceof RealType) 140 il.append(new DCONST(0)); // 0.0 for floating point numbers 141 else 142 il.append(new ACONST_NULL()); // and 'null' for anything else 143 144 // Mark the store as the start of the live range of the variable 145 _local.setStart(il.append(_type.STORE(_local.getIndex()))); 146 147 } 148 } 149 150 public void translate(ClassGenerator classGen, MethodGenerator methodGen) { 151 final ConstantPoolGen cpg = classGen.getConstantPool(); 152 final InstructionList il = methodGen.getInstructionList(); 153 154 // Don't generate code for unreferenced variables 155 if (_refs.isEmpty()) { 156 _ignore = true; 157 } 158 159 // Make sure that a variable instance is only compiled once 160 if (_ignore) return; 161 _ignore = true; 162 163 final String name = getEscapedName(); 164 165 if (isLocal()) { 166 // Compile variable value computation 167 translateValue(classGen, methodGen); 168 169 // Add a new local variable and store value 170 boolean createLocal = _local == null; 171 if (createLocal) { 172 mapRegister(methodGen); 173 } 174 InstructionHandle storeInst = 175 il.append(_type.STORE(_local.getIndex())); 176 177 // If the local is just being created, mark the store as the start 178 // of its live range. Note that it might have been created by 179 // initializeVariables already, which would have set the start of 180 // the live range already. 181 if (createLocal) { 182 _local.setStart(storeInst); 183 } 184 } 185 else { 186 String signature = _type.toSignature(); 187 188 // Global variables are store in class fields 189 if (classGen.containsField(name) == null) { 190 classGen.addField(new Field(ACC_PUBLIC, 191 cpg.addUtf8(name), 192 cpg.addUtf8(signature), 193 null, cpg.getConstantPool())); 194 195 // Push a reference to "this" for putfield 196 il.append(classGen.loadTranslet()); 197 // Compile variable value computation 198 translateValue(classGen, methodGen); 199 // Store the variable in the allocated field 200 il.append(new PUTFIELD(cpg.addFieldref(classGen.getClassName(), 201 name, signature))); 202 } 203 } 204 } 205} 206