IdentNode.java revision 1068:34ef988d5959
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 long serialVersionUID = 1L; 46 47 private static final int PROPERTY_NAME = 1 << 0; 48 private static final int INITIALIZED_HERE = 1 << 1; 49 private static final int FUNCTION = 1 << 2; 50 private static final int FUTURESTRICT_NAME = 1 << 3; 51 private static final int IS_DECLARED_HERE = 1 << 4; 52 private static final int IS_DEAD = 1 << 5; 53 54 /** Identifier. */ 55 private final String name; 56 57 /** Optimistic type */ 58 private final Type type; 59 60 private final int flags; 61 62 private final int programPoint; 63 64 private final LocalVariableConversion conversion; 65 66 private Symbol symbol; 67 68 69 /** 70 * Constructor 71 * 72 * @param token token 73 * @param finish finish position 74 * @param name name of identifier 75 */ 76 public IdentNode(final long token, final int finish, final String name) { 77 super(token, finish); 78 this.name = name; 79 this.type = null; 80 this.flags = 0; 81 this.programPoint = INVALID_PROGRAM_POINT; 82 this.conversion = null; 83 } 84 85 private IdentNode(final IdentNode identNode, final String name, final Type type, final int flags, final int programPoint, final LocalVariableConversion conversion) { 86 super(identNode); 87 this.name = name; 88 this.type = type; 89 this.flags = flags; 90 this.programPoint = programPoint; 91 this.conversion = conversion; 92 this.symbol = identNode.symbol; 93 } 94 95 /** 96 * Copy constructor - create a new IdentNode for the same location 97 * 98 * @param identNode identNode 99 */ 100 public IdentNode(final IdentNode identNode) { 101 super(identNode); 102 this.name = identNode.getName(); 103 this.type = identNode.type; 104 this.flags = identNode.flags; 105 this.conversion = identNode.conversion; 106 this.programPoint = INVALID_PROGRAM_POINT; 107 this.symbol = identNode.symbol; 108 } 109 110 /** 111 * Creates an identifier for the symbol. Normally used by code generator for creating temporary storage identifiers 112 * that must contain both a symbol and a type. 113 * @param symbol the symbol to create a temporary identifier for. 114 * @return a temporary identifier for the symbol. 115 */ 116 public static IdentNode createInternalIdentifier(final Symbol symbol) { 117 return new IdentNode(Token.toDesc(TokenType.IDENT, 0, 0), 0, symbol.getName()).setSymbol(symbol); 118 } 119 120 @Override 121 public Type getType(final Function<Symbol, Type> localVariableTypes) { 122 if(type != null) { 123 return type; 124 } else if(symbol != null && symbol.isScope()) { 125 return Type.OBJECT; 126 } 127 final Type symbolType = localVariableTypes.apply(symbol); 128 return symbolType == null ? Type.UNDEFINED : symbolType; 129 } 130 131 /** 132 * Assist in IR navigation. 133 * 134 * @param visitor IR navigating visitor. 135 */ 136 @Override 137 public Node accept(final NodeVisitor<? extends LexicalContext> visitor) { 138 if (visitor.enterIdentNode(this)) { 139 return visitor.leaveIdentNode(this); 140 } 141 142 return this; 143 } 144 145 @Override 146 public void toString(final StringBuilder sb, final boolean printType) { 147 if (printType) { 148 optimisticTypeToString(sb, symbol == null || !symbol.hasSlot()); 149 } 150 sb.append(name); 151 } 152 153 /** 154 * Get the name of the identifier 155 * @return IdentNode name 156 */ 157 public String getName() { 158 return name; 159 } 160 161 @Override 162 public String getPropertyName() { 163 return getName(); 164 } 165 166 @Override 167 public boolean isLocal() { 168 return !getSymbol().isScope(); 169 } 170 171 /** 172 * Return the Symbol the compiler has assigned to this identifier. The symbol is a description of the storage 173 * location for the identifier. 174 * 175 * @return the symbol 176 */ 177 public Symbol getSymbol() { 178 return symbol; 179 } 180 181 /** 182 * Assign a symbol to this identifier. See {@link IdentNode#getSymbol()} for explanation of what a symbol is. 183 * 184 * @param symbol the symbol 185 * @return new node 186 */ 187 public IdentNode setSymbol(final Symbol symbol) { 188 if (this.symbol == symbol) { 189 return this; 190 } 191 final IdentNode newIdent = (IdentNode)clone(); 192 newIdent.symbol = symbol; 193 return newIdent; 194 } 195 196 /** 197 * Check if this IdentNode is a property name 198 * @return true if this is a property name 199 */ 200 public boolean isPropertyName() { 201 return (flags & PROPERTY_NAME) == PROPERTY_NAME; 202 } 203 204 /** 205 * Flag this IdentNode as a property name 206 * @return a node equivalent to this one except for the requested change. 207 */ 208 public IdentNode setIsPropertyName() { 209 if (isPropertyName()) { 210 return this; 211 } 212 return new IdentNode(this, name, type, flags | PROPERTY_NAME, programPoint, conversion); 213 } 214 215 /** 216 * Check if this IdentNode is a future strict name 217 * @return true if this is a future strict name 218 */ 219 public boolean isFutureStrictName() { 220 return (flags & FUTURESTRICT_NAME) == FUTURESTRICT_NAME; 221 } 222 223 /** 224 * Flag this IdentNode as a future strict name 225 * @return a node equivalent to this one except for the requested change. 226 */ 227 public IdentNode setIsFutureStrictName() { 228 if (isFutureStrictName()) { 229 return this; 230 } 231 return new IdentNode(this, name, type, flags | FUTURESTRICT_NAME, programPoint, conversion); 232 } 233 234 /** 235 * Helper function for local def analysis. 236 * @return true if IdentNode is initialized on creation 237 */ 238 public boolean isInitializedHere() { 239 return (flags & INITIALIZED_HERE) == INITIALIZED_HERE; 240 } 241 242 /** 243 * Flag IdentNode to be initialized on creation 244 * @return a node equivalent to this one except for the requested change. 245 */ 246 public IdentNode setIsInitializedHere() { 247 if (isInitializedHere()) { 248 return this; 249 } 250 return new IdentNode(this, name, type, flags | INITIALIZED_HERE, programPoint, conversion); 251 } 252 253 /** 254 * Is this a LET or CONST identifier used before its declaration? 255 * 256 * @return true if identifier is dead 257 */ 258 public boolean isDead() { 259 return (flags & IS_DEAD) != 0; 260 } 261 262 /** 263 * Flag this IdentNode as a LET or CONST identifier used before its declaration. 264 * 265 * @return a new IdentNode equivalent to this but marked as dead. 266 */ 267 public IdentNode markDead() { 268 return new IdentNode(this, name, type, flags | IS_DEAD, programPoint, conversion); 269 } 270 271 /** 272 * Is this IdentNode declared here? 273 * 274 * @return true if identifier is declared here 275 */ 276 public boolean isDeclaredHere() { 277 return (flags & IS_DECLARED_HERE) != 0; 278 } 279 280 /** 281 * Flag this IdentNode as being declared here. 282 * 283 * @return a new IdentNode equivalent to this but marked as declared here. 284 */ 285 public IdentNode setIsDeclaredHere() { 286 if (isDeclaredHere()) { 287 return this; 288 } 289 return new IdentNode(this, name, type, flags | IS_DECLARED_HERE, programPoint, conversion); 290 } 291 292 /** 293 * Check if the name of this IdentNode is same as that of a compile-time property (currently __DIR__, __FILE__, and 294 * __LINE__). 295 * 296 * @return true if this IdentNode's name is same as that of a compile-time property 297 */ 298 public boolean isCompileTimePropertyName() { 299 return name.equals(__DIR__.symbolName()) || name.equals(__FILE__.symbolName()) || name.equals(__LINE__.symbolName()); 300 } 301 302 @Override 303 public boolean isFunction() { 304 return (flags & FUNCTION) == FUNCTION; 305 } 306 307 @Override 308 public IdentNode setType(final Type type) { 309 if (this.type == type) { 310 return this; 311 } 312 return new IdentNode(this, name, type, flags, programPoint, conversion); 313 } 314 315 /** 316 * Mark this node as being the callee operand of a {@link CallNode}. 317 * @return an ident node identical to this one in all aspects except with its function flag set. 318 */ 319 public IdentNode setIsFunction() { 320 if (isFunction()) { 321 return this; 322 } 323 return new IdentNode(this, name, type, flags | FUNCTION, programPoint, conversion); 324 } 325 326 /** 327 * Mark this node as not being the callee operand of a {@link CallNode}. 328 * @return an ident node identical to this one in all aspects except with its function flag unset. 329 */ 330 public IdentNode setIsNotFunction() { 331 if (! isFunction()) { 332 return this; 333 } 334 return new IdentNode(this, name, type, flags & ~FUNCTION, programPoint, conversion); 335 } 336 337 @Override 338 public int getProgramPoint() { 339 return programPoint; 340 } 341 342 @Override 343 public Optimistic setProgramPoint(final int programPoint) { 344 if (this.programPoint == programPoint) { 345 return this; 346 } 347 return new IdentNode(this, name, type, flags, programPoint, conversion); 348 } 349 350 @Override 351 public Type getMostOptimisticType() { 352 return Type.INT; 353 } 354 355 @Override 356 public Type getMostPessimisticType() { 357 return Type.OBJECT; 358 } 359 360 @Override 361 public boolean canBeOptimistic() { 362 return true; 363 } 364 365 @Override 366 public JoinPredecessor setLocalVariableConversion(final LexicalContext lc, final LocalVariableConversion conversion) { 367 if(this.conversion == conversion) { 368 return this; 369 } 370 return new IdentNode(this, name, type, flags, programPoint, conversion); 371 } 372 373 /** 374 * Is this an internal symbol, i.e. one that starts with ':'. Those can 375 * never be optimistic. 376 * @return true if internal symbol 377 */ 378 public boolean isInternal() { 379 assert name != null; 380 return name.charAt(0) == ':'; 381 } 382 383 @Override 384 public LocalVariableConversion getLocalVariableConversion() { 385 return conversion; 386 } 387} 388