IdentNode.java revision 1152:5f6a840fc19d
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 jdk.nashorn.internal.codegen.types.Type; 34import jdk.nashorn.internal.ir.annotations.Immutable; 35import jdk.nashorn.internal.ir.visitor.NodeVisitor; 36import jdk.nashorn.internal.parser.Token; 37import jdk.nashorn.internal.parser.TokenType; 38 39/** 40 * IR representation for an identifier. 41 */ 42@Immutable 43public final class IdentNode extends Expression implements PropertyKey, FunctionCall, Optimistic, JoinPredecessor { 44 private static final long serialVersionUID = 1L; 45 46 private static final int PROPERTY_NAME = 1 << 0; 47 private static final int INITIALIZED_HERE = 1 << 1; 48 private static final int FUNCTION = 1 << 2; 49 private static final int FUTURESTRICT_NAME = 1 << 3; 50 private static final int IS_DECLARED_HERE = 1 << 4; 51 private static final int IS_DEAD = 1 << 5; 52 53 /** Identifier. */ 54 private final String name; 55 56 /** Optimistic type */ 57 private final Type type; 58 59 private final int flags; 60 61 private final int programPoint; 62 63 private final LocalVariableConversion conversion; 64 65 private Symbol symbol; 66 67 68 /** 69 * Constructor 70 * 71 * @param token token 72 * @param finish finish position 73 * @param name name of identifier 74 */ 75 public IdentNode(final long token, final int finish, final String name) { 76 super(token, finish); 77 this.name = name; 78 this.type = null; 79 this.flags = 0; 80 this.programPoint = INVALID_PROGRAM_POINT; 81 this.conversion = null; 82 } 83 84 private IdentNode(final IdentNode identNode, final String name, final Type type, final int flags, final int programPoint, final LocalVariableConversion conversion) { 85 super(identNode); 86 this.name = name; 87 this.type = type; 88 this.flags = flags; 89 this.programPoint = programPoint; 90 this.conversion = conversion; 91 this.symbol = identNode.symbol; 92 } 93 94 /** 95 * Copy constructor - create a new IdentNode for the same location 96 * 97 * @param identNode identNode 98 */ 99 public IdentNode(final IdentNode identNode) { 100 super(identNode); 101 this.name = identNode.getName(); 102 this.type = identNode.type; 103 this.flags = identNode.flags; 104 this.conversion = identNode.conversion; 105 this.programPoint = INVALID_PROGRAM_POINT; 106 this.symbol = identNode.symbol; 107 } 108 109 /** 110 * Creates an identifier for the symbol. Normally used by code generator for creating temporary storage identifiers 111 * that must contain both a symbol and a type. 112 * @param symbol the symbol to create a temporary identifier for. 113 * @return a temporary identifier for the symbol. 114 */ 115 public static IdentNode createInternalIdentifier(final Symbol symbol) { 116 return new IdentNode(Token.toDesc(TokenType.IDENT, 0, 0), 0, symbol.getName()).setSymbol(symbol); 117 } 118 119 @Override 120 public Type getType() { 121 if(type != null) { 122 return type; 123 } else if(symbol != null && symbol.isScope()) { 124 return Type.OBJECT; 125 } 126 return Type.UNDEFINED; 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