comparison graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java @ 5061:e808627bd16f

Renamed projects.
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Thu, 08 Mar 2012 19:24:17 +0100
parents graal/com.oracle.max.graal.graph/src/com/oracle/graal/graph/Node.java@4ed4295ce15f
children 3ac351ed7270
comparison
equal deleted inserted replaced
5060:4ed4295ce15f 5061:e808627bd16f
1 /*
2 * Copyright (c) 2011, 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.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23 package com.oracle.graal.graph;
24
25 import java.lang.annotation.*;
26 import java.util.*;
27
28 import com.oracle.graal.graph.NodeClass.*;
29
30
31 /**
32 * This class is the base class for all nodes, it represent a node which can be inserted in a {@link Graph}.<br>
33 * Once a node has been added to a graph, it has a graph-unique {@link #id()}. Edges in the subclasses are represented
34 * with annotated fields. There are two kind of edges : {@link Input} and {@link Successor}. If a field, of a type
35 * compatible with {@link Node}, annotated with either {@link Input} and {@link Successor} is not null, then there is an
36 * edge from this node to the node this field points to.<br>
37 * Fields in a node subclass can also be annotated with {@link Data} : such fields will be used when comparing 2 nodes
38 * with {@link #equals(Object)}, for value numbering and for debugging purposes.<br>
39 * Nodes which are be value numberable should implement the {@link ValueNumberable} interface.
40 *
41 * <h1>Assertions and Verification</h1>
42 *
43 * The Node class supplies the {@link #assertTrue(boolean, String, Object...)} and
44 * {@link #assertFalse(boolean, String, Object...)} methods, which will check the supplied boolean and throw a
45 * VerificationError if it has the wrong value. Both methods will always either throw an exception or return true.
46 * They can thus be used within an assert statement, so that the check is only performed if assertions are enabled.
47 *
48 *
49 */
50 public abstract class Node implements Cloneable, Formattable {
51
52 static final int DELETED_ID_START = -1000000000;
53 static final int INITIAL_ID = -1;
54 static final int ALIVE_ID_START = 0;
55
56 @Retention(RetentionPolicy.RUNTIME)
57 @Target(ElementType.FIELD)
58 public static @interface Input {
59 boolean notDataflow() default false;
60 }
61
62 @Retention(RetentionPolicy.RUNTIME)
63 @Target(ElementType.FIELD)
64 public static @interface Successor {}
65
66 @Retention(RetentionPolicy.RUNTIME)
67 @Target(ElementType.FIELD)
68 public static @interface Data {}
69
70 /**
71 * Denotes that a parameter of an {@linkplain NodeIntrinsic intrinsic} method
72 * must be a compile time constant at all call sites to the intrinic method.
73 */
74 @Retention(RetentionPolicy.RUNTIME)
75 @Target(ElementType.PARAMETER)
76 public static @interface ConstantNodeParameter {}
77
78 /**
79 * Annotates a method that can be replaced by a compiler intrinsic.
80 * That is, a (resolved) call to the annotated method can be replaced
81 * with an instance of the node class denoted by {@link #value()}.
82 * For this reason, the signature of the annotated method must match
83 * the signature of a constructor in the node class.
84 */
85 @Retention(RetentionPolicy.RUNTIME)
86 @Target(ElementType.METHOD)
87 public static @interface NodeIntrinsic {
88 /**
89 * Gets the {@link Node} subclass instantiated when intrinsifying a call to the annotated method.
90 * If not specified, then the class in which the annotated method is declared is used
91 * (and is assumed to be a {@link Node} subclass).
92 */
93 Class value() default NodeIntrinsic.class;
94 }
95
96 @Retention(RetentionPolicy.RUNTIME)
97 @Target(ElementType.METHOD)
98 public static @interface NodePhase {
99 Class value() default NodePhase.class;
100 }
101
102 public interface ValueNumberable {}
103
104 public interface IterableNodeType {}
105
106 private Graph graph;
107 int id;
108
109 // this next pointer is used in Graph to implement fast iteration over NodeClass types, it therefore points to the next Node of the same type.
110 Node typeCacheNext;
111
112 private NodeUsagesList usages;
113 private Node predecessor;
114 private int modCount;
115 private NodeClass nodeClass;
116
117 public Node() {
118 this.graph = null;
119 this.id = INITIAL_ID;
120 nodeClass = NodeClass.get(getClass());
121 }
122
123 protected int id() {
124 return id;
125 }
126
127 public Graph graph() {
128 return graph;
129 }
130
131 /**
132 * Returns an {@link NodeInputsIterable iterable} which can be used to traverse all non-null input edges of this node.
133 * @return an {@link NodeInputsIterable iterable} for all non-null input edges.
134 */
135 public NodeInputsIterable inputs() {
136 return getNodeClass().getInputIterable(this);
137 }
138
139 /**
140 * Returns an {@link NodeSuccessorsIterable iterable} which can be used to traverse all non-null successor edges of this node.
141 * @return an {@link NodeSuccessorsIterable iterable} for all non-null successor edges.
142 */
143 public NodeSuccessorsIterable successors() {
144 return getNodeClass().getSuccessorIterable(this);
145 }
146
147 public final NodeUsagesList usages() {
148 return usages;
149 }
150
151 public final Node predecessor() {
152 return predecessor;
153 }
154
155 final int modCount() {
156 return modCount;
157 }
158
159 final void incModCount() {
160 modCount++;
161 }
162
163 public boolean isDeleted() {
164 return id <= DELETED_ID_START;
165 }
166
167 public boolean isAlive() {
168 return id >= ALIVE_ID_START;
169 }
170
171 /**
172 * Updates the usages sets of the given nodes after an input slot is changed from oldInput to newInput:
173 * removes this node from oldInput's usages and adds this node to newInput's usages.
174 */
175 protected void updateUsages(Node oldInput, Node newInput) {
176 assert assertTrue(usages != null, "usages == null while adding %s to %s", newInput, this);
177 if (oldInput != newInput) {
178 if (oldInput != null) {
179 boolean result = removeThisFromUsages(oldInput);
180 assert assertTrue(result, "not found in usages, old input: %s", oldInput);
181 }
182 if (newInput != null) {
183 NodeWorkList inputChanged = graph.inputChanged;
184 if (inputChanged != null) {
185 inputChanged.addAgain(this);
186 }
187 newInput.usages.add(this);
188 }
189 }
190 }
191
192 /**
193 * Updates the predecessor sets of the given nodes after a successor slot is changed from oldSuccessor to newSuccessor:
194 * removes this node from oldSuccessor's predecessors and adds this node to newSuccessor's predecessors.
195 */
196 protected void updatePredecessors(Node oldSuccessor, Node newSuccessor) {
197 assert assertTrue(usages != null, "usages == null while adding %s to %s", newSuccessor, this);
198 if (oldSuccessor != newSuccessor) {
199 if (oldSuccessor != null) {
200 assert assertTrue(oldSuccessor.predecessor == this, "wrong predecessor in old successor (%s): %s", oldSuccessor, oldSuccessor.predecessor);
201 oldSuccessor.predecessor = null;
202 }
203 if (newSuccessor != null) {
204 assert assertTrue(newSuccessor.predecessor == null, "unexpected non-null predecessor in new successor (%s): %s", newSuccessor, newSuccessor.predecessor);
205 newSuccessor.predecessor = this;
206 }
207 }
208 }
209
210 void initialize(Graph newGraph) {
211 assert assertTrue(id == INITIAL_ID, "unexpected id: %d", id);
212 this.graph = newGraph;
213 newGraph.register(this);
214 usages = new NodeUsagesList();
215 for (Node input : inputs()) {
216 updateUsages(null, input);
217 }
218 for (Node successor : successors()) {
219 updatePredecessors(null, successor);
220 }
221 }
222
223 public final NodeClass getNodeClass() {
224 return nodeClass;
225 }
226
227 // TODO (thomaswue): Do not allow to replace with null.
228 private boolean checkReplaceWith(Node other) {
229 assert assertFalse(other == this, "cannot replace a node with itself");
230 assert assertFalse(isDeleted(), "cannot replace deleted node");
231 // assert assertTrue(other != null, "cannot replace with null node");
232 assert assertTrue(other == null || !other.isDeleted(), "cannot replace with deleted node %s", other);
233 assert assertTrue(other == null || other.graph() == graph, "cannot replace with node in different graph: %s", other == null ? null : other.graph());
234 return true;
235 }
236
237 public void replaceAtUsages(Node other) {
238 assert checkReplaceWith(other);
239 for (Node usage : usages) {
240 boolean result = usage.getNodeClass().replaceFirstInput(usage, this, other);
241 assert assertTrue(result, "not found in inputs, usage: %s", usage);
242 if (other != null) {
243 other.usages.add(usage);
244 }
245 }
246 usages.clear();
247 }
248
249 public void replaceAtPredecessors(Node other) {
250 assert checkReplaceWith(other);
251 if (predecessor != null) {
252 boolean result = predecessor.getNodeClass().replaceFirstSuccessor(predecessor, this, other);
253 assert assertTrue(result, "not found in successors, predecessor: %s", predecessor);
254 predecessor.updatePredecessors(this, other);
255 }
256 }
257
258 public void replaceAndDelete(Node other) {
259 assert checkReplaceWith(other);
260 if (other != null) {
261 clearSuccessors();
262 replaceAtUsages(other);
263 replaceAtPredecessors(other);
264 }
265 safeDelete();
266 }
267
268 public void replaceFirstSuccessor(Node oldSuccessor, Node newSuccessor) {
269 if (getNodeClass().replaceFirstSuccessor(this, oldSuccessor, newSuccessor)) {
270 updatePredecessors(oldSuccessor, newSuccessor);
271 }
272 }
273
274 public void replaceFirstInput(Node oldInput, Node newInput) {
275 if (getNodeClass().replaceFirstInput(this, oldInput, newInput)) {
276 updateUsages(oldInput, newInput);
277 }
278 }
279
280 public void clearInputs() {
281 assert assertFalse(isDeleted(), "cannot clear inputs of deleted node");
282
283 for (Node input : inputs()) {
284 removeThisFromUsages(input);
285 }
286 getNodeClass().clearInputs(this);
287 }
288
289 private boolean removeThisFromUsages(Node n) {
290 if (n.usages.remove(this)) {
291 if (n.usages.size() == 0) {
292 graph.usagesDropped.add(n);
293 }
294 return true;
295 } else {
296 return false;
297 }
298 }
299
300 public void clearSuccessors() {
301 assert assertFalse(isDeleted(), "cannot clear successors of deleted node");
302
303 for (Node successor : successors()) {
304 assert assertTrue(successor.predecessor == this, "wrong predecessor in old successor (%s): %s", successor, successor.predecessor);
305 successor.predecessor = null;
306 }
307 getNodeClass().clearSuccessors(this);
308 }
309
310 private boolean checkDeletion() {
311 assertTrue(usages.isEmpty(), "cannot delete node %s because of usages: %s", this, usages);
312 assertTrue(predecessor == null, "cannot delete node %s because of predecessor: %s", this, predecessor);
313 return true;
314 }
315
316 public void safeDelete() {
317 assert checkDeletion();
318 clearInputs();
319 clearSuccessors();
320 graph.unregister(this);
321 id = DELETED_ID_START - id;
322 assert isDeleted();
323 }
324
325 public final Node copyWithInputs() {
326 Node newNode = clone(graph);
327 NodeClass clazz = getNodeClass();
328 clazz.copyInputs(this, newNode);
329 for (Node input : inputs()) {
330 input.usages.add(newNode);
331 }
332 return newNode;
333 }
334
335 public Node clone(Graph into) {
336 Node newNode = null;
337 try {
338 newNode = (Node) this.clone();
339 } catch (CloneNotSupportedException e) {
340 throw new GraalInternalError(e).addContext(this);
341 }
342 getNodeClass().clearInputs(newNode);
343 getNodeClass().clearSuccessors(newNode);
344 newNode.graph = into;
345 newNode.typeCacheNext = null;
346 newNode.id = INITIAL_ID;
347 into.register(newNode);
348 newNode.usages = new NodeUsagesList();
349 newNode.predecessor = null;
350 newNode.modCount = 0;
351 return newNode;
352 }
353
354 public boolean verify() {
355 assertTrue(isAlive(), "cannot verify inactive nodes (id=%d)", id);
356 assertTrue(graph() != null, "null graph");
357 for (Node input : inputs()) {
358 assertTrue(input.usages().contains(this), "missing usage in input %s", input);
359 assertTrue(input.graph() == graph(), "mismatching graph in input %s", input);
360 }
361 for (Node successor : successors()) {
362 assertTrue(successor.predecessor() == this, "missing predecessor in %s (actual: %s)", successor, successor.predecessor());
363 assertTrue(successor.graph() == graph(), "mismatching graph in successor %s", successor);
364 }
365 for (Node usage : usages()) {
366 assertFalse(usage.isDeleted(), "usage must never be deleted");
367 assertTrue(usage.inputs().contains(this), "missing input in usage %s", usage);
368 }
369 if (predecessor != null) {
370 assertFalse(predecessor.isDeleted(), "predecessor must never be deleted");
371 assertTrue(predecessor.successors().contains(this), "missing successor in predecessor %s", predecessor);
372 }
373 return true;
374 }
375
376 public boolean assertTrue(boolean condition, String message, Object... args) {
377 if (condition) {
378 return true;
379 } else {
380 throw new VerificationError(message, args).addContext(this);
381 }
382 }
383
384 public boolean assertFalse(boolean condition, String message, Object... args) {
385 if (condition) {
386 throw new VerificationError(message, args).addContext(this);
387 } else {
388 return true;
389 }
390 }
391
392 public Iterable<? extends Node> cfgPredecessors() {
393 if (predecessor == null) {
394 return Collections.emptySet();
395 } else {
396 return Collections.singleton(predecessor);
397 }
398 }
399
400 /**
401 * Returns an iterator that will provide all control-flow successors of this node. Normally this will be the contents of all fields marked as NodeSuccessor,
402 * but some node classes (like EndNode) may return different nodes.
403 * Note that the iterator may generate null values if the fields contain them.
404 */
405 public Iterable<? extends Node> cfgSuccessors() {
406 return successors();
407 }
408
409 /**
410 * hashCode and equals should always rely on object identity alone, thus hashCode and equals are final.
411 */
412 @Override
413 public final int hashCode() {
414 return super.hashCode();
415 }
416
417 /**
418 * hashCode and equals should always rely on object identity alone, thus hashCode and equals are final.
419 */
420 @Override
421 public final boolean equals(Object obj) {
422 return super.equals(obj);
423 }
424
425 /**
426 * Provides a {@link Map} of properties of this node for use in debugging (e.g., to view in the ideal graph
427 * visualizer). Subclasses overriding this method should add to the map returned by their superclass.
428 */
429 public Map<Object, Object> getDebugProperties() {
430 Map<Object, Object> map = new HashMap<>();
431 map.put("usageCount", usages.size());
432 map.put("predecessorCount", predecessor == null ? 0 : 1);
433 getNodeClass().getDebugProperties(this, map);
434 return map;
435 }
436
437 /**
438 * This method is a shortcut for {@link #toString(Verbosity)} with {@link Verbosity#Short}.
439 */
440 @Override
441 public final String toString() {
442 return toString(Verbosity.Short);
443 }
444
445 public enum Verbosity {
446 /**
447 * Only the id of the node.
448 */
449 Id,
450 /**
451 * Only the name of the node, which may contain some more information for certain node types (constants, ...).
452 */
453 Name,
454 /**
455 * {@link #Id} + {@link #Name}.
456 */
457 Short,
458 /**
459 * Defaults to {@link #Short} and may be enhanced by subclasses.
460 */
461 Long,
462 /**
463 * For use by a custom formatting facility in an IDE.
464 */
465 Debugger,
466 /**
467 * All the other information plus all debug properties of the node.
468 */
469 All
470 }
471
472 /**
473 * Creates a String representation for this node with a given {@link Verbosity}.
474 */
475 public String toString(Verbosity verbosity) {
476 switch (verbosity) {
477 case Id:
478 return Integer.toString(id);
479 case Name:
480 return getNodeClass().shortName();
481 case Short:
482 return toString(Verbosity.Id) + "|" + toString(Verbosity.Name);
483 case Long:
484 return toString(Verbosity.Short);
485 case Debugger:
486 case All: {
487 StringBuilder str = new StringBuilder();
488 str.append(toString(Verbosity.Short)).append(" { ");
489 for (Map.Entry<Object, Object> entry : getDebugProperties().entrySet()) {
490 str.append(entry.getKey()).append("=").append(entry.getValue()).append(", ");
491 }
492 str.append(" }");
493 return str.toString();
494 }
495 default:
496 throw new RuntimeException("unknown verbosity: " + verbosity);
497 }
498 }
499
500 @Override
501 public void formatTo(Formatter formatter, int flags, int width, int precision) {
502 if ((flags & FormattableFlags.ALTERNATE) == FormattableFlags.ALTERNATE) {
503 formatter.format("%s", toString(Verbosity.Id));
504 } else if ((flags & FormattableFlags.UPPERCASE) == FormattableFlags.UPPERCASE) {
505 formatter.format("%s", toString(Verbosity.Long));
506 } else {
507 formatter.format("%s", toString(Verbosity.Short));
508 }
509
510 boolean neighborsAlternate = ((flags & FormattableFlags.LEFT_JUSTIFY) == FormattableFlags.LEFT_JUSTIFY);
511 int neighborsFlags = (neighborsAlternate ? FormattableFlags.ALTERNATE | FormattableFlags.LEFT_JUSTIFY : 0);
512 if (width > 0) {
513 if (this.predecessor != null) {
514 formatter.format(" pred={");
515 this.predecessor.formatTo(formatter, neighborsFlags, width - 1, 0);
516 formatter.format("}");
517 }
518
519 NodeClassIterator inputIter = inputs().iterator();
520 while (inputIter.hasNext()) {
521 Position position = inputIter.nextPosition();
522 Node input = getNodeClass().get(this, position);
523 if (input != null) {
524 formatter.format(" ");
525 formatter.format(getNodeClass().getName(position));
526 formatter.format("={");
527 input.formatTo(formatter, neighborsFlags, width - 1, 0);
528 formatter.format("}");
529 }
530 }
531 }
532
533 if (precision > 0) {
534 if (this.usages.size() > 0) {
535 formatter.format(" usages={");
536 int z = 0;
537 for (Node usage : this.usages) {
538 if (z != 0) {
539 formatter.format(", ");
540 }
541 usage.formatTo(formatter, neighborsFlags, 0, precision - 1);
542 ++z;
543 }
544 formatter.format("}");
545 }
546
547 NodeClassIterator succIter = successors().iterator();
548 while (succIter.hasNext()) {
549 Position position = succIter.nextPosition();
550 Node successor = getNodeClass().get(this, position);
551 if (successor != null) {
552 formatter.format(" ");
553 formatter.format(getNodeClass().getName(position));
554 formatter.format("={");
555 successor.formatTo(formatter, neighborsFlags, 0, precision - 1);
556 formatter.format("}");
557 }
558 }
559 }
560 }
561 }