comparison graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java @ 20129:5b7db8941fd7

Truffle: make NodeClass and NodeField a top-level class.
author Christian Humer <christian.humer@gmail.com>
date Thu, 02 Apr 2015 01:22:41 +0200
parents a0971187a38a
children 8dc73c226c63
comparison
equal deleted inserted replaced
20128:7ad60a16bbb0 20129:5b7db8941fd7
25 package com.oracle.truffle.api.nodes; 25 package com.oracle.truffle.api.nodes;
26 26
27 import java.io.*; 27 import java.io.*;
28 import java.lang.annotation.*; 28 import java.lang.annotation.*;
29 import java.lang.reflect.*; 29 import java.lang.reflect.*;
30 import java.security.*;
31 import java.util.*; 30 import java.util.*;
32 31
33 import sun.misc.*; 32 import sun.misc.*;
34 33
35 import com.oracle.truffle.api.*; 34 import com.oracle.truffle.api.*;
36 import com.oracle.truffle.api.instrument.*; 35 import com.oracle.truffle.api.instrument.*;
37 import com.oracle.truffle.api.instrument.ProbeNode.WrapperNode; 36 import com.oracle.truffle.api.instrument.ProbeNode.WrapperNode;
38 import com.oracle.truffle.api.nodes.Node.Child; 37 import com.oracle.truffle.api.nodes.NodeFieldAccessor.NodeFieldKind;
39 import com.oracle.truffle.api.nodes.Node.Children;
40 import com.oracle.truffle.api.source.*; 38 import com.oracle.truffle.api.source.*;
41 39
42 /** 40 /**
43 * Utility class that manages the special access methods for node instances. 41 * Utility class that manages the special access methods for node instances.
44 */ 42 */
45 public final class NodeUtil { 43 public final class NodeUtil {
46 private static final boolean USE_UNSAFE = Boolean.getBoolean("truffle.unsafe");
47 44
48 /** 45 /**
49 * Interface that allows the customization of field offsets used for {@link Unsafe} field 46 * Interface that allows the customization of field offsets used for {@link Unsafe} field
50 * accesses. 47 * accesses.
51 */ 48 */
52 public interface FieldOffsetProvider { 49 public interface FieldOffsetProvider {
53 50
54 long objectFieldOffset(Field field); 51 long objectFieldOffset(Field field);
55 52
56 int getTypeSize(Class<?> clazz); 53 int getTypeSize(Class<?> clazz);
57 }
58
59 private static final FieldOffsetProvider unsafeFieldOffsetProvider = new FieldOffsetProvider() {
60
61 @Override
62 public long objectFieldOffset(Field field) {
63 return unsafe.objectFieldOffset(field);
64 }
65
66 @Override
67 public int getTypeSize(Class<?> clazz) {
68 if (!clazz.isPrimitive()) {
69 return Unsafe.ARRAY_OBJECT_INDEX_SCALE;
70 } else if (clazz == int.class) {
71 return Unsafe.ARRAY_INT_INDEX_SCALE;
72 } else {
73 throw new UnsupportedOperationException("unsupported field type: " + clazz);
74 }
75 }
76 };
77
78 public static enum NodeFieldKind {
79 /** The single {@link Node#getParent() parent} field. */
80 PARENT,
81 /** A field annotated with {@link Child}. */
82 CHILD,
83 /** A field annotated with {@link Children}. */
84 CHILDREN,
85 /** A normal non-child data field of the node. */
86 DATA
87 }
88
89 /**
90 * Information about a field in a {@link Node} class.
91 */
92 public abstract static class NodeField {
93
94 private final NodeFieldKind kind;
95 private final String name;
96 protected final Class<?> type;
97 protected final long offset;
98
99 protected NodeField(NodeFieldKind kind, Field field) {
100 this.kind = kind;
101 this.type = field.getType();
102 this.name = field.getName();
103 this.offset = unsafeFieldOffsetProvider.objectFieldOffset(field);
104 }
105
106 protected static NodeField create(NodeFieldKind kind, Field field) {
107 if (USE_UNSAFE) {
108 return new UnsafeNodeField(kind, field);
109 } else {
110 return new ReflectionNodeField(kind, field);
111 }
112 }
113
114 public NodeFieldKind getKind() {
115 return kind;
116 }
117
118 public Class<?> getType() {
119 return type;
120 }
121
122 public String getName() {
123 return name;
124 }
125
126 public long getOffset() {
127 return offset;
128 }
129
130 public abstract void putObject(Node receiver, Object value);
131
132 public abstract Object getObject(Node receiver);
133
134 public abstract Object loadValue(Node node);
135
136 @Override
137 public int hashCode() {
138 return kind.hashCode() | type.hashCode() | name.hashCode() | ((Long) offset).hashCode();
139 }
140
141 @Override
142 public boolean equals(Object obj) {
143 if (obj instanceof NodeField) {
144 NodeField other = (NodeField) obj;
145 return offset == other.offset && name.equals(other.name) && type.equals(other.type) && kind.equals(other.kind);
146 }
147 return false;
148 }
149 }
150
151 private static final class UnsafeNodeField extends NodeField {
152 protected UnsafeNodeField(NodeFieldKind kind, Field field) {
153 super(kind, field);
154 }
155
156 @Override
157 public void putObject(Node receiver, Object value) {
158 if (!type.isPrimitive() && value == null || type.isInstance(value)) {
159 unsafe.putObject(receiver, offset, value);
160 } else {
161 throw new IllegalArgumentException();
162 }
163 }
164
165 @Override
166 public Object getObject(Node receiver) {
167 if (!type.isPrimitive()) {
168 return unsafe.getObject(receiver, offset);
169 } else {
170 throw new IllegalArgumentException();
171 }
172 }
173
174 @Override
175 public Object loadValue(Node node) {
176 if (type == boolean.class) {
177 return unsafe.getBoolean(node, offset);
178 } else if (type == byte.class) {
179 return unsafe.getByte(node, offset);
180 } else if (type == short.class) {
181 return unsafe.getShort(node, offset);
182 } else if (type == char.class) {
183 return unsafe.getChar(node, offset);
184 } else if (type == int.class) {
185 return unsafe.getInt(node, offset);
186 } else if (type == long.class) {
187 return unsafe.getLong(node, offset);
188 } else if (type == float.class) {
189 return unsafe.getFloat(node, offset);
190 } else if (type == double.class) {
191 return unsafe.getDouble(node, offset);
192 } else {
193 return unsafe.getObject(node, offset);
194 }
195 }
196 }
197
198 private static final class ReflectionNodeField extends NodeField {
199 private final Field field;
200
201 protected ReflectionNodeField(NodeFieldKind kind, Field field) {
202 super(kind, field);
203 this.field = field;
204 field.setAccessible(true);
205 }
206
207 @Override
208 public void putObject(Node receiver, Object value) {
209 assert !type.isPrimitive() && value == null || type.isInstance(value);
210 try {
211 field.set(receiver, value);
212 } catch (IllegalAccessException e) {
213 throw new AssertionError(e);
214 }
215 }
216
217 @Override
218 public Object getObject(Node receiver) {
219 assert !type.isPrimitive();
220 try {
221 return field.get(receiver);
222 } catch (IllegalAccessException e) {
223 throw new AssertionError(e);
224 }
225 }
226
227 @Override
228 public Object loadValue(Node node) {
229 try {
230 if (type == boolean.class) {
231 return field.getBoolean(node);
232 } else if (type == byte.class) {
233 return field.getByte(node);
234 } else if (type == short.class) {
235 return field.getShort(node);
236 } else if (type == char.class) {
237 return field.getChar(node);
238 } else if (type == int.class) {
239 return field.getInt(node);
240 } else if (type == long.class) {
241 return field.getLong(node);
242 } else if (type == float.class) {
243 return field.getFloat(node);
244 } else if (type == double.class) {
245 return field.getDouble(node);
246 } else {
247 return field.get(node);
248 }
249 } catch (IllegalAccessException e) {
250 throw new AssertionError(e);
251 }
252 }
253 }
254
255 /**
256 * Information about a {@link Node} class. A single instance of this class is allocated for
257 * every subclass of {@link Node} that is used.
258 */
259 public static final class NodeClass {
260 private static final ClassValue<NodeClass> nodeClasses = new ClassValue<NodeClass>() {
261 @SuppressWarnings("unchecked")
262 @Override
263 protected NodeClass computeValue(final Class<?> clazz) {
264 assert Node.class.isAssignableFrom(clazz);
265 return AccessController.doPrivileged(new PrivilegedAction<NodeClass>() {
266 public NodeClass run() {
267 return new NodeClass((Class<? extends Node>) clazz);
268 }
269 });
270 }
271 };
272
273 // The comprehensive list of all fields.
274 private final NodeField[] fields;
275 // Separate arrays for the frequently accessed fields.
276 private final NodeField parentField;
277 private final NodeField[] childFields;
278 private final NodeField[] childrenFields;
279 private final NodeField[] cloneableFields;
280
281 private final Class<? extends Node> clazz;
282
283 public static NodeClass get(Class<? extends Node> clazz) {
284 return nodeClasses.get(clazz);
285 }
286
287 public NodeClass(Class<? extends Node> clazz) {
288 List<NodeField> fieldsList = new ArrayList<>();
289 NodeField parentFieldTmp = null;
290 List<NodeField> childFieldList = new ArrayList<>();
291 List<NodeField> childrenFieldList = new ArrayList<>();
292 List<NodeField> cloneableFieldList = new ArrayList<>();
293
294 for (Field field : getAllFields(clazz)) {
295 if (Modifier.isStatic(field.getModifiers()) || field.isSynthetic()) {
296 continue;
297 }
298
299 NodeField nodeField;
300 if (field.getDeclaringClass() == Node.class && field.getName().equals("parent")) {
301 assert Node.class.isAssignableFrom(field.getType());
302 nodeField = NodeField.create(NodeFieldKind.PARENT, field);
303 parentFieldTmp = nodeField;
304 } else if (field.getAnnotation(Child.class) != null) {
305 checkChildField(field);
306 nodeField = NodeField.create(NodeFieldKind.CHILD, field);
307 childFieldList.add(nodeField);
308 } else if (field.getAnnotation(Children.class) != null) {
309 checkChildrenField(field);
310 nodeField = NodeField.create(NodeFieldKind.CHILDREN, field);
311 childrenFieldList.add(nodeField);
312 } else {
313 nodeField = NodeField.create(NodeFieldKind.DATA, field);
314 if (NodeCloneable.class.isAssignableFrom(field.getType())) {
315 cloneableFieldList.add(nodeField);
316 }
317 }
318 fieldsList.add(nodeField);
319 }
320
321 if (parentFieldTmp == null) {
322 throw new AssertionError("parent field not found");
323 }
324
325 this.fields = fieldsList.toArray(new NodeField[fieldsList.size()]);
326 this.parentField = parentFieldTmp;
327 this.childFields = childFieldList.toArray(new NodeField[childFieldList.size()]);
328 this.childrenFields = childrenFieldList.toArray(new NodeField[childrenFieldList.size()]);
329 this.cloneableFields = cloneableFieldList.toArray(new NodeField[cloneableFieldList.size()]);
330 this.clazz = clazz;
331 }
332
333 private static boolean isNodeType(Class<?> clazz) {
334 return Node.class.isAssignableFrom(clazz) || (clazz.isInterface() && NodeInterface.class.isAssignableFrom(clazz));
335 }
336
337 private static void checkChildField(Field field) {
338 if (!isNodeType(field.getType())) {
339 throw new AssertionError("@Child field type must be a subclass of Node or an interface extending NodeInterface (" + field + ")");
340 }
341 if (Modifier.isFinal(field.getModifiers())) {
342 throw new AssertionError("@Child field must not be final (" + field + ")");
343 }
344 }
345
346 private static void checkChildrenField(Field field) {
347 if (!(field.getType().isArray() && isNodeType(field.getType().getComponentType()))) {
348 throw new AssertionError("@Children field type must be an array of a subclass of Node or an interface extending NodeInterface (" + field + ")");
349 }
350 if (!Modifier.isFinal(field.getModifiers())) {
351 throw new AssertionError("@Children field must be final (" + field + ")");
352 }
353 }
354
355 public NodeField[] getFields() {
356 return fields;
357 }
358
359 public NodeField getParentField() {
360 return parentField;
361 }
362
363 public NodeField[] getChildFields() {
364 return childFields;
365 }
366
367 public NodeField[] getChildrenFields() {
368 return childrenFields;
369 }
370
371 @Override
372 public int hashCode() {
373 return clazz.hashCode();
374 }
375
376 @Override
377 public boolean equals(Object obj) {
378 if (obj instanceof NodeClass) {
379 NodeClass other = (NodeClass) obj;
380 return clazz.equals(other.clazz);
381 }
382 return false;
383 }
384
385 public Iterator<Node> makeIterator(Node node) {
386 assert clazz.isInstance(node);
387 return new NodeIterator(node);
388 }
389
390 private final class NodeIterator implements Iterator<Node> {
391 private final Node node;
392 private final int childrenCount;
393 private int index;
394
395 protected NodeIterator(Node node) {
396 this.node = node;
397 this.index = 0;
398 this.childrenCount = childrenCount();
399 }
400
401 private int childrenCount() {
402 int nodeCount = childFields.length;
403 for (NodeField childrenField : childrenFields) {
404 Object[] children = ((Object[]) childrenField.getObject(node));
405 if (children != null) {
406 nodeCount += children.length;
407 }
408 }
409 return nodeCount;
410 }
411
412 private Node nodeAt(int idx) {
413 int nodeCount = childFields.length;
414 if (idx < nodeCount) {
415 return (Node) childFields[idx].getObject(node);
416 } else {
417 for (NodeField childrenField : childrenFields) {
418 Object[] nodeArray = (Object[]) childrenField.getObject(node);
419 if (idx < nodeCount + nodeArray.length) {
420 return (Node) nodeArray[idx - nodeCount];
421 }
422 nodeCount += nodeArray.length;
423 }
424 }
425 return null;
426 }
427
428 private void forward() {
429 if (index < childrenCount) {
430 index++;
431 }
432 }
433
434 public boolean hasNext() {
435 return index < childrenCount;
436 }
437
438 public Node next() {
439 try {
440 return nodeAt(index);
441 } finally {
442 forward();
443 }
444 }
445
446 public void remove() {
447 throw new UnsupportedOperationException();
448 }
449 }
450 } 54 }
451 55
452 static Iterator<Node> makeIterator(Node node) { 56 static Iterator<Node> makeIterator(Node node) {
453 return NodeClass.get(node.getClass()).makeIterator(node); 57 return NodeClass.get(node.getClass()).makeIterator(node);
454 } 58 }
519 public void remove() { 123 public void remove() {
520 throw new UnsupportedOperationException(); 124 throw new UnsupportedOperationException();
521 } 125 }
522 } 126 }
523 127
524 private static final Unsafe unsafe = getUnsafe();
525
526 private static Unsafe getUnsafe() {
527 try {
528 return Unsafe.getUnsafe();
529 } catch (SecurityException e) {
530 }
531 try {
532 Field theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe");
533 theUnsafeInstance.setAccessible(true);
534 return (Unsafe) theUnsafeInstance.get(Unsafe.class);
535 } catch (Exception e) {
536 throw new RuntimeException("exception while trying to get Unsafe.theUnsafe via reflection:", e);
537 }
538 }
539
540 @SuppressWarnings("unchecked") 128 @SuppressWarnings("unchecked")
541 public static <T extends Node> T cloneNode(T orig) { 129 public static <T extends Node> T cloneNode(T orig) {
542 return (T) orig.deepCopy(); 130 return (T) orig.deepCopy();
543 } 131 }
544 132
545 static Node deepCopyImpl(Node orig) { 133 static Node deepCopyImpl(Node orig) {
546 final Node clone = orig.copy(); 134 final Node clone = orig.copy();
547 NodeClass nodeClass = NodeClass.get(clone.getClass()); 135 NodeClass nodeClass = NodeClass.get(clone.getClass());
548 136
549 nodeClass.parentField.putObject(clone, null); 137 nodeClass.getParentField().putObject(clone, null);
550 138
551 for (NodeField childField : nodeClass.childFields) { 139 for (NodeFieldAccessor childField : nodeClass.getChildFields()) {
552 Node child = (Node) childField.getObject(orig); 140 Node child = (Node) childField.getObject(orig);
553 if (child != null) { 141 if (child != null) {
554 Node clonedChild = child.deepCopy(); 142 Node clonedChild = child.deepCopy();
555 nodeClass.parentField.putObject(clonedChild, clone); 143 nodeClass.getParentField().putObject(clonedChild, clone);
556 childField.putObject(clone, clonedChild); 144 childField.putObject(clone, clonedChild);
557 } 145 }
558 } 146 }
559 for (NodeField childrenField : nodeClass.childrenFields) { 147 for (NodeFieldAccessor childrenField : nodeClass.getChildrenFields()) {
560 Object[] children = (Object[]) childrenField.getObject(orig); 148 Object[] children = (Object[]) childrenField.getObject(orig);
561 if (children != null) { 149 if (children != null) {
562 Object[] clonedChildren = (Object[]) Array.newInstance(children.getClass().getComponentType(), children.length); 150 Object[] clonedChildren = (Object[]) Array.newInstance(children.getClass().getComponentType(), children.length);
563 for (int i = 0; i < children.length; i++) { 151 for (int i = 0; i < children.length; i++) {
564 if (children[i] != null) { 152 if (children[i] != null) {
565 Node clonedChild = ((Node) children[i]).deepCopy(); 153 Node clonedChild = ((Node) children[i]).deepCopy();
566 clonedChildren[i] = clonedChild; 154 clonedChildren[i] = clonedChild;
567 nodeClass.parentField.putObject(clonedChild, clone); 155 nodeClass.getParentField().putObject(clonedChild, clone);
568 } 156 }
569 } 157 }
570 childrenField.putObject(clone, clonedChildren); 158 childrenField.putObject(clone, clonedChildren);
571 } 159 }
572 } 160 }
573 for (NodeField cloneableField : nodeClass.cloneableFields) { 161 for (NodeFieldAccessor cloneableField : nodeClass.getCloneableFields()) {
574 Object cloneable = cloneableField.getObject(clone); 162 Object cloneable = cloneableField.getObject(clone);
575 if (cloneable != null && cloneable == cloneableField.getObject(orig)) { 163 if (cloneable != null && cloneable == cloneableField.getObject(orig)) {
576 cloneableField.putObject(clone, ((NodeCloneable) cloneable).clone()); 164 cloneableField.putObject(clone, ((NodeCloneable) cloneable).clone());
577 } 165 }
578 } 166 }
581 169
582 public static List<Node> findNodeChildren(Node node) { 170 public static List<Node> findNodeChildren(Node node) {
583 List<Node> nodes = new ArrayList<>(); 171 List<Node> nodes = new ArrayList<>();
584 NodeClass nodeClass = NodeClass.get(node.getClass()); 172 NodeClass nodeClass = NodeClass.get(node.getClass());
585 173
586 for (NodeField nodeField : nodeClass.childFields) { 174 for (NodeFieldAccessor nodeField : nodeClass.getChildFields()) {
587 Object child = nodeField.getObject(node); 175 Object child = nodeField.getObject(node);
588 if (child != null) { 176 if (child != null) {
589 nodes.add((Node) child); 177 nodes.add((Node) child);
590 } 178 }
591 } 179 }
592 for (NodeField nodeField : nodeClass.childrenFields) { 180 for (NodeFieldAccessor nodeField : nodeClass.getChildrenFields()) {
593 Object[] children = (Object[]) nodeField.getObject(node); 181 Object[] children = (Object[]) nodeField.getObject(node);
594 if (children != null) { 182 if (children != null) {
595 for (Object child : children) { 183 for (Object child : children) {
596 if (child != null) { 184 if (child != null) {
597 nodes.add((Node) child); 185 nodes.add((Node) child);
609 } 197 }
610 198
611 public static boolean replaceChild(Node parent, Node oldChild, Node newChild) { 199 public static boolean replaceChild(Node parent, Node oldChild, Node newChild) {
612 NodeClass nodeClass = NodeClass.get(parent.getClass()); 200 NodeClass nodeClass = NodeClass.get(parent.getClass());
613 201
614 for (NodeField nodeField : nodeClass.getChildFields()) { 202 for (NodeFieldAccessor nodeField : nodeClass.getChildFields()) {
615 if (nodeField.getObject(parent) == oldChild) { 203 if (nodeField.getObject(parent) == oldChild) {
616 assert assertAssignable(nodeField, newChild); 204 assert assertAssignable(nodeField, newChild);
617 nodeField.putObject(parent, newChild); 205 nodeField.putObject(parent, newChild);
618 return true; 206 return true;
619 } 207 }
620 } 208 }
621 209
622 for (NodeField nodeField : nodeClass.getChildrenFields()) { 210 for (NodeFieldAccessor nodeField : nodeClass.getChildrenFields()) {
623 Object arrayObject = nodeField.getObject(parent); 211 Object arrayObject = nodeField.getObject(parent);
624 if (arrayObject != null) { 212 if (arrayObject != null) {
625 Object[] array = (Object[]) arrayObject; 213 Object[] array = (Object[]) arrayObject;
626 for (int i = 0; i < array.length; i++) { 214 for (int i = 0; i < array.length; i++) {
627 if (array[i] == oldChild) { 215 if (array[i] == oldChild) {
633 } 221 }
634 } 222 }
635 return false; 223 return false;
636 } 224 }
637 225
638 private static boolean assertAssignable(NodeField field, Object newValue) { 226 private static boolean assertAssignable(NodeFieldAccessor field, Object newValue) {
639 if (newValue == null) { 227 if (newValue == null) {
640 return true; 228 return true;
641 } 229 }
642 if (field.getKind() == NodeFieldKind.CHILD) { 230 if (field.getKind() == NodeFieldKind.CHILD) {
643 if (field.getType().isAssignableFrom(newValue.getClass())) { 231 if (field.getType().isAssignableFrom(newValue.getClass())) {
660 /** 248 /**
661 * Finds the field in a parent node, if any, that holds a specified child node. 249 * Finds the field in a parent node, if any, that holds a specified child node.
662 * 250 *
663 * @return the field (possibly an array) holding the child, {@code null} if not found. 251 * @return the field (possibly an array) holding the child, {@code null} if not found.
664 */ 252 */
665 public static NodeField findChildField(Node parent, Node child) { 253 public static NodeFieldAccessor findChildField(Node parent, Node child) {
666 assert child != null; 254 assert child != null;
667 NodeClass parentNodeClass = NodeClass.get(parent.getClass()); 255 NodeClass parentNodeClass = NodeClass.get(parent.getClass());
668 256
669 for (NodeField field : parentNodeClass.getChildFields()) { 257 for (NodeFieldAccessor field : parentNodeClass.getChildFields()) {
670 if (field.getObject(parent) == child) { 258 if (field.getObject(parent) == child) {
671 return field; 259 return field;
672 } 260 }
673 } 261 }
674 262
675 for (NodeField field : parentNodeClass.getChildrenFields()) { 263 for (NodeFieldAccessor field : parentNodeClass.getChildrenFields()) {
676 Object arrayObject = field.getObject(parent); 264 Object arrayObject = field.getObject(parent);
677 if (arrayObject != null) { 265 if (arrayObject != null) {
678 Object[] array = (Object[]) arrayObject; 266 Object[] array = (Object[]) arrayObject;
679 for (int i = 0; i < array.length; i++) { 267 for (int i = 0; i < array.length; i++) {
680 if (array[i] == child) { 268 if (array[i] == child) {
690 * Determines whether a proposed child replacement would be safe: structurally and type. 278 * Determines whether a proposed child replacement would be safe: structurally and type.
691 */ 279 */
692 public static boolean isReplacementSafe(Node parent, Node oldChild, Node newChild) { 280 public static boolean isReplacementSafe(Node parent, Node oldChild, Node newChild) {
693 assert newChild != null; 281 assert newChild != null;
694 if (parent != null) { 282 if (parent != null) {
695 final NodeField field = findChildField(parent, oldChild); 283 final NodeFieldAccessor field = findChildField(parent, oldChild);
696 if (field != null) { 284 if (field != null) {
697 switch (field.getKind()) { 285 switch (field.getKind()) {
698 case CHILD: 286 case CHILD:
699 return field.getType().isAssignableFrom(newChild.getClass()); 287 return field.getType().isAssignableFrom(newChild.getClass());
700 case CHILDREN: 288 case CHILDREN:
714 */ 302 */
715 public static boolean forEachChild(Node parent, NodeVisitor visitor) { 303 public static boolean forEachChild(Node parent, NodeVisitor visitor) {
716 Objects.requireNonNull(visitor); 304 Objects.requireNonNull(visitor);
717 NodeClass parentNodeClass = NodeClass.get(parent.getClass()); 305 NodeClass parentNodeClass = NodeClass.get(parent.getClass());
718 306
719 for (NodeField field : parentNodeClass.getChildFields()) { 307 for (NodeFieldAccessor field : parentNodeClass.getChildFields()) {
720 Object child = field.getObject(parent); 308 Object child = field.getObject(parent);
721 if (child != null) { 309 if (child != null) {
722 if (!visitor.visit((Node) child)) { 310 if (!visitor.visit((Node) child)) {
723 return false; 311 return false;
724 } 312 }
725 } 313 }
726 } 314 }
727 315
728 for (NodeField field : parentNodeClass.getChildrenFields()) { 316 for (NodeFieldAccessor field : parentNodeClass.getChildrenFields()) {
729 Object arrayObject = field.getObject(parent); 317 Object arrayObject = field.getObject(parent);
730 if (arrayObject != null) { 318 if (arrayObject != null) {
731 Object[] array = (Object[]) arrayObject; 319 Object[] array = (Object[]) arrayObject;
732 for (int i = 0; i < array.length; i++) { 320 for (int i = 0; i < array.length; i++) {
733 Object child = array[i]; 321 Object child = array[i];
742 330
743 return true; 331 return true;
744 } 332 }
745 333
746 /** Returns all declared fields in the class hierarchy. */ 334 /** Returns all declared fields in the class hierarchy. */
747 private static Field[] getAllFields(Class<? extends Object> clazz) { 335 static Field[] getAllFields(Class<? extends Object> clazz) {
748 Field[] declaredFields = clazz.getDeclaredFields(); 336 Field[] declaredFields = clazz.getDeclaredFields();
749 if (clazz.getSuperclass() != null) { 337 if (clazz.getSuperclass() != null) {
750 return concat(getAllFields(clazz.getSuperclass()), declaredFields); 338 return concat(getAllFields(clazz.getSuperclass()), declaredFields);
751 } 339 }
752 return declaredFields; 340 return declaredFields;
974 } 562 }
975 p.flush(); 563 p.flush();
976 } 564 }
977 565
978 private static String getNodeFieldName(Node parent, Node node, String defaultName) { 566 private static String getNodeFieldName(Node parent, Node node, String defaultName) {
979 NodeField[] fields = NodeClass.get(parent.getClass()).fields; 567 NodeFieldAccessor[] fields = NodeClass.get(parent.getClass()).getFields();
980 for (NodeField field : fields) { 568 for (NodeFieldAccessor field : fields) {
981 Object value = field.loadValue(parent); 569 Object value = field.loadValue(parent);
982 if (field.getKind() == NodeFieldKind.CHILD && value == node) { 570 if (field.getKind() == NodeFieldKind.CHILD && value == node) {
983 return field.getName(); 571 return field.getName();
984 } else if (field.getKind() == NodeFieldKind.CHILDREN) { 572 } else if (field.getKind() == NodeFieldKind.CHILDREN) {
985 int index = 0; 573 int index = 0;
1051 return; 639 return;
1052 } 640 }
1053 641
1054 p.print(nodeName(node)); 642 p.print(nodeName(node));
1055 643
1056 ArrayList<NodeField> childFields = new ArrayList<>(); 644 ArrayList<NodeFieldAccessor> childFields = new ArrayList<>();
1057 String sep = ""; 645 String sep = "";
1058 p.print("("); 646 p.print("(");
1059 for (NodeField field : NodeClass.get(node.getClass()).fields) { 647 for (NodeFieldAccessor field : NodeClass.get(node.getClass()).getFields()) {
1060 if (field.getKind() == NodeFieldKind.CHILD || field.getKind() == NodeFieldKind.CHILDREN) { 648 if (field.getKind() == NodeFieldKind.CHILD || field.getKind() == NodeFieldKind.CHILDREN) {
1061 childFields.add(field); 649 childFields.add(field);
1062 } else if (field.getKind() == NodeFieldKind.DATA) { 650 } else if (field.getKind() == NodeFieldKind.DATA) {
1063 p.print(sep); 651 p.print(sep);
1064 sep = ", "; 652 sep = ", ";
1070 } 658 }
1071 p.print(")"); 659 p.print(")");
1072 660
1073 if (childFields.size() != 0) { 661 if (childFields.size() != 0) {
1074 p.print(" {"); 662 p.print(" {");
1075 for (NodeField field : childFields) { 663 for (NodeFieldAccessor field : childFields) {
1076 printNewLine(p, level); 664 printNewLine(p, level);
1077 p.print(field.getName()); 665 p.print(field.getName());
1078 666
1079 Object value = field.loadValue(node); 667 Object value = field.loadValue(node);
1080 if (value == null) { 668 if (value == null) {