src/jdk/nashorn/internal/ir/Node.java

Thu, 14 Feb 2013 13:22:26 +0100

author
attila
date
Thu, 14 Feb 2013 13:22:26 +0100
changeset 90
5a820fb11814
parent 57
59970b70ebb5
child 144
4be452026847
permissions
-rw-r--r--

8008085: Integrate Dynalink source code into Nashorn codebase
Reviewed-by: jlaskey, lagergren, sundar

jlaskey@3 1 /*
jlaskey@7 2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
jlaskey@3 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
jlaskey@3 4 *
jlaskey@3 5 * This code is free software; you can redistribute it and/or modify it
jlaskey@3 6 * under the terms of the GNU General Public License version 2 only, as
jlaskey@3 7 * published by the Free Software Foundation. Oracle designates this
jlaskey@3 8 * particular file as subject to the "Classpath" exception as provided
jlaskey@3 9 * by Oracle in the LICENSE file that accompanied this code.
jlaskey@3 10 *
jlaskey@3 11 * This code is distributed in the hope that it will be useful, but WITHOUT
jlaskey@3 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
jlaskey@3 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
jlaskey@3 14 * version 2 for more details (a copy is included in the LICENSE file that
jlaskey@3 15 * accompanied this code).
jlaskey@3 16 *
jlaskey@3 17 * You should have received a copy of the GNU General Public License version
jlaskey@3 18 * 2 along with this work; if not, write to the Free Software Foundation,
jlaskey@3 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
jlaskey@3 20 *
jlaskey@3 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
jlaskey@3 22 * or visit www.oracle.com if you need additional information or have any
jlaskey@3 23 * questions.
jlaskey@3 24 */
jlaskey@3 25
jlaskey@3 26 package jdk.nashorn.internal.ir;
jlaskey@3 27
jlaskey@3 28 import java.util.IdentityHashMap;
jlaskey@3 29 import jdk.nashorn.internal.codegen.types.Type;
jlaskey@3 30 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
jlaskey@3 31 import jdk.nashorn.internal.parser.Token;
jlaskey@3 32 import jdk.nashorn.internal.runtime.Source;
jlaskey@3 33
jlaskey@3 34 /**
jlaskey@3 35 * Nodes are used to compose Abstract Syntax Trees.
jlaskey@3 36 *
jlaskey@3 37 */
jlaskey@3 38 public abstract class Node extends Location {
jlaskey@3 39 /** Node symbol. */
lagergren@57 40 private Symbol symbol;
jlaskey@3 41
jlaskey@3 42 /** Start of source range. */
jlaskey@3 43 protected int start;
jlaskey@3 44
jlaskey@3 45 /** End of source range. */
jlaskey@3 46 protected int finish;
jlaskey@3 47
jlaskey@3 48 /** Has this node been resolved - i.e. emitted code already */
jlaskey@3 49 private boolean isResolved;
jlaskey@3 50
jlaskey@3 51 /** Is this node terminal */
jlaskey@3 52 private boolean isTerminal;
jlaskey@3 53
jlaskey@3 54 /** Is this a goto node */
jlaskey@3 55 private boolean hasGoto;
jlaskey@3 56
jlaskey@3 57 /** Is this a discard */
jlaskey@3 58 private boolean shouldDiscard;
jlaskey@3 59
jlaskey@3 60 /**
jlaskey@3 61 * Constructor
jlaskey@3 62 *
jlaskey@3 63 * @param source the source
jlaskey@3 64 * @param token token
jlaskey@3 65 * @param finish finish
jlaskey@3 66 */
jlaskey@3 67 public Node(final Source source, final long token, final int finish) {
jlaskey@3 68 super(source, token);
jlaskey@3 69
lagergren@57 70 this.start = Token.descPosition(token);
jlaskey@3 71 this.finish = finish;
jlaskey@3 72 }
jlaskey@3 73
jlaskey@3 74 /**
jlaskey@3 75 * Copy constructor
jlaskey@3 76 *
jlaskey@3 77 * @param node source node
jlaskey@3 78 */
jlaskey@3 79 protected Node(final Node node) {
jlaskey@3 80 super(node);
jlaskey@3 81
lagergren@57 82 this.symbol = node.symbol;
jlaskey@3 83 this.isResolved = node.isResolved;
jlaskey@3 84 this.isTerminal = node.isTerminal;
jlaskey@3 85 this.hasGoto = node.hasGoto;
jlaskey@3 86 this.shouldDiscard = node.shouldDiscard;
jlaskey@3 87 this.start = node.start;
jlaskey@3 88 this.finish = node.finish;
jlaskey@3 89 }
jlaskey@3 90
jlaskey@3 91 /**
jlaskey@3 92 * Check if the node has a type. The default behavior is to go into the symbol
jlaskey@3 93 * and check the symbol type, but there may be overrides, for example in
jlaskey@3 94 * getters that require a different type than the internal representation
jlaskey@3 95 *
jlaskey@3 96 * @return true if a type exists
jlaskey@3 97 */
jlaskey@3 98 public boolean hasType() {
jlaskey@3 99 return getSymbol() != null;
jlaskey@3 100 }
jlaskey@3 101
jlaskey@3 102 /**
jlaskey@3 103 * Returns the type of the node. Typically this is the symbol type. No types
jlaskey@3 104 * are stored in the node itself, unless it implements TypeOverride
jlaskey@3 105 *
jlaskey@3 106 * @return the type of the node.
jlaskey@3 107 */
jlaskey@3 108 public Type getType() {
lagergren@57 109 assert hasType() : this + " has no type";
lagergren@57 110 return symbol.getSymbolType();
jlaskey@3 111 }
jlaskey@3 112
jlaskey@3 113 /**
jlaskey@3 114 * Is this an atom node - for example a literal or an identity
jlaskey@3 115 *
jlaskey@3 116 * @return true if atom
jlaskey@3 117 */
jlaskey@3 118 public boolean isAtom() {
jlaskey@3 119 return false;
jlaskey@3 120 }
jlaskey@3 121
jlaskey@3 122 /**
jlaskey@3 123 * Is this a loop node?
jlaskey@3 124 *
jlaskey@3 125 * @return true if atom
jlaskey@3 126 */
jlaskey@3 127 public boolean isLoop() {
jlaskey@3 128 return false;
jlaskey@3 129 }
jlaskey@3 130
jlaskey@3 131 /**
jlaskey@3 132 * Is this an assignment node - for example a var node with an init
jlaskey@3 133 * or a binary node that writes to a destination
jlaskey@3 134 *
jlaskey@3 135 * @return true if assignment
jlaskey@3 136 */
jlaskey@3 137 public boolean isAssignment() {
jlaskey@3 138 return false;
jlaskey@3 139 }
jlaskey@3 140
jlaskey@3 141 /**
jlaskey@3 142 * Is this a self modifying assignment?
jlaskey@3 143 * @return true if self modifying, e.g. a++, or a*= 17
jlaskey@3 144 */
jlaskey@3 145 public boolean isSelfModifying() {
jlaskey@3 146 return false;
jlaskey@3 147 }
jlaskey@3 148
jlaskey@3 149 /**
jlaskey@3 150 * Returns widest operation type of this operation.
jlaskey@3 151 *
jlaskey@3 152 * @return the widest type for this operation
jlaskey@3 153 */
jlaskey@3 154 public Type getWidestOperationType() {
jlaskey@3 155 return Type.OBJECT;
jlaskey@3 156 }
jlaskey@3 157
jlaskey@3 158 /**
jlaskey@3 159 * Test to see if code been generated for this node. Set isResolved if not.
jlaskey@3 160 *
jlaskey@3 161 * @return True if node has already been resolved.
jlaskey@3 162 */
jlaskey@3 163 public boolean testResolved() {
jlaskey@3 164 if (isResolved()) {
jlaskey@3 165 return true;
jlaskey@3 166 }
jlaskey@3 167
jlaskey@3 168 setIsResolved();
jlaskey@3 169
jlaskey@3 170 return false;
jlaskey@3 171 }
jlaskey@3 172
jlaskey@3 173 /**
jlaskey@3 174 * Is this a debug info node like LineNumberNode etc?
jlaskey@3 175 *
jlaskey@3 176 * @return true if this is a debug node
jlaskey@3 177 */
jlaskey@3 178 public boolean isDebug() {
jlaskey@3 179 return false;
jlaskey@3 180 }
jlaskey@3 181
jlaskey@3 182 /**
jlaskey@3 183 * Helper class used for node cloning
jlaskey@3 184 */
jlaskey@3 185 public static final class CopyState {
jlaskey@3 186 private final IdentityHashMap<Node, Node> cloneMap = new IdentityHashMap<>();
jlaskey@3 187
jlaskey@3 188 /**
jlaskey@3 189 * Find existing or create new copy of the node.
jlaskey@3 190 *
jlaskey@3 191 * @param node Node to copy.
jlaskey@3 192 *
jlaskey@3 193 * @return New object.
jlaskey@3 194 */
jlaskey@3 195 public Node existingOrCopy(final Node node) {
jlaskey@3 196 if (node != null) {
jlaskey@3 197 Node copy = cloneMap.get(node);
jlaskey@3 198
jlaskey@3 199 if (copy == null) {
jlaskey@3 200 copy = node.copy(this);
jlaskey@3 201 cloneMap.put(node, copy);
jlaskey@3 202 }
jlaskey@3 203
jlaskey@3 204 return copy;
jlaskey@3 205 }
jlaskey@3 206
jlaskey@3 207 return node;
jlaskey@3 208 }
jlaskey@3 209
jlaskey@3 210 /**
jlaskey@3 211 * Find existing or use old copy of the node.
jlaskey@3 212 *
jlaskey@3 213 * @param node Node to copy.
jlaskey@3 214 *
jlaskey@3 215 * @return new object.
jlaskey@3 216 */
jlaskey@3 217 public Node existingOrSame(final Node node) {
jlaskey@3 218 if (node != null) {
jlaskey@3 219 Node copy = cloneMap.get(node);
jlaskey@3 220
jlaskey@3 221 if (copy == null) {
jlaskey@3 222 copy = node;
jlaskey@3 223 }
jlaskey@3 224
jlaskey@3 225 return copy;
jlaskey@3 226 }
jlaskey@3 227
jlaskey@3 228 return node;
jlaskey@3 229 }
jlaskey@3 230 }
jlaskey@3 231
jlaskey@3 232 /**
jlaskey@3 233 * Deep copy the node.
jlaskey@3 234 *
jlaskey@3 235 * @return Deep copy of the Node.
jlaskey@3 236 */
jlaskey@3 237 @Override
jlaskey@3 238 public final Node clone() {
jlaskey@3 239 return copy(new CopyState());
jlaskey@3 240 }
jlaskey@3 241
jlaskey@3 242 /**
jlaskey@3 243 * Deep copy the node.
jlaskey@3 244 *
jlaskey@3 245 * @param cs CopyState passed around to re-use certain nodes.
jlaskey@3 246 * @return Deep copy of the Node.
jlaskey@3 247 */
jlaskey@3 248 protected Node copy(final CopyState cs) {
jlaskey@3 249 return cs.existingOrCopy(this);
jlaskey@3 250 }
jlaskey@3 251
jlaskey@3 252 /**
jlaskey@3 253 * Provides a means to navigate the IR.
jlaskey@3 254 * @param visitor Node visitor.
jlaskey@3 255 * @return node the node or its replacement after visitation, null if no further visitations are required
jlaskey@3 256 */
jlaskey@3 257 public abstract Node accept(NodeVisitor visitor);
jlaskey@3 258
jlaskey@3 259 @Override
jlaskey@3 260 public String toString() {
jlaskey@3 261 final StringBuilder sb = new StringBuilder();
jlaskey@3 262 toString(sb);
jlaskey@3 263 return sb.toString();
jlaskey@3 264 }
jlaskey@3 265
jlaskey@3 266 /**
jlaskey@3 267 * String conversion helper. Fills a {@link StringBuilder} with the
jlaskey@3 268 * string version of this node
jlaskey@3 269 *
jlaskey@3 270 * @param sb a StringBuilder
jlaskey@3 271 */
jlaskey@3 272 public abstract void toString(StringBuilder sb);
jlaskey@3 273
jlaskey@3 274 /**
jlaskey@3 275 * Check if this node has terminal flags, i.e. ends or breaks control flow
jlaskey@3 276 *
jlaskey@3 277 * @return true if terminal
jlaskey@3 278 */
jlaskey@3 279 public boolean hasTerminalFlags() {
jlaskey@3 280 return isTerminal || hasGoto;
jlaskey@3 281 }
jlaskey@3 282
jlaskey@3 283 /**
jlaskey@3 284 * Copy the terminal flags state of a node to another node
jlaskey@3 285 *
jlaskey@3 286 * @param other source node
jlaskey@3 287 */
jlaskey@3 288 public void copyTerminalFlags(final Node other) {
jlaskey@3 289 isTerminal = other.isTerminal;
jlaskey@3 290 hasGoto = other.hasGoto;
jlaskey@3 291 }
jlaskey@3 292
jlaskey@3 293 /**
jlaskey@3 294 * Check if the return value of this expression should be discarded
jlaskey@3 295 * @return true if return value is discarded
jlaskey@3 296 */
jlaskey@3 297 public boolean shouldDiscard() {
jlaskey@3 298 return shouldDiscard;
jlaskey@3 299 }
jlaskey@3 300
jlaskey@3 301 /**
jlaskey@3 302 * Setter that determines whether this node's return value should be discarded
jlaskey@3 303 * or not
jlaskey@3 304 *
jlaskey@3 305 * @param shouldDiscard true if return value is discarded, false otherwise
jlaskey@3 306 */
jlaskey@3 307 public void setDiscard(final boolean shouldDiscard) {
jlaskey@3 308 this.shouldDiscard = shouldDiscard;
jlaskey@3 309 }
jlaskey@3 310
jlaskey@3 311 /**
jlaskey@3 312 * Get the finish position for this node in the source string
jlaskey@3 313 * @return finish
jlaskey@3 314 */
jlaskey@3 315 public int getFinish() {
jlaskey@3 316 return finish;
jlaskey@3 317 }
jlaskey@3 318
jlaskey@3 319 /**
jlaskey@3 320 * Set finish position for this node in the source string
jlaskey@3 321 * @param finish finish
jlaskey@3 322 */
jlaskey@3 323 public void setFinish(final int finish) {
jlaskey@3 324 this.finish = finish;
jlaskey@3 325 }
jlaskey@3 326
jlaskey@3 327 /**
jlaskey@3 328 * Check if this function repositions control flow with goto like
jlaskey@3 329 * semantics, for example {@link BreakNode} or a {@link ForNode} with no test
jlaskey@3 330 * @return true if node has goto semantics
jlaskey@3 331 */
jlaskey@3 332 public boolean hasGoto() {
jlaskey@3 333 return hasGoto;
jlaskey@3 334 }
jlaskey@3 335
jlaskey@3 336 /**
jlaskey@3 337 * Flag this node as having goto semantics as described in {@link Node#hasGoto()}
jlaskey@3 338 */
jlaskey@3 339 public void setHasGoto() {
jlaskey@3 340 this.hasGoto = true;
jlaskey@3 341 }
jlaskey@3 342
jlaskey@3 343 /**
jlaskey@3 344 * Check whether this node is resolved, i.e. code has been generated for it
jlaskey@3 345 * @return true if node is resolved
jlaskey@3 346 */
jlaskey@3 347 public boolean isResolved() {
jlaskey@3 348 return isResolved;
jlaskey@3 349 }
jlaskey@3 350
jlaskey@3 351 /**
jlaskey@3 352 * Flag this node as resolved, i.e. code has been generated for it
jlaskey@3 353 */
jlaskey@3 354 public void setIsResolved() {
jlaskey@3 355 this.isResolved = true;
jlaskey@3 356 }
jlaskey@3 357
jlaskey@3 358 /**
jlaskey@3 359 * Get start position for node
jlaskey@3 360 * @return start position
jlaskey@3 361 */
jlaskey@3 362 public int getStart() {
jlaskey@3 363 return start;
jlaskey@3 364 }
jlaskey@3 365
jlaskey@3 366 /**
jlaskey@3 367 * Set start position for node
jlaskey@3 368 * @param start start position
jlaskey@3 369 */
jlaskey@3 370 public void setStart(final int start) {
jlaskey@3 371 this.start = start;
jlaskey@3 372 }
jlaskey@3 373
jlaskey@3 374 /**
jlaskey@3 375 * Return the Symbol the compiler has assigned to this Node. The symbol
jlaskey@3 376 * is the place where it's expression value is stored after evaluation
jlaskey@3 377 *
jlaskey@3 378 * @return the symbol
jlaskey@3 379 */
jlaskey@3 380 public Symbol getSymbol() {
lagergren@57 381 return symbol;
jlaskey@3 382 }
jlaskey@3 383
jlaskey@3 384 /**
jlaskey@3 385 * Assign a symbol to this node. See {@link Node#getSymbol()} for explanation
jlaskey@3 386 * of what a symbol is
jlaskey@3 387 *
jlaskey@3 388 * @param symbol the symbol
jlaskey@3 389 */
jlaskey@3 390 public void setSymbol(final Symbol symbol) {
lagergren@57 391 this.symbol = symbol;
jlaskey@3 392 }
jlaskey@3 393
jlaskey@3 394 /**
jlaskey@3 395 * Is this a terminal Node, i.e. does it end control flow like a throw or return
jlaskey@3 396 * expression does?
jlaskey@3 397 *
jlaskey@3 398 * @return true if this node is terminal
jlaskey@3 399 */
jlaskey@3 400 public boolean isTerminal() {
jlaskey@3 401 return isTerminal;
jlaskey@3 402 }
jlaskey@3 403
jlaskey@3 404 /**
jlaskey@3 405 * Set this to be a terminal node, i.e. it terminates control flow as described
jlaskey@3 406 * in {@link Node#isTerminal()}
jlaskey@3 407 *
jlaskey@3 408 * @param isTerminal true if this is a terminal node, false otherwise
jlaskey@3 409 */
jlaskey@3 410 public void setIsTerminal(final boolean isTerminal) {
jlaskey@3 411 this.isTerminal = isTerminal;
jlaskey@3 412 }
jlaskey@3 413
jlaskey@3 414 }

mercurial