Mercurial > hg > truffle
comparison graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java @ 18984:0f462015296f
Truffle: Additions to NodeUtil to support optional "safe" AST node replacement (and diagnostics when unsafe)
author | Michael Van De Vanter <michael.van.de.vanter@oracle.com> |
---|---|
date | Tue, 27 Jan 2015 20:23:13 -0800 |
parents | c46e268fd091 |
children | 3bf612703773 |
comparison
equal
deleted
inserted
replaced
18983:43baadc1913a | 18984:0f462015296f |
---|---|
1 /* | 1 /* |
2 * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. | 2 * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * | 4 * |
5 * This code is free software; you can redistribute it and/or modify it | 5 * This code is free software; you can redistribute it and/or modify it |
6 * under the terms of the GNU General Public License version 2 only, as | 6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. Oracle designates this | 7 * published by the Free Software Foundation. Oracle designates this |
360 | 360 |
361 public NodeField[] getChildrenFields() { | 361 public NodeField[] getChildrenFields() { |
362 return childrenFields; | 362 return childrenFields; |
363 } | 363 } |
364 | 364 |
365 public NodeField findField(long fieldOffset) { | |
366 for (NodeField field : getFields()) { | |
367 if (field.getOffset() == fieldOffset) { | |
368 return field; | |
369 } | |
370 } | |
371 return null; | |
372 } | |
373 | |
365 @Override | 374 @Override |
366 public int hashCode() { | 375 public int hashCode() { |
367 return clazz.hashCode(); | 376 return clazz.hashCode(); |
368 } | 377 } |
369 | 378 |
642 assert false : "Child class " + newValue.getClass().getName() + " is not assignable to field \"" + field.getName() + "\" of type " + field.getType().getName(); | 651 assert false : "Child class " + newValue.getClass().getName() + " is not assignable to field \"" + field.getName() + "\" of type " + field.getType().getName(); |
643 return false; | 652 return false; |
644 } | 653 } |
645 } | 654 } |
646 throw new IllegalArgumentException(); | 655 throw new IllegalArgumentException(); |
656 } | |
657 | |
658 /** | |
659 * Finds the field in a parent node, if any, that holds a specified child node. | |
660 * | |
661 * @return the field (possibly an array) holding the child, {@code null} if not found. | |
662 */ | |
663 public static NodeField findChildField(Node parent, Node child) { | |
664 assert child != null; | |
665 NodeClass parentNodeClass = NodeClass.get(parent.getClass()); | |
666 | |
667 for (NodeField field : parentNodeClass.getChildFields()) { | |
668 final long fieldOffset = field.getOffset(); | |
669 if (unsafe.getObject(parent, fieldOffset) == child) { | |
670 return parentNodeClass.findField(fieldOffset); | |
671 } | |
672 } | |
673 | |
674 for (NodeField field : parentNodeClass.getChildrenFields()) { | |
675 final long fieldOffset = field.getOffset(); | |
676 Object arrayObject = unsafe.getObject(parent, fieldOffset); | |
677 if (arrayObject != null) { | |
678 Object[] array = (Object[]) arrayObject; | |
679 for (int i = 0; i < array.length; i++) { | |
680 if (array[i] == child) { | |
681 return parentNodeClass.findField(fieldOffset); | |
682 } | |
683 } | |
684 } | |
685 } | |
686 return null; | |
687 } | |
688 | |
689 /** | |
690 * Determines whether a proposed child replacement would be type safe. | |
691 * | |
692 * @param parent non-null node | |
693 * @param oldChild non-null existing child of parent | |
694 * @param newChild non-null proposed replacement for existing child | |
695 */ | |
696 public static boolean isReplacementSafe(Node parent, Node oldChild, Node newChild) { | |
697 assert newChild != null; | |
698 final NodeField field = findChildField(parent, oldChild); | |
699 if (field == null) { | |
700 throw new IllegalArgumentException(); | |
701 } | |
702 switch (field.getKind()) { | |
703 case CHILD: | |
704 return field.getType().isAssignableFrom(newChild.getClass()); | |
705 case CHILDREN: | |
706 return field.getType().getComponentType().isAssignableFrom(newChild.getClass()); | |
707 default: | |
708 throw new IllegalArgumentException(); | |
709 } | |
647 } | 710 } |
648 | 711 |
649 /** Returns all declared fields in the class hierarchy. */ | 712 /** Returns all declared fields in the class hierarchy. */ |
650 private static Field[] getAllFields(Class<? extends Object> clazz) { | 713 private static Field[] getAllFields(Class<? extends Object> clazz) { |
651 Field[] declaredFields = clazz.getDeclaredFields(); | 714 Field[] declaredFields = clazz.getDeclaredFields(); |