Mercurial > hg > openjdk > jigsaw > nashorn
view src/jdk/nashorn/internal/ir/Node.java @ 143:4be452026847
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
Reviewed-by: jlaskey, lagergren
author | attila |
---|---|
date | Sat, 23 Mar 2013 00:58:39 +0100 |
parents | 5a820fb11814 |
children |
line wrap: on
line source
/* * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package jdk.nashorn.internal.ir; import java.util.IdentityHashMap; import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.parser.Token; import jdk.nashorn.internal.runtime.Source; /** * Nodes are used to compose Abstract Syntax Trees. * */ public abstract class Node extends Location { /** Node symbol. */ private Symbol symbol; /** Start of source range. */ protected int start; /** End of source range. */ protected int finish; /** Has this node been resolved - i.e. emitted code already */ private boolean isResolved; /** Is this node terminal */ private boolean isTerminal; /** Is this a goto node */ private boolean hasGoto; /** Is this a discard */ private boolean shouldDiscard; /** * Constructor * * @param source the source * @param token token * @param finish finish */ public Node(final Source source, final long token, final int finish) { super(source, token); this.start = Token.descPosition(token); this.finish = finish; } /** * Copy constructor * * @param node source node */ protected Node(final Node node) { super(node); this.symbol = node.symbol; this.isResolved = node.isResolved; this.isTerminal = node.isTerminal; this.hasGoto = node.hasGoto; this.shouldDiscard = node.shouldDiscard; this.start = node.start; this.finish = node.finish; } /** * Check if the node has a type. The default behavior is to go into the symbol * and check the symbol type, but there may be overrides, for example in * getters that require a different type than the internal representation * * @return true if a type exists */ public boolean hasType() { return getSymbol() != null; } /** * Returns the type of the node. Typically this is the symbol type. No types * are stored in the node itself, unless it implements TypeOverride * * @return the type of the node. */ public Type getType() { assert hasType() : this + " has no type"; return symbol.getSymbolType(); } /** * Is this an atom node - for example a literal or an identity * * @return true if atom */ public boolean isAtom() { return false; } /** * Is this a loop node? * * @return true if atom */ public boolean isLoop() { return false; } /** * Is this an assignment node - for example a var node with an init * or a binary node that writes to a destination * * @return true if assignment */ public boolean isAssignment() { return false; } /** * Is this a self modifying assignment? * @return true if self modifying, e.g. a++, or a*= 17 */ public boolean isSelfModifying() { return false; } /** * Returns widest operation type of this operation. * * @return the widest type for this operation */ public Type getWidestOperationType() { return Type.OBJECT; } /** * Test to see if code been generated for this node. Set isResolved if not. * * @return True if node has already been resolved. */ public boolean testResolved() { if (isResolved()) { return true; } setIsResolved(true); return false; } /** * Reset the resolved flag. */ public void resetResolved() { setIsResolved(false); } /** * Is this a debug info node like LineNumberNode etc? * * @return true if this is a debug node */ public boolean isDebug() { return false; } /** * Helper class used for node cloning */ public static final class CopyState { private final IdentityHashMap<Node, Node> cloneMap = new IdentityHashMap<>(); /** * Find existing or create new copy of the node. * * @param node Node to copy. * * @return New object. */ public Node existingOrCopy(final Node node) { if (node != null) { Node copy = cloneMap.get(node); if (copy == null) { copy = node.copy(this); cloneMap.put(node, copy); } return copy; } return node; } /** * Find existing or use old copy of the node. * * @param node Node to copy. * * @return new object. */ public Node existingOrSame(final Node node) { if (node != null) { Node copy = cloneMap.get(node); if (copy == null) { copy = node; } return copy; } return node; } } /** * Deep copy the node. * * @return Deep copy of the Node. */ public final Node copy() { return copy(new CopyState()); } /** * Deep copy the node. * * @param cs CopyState passed around to re-use certain nodes. * @return Deep copy of the Node. */ protected Node copy(final CopyState cs) { return cs.existingOrCopy(this); } /** * Provides a means to navigate the IR. * @param visitor Node visitor. * @return node the node or its replacement after visitation, null if no further visitations are required */ public abstract Node accept(NodeVisitor visitor); @Override public String toString() { final StringBuilder sb = new StringBuilder(); toString(sb); return sb.toString(); } /** * String conversion helper. Fills a {@link StringBuilder} with the * string version of this node * * @param sb a StringBuilder */ public abstract void toString(StringBuilder sb); /** * Check if this node has terminal flags, i.e. ends or breaks control flow * * @return true if terminal */ public boolean hasTerminalFlags() { return isTerminal || hasGoto; } /** * Copy the terminal flags state of a node to another node * * @param other source node */ public void copyTerminalFlags(final Node other) { isTerminal = other.isTerminal; hasGoto = other.hasGoto; } /** * Check if the return value of this expression should be discarded * @return true if return value is discarded */ public boolean shouldDiscard() { return shouldDiscard; } /** * Setter that determines whether this node's return value should be discarded * or not * * @param shouldDiscard true if return value is discarded, false otherwise */ public void setDiscard(final boolean shouldDiscard) { this.shouldDiscard = shouldDiscard; } /** * Get the finish position for this node in the source string * @return finish */ public int getFinish() { return finish; } /** * Set finish position for this node in the source string * @param finish finish */ public void setFinish(final int finish) { this.finish = finish; } /** * Check if this function repositions control flow with goto like * semantics, for example {@link BreakNode} or a {@link ForNode} with no test * @return true if node has goto semantics */ public boolean hasGoto() { return hasGoto; } /** * Flag this node as having goto semantics as described in {@link Node#hasGoto()} */ public void setHasGoto() { this.hasGoto = true; } /** * Check whether this node is resolved, i.e. code has been generated for it * @return true if node is resolved */ public boolean isResolved() { return isResolved; } /** * Flag this node as resolved or not, i.e. code has been generated for it */ private void setIsResolved(boolean isResolved) { this.isResolved = isResolved; } /** * Get start position for node * @return start position */ public int getStart() { return start; } /** * Set start position for node * @param start start position */ public void setStart(final int start) { this.start = start; } /** * Return the Symbol the compiler has assigned to this Node. The symbol * is the place where it's expression value is stored after evaluation * * @return the symbol */ public Symbol getSymbol() { return symbol; } /** * Assign a symbol to this node. See {@link Node#getSymbol()} for explanation * of what a symbol is * * @param symbol the symbol */ public void setSymbol(final Symbol symbol) { this.symbol = symbol; } /** * Is this a terminal Node, i.e. does it end control flow like a throw or return * expression does? * * @return true if this node is terminal */ public boolean isTerminal() { return isTerminal; } /** * Set this to be a terminal node, i.e. it terminates control flow as described * in {@link Node#isTerminal()} * * @param isTerminal true if this is a terminal node, false otherwise */ public void setIsTerminal(final boolean isTerminal) { this.isTerminal = isTerminal; } }