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

Fri, 21 Dec 2012 16:36:24 -0400

author
jlaskey
date
Fri, 21 Dec 2012 16:36:24 -0400
changeset 3
da1e581c933b
child 7
5a1b0714df0e
permissions
-rw-r--r--

8005403: Open-source Nashorn
Reviewed-by: attila, hannesw, lagergren, sundar
Contributed-by: james.laskey@oracle.com, akhil.arora@oracle.com, andreas.woess@jku.at, attila.szegedi@oracle.com, hannes.wallnoefer@oracle.com, henry.jen@oracle.com, marcus.lagergren@oracle.com, pavel.semenov@oracle.com, pavel.stepanov@oracle.com, petr.hejl@oracle.com, petr.pisl@oracle.com, sundararajan.athijegannathan@oracle.com

     1 /*
     2  * Copyright (c) 2010, 2012, 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  */
    26 package jdk.nashorn.internal.ir;
    28 import java.util.IdentityHashMap;
    29 import java.util.List;
    30 import jdk.nashorn.internal.codegen.types.Type;
    31 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
    32 import jdk.nashorn.internal.parser.Token;
    33 import jdk.nashorn.internal.runtime.Source;
    35 /**
    36  * Nodes are used to compose Abstract Syntax Trees.
    37  *
    38  */
    39 public abstract class Node extends Location {
    40     /** Node symbol. */
    41     private Symbol nodeSymbol;
    43     /** Start of source range. */
    44     protected int start;
    46     /** End of source range. */
    47     protected int finish;
    49     /** Has this node been resolved - i.e. emitted code already */
    50     private boolean isResolved;
    52     /** Is this node terminal */
    53     private boolean isTerminal;
    55     /** Is this a goto node */
    56     private boolean hasGoto;
    58     /** Is this a discard */
    59     private boolean shouldDiscard;
    61     /**
    62      * Constructor
    63      *
    64      * @param source the source
    65      * @param token  token
    66      * @param finish finish
    67      */
    68     public Node(final Source source, final long token, final int finish) {
    69         super(source, token);
    71         start  = Token.descPosition(token);
    72         this.finish = finish;
    73     }
    75     /**
    76      * Copy constructor
    77      *
    78      * @param node source node
    79      */
    80     protected Node(final Node node) {
    81         super(node);
    83         this.nodeSymbol    = node.nodeSymbol;
    84         this.isResolved    = node.isResolved;
    85         this.isTerminal    = node.isTerminal;
    86         this.hasGoto       = node.hasGoto;
    87         this.shouldDiscard = node.shouldDiscard;
    88         this.start         = node.start;
    89         this.finish        = node.finish;
    90     }
    92     /**
    93      * Check if the node has a type. The default behavior is to go into the symbol
    94      * and check the symbol type, but there may be overrides, for example in
    95      * getters that require a different type than the internal representation
    96      *
    97      * @return true if a type exists
    98      */
    99     public boolean hasType() {
   100         return getSymbol() != null;
   101     }
   103     /**
   104      * Returns the type of the node. Typically this is the symbol type. No types
   105      * are stored in the node itself, unless it implements TypeOverride
   106      *
   107      * @return the type of the node.
   108      */
   109     public Type getType() {
   110         assert hasType();
   111         return nodeSymbol.getSymbolType();
   112     }
   114     /**
   115      * Is this an atom node - for example a literal or an identity
   116      *
   117      * @return true if atom
   118      */
   119     public boolean isAtom() {
   120         return false;
   121     }
   123     /**
   124      * Is this a loop node?
   125      *
   126      * @return true if atom
   127      */
   128     public boolean isLoop() {
   129         return false;
   130     }
   132     /**
   133      * Is this an assignment node - for example a var node with an init
   134      * or a binary node that writes to a destination
   135      *
   136      * @return true if assignment
   137      */
   138     public boolean isAssignment() {
   139         return false;
   140     }
   142     /**
   143      * Is this a self modifying assignment?
   144      * @return true if self modifying, e.g. a++, or a*= 17
   145      */
   146     public boolean isSelfModifying() {
   147         return false;
   148     }
   150     /**
   151      * Returns widest operation type of this operation.
   152      *
   153      * @return the widest type for this operation
   154      */
   155     public Type getWidestOperationType() {
   156         return Type.OBJECT;
   157     }
   159     /**
   160      * Test to see if code been generated for this node. Set isResolved if not.
   161      *
   162      * @return True if node has already been resolved.
   163      */
   164     public boolean testResolved() {
   165         if (isResolved()) {
   166             return true;
   167         }
   169         setIsResolved();
   171         return false;
   172     }
   174     /**
   175      * Is this a debug info node like LineNumberNode etc?
   176      *
   177      * @return true if this is a debug node
   178      */
   179     public boolean isDebug() {
   180         return false;
   181     }
   183     /**
   184      * Helper class used for node cloning
   185      */
   186     public static final class CopyState {
   187         private final IdentityHashMap<Node, Node> cloneMap = new IdentityHashMap<>();
   189         /**
   190          * Find existing or create new copy of the node.
   191          *
   192          * @param node Node to copy.
   193          *
   194          * @return New object.
   195          */
   196         public Node existingOrCopy(final Node node) {
   197             if (node != null) {
   198                 Node copy = cloneMap.get(node);
   200                 if (copy == null) {
   201                     copy = node.copy(this);
   202                     cloneMap.put(node, copy);
   203                 }
   205                 return copy;
   206             }
   208             return node;
   209         }
   211         /**
   212          * Find existing or use old copy of the node.
   213          *
   214          * @param node Node to copy.
   215          *
   216          * @return new object.
   217          */
   218         public Node existingOrSame(final Node node) {
   219             if (node != null) {
   220                 Node copy = cloneMap.get(node);
   222                 if (copy == null) {
   223                     copy = node;
   224                 }
   226                 return copy;
   227             }
   229             return node;
   230         }
   231     }
   233     /**
   234      * Deep copy the node.
   235      *
   236      * @return Deep copy of the  Node.
   237      */
   238     @Override
   239     public final Node clone() {
   240         return copy(new CopyState());
   241     }
   243     /**
   244      * Deep copy the node.
   245      *
   246      * @param cs CopyState passed around to re-use certain nodes.
   247      * @return Deep copy of the  Node.
   248      */
   249     protected Node copy(final CopyState cs) {
   250         return cs.existingOrCopy(this);
   251     }
   253     /**
   254      * Provides a means to navigate the IR.
   255      * @param visitor Node visitor.
   256      * @return node the node or its replacement after visitation, null if no further visitations are required
   257      */
   258     public abstract Node accept(NodeVisitor visitor);
   260     @Override
   261     public String toString() {
   262         final StringBuilder sb = new StringBuilder();
   263         toString(sb);
   264         return sb.toString();
   265     }
   267     /**
   268      * String conversion helper. Fills a {@link StringBuilder} with the
   269      * string version of this node
   270      *
   271      * @param sb a StringBuilder
   272      */
   273     public abstract void toString(StringBuilder sb);
   275     /**
   276      * Check if this node has terminal flags, i.e. ends or breaks control flow
   277      *
   278      * @return true if terminal
   279      */
   280     public boolean hasTerminalFlags() {
   281         return isTerminal || hasGoto;
   282     }
   284     /**
   285      * Copy the terminal flags state of a node to another node
   286      *
   287      * @param other source node
   288      */
   289     public void copyTerminalFlags(final Node other) {
   290         isTerminal = other.isTerminal;
   291         hasGoto    = other.hasGoto;
   292     }
   294     /**
   295      * Check if the return value of this expression should be discarded
   296      * @return true if return value is discarded
   297      */
   298     public boolean shouldDiscard() {
   299         return shouldDiscard;
   300     }
   302     /**
   303      * Setter that determines whether this node's return value should be discarded
   304      * or not
   305      *
   306      * @param shouldDiscard true if return value is discarded, false otherwise
   307      */
   308     public void setDiscard(final boolean shouldDiscard) {
   309         this.shouldDiscard = shouldDiscard;
   310     }
   312     /**
   313      * Get the finish position for this node in the source string
   314      * @return finish
   315      */
   316     public int getFinish() {
   317         return finish;
   318     }
   320     /**
   321      * Set finish position for this node in the source string
   322      * @param finish finish
   323      */
   324     public void setFinish(final int finish) {
   325         this.finish = finish;
   326     }
   328     /**
   329      * Check if this function repositions control flow with goto like
   330      * semantics, for example {@link BreakNode} or a {@link ForNode} with no test
   331      * @return true if node has goto semantics
   332      */
   333     public boolean hasGoto() {
   334         return hasGoto;
   335     }
   337     /**
   338      * Flag this node as having goto semantics as described in {@link Node#hasGoto()}
   339      */
   340     public void setHasGoto() {
   341         this.hasGoto = true;
   342     }
   344     /**
   345      * Check whether this node is resolved, i.e. code has been generated for it
   346      * @return true if node is resolved
   347      */
   348     public boolean isResolved() {
   349         return isResolved;
   350     }
   352     /**
   353      * Flag this node as resolved, i.e. code has been generated for it
   354      */
   355     public void setIsResolved() {
   356         this.isResolved = true;
   357     }
   359     /**
   360      * Get start position for node
   361      * @return start position
   362      */
   363     public int getStart() {
   364         return start;
   365     }
   367     /**
   368      * Set start position for node
   369      * @param start start position
   370      */
   371     public void setStart(final int start) {
   372         this.start = start;
   373     }
   375     /**
   376      * Return the Symbol the compiler has assigned to this Node. The symbol
   377      * is the place where it's expression value is stored after evaluation
   378      *
   379      * @return the symbol
   380      */
   381     public Symbol getSymbol() {
   382         return nodeSymbol;
   383     }
   385     /**
   386      * Assign a symbol to this node. See {@link Node#getSymbol()} for explanation
   387      * of what a symbol is
   388      *
   389      * @param symbol the symbol
   390      */
   391     public void setSymbol(final Symbol symbol) {
   392         nodeSymbol = symbol;
   393     }
   395     /**
   396      * Is this a terminal Node, i.e. does it end control flow like a throw or return
   397      * expression does?
   398      *
   399      * @return true if this node is terminal
   400      */
   401     public boolean isTerminal() {
   402         return isTerminal;
   403     }
   405     /**
   406      * Set this to be a terminal node, i.e. it terminates control flow as described
   407      * in {@link Node#isTerminal()}
   408      *
   409      * @param isTerminal true if this is a terminal node, false otherwise
   410      */
   411     public void setIsTerminal(final boolean isTerminal) {
   412         this.isTerminal = isTerminal;
   413     }
   415     /**
   416      * Return last node in a statement list.
   417      *
   418      * @param statements Statement list.
   419      *
   420      * @return Last (non-debug) statement or null if empty block.
   421      */
   422     public static Node lastStatement(final List<Node> statements) {
   423         for (int lastIndex = statements.size() - 1; lastIndex >= 0; lastIndex--) {
   424             final Node node = statements.get(lastIndex);
   425             if (!node.isDebug()) {
   426                 return node;
   427             }
   428         }
   430         return null;
   431     }
   432 }

mercurial