comparison truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java @ 21951:9c8c0937da41

Moving all sources into truffle subdirectory
author Jaroslav Tulach <jaroslav.tulach@oracle.com>
date Wed, 17 Jun 2015 10:58:08 +0200
parents graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java@f4cd6b1c2efc
children 5023b913e2ba
comparison
equal deleted inserted replaced
21950:2a5011c7e641 21951:9c8c0937da41
1 /*
2 * Copyright (c) 2012, 2015, 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 */
25 package com.oracle.truffle.api.nodes;
26
27 import java.io.*;
28 import java.lang.annotation.*;
29 import java.lang.reflect.*;
30 import java.util.*;
31
32 import sun.misc.*;
33
34 import com.oracle.truffle.api.*;
35 import com.oracle.truffle.api.instrument.*;
36 import com.oracle.truffle.api.instrument.ProbeNode.WrapperNode;
37 import com.oracle.truffle.api.nodes.NodeFieldAccessor.NodeFieldKind;
38 import com.oracle.truffle.api.source.*;
39
40 /**
41 * Utility class that manages the special access methods for node instances.
42 */
43 public final class NodeUtil {
44
45 /**
46 * Interface that allows the customization of field offsets used for {@link Unsafe} field
47 * accesses.
48 */
49 public interface FieldOffsetProvider {
50
51 long objectFieldOffset(Field field);
52
53 int getTypeSize(Class<?> clazz);
54 }
55
56 static Iterator<Node> makeIterator(Node node) {
57 return node.getNodeClass().makeIterator(node);
58 }
59
60 public static Iterator<Node> makeRecursiveIterator(Node node) {
61 return new RecursiveNodeIterator(node);
62 }
63
64 private static final class RecursiveNodeIterator implements Iterator<Node> {
65 private final List<Iterator<Node>> iteratorStack = new ArrayList<>();
66
67 public RecursiveNodeIterator(final Node node) {
68 iteratorStack.add(new Iterator<Node>() {
69
70 private boolean visited;
71
72 public void remove() {
73 throw new UnsupportedOperationException();
74 }
75
76 public Node next() {
77 if (visited) {
78 throw new NoSuchElementException();
79 }
80 visited = true;
81 return node;
82 }
83
84 public boolean hasNext() {
85 return !visited;
86 }
87 });
88 }
89
90 public boolean hasNext() {
91 return peekIterator() != null;
92 }
93
94 public Node next() {
95 Iterator<Node> iterator = peekIterator();
96 if (iterator == null) {
97 throw new NoSuchElementException();
98 }
99
100 Node node = iterator.next();
101 if (node != null) {
102 Iterator<Node> childIterator = makeIterator(node);
103 if (childIterator.hasNext()) {
104 iteratorStack.add(childIterator);
105 }
106 }
107 return node;
108 }
109
110 private Iterator<Node> peekIterator() {
111 int tos = iteratorStack.size() - 1;
112 while (tos >= 0) {
113 Iterator<Node> iterable = iteratorStack.get(tos);
114 if (iterable.hasNext()) {
115 return iterable;
116 } else {
117 iteratorStack.remove(tos--);
118 }
119 }
120 return null;
121 }
122
123 public void remove() {
124 throw new UnsupportedOperationException();
125 }
126 }
127
128 @SuppressWarnings("unchecked")
129 public static <T extends Node> T cloneNode(T orig) {
130 return (T) orig.deepCopy();
131 }
132
133 static Node deepCopyImpl(Node orig) {
134 final Node clone = orig.copy();
135 NodeClass nodeClass = clone.getNodeClass();
136
137 nodeClass.getParentField().putObject(clone, null);
138
139 for (NodeFieldAccessor childField : nodeClass.getChildFields()) {
140 Node child = (Node) childField.getObject(orig);
141 if (child != null) {
142 Node clonedChild = child.deepCopy();
143 nodeClass.getParentField().putObject(clonedChild, clone);
144 childField.putObject(clone, clonedChild);
145 }
146 }
147 for (NodeFieldAccessor childrenField : nodeClass.getChildrenFields()) {
148 Object[] children = (Object[]) childrenField.getObject(orig);
149 if (children != null) {
150 Object[] clonedChildren = (Object[]) Array.newInstance(children.getClass().getComponentType(), children.length);
151 for (int i = 0; i < children.length; i++) {
152 if (children[i] != null) {
153 Node clonedChild = ((Node) children[i]).deepCopy();
154 clonedChildren[i] = clonedChild;
155 nodeClass.getParentField().putObject(clonedChild, clone);
156 }
157 }
158 childrenField.putObject(clone, clonedChildren);
159 }
160 }
161 for (NodeFieldAccessor cloneableField : nodeClass.getCloneableFields()) {
162 Object cloneable = cloneableField.getObject(clone);
163 if (cloneable != null && cloneable == cloneableField.getObject(orig)) {
164 cloneableField.putObject(clone, ((NodeCloneable) cloneable).clone());
165 }
166 }
167 return clone;
168 }
169
170 public static List<Node> findNodeChildren(Node node) {
171 List<Node> nodes = new ArrayList<>();
172 NodeClass nodeClass = node.getNodeClass();
173
174 for (NodeFieldAccessor nodeField : nodeClass.getChildFields()) {
175 Object child = nodeField.getObject(node);
176 if (child != null) {
177 nodes.add((Node) child);
178 }
179 }
180 for (NodeFieldAccessor nodeField : nodeClass.getChildrenFields()) {
181 Object[] children = (Object[]) nodeField.getObject(node);
182 if (children != null) {
183 for (Object child : children) {
184 if (child != null) {
185 nodes.add((Node) child);
186 }
187 }
188 }
189 }
190
191 return nodes;
192 }
193
194 public static <T extends Node> T nonAtomicReplace(Node oldNode, T newNode, CharSequence reason) {
195 oldNode.replaceHelper(newNode, reason);
196 return newNode;
197 }
198
199 public static boolean replaceChild(Node parent, Node oldChild, Node newChild) {
200 NodeClass nodeClass = parent.getNodeClass();
201
202 for (NodeFieldAccessor nodeField : nodeClass.getChildFields()) {
203 if (nodeField.getObject(parent) == oldChild) {
204 assert assertAssignable(nodeField, newChild);
205 nodeField.putObject(parent, newChild);
206 return true;
207 }
208 }
209
210 for (NodeFieldAccessor nodeField : nodeClass.getChildrenFields()) {
211 Object arrayObject = nodeField.getObject(parent);
212 if (arrayObject != null) {
213 Object[] array = (Object[]) arrayObject;
214 for (int i = 0; i < array.length; i++) {
215 if (array[i] == oldChild) {
216 assert assertAssignable(nodeField, newChild);
217 array[i] = newChild;
218 return true;
219 }
220 }
221 }
222 }
223 return false;
224 }
225
226 private static boolean assertAssignable(NodeFieldAccessor field, Object newValue) {
227 if (newValue == null) {
228 return true;
229 }
230 if (field.getKind() == NodeFieldKind.CHILD) {
231 if (field.getType().isAssignableFrom(newValue.getClass())) {
232 return true;
233 } else {
234 assert false : "Child class " + newValue.getClass().getName() + " is not assignable to field \"" + field.getName() + "\" of type " + field.getType().getName();
235 return false;
236 }
237 } else if (field.getKind() == NodeFieldKind.CHILDREN) {
238 if (field.getType().getComponentType().isAssignableFrom(newValue.getClass())) {
239 return true;
240 } else {
241 assert false : "Child class " + newValue.getClass().getName() + " is not assignable to field \"" + field.getName() + "\" of type " + field.getType().getName();
242 return false;
243 }
244 }
245 throw new IllegalArgumentException();
246 }
247
248 /**
249 * Finds the field in a parent node, if any, that holds a specified child node.
250 *
251 * @return the field (possibly an array) holding the child, {@code null} if not found.
252 */
253 public static NodeFieldAccessor findChildField(Node parent, Node child) {
254 assert child != null;
255 NodeClass parentNodeClass = parent.getNodeClass();
256
257 for (NodeFieldAccessor field : parentNodeClass.getChildFields()) {
258 if (field.getObject(parent) == child) {
259 return field;
260 }
261 }
262
263 for (NodeFieldAccessor field : parentNodeClass.getChildrenFields()) {
264 Object arrayObject = field.getObject(parent);
265 if (arrayObject != null) {
266 Object[] array = (Object[]) arrayObject;
267 for (int i = 0; i < array.length; i++) {
268 if (array[i] == child) {
269 return field;
270 }
271 }
272 }
273 }
274 return null;
275 }
276
277 /**
278 * Determines whether a proposed child replacement would be safe: structurally and type.
279 */
280 public static boolean isReplacementSafe(Node parent, Node oldChild, Node newChild) {
281 assert newChild != null;
282 if (parent != null) {
283 final NodeFieldAccessor field = findChildField(parent, oldChild);
284 if (field != null) {
285 switch (field.getKind()) {
286 case CHILD:
287 return field.getType().isAssignableFrom(newChild.getClass());
288 case CHILDREN:
289 return field.getType().getComponentType().isAssignableFrom(newChild.getClass());
290 default:
291 throw new IllegalStateException();
292 }
293 }
294 }
295 return false;
296 }
297
298 /**
299 * Executes a closure for every non-null child of the parent node.
300 *
301 * @return {@code true} if all children were visited, {@code false} otherwise
302 */
303 public static boolean forEachChild(Node parent, NodeVisitor visitor) {
304 Objects.requireNonNull(visitor);
305 NodeClass parentNodeClass = parent.getNodeClass();
306
307 for (NodeFieldAccessor field : parentNodeClass.getChildFields()) {
308 Object child = field.getObject(parent);
309 if (child != null) {
310 if (!visitor.visit((Node) child)) {
311 return false;
312 }
313 }
314 }
315
316 for (NodeFieldAccessor field : parentNodeClass.getChildrenFields()) {
317 Object arrayObject = field.getObject(parent);
318 if (arrayObject != null) {
319 Object[] array = (Object[]) arrayObject;
320 for (int i = 0; i < array.length; i++) {
321 Object child = array[i];
322 if (child != null) {
323 if (!visitor.visit((Node) child)) {
324 return false;
325 }
326 }
327 }
328 }
329 }
330
331 return true;
332 }
333
334 static boolean forEachChildRecursive(Node parent, NodeVisitor visitor) {
335 NodeClass parentNodeClass = parent.getNodeClass();
336
337 for (NodeFieldAccessor field : parentNodeClass.getChildFields()) {
338 if (!visitChild((Node) field.getObject(parent), visitor)) {
339 return false;
340 }
341 }
342
343 for (NodeFieldAccessor field : parentNodeClass.getChildrenFields()) {
344 Object arrayObject = field.getObject(parent);
345 if (arrayObject == null) {
346 continue;
347 }
348 Object[] array = (Object[]) arrayObject;
349 for (int i = 0; i < array.length; i++) {
350 if (!visitChild((Node) array[i], visitor)) {
351 return false;
352 }
353 }
354 }
355
356 return true;
357 }
358
359 private static boolean visitChild(Node child, NodeVisitor visitor) {
360 if (child == null) {
361 return true;
362 }
363 if (!visitor.visit(child)) {
364 return false;
365 }
366 if (!forEachChildRecursive(child, visitor)) {
367 return false;
368 }
369 return true;
370 }
371
372 /** Returns all declared fields in the class hierarchy. */
373 static Field[] getAllFields(Class<? extends Object> clazz) {
374 Field[] declaredFields = clazz.getDeclaredFields();
375 if (clazz.getSuperclass() != null) {
376 return concat(getAllFields(clazz.getSuperclass()), declaredFields);
377 }
378 return declaredFields;
379 }
380
381 public static <T> T[] concat(T[] first, T[] second) {
382 T[] result = Arrays.copyOf(first, first.length + second.length);
383 System.arraycopy(second, 0, result, first.length, second.length);
384 return result;
385 }
386
387 /**
388 * Get the nth parent of a node, where the 0th parent is the node itself. Returns null if there
389 * are less than n ancestors.
390 */
391 public static Node getNthParent(Node node, int n) {
392 Node parent = node;
393
394 for (int i = 0; i < n; i++) {
395 parent = parent.getParent();
396
397 if (parent == null) {
398 return null;
399 }
400 }
401
402 return parent;
403 }
404
405 /** find annotation in class/interface hierarchy. */
406 public static <T extends Annotation> T findAnnotation(Class<?> clazz, Class<T> annotationClass) {
407 if (clazz.getAnnotation(annotationClass) != null) {
408 return clazz.getAnnotation(annotationClass);
409 } else {
410 for (Class<?> intf : clazz.getInterfaces()) {
411 if (intf.getAnnotation(annotationClass) != null) {
412 return intf.getAnnotation(annotationClass);
413 }
414 }
415 if (clazz.getSuperclass() != null) {
416 return findAnnotation(clazz.getSuperclass(), annotationClass);
417 }
418 }
419 return null;
420 }
421
422 public static <T> T findParent(Node start, Class<T> clazz) {
423 Node parent = start.getParent();
424 if (parent == null) {
425 return null;
426 } else if (clazz.isInstance(parent)) {
427 return clazz.cast(parent);
428 } else {
429 return findParent(parent, clazz);
430 }
431 }
432
433 public static <T> List<T> findAllParents(Node start, Class<T> clazz) {
434 List<T> parents = new ArrayList<>();
435 T parent = findParent(start, clazz);
436 while (parent != null) {
437 parents.add(parent);
438 parent = findParent((Node) parent, clazz);
439 }
440 return parents;
441 }
442
443 public static List<Node> collectNodes(Node parent, Node child) {
444 List<Node> nodes = new ArrayList<>();
445 Node current = child;
446 while (current != null) {
447 nodes.add(current);
448 if (current == parent) {
449 return nodes;
450 }
451 current = current.getParent();
452 }
453 throw new IllegalArgumentException("Node " + parent + " is not a parent of " + child + ".");
454 }
455
456 public static <T> T findFirstNodeInstance(Node root, Class<T> clazz) {
457 if (clazz.isInstance(root)) {
458 return clazz.cast(root);
459 }
460 for (Node child : root.getChildren()) {
461 T node = findFirstNodeInstance(child, clazz);
462 if (node != null) {
463 return node;
464 }
465 }
466 return null;
467 }
468
469 public static <T> List<T> findAllNodeInstances(final Node root, final Class<T> clazz) {
470 final List<T> nodeList = new ArrayList<>();
471 root.accept(new NodeVisitor() {
472 public boolean visit(Node node) {
473 if (clazz.isInstance(node)) {
474 nodeList.add(clazz.cast(node));
475 }
476 return true;
477 }
478 });
479 return nodeList;
480 }
481
482 public static int countNodes(Node root) {
483 return countNodes(root, NodeCountFilter.NO_FILTER);
484 }
485
486 public static int countNodes(Node root, NodeCountFilter filter) {
487 NodeCounter counter = new NodeCounter(filter);
488 root.accept(counter);
489 return counter.count;
490 }
491
492 public interface NodeCountFilter {
493
494 NodeCountFilter NO_FILTER = new NodeCountFilter() {
495
496 public boolean isCounted(Node node) {
497 return true;
498 }
499 };
500
501 boolean isCounted(Node node);
502
503 }
504
505 public static String printCompactTreeToString(Node node) {
506 StringWriter out = new StringWriter();
507 printCompactTree(new PrintWriter(out), null, node, 1);
508 return out.toString();
509 }
510
511 public static void printCompactTree(OutputStream out, Node node) {
512 printCompactTree(new PrintWriter(out), null, node, 1);
513 }
514
515 private static void printCompactTree(PrintWriter p, Node parent, Node node, int level) {
516 if (node == null) {
517 return;
518 }
519 for (int i = 0; i < level; i++) {
520 p.print(" ");
521 }
522 if (parent == null) {
523 p.println(nodeName(node));
524 } else {
525 p.print(getNodeFieldName(parent, node, "unknownField"));
526 p.print(" = ");
527 p.println(nodeName(node));
528 }
529
530 for (Node child : node.getChildren()) {
531 printCompactTree(p, node, child, level + 1);
532 }
533 p.flush();
534 }
535
536 public static String printSourceAttributionTree(Node node) {
537 StringWriter out = new StringWriter();
538 printSourceAttributionTree(new PrintWriter(out), null, node, 1);
539 return out.toString();
540 }
541
542 public static void printSourceAttributionTree(OutputStream out, Node node) {
543 printSourceAttributionTree(new PrintWriter(out), null, node, 1);
544 }
545
546 public static void printSourceAttributionTree(PrintWriter out, Node node) {
547 printSourceAttributionTree(out, null, node, 1);
548 }
549
550 private static void printSourceAttributionTree(PrintWriter p, Node parent, Node node, int level) {
551 if (node == null) {
552 return;
553 }
554 if (parent == null) {
555 // Add some preliminary information before starting with the root node
556 final SourceSection sourceSection = node.getSourceSection();
557 if (sourceSection != null) {
558 final String txt = sourceSection.getSource().getCode();
559 p.println("Full source len=(" + txt.length() + ") ___" + txt + "___");
560 p.println("AST source attribution:");
561 }
562 }
563 final StringBuilder sb = new StringBuilder();
564 for (int i = 0; i < level; i++) {
565 sb.append("| ");
566 }
567
568 if (parent != null) {
569 sb.append(getNodeFieldName(parent, node, ""));
570 }
571
572 sb.append(" (" + node.getClass().getSimpleName() + ") ");
573
574 sb.append(printSyntaxTags(node));
575
576 sb.append(displaySourceAttribution(node));
577 p.println(sb.toString());
578
579 for (Node child : node.getChildren()) {
580 printSourceAttributionTree(p, node, child, level + 1);
581 }
582 p.flush();
583 }
584
585 private static String getNodeFieldName(Node parent, Node node, String defaultName) {
586 NodeFieldAccessor[] fields = parent.getNodeClass().getFields();
587 for (NodeFieldAccessor field : fields) {
588 Object value = field.loadValue(parent);
589 if (field.getKind() == NodeFieldKind.CHILD && value == node) {
590 return field.getName();
591 } else if (field.getKind() == NodeFieldKind.CHILDREN) {
592 int index = 0;
593 for (Object arrayNode : (Object[]) value) {
594 if (arrayNode == node) {
595 return field.getName() + "[" + index + "]";
596 }
597 index++;
598 }
599 }
600 }
601 return defaultName;
602 }
603
604 /**
605 * Returns a string listing the {@linkplain SyntaxTag syntax tags}, if any, associated with a
606 * node:
607 * <ul>
608 * <li>"[{@linkplain StandardSyntaxTag#STATEMENT STATEMENT},
609 * {@linkplain StandardSyntaxTag#ASSIGNMENT ASSIGNMENT}]" if tags have been applied;</li>
610 * <li>"[]" if the node supports tags, but none are present; and</li>
611 * <li>"" if the node does not support tags.</li>
612 * </ul>
613 */
614 public static String printSyntaxTags(final Object node) {
615 if (node instanceof WrapperNode) {
616 final Probe probe = ((WrapperNode) node).getProbe();
617 final Collection<SyntaxTag> syntaxTags = probe.getSyntaxTags();
618 final StringBuilder sb = new StringBuilder();
619 String prefix = "";
620 sb.append("[");
621 for (SyntaxTag tag : syntaxTags) {
622 sb.append(prefix);
623 prefix = ",";
624 sb.append(tag.toString());
625 }
626 sb.append("]");
627 return sb.toString();
628 }
629 return "";
630 }
631
632 /**
633 * Prints a human readable form of a {@link Node} AST to the given {@link PrintStream}. This
634 * print method does not check for cycles in the node structure.
635 *
636 * @param out the stream to print to.
637 * @param node the root node to write
638 */
639 public static void printTree(OutputStream out, Node node) {
640 printTree(new PrintWriter(out), node);
641 }
642
643 public static String printTreeToString(Node node) {
644 StringWriter out = new StringWriter();
645 printTree(new PrintWriter(out), node);
646 return out.toString();
647 }
648
649 public static void printTree(PrintWriter p, Node node) {
650 printTree(p, node, 1);
651 p.println();
652 p.flush();
653 }
654
655 private static void printTree(PrintWriter p, Node node, int level) {
656 if (node == null) {
657 p.print("null");
658 return;
659 }
660
661 p.print(nodeName(node));
662
663 ArrayList<NodeFieldAccessor> childFields = new ArrayList<>();
664 String sep = "";
665 p.print("(");
666 for (NodeFieldAccessor field : NodeClass.get(node).getFields()) {
667 if (field.getKind() == NodeFieldKind.CHILD || field.getKind() == NodeFieldKind.CHILDREN) {
668 childFields.add(field);
669 } else if (field.getKind() == NodeFieldKind.DATA) {
670 p.print(sep);
671 sep = ", ";
672
673 p.print(field.getName());
674 p.print(" = ");
675 p.print(field.loadValue(node));
676 }
677 }
678 p.print(")");
679
680 if (childFields.size() != 0) {
681 p.print(" {");
682 for (NodeFieldAccessor field : childFields) {
683 printNewLine(p, level);
684 p.print(field.getName());
685
686 Object value = field.loadValue(node);
687 if (value == null) {
688 p.print(" = null ");
689 } else if (field.getKind() == NodeFieldKind.CHILD) {
690 p.print(" = ");
691 printTree(p, (Node) value, level + 1);
692 } else if (field.getKind() == NodeFieldKind.CHILDREN) {
693 printChildren(p, level, value);
694 }
695 }
696 printNewLine(p, level - 1);
697 p.print("}");
698 }
699 }
700
701 private static void printChildren(PrintWriter p, int level, Object value) {
702 String sep;
703 Object[] children = (Object[]) value;
704 p.print(" = [");
705 sep = "";
706 for (Object child : children) {
707 p.print(sep);
708 sep = ", ";
709 printTree(p, (Node) child, level + 1);
710 }
711 p.print("]");
712 }
713
714 private static void printNewLine(PrintWriter p, int level) {
715 p.println();
716 for (int i = 0; i < level; i++) {
717 p.print(" ");
718 }
719 }
720
721 private static String nodeName(Node node) {
722 return node.getClass().getSimpleName();
723 }
724
725 private static String displaySourceAttribution(Node node) {
726 final SourceSection section = node.getSourceSection();
727 if (section instanceof NullSourceSection) {
728 return "source: " + section.getShortDescription();
729 }
730 if (section != null) {
731 final String srcText = section.getCode();
732 final StringBuilder sb = new StringBuilder();
733 sb.append("source:");
734 sb.append(" (" + section.getCharIndex() + "," + (section.getCharEndIndex() - 1) + ")");
735 sb.append(" line=" + section.getLineLocation().getLineNumber());
736 sb.append(" len=" + srcText.length());
737 sb.append(" text=\"" + srcText + "\"");
738 return sb.toString();
739 }
740 return "";
741 }
742
743 public static boolean verify(Node root) {
744 Iterable<Node> children = root.getChildren();
745 for (Node child : children) {
746 if (child != null) {
747 if (child.getParent() != root) {
748 throw new AssertionError(toStringWithClass(child) + ": actual parent=" + toStringWithClass(child.getParent()) + " expected parent=" + toStringWithClass(root));
749 }
750 verify(child);
751 }
752 }
753 return true;
754 }
755
756 private static String toStringWithClass(Object obj) {
757 return obj == null ? "null" : obj + "(" + obj.getClass().getName() + ")";
758 }
759
760 static void traceRewrite(Node oldNode, Node newNode, CharSequence reason) {
761 if (TruffleOptions.TraceRewritesFilterFromCost != null) {
762 if (filterByKind(oldNode, TruffleOptions.TraceRewritesFilterFromCost)) {
763 return;
764 }
765 }
766
767 if (TruffleOptions.TraceRewritesFilterToCost != null) {
768 if (filterByKind(newNode, TruffleOptions.TraceRewritesFilterToCost)) {
769 return;
770 }
771 }
772
773 String filter = TruffleOptions.TraceRewritesFilterClass;
774 Class<? extends Node> from = oldNode.getClass();
775 Class<? extends Node> to = newNode.getClass();
776 if (filter != null && (filterByContainsClassName(from, filter) || filterByContainsClassName(to, filter))) {
777 return;
778 }
779
780 final SourceSection reportedSourceSection = oldNode.getEncapsulatingSourceSection();
781
782 PrintStream out = System.out;
783 out.printf("[truffle] rewrite %-50s |From %-40s |To %-40s |Reason %s%s%n", oldNode.toString(), formatNodeInfo(oldNode), formatNodeInfo(newNode),
784 reason != null && reason.length() > 0 ? reason : "unknown", reportedSourceSection != null ? " at " + reportedSourceSection.getShortDescription() : "");
785 }
786
787 private static String formatNodeInfo(Node node) {
788 String cost = "?";
789 switch (node.getCost()) {
790 case NONE:
791 cost = "G";
792 break;
793 case MONOMORPHIC:
794 cost = "M";
795 break;
796 case POLYMORPHIC:
797 cost = "P";
798 break;
799 case MEGAMORPHIC:
800 cost = "G";
801 break;
802 default:
803 cost = "?";
804 break;
805 }
806 return cost + " " + node.getClass().getSimpleName();
807 }
808
809 private static boolean filterByKind(Node node, NodeCost cost) {
810 return node.getCost() == cost;
811 }
812
813 private static boolean filterByContainsClassName(Class<? extends Node> from, String filter) {
814 Class<?> currentFrom = from;
815 while (currentFrom != null) {
816 if (currentFrom.getName().contains(filter)) {
817 return false;
818 }
819 currentFrom = currentFrom.getSuperclass();
820 }
821 return true;
822 }
823
824 private static final class NodeCounter implements NodeVisitor {
825
826 public int count;
827 private final NodeCountFilter filter;
828
829 public NodeCounter(NodeCountFilter filter) {
830 this.filter = filter;
831 }
832
833 public boolean visit(Node node) {
834 if (filter.isCounted(node)) {
835 count++;
836 }
837 return true;
838 }
839
840 }
841 }