IdentNode.java revision 1002:2f0161551858
1156956Sume/* 2156956Sume * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 3156956Sume * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4156956Sume * 5156956Sume * This code is free software; you can redistribute it and/or modify it 6156956Sume * under the terms of the GNU General Public License version 2 only, as 7156956Sume * published by the Free Software Foundation. Oracle designates this 8156956Sume * particular file as subject to the "Classpath" exception as provided 9156956Sume * by Oracle in the LICENSE file that accompanied this code. 10156956Sume * 11156956Sume * This code is distributed in the hope that it will be useful, but WITHOUT 12156956Sume * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13156956Sume * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14156956Sume * version 2 for more details (a copy is included in the LICENSE file that 15156956Sume * accompanied this code). 16156956Sume * 17156956Sume * You should have received a copy of the GNU General Public License version 18156956Sume * 2 along with this work; if not, write to the Free Software Foundation, 19156956Sume * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20156956Sume * 21156956Sume * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22156956Sume * or visit www.oracle.com if you need additional information or have any 23156956Sume * questions. 24156956Sume */ 25156956Sume 26156956Sumepackage jdk.nashorn.internal.ir; 27156956Sume 28156956Sumeimport static jdk.nashorn.internal.codegen.CompilerConstants.__DIR__; 29156956Sumeimport static jdk.nashorn.internal.codegen.CompilerConstants.__FILE__; 30156956Sumeimport static jdk.nashorn.internal.codegen.CompilerConstants.__LINE__; 31156956Sumeimport static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT; 32168441Skan 33156956Sumeimport java.util.function.Function; 34156956Sumeimport jdk.nashorn.internal.codegen.types.Type; 35156956Sumeimport jdk.nashorn.internal.ir.annotations.Immutable; 36156956Sumeimport jdk.nashorn.internal.ir.visitor.NodeVisitor; 37156956Sumeimport jdk.nashorn.internal.parser.Token; 38156956Sumeimport jdk.nashorn.internal.parser.TokenType; 39156956Sume 40156956Sume/** 41156956Sume * IR representation for an identifier. 42156956Sume */ 43156956Sume@Immutable 44156956Sumepublic final class IdentNode extends Expression implements PropertyKey, FunctionCall, Optimistic, JoinPredecessor { 45156956Sume private static final int PROPERTY_NAME = 1 << 0; 46156956Sume private static final int INITIALIZED_HERE = 1 << 1; 47156956Sume private static final int FUNCTION = 1 << 2; 48156956Sume private static final int FUTURESTRICT_NAME = 1 << 3; 49156956Sume private static final int IS_DECLARED_HERE = 1 << 4; 50156956Sume private static final int IS_DEAD = 1 << 5; 51156956Sume 52156956Sume /** Identifier. */ 53156956Sume private final String name; 54156956Sume 55156956Sume /** Optimistic type */ 56156956Sume private final Type type; 57156956Sume 58156956Sume private final int flags; 59156956Sume 60156956Sume private final int programPoint; 61156956Sume 62158787Sume private final LocalVariableConversion conversion; 63158787Sume 64156956Sume private Symbol symbol; 65156956Sume 66158787Sume 67158787Sume /** 68156956Sume * Constructor 69156956Sume * 70156956Sume * @param token token 71156956Sume * @param finish finish position 72156956Sume * @param name name of identifier 73156956Sume */ 74156956Sume public IdentNode(final long token, final int finish, final String name) { 75156956Sume super(token, finish); 76156956Sume this.name = name; 77156956Sume this.type = null; 78156956Sume this.flags = 0; 79158787Sume this.programPoint = INVALID_PROGRAM_POINT; 80156956Sume this.conversion = null; 81156956Sume } 82156956Sume 83156956Sume private IdentNode(final IdentNode identNode, final String name, final Type type, final int flags, final int programPoint, final LocalVariableConversion conversion) { 84156956Sume super(identNode); 85158787Sume this.name = name; 86156956Sume this.type = type; 87156956Sume this.flags = flags; 88156956Sume this.programPoint = programPoint; 89156956Sume this.conversion = conversion; 90156956Sume this.symbol = identNode.symbol; 91156956Sume } 92157282Sdeischen 93156956Sume /** 94156956Sume * Copy constructor - create a new IdentNode for the same location 95156956Sume * 96156956Sume * @param identNode identNode 97156956Sume */ 98156956Sume public IdentNode(final IdentNode identNode) { 99156956Sume super(identNode); 100156956Sume this.name = identNode.getName(); 101156956Sume this.type = identNode.type; 102156956Sume this.flags = identNode.flags; 103156956Sume this.conversion = identNode.conversion; 104156956Sume this.programPoint = INVALID_PROGRAM_POINT; 105156956Sume this.symbol = identNode.symbol; 106158787Sume } 107156956Sume 108 /** 109 * Creates an identifier for the symbol. Normally used by code generator for creating temporary storage identifiers 110 * that must contain both a symbol and a type. 111 * @param symbol the symbol to create a temporary identifier for. 112 * @return a temporary identifier for the symbol. 113 */ 114 public static IdentNode createInternalIdentifier(final Symbol symbol) { 115 return new IdentNode(Token.toDesc(TokenType.IDENT, 0, 0), 0, symbol.getName()).setSymbol(symbol); 116 } 117 118 @Override 119 public Type getType(final Function<Symbol, Type> localVariableTypes) { 120 if(type != null) { 121 return type; 122 } else if(symbol != null && symbol.isScope()) { 123 return Type.OBJECT; 124 } 125 final Type symbolType = localVariableTypes.apply(symbol); 126 return symbolType == null ? Type.UNDEFINED : symbolType; 127 } 128 129 /** 130 * Assist in IR navigation. 131 * 132 * @param visitor IR navigating visitor. 133 */ 134 @Override 135 public Node accept(final NodeVisitor<? extends LexicalContext> visitor) { 136 if (visitor.enterIdentNode(this)) { 137 return visitor.leaveIdentNode(this); 138 } 139 140 return this; 141 } 142 143 @Override 144 public void toString(final StringBuilder sb, final boolean printType) { 145 if (printType) { 146 optimisticTypeToString(sb, symbol == null || !symbol.hasSlot()); 147 } 148 sb.append(name); 149 } 150 151 /** 152 * Get the name of the identifier 153 * @return IdentNode name 154 */ 155 public String getName() { 156 return name; 157 } 158 159 @Override 160 public String getPropertyName() { 161 return getName(); 162 } 163 164 @Override 165 public boolean isLocal() { 166 return !getSymbol().isScope(); 167 } 168 169 /** 170 * Return the Symbol the compiler has assigned to this identifier. The symbol is a description of the storage 171 * location for the identifier. 172 * 173 * @return the symbol 174 */ 175 public Symbol getSymbol() { 176 return symbol; 177 } 178 179 /** 180 * Assign a symbol to this identifier. See {@link IdentNode#getSymbol()} for explanation of what a symbol is. 181 * 182 * @param symbol the symbol 183 * @return new node 184 */ 185 public IdentNode setSymbol(final Symbol symbol) { 186 if (this.symbol == symbol) { 187 return this; 188 } 189 final IdentNode newIdent = (IdentNode)clone(); 190 newIdent.symbol = symbol; 191 return newIdent; 192 } 193 194 /** 195 * Check if this IdentNode is a property name 196 * @return true if this is a property name 197 */ 198 public boolean isPropertyName() { 199 return (flags & PROPERTY_NAME) == PROPERTY_NAME; 200 } 201 202 /** 203 * Flag this IdentNode as a property name 204 * @return a node equivalent to this one except for the requested change. 205 */ 206 public IdentNode setIsPropertyName() { 207 if (isPropertyName()) { 208 return this; 209 } 210 return new IdentNode(this, name, type, flags | PROPERTY_NAME, programPoint, conversion); 211 } 212 213 /** 214 * Check if this IdentNode is a future strict name 215 * @return true if this is a future strict name 216 */ 217 public boolean isFutureStrictName() { 218 return (flags & FUTURESTRICT_NAME) == FUTURESTRICT_NAME; 219 } 220 221 /** 222 * Flag this IdentNode as a future strict name 223 * @return a node equivalent to this one except for the requested change. 224 */ 225 public IdentNode setIsFutureStrictName() { 226 if (isFutureStrictName()) { 227 return this; 228 } 229 return new IdentNode(this, name, type, flags | FUTURESTRICT_NAME, programPoint, conversion); 230 } 231 232 /** 233 * Helper function for local def analysis. 234 * @return true if IdentNode is initialized on creation 235 */ 236 public boolean isInitializedHere() { 237 return (flags & INITIALIZED_HERE) == INITIALIZED_HERE; 238 } 239 240 /** 241 * Flag IdentNode to be initialized on creation 242 * @return a node equivalent to this one except for the requested change. 243 */ 244 public IdentNode setIsInitializedHere() { 245 if (isInitializedHere()) { 246 return this; 247 } 248 return new IdentNode(this, name, type, flags | INITIALIZED_HERE, programPoint, conversion); 249 } 250 251 /** 252 * Is this a LET or CONST identifier used before its declaration? 253 * 254 * @return true if identifier is dead 255 */ 256 public boolean isDead() { 257 return (flags & IS_DEAD) != 0; 258 } 259 260 /** 261 * Flag this IdentNode as a LET or CONST identifier used before its declaration. 262 * 263 * @return a new IdentNode equivalent to this but marked as dead. 264 */ 265 public IdentNode markDead() { 266 return new IdentNode(this, name, type, flags | IS_DEAD, programPoint, conversion); 267 } 268 269 /** 270 * Is this IdentNode declared here? 271 * 272 * @return true if identifier is declared here 273 */ 274 public boolean isDeclaredHere() { 275 return (flags & IS_DECLARED_HERE) != 0; 276 } 277 278 /** 279 * Flag this IdentNode as being declared here. 280 * 281 * @return a new IdentNode equivalent to this but marked as declared here. 282 */ 283 public IdentNode setIsDeclaredHere() { 284 if (isDeclaredHere()) { 285 return this; 286 } 287 return new IdentNode(this, name, type, flags | IS_DECLARED_HERE, programPoint, conversion); 288 } 289 290 /** 291 * Check if the name of this IdentNode is same as that of a compile-time property (currently __DIR__, __FILE__, and 292 * __LINE__). 293 * 294 * @return true if this IdentNode's name is same as that of a compile-time property 295 */ 296 public boolean isCompileTimePropertyName() { 297 return name.equals(__DIR__.symbolName()) || name.equals(__FILE__.symbolName()) || name.equals(__LINE__.symbolName()); 298 } 299 300 @Override 301 public boolean isFunction() { 302 return (flags & FUNCTION) == FUNCTION; 303 } 304 305 @Override 306 public IdentNode setType(final Type type) { 307 if (this.type == type) { 308 return this; 309 } 310 return new IdentNode(this, name, type, flags, programPoint, conversion); 311 } 312 313 /** 314 * Mark this node as being the callee operand of a {@link CallNode}. 315 * @return an ident node identical to this one in all aspects except with its function flag set. 316 */ 317 public IdentNode setIsFunction() { 318 if (isFunction()) { 319 return this; 320 } 321 return new IdentNode(this, name, type, flags | FUNCTION, programPoint, conversion); 322 } 323 324 /** 325 * Mark this node as not being the callee operand of a {@link CallNode}. 326 * @return an ident node identical to this one in all aspects except with its function flag unset. 327 */ 328 public IdentNode setIsNotFunction() { 329 if (! isFunction()) { 330 return this; 331 } 332 return new IdentNode(this, name, type, flags & ~FUNCTION, programPoint, conversion); 333 } 334 335 @Override 336 public int getProgramPoint() { 337 return programPoint; 338 } 339 340 @Override 341 public Optimistic setProgramPoint(final int programPoint) { 342 if (this.programPoint == programPoint) { 343 return this; 344 } 345 return new IdentNode(this, name, type, flags, programPoint, conversion); 346 } 347 348 @Override 349 public Type getMostOptimisticType() { 350 return Type.INT; 351 } 352 353 @Override 354 public Type getMostPessimisticType() { 355 return Type.OBJECT; 356 } 357 358 @Override 359 public boolean canBeOptimistic() { 360 return true; 361 } 362 363 @Override 364 public JoinPredecessor setLocalVariableConversion(final LexicalContext lc, final LocalVariableConversion conversion) { 365 if(this.conversion == conversion) { 366 return this; 367 } 368 return new IdentNode(this, name, type, flags, programPoint, conversion); 369 } 370 371 /** 372 * Is this an internal symbol, i.e. one that starts with ':'. Those can 373 * never be optimistic. 374 * @return true if internal symbol 375 */ 376 public boolean isInternal() { 377 assert name != null; 378 return name.charAt(0) == ':'; 379 } 380 381 @Override 382 public LocalVariableConversion getLocalVariableConversion() { 383 return conversion; 384 } 385} 386