comparison graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java @ 17275:846c059e3ecf

Truffle: allow interface types in child fields
author Andreas Woess <andreas.woess@jku.at>
date Tue, 30 Sep 2014 23:42:08 +0200
parents e52ad0d3b7d6
children 5787218bad91
comparison
equal deleted inserted replaced
17274:5c55441b4c62 17275:846c059e3ecf
183 return nodeClasses.get(clazz); 183 return nodeClasses.get(clazz);
184 } 184 }
185 185
186 public NodeClass(Class<? extends Node> clazz, FieldOffsetProvider fieldOffsetProvider) { 186 public NodeClass(Class<? extends Node> clazz, FieldOffsetProvider fieldOffsetProvider) {
187 List<NodeField> fieldsList = new ArrayList<>(); 187 List<NodeField> fieldsList = new ArrayList<>();
188 List<Long> parentOffsetsList = new ArrayList<>(); 188 long parentFieldOffset = -1;
189 List<Long> childOffsetsList = new ArrayList<>(); 189 List<Long> childOffsetsList = new ArrayList<>();
190 List<Long> childrenOffsetsList = new ArrayList<>(); 190 List<Long> childrenOffsetsList = new ArrayList<>();
191 191
192 for (Field field : getAllFields(clazz)) { 192 for (Field field : getAllFields(clazz)) {
193 if (Modifier.isStatic(field.getModifiers()) || field.isSynthetic()) { 193 if (Modifier.isStatic(field.getModifiers()) || field.isSynthetic()) {
194 continue; 194 continue;
195 } 195 }
196 196
197 NodeFieldKind kind; 197 NodeFieldKind kind;
198 if (Node.class.isAssignableFrom(field.getType()) && field.getName().equals("parent") && field.getDeclaringClass() == Node.class) { 198 if (field.getDeclaringClass() == Node.class && field.getName().equals("parent")) {
199 assert Node.class.isAssignableFrom(field.getType());
199 kind = NodeFieldKind.PARENT; 200 kind = NodeFieldKind.PARENT;
200 parentOffsetsList.add(fieldOffsetProvider.objectFieldOffset(field)); 201 parentFieldOffset = fieldOffsetProvider.objectFieldOffset(field);
201 } else if (Node.class.isAssignableFrom(field.getType()) && field.getAnnotation(Child.class) != null) { 202 } else if (field.getAnnotation(Child.class) != null) {
203 checkChildField(field);
202 kind = NodeFieldKind.CHILD; 204 kind = NodeFieldKind.CHILD;
203 childOffsetsList.add(fieldOffsetProvider.objectFieldOffset(field)); 205 childOffsetsList.add(fieldOffsetProvider.objectFieldOffset(field));
204 assert !Modifier.isFinal(field.getModifiers()) : "child field must not be final (\"" + field.getName() + "\", " + clazz + ")"; 206 } else if (field.getAnnotation(Children.class) != null) {
205 } else if (field.getType().isArray() && Node.class.isAssignableFrom(field.getType().getComponentType()) && field.getAnnotation(Children.class) != null) { 207 checkChildrenField(field);
206 kind = NodeFieldKind.CHILDREN; 208 kind = NodeFieldKind.CHILDREN;
207 childrenOffsetsList.add(fieldOffsetProvider.objectFieldOffset(field)); 209 childrenOffsetsList.add(fieldOffsetProvider.objectFieldOffset(field));
208 assert Modifier.isFinal(field.getModifiers()) : "children array field must be final (\"" + field.getName() + "\", " + clazz + ")";
209 } else { 210 } else {
210 kind = NodeFieldKind.DATA; 211 kind = NodeFieldKind.DATA;
211 } 212 }
212 fieldsList.add(new NodeField(kind, field.getType(), field.getName(), fieldOffsetProvider.objectFieldOffset(field))); 213 fieldsList.add(new NodeField(kind, field.getType(), field.getName(), fieldOffsetProvider.objectFieldOffset(field)));
213 } 214 }
215
216 if (parentFieldOffset < 0) {
217 throw new AssertionError("parent field not found");
218 }
219
214 this.fields = fieldsList.toArray(new NodeField[fieldsList.size()]); 220 this.fields = fieldsList.toArray(new NodeField[fieldsList.size()]);
215 assert parentOffsetsList.size() == 1 : "must have exactly one parent field"; 221 this.parentOffset = parentFieldOffset;
216 this.parentOffset = parentOffsetsList.get(0);
217 this.childOffsets = toLongArray(childOffsetsList); 222 this.childOffsets = toLongArray(childOffsetsList);
218 this.childrenOffsets = toLongArray(childrenOffsetsList); 223 this.childrenOffsets = toLongArray(childrenOffsetsList);
219 this.clazz = clazz; 224 this.clazz = clazz;
225 }
226
227 private static void checkChildField(Field field) {
228 if (!(Node.class.isAssignableFrom(field.getType()) || field.getType().isInterface())) {
229 throw new AssertionError("@Child field type must be a subclass of Node or an interface (" + field + ")");
230 }
231 if (Modifier.isFinal(field.getModifiers())) {
232 throw new AssertionError("@Child field must not be final (" + field + ")");
233 }
234 }
235
236 private static void checkChildrenField(Field field) {
237 if (!(field.getType().isArray() && (Node.class.isAssignableFrom(field.getType().getComponentType()) || field.getType().getComponentType().isInterface()))) {
238 throw new AssertionError("@Children field type must be an array of a subclass of Node or an interface (" + field + ")");
239 }
240 if (!Modifier.isFinal(field.getModifiers())) {
241 throw new AssertionError("@Children field must be final (" + field + ")");
242 }
220 } 243 }
221 244
222 public NodeField[] getFields() { 245 public NodeField[] getFields() {
223 return fields; 246 return fields;
224 } 247 }
267 } 290 }
268 291
269 private int childrenCount() { 292 private int childrenCount() {
270 int nodeCount = childOffsets.length; 293 int nodeCount = childOffsets.length;
271 for (long fieldOffset : childrenOffsets) { 294 for (long fieldOffset : childrenOffsets) {
272 Node[] children = ((Node[]) unsafe.getObject(node, fieldOffset)); 295 Object[] children = ((Object[]) unsafe.getObject(node, fieldOffset));
273 if (children != null) { 296 if (children != null) {
274 nodeCount += children.length; 297 nodeCount += children.length;
275 } 298 }
276 } 299 }
277 return nodeCount; 300 return nodeCount;
281 int nodeCount = childOffsets.length; 304 int nodeCount = childOffsets.length;
282 if (idx < nodeCount) { 305 if (idx < nodeCount) {
283 return (Node) unsafe.getObject(node, childOffsets[idx]); 306 return (Node) unsafe.getObject(node, childOffsets[idx]);
284 } else { 307 } else {
285 for (long fieldOffset : childrenOffsets) { 308 for (long fieldOffset : childrenOffsets) {
286 Node[] nodeArray = (Node[]) unsafe.getObject(node, fieldOffset); 309 Object[] nodeArray = (Object[]) unsafe.getObject(node, fieldOffset);
287 if (idx < nodeCount + nodeArray.length) { 310 if (idx < nodeCount + nodeArray.length) {
288 return nodeArray[idx - nodeCount]; 311 return (Node) nodeArray[idx - nodeCount];
289 } 312 }
290 nodeCount += nodeArray.length; 313 nodeCount += nodeArray.length;
291 } 314 }
292 } 315 }
293 return null; 316 return null;
359 unsafe.putObject(clonedChild, nodeClass.parentOffset, clone); 382 unsafe.putObject(clonedChild, nodeClass.parentOffset, clone);
360 unsafe.putObject(clone, fieldOffset, clonedChild); 383 unsafe.putObject(clone, fieldOffset, clonedChild);
361 } 384 }
362 } 385 }
363 for (long fieldOffset : nodeClass.childrenOffsets) { 386 for (long fieldOffset : nodeClass.childrenOffsets) {
364 Node[] children = (Node[]) unsafe.getObject(orig, fieldOffset); 387 Object[] children = (Object[]) unsafe.getObject(orig, fieldOffset);
365 if (children != null) { 388 if (children != null) {
366 Node[] clonedChildren = (Node[]) Array.newInstance(children.getClass().getComponentType(), children.length); 389 Object[] clonedChildren = (Object[]) Array.newInstance(children.getClass().getComponentType(), children.length);
367 for (int i = 0; i < children.length; i++) { 390 for (int i = 0; i < children.length; i++) {
368 if (children[i] != null) { 391 if (children[i] != null) {
369 Node clonedChild = cloneNode(children[i]); 392 Node clonedChild = cloneNode((Node) children[i]);
370 clonedChildren[i] = clonedChild; 393 clonedChildren[i] = clonedChild;
371 unsafe.putObject(clonedChild, nodeClass.parentOffset, clone); 394 unsafe.putObject(clonedChild, nodeClass.parentOffset, clone);
372 } 395 }
373 } 396 }
374 unsafe.putObject(clone, fieldOffset, clonedChildren); 397 unsafe.putObject(clone, fieldOffset, clonedChildren);
386 if (child != null) { 409 if (child != null) {
387 nodes.add((Node) child); 410 nodes.add((Node) child);
388 } 411 }
389 } 412 }
390 for (long fieldOffset : nodeClass.childrenOffsets) { 413 for (long fieldOffset : nodeClass.childrenOffsets) {
391 Node[] children = (Node[]) unsafe.getObject(node, fieldOffset); 414 Object[] children = (Object[]) unsafe.getObject(node, fieldOffset);
392 if (children != null) { 415 if (children != null) {
393 for (Node child : children) { 416 for (Object child : children) {
394 if (child != null) { 417 if (child != null) {
395 nodes.add(child); 418 nodes.add((Node) child);
396 } 419 }
397 } 420 }
398 } 421 }
399 } 422 }
400 423
413 } 436 }
414 437
415 for (long fieldOffset : nodeClass.getChildrenOffsets()) { 438 for (long fieldOffset : nodeClass.getChildrenOffsets()) {
416 Object arrayObject = unsafe.getObject(parent, fieldOffset); 439 Object arrayObject = unsafe.getObject(parent, fieldOffset);
417 if (arrayObject != null) { 440 if (arrayObject != null) {
418 assert arrayObject instanceof Node[] : "Children array must be instanceof Node[] "; 441 Object[] array = (Object[]) arrayObject;
419 Node[] array = (Node[]) arrayObject;
420 for (int i = 0; i < array.length; i++) { 442 for (int i = 0; i < array.length; i++) {
421 if (array[i] == oldChild) { 443 if (array[i] == oldChild) {
422 assert assertAssignable(nodeClass, fieldOffset, newChild); 444 assert assertAssignable(nodeClass, fieldOffset, newChild);
423 array[i] = newChild; 445 array[i] = newChild;
424 return true; 446 return true;
653 p.print(" "); 675 p.print(" ");
654 } 676 }
655 if (parent == null) { 677 if (parent == null) {
656 p.println(nodeName(node)); 678 p.println(nodeName(node));
657 } else { 679 } else {
658 String fieldName = "unknownField"; 680 p.print(getNodeFieldName(parent, node, "unknownField"));
659 NodeField[] fields = NodeClass.get(parent.getClass()).fields;
660 for (NodeField field : fields) {
661 Object value = field.loadValue(parent);
662 if (value == node) {
663 fieldName = field.getName();
664 break;
665 } else if (value instanceof Node[]) {
666 int index = 0;
667 for (Node arrayNode : (Node[]) value) {
668 if (arrayNode == node) {
669 fieldName = field.getName() + "[" + index + "]";
670 break;
671 }
672 index++;
673 }
674 }
675 }
676 p.print(fieldName);
677 p.print(" = "); 681 p.print(" = ");
678 p.println(nodeName(node)); 682 p.println(nodeName(node));
679 } 683 }
680 684
681 for (Node child : node.getChildren()) { 685 for (Node child : node.getChildren()) {
711 for (int i = 0; i < level; i++) { 715 for (int i = 0; i < level; i++) {
712 sb.append("| "); 716 sb.append("| ");
713 } 717 }
714 718
715 if (parent != null) { 719 if (parent != null) {
716 String childName = ""; 720 sb.append(getNodeFieldName(parent, node, ""));
717 NodeField[] fields = NodeClass.get(parent.getClass()).fields;
718 for (NodeField field : fields) {
719 Object value = field.loadValue(parent);
720 if (value == node) {
721 childName = field.getName();
722 break;
723 } else if (value instanceof Node[]) {
724 int index = 0;
725 for (Node arrayNode : (Node[]) value) {
726 if (arrayNode == node) {
727 childName = field.getName() + "[" + index + "]";
728 break;
729 }
730 index++;
731 }
732 }
733 }
734 sb.append(childName);
735 } 721 }
736 722
737 sb.append(" (" + node.getClass().getSimpleName() + ") "); 723 sb.append(" (" + node.getClass().getSimpleName() + ") ");
738 sb.append(displaySourceAttribution(node)); 724 sb.append(displaySourceAttribution(node));
739 p.println(sb.toString()); 725 p.println(sb.toString());
740 726
741 for (Node child : node.getChildren()) { 727 for (Node child : node.getChildren()) {
742 printSourceAttributionTree(p, node, child, level + 1); 728 printSourceAttributionTree(p, node, child, level + 1);
743 } 729 }
744 p.flush(); 730 p.flush();
731 }
732
733 private static String getNodeFieldName(Node parent, Node node, String defaultName) {
734 NodeField[] fields = NodeClass.get(parent.getClass()).fields;
735 for (NodeField field : fields) {
736 Object value = field.loadValue(parent);
737 if (field.getKind() == NodeFieldKind.CHILD && value == node) {
738 return field.getName();
739 } else if (field.getKind() == NodeFieldKind.CHILDREN) {
740 int index = 0;
741 for (Object arrayNode : (Object[]) value) {
742 if (arrayNode == node) {
743 return field.getName() + "[" + index + "]";
744 }
745 index++;
746 }
747 }
748 }
749 return defaultName;
745 } 750 }
746 751
747 /** 752 /**
748 * Prints a human readable form of a {@link Node} AST to the given {@link PrintStream}. This 753 * Prints a human readable form of a {@link Node} AST to the given {@link PrintStream}. This
749 * print method does not check for cycles in the node structure. 754 * print method does not check for cycles in the node structure.
813 } 818 }
814 } 819 }
815 820
816 private static void printChildren(PrintWriter p, int level, Object value) { 821 private static void printChildren(PrintWriter p, int level, Object value) {
817 String sep; 822 String sep;
818 Node[] children = (Node[]) value; 823 Object[] children = (Object[]) value;
819 p.print(" = ["); 824 p.print(" = [");
820 sep = ""; 825 sep = "";
821 for (Node child : children) { 826 for (Object child : children) {
822 p.print(sep); 827 p.print(sep);
823 sep = ", "; 828 sep = ", ";
824 printTree(p, child, level + 1); 829 printTree(p, (Node) child, level + 1);
825 } 830 }
826 p.print("]"); 831 p.print("]");
827 } 832 }
828 833
829 private static void printNewLine(PrintWriter p, int level) { 834 private static void printNewLine(PrintWriter p, int level) {