Mercurial > hg > truffle
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 } |