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