IdentNode.java revision 953:221a84ef44c0
1/* 2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package jdk.nashorn.internal.ir; 27 28import static jdk.nashorn.internal.codegen.CompilerConstants.__DIR__; 29import static jdk.nashorn.internal.codegen.CompilerConstants.__FILE__; 30import static jdk.nashorn.internal.codegen.CompilerConstants.__LINE__; 31import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT; 32 33import java.util.function.Function; 34import jdk.nashorn.internal.codegen.types.Type; 35import jdk.nashorn.internal.ir.annotations.Immutable; 36import jdk.nashorn.internal.ir.visitor.NodeVisitor; 37import jdk.nashorn.internal.parser.Token; 38import jdk.nashorn.internal.parser.TokenType; 39 40/** 41 * IR representation for an identifier. 42 */ 43@Immutable 44public final class IdentNode extends Expression implements PropertyKey, FunctionCall, Optimistic, JoinPredecessor { 45 private static final int PROPERTY_NAME = 1 << 0; 46 private static final int INITIALIZED_HERE = 1 << 1; 47 private static final int FUNCTION = 1 << 2; 48 private static final int FUTURESTRICT_NAME = 1 << 3; 49 50 /** Identifier. */ 51 private final String name; 52 53 /** Optimistic type */ 54 private final Type type; 55 56 private final int flags; 57 58 private final int programPoint; 59 60 private final LocalVariableConversion conversion; 61 62 private Symbol symbol; 63 64 65 /** 66 * Constructor 67 * 68 * @param token token 69 * @param finish finish position 70 * @param name name of identifier 71 */ 72 public IdentNode(final long token, final int finish, final String name) { 73 super(token, finish); 74 this.name = name.intern(); 75 this.type = null; 76 this.flags = 0; 77 this.programPoint = INVALID_PROGRAM_POINT; 78 this.conversion = null; 79 } 80 81 private IdentNode(final IdentNode identNode, final String name, final Type type, final int flags, final int programPoint, final LocalVariableConversion conversion) { 82 super(identNode); 83 this.name = name; 84 this.type = type; 85 this.flags = flags; 86 this.programPoint = programPoint; 87 this.conversion = conversion; 88 this.symbol = identNode.symbol; 89 } 90 91 /** 92 * Copy constructor - create a new IdentNode for the same location 93 * 94 * @param identNode identNode 95 */ 96 public IdentNode(final IdentNode identNode) { 97 super(identNode); 98 this.name = identNode.getName(); 99 this.type = identNode.type; 100 this.flags = identNode.flags; 101 this.conversion = identNode.conversion; 102 this.programPoint = INVALID_PROGRAM_POINT; 103 this.symbol = identNode.symbol; 104 } 105 106 /** 107 * Creates an identifier for the symbol. Normally used by code generator for creating temporary storage identifiers 108 * that must contain both a symbol and a type. 109 * @param symbol the symbol to create a temporary identifier for. 110 * @return a temporary identifier for the symbol. 111 */ 112 public static IdentNode createInternalIdentifier(final Symbol symbol) { 113 return new IdentNode(Token.toDesc(TokenType.IDENT, 0, 0), 0, symbol.getName()).setSymbol(symbol); 114 } 115 116 @Override 117 public Type getType(final Function<Symbol, Type> localVariableTypes) { 118 if(type != null) { 119 return type; 120 } else if(symbol != null && symbol.isScope()) { 121 return Type.OBJECT; 122 } 123 final Type symbolType = localVariableTypes.apply(symbol); 124 return symbolType == null ? Type.UNDEFINED : symbolType; 125 } 126 127 /** 128 * Assist in IR navigation. 129 * 130 * @param visitor IR navigating visitor. 131 */ 132 @Override 133 public Node accept(final NodeVisitor<? extends LexicalContext> visitor) { 134 if (visitor.enterIdentNode(this)) { 135 return visitor.leaveIdentNode(this); 136 } 137 138 return this; 139 } 140 141 @Override 142 public void toString(final StringBuilder sb, final boolean printType) { 143 if (printType) { 144 optimisticTypeToString(sb, symbol == null || !symbol.hasSlot()); 145 } 146 sb.append(name); 147 } 148 149 /** 150 * Get the name of the identifier 151 * @return IdentNode name 152 */ 153 public String getName() { 154 return name; 155 } 156 157 @Override 158 public String getPropertyName() { 159 return getName(); 160 } 161 162 @Override 163 public boolean isLocal() { 164 return !getSymbol().isScope(); 165 } 166 167 /** 168 * Return the Symbol the compiler has assigned to this identifier. The symbol is a description of the storage 169 * location for the identifier. 170 * 171 * @return the symbol 172 */ 173 public Symbol getSymbol() { 174 return symbol; 175 } 176 177 /** 178 * Assign a symbol to this identifier. See {@link IdentNode#getSymbol()} for explanation of what a symbol is. 179 * 180 * @param symbol the symbol 181 * @return new node 182 */ 183 public IdentNode setSymbol(final Symbol symbol) { 184 if (this.symbol == symbol) { 185 return this; 186 } 187 final IdentNode newIdent = (IdentNode)clone(); 188 newIdent.symbol = symbol; 189 return newIdent; 190 } 191 192 /** 193 * Check if this IdentNode is a property name 194 * @return true if this is a property name 195 */ 196 public boolean isPropertyName() { 197 return (flags & PROPERTY_NAME) == PROPERTY_NAME; 198 } 199 200 /** 201 * Flag this IdentNode as a property name 202 * @return a node equivalent to this one except for the requested change. 203 */ 204 public IdentNode setIsPropertyName() { 205 if (isPropertyName()) { 206 return this; 207 } 208 return new IdentNode(this, name, type, flags | PROPERTY_NAME, programPoint, conversion); 209 } 210 211 /** 212 * Check if this IdentNode is a future strict name 213 * @return true if this is a future strict name 214 */ 215 public boolean isFutureStrictName() { 216 return (flags & FUTURESTRICT_NAME) == FUTURESTRICT_NAME; 217 } 218 219 /** 220 * Flag this IdentNode as a future strict name 221 * @return a node equivalent to this one except for the requested change. 222 */ 223 public IdentNode setIsFutureStrictName() { 224 if (isFutureStrictName()) { 225 return this; 226 } 227 return new IdentNode(this, name, type, flags | FUTURESTRICT_NAME, programPoint, conversion); 228 } 229 230 /** 231 * Helper function for local def analysis. 232 * @return true if IdentNode is initialized on creation 233 */ 234 public boolean isInitializedHere() { 235 return (flags & INITIALIZED_HERE) == INITIALIZED_HERE; 236 } 237 238 /** 239 * Flag IdentNode to be initialized on creation 240 * @return a node equivalent to this one except for the requested change. 241 */ 242 public IdentNode setIsInitializedHere() { 243 if (isInitializedHere()) { 244 return this; 245 } 246 return new IdentNode(this, name, type, flags | INITIALIZED_HERE, programPoint, conversion); 247 } 248 249 /** 250 * Check if the name of this IdentNode is same as that of a compile-time property (currently __DIR__, __FILE__, and 251 * __LINE__). 252 * 253 * @return true if this IdentNode's name is same as that of a compile-time property 254 */ 255 public boolean isCompileTimePropertyName() { 256 return name.equals(__DIR__.symbolName()) || name.equals(__FILE__.symbolName()) || name.equals(__LINE__.symbolName()); 257 } 258 259 @Override 260 public boolean isFunction() { 261 return (flags & FUNCTION) == FUNCTION; 262 } 263 264 @Override 265 public IdentNode setType(final Type type) { 266 if (this.type == type) { 267 return this; 268 } 269 return new IdentNode(this, name, type, flags, programPoint, conversion); 270 } 271 272 /** 273 * Mark this node as being the callee operand of a {@link CallNode}. 274 * @return an ident node identical to this one in all aspects except with its function flag set. 275 */ 276 public IdentNode setIsFunction() { 277 if (isFunction()) { 278 return this; 279 } 280 return new IdentNode(this, name, type, flags | FUNCTION, programPoint, conversion); 281 } 282 283 /** 284 * Mark this node as not being the callee operand of a {@link CallNode}. 285 * @return an ident node identical to this one in all aspects except with its function flag unset. 286 */ 287 public IdentNode setIsNotFunction() { 288 if (! isFunction()) { 289 return this; 290 } 291 return new IdentNode(this, name, type, flags & ~FUNCTION, programPoint, conversion); 292 } 293 294 @Override 295 public int getProgramPoint() { 296 return programPoint; 297 } 298 299 @Override 300 public Optimistic setProgramPoint(final int programPoint) { 301 if (this.programPoint == programPoint) { 302 return this; 303 } 304 return new IdentNode(this, name, type, flags, programPoint, conversion); 305 } 306 307 @Override 308 public Type getMostOptimisticType() { 309 return Type.INT; 310 } 311 312 @Override 313 public Type getMostPessimisticType() { 314 return Type.OBJECT; 315 } 316 317 @Override 318 public boolean canBeOptimistic() { 319 return true; 320 } 321 322 @Override 323 public JoinPredecessor setLocalVariableConversion(final LexicalContext lc, final LocalVariableConversion conversion) { 324 if(this.conversion == conversion) { 325 return this; 326 } 327 return new IdentNode(this, name, type, flags, programPoint, conversion); 328 } 329 330 /** 331 * Is this an internal symbol, i.e. one that starts with ':'. Those can 332 * never be optimistic. 333 * @return true if internal symbol 334 */ 335 public boolean isInternal() { 336 assert name != null; 337 return name.charAt(0) == ':'; 338 } 339 340 @Override 341 public LocalVariableConversion getLocalVariableConversion() { 342 return conversion; 343 } 344} 345