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