Mon, 20 Oct 2014 12:06:36 +0200
8059844: Implement optimistic splitter
Reviewed-by: hannesw, lagergren
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 */
26 package jdk.nashorn.internal.ir;
28 import java.io.Serializable;
29 import java.util.ArrayList;
30 import java.util.List;
31 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
32 import jdk.nashorn.internal.parser.Token;
33 import jdk.nashorn.internal.parser.TokenType;
35 /**
36 * Nodes are used to compose Abstract Syntax Trees.
37 */
38 public abstract class Node implements Cloneable, Serializable {
39 private static final long serialVersionUID = 1L;
41 /** Constant used for synthetic AST nodes that have no line number. */
42 public static final int NO_LINE_NUMBER = -1;
44 /** Constant used for synthetic AST nodes that have no token. */
45 public static final long NO_TOKEN = 0L;
47 /** Constant used for synthetic AST nodes that have no finish. */
48 public static final int NO_FINISH = 0;
50 /** Start of source range. */
51 protected final int start;
53 /** End of source range. */
54 protected int finish;
56 /** Token descriptor. */
57 private final long token;
59 /**
60 * Constructor
61 *
62 * @param token token
63 * @param finish finish
64 */
65 public Node(final long token, final int finish) {
66 this.token = token;
67 this.start = Token.descPosition(token);
68 this.finish = finish;
69 }
71 /**
72 * Constructor
73 *
74 * @param token token
75 * @param start start
76 * @param finish finish
77 */
78 protected Node(final long token, final int start, final int finish) {
79 this.start = start;
80 this.finish = finish;
81 this.token = token;
82 }
84 /**
85 * Copy constructor
86 *
87 * @param node source node
88 */
89 protected Node(final Node node) {
90 this.token = node.token;
91 this.start = node.start;
92 this.finish = node.finish;
93 }
95 /**
96 * Is this a loop node?
97 *
98 * @return true if atom
99 */
100 public boolean isLoop() {
101 return false;
102 }
104 /**
105 * Is this an assignment node - for example a var node with an init
106 * or a binary node that writes to a destination
107 *
108 * @return true if assignment
109 */
110 public boolean isAssignment() {
111 return false;
112 }
114 /**
115 * For reference copies - ensure that labels in the copy node are unique
116 * using an appropriate copy constructor
117 * @param lc lexical context
118 * @return new node or same of no labels
119 */
120 public Node ensureUniqueLabels(final LexicalContext lc) {
121 return this;
122 }
124 /**
125 * Provides a means to navigate the IR.
126 * @param visitor Node visitor.
127 * @return node the node or its replacement after visitation, null if no further visitations are required
128 */
129 public abstract Node accept(NodeVisitor<? extends LexicalContext> visitor);
131 @Override
132 public String toString() {
133 final StringBuilder sb = new StringBuilder();
134 toString(sb);
135 return sb.toString();
136 }
138 /**
139 * String conversion helper. Fills a {@link StringBuilder} with the
140 * string version of this node
141 *
142 * @param sb a StringBuilder
143 */
144 public void toString(final StringBuilder sb) {
145 toString(sb, true);
146 }
148 /**
149 * Print logic that decides whether to show the optimistic type
150 * or not - for example it should not be printed after just parse,
151 * when it hasn't been computed, or has been set to a trivially provable
152 * value
153 * @param sb string builder
154 * @param printType print type?
155 */
156 public abstract void toString(final StringBuilder sb, final boolean printType);
158 /**
159 * Get the finish position for this node in the source string
160 * @return finish
161 */
162 public int getFinish() {
163 return finish;
164 }
166 /**
167 * Set finish position for this node in the source string
168 * @param finish finish
169 */
170 public void setFinish(final int finish) {
171 this.finish = finish;
172 }
174 /**
175 * Get start position for node
176 * @return start position
177 */
178 public int getStart() {
179 return start;
180 }
182 @Override
183 protected Object clone() {
184 try {
185 return super.clone();
186 } catch (final CloneNotSupportedException e) {
187 throw new AssertionError(e);
188 }
189 }
191 @Override
192 public final boolean equals(final Object other) {
193 return this == other;
194 }
196 @Override
197 public final int hashCode() {
198 // NOTE: we aren't delegating to Object.hashCode as it still requires trip to the VM for initializing,
199 // it touches the object header and/or stores the identity hashcode somewhere, etc. There's several
200 // places in the compiler pipeline that store nodes in maps, so this can get hot.
201 return Long.hashCode(token);
202 }
204 /**
205 * Return token position from a token descriptor.
206 *
207 * @return Start position of the token in the source.
208 */
209 public int position() {
210 return Token.descPosition(token);
211 }
213 /**
214 * Return token length from a token descriptor.
215 *
216 * @return Length of the token.
217 */
218 public int length() {
219 return Token.descLength(token);
220 }
222 /**
223 * Return token tokenType from a token descriptor.
224 *
225 * @return Type of token.
226 */
227 public TokenType tokenType() {
228 return Token.descType(token);
229 }
231 /**
232 * Test token tokenType.
233 *
234 * @param type a type to check this token against
235 * @return true if token types match.
236 */
237 public boolean isTokenType(final TokenType type) {
238 return Token.descType(token) == type;
239 }
241 /**
242 * Get the token for this location
243 * @return the token
244 */
245 public long getToken() {
246 return token;
247 }
249 //on change, we have to replace the entire list, that's we can't simple do ListIterator.set
250 static <T extends Node> List<T> accept(final NodeVisitor<? extends LexicalContext> visitor, final List<T> list) {
251 final int size = list.size();
252 if (size == 0) {
253 return list;
254 }
256 List<T> newList = null;
258 for (int i = 0; i < size; i++) {
259 final T node = list.get(i);
260 @SuppressWarnings("unchecked")
261 final T newNode = node == null ? null : (T)node.accept(visitor);
262 if (newNode != node) {
263 if (newList == null) {
264 newList = new ArrayList<>(size);
265 for (int j = 0; j < i; j++) {
266 newList.add(list.get(j));
267 }
268 }
269 newList.add(newNode);
270 } else {
271 if (newList != null) {
272 newList.add(node);
273 }
274 }
275 }
277 return newList == null ? list : newList;
278 }
280 static <T extends LexicalContextNode> T replaceInLexicalContext(final LexicalContext lc, final T oldNode, final T newNode) {
281 if (lc != null) {
282 lc.replace(oldNode, newNode);
283 }
284 return newNode;
285 }
286 }