Mercurial > hg > truffle
comparison graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java @ 18904:6ba170cb6f53
Truffle: channel all NodeUtil field accesses through NodeField class
author | Andreas Woess <andreas.woess@jku.at> |
---|---|
date | Thu, 22 Jan 2015 00:37:29 +0100 |
parents | e55e18c1f40d |
children | c46e268fd091 |
comparison
equal
deleted
inserted
replaced
18903:11ec0a5c5518 | 18904:6ba170cb6f53 |
---|---|
93 private final NodeFieldKind kind; | 93 private final NodeFieldKind kind; |
94 private final Class<?> type; | 94 private final Class<?> type; |
95 private final String name; | 95 private final String name; |
96 private long offset; | 96 private long offset; |
97 | 97 |
98 protected NodeField(NodeFieldKind kind, Class<?> type, String name, long offset) { | 98 private NodeField(NodeFieldKind kind, Field field) { |
99 this.kind = kind; | 99 this.kind = kind; |
100 this.type = type; | 100 this.type = field.getType(); |
101 this.name = name; | 101 this.name = field.getName(); |
102 this.offset = offset; | 102 this.offset = unsafeFieldOffsetProvider.objectFieldOffset(field); |
103 } | |
104 | |
105 protected static NodeField create(NodeFieldKind kind, Field field) { | |
106 return new NodeField(kind, field); | |
103 } | 107 } |
104 | 108 |
105 public NodeFieldKind getKind() { | 109 public NodeFieldKind getKind() { |
106 return kind; | 110 return kind; |
107 } | 111 } |
117 public long getOffset() { | 121 public long getOffset() { |
118 return offset; | 122 return offset; |
119 } | 123 } |
120 | 124 |
121 public void putObject(Object receiver, Object value) { | 125 public void putObject(Object receiver, Object value) { |
122 assert value == null || type.isInstance(value); | 126 assert !type.isPrimitive() && value == null || type.isInstance(value); |
123 unsafe.putObject(receiver, offset, value); | 127 unsafe.putObject(receiver, offset, value); |
128 } | |
129 | |
130 public Object getObject(Object receiver) { | |
131 assert !type.isPrimitive(); | |
132 return unsafe.getObject(receiver, offset); | |
124 } | 133 } |
125 | 134 |
126 public Object loadValue(Node node) { | 135 public Object loadValue(Node node) { |
127 if (type == boolean.class) { | 136 if (type == boolean.class) { |
128 return unsafe.getBoolean(node, offset); | 137 return unsafe.getBoolean(node, offset); |
170 @Override | 179 @Override |
171 protected NodeClass computeValue(final Class<?> clazz) { | 180 protected NodeClass computeValue(final Class<?> clazz) { |
172 assert Node.class.isAssignableFrom(clazz); | 181 assert Node.class.isAssignableFrom(clazz); |
173 return AccessController.doPrivileged(new PrivilegedAction<NodeClass>() { | 182 return AccessController.doPrivileged(new PrivilegedAction<NodeClass>() { |
174 public NodeClass run() { | 183 public NodeClass run() { |
175 return new NodeClass((Class<? extends Node>) clazz, unsafeFieldOffsetProvider); | 184 return new NodeClass((Class<? extends Node>) clazz); |
176 } | 185 } |
177 }); | 186 }); |
178 } | 187 } |
179 }; | 188 }; |
180 | 189 |
181 // The comprehensive list of all fields. | 190 // The comprehensive list of all fields. |
182 private final NodeField[] fields; | 191 private final NodeField[] fields; |
183 // Separate arrays for the frequently accessed field offsets. | 192 // Separate arrays for the frequently accessed fields. |
184 private final long parentOffset; | 193 private final NodeField parentField; |
185 private final long[] childOffsets; | 194 private final NodeField[] childFields; |
186 private final long[] childrenOffsets; | 195 private final NodeField[] childrenFields; |
187 private final long[] cloneableOffsets; | 196 private final NodeField[] cloneableFields; |
197 | |
188 private final Class<? extends Node> clazz; | 198 private final Class<? extends Node> clazz; |
189 | 199 |
190 public static NodeClass get(Class<? extends Node> clazz) { | 200 public static NodeClass get(Class<? extends Node> clazz) { |
191 return nodeClasses.get(clazz); | 201 return nodeClasses.get(clazz); |
192 } | 202 } |
193 | 203 |
194 public NodeClass(Class<? extends Node> clazz, FieldOffsetProvider fieldOffsetProvider) { | 204 public NodeClass(Class<? extends Node> clazz) { |
195 List<NodeField> fieldsList = new ArrayList<>(); | 205 List<NodeField> fieldsList = new ArrayList<>(); |
196 long parentFieldOffset = -1; | 206 NodeField parentFieldTmp = null; |
197 List<Long> childOffsetsList = new ArrayList<>(); | 207 List<NodeField> childFieldList = new ArrayList<>(); |
198 List<Long> childrenOffsetsList = new ArrayList<>(); | 208 List<NodeField> childrenFieldList = new ArrayList<>(); |
199 List<Long> cloneableOffsetsList = new ArrayList<>(); | 209 List<NodeField> cloneableFieldList = new ArrayList<>(); |
200 | 210 |
201 for (Field field : getAllFields(clazz)) { | 211 for (Field field : getAllFields(clazz)) { |
202 if (Modifier.isStatic(field.getModifiers()) || field.isSynthetic()) { | 212 if (Modifier.isStatic(field.getModifiers()) || field.isSynthetic()) { |
203 continue; | 213 continue; |
204 } | 214 } |
205 | 215 |
206 NodeFieldKind kind; | 216 NodeField nodeField; |
207 if (field.getDeclaringClass() == Node.class && field.getName().equals("parent")) { | 217 if (field.getDeclaringClass() == Node.class && field.getName().equals("parent")) { |
208 assert Node.class.isAssignableFrom(field.getType()); | 218 assert Node.class.isAssignableFrom(field.getType()); |
209 kind = NodeFieldKind.PARENT; | 219 nodeField = NodeField.create(NodeFieldKind.PARENT, field); |
210 parentFieldOffset = fieldOffsetProvider.objectFieldOffset(field); | 220 parentFieldTmp = nodeField; |
211 } else if (field.getAnnotation(Child.class) != null) { | 221 } else if (field.getAnnotation(Child.class) != null) { |
212 checkChildField(field); | 222 checkChildField(field); |
213 kind = NodeFieldKind.CHILD; | 223 nodeField = NodeField.create(NodeFieldKind.CHILD, field); |
214 childOffsetsList.add(fieldOffsetProvider.objectFieldOffset(field)); | 224 childFieldList.add(nodeField); |
215 } else if (field.getAnnotation(Children.class) != null) { | 225 } else if (field.getAnnotation(Children.class) != null) { |
216 checkChildrenField(field); | 226 checkChildrenField(field); |
217 kind = NodeFieldKind.CHILDREN; | 227 nodeField = NodeField.create(NodeFieldKind.CHILDREN, field); |
218 childrenOffsetsList.add(fieldOffsetProvider.objectFieldOffset(field)); | 228 childrenFieldList.add(nodeField); |
219 } else if (NodeCloneable.class.isAssignableFrom(field.getType())) { | |
220 kind = NodeFieldKind.DATA; | |
221 cloneableOffsetsList.add(fieldOffsetProvider.objectFieldOffset(field)); | |
222 } else { | 229 } else { |
223 kind = NodeFieldKind.DATA; | 230 nodeField = NodeField.create(NodeFieldKind.DATA, field); |
224 } | 231 if (NodeCloneable.class.isAssignableFrom(field.getType())) { |
225 fieldsList.add(new NodeField(kind, field.getType(), field.getName(), fieldOffsetProvider.objectFieldOffset(field))); | 232 cloneableFieldList.add(nodeField); |
226 } | 233 } |
227 | 234 } |
228 if (parentFieldOffset < 0) { | 235 fieldsList.add(nodeField); |
236 } | |
237 | |
238 if (parentFieldTmp == null) { | |
229 throw new AssertionError("parent field not found"); | 239 throw new AssertionError("parent field not found"); |
230 } | 240 } |
231 | 241 |
232 this.fields = fieldsList.toArray(new NodeField[fieldsList.size()]); | 242 this.fields = fieldsList.toArray(new NodeField[fieldsList.size()]); |
233 this.parentOffset = parentFieldOffset; | 243 this.parentField = parentFieldTmp; |
234 this.childOffsets = toLongArray(childOffsetsList); | 244 this.childFields = childFieldList.toArray(new NodeField[childFieldList.size()]); |
235 this.childrenOffsets = toLongArray(childrenOffsetsList); | 245 this.childrenFields = childrenFieldList.toArray(new NodeField[childrenFieldList.size()]); |
236 this.cloneableOffsets = toLongArray(cloneableOffsetsList); | 246 this.cloneableFields = cloneableFieldList.toArray(new NodeField[cloneableFieldList.size()]); |
237 this.clazz = clazz; | 247 this.clazz = clazz; |
238 } | 248 } |
239 | 249 |
240 private static boolean isNodeType(Class<?> clazz) { | 250 private static boolean isNodeType(Class<?> clazz) { |
241 return Node.class.isAssignableFrom(clazz) || (clazz.isInterface() && NodeInterface.class.isAssignableFrom(clazz)); | 251 return Node.class.isAssignableFrom(clazz) || (clazz.isInterface() && NodeInterface.class.isAssignableFrom(clazz)); |
261 | 271 |
262 public NodeField[] getFields() { | 272 public NodeField[] getFields() { |
263 return fields; | 273 return fields; |
264 } | 274 } |
265 | 275 |
266 public long getParentOffset() { | 276 public NodeField getParentField() { |
267 return parentOffset; | 277 return parentField; |
268 } | 278 } |
269 | 279 |
270 public long[] getChildOffsets() { | 280 public NodeField[] getChildFields() { |
271 return childOffsets; | 281 return childFields; |
272 } | 282 } |
273 | 283 |
274 public long[] getChildrenOffsets() { | 284 public NodeField[] getChildrenFields() { |
275 return childrenOffsets; | 285 return childrenFields; |
276 } | 286 } |
277 | 287 |
278 @Override | 288 @Override |
279 public int hashCode() { | 289 public int hashCode() { |
280 return Arrays.hashCode(fields) ^ Arrays.hashCode(childOffsets) ^ Arrays.hashCode(childrenOffsets) ^ ((Long) parentOffset).hashCode(); | 290 return clazz.hashCode(); |
281 } | 291 } |
282 | 292 |
283 @Override | 293 @Override |
284 public boolean equals(Object obj) { | 294 public boolean equals(Object obj) { |
285 if (obj instanceof NodeClass) { | 295 if (obj instanceof NodeClass) { |
286 NodeClass other = (NodeClass) obj; | 296 NodeClass other = (NodeClass) obj; |
287 return Arrays.equals(fields, other.fields) && Arrays.equals(childOffsets, other.childOffsets) && Arrays.equals(childrenOffsets, other.childrenOffsets) && | 297 return clazz.equals(other.clazz); |
288 parentOffset == other.parentOffset; | |
289 } | 298 } |
290 return false; | 299 return false; |
291 } | 300 } |
292 | 301 |
293 public Iterator<Node> makeIterator(Node node) { | 302 public Iterator<Node> makeIterator(Node node) { |
305 this.index = 0; | 314 this.index = 0; |
306 this.childrenCount = childrenCount(); | 315 this.childrenCount = childrenCount(); |
307 } | 316 } |
308 | 317 |
309 private int childrenCount() { | 318 private int childrenCount() { |
310 int nodeCount = childOffsets.length; | 319 int nodeCount = childFields.length; |
311 for (long fieldOffset : childrenOffsets) { | 320 for (NodeField childrenField : childrenFields) { |
312 Object[] children = ((Object[]) unsafe.getObject(node, fieldOffset)); | 321 Object[] children = ((Object[]) childrenField.getObject(node)); |
313 if (children != null) { | 322 if (children != null) { |
314 nodeCount += children.length; | 323 nodeCount += children.length; |
315 } | 324 } |
316 } | 325 } |
317 return nodeCount; | 326 return nodeCount; |
318 } | 327 } |
319 | 328 |
320 private Node nodeAt(int idx) { | 329 private Node nodeAt(int idx) { |
321 int nodeCount = childOffsets.length; | 330 int nodeCount = childFields.length; |
322 if (idx < nodeCount) { | 331 if (idx < nodeCount) { |
323 return (Node) unsafe.getObject(node, childOffsets[idx]); | 332 return (Node) childFields[idx].getObject(node); |
324 } else { | 333 } else { |
325 for (long fieldOffset : childrenOffsets) { | 334 for (NodeField childrenField : childrenFields) { |
326 Object[] nodeArray = (Object[]) unsafe.getObject(node, fieldOffset); | 335 Object[] nodeArray = (Object[]) childrenField.getObject(node); |
327 if (idx < nodeCount + nodeArray.length) { | 336 if (idx < nodeCount + nodeArray.length) { |
328 return (Node) nodeArray[idx - nodeCount]; | 337 return (Node) nodeArray[idx - nodeCount]; |
329 } | 338 } |
330 nodeCount += nodeArray.length; | 339 nodeCount += nodeArray.length; |
331 } | 340 } |
427 public void remove() { | 436 public void remove() { |
428 throw new UnsupportedOperationException(); | 437 throw new UnsupportedOperationException(); |
429 } | 438 } |
430 } | 439 } |
431 | 440 |
432 private static long[] toLongArray(List<Long> list) { | |
433 long[] array = new long[list.size()]; | |
434 for (int i = 0; i < list.size(); i++) { | |
435 array[i] = list.get(i); | |
436 } | |
437 return array; | |
438 } | |
439 | |
440 private static final Unsafe unsafe = getUnsafe(); | 441 private static final Unsafe unsafe = getUnsafe(); |
441 | 442 |
442 private static Unsafe getUnsafe() { | 443 private static Unsafe getUnsafe() { |
443 try { | 444 try { |
444 return Unsafe.getUnsafe(); | 445 return Unsafe.getUnsafe(); |
460 | 461 |
461 static Node deepCopyImpl(Node orig) { | 462 static Node deepCopyImpl(Node orig) { |
462 final Node clone = orig.copy(); | 463 final Node clone = orig.copy(); |
463 NodeClass nodeClass = NodeClass.get(clone.getClass()); | 464 NodeClass nodeClass = NodeClass.get(clone.getClass()); |
464 | 465 |
465 unsafe.putObject(clone, nodeClass.parentOffset, null); | 466 nodeClass.parentField.putObject(clone, null); |
466 | 467 |
467 for (long fieldOffset : nodeClass.childOffsets) { | 468 for (NodeField childField : nodeClass.childFields) { |
468 Node child = (Node) unsafe.getObject(orig, fieldOffset); | 469 Node child = (Node) childField.getObject(orig); |
469 if (child != null) { | 470 if (child != null) { |
470 Node clonedChild = child.deepCopy(); | 471 Node clonedChild = child.deepCopy(); |
471 unsafe.putObject(clonedChild, nodeClass.parentOffset, clone); | 472 nodeClass.parentField.putObject(clonedChild, clone); |
472 unsafe.putObject(clone, fieldOffset, clonedChild); | 473 childField.putObject(clone, clonedChild); |
473 } | 474 } |
474 } | 475 } |
475 for (long fieldOffset : nodeClass.childrenOffsets) { | 476 for (NodeField childrenField : nodeClass.childrenFields) { |
476 Object[] children = (Object[]) unsafe.getObject(orig, fieldOffset); | 477 Object[] children = (Object[]) childrenField.getObject(orig); |
477 if (children != null) { | 478 if (children != null) { |
478 Object[] clonedChildren = (Object[]) Array.newInstance(children.getClass().getComponentType(), children.length); | 479 Object[] clonedChildren = (Object[]) Array.newInstance(children.getClass().getComponentType(), children.length); |
479 for (int i = 0; i < children.length; i++) { | 480 for (int i = 0; i < children.length; i++) { |
480 if (children[i] != null) { | 481 if (children[i] != null) { |
481 Node clonedChild = ((Node) children[i]).deepCopy(); | 482 Node clonedChild = ((Node) children[i]).deepCopy(); |
482 clonedChildren[i] = clonedChild; | 483 clonedChildren[i] = clonedChild; |
483 unsafe.putObject(clonedChild, nodeClass.parentOffset, clone); | 484 nodeClass.parentField.putObject(clonedChild, clone); |
484 } | 485 } |
485 } | 486 } |
486 unsafe.putObject(clone, fieldOffset, clonedChildren); | 487 childrenField.putObject(clone, clonedChildren); |
487 } | 488 } |
488 } | 489 } |
489 for (long fieldOffset : nodeClass.cloneableOffsets) { | 490 for (NodeField cloneableField : nodeClass.cloneableFields) { |
490 Object cloneable = unsafe.getObject(clone, fieldOffset); | 491 Object cloneable = cloneableField.getObject(clone); |
491 if (cloneable != null && cloneable == unsafe.getObject(orig, fieldOffset)) { | 492 if (cloneable != null && cloneable == cloneableField.getObject(orig)) { |
492 unsafe.putObject(clone, fieldOffset, ((NodeCloneable) cloneable).clone()); | 493 cloneableField.putObject(clone, ((NodeCloneable) cloneable).clone()); |
493 } | 494 } |
494 } | 495 } |
495 return clone; | 496 return clone; |
496 } | 497 } |
497 | 498 |
498 public static List<Node> findNodeChildren(Node node) { | 499 public static List<Node> findNodeChildren(Node node) { |
499 List<Node> nodes = new ArrayList<>(); | 500 List<Node> nodes = new ArrayList<>(); |
500 NodeClass nodeClass = NodeClass.get(node.getClass()); | 501 NodeClass nodeClass = NodeClass.get(node.getClass()); |
501 | 502 |
502 for (long fieldOffset : nodeClass.childOffsets) { | 503 for (NodeField nodeField : nodeClass.childFields) { |
503 Object child = unsafe.getObject(node, fieldOffset); | 504 Object child = nodeField.getObject(node); |
504 if (child != null) { | 505 if (child != null) { |
505 nodes.add((Node) child); | 506 nodes.add((Node) child); |
506 } | 507 } |
507 } | 508 } |
508 for (long fieldOffset : nodeClass.childrenOffsets) { | 509 for (NodeField nodeField : nodeClass.childrenFields) { |
509 Object[] children = (Object[]) unsafe.getObject(node, fieldOffset); | 510 Object[] children = (Object[]) nodeField.getObject(node); |
510 if (children != null) { | 511 if (children != null) { |
511 for (Object child : children) { | 512 for (Object child : children) { |
512 if (child != null) { | 513 if (child != null) { |
513 nodes.add((Node) child); | 514 nodes.add((Node) child); |
514 } | 515 } |
520 } | 521 } |
521 | 522 |
522 public static boolean replaceChild(Node parent, Node oldChild, Node newChild) { | 523 public static boolean replaceChild(Node parent, Node oldChild, Node newChild) { |
523 NodeClass nodeClass = NodeClass.get(parent.getClass()); | 524 NodeClass nodeClass = NodeClass.get(parent.getClass()); |
524 | 525 |
525 for (long fieldOffset : nodeClass.getChildOffsets()) { | 526 for (NodeField nodeField : nodeClass.getChildFields()) { |
526 if (unsafe.getObject(parent, fieldOffset) == oldChild) { | 527 if (nodeField.getObject(parent) == oldChild) { |
527 assert assertAssignable(nodeClass, fieldOffset, newChild); | 528 assert assertAssignable(nodeField, newChild); |
528 unsafe.putObject(parent, fieldOffset, newChild); | 529 nodeField.putObject(parent, newChild); |
529 return true; | 530 return true; |
530 } | 531 } |
531 } | 532 } |
532 | 533 |
533 for (long fieldOffset : nodeClass.getChildrenOffsets()) { | 534 for (NodeField nodeField : nodeClass.getChildrenFields()) { |
534 Object arrayObject = unsafe.getObject(parent, fieldOffset); | 535 Object arrayObject = nodeField.getObject(parent); |
535 if (arrayObject != null) { | 536 if (arrayObject != null) { |
536 Object[] array = (Object[]) arrayObject; | 537 Object[] array = (Object[]) arrayObject; |
537 for (int i = 0; i < array.length; i++) { | 538 for (int i = 0; i < array.length; i++) { |
538 if (array[i] == oldChild) { | 539 if (array[i] == oldChild) { |
539 assert assertAssignable(nodeClass, fieldOffset, newChild); | 540 assert assertAssignable(nodeField, newChild); |
540 array[i] = newChild; | 541 array[i] = newChild; |
541 return true; | 542 return true; |
542 } | 543 } |
543 } | 544 } |
544 } | 545 } |
545 } | 546 } |
546 return false; | 547 return false; |
547 } | 548 } |
548 | 549 |
549 private static boolean assertAssignable(NodeClass clazz, long fieldOffset, Object newValue) { | 550 private static boolean assertAssignable(NodeField field, Object newValue) { |
550 if (newValue == null) { | 551 if (newValue == null) { |
551 return true; | 552 return true; |
552 } | 553 } |
553 for (NodeField field : clazz.getFields()) { | 554 if (field.getKind() == NodeFieldKind.CHILD) { |
554 if (field.getOffset() == fieldOffset) { | 555 if (field.getType().isAssignableFrom(newValue.getClass())) { |
555 if (field.getKind() == NodeFieldKind.CHILD) { | 556 return true; |
556 if (field.getType().isAssignableFrom(newValue.getClass())) { | 557 } else { |
557 return true; | 558 assert false : "Child class " + newValue.getClass().getName() + " is not assignable to field \"" + field.getName() + "\" of type " + field.getType().getName(); |
558 } else { | 559 return false; |
559 assert false : "Child class " + newValue.getClass().getName() + " is not assignable to field \"" + field.getName() + "\" of type " + field.getType().getName(); | 560 } |
560 return false; | 561 } else if (field.getKind() == NodeFieldKind.CHILDREN) { |
561 } | 562 if (field.getType().getComponentType().isAssignableFrom(newValue.getClass())) { |
562 } else if (field.getKind() == NodeFieldKind.CHILDREN) { | 563 return true; |
563 if (field.getType().getComponentType().isAssignableFrom(newValue.getClass())) { | 564 } else { |
564 return true; | 565 assert false : "Child class " + newValue.getClass().getName() + " is not assignable to field \"" + field.getName() + "\" of type " + field.getType().getName(); |
565 } else { | 566 return false; |
566 assert false : "Child class " + newValue.getClass().getName() + " is not assignable to field \"" + field.getName() + "\" of type " + field.getType().getName(); | |
567 return false; | |
568 } | |
569 } | |
570 } | 567 } |
571 } | 568 } |
572 throw new IllegalArgumentException(); | 569 throw new IllegalArgumentException(); |
573 } | 570 } |
574 | 571 |