changeset 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 43baadc1913a
children 867058575979
files graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java
diffstat 1 files changed, 64 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java	Tue Jan 27 15:47:34 2015 -0800
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java	Tue Jan 27 20:23:13 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -362,6 +362,15 @@
             return childrenFields;
         }
 
+        public NodeField findField(long fieldOffset) {
+            for (NodeField field : getFields()) {
+                if (field.getOffset() == fieldOffset) {
+                    return field;
+                }
+            }
+            return null;
+        }
+
         @Override
         public int hashCode() {
             return clazz.hashCode();
@@ -646,6 +655,60 @@
         throw new IllegalArgumentException();
     }
 
+    /**
+     * Finds the field in a parent node, if any, that holds a specified child node.
+     *
+     * @return the field (possibly an array) holding the child, {@code null} if not found.
+     */
+    public static NodeField findChildField(Node parent, Node child) {
+        assert child != null;
+        NodeClass parentNodeClass = NodeClass.get(parent.getClass());
+
+        for (NodeField field : parentNodeClass.getChildFields()) {
+            final long fieldOffset = field.getOffset();
+            if (unsafe.getObject(parent, fieldOffset) == child) {
+                return parentNodeClass.findField(fieldOffset);
+            }
+        }
+
+        for (NodeField field : parentNodeClass.getChildrenFields()) {
+            final long fieldOffset = field.getOffset();
+            Object arrayObject = unsafe.getObject(parent, fieldOffset);
+            if (arrayObject != null) {
+                Object[] array = (Object[]) arrayObject;
+                for (int i = 0; i < array.length; i++) {
+                    if (array[i] == child) {
+                        return parentNodeClass.findField(fieldOffset);
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Determines whether a proposed child replacement would be type safe.
+     *
+     * @param parent non-null node
+     * @param oldChild non-null existing child of parent
+     * @param newChild non-null proposed replacement for existing child
+     */
+    public static boolean isReplacementSafe(Node parent, Node oldChild, Node newChild) {
+        assert newChild != null;
+        final NodeField field = findChildField(parent, oldChild);
+        if (field == null) {
+            throw new IllegalArgumentException();
+        }
+        switch (field.getKind()) {
+            case CHILD:
+                return field.getType().isAssignableFrom(newChild.getClass());
+            case CHILDREN:
+                return field.getType().getComponentType().isAssignableFrom(newChild.getClass());
+            default:
+                throw new IllegalArgumentException();
+        }
+    }
+
     /** Returns all declared fields in the class hierarchy. */
     private static Field[] getAllFields(Class<? extends Object> clazz) {
         Field[] declaredFields = clazz.getDeclaredFields();