changeset 17238:45c8f71196ec

Merge
author Stefan Anzinger <stefan.anzinger@oracle.com>
date Fri, 26 Sep 2014 10:41:19 -0700
parents c990248e816e (current diff) fd0f5f9abb79 (diff)
children d1cc47f5b1dd
files graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/EdgesSubstitutions.java
diffstat 15 files changed, 659 insertions(+), 357 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/FieldIntrospection.java	Fri Sep 26 10:40:34 2014 -0700
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/FieldIntrospection.java	Fri Sep 26 10:41:19 2014 -0700
@@ -29,8 +29,7 @@
 public abstract class FieldIntrospection extends UnsafeAccess {
 
     /**
-     * Interface used by {@link #rescanAllFieldOffsets(CalcOffset)} to determine the offset (in
-     * bytes) of a field.
+     * Interface used to determine the offset (in bytes) of a field.
      */
     public interface CalcOffset {
 
@@ -60,14 +59,6 @@
         return clazz;
     }
 
-    public static void rescanAllFieldOffsets(CalcOffset calc) {
-        for (FieldIntrospection nodeClass : allClasses.values()) {
-            nodeClass.rescanFieldOffsets(calc);
-        }
-    }
-
-    protected abstract void rescanFieldOffsets(CalcOffset calc);
-
     public abstract static class BaseFieldScanner {
 
         private final CalcOffset calc;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/Fields.java	Fri Sep 26 10:41:19 2014 -0700
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2014, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.common;
+
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
+
+import java.util.*;
+
+import sun.misc.*;
+
+/**
+ * Describes fields in a class, primarily for access via {@link Unsafe}.
+ */
+public class Fields {
+
+    protected final Class<?> clazz;
+    protected final long[] offsets;
+    private final String[] names;
+    private final Class<?>[] types;
+
+    public Fields(Class<?> clazz, long[] offsets, Map<Long, String> names, Map<Long, Class<?>> types) {
+        this.clazz = clazz;
+        this.offsets = offsets;
+
+        this.names = new String[offsets.length];
+        this.types = new Class[offsets.length];
+        for (int i = 0; i < offsets.length; i++) {
+            this.names[i] = names.get(offsets[i]);
+            this.types[i] = types.get(offsets[i]);
+        }
+    }
+
+    /**
+     * Gets the number of fields represented by this object.
+     */
+    public int getCount() {
+        return offsets.length;
+    }
+
+    /**
+     * Gets the value of a field for a given object.
+     *
+     * @param object the object whose field is to be read
+     * @param index the index of the field (between 0 and {@link #getCount()})
+     * @return the value of the specified field which will be boxed if the field type is primitive
+     */
+    public Object get(Object object, int index) {
+        long offset = offsets[index];
+        Class<?> type = types[index];
+        Object value = null;
+        if (type.isPrimitive()) {
+            if (type == Integer.TYPE) {
+                value = unsafe.getInt(object, offset);
+            } else if (type == Long.TYPE) {
+                value = unsafe.getLong(object, offset);
+            } else if (type == Boolean.TYPE) {
+                value = unsafe.getBoolean(object, offset);
+            } else if (type == Float.TYPE) {
+                value = unsafe.getFloat(object, offset);
+            } else if (type == Double.TYPE) {
+                value = unsafe.getDouble(object, offset);
+            } else if (type == Short.TYPE) {
+                value = unsafe.getShort(object, offset);
+            } else if (type == Character.TYPE) {
+                value = unsafe.getChar(object, offset);
+            } else if (type == Byte.TYPE) {
+                value = unsafe.getByte(object, offset);
+            } else {
+                assert false : "unhandled property type: " + type;
+            }
+        } else {
+            value = unsafe.getObject(object, offset);
+        }
+        return value;
+    }
+
+    /**
+     * Determines if a field in the domain of this object is the same as the field denoted by the
+     * same index in another {@link Fields} object.
+     */
+    public boolean isSame(Fields other, int index) {
+        return other.offsets[index] == offsets[index];
+    }
+
+    /**
+     * Gets the name of a field.
+     *
+     * @param index index of a field
+     */
+    public String getName(int index) {
+        return names[index];
+    }
+
+    /**
+     * Gets the type of a field.
+     *
+     * @param index index of a field
+     */
+    public Class<?> getType(int index) {
+        return types[index];
+    }
+
+    /**
+     * Checks that a given field is assignable from a given value.
+     *
+     * @param index the index of the field to check
+     * @param value a value that will be assigned to the field
+     */
+    private boolean checkAssignableFrom(int index, Object value) {
+        assert value == null || getType(index).isAssignableFrom(value.getClass()) : String.format("%s.%s of type %s is not assignable from %s", clazz.getSimpleName(), getName(index),
+                        getType(index).getSimpleName(), value.getClass().getSimpleName());
+        return true;
+    }
+
+    public void set(Object object, int index, Object value) {
+        long dataOffset = offsets[index];
+        Class<?> type = types[index];
+        if (type.isPrimitive()) {
+            if (type == Integer.TYPE) {
+                unsafe.putInt(object, dataOffset, (Integer) value);
+            } else if (type == Long.TYPE) {
+                unsafe.putLong(object, dataOffset, (Long) value);
+            } else if (type == Boolean.TYPE) {
+                unsafe.putBoolean(object, dataOffset, (Boolean) value);
+            } else if (type == Float.TYPE) {
+                unsafe.putFloat(object, dataOffset, (Float) value);
+            } else if (type == Double.TYPE) {
+                unsafe.putDouble(object, dataOffset, (Double) value);
+            } else if (type == Short.TYPE) {
+                unsafe.putShort(object, dataOffset, (Short) value);
+            } else if (type == Character.TYPE) {
+                unsafe.putChar(object, dataOffset, (Character) value);
+            } else if (type == Byte.TYPE) {
+                unsafe.putByte(object, dataOffset, (Byte) value);
+            } else {
+                assert false : "unhandled property type: " + type;
+            }
+        } else {
+            assert checkAssignableFrom(index, value);
+            unsafe.putObject(object, dataOffset, value);
+        }
+    }
+
+    @Override
+    public String toString() {
+        return clazz.getSimpleName();
+    }
+
+    public void appendFields(StringBuilder sb) {
+        for (int i = 0; i < offsets.length; i++) {
+            sb.append(i == 0 ? "" : ", ").append(getName(i)).append('@').append(offsets[i]);
+        }
+    }
+
+    public boolean getBoolean(Object n, int i) {
+        assert types[i] == boolean.class;
+        return unsafe.getBoolean(n, offsets[i]);
+    }
+
+    public byte getByte(Object n, int i) {
+        assert types[i] == byte.class;
+        return unsafe.getByte(n, offsets[i]);
+    }
+
+    public short getShort(Object n, int i) {
+        assert types[i] == short.class;
+        return unsafe.getShort(n, offsets[i]);
+    }
+
+    public char getChar(Object n, int i) {
+        assert types[i] == char.class;
+        return unsafe.getChar(n, offsets[i]);
+    }
+
+    public int getInt(Object n, int i) {
+        assert types[i] == int.class;
+        return unsafe.getInt(n, offsets[i]);
+    }
+
+    public long getLong(Object n, int i) {
+        assert types[i] == long.class;
+        return unsafe.getLong(n, offsets[i]);
+    }
+
+    public float getFloat(Object n, int i) {
+        assert types[i] == float.class;
+        return unsafe.getFloat(n, offsets[i]);
+    }
+
+    public double getDouble(Object n, int i) {
+        assert types[i] == double.class;
+        return unsafe.getDouble(n, offsets[i]);
+    }
+
+    public Object getObject(Object object, int i) {
+        assert !types[i].isPrimitive();
+        return unsafe.getObject(object, offsets[i]);
+    }
+}
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CheckGraalInvariants.java	Fri Sep 26 10:40:34 2014 -0700
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CheckGraalInvariants.java	Fri Sep 26 10:41:19 2014 -0700
@@ -75,28 +75,31 @@
 
         bootclasspath.split(File.pathSeparator);
 
-        String graalJar = null;
-        for (String e : bootclasspath.split(File.pathSeparator)) {
-            if (e.endsWith("graal.jar")) {
-                graalJar = e;
-                break;
-            }
-        }
-        Assert.assertNotNull("Could not find graal.jar on boot class path: " + bootclasspath, graalJar);
+        final List<String> classNames = new ArrayList<>();
+        for (String jarName : new String[]{"graal.jar", "graal-truffle.jar"}) {
 
-        final List<String> classNames = new ArrayList<>();
-        try {
-            final ZipFile zipFile = new ZipFile(new File(graalJar));
-            for (final Enumeration<? extends ZipEntry> e = zipFile.entries(); e.hasMoreElements();) {
-                final ZipEntry zipEntry = e.nextElement();
-                String name = zipEntry.getName();
-                if (name.endsWith(".class")) {
-                    String className = name.substring(0, name.length() - ".class".length()).replace('/', '.');
-                    classNames.add(className);
+            String jar = null;
+            for (String e : bootclasspath.split(File.pathSeparator)) {
+                if (e.endsWith(jarName)) {
+                    jar = e;
+                    break;
                 }
             }
-        } catch (IOException e) {
-            Assert.fail(e.toString());
+            Assert.assertNotNull("Could not find graal.jar on boot class path: " + bootclasspath, jar);
+
+            try {
+                final ZipFile zipFile = new ZipFile(new File(jar));
+                for (final Enumeration<? extends ZipEntry> e = zipFile.entries(); e.hasMoreElements();) {
+                    final ZipEntry zipEntry = e.nextElement();
+                    String name = zipEntry.getName();
+                    if (name.endsWith(".class")) {
+                        String className = name.substring(0, name.length() - ".class".length()).replace('/', '.');
+                        classNames.add(className);
+                    }
+                }
+            } catch (IOException e) {
+                Assert.fail(e.toString());
+            }
         }
 
         // Allows a subset of methods to be checked through use of a system property
@@ -131,8 +134,9 @@
                         boolean verifyEquals = !m.isAnnotationPresent(ExcludeFromIdentityComparisonVerification.class);
                         if (matches(filters, methodName)) {
                             executor.execute(() -> {
-                                StructuredGraph graph = new StructuredGraph(metaAccess.lookupJavaMethod(m));
-                                try (DebugConfigScope s = Debug.setConfig(new DelegatingDebugConfig().disable(INTERCEPT))) {
+                                ResolvedJavaMethod method = metaAccess.lookupJavaMethod(m);
+                                StructuredGraph graph = new StructuredGraph(method);
+                                try (DebugConfigScope s = Debug.setConfig(new DelegatingDebugConfig().disable(INTERCEPT)); Debug.Scope ds = Debug.scope("CheckingGraph", graph, method)) {
                                     graphBuilderSuite.apply(graph, context);
                                     // update phi stamps
                                     graph.getNodes().filter(PhiNode.class).forEach(PhiNode::inferStamp);
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Edges.java	Fri Sep 26 10:40:34 2014 -0700
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Edges.java	Fri Sep 26 10:41:19 2014 -0700
@@ -28,11 +28,13 @@
 
 import java.util.*;
 
+import com.oracle.graal.compiler.common.*;
+
 /**
  * Describes {@link Node} fields representing the set of inputs for the node or the set of the
  * node's successors.
  */
-public abstract class Edges {
+public abstract class Edges extends Fields {
 
     /**
      * Constants denoting whether a set of edges are inputs or successors.
@@ -42,41 +44,13 @@
         Successors;
     }
 
-    private final Class<? extends Node> nodeClass;
     private final int directCount;
-    private final long[] offsets;
-    private final String[] names;
-    private final Class<?>[] types;
     private final Type type;
 
-    @SuppressWarnings("unchecked")
     public Edges(Class<?> nodeClass, Type type, int directCount, long[] offsets, Map<Long, String> names, Map<Long, Class<?>> types) {
-        this.nodeClass = (Class<? extends Node>) nodeClass;
+        super(nodeClass, offsets, names, types);
         this.type = type;
         this.directCount = directCount;
-        this.offsets = offsets;
-
-        this.names = new String[offsets.length];
-        this.types = new Class[offsets.length];
-        for (int i = 0; i < offsets.length; i++) {
-            this.names[i] = names.get(offsets[i]);
-            this.types[i] = types.get(offsets[i]);
-        }
-    }
-
-    /**
-     * Gets the number of edges represented by this object.
-     */
-    public int getCount() {
-        return offsets.length;
-    }
-
-    /**
-     * Get the number of direct edges represented by this object. A direct edge goes directly to
-     * another {@link Node}. An indirect edge goes via a {@link NodeList}.
-     */
-    public int getDirectCount() {
-        return directCount;
     }
 
     private static Node getNode(Node node, long offset) {
@@ -97,6 +71,14 @@
     }
 
     /**
+     * Get the number of direct edges represented by this object. A direct edge goes directly to
+     * another {@link Node}. An indirect edge goes via a {@link NodeList}.
+     */
+    public int getDirectCount() {
+        return directCount;
+    }
+
+    /**
      * Gets the {@link Node} at the end point of a {@linkplain #getDirectCount() direct} edge.
      *
      * @param node one end point of the edge
@@ -117,7 +99,7 @@
      * @return the {@link NodeList} at the other edge of the requested edge
      */
     public NodeList<Node> getNodeList(Node node, int index) {
-        assert index >= directCount && index < offsets.length;
+        assert index >= directCount && index < getCount();
         return getNodeList(node, offsets[index]);
     }
 
@@ -152,7 +134,7 @@
      * @param toNode the node to which the edges should be copied.
      */
     public void copy(Node fromNode, Node toNode) {
-        assert fromNode.getNodeClass().getClazz() == nodeClass && toNode.getNodeClass().getClazz() == nodeClass;
+        assert fromNode.getNodeClass().getClazz() == clazz && toNode.getNodeClass().getClazz() == clazz;
         int index = 0;
         while (index < getDirectCount()) {
             initializeNode(toNode, index, getNode(fromNode, index));
@@ -187,7 +169,7 @@
         }
         while (index < getCount()) {
             NodeList<Node> list = getNodeList(node, index);
-            assert list != null : nodeClass;
+            assert list != null : clazz;
             if (list.replaceFirst(key, replacement)) {
                 return true;
             }
@@ -196,36 +178,20 @@
         return false;
     }
 
-    public boolean isSameEdge(Edges other, int index) {
-        return offsets[index] == other.offsets[index];
-    }
-
-    /**
-     * Gets the name of an edge.
-     *
-     * @param index index of an edge
-     */
-    public String getName(int index) {
-        return names[index];
+    @Override
+    public void set(Object node, int index, Object value) {
+        throw new IllegalArgumentException("Cannot call set on " + this);
     }
 
     /**
-     * Gets the type of the field storing the end point of an edge.
+     * Sets the value of a given edge without notifying the new and old nodes on the other end of
+     * the edge of the change.
      *
-     * @param index index of an edge
+     * @param node the node whose edge is to be updated
+     * @param index the index of the edge (between 0 and {@link #getCount()})
+     * @param value the node to be written to the edge
      */
-    public Class<?> getType(int index) {
-        return types[index];
-    }
-
-    private boolean checkAssignable(int index, Node value) {
-        assert value == null || getType(index).isAssignableFrom(value.getClass()) : String.format("%s.%s of type %s is not assignable from %s", nodeClass.getSimpleName(), getName(index),
-                        getType(index).getSimpleName(), value.getClass().getSimpleName());
-        return true;
-    }
-
     public void initializeNode(Node node, int index, Node value) {
-        assert checkAssignable(index, value);
         putNode(node, offsets[index], value);
     }
 
@@ -234,12 +200,18 @@
         putNodeList(node, offsets[index], value);
     }
 
+    /**
+     * Sets the value of a given edge and notifies the new and old nodes on the other end of the
+     * edge of the change.
+     *
+     * @param node the node whose edge is to be updated
+     * @param index the index of the edge (between 0 and {@link #getCount()})
+     * @param value the node to be written to the edge
+     */
     public void setNode(Node node, int index, Node value) {
         assert index < directCount;
-        long offset = offsets[index];
-        Node old = getNode(node, offset);
-        assert checkAssignable(index, value);
-        putNode(node, offset, value);
+        Node old = getNode(node, offsets[index]);
+        putNode(node, offsets[index], value);
         update(node, old, value);
     }
 
@@ -263,7 +235,7 @@
      * Determines if the edges of two given nodes are the same.
      */
     public boolean areEqualIn(Node node, Node other) {
-        assert node.getNodeClass().getClazz() == nodeClass && other.getNodeClass().getClazz() == nodeClass;
+        assert node.getNodeClass().getClazz() == clazz && other.getNodeClass().getClazz() == clazz;
         int index = 0;
         while (index < directCount) {
             if (getNode(other, index) != getNode(node, index)) {
@@ -476,12 +448,6 @@
 
     @Override
     public String toString() {
-        return nodeClass.getSimpleName() + ":" + type;
-    }
-
-    void appendOffsets(StringBuilder sb) {
-        for (int i = 0; i < offsets.length; i++) {
-            sb.append(i == 0 ? "" : ", ").append(offsets[i]);
-        }
+        return super.toString() + ":" + type;
     }
 }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Fri Sep 26 10:40:34 2014 -0700
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Fri Sep 26 10:41:19 2014 -0700
@@ -28,6 +28,7 @@
 import java.lang.annotation.*;
 import java.util.*;
 
+import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.graph.Graph.NodeEventListener;
 import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.graph.spi.*;
@@ -471,8 +472,9 @@
     }
 
     /**
-     * Updates the usages sets of the given nodes after an input slot is changed from oldInput to
-     * newInput: removes this node from oldInput's usages and adds this node to newInput's usages.
+     * Updates the usages sets of the given nodes after an input slot is changed from
+     * {@code oldInput} to {@code newInput} by removing this node from {@code oldInput}'s usages and
+     * adds this node to {@code newInput}'s usages.
      */
     protected void updateUsages(Node oldInput, Node newInput) {
         assert isAlive() && (newInput == null || newInput.isAlive()) : "adding " + newInput + " to " + this + " instead of " + oldInput;
@@ -883,9 +885,9 @@
      */
     public Map<Object, Object> getDebugProperties(Map<Object, Object> map) {
         NodeClass nodeClass = getNodeClass();
-        for (Integer pos : nodeClass.getPropertyPositions()) {
-            map.put(nodeClass.getPropertyName(pos), nodeClass.getProperty(this, pos));
-
+        Fields properties = nodeClass.getProperties();
+        for (int i = 0; i < properties.getCount(); i++) {
+            map.put(properties.getName(i), properties.get(this, i));
         }
         return map;
     }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Fri Sep 26 10:40:34 2014 -0700
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Fri Sep 26 10:41:19 2014 -0700
@@ -111,8 +111,8 @@
 
     private final Edges inputs;
     private final Edges successors;
+    private final Fields properties;
 
-    private final Class<?>[] dataTypes;
     private final boolean canGVN;
     private final int startGVNNumber;
     private final String shortName;
@@ -174,11 +174,7 @@
             inputs = new InputEdges(clazz, fs.inputOffsets.size(), sortedOffsets(fs.inputOffsets, fs.inputListOffsets), fs.fieldNames, fs.fieldTypes, fs.types, fs.optionalInputs);
         }
         try (TimerCloseable t1 = Init_Data.start()) {
-            dataOffsets = sortedLongCopy(fs.dataOffsets);
-            dataTypes = new Class[dataOffsets.length];
-            for (int i = 0; i < dataOffsets.length; i++) {
-                dataTypes[i] = fs.fieldTypes.get(dataOffsets[i]);
-            }
+            properties = new Fields(clazz, sortedLongCopy(fs.dataOffsets), fs.fieldNames, fs.fieldTypes);
         }
 
         isLeafNode = inputs.getCount() + successors.getCount() == 0;
@@ -281,11 +277,6 @@
         return false;
     }
 
-    @Override
-    protected void rescanFieldOffsets(CalcOffset calc) {
-        throw new UnsupportedOperationException();
-    }
-
     /**
      * Determines if a given {@link Node} class is described by this {@link NodeClass} object. This
      * is useful for doing an exact type test (as opposed to an instanceof test) on a node. For
@@ -293,7 +284,7 @@
      *
      * <pre>
      *     if (node.getNodeClass().is(BeginNode.class)) { ... }
-     *
+     * 
      *     // Due to generated Node classes, the test below
      *     // is *not* the same as the test above:
      *     if (node.getClass() == BeginNode.class) { ... }
@@ -407,13 +398,11 @@
     public String toString() {
         StringBuilder str = new StringBuilder();
         str.append("NodeClass ").append(getClazz().getSimpleName()).append(" [");
-        inputs.appendOffsets(str);
-        str.append("] [");
-        successors.appendOffsets(str);
+        inputs.appendFields(str);
         str.append("] [");
-        for (int i = 0; i < dataOffsets.length; i++) {
-            str.append(i == 0 ? "" : ", ").append(dataOffsets[i]);
-        }
+        successors.appendFields(str);
+        str.append("] [");
+        properties.appendFields(str);
         str.append("]");
         return str.toString();
     }
@@ -448,41 +437,41 @@
         int number = 0;
         if (canGVN) {
             number = startGVNNumber;
-            for (int i = 0; i < dataOffsets.length; ++i) {
-                Class<?> type = dataTypes[i];
+            for (int i = 0; i < properties.getCount(); ++i) {
+                Class<?> type = properties.getType(i);
                 if (type.isPrimitive()) {
                     if (type == Integer.TYPE) {
-                        int intValue = unsafe.getInt(n, dataOffsets[i]);
+                        int intValue = properties.getInt(n, i);
                         number += intValue;
                     } else if (type == Long.TYPE) {
-                        long longValue = unsafe.getLong(n, dataOffsets[i]);
+                        long longValue = properties.getLong(n, i);
                         number += longValue ^ (longValue >>> 32);
                     } else if (type == Boolean.TYPE) {
-                        boolean booleanValue = unsafe.getBoolean(n, dataOffsets[i]);
+                        boolean booleanValue = properties.getBoolean(n, i);
                         if (booleanValue) {
                             number += 7;
                         }
                     } else if (type == Float.TYPE) {
-                        float floatValue = unsafe.getFloat(n, dataOffsets[i]);
+                        float floatValue = properties.getFloat(n, i);
                         number += Float.floatToRawIntBits(floatValue);
                     } else if (type == Double.TYPE) {
-                        double doubleValue = unsafe.getDouble(n, dataOffsets[i]);
+                        double doubleValue = properties.getDouble(n, i);
                         long longValue = Double.doubleToRawLongBits(doubleValue);
                         number += longValue ^ (longValue >>> 32);
                     } else if (type == Short.TYPE) {
-                        short shortValue = unsafe.getShort(n, dataOffsets[i]);
+                        short shortValue = properties.getShort(n, i);
                         number += shortValue;
                     } else if (type == Character.TYPE) {
-                        char charValue = unsafe.getChar(n, dataOffsets[i]);
+                        char charValue = properties.getChar(n, i);
                         number += charValue;
                     } else if (type == Byte.TYPE) {
-                        byte byteValue = unsafe.getByte(n, dataOffsets[i]);
+                        byte byteValue = properties.getByte(n, i);
                         number += byteValue;
                     } else {
                         assert false : "unhandled property type: " + type;
                     }
                 } else {
-                    Object o = unsafe.getObject(n, dataOffsets[i]);
+                    Object o = properties.getObject(n, i);
                     number += deepHashCode0(o);
                 }
                 number *= 13;
@@ -522,54 +511,54 @@
         if (a.getClass() != b.getClass()) {
             return a == b;
         }
-        for (int i = 0; i < dataOffsets.length; ++i) {
-            Class<?> type = dataTypes[i];
+        for (int i = 0; i < properties.getCount(); ++i) {
+            Class<?> type = properties.getType(i);
             if (type.isPrimitive()) {
                 if (type == Integer.TYPE) {
-                    int aInt = unsafe.getInt(a, dataOffsets[i]);
-                    int bInt = unsafe.getInt(b, dataOffsets[i]);
+                    int aInt = properties.getInt(a, i);
+                    int bInt = properties.getInt(b, i);
                     if (aInt != bInt) {
                         return false;
                     }
                 } else if (type == Boolean.TYPE) {
-                    boolean aBoolean = unsafe.getBoolean(a, dataOffsets[i]);
-                    boolean bBoolean = unsafe.getBoolean(b, dataOffsets[i]);
+                    boolean aBoolean = properties.getBoolean(a, i);
+                    boolean bBoolean = properties.getBoolean(b, i);
                     if (aBoolean != bBoolean) {
                         return false;
                     }
                 } else if (type == Long.TYPE) {
-                    long aLong = unsafe.getLong(a, dataOffsets[i]);
-                    long bLong = unsafe.getLong(b, dataOffsets[i]);
+                    long aLong = properties.getLong(a, i);
+                    long bLong = properties.getLong(b, i);
                     if (aLong != bLong) {
                         return false;
                     }
                 } else if (type == Float.TYPE) {
-                    float aFloat = unsafe.getFloat(a, dataOffsets[i]);
-                    float bFloat = unsafe.getFloat(b, dataOffsets[i]);
+                    float aFloat = properties.getFloat(a, i);
+                    float bFloat = properties.getFloat(b, i);
                     if (aFloat != bFloat) {
                         return false;
                     }
                 } else if (type == Double.TYPE) {
-                    double aDouble = unsafe.getDouble(a, dataOffsets[i]);
-                    double bDouble = unsafe.getDouble(b, dataOffsets[i]);
+                    double aDouble = properties.getDouble(a, i);
+                    double bDouble = properties.getDouble(b, i);
                     if (aDouble != bDouble) {
                         return false;
                     }
                 } else if (type == Short.TYPE) {
-                    short aShort = unsafe.getShort(a, dataOffsets[i]);
-                    short bShort = unsafe.getShort(b, dataOffsets[i]);
+                    short aShort = properties.getShort(a, i);
+                    short bShort = properties.getShort(b, i);
                     if (aShort != bShort) {
                         return false;
                     }
                 } else if (type == Character.TYPE) {
-                    char aChar = unsafe.getChar(a, dataOffsets[i]);
-                    char bChar = unsafe.getChar(b, dataOffsets[i]);
+                    char aChar = properties.getChar(a, i);
+                    char bChar = properties.getChar(b, i);
                     if (aChar != bChar) {
                         return false;
                     }
                 } else if (type == Byte.TYPE) {
-                    byte aByte = unsafe.getByte(a, dataOffsets[i]);
-                    byte bByte = unsafe.getByte(b, dataOffsets[i]);
+                    byte aByte = properties.getByte(a, i);
+                    byte bByte = properties.getByte(b, i);
                     if (aByte != bByte) {
                         return false;
                     }
@@ -577,8 +566,8 @@
                     assert false : "unhandled type: " + type;
                 }
             } else {
-                Object objectA = unsafe.getObject(a, dataOffsets[i]);
-                Object objectB = unsafe.getObject(b, dataOffsets[i]);
+                Object objectA = properties.getObject(a, i);
+                Object objectB = properties.getObject(b, i);
                 if (objectA != objectB) {
                     if (objectA != null && objectB != null) {
                         if (!deepEquals0(objectA, objectB)) {
@@ -604,74 +593,14 @@
         if (pos.getIndex() >= fromEdges.getCount()) {
             return false;
         }
-        return toEdges.isSameEdge(fromEdges, pos.getIndex());
-    }
-
-    public String getPropertyName(int pos) {
-        return fieldNames.get(dataOffsets[pos]);
-    }
-
-    public Class<?> getPropertyType(int pos) {
-        return fieldTypes.get(dataOffsets[pos]);
+        return toEdges.isSame(fromEdges, pos.getIndex());
     }
 
-    public Object getProperty(Node node, int pos) {
-        long dataOffset = dataOffsets[pos];
-        Class<?> type = fieldTypes.get(dataOffset);
-        Object value = null;
-        if (type.isPrimitive()) {
-            if (type == Integer.TYPE) {
-                value = unsafe.getInt(node, dataOffset);
-            } else if (type == Long.TYPE) {
-                value = unsafe.getLong(node, dataOffset);
-            } else if (type == Boolean.TYPE) {
-                value = unsafe.getBoolean(node, dataOffset);
-            } else if (type == Float.TYPE) {
-                value = unsafe.getFloat(node, dataOffset);
-            } else if (type == Double.TYPE) {
-                value = unsafe.getDouble(node, dataOffset);
-            } else if (type == Short.TYPE) {
-                value = unsafe.getShort(node, dataOffset);
-            } else if (type == Character.TYPE) {
-                value = unsafe.getChar(node, dataOffset);
-            } else if (type == Byte.TYPE) {
-                value = unsafe.getByte(node, dataOffset);
-            } else {
-                assert false : "unhandled property type: " + type;
-            }
-        } else {
-            value = unsafe.getObject(node, dataOffset);
-        }
-        return value;
-    }
-
-    public void setProperty(Node node, int pos, Object value) {
-        long dataOffset = dataOffsets[pos];
-        Class<?> type = fieldTypes.get(dataOffset);
-        if (type.isPrimitive()) {
-            if (type == Integer.TYPE) {
-                unsafe.putInt(node, dataOffset, (Integer) value);
-            } else if (type == Long.TYPE) {
-                unsafe.putLong(node, dataOffset, (Long) value);
-            } else if (type == Boolean.TYPE) {
-                unsafe.putBoolean(node, dataOffset, (Boolean) value);
-            } else if (type == Float.TYPE) {
-                unsafe.putFloat(node, dataOffset, (Float) value);
-            } else if (type == Double.TYPE) {
-                unsafe.putDouble(node, dataOffset, (Double) value);
-            } else if (type == Short.TYPE) {
-                unsafe.putShort(node, dataOffset, (Short) value);
-            } else if (type == Character.TYPE) {
-                unsafe.putChar(node, dataOffset, (Character) value);
-            } else if (type == Byte.TYPE) {
-                unsafe.putByte(node, dataOffset, (Byte) value);
-            } else {
-                assert false : "unhandled property type: " + type;
-            }
-        } else {
-            assert value == null || !value.getClass().isPrimitive();
-            unsafe.putObject(node, dataOffset, value);
-        }
+    /**
+     * Gets the non-edge properties defined by this node class.
+     */
+    public Fields getProperties() {
+        return properties;
     }
 
     static void updateEdgesInPlace(Node node, InplaceUpdateClosure duplicationReplacement, Edges edges) {
@@ -724,36 +653,6 @@
         return type == Edges.Type.Inputs ? inputs : successors;
     }
 
-    public Collection<Integer> getPropertyPositions() {
-        return new AbstractCollection<Integer>() {
-            @Override
-            public Iterator<Integer> iterator() {
-                return new Iterator<Integer>() {
-                    int i = 0;
-
-                    @Override
-                    public void remove() {
-                        throw new UnsupportedOperationException();
-                    }
-
-                    public Integer next() {
-                        Integer pos = i++;
-                        return pos;
-                    }
-
-                    public boolean hasNext() {
-                        return i < dataOffsets.length;
-                    }
-                };
-            }
-
-            @Override
-            public int size() {
-                return dataOffsets.length;
-            }
-        };
-    }
-
     /**
      * Initializes a fresh allocated node for which no constructor is called yet. Needed to
      * implement node factories in svm.
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValueClass.java	Fri Sep 26 10:40:34 2014 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValueClass.java	Fri Sep 26 10:41:19 2014 -0700
@@ -83,22 +83,6 @@
         fieldTypes = scanner.fieldTypes;
     }
 
-    @Override
-    protected void rescanFieldOffsets(CalcOffset calc) {
-        ValueFieldScanner scanner = new ValueFieldScanner(calc);
-        scanner.scan(getClazz());
-
-        OperandModeAnnotation mode = scanner.valueAnnotations.get(CompositeValue.Component.class);
-        copyInto(componentOffsets, sortedLongCopy(mode.scalarOffsets, mode.arrayOffsets));
-
-        copyInto(dataOffsets, sortedLongCopy(scanner.dataOffsets));
-
-        fieldNames.clear();
-        fieldNames.putAll(scanner.fieldNames);
-        fieldTypes.clear();
-        fieldTypes.putAll(scanner.fieldTypes);
-    }
-
     private static class ValueFieldScanner extends FieldScanner {
 
         public ValueFieldScanner(CalcOffset calc) {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionClass.java	Fri Sep 26 10:40:34 2014 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionClass.java	Fri Sep 26 10:41:19 2014 -0700
@@ -113,32 +113,6 @@
         opcodeOffset = scanner.opcodeOffset;
     }
 
-    @Override
-    protected void rescanFieldOffsets(CalcOffset calc) {
-        InstructionFieldScanner scanner = new InstructionFieldScanner(calc);
-        scanner.scan(getClazz());
-
-        OperandModeAnnotation mode = scanner.valueAnnotations.get(LIRInstruction.Use.class);
-        copyInto(useOffsets, sortedLongCopy(mode.scalarOffsets, mode.arrayOffsets));
-        mode = scanner.valueAnnotations.get(LIRInstruction.Alive.class);
-        copyInto(aliveOffsets, sortedLongCopy(mode.scalarOffsets, mode.arrayOffsets));
-        mode = scanner.valueAnnotations.get(LIRInstruction.Temp.class);
-        copyInto(tempOffsets, sortedLongCopy(mode.scalarOffsets, mode.arrayOffsets));
-        mode = scanner.valueAnnotations.get(LIRInstruction.Def.class);
-        copyInto(defOffsets, sortedLongCopy(mode.scalarOffsets, mode.arrayOffsets));
-
-        copyInto(stateOffsets, sortedLongCopy(scanner.stateOffsets));
-        copyInto(dataOffsets, sortedLongCopy(scanner.dataOffsets));
-
-        fieldNames.clear();
-        fieldNames.putAll(scanner.fieldNames);
-        fieldTypes.clear();
-        fieldTypes.putAll(scanner.fieldTypes);
-
-        opcodeConstant = scanner.opcodeConstant;
-        opcodeOffset = scanner.opcodeOffset;
-    }
-
     private static class InstructionFieldScanner extends FieldScanner {
 
         private String opcodeConstant;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/EdgesTest.java	Fri Sep 26 10:41:19 2014 -0700
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2013, 2014, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.replacements.test;
+
+import java.lang.reflect.*;
+
+import org.junit.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.compiler.test.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.Edges.Type;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
+import com.oracle.graal.phases.tiers.*;
+
+public class EdgesTest extends GraalCompilerTest {
+
+    @NodeInfo
+    static class TestNode extends Node {
+        @Input NodeInputList<ValueNode> itail;
+        @Input ConstantNode i1;
+        @Input FloatingNode i2;
+
+        public static TestNode create() {
+            return USE_GENERATED_NODES ? new EdgesTest_TestNodeGen() : new TestNode();
+        }
+    }
+
+    StructuredGraph graph = new StructuredGraph();
+    TestNode node;
+    ConstantNode i1;
+    ConstantNode i2;
+    ConstantNode i3;
+    ConstantNode i4;
+    Edges inputs;
+
+    public EdgesTest() {
+        node = TestNode.create();
+        i1 = ConstantNode.forInt(1, graph);
+        i2 = ConstantNode.forDouble(1.0d, graph);
+        i3 = ConstantNode.forInt(4, graph);
+        i4 = ConstantNode.forInt(14, graph);
+        node.itail = new NodeInputList<>(node, new ValueNode[]{i3, i4});
+        node.i1 = i1;
+        node.i2 = i2;
+        graph.add(node);
+        inputs = node.getNodeClass().getEdges(Type.Inputs);
+    }
+
+    /**
+     * Checks that there are no checkcasts in the compiled version of
+     * {@link Edges#getNode(Node, int)}
+     */
+    @Test
+    public void test0() {
+        testMethod(getMethod("getNode", Node.class, int.class), inputs, node, 0);
+    }
+
+    /**
+     * Checks that there are no checkcasts in the compiled version of
+     * {@link Edges#getNodeList(Node, int)}
+     */
+    @Test
+    public void test1() {
+        testMethod(getMethod("getNodeList", Node.class, int.class), inputs, node, 2);
+    }
+
+    /**
+     * Checks that there are no checkcasts in the compiled version of
+     * {@link Edges#setNode(Node, int, Node)}
+     */
+    @Test
+    public void test2() {
+        testMethod(getMethod("setNode", Node.class, int.class, Node.class), inputs, node, 1, i2);
+    }
+
+    private void testMethod(Method method, Object receiver, Object... args) {
+        try {
+            // Invoke the method to ensure it has a type profile
+            for (int i = 0; i < 5000; i++) {
+                method.invoke(receiver, args);
+            }
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+
+        StructuredGraph g = parseProfiled(method);
+        Assumptions assumptions = new Assumptions(false);
+        HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
+        new InliningPhase(new CanonicalizerPhase(true)).apply(g, context);
+        new CanonicalizerPhase(false).apply(g, context);
+        Assert.assertTrue(g.getNodes().filter(CheckCastNode.class).isEmpty());
+    }
+
+    private static Method getMethod(final String name, Class<?>... parameters) {
+        try {
+            return Edges.class.getDeclaredMethod(name, parameters);
+        } catch (NoSuchMethodException | SecurityException e) {
+            throw new RuntimeException(e);
+        }
+    }
+}
--- a/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/MethodSubstitutionVerifier.java	Fri Sep 26 10:40:34 2014 -0700
+++ b/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/MethodSubstitutionVerifier.java	Fri Sep 26 10:41:19 2014 -0700
@@ -89,18 +89,18 @@
         }
 
         String originalName = originalName(substitutionMethod, annotation);
-        TypeMirror[] originalSignature = originalSignature(originalType, substitutionMethod, annotation);
+        boolean isStatic = resolveAnnotationValue(Boolean.class, findAnnotationValue(annotation, ORIGINAL_IS_STATIC));
+        TypeMirror[] originalSignature = originalSignature(originalType, substitutionMethod, annotation, isStatic);
         if (originalSignature == null) {
             return;
         }
-        ExecutableElement originalMethod = originalMethod(substitutionMethod, annotation, originalType, originalName, originalSignature);
+        ExecutableElement originalMethod = originalMethod(substitutionMethod, annotation, originalType, originalName, originalSignature, isStatic);
         if (DEBUG && originalMethod != null) {
             env.getMessager().printMessage(Kind.NOTE, String.format("Found original method %s in type %s.", originalMethod, findEnclosingClass(originalMethod)));
         }
     }
 
-    private TypeMirror[] originalSignature(TypeElement originalType, ExecutableElement method, AnnotationMirror annotation) {
-        boolean isStatic = resolveAnnotationValue(Boolean.class, findAnnotationValue(annotation, ORIGINAL_IS_STATIC));
+    private TypeMirror[] originalSignature(TypeElement originalType, ExecutableElement method, AnnotationMirror annotation, boolean isStatic) {
         AnnotationValue signatureValue = findAnnotationValue(annotation, ORIGINAL_SIGNATURE);
         String signatureString = resolveAnnotationValue(String.class, signatureValue);
         List<TypeMirror> parameters = new ArrayList<>();
@@ -150,7 +150,7 @@
     }
 
     private ExecutableElement originalMethod(ExecutableElement substitutionMethod, AnnotationMirror substitutionAnnotation, TypeElement originalType, String originalName,
-                    TypeMirror[] originalSignature) {
+                    TypeMirror[] originalSignature, boolean isStatic) {
         TypeMirror signatureReturnType = originalSignature[0];
         TypeMirror[] signatureParameters = Arrays.copyOfRange(originalSignature, 1, originalSignature.length);
         List<ExecutableElement> searchElements;
@@ -182,6 +182,14 @@
             return null;
         }
 
+        if (originalMethod.getModifiers().contains(Modifier.STATIC) != isStatic) {
+            boolean optional = resolveAnnotationValue(Boolean.class, findAnnotationValue(substitutionAnnotation, "optional"));
+            if (!optional) {
+                env.getMessager().printMessage(Kind.ERROR, String.format("The %s element must be set to %s.", ORIGINAL_IS_STATIC, !isStatic), substitutionMethod, substitutionAnnotation);
+            }
+            return null;
+        }
+
         if (!isTypeCompatible(originalMethod.getReturnType(), signatureReturnType)) {
             env.getMessager().printMessage(
                             Kind.ERROR,
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/EdgesSubstitutions.java	Fri Sep 26 10:40:34 2014 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/EdgesSubstitutions.java	Fri Sep 26 10:41:19 2014 -0700
@@ -27,13 +27,14 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.replacements.nodes.*;
 
 /**
  * Substitutions for improving the performance of some critical methods in {@link Edges}. These
  * substitutions improve the performance by forcing the relevant methods to be inlined
  * (intrinsification being a special form of inlining) and removing a checked cast. The latter
- * cannot be done directly in Java code as {@link PiNode} is not available to the project containing
- * {@link Edges}.
+ * cannot be done directly in Java code as {@link DeferredPiNode} is not available to the project
+ * containing {@link Edges}.
  */
 @ClassSubstitution(Edges.class)
 public class EdgesSubstitutions {
@@ -57,5 +58,4 @@
     private static void putNodeList(Node node, long offset, NodeList<?> value) {
         UnsafeStoreNode.store(node, offset, value, Kind.Object, LocationIdentity.ANY_LOCATION);
     }
-
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraalMethodSubstitutions.java	Fri Sep 26 10:40:34 2014 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraalMethodSubstitutions.java	Fri Sep 26 10:41:19 2014 -0700
@@ -30,6 +30,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.spi.*;
 
 /**
@@ -50,6 +51,7 @@
             replacements.registerSubstitutions(Character.class, CharacterSubstitutions.class);
             replacements.registerSubstitutions(Short.class, ShortSubstitutions.class);
             replacements.registerSubstitutions(UnsignedMath.class, UnsignedMathSubstitutions.class);
+            replacements.registerSubstitutions(Edges.class, EdgesSubstitutions.class);
         }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DeferredPiNode.java	Fri Sep 26 10:41:19 2014 -0700
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2012, 2013, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.replacements.nodes;
+
+//JaCoCo Exclude
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.replacements.*;
+
+/**
+ * A node for use in method substitutions or snippets that changes the type of its input where the
+ * type is not immediately available at {@link NodeIntrinsificationPhase intrinsification} time. It
+ * is replaced by a {@link PiNode} once the type becomes constant (which <b>must</b> happen).
+ */
+@NodeInfo
+public class DeferredPiNode extends FloatingNode implements Canonicalizable {
+
+    @Input ValueNode object;
+    @Input ValueNode type;
+
+    public ValueNode object() {
+        return object;
+    }
+
+    public static DeferredPiNode create(ValueNode type, ValueNode object) {
+        return USE_GENERATED_NODES ? new DeferredPiNodeGen(type, object) : new DeferredPiNode(type, object);
+    }
+
+    protected DeferredPiNode(ValueNode type, ValueNode object) {
+        super(StampFactory.object());
+        this.type = type;
+        this.object = object;
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (type.isConstant()) {
+            ResolvedJavaType javaType = tool.getConstantReflection().asJavaType(type.asConstant());
+            ObjectStamp objectStamp = (ObjectStamp) stamp();
+            return PiNode.create(object, javaType, objectStamp.isExactType(), objectStamp.nonNull());
+        }
+        return this;
+    }
+
+    @NodeIntrinsic
+    public static native <T> T piCast(Class<T> type, Object object);
+}
--- a/mx/mx_graal.py	Fri Sep 26 10:40:34 2014 -0700
+++ b/mx/mx_graal.py	Fri Sep 26 10:41:19 2014 -0700
@@ -154,6 +154,9 @@
         _vmbuild = self.previousBuild
 
 def chmodRecursive(dirname, chmodFlagsDir):
+    if mx.get_os() == 'windows':
+        return
+
     def _chmodDir(chmodFlags, dirname, fnames):
         os.chmod(dirname, chmodFlagsDir)
 
@@ -351,9 +354,10 @@
     Get the directory within a JDK where the server and client
     subdirectories are located.
     """
-    if platform.system() == 'Darwin':
+    mxos = mx.get_os()
+    if mxos == 'darwin':
         return join(jdk, 'jre', 'lib')
-    if platform.system() == 'Windows':
+    if mxos == 'windows' or mxos == 'cygwin':
         return join(jdk, 'jre', 'bin')
     return join(jdk, 'jre', 'lib', mx.get_arch())
 
@@ -361,9 +365,10 @@
     """
     Get the directories within a JDK where the jli library designates to.
     """
-    if platform.system() == 'Darwin':
+    mxos = mx.get_os()
+    if mxos == 'darwin':
         return [join(jdk, 'jre', 'lib', 'jli')]
-    if platform.system() == 'Windows':
+    if mxos == 'windows' or mxos == 'cygwin':
         return [join(jdk, 'jre', 'bin'), join(jdk, 'bin')]
     return [join(jdk, 'jre', 'lib', mx.get_arch(), 'jli'), join(jdk, 'lib', mx.get_arch(), 'jli')]
 
@@ -371,7 +376,8 @@
     """
     Get the jvm.cfg file.
     """
-    if platform.system() == 'Windows':
+    mxos = mx.get_os()
+    if mxos == "windows" or mxos == "cygwin":
         return join(jdk, 'jre', 'lib', mx.get_arch(), jvmCfgFile)
     return join(_vmLibDirInJdk(jdk), jvmCfgFile)
 
@@ -426,11 +432,9 @@
                         jvmCfgLines += [line]
 
             assert defaultVM is not None, 'Could not find default VM in ' + jvmCfg
-            if mx.get_os() != 'windows':
-                chmodRecursive(jdk, JDK_UNIX_PERMISSIONS_DIR)
+            chmodRecursive(jdk, JDK_UNIX_PERMISSIONS_DIR)
             shutil.move(join(_vmLibDirInJdk(jdk), defaultVM), join(_vmLibDirInJdk(jdk), 'original'))
 
-
             with open(jvmCfg, 'w') as fp:
                 for line in jvmCfgLines:
                     fp.write(line)
@@ -525,7 +529,7 @@
         graalRuntime_inline_hpp = join(genSrcDir, 'graalRuntime.inline.hpp')
         cp = os.pathsep.join([mx.distribution(d).path for d in dist.distDependencies] + [dist.path, p.output_dir()])
         tmp = StringIO.StringIO()
-        mx.run_java(['-cp', cp, mainClass], out=tmp.write)
+        mx.run_java(['-cp', mx._tspU2W(cp), mainClass], out=tmp.write)
 
         # Compute SHA1 for currently generated graalRuntime.inline.hpp content
         # and all other generated sources in genSrcDir
@@ -548,7 +552,7 @@
         javaClass = join(_graal_home, 'GeneratedSourcesSha1.class')
         with open(javaSource, 'w') as fp:
             print >> fp, 'class GeneratedSourcesSha1 { private static final String value = "' + sha1 + '"; }'
-        subprocess.check_call([mx.java().javac, '-d', _graal_home, javaSource], stderr=subprocess.PIPE, stdout=subprocess.PIPE)
+        subprocess.check_call([mx.java().javac, '-d', mx._tpU2W(_graal_home), mx._tpU2W(javaSource)], stderr=subprocess.PIPE, stdout=subprocess.PIPE)
         zf = zipfile.ZipFile(dist.path, 'a')
         with open(javaClass, 'rb') as fp:
             zf.writestr(os.path.basename(javaClass), fp.read())
@@ -607,21 +611,26 @@
 
     winSDK = mx.get_env('WIN_SDK', 'C:\\Program Files\\Microsoft SDKs\\Windows\\v7.1\\')
 
-    if not exists(winSDK):
+    if not exists(mx._tpW2U(winSDK)):
         mx.abort("Could not find Windows SDK : '" + winSDK + "' does not exist")
 
-    if not exists(join(winSDK, 'Bin', 'SetEnv.cmd')):
+    winSDKSetEnv = mx._tpW2U(join(winSDK, 'Bin', 'SetEnv.cmd'))
+    if not exists(winSDKSetEnv):
         mx.abort("Invalid Windows SDK path (" + winSDK + ") : could not find Bin/SetEnv.cmd (you can use the WIN_SDK environment variable to specify an other path)")
 
-    p = subprocess.Popen('cmd.exe /E:ON /V:ON /K ""' + winSDK + '/Bin/SetEnv.cmd" & echo ' + startToken + '"', \
-            shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, creationflags=subprocess.CREATE_NEW_PROCESS_GROUP)
+    wincmd = 'cmd.exe /E:ON /V:ON /K "' + mx._tpU2W(winSDKSetEnv) + '"'
+    p = subprocess.Popen(wincmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
     stdout = p.stdout
     stdin = p.stdin
     if logFile:
         log = open(logFile, 'w')
     ret = False
+
+    def _writeProcess(s):
+        stdin.write(s + newLine)
+
+    _writeProcess("echo " + startToken)
     while True:
-
         # encoding may be None on windows plattforms
         if sys.stdout.encoding is None:
             encoding = 'utf-8'
@@ -634,25 +643,25 @@
         line = line.strip()
         mx.log(line)
         if line == startToken:
-            stdin.write('cd /D ' + workingDir + ' & ' + cmd + ' & echo ' + endToken + newLine)
+            _writeProcess('cd /D ' + workingDir + ' & ' + cmd + ' & echo ' + endToken)
         for regex in respondTo.keys():
             match = regex.search(line)
             if match:
-                stdin.write(respondTo[regex] + newLine)
+                _writeProcess(respondTo[regex])
         if findInOutput:
             match = findInOutput.search(line)
             if match:
                 ret = True
         if line == endToken:
             if not findInOutput:
-                stdin.write('echo ERRXXX%errorlevel%' + newLine)
+                _writeProcess('echo ERRXXX%errorlevel%')
             else:
                 break
         if line.startswith('ERRXXX'):
             if line == 'ERRXXX0':
                 ret = True
             break
-    stdin.write('exit' + newLine)
+    _writeProcess("exit")
     if logFile:
         log.close()
     return ret
@@ -806,8 +815,7 @@
 
         vmDir = join(_vmLibDirInJdk(jdk), vm)
         if not exists(vmDir):
-            if mx.get_os() != 'windows':
-                chmodRecursive(jdk, JDK_UNIX_PERMISSIONS_DIR)
+            chmodRecursive(jdk, JDK_UNIX_PERMISSIONS_DIR)
             mx.log('Creating VM directory in JDK: ' + vmDir)
             os.makedirs(vmDir)
 
@@ -838,21 +846,22 @@
             mx.logv('[all files in src and make directories are older than ' + timestampFile[len(_graal_home) + 1:] + ' - skipping native build]')
             continue
 
-        if platform.system() == 'Windows':
-            compilelogfile = _graal_home + '/graalCompile.log'
+        if platform.system() == 'Windows' or "CYGWIN" in platform.system():
+            t_compilelogfile = mx._tpU2W(os.path.join(_graal_home, "graalCompile.log"))
             mksHome = mx.get_env('MKS_HOME', 'C:\\cygwin\\bin')
 
             variant = {'client': 'compiler1', 'server': 'compiler2'}.get(vm, vm)
             project_config = variant + '_' + build
-            _runInDebugShell('msbuild ' + _graal_home + r'\build\vs-amd64\jvm.vcproj /p:Configuration=' + project_config + ' /target:clean', _graal_home)
-            winCompileCmd = r'set HotSpotMksHome=' + mksHome + r'& set OUT_DIR=' + jdk + r'& set JAVA_HOME=' + jdk + r'& set path=%JAVA_HOME%\bin;%path%;%HotSpotMksHome%& cd /D "' + _graal_home + r'\make\windows"& call create.bat ' + _graal_home
+            t_graal_home = mx._tpU2W(_graal_home)
+            _runInDebugShell('msbuild ' + t_graal_home + r'\build\vs-amd64\jvm.vcproj /p:Configuration=' + project_config + ' /target:clean', t_graal_home)
+            winCompileCmd = r'set HotSpotMksHome=' + mksHome + r'& set OUT_DIR=' + mx._tpU2W(jdk) + r'& set JAVA_HOME=' + mx._tpU2W(jdk) + r'& set path=%JAVA_HOME%\bin;%path%;%HotSpotMksHome%& cd /D "' + t_graal_home + r'\make\windows"& call create.bat ' + t_graal_home
             print winCompileCmd
             winCompileSuccess = re.compile(r"^Writing \.vcxproj file:")
-            if not _runInDebugShell(winCompileCmd, _graal_home, compilelogfile, winCompileSuccess):
+            if not _runInDebugShell(winCompileCmd, t_graal_home, t_compilelogfile, winCompileSuccess):
                 mx.log('Error executing create command')
                 return
-            winBuildCmd = 'msbuild ' + _graal_home + r'\build\vs-amd64\jvm.vcxproj /p:Configuration=' + project_config + ' /p:Platform=x64'
-            if not _runInDebugShell(winBuildCmd, _graal_home, compilelogfile):
+            winBuildCmd = 'msbuild ' + t_graal_home + r'\build\vs-amd64\jvm.vcxproj /p:Configuration=' + project_config + ' /p:Platform=x64'
+            if not _runInDebugShell(winBuildCmd, t_graal_home, t_compilelogfile):
                 mx.log('Error building project')
                 return
         else:
@@ -1442,7 +1451,8 @@
     _jacoco = 'off'
 
     t = Task('CleanAndBuildIdealGraphVisualizer')
-    mx.run(['ant', '-f', join(_graal_home, 'src', 'share', 'tools', 'IdealGraphVisualizer', 'build.xml'), '-q', 'clean', 'build'])
+    buildxml = mx._tpU2W(join(_graal_home, 'src', 'share', 'tools', 'IdealGraphVisualizer', 'build.xml'))
+    mx.run(['ant', '-f', buildxml, '-q', 'clean', 'build'])
     tasks.append(t.stop())
 
     # Prevent Graal modifications from breaking the standard builds
@@ -2235,13 +2245,13 @@
         findbugsJar = join(findbugsLib, 'findbugs.jar')
     assert exists(findbugsJar)
     nonTestProjects = [p for p in mx.projects() if not p.name.endswith('.test') and not p.name.endswith('.jtt')]
-    outputDirs = [p.output_dir() for p in nonTestProjects]
+    outputDirs = map(mx._tpU2W, [p.output_dir() for p in nonTestProjects])
     findbugsResults = join(_graal_home, 'findbugs.results')
 
-    cmd = ['-jar', findbugsJar, '-textui', '-low', '-maxRank', '15']
+    cmd = ['-jar', mx._tpU2W(findbugsJar), '-textui', '-low', '-maxRank', '15']
     if sys.stdout.isatty():
         cmd.append('-progress')
-    cmd = cmd + ['-auxclasspath', mx.classpath([d.name for d in _jdkDeployedDists] + [p.name for p in nonTestProjects]), '-output', findbugsResults, '-exitcode'] + args + outputDirs
+    cmd = cmd + ['-auxclasspath', mx.classpath([d.name for d in _jdkDeployedDists] + [p.name for p in nonTestProjects]), '-output', mx._tpU2W(findbugsResults), '-exitcode'] + args + outputDirs
     exitcode = mx.run_java(cmd, nonZeroIsFatal=False)
     if exitcode != 0:
         with open(findbugsResults) as fp:
--- a/mxtool/mx.py	Fri Sep 26 10:40:34 2014 -0700
+++ b/mxtool/mx.py	Fri Sep 26 10:41:19 2014 -0700
@@ -639,16 +639,7 @@
             return NotImplemented
 
     def is_present_in_jdk(self, jdk):
-        for e in jdk.bootclasspath().split(os.pathsep):
-            if basename(e) == self.jar:
-                return True
-        for d in jdk.extdirs().split(os.pathsep):
-            if len(d) and self.jar in os.listdir(d):
-                return True
-        for d in jdk.endorseddirs().split(os.pathsep):
-            if len(d) and self.jar in os.listdir(d):
-                return True
-        return False
+        return jdk.containsJar(self.jar)
 
     def all_deps(self, deps, includeLibs, includeSelf=True, includeJreLibs=False, includeAnnotationProcessors=False):
         """
@@ -1337,11 +1328,47 @@
         return 'linux'
     elif sys.platform.startswith('sunos'):
         return 'solaris'
-    elif sys.platform.startswith('win32') or sys.platform.startswith('cygwin'):
+    elif sys.platform.startswith('win32'):
         return 'windows'
+    elif sys.platform.startswith('cygwin'):
+        return 'cygwin'
     else:
         abort('Unknown operating system ' + sys.platform)
 
+def _tpU2W(p):
+    """
+    Translate a path from unix-style to windows-style
+    """
+    if p is None or get_os() != "cygwin":
+        return p
+    return subprocess.check_output(['cygpath', '-w', p]).strip()
+
+def _tpW2U(p):
+    """
+    Translate a path from windows-style to unix-style
+    """
+    if p is None or get_os() != "cygwin":
+        return p
+    return subprocess.check_output(['cygpath', '-u', p]).strip()
+
+def _tspU2W(p):
+    """
+    Translate a group of paths, seperated by a path seperator.
+    unix-style to windows-style.
+    """
+    if p is None or p == "" or get_os() != "cygwin":
+        return p
+    return ';'.join(map(_tpU2W, p.split(os.pathsep)))
+
+def _tspW2U(p):
+    """
+    Translate a group of paths, seperated by a path seperator.
+    windows-style to unix-style.
+    """
+    if p is None or p == "" or get_os() != "cygwin":
+        return p
+    return os.pathsep.join(map(_tpW2U, p.split(';')))
+
 def get_arch():
     machine = platform.uname()[4]
     if machine in ['amd64', 'AMD64', 'x86_64', 'i86pc']:
@@ -1530,7 +1557,8 @@
 
     if includeBootClasspath:
         result = os.pathsep.join([java().bootclasspath(), result])
-    return result
+
+    return _tspU2W(result)
 
 def classpath_walk(names=None, resolve=True, includeSelf=True, includeBootClasspath=False):
     """
@@ -1998,7 +2026,7 @@
         return cmp(self.parts, other.parts)
 
 def _filter_non_existant_paths(paths):
-    return os.pathsep.join([path for path in paths.split(os.pathsep) if exists(path)])
+    return os.pathsep.join([path for path in _tspW2U(paths).split(os.pathsep) if exists(path)])
 
 """
 A JavaConfig object encapsulates info on how Java commands are run.
@@ -2063,8 +2091,8 @@
             os.makedirs(outDir)
         javaSource = join(myDir, 'ClasspathDump.java')
         if not exists(join(outDir, 'ClasspathDump.class')):
-            subprocess.check_call([self.javac, '-d', outDir, javaSource], stderr=subprocess.PIPE, stdout=subprocess.PIPE)
-        self._bootclasspath, self._extdirs, self._endorseddirs = [x if x != 'null' else None for x in subprocess.check_output([self.java, '-cp', outDir, 'ClasspathDump'], stderr=subprocess.PIPE).split('|')]
+            subprocess.check_call([self.javac, '-d', _tpU2W(outDir), _tpU2W(javaSource)], stderr=subprocess.PIPE, stdout=subprocess.PIPE)
+        self._bootclasspath, self._extdirs, self._endorseddirs = [x if x != 'null' else None for x in subprocess.check_output([self.java, '-cp', _tspU2W(outDir), 'ClasspathDump'], stderr=subprocess.PIPE).split('|')]
         if not self._bootclasspath or not self._extdirs or not self._endorseddirs:
             warn("Could not find all classpaths: boot='" + str(self._bootclasspath) + "' extdirs='" + str(self._extdirs) + "' endorseddirs='" + str(self._endorseddirs) + "'")
         self._bootclasspath = _filter_non_existant_paths(self._bootclasspath)
@@ -2091,17 +2119,32 @@
     def bootclasspath(self):
         if self._bootclasspath is None:
             self._init_classpaths()
-        return self._bootclasspath
+        return _tspU2W(self._bootclasspath)
 
     def extdirs(self):
         if self._extdirs is None:
             self._init_classpaths()
-        return self._extdirs
+        return _tspU2W(self._extdirs)
 
     def endorseddirs(self):
         if self._endorseddirs is None:
             self._init_classpaths()
-        return self._endorseddirs
+        return _tspU2W(self._endorseddirs)
+
+    def containsJar(self, jar):
+        if self._bootclasspath is None:
+            self._init_classpaths()
+
+        for e in self._bootclasspath.split(os.pathsep):
+            if basename(e) == self.jar:
+                return True
+        for d in self._extdirs.split(os.pathsep):
+            if len(d) and self.jar in os.listdir(d):
+                return True
+        for d in self._endorseddirs.split(os.pathsep):
+            if len(d) and self.jar in os.listdir(d):
+                return True
+        return False
 
 def check_get_env(key):
     """
@@ -2232,11 +2275,11 @@
     javaSource = join(myDir, 'URLConnectionDownload.java')
     javaClass = join(myDir, 'URLConnectionDownload.class')
     if not exists(javaClass) or getmtime(javaClass) < getmtime(javaSource):
-        subprocess.check_call([java().javac, '-d', myDir, javaSource])
+        subprocess.check_call([java().javac, '-d', _tpU2W(myDir), _tpU2W(javaSource)])
     verbose = []
     if sys.stderr.isatty():
         verbose.append("-v")
-    if run([java().java, '-cp', myDir, 'URLConnectionDownload', path] + verbose + urls, nonZeroIsFatal=False) == 0:
+    if run([java().java, '-cp', _tpU2W(myDir), 'URLConnectionDownload', _tpU2W(path)] + verbose + urls, nonZeroIsFatal=False) == 0:
         return
 
     abort('Could not download to ' + path + ' from any of the following URLs:\n\n    ' +
@@ -2291,24 +2334,23 @@
     def execute(self):
         argfileName = join(self.proj.dir, 'javafilelist.txt')
         argfile = open(argfileName, 'wb')
-        argfile.write('\n'.join(self.javafilelist))
+        argfile.write('\n'.join(map(_tpU2W, self.javafilelist)))
         argfile.close()
 
         processorArgs = []
-
         processorPath = self.proj.annotation_processors_path()
         if processorPath:
             genDir = self.proj.source_gen_dir()
             if exists(genDir):
                 shutil.rmtree(genDir)
             os.mkdir(genDir)
-            processorArgs += ['-processorpath', join(processorPath), '-s', genDir]
+            processorArgs += ['-processorpath', _tspU2W(join(processorPath)), '-s', _tpU2W(genDir)]
         else:
             processorArgs += ['-proc:none']
 
         args = self.args
         jdk = self.jdk
-        outputDir = self.outputDir
+        outputDir = _tpU2W(self.outputDir)
         compliance = str(jdk.javaCompliance)
         cp = classpath(self.proj.name, includeSelf=True)
         toBeDeleted = [argfileName]
@@ -2323,7 +2365,7 @@
                     if jdk.debug_port is not None:
                         javacCmd += ['-J-Xdebug', '-J-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(jdk.debug_port)]
                     javacCmd += processorArgs
-                    javacCmd += ['@' + argfile.name]
+                    javacCmd += ['@' + _tpU2W(argfile.name)]
 
                     if not args.warnAPI:
                         javacCmd.append('-XDignore.symbol.file')