Mercurial > hg > truffle
comparison graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java @ 16513:d86f948268da
Merge with f0f4402a4f65bc5456feeb4d78e6b4843ec23d8c
author | Michael Van De Vanter <michael.van.de.vanter@oracle.com> |
---|---|
date | Mon, 14 Jul 2014 17:06:32 -0700 |
parents | aee02665e505 9fa5872291c1 |
children | a3b0a2d61e62 |
comparison
equal
deleted
inserted
replaced
16512:abe7128ca473 | 16513:d86f948268da |
---|---|
155 /** | 155 /** |
156 * Information about a {@link Node} class. A single instance of this class is allocated for | 156 * Information about a {@link Node} class. A single instance of this class is allocated for |
157 * every subclass of {@link Node} that is used. | 157 * every subclass of {@link Node} that is used. |
158 */ | 158 */ |
159 public static final class NodeClass { | 159 public static final class NodeClass { |
160 | 160 private static final ClassValue<NodeClass> nodeClasses = new ClassValue<NodeClass>() { |
161 private static final Map<Class<?>, NodeClass> nodeClasses = new IdentityHashMap<>(); | 161 @SuppressWarnings("unchecked") |
162 @Override | |
163 protected NodeClass computeValue(Class<?> clazz) { | |
164 assert Node.class.isAssignableFrom(clazz); | |
165 return new NodeClass((Class<? extends Node>) clazz, unsafeFieldOffsetProvider); | |
166 } | |
167 }; | |
162 | 168 |
163 // The comprehensive list of all fields. | 169 // The comprehensive list of all fields. |
164 private final NodeField[] fields; | 170 private final NodeField[] fields; |
165 // Separate arrays for the frequently accessed field offsets. | 171 // Separate arrays for the frequently accessed field offsets. |
166 private final long parentOffset; | 172 private final long parentOffset; |
167 private final long[] childOffsets; | 173 private final long[] childOffsets; |
168 private final long[] childrenOffsets; | 174 private final long[] childrenOffsets; |
175 private final Class<? extends Node> clazz; | |
169 | 176 |
170 public static NodeClass get(Class<? extends Node> clazz) { | 177 public static NodeClass get(Class<? extends Node> clazz) { |
171 NodeClass nodeClass = nodeClasses.get(clazz); | 178 return nodeClasses.get(clazz); |
172 if (nodeClass == null) { | |
173 nodeClass = new NodeClass(clazz, unsafeFieldOffsetProvider); | |
174 nodeClasses.put(clazz, nodeClass); | |
175 } | |
176 return nodeClass; | |
177 } | 179 } |
178 | 180 |
179 public NodeClass(Class<? extends Node> clazz, FieldOffsetProvider fieldOffsetProvider) { | 181 public NodeClass(Class<? extends Node> clazz, FieldOffsetProvider fieldOffsetProvider) { |
180 List<NodeField> fieldsList = new ArrayList<>(); | 182 List<NodeField> fieldsList = new ArrayList<>(); |
181 List<Long> parentOffsetsList = new ArrayList<>(); | 183 List<Long> parentOffsetsList = new ArrayList<>(); |
207 this.fields = fieldsList.toArray(new NodeField[fieldsList.size()]); | 209 this.fields = fieldsList.toArray(new NodeField[fieldsList.size()]); |
208 assert parentOffsetsList.size() == 1 : "must have exactly one parent field"; | 210 assert parentOffsetsList.size() == 1 : "must have exactly one parent field"; |
209 this.parentOffset = parentOffsetsList.get(0); | 211 this.parentOffset = parentOffsetsList.get(0); |
210 this.childOffsets = toLongArray(childOffsetsList); | 212 this.childOffsets = toLongArray(childOffsetsList); |
211 this.childrenOffsets = toLongArray(childrenOffsetsList); | 213 this.childrenOffsets = toLongArray(childrenOffsetsList); |
214 this.clazz = clazz; | |
212 } | 215 } |
213 | 216 |
214 public NodeField[] getFields() { | 217 public NodeField[] getFields() { |
215 return fields; | 218 return fields; |
216 } | 219 } |
239 return Arrays.equals(fields, other.fields) && Arrays.equals(childOffsets, other.childOffsets) && Arrays.equals(childrenOffsets, other.childrenOffsets) && | 242 return Arrays.equals(fields, other.fields) && Arrays.equals(childOffsets, other.childOffsets) && Arrays.equals(childrenOffsets, other.childrenOffsets) && |
240 parentOffset == other.parentOffset; | 243 parentOffset == other.parentOffset; |
241 } | 244 } |
242 return false; | 245 return false; |
243 } | 246 } |
244 } | 247 |
245 | 248 public Iterator<Node> makeIterator(Node node) { |
246 static class NodeIterator implements Iterator<Node> { | 249 assert clazz.isInstance(node); |
247 | 250 return new NodeIterator(node); |
248 private final Node node; | 251 } |
249 private final NodeClass nodeClass; | 252 |
250 private final int childrenCount; | 253 private final class NodeIterator implements Iterator<Node> { |
251 private int index; | 254 private final Node node; |
252 | 255 private int fieldIndex; |
253 protected NodeIterator(Node node) { | 256 private int arrayIndex; |
254 this.node = node; | 257 |
255 this.index = 0; | 258 protected NodeIterator(Node node) { |
256 this.nodeClass = NodeClass.get(node.getClass()); | 259 this.node = node; |
257 this.childrenCount = childrenCount(); | 260 } |
258 } | 261 |
259 | 262 private void forward() { |
260 private int childrenCount() { | 263 if (fieldIndex < childOffsets.length) { |
261 int nodeCount = nodeClass.childOffsets.length; | 264 fieldIndex++; |
262 for (long fieldOffset : nodeClass.childrenOffsets) { | 265 } else if (fieldIndex < childOffsets.length + childrenOffsets.length) { |
263 Node[] children = ((Node[]) unsafe.getObject(node, fieldOffset)); | 266 if (arrayIndex + 1 < currentChildrenArrayLength()) { |
264 if (children != null) { | 267 arrayIndex++; |
265 nodeCount += children.length; | 268 } else { |
266 } | 269 arrayIndex = 0; |
267 } | 270 do { |
268 return nodeCount; | 271 fieldIndex++; |
269 } | 272 } while (fieldIndex < childOffsets.length + childrenOffsets.length && currentChildrenArrayLength() == 0); |
270 | |
271 private Node nodeAt(int idx) { | |
272 int nodeCount = nodeClass.childOffsets.length; | |
273 if (idx < nodeCount) { | |
274 return (Node) unsafe.getObject(node, nodeClass.childOffsets[idx]); | |
275 } else { | |
276 for (long fieldOffset : nodeClass.childrenOffsets) { | |
277 Node[] nodeArray = (Node[]) unsafe.getObject(node, fieldOffset); | |
278 if (idx < nodeCount + nodeArray.length) { | |
279 return nodeArray[idx - nodeCount]; | |
280 } | 273 } |
281 nodeCount += nodeArray.length; | 274 } |
282 } | 275 } |
283 } | 276 |
284 return null; | 277 public boolean hasNext() { |
285 } | 278 return fieldIndex < childOffsets.length || (fieldIndex < childOffsets.length + childrenOffsets.length && arrayIndex < currentChildrenArrayLength()); |
286 | 279 } |
287 private void forward() { | 280 |
288 if (index < childrenCount) { | 281 private Node[] currentChildrenArray() { |
289 index++; | 282 assert fieldIndex >= childOffsets.length && fieldIndex < childOffsets.length + childrenOffsets.length; |
290 } | 283 return (Node[]) unsafe.getObject(node, childrenOffsets[fieldIndex - childOffsets.length]); |
291 } | 284 } |
292 | 285 |
293 @Override | 286 private int currentChildrenArrayLength() { |
294 public boolean hasNext() { | 287 Node[] childrenArray = currentChildrenArray(); |
295 return index < childrenCount; | 288 return childrenArray != null ? childrenArray.length : 0; |
296 } | 289 } |
297 | 290 |
298 @Override | 291 public Node next() { |
299 public Node next() { | 292 Node next; |
300 try { | 293 if (fieldIndex < childOffsets.length) { |
301 return nodeAt(index); | 294 next = (Node) unsafe.getObject(node, childOffsets[fieldIndex]); |
302 } finally { | 295 } else if (fieldIndex < childOffsets.length + childrenOffsets.length) { |
296 next = currentChildrenArray()[arrayIndex]; | |
297 } else { | |
298 throw new NoSuchElementException(); | |
299 } | |
303 forward(); | 300 forward(); |
304 } | 301 return next; |
305 } | 302 } |
306 | 303 |
307 @Override | 304 public void remove() { |
308 public void remove() { | 305 throw new UnsupportedOperationException(); |
309 throw new UnsupportedOperationException(); | 306 } |
310 } | 307 } |
308 } | |
309 | |
310 static Iterator<Node> makeIterator(Node node) { | |
311 return NodeClass.get(node.getClass()).makeIterator(node); | |
311 } | 312 } |
312 | 313 |
313 private static long[] toLongArray(List<Long> list) { | 314 private static long[] toLongArray(List<Long> list) { |
314 long[] array = new long[list.size()]; | 315 long[] array = new long[list.size()]; |
315 for (int i = 0; i < list.size(); i++) { | 316 for (int i = 0; i < list.size(); i++) { |
540 } | 541 } |
541 } | 542 } |
542 return null; | 543 return null; |
543 } | 544 } |
544 | 545 |
545 public static <T extends Node> List<T> findAllNodeInstances(final Node root, final Class<T> clazz) { | 546 public static <T> List<T> findAllNodeInstances(final Node root, final Class<T> clazz) { |
546 final List<T> nodeList = new ArrayList<>(); | 547 final List<T> nodeList = new ArrayList<>(); |
547 root.accept(new NodeVisitor() { | 548 root.accept(new NodeVisitor() { |
548 | |
549 @SuppressWarnings("unchecked") | |
550 @Override | |
551 public boolean visit(Node node) { | 549 public boolean visit(Node node) { |
552 if (clazz.isInstance(node)) { | 550 if (clazz.isInstance(node)) { |
553 nodeList.add((T) node); | 551 nodeList.add(clazz.cast(node)); |
554 } | 552 } |
555 return true; | 553 return true; |
556 } | 554 } |
557 }); | 555 }); |
558 return nodeList; | 556 return nodeList; |
559 } | 557 } |
560 | 558 |
561 // Don't visit found node instances. | 559 /** |
562 public static <T extends Node> List<T> findNodeInstancesShallow(final Node root, final Class<T> clazz) { | 560 * Like {@link #findAllNodeInstances(Node, Class)} but do not visit children of found nodes. |
561 */ | |
562 public static <T> List<T> findNodeInstancesShallow(final Node root, final Class<T> clazz) { | |
563 final List<T> nodeList = new ArrayList<>(); | 563 final List<T> nodeList = new ArrayList<>(); |
564 root.accept(new NodeVisitor() { | 564 root.accept(new NodeVisitor() { |
565 | |
566 @SuppressWarnings("unchecked") | |
567 @Override | |
568 public boolean visit(Node node) { | 565 public boolean visit(Node node) { |
569 if (clazz.isInstance(node)) { | 566 if (clazz.isInstance(node)) { |
570 nodeList.add((T) node); | 567 nodeList.add(clazz.cast(node)); |
571 return false; | |
572 } | |
573 return true; | |
574 } | |
575 }); | |
576 return nodeList; | |
577 } | |
578 | |
579 /** Find node instances within current function only (not in nested functions). */ | |
580 public static <T extends Node> List<T> findNodeInstancesInFunction(final Node root, final Class<T> clazz) { | |
581 final List<T> nodeList = new ArrayList<>(); | |
582 root.accept(new NodeVisitor() { | |
583 | |
584 @SuppressWarnings("unchecked") | |
585 @Override | |
586 public boolean visit(Node node) { | |
587 if (clazz.isInstance(node)) { | |
588 nodeList.add((T) node); | |
589 } else if (node instanceof RootNode && node != root) { | |
590 return false; | |
591 } | |
592 return true; | |
593 } | |
594 }); | |
595 return nodeList; | |
596 } | |
597 | |
598 public static <I> List<I> findNodeInstancesInFunctionInterface(final Node root, final Class<I> clazz) { | |
599 final List<I> nodeList = new ArrayList<>(); | |
600 root.accept(new NodeVisitor() { | |
601 | |
602 @SuppressWarnings("unchecked") | |
603 @Override | |
604 public boolean visit(Node node) { | |
605 if (clazz.isInstance(node)) { | |
606 nodeList.add((I) node); | |
607 } else if (node instanceof RootNode && node != root) { | |
608 return false; | 568 return false; |
609 } | 569 } |
610 return true; | 570 return true; |
611 } | 571 } |
612 }); | 572 }); |
892 } | 852 } |
893 | 853 |
894 private static String toStringWithClass(Object obj) { | 854 private static String toStringWithClass(Object obj) { |
895 return obj == null ? "null" : obj + "(" + obj.getClass().getName() + ")"; | 855 return obj == null ? "null" : obj + "(" + obj.getClass().getName() + ")"; |
896 } | 856 } |
857 | |
858 static void traceRewrite(Node oldNode, Node newNode, CharSequence reason) { | |
859 if (TruffleOptions.TraceRewritesFilterFromCost != null) { | |
860 if (filterByKind(oldNode, TruffleOptions.TraceRewritesFilterFromCost)) { | |
861 return; | |
862 } | |
863 } | |
864 | |
865 if (TruffleOptions.TraceRewritesFilterToCost != null) { | |
866 if (filterByKind(newNode, TruffleOptions.TraceRewritesFilterToCost)) { | |
867 return; | |
868 } | |
869 } | |
870 | |
871 String filter = TruffleOptions.TraceRewritesFilterClass; | |
872 Class<? extends Node> from = oldNode.getClass(); | |
873 Class<? extends Node> to = newNode.getClass(); | |
874 if (filter != null && (filterByContainsClassName(from, filter) || filterByContainsClassName(to, filter))) { | |
875 return; | |
876 } | |
877 | |
878 final SourceSection reportedSourceSection = oldNode.getEncapsulatingSourceSection(); | |
879 | |
880 PrintStream out = System.out; | |
881 out.printf("[truffle] rewrite %-50s |From %-40s |To %-40s |Reason %s%s%n", oldNode.toString(), formatNodeInfo(oldNode), formatNodeInfo(newNode), | |
882 reason != null && reason.length() > 0 ? reason : "unknown", reportedSourceSection != null ? " at " + reportedSourceSection.getShortDescription() : ""); | |
883 } | |
884 | |
885 private static String formatNodeInfo(Node node) { | |
886 String cost = "?"; | |
887 switch (node.getCost()) { | |
888 case NONE: | |
889 cost = "G"; | |
890 break; | |
891 case MONOMORPHIC: | |
892 cost = "M"; | |
893 break; | |
894 case POLYMORPHIC: | |
895 cost = "P"; | |
896 break; | |
897 case MEGAMORPHIC: | |
898 cost = "G"; | |
899 break; | |
900 default: | |
901 cost = "?"; | |
902 break; | |
903 } | |
904 return cost + " " + node.getClass().getSimpleName(); | |
905 } | |
906 | |
907 private static boolean filterByKind(Node node, NodeCost cost) { | |
908 return node.getCost() == cost; | |
909 } | |
910 | |
911 private static boolean filterByContainsClassName(Class<? extends Node> from, String filter) { | |
912 Class<?> currentFrom = from; | |
913 while (currentFrom != null) { | |
914 if (currentFrom.getName().contains(filter)) { | |
915 return false; | |
916 } | |
917 currentFrom = currentFrom.getSuperclass(); | |
918 } | |
919 return true; | |
920 } | |
897 } | 921 } |