Merge
authoriveresov
Wed, 19 Apr 2017 04:10:56 +0000
changeset 46395 ab5b504181d8
parent 46392 d5572756efd6 (current diff)
parent 46394 c5bfe8f7bb1e (diff)
child 46396 4cca6758a9ee
child 46400 3b90b2f0d575
Merge
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArchHotSpotNodeCostProvider.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotNodeCostProvider.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotNodeCostProvider.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompileTheWorld.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompileTheWorldOptions.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/HotSpotNodeCostProvider.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/DefaultNodeCostProvider.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/NodeCostProvider.java
--- a/hotspot/src/jdk.internal.vm.compiler/.mx.graal/suite.py	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/.mx.graal/suite.py	Wed Apr 19 04:10:56 2017 +0000
@@ -199,6 +199,7 @@
       "dependencies" : [
         "org.graalvm.compiler.api.runtime",
         "org.graalvm.compiler.replacements",
+        "org.graalvm.compiler.printer",
         "org.graalvm.compiler.runtime",
       ],
       "imports" : [
@@ -929,6 +930,7 @@
       "subDir" : "share/classes",
       "sourceDirs" : ["src"],
       "dependencies" : [
+        "org.graalvm.util",
         "mx:JUNIT",
       ],
       "checkstyle" : "org.graalvm.compiler.graph",
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Address.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Address.java	Wed Apr 19 04:10:56 2017 +0000
@@ -286,7 +286,7 @@
                 return immediate & NumUtil.getNbitNumberInt(9);
             case IMMEDIATE_SCALED:
                 // Unsigned value can be returned as-is.
-                assert NumUtil.isUnsignedNbit(9, immediate);
+                assert NumUtil.isUnsignedNbit(12, immediate);
                 return immediate;
             case PC_LITERAL:
                 // 21-bit signed value, but lower 2 bits are always 0 and are shifted out.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ByteBufferTest.java	Wed Apr 19 04:10:56 2017 +0000
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2017, 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 org.graalvm.compiler.core.test;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.Collection;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class ByteBufferTest extends GraalCompilerTest {
+
+    class Ret {
+
+        byte byteValue = 0;
+        short shortValue = 0;
+        int intValue = 0;
+        float floatValue = 0.0f;
+        double doubleValue = 0.0d;
+
+        @Override
+        public boolean equals(Object obj) {
+            if (!(obj instanceof Ret)) {
+                return false;
+            }
+
+            Ret other = (Ret) obj;
+            if (this.byteValue != other.byteValue) {
+                return false;
+            }
+            if (this.shortValue != other.shortValue) {
+                return false;
+            }
+            if (this.intValue != other.intValue) {
+                return false;
+            }
+            if (Float.floatToRawIntBits(this.floatValue) != Float.floatToRawIntBits(other.floatValue)) {
+                return false;
+            }
+            if (Double.doubleToRawLongBits(this.doubleValue) != Double.doubleToRawLongBits(other.doubleValue)) {
+                return false;
+            }
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            return 0;
+        }
+
+        @Override
+        public String toString() {
+            return String.format("0x%02x, 0x%04x, 0x%08x, 0x%04x, 0x%08x", byteValue, shortValue, intValue, Float.floatToRawIntBits(floatValue), Double.doubleToRawLongBits(doubleValue));
+        }
+    }
+
+    @Parameters(name = "{0}")
+    public static Collection<Object[]> data() {
+        ArrayList<Object[]> ret = new ArrayList<>();
+        ret.add(new Object[]{ByteOrder.BIG_ENDIAN});
+        ret.add(new Object[]{ByteOrder.LITTLE_ENDIAN});
+        return ret;
+    }
+
+    @Parameter public ByteOrder byteOrder;
+
+    Ret alignedReadSnippet(byte[] arg) {
+        ByteBuffer buffer = ByteBuffer.wrap(arg).order(byteOrder);
+
+        Ret ret = new Ret();
+        ret.byteValue = buffer.get();
+        ret.byteValue += buffer.get();
+        ret.shortValue = buffer.getShort();
+        ret.intValue = buffer.getInt();
+        ret.doubleValue = buffer.getDouble();
+        ret.floatValue = buffer.getFloat();
+
+        return ret;
+    }
+
+    @Test
+    public void testReadAligned() {
+        byte[] input = new byte[20];
+        for (int i = 0; i < 20; i++) {
+            input[i] = (byte) (7 * (i + 42));
+        }
+        test("alignedReadSnippet", input);
+    }
+
+    byte[] alignedWriteSnippet(byte a, byte b, short c, int d, double e, float f) {
+        byte[] ret = new byte[20];
+        ByteBuffer buffer = ByteBuffer.wrap(ret).order(byteOrder);
+
+        buffer.put(a);
+        buffer.put(b);
+        buffer.putShort(c);
+        buffer.putInt(d);
+        buffer.putDouble(e);
+        buffer.putFloat(f);
+
+        return ret;
+    }
+
+    @Test
+    public void testWriteAligned() {
+        test("alignedWriteSnippet", (byte) 5, (byte) -3, (short) 17, 42, 84.72, 1.23f);
+    }
+
+    Ret unalignedReadSnippet(byte[] arg) {
+        ByteBuffer buffer = ByteBuffer.wrap(arg).order(byteOrder);
+
+        Ret ret = new Ret();
+        ret.byteValue = buffer.get();
+        ret.shortValue = buffer.getShort();
+        ret.intValue = buffer.getInt();
+        ret.doubleValue = buffer.getDouble();
+        ret.floatValue = buffer.getFloat();
+
+        return ret;
+    }
+
+    @Test
+    public void testReadUnaligned() {
+        byte[] input = new byte[19];
+        for (int i = 0; i < 19; i++) {
+            input[i] = (byte) (7 * (i + 42));
+        }
+        test("unalignedReadSnippet", input);
+    }
+
+    byte[] unalignedWriteSnippet(byte a, short b, int c, double d, float e) {
+        byte[] ret = new byte[20];
+        ByteBuffer buffer = ByteBuffer.wrap(ret).order(byteOrder);
+
+        buffer.put(a);
+        buffer.putShort(b);
+        buffer.putInt(c);
+        buffer.putDouble(d);
+        buffer.putFloat(e);
+
+        return ret;
+    }
+
+    @Test
+    public void testWriteUnaligned() {
+        test("unalignedWriteSnippet", (byte) -3, (short) 17, 42, 84.72, 1.23f);
+    }
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java	Wed Apr 19 04:10:56 2017 +0000
@@ -57,6 +57,7 @@
 import org.graalvm.compiler.debug.DebugEnvironment;
 import org.graalvm.compiler.debug.DelegatingDebugConfig;
 import org.graalvm.compiler.debug.GraalDebugConfig;
+import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.java.GraphBuilderPhase;
@@ -72,6 +73,7 @@
 import org.graalvm.compiler.phases.PhaseSuite;
 import org.graalvm.compiler.phases.VerifyPhase;
 import org.graalvm.compiler.phases.VerifyPhase.VerificationError;
+import org.graalvm.compiler.phases.contract.VerifyNodeCosts;
 import org.graalvm.compiler.phases.tiers.HighTierContext;
 import org.graalvm.compiler.phases.util.Providers;
 import org.graalvm.compiler.phases.verify.VerifyBailoutUsage;
@@ -114,17 +116,52 @@
         return true;
     }
 
-    private static boolean shouldProcess(String classpathEntry) {
-        if (classpathEntry.endsWith(".jar")) {
-            String name = new File(classpathEntry).getName();
-            return name.contains("jvmci") || name.contains("graal") || name.contains("jdk.internal.vm.compiler");
+    public static String relativeFileName(String absolutePath) {
+        int lastFileSeparatorIndex = absolutePath.lastIndexOf(File.separator);
+        return absolutePath.substring(lastFileSeparatorIndex >= 0 ? lastFileSeparatorIndex : 0);
+    }
+
+    public static class InvariantsTool {
+
+        protected boolean shouldProcess(String classpathEntry) {
+            if (classpathEntry.endsWith(".jar")) {
+                String name = new File(classpathEntry).getName();
+                return name.contains("jvmci") || name.contains("graal") || name.contains("jdk.internal.vm.compiler");
+            }
+            return false;
         }
-        return false;
+
+        protected String getClassPath() {
+            String bootclasspath;
+            if (Java8OrEarlier) {
+                bootclasspath = System.getProperty("sun.boot.class.path");
+            } else {
+                bootclasspath = System.getProperty("jdk.module.path") + File.pathSeparatorChar + System.getProperty("jdk.module.upgrade.path");
+            }
+            return bootclasspath;
+        }
+
+        protected boolean shouldLoadClass(String className) {
+            return !className.equals("module-info");
+        }
+
+        protected void handleClassLoadingException(Throwable t) {
+            GraalError.shouldNotReachHere(t);
+        }
+
+        protected void handleParsingException(Throwable t) {
+            GraalError.shouldNotReachHere(t);
+        }
     }
 
     @Test
     @SuppressWarnings("try")
     public void test() {
+        runTest(new InvariantsTool());
+    }
+
+    @SuppressWarnings("try")
+    public static void runTest(InvariantsTool tool) {
         RuntimeProvider rt = Graal.getRequiredCapability(RuntimeProvider.class);
         Providers providers = rt.getHostBackend().getProviders();
         MetaAccessProvider metaAccess = providers.getMetaAccess();
@@ -137,17 +174,12 @@
 
         Assume.assumeTrue(VerifyPhase.class.desiredAssertionStatus());
 
-        String bootclasspath;
-        if (Java8OrEarlier) {
-            bootclasspath = System.getProperty("sun.boot.class.path");
-        } else {
-            bootclasspath = System.getProperty("jdk.module.path") + File.pathSeparatorChar + System.getProperty("jdk.module.upgrade.path");
-        }
+        String bootclasspath = tool.getClassPath();
         Assert.assertNotNull("Cannot find boot class path", bootclasspath);
 
         final List<String> classNames = new ArrayList<>();
         for (String path : bootclasspath.split(File.pathSeparator)) {
-            if (shouldProcess(path)) {
+            if (tool.shouldProcess(path)) {
                 try {
                     final ZipFile zipFile = new ZipFile(new File(path));
                     for (final Enumeration<? extends ZipEntry> entry = zipFile.entries(); entry.hasMoreElements();) {
@@ -200,7 +232,7 @@
             // Order outer classes before the inner classes
             classNames.sort((String a, String b) -> a.compareTo(b));
             // Initialize classes in single thread to avoid deadlocking issues during initialization
-            List<Class<?>> classes = initializeClasses(classNames);
+            List<Class<?>> classes = initializeClasses(tool, classNames);
             for (Class<?> c : classes) {
                 String className = c.getName();
                 executor.execute(() -> {
@@ -234,7 +266,11 @@
                                     // Graal bail outs on certain patterns in Java bytecode (e.g.,
                                     // unbalanced monitors introduced by jacoco).
                                 } catch (Throwable e) {
-                                    errors.add(String.format("Error while checking %s:%n%s", methodName, printStackTraceToString(e)));
+                                    try {
+                                        tool.handleParsingException(e);
+                                    } catch (Throwable t) {
+                                        errors.add(String.format("Error while checking %s:%n%s", methodName, printStackTraceToString(e)));
+                                    }
                                 }
                             });
                         }
@@ -261,17 +297,17 @@
         }
     }
 
-    private static List<Class<?>> initializeClasses(List<String> classNames) {
+    private static List<Class<?>> initializeClasses(InvariantsTool tool, List<String> classNames) {
         List<Class<?>> classes = new ArrayList<>(classNames.size());
         for (String className : classNames) {
-            if (className.equals("module-info")) {
+            if (!tool.shouldLoadClass(className)) {
                 continue;
             }
             try {
                 Class<?> c = Class.forName(className, true, CheckGraalInvariants.class.getClassLoader());
                 classes.add(c);
-            } catch (ClassNotFoundException e) {
-                e.printStackTrace();
+            } catch (Throwable t) {
+                tool.handleClassLoadingException(t);
             }
         }
         return classes;
@@ -285,6 +321,7 @@
             if (c.getAnnotation(NodeInfo.class) == null) {
                 throw new AssertionError(String.format("Node subclass %s requires %s annotation", c.getName(), NodeClass.class.getSimpleName()));
             }
+            VerifyNodeCosts.verifyNodeClass(c);
         }
     }
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/NodePropertiesTest.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/NodePropertiesTest.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,9 +22,6 @@
  */
 package org.graalvm.compiler.core.test;
 
-import org.junit.Assert;
-import org.junit.Test;
-
 import org.graalvm.compiler.api.directives.GraalDirectives;
 import org.graalvm.compiler.debug.Debug;
 import org.graalvm.compiler.graph.Node;
@@ -35,13 +32,14 @@
 import org.graalvm.compiler.nodes.LoopBeginNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.ValueNode;
-import org.graalvm.compiler.nodes.spi.NodeCostProvider;
 import org.graalvm.compiler.phases.BasePhase;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase.CustomCanonicalizer;
 import org.graalvm.compiler.phases.contract.NodeCostUtil;
 import org.graalvm.compiler.phases.tiers.HighTierContext;
 import org.graalvm.compiler.phases.tiers.PhaseContext;
+import org.junit.Assert;
+import org.junit.Test;
 
 public class NodePropertiesTest extends GraalCompilerTest {
 
@@ -147,9 +145,8 @@
     }
 
     public static int arrayStoreTest(int a) {
-        String s = String.valueOf(a);
-        array[2] = s;
-        return s.length();
+        array[2] = a;
+        return a;
     }
 
     public static int fieldLoad(int a) {
@@ -164,10 +161,10 @@
     @Test
     public void testCanonicalizationExample() {
         HighTierContext htc = getDefaultHighTierContext();
-        ImprovementSavingCanonicalizer c1 = new ImprovementSavingCanonicalizer(htc.getNodeCostProvider());
+        ImprovementSavingCanonicalizer c1 = new ImprovementSavingCanonicalizer();
         StructuredGraph g1 = parseForCompile(getResolvedJavaMethod("test1Snippet"));
         new CanonicalizerPhase(c1).apply(g1, htc);
-        ImprovementSavingCanonicalizer c2 = new ImprovementSavingCanonicalizer(htc.getNodeCostProvider());
+        ImprovementSavingCanonicalizer c2 = new ImprovementSavingCanonicalizer();
         StructuredGraph g2 = parseForCompile(getResolvedJavaMethod("test2Snippet"));
         new CanonicalizerPhase(c2).apply(g2, htc);
         Assert.assertTrue(c1.savedCycles > c2.savedCycles);
@@ -270,7 +267,7 @@
         new CanonicalizerPhase().apply(g1, htc);
         GraphCostPhase gc1 = new GraphCostPhase();
         gc1.apply(g1, htc);
-        Assert.assertEquals(35, gc1.finalCycles, 25);
+        Assert.assertEquals(15, gc1.finalCycles, 25);
     }
 
     @Test
@@ -280,7 +277,7 @@
         new CanonicalizerPhase().apply(g1, htc);
         GraphCostPhase gc1 = new GraphCostPhase();
         gc1.apply(g1, htc);
-        Assert.assertEquals(50, gc1.finalCycles, 25);
+        Assert.assertEquals(15, gc1.finalCycles, 25);
     }
 
     @Test
@@ -290,7 +287,7 @@
         new CanonicalizerPhase().apply(g1, htc);
         GraphCostPhase gc1 = new GraphCostPhase();
         gc1.apply(g1, htc);
-        Assert.assertEquals(30, gc1.finalCycles, 25);
+        Assert.assertEquals(15, gc1.finalCycles, 25);
     }
 
     @Test
@@ -300,16 +297,11 @@
         new CanonicalizerPhase().apply(g1, htc);
         GraphCostPhase gc1 = new GraphCostPhase();
         gc1.apply(g1, htc);
-        Assert.assertEquals(40, gc1.finalCycles, 25);
+        Assert.assertEquals(15, gc1.finalCycles, 25);
     }
 
     static class ImprovementSavingCanonicalizer extends CustomCanonicalizer {
         private int savedCycles;
-        private final NodeCostProvider nodeCostProvider;
-
-        ImprovementSavingCanonicalizer(NodeCostProvider nodeCostProvider) {
-            this.nodeCostProvider = nodeCostProvider;
-        }
 
         @Override
         public void simplify(Node node, SimplifierTool tool) {
@@ -318,7 +310,7 @@
                 Canonicalizable.Binary<ValueNode> bc = (Canonicalizable.Binary<ValueNode>) node;
                 Node canonicalized = bc.canonical(tool, bc.getX(), bc.getY());
                 if (canonicalized != node) {
-                    savedCycles += nodeCostProvider.getEstimatedCPUCycles(node) - nodeCostProvider.getEstimatedCPUCycles(canonicalized);
+                    savedCycles += node.estimatedNodeCycles().value - canonicalized.estimatedNodeCycles().value;
                 }
             }
         }
@@ -330,8 +322,8 @@
 
         @Override
         protected void run(StructuredGraph graph, PhaseContext context) {
-            finalCycles = NodeCostUtil.computeGraphCycles(graph, context.getNodeCostProvider(), true);
-            finalSize = NodeCostUtil.computeGraphSize(graph, context.getNodeCostProvider());
+            finalCycles = NodeCostUtil.computeGraphCycles(graph, true);
+            finalSize = NodeCostUtil.computeGraphSize(graph);
         }
 
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReflectionOptionDescriptors.java	Wed Apr 19 04:10:56 2017 +0000
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 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 org.graalvm.compiler.core.test;
+
+import java.lang.annotation.RetentionPolicy;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionDescriptor;
+import org.graalvm.compiler.options.OptionDescriptors;
+import org.graalvm.compiler.options.OptionKey;
+import org.graalvm.compiler.options.OptionValues;
+import org.graalvm.util.EconomicMap;
+import org.graalvm.util.MapCursor;
+
+/**
+ * An implementation of {@link OptionDescriptor} that uses reflection to create descriptors from a
+ * list of field name and help text pairs. We cannot use the {@link Option} annotation as it has a
+ * {@link RetentionPolicy#SOURCE} retention policy.
+ *
+ * This class is useful for working with {@link OptionKey} and {@link OptionValues} but without
+ * having to rely on {@link Option} and its associated annotation processor.
+ */
+public class ReflectionOptionDescriptors implements OptionDescriptors {
+
+    /**
+     * Extracts name/value entries from a set of properties based on a given name prefix.
+     *
+     * @param properties the properties set to extract from
+     * @param prefix entries whose names start with this prefix are extracted
+     * @param stripPrefix specifies whether to remove the prefix from the names in the returned map
+     */
+    public static EconomicMap<String, String> extractEntries(Properties properties, String prefix, boolean stripPrefix) {
+        EconomicMap<String, String> matches = EconomicMap.create();
+        for (Map.Entry<Object, Object> e : properties.entrySet()) {
+            String name = (String) e.getKey();
+            if (name.startsWith(prefix)) {
+                String value = (String) e.getValue();
+                if (stripPrefix) {
+                    name = name.substring(prefix.length());
+                }
+                matches.put(name, value);
+            }
+        }
+        return matches;
+    }
+
+    private final EconomicMap<String, OptionDescriptor> descriptors = EconomicMap.create();
+
+    public ReflectionOptionDescriptors(Class<?> declaringClass, String... fieldsAndHelp) {
+        assert fieldsAndHelp.length % 2 == 0;
+        for (int i = 0; i < fieldsAndHelp.length; i += 2) {
+            String fieldName = fieldsAndHelp[i];
+            String help = fieldsAndHelp[i + 1];
+            addOption(declaringClass, fieldName, help);
+        }
+    }
+
+    public ReflectionOptionDescriptors(Class<?> declaringClass, EconomicMap<String, String> fieldsAndHelp) {
+        MapCursor<String, String> cursor = fieldsAndHelp.getEntries();
+        while (cursor.advance()) {
+            String fieldName = cursor.getKey();
+            String help = cursor.getValue();
+            addOption(declaringClass, fieldName, help);
+        }
+    }
+
+    private void addOption(Class<?> declaringClass, String fieldName, String help) {
+        try {
+            Field f = declaringClass.getDeclaredField(fieldName);
+            if (!OptionKey.class.isAssignableFrom(f.getType())) {
+                throw new IllegalArgumentException(String.format("Option field must be of type %s: %s", OptionKey.class.getName(), f));
+            }
+            if (!Modifier.isStatic(f.getModifiers())) {
+                throw new IllegalArgumentException(String.format("Option field must be static: %s", f));
+            }
+            f.setAccessible(true);
+            Type declaredType = f.getAnnotatedType().getType();
+            if (!(declaredType instanceof ParameterizedType)) {
+                throw new IllegalArgumentException(String.format("Option field must have a parameterized type: %s", f));
+            }
+            ParameterizedType pt = (ParameterizedType) declaredType;
+            Type[] actualTypeArguments = pt.getActualTypeArguments();
+            assert actualTypeArguments.length == 1;
+            Class<?> optionType = (Class<?>) actualTypeArguments[0];
+            descriptors.put(fieldName, OptionDescriptor.create(fieldName, optionType, help, declaringClass, fieldName, (OptionKey<?>) f.get(null)));
+        } catch (IllegalAccessException | NoSuchFieldException e) {
+            throw new IllegalArgumentException(e);
+        }
+    }
+
+    @Override
+    public Iterator<OptionDescriptor> iterator() {
+        return descriptors.getValues().iterator();
+    }
+
+    @Override
+    public OptionDescriptor get(String value) {
+        return descriptors.get(value);
+    }
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyDebugUsageTest.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyDebugUsageTest.java	Wed Apr 19 04:10:56 2017 +0000
@@ -205,7 +205,7 @@
     private static class InvalidGraalErrorGuaranteePhase extends Phase {
         @Override
         protected void run(StructuredGraph graph) {
-            GraalError.guarantee(graph.getNodes().count() > 0, "Graph must contain nodes %s %s %s", graph, graph, graph, graph.toString());
+            GraalError.guarantee(graph.getNodes().count() > 0, "Graph must contain nodes %s %s %s", graph, graph, graph.toString());
         }
     }
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompiler.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompiler.java	Wed Apr 19 04:10:56 2017 +0000
@@ -298,18 +298,10 @@
             assert startBlock != null;
             assert startBlock.getPredecessorCount() == 0;
 
-            LIR lir = null;
-            AbstractBlockBase<?>[] codeEmittingOrder = null;
-            AbstractBlockBase<?>[] linearScanOrder = null;
-            try (Scope s = Debug.scope("ComputeLinearScanOrder", lir)) {
-                codeEmittingOrder = ComputeBlockOrder.computeCodeEmittingOrder(blocks.length, startBlock);
-                linearScanOrder = ComputeBlockOrder.computeLinearScanOrder(blocks.length, startBlock);
+            AbstractBlockBase<?>[] codeEmittingOrder = ComputeBlockOrder.computeCodeEmittingOrder(blocks.length, startBlock);
+            AbstractBlockBase<?>[] linearScanOrder = ComputeBlockOrder.computeLinearScanOrder(blocks.length, startBlock);
+            LIR lir = new LIR(schedule.getCFG(), linearScanOrder, codeEmittingOrder, graph.getOptions());
 
-                lir = new LIR(schedule.getCFG(), linearScanOrder, codeEmittingOrder, graph.getOptions());
-                Debug.dump(Debug.INFO_LEVEL, lir, "After linear scan order");
-            } catch (Throwable e) {
-                throw Debug.handle(e);
-            }
             FrameMapBuilder frameMapBuilder = backend.newFrameMapBuilder(registerConfig);
             LIRGenerationResult lirGenRes = backend.newLIRGenerationResult(graph.compilationId(), lir, frameMapBuilder, graph, stub);
             LIRGeneratorTool lirGen = backend.newLIRGenerator(lirGenRes);
@@ -320,9 +312,9 @@
             new LIRGenerationPhase().apply(backend.getTarget(), lirGenRes, context);
 
             try (Scope s = Debug.scope("LIRStages", nodeLirGen, lir)) {
-                Debug.dump(Debug.BASIC_LEVEL, lir, "After LIR generation");
+                // Dump LIR along with HIR (the LIR is looked up from context)
+                Debug.dump(Debug.BASIC_LEVEL, graph.getLastSchedule(), "After LIR generation");
                 LIRGenerationResult result = emitLowLevel(backend.getTarget(), lirGenRes, lirGen, lirSuites, backend.newRegisterAllocationConfig(registerConfig, allocationRestrictedTo));
-                Debug.dump(Debug.BASIC_LEVEL, lir, "Before code generation");
                 return result;
             } catch (Throwable e) {
                 throw Debug.handle(e);
@@ -349,12 +341,15 @@
                     RegisterAllocationConfig registerAllocationConfig) {
         PreAllocationOptimizationContext preAllocOptContext = new PreAllocationOptimizationContext(lirGen);
         lirSuites.getPreAllocationOptimizationStage().apply(target, lirGenRes, preAllocOptContext);
+        Debug.dump(Debug.BASIC_LEVEL, lirGenRes.getLIR(), "After PreAllocationOptimizationStage");
 
         AllocationContext allocContext = new AllocationContext(lirGen.getSpillMoveFactory(), registerAllocationConfig);
         lirSuites.getAllocationStage().apply(target, lirGenRes, allocContext);
+        Debug.dump(Debug.BASIC_LEVEL, lirGenRes.getLIR(), "After AllocationStage");
 
         PostAllocationOptimizationContext postAllocOptContext = new PostAllocationOptimizationContext(lirGen);
         lirSuites.getPostAllocationOptimizationStage().apply(target, lirGenRes, postAllocOptContext);
+        Debug.dump(Debug.BASIC_LEVEL, lirGenRes.getLIR(), "After PostAllocationOptimizationStage");
 
         return lirGenRes;
     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Debug.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Debug.java	Wed Apr 19 04:10:56 2017 +0000
@@ -127,6 +127,9 @@
      *
      * For HIR dumping, only ~5 graphs per method: after parsing, after inlining, after high tier,
      * after mid tier, after low tier.
+     *
+     * LIR dumping: After LIR generation, after each pre-allocation, allocation and post allocation
+     * stage, and after code installation.
      */
     public static final int BASIC_LEVEL = 1;
 
@@ -134,6 +137,8 @@
      * Informational debug level.
      *
      * HIR dumping: One graph after each applied top-level phase.
+     *
+     * LIR dumping: After each applied phase.
      */
     public static final int INFO_LEVEL = 2;
 
@@ -141,6 +146,8 @@
      * Verbose debug level.
      *
      * HIR dumping: One graph after each phase (including sub phases).
+     *
+     * LIR dumping: After each phase including sub phases.
      */
     public static final int VERBOSE_LEVEL = 3;
 
@@ -148,6 +155,8 @@
      * Detailed debug level.
      *
      * HIR dumping: Graphs within phases where interesting for a phase, max ~5 per phase.
+     *
+     * LIR dumping: Dump CFG within phases where interesting.
      */
     public static final int DETAILED_LEVEL = 4;
 
@@ -155,6 +164,8 @@
      * Very detailed debug level.
      *
      * HIR dumping: Graphs per node granularity graph change (before/after change).
+     *
+     * LIR dumping: Intermediate CFGs of phases where interesting.
      */
     public static final int VERY_DETAILED_LEVEL = 5;
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/GraalDebugConfig.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/GraalDebugConfig.java	Wed Apr 19 04:10:56 2017 +0000
@@ -117,6 +117,7 @@
         public static final OptionKey<Integer> PrintBinaryGraphPort = new OptionKey<>(4445);
         @Option(help = "Schedule graphs as they are dumped.", type = OptionType.Debug)
         public static final OptionKey<Boolean> PrintGraphWithSchedule = new OptionKey<>(false);
+
         @Option(help = "Enable dumping Truffle ASTs to the IdealGraphVisualizer.", type = OptionType.Debug)
         public static final OptionKey<Boolean> PrintTruffleTrees = new OptionKey<>(true);
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/GraalError.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/GraalError.java	Wed Apr 19 04:10:56 2017 +0000
@@ -60,10 +60,75 @@
      * if possible.
      *
      * @param condition the condition to check
+     * @param msg the message that will be associated with the error
+     */
+    public static void guarantee(boolean condition, String msg) {
+        if (!condition) {
+            throw new GraalError("failed guarantee: " + msg);
+        }
+    }
+
+    /**
+     * Checks a given condition and throws a {@link GraalError} if it is false. Guarantees are
+     * stronger than assertions in that they are always checked. Error messages for guarantee
+     * violations should clearly indicate the nature of the problem as well as a suggested solution
+     * if possible.
+     *
+     * @param condition the condition to check
+     * @param msg the message that will be associated with the error, in
+     *            {@link String#format(String, Object...)} syntax
+     * @param arg argument to the format string in {@code msg}
+     */
+    public static void guarantee(boolean condition, String msg, Object arg) {
+        if (!condition) {
+            throw new GraalError("failed guarantee: " + msg, arg);
+        }
+    }
+
+    /**
+     * Checks a given condition and throws a {@link GraalError} if it is false. Guarantees are
+     * stronger than assertions in that they are always checked. Error messages for guarantee
+     * violations should clearly indicate the nature of the problem as well as a suggested solution
+     * if possible.
+     *
+     * @param condition the condition to check
      * @param msg the message that will be associated with the error, in
      *            {@link String#format(String, Object...)} syntax
-     * @param args arguments to the format string
+     * @param arg1 argument to the format string in {@code msg}
+     * @param arg2 argument to the format string in {@code msg}
      */
+    public static void guarantee(boolean condition, String msg, Object arg1, Object arg2) {
+        if (!condition) {
+            throw new GraalError("failed guarantee: " + msg, arg1, arg2);
+        }
+    }
+
+    /**
+     * Checks a given condition and throws a {@link GraalError} if it is false. Guarantees are
+     * stronger than assertions in that they are always checked. Error messages for guarantee
+     * violations should clearly indicate the nature of the problem as well as a suggested solution
+     * if possible.
+     *
+     * @param condition the condition to check
+     * @param msg the message that will be associated with the error, in
+     *            {@link String#format(String, Object...)} syntax
+     * @param arg1 argument to the format string in {@code msg}
+     * @param arg2 argument to the format string in {@code msg}
+     * @param arg3 argument to the format string in {@code msg}
+     */
+    public static void guarantee(boolean condition, String msg, Object arg1, Object arg2, Object arg3) {
+        if (!condition) {
+            throw new GraalError("failed guarantee: " + msg, arg1, arg2, arg3);
+        }
+    }
+
+    /**
+     * This override exists to catch cases when {@link #guarantee(boolean, String, Object)} is
+     * called with one argument bound to a varargs method parameter. It will bind to this method
+     * instead of the single arg variant and produce a deprecation warning instead of silently
+     * wrapping the Object[] inside of another Object[].
+     */
+    @Deprecated
     public static void guarantee(boolean condition, String msg, Object... args) {
         if (!condition) {
             throw new GraalError("failed guarantee: " + msg, args);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Graph.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Graph.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,6 +22,9 @@
  */
 package org.graalvm.compiler.graph;
 
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Iterator;
@@ -793,7 +796,7 @@
     }
 
     // Fully qualified annotation name is required to satisfy javac
-    @org.graalvm.compiler.nodeinfo.NodeInfo
+    @org.graalvm.compiler.nodeinfo.NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
     static final class PlaceHolderNode extends Node {
 
         public static final NodeClass<PlaceHolderNode> TYPE = NodeClass.create(PlaceHolderNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java	Wed Apr 19 04:10:56 2017 +0000
@@ -52,7 +52,9 @@
 import org.graalvm.compiler.graph.spi.Simplifiable;
 import org.graalvm.compiler.graph.spi.SimplifierTool;
 import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeCycles;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodeinfo.NodeSize;
 import org.graalvm.compiler.nodeinfo.Verbosity;
 import org.graalvm.compiler.options.OptionValues;
 
@@ -606,10 +608,18 @@
     }
 
     private boolean checkReplaceWith(Node other) {
-        assert assertTrue(graph == null || !graph.isFrozen(), "cannot modify frozen graph");
-        assert assertFalse(other == this, "cannot replace a node with itself");
-        assert assertFalse(isDeleted(), "cannot replace deleted node");
-        assert assertTrue(other == null || !other.isDeleted(), "cannot replace with deleted node %s", other);
+        if (graph != null && graph.isFrozen()) {
+            fail("cannot modify frozen graph");
+        }
+        if (other == this) {
+            fail("cannot replace a node with itself");
+        }
+        if (isDeleted()) {
+            fail("cannot replace deleted node");
+        }
+        if (other != null && other.isDeleted()) {
+            fail("cannot replace with deleted node %s", other);
+        }
         return true;
     }
 
@@ -640,7 +650,7 @@
     }
 
     protected void replaceAtAllUsages(Node other, Node toBeDeleted) {
-        assert checkReplaceWith(other);
+        checkReplaceWith(other);
         if (usage0 == null) {
             return;
         }
@@ -679,12 +689,14 @@
     }
 
     private void replaceAtMatchingUsages(Node other, Predicate<Node> filter, Node toBeDeleted) {
-        assert filter != null;
-        assert checkReplaceWith(other);
+        if (filter == null) {
+            fail("filter cannot be null");
+        }
+        checkReplaceWith(other);
         int i = 0;
         while (i < this.getUsageCount()) {
             Node usage = this.getUsageAt(i);
-            if (filter == null || filter.test(usage)) {
+            if (filter.test(usage)) {
                 replaceAtUsage(other, toBeDeleted, usage);
                 this.movUsageFromEndTo(i);
             } else {
@@ -704,12 +716,12 @@
     }
 
     public void replaceAtMatchingUsages(Node other, NodePredicate usagePredicate) {
-        assert checkReplaceWith(other);
+        checkReplaceWith(other);
         replaceAtMatchingUsages(other, usagePredicate, null);
     }
 
     public void replaceAtUsages(InputType type, Node other) {
-        assert checkReplaceWith(other);
+        checkReplaceWith(other);
         for (Node usage : usages().snapshot()) {
             for (Position pos : usage.inputPositions()) {
                 if (pos.getInputType() == type && pos.get(usage) == this) {
@@ -746,17 +758,20 @@
     }
 
     public void replaceAtPredecessor(Node other) {
-        assert checkReplaceWith(other);
+        checkReplaceWith(other);
         if (predecessor != null) {
-            boolean result = predecessor.getNodeClass().replaceFirstSuccessor(predecessor, this, other);
-            assert assertTrue(result, "not found in successors, predecessor: %s", predecessor);
+            if (!predecessor.getNodeClass().replaceFirstSuccessor(predecessor, this, other)) {
+                fail("not found in successors, predecessor: %s", predecessor);
+            }
             predecessor.updatePredecessor(this, other);
         }
     }
 
     public void replaceAndDelete(Node other) {
-        assert checkReplaceWith(other);
-        assert other != null;
+        checkReplaceWith(other);
+        if (other == null) {
+            fail("cannot replace with null");
+        }
         if (this.hasUsages()) {
             replaceAtUsages(other);
         }
@@ -1173,4 +1188,13 @@
     public final void pushInputs(NodeStack stack) {
         getNodeClass().pushInputs(this, stack);
     }
+
+    public NodeSize estimatedNodeSize() {
+        return nodeClass.size();
+    }
+
+    public NodeCycles estimatedNodeCycles() {
+        return nodeClass.cycles();
+    }
+
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java	Wed Apr 19 04:10:56 2017 +0000
@@ -941,6 +941,10 @@
         return this.leafId;
     }
 
+    public NodeClass<? super T> getSuperNodeClass() {
+        return superNodeClass;
+    }
+
     public long inputsIteration() {
         return inputsIteration;
     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/spi/CanonicalizerTool.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/spi/CanonicalizerTool.java	Wed Apr 19 04:10:56 2017 +0000
@@ -50,10 +50,10 @@
     boolean allUsagesAvailable();
 
     /**
-     * Indicates whether the target platform supports comparison of integers of a particular bit
-     * width. This check is used by canonicalizations that might introduce subword compares.
+     * Indicates the smallest width for comparing an integer value on the target platform. If this
+     * method returns null, then there is no known smallest compare width.
      */
-    boolean supportSubwordCompare(int bits);
+    Integer smallestCompareWidth();
 
     OptionValues getOptions();
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackendFactory.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackendFactory.java	Wed Apr 19 04:10:56 2017 +0000
@@ -46,10 +46,8 @@
 import org.graalvm.compiler.hotspot.meta.HotSpotSnippetReflectionProvider;
 import org.graalvm.compiler.hotspot.meta.HotSpotStampProvider;
 import org.graalvm.compiler.hotspot.meta.HotSpotSuitesProvider;
-import org.graalvm.compiler.hotspot.nodes.HotSpotNodeCostProvider;
 import org.graalvm.compiler.hotspot.word.HotSpotWordTypes;
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
-import org.graalvm.compiler.nodes.spi.NodeCostProvider;
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
 import org.graalvm.compiler.phases.util.Providers;
@@ -107,7 +105,6 @@
         HotSpotSuitesProvider suites;
         HotSpotWordTypes wordTypes;
         Plugins plugins;
-        NodeCostProvider nodeCostProvider;
         BytecodeProvider bytecodeProvider;
         try (InitTimer t = timer("create providers")) {
             try (InitTimer rt = timer("create HotSpotRegisters provider")) {
@@ -125,11 +122,8 @@
             try (InitTimer rt = timer("create Lowerer provider")) {
                 lowerer = createLowerer(graalRuntime, metaAccess, foreignCalls, registers, constantReflection, target);
             }
-            try (InitTimer rt = timer("create NodeCost provider")) {
-                nodeCostProvider = createNodeCostProvider();
-            }
             HotSpotStampProvider stampProvider = new HotSpotStampProvider();
-            Providers p = new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, null, stampProvider, nodeCostProvider);
+            Providers p = new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, null, stampProvider);
 
             try (InitTimer rt = timer("create SnippetReflection provider")) {
                 snippetReflection = createSnippetReflection(graalRuntime, constantReflection, wordTypes);
@@ -147,7 +141,7 @@
             try (InitTimer rt = timer("create Suites provider")) {
                 suites = createSuites(config, graalRuntime, compilerConfiguration, plugins);
             }
-            providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, replacements, nodeCostProvider, suites, registers,
+            providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, replacements, suites, registers,
                             snippetReflection, wordTypes,
                             plugins);
         }
@@ -194,10 +188,6 @@
         return new AArch64HotSpotLoweringProvider(runtime, metaAccess, foreignCalls, registers, constantReflection, target);
     }
 
-    protected HotSpotNodeCostProvider createNodeCostProvider() {
-        return new AArchHotSpotNodeCostProvider();
-    }
-
     protected static Value[] createNativeABICallerSaveRegisters(@SuppressWarnings("unused") GraalHotSpotVMConfig config, RegisterConfig regConfig) {
         AArch64HotSpotRegisterConfig conf = (AArch64HotSpotRegisterConfig) regConfig;
         RegisterArray callerSavedRegisters = conf.getCallerSaveRegisters();
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotMove.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotMove.java	Wed Apr 19 04:10:56 2017 +0000
@@ -24,6 +24,7 @@
 
 import static jdk.vm.ci.aarch64.AArch64.zr;
 import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT;
 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL;
 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
@@ -105,7 +106,7 @@
         public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
             Register resultRegister = asRegister(result);
             Register ptr = asRegister(input);
-            Register base = asRegister(baseRegister);
+            Register base = (isRegister(baseRegister) ? asRegister(baseRegister) : zr);
             // result = (ptr - base) >> shift
             if (!encoding.hasBase()) {
                 if (encoding.hasShift()) {
@@ -156,7 +157,7 @@
         public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
             Register ptr = asRegister(input);
             Register resultRegister = asRegister(result);
-            Register base = asRegister(baseRegister);
+            Register base = (isRegister(baseRegister) ? asRegister(baseRegister) : zr);
             // result = base + (ptr << shift)
             if (nonNull) {
                 masm.add(64, resultRegister, base, ptr, AArch64Assembler.ShiftType.LSL, encoding.getShift());
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64RawNativeCallNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64RawNativeCallNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -23,7 +23,7 @@
 package org.graalvm.compiler.hotspot.aarch64;
 
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_20;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
 
 import org.graalvm.compiler.core.aarch64.AArch64NodeLIRBuilder;
 import org.graalvm.compiler.core.common.type.RawPointerStamp;
@@ -46,7 +46,7 @@
 import jdk.vm.ci.meta.ResolvedJavaType;
 import jdk.vm.ci.meta.Value;
 
-@NodeInfo(cycles = CYCLES_UNKNOWN, cyclesRationale = "Native call is a block hole", size = SIZE_20)
+@NodeInfo(cycles = CYCLES_UNKNOWN, cyclesRationale = "Native call is a block hole", size = SIZE_UNKNOWN)
 public final class AArch64RawNativeCallNode extends FixedWithNextNode implements LIRLowerable {
     public static final NodeClass<AArch64RawNativeCallNode> TYPE = NodeClass.create(AArch64RawNativeCallNode.class);
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArchHotSpotNodeCostProvider.java	Tue Apr 18 20:10:55 2017 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2016, 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 org.graalvm.compiler.hotspot.aarch64;
-
-import org.graalvm.compiler.graph.Node;
-import org.graalvm.compiler.hotspot.nodes.HotSpotNodeCostProvider;
-import org.graalvm.compiler.nodeinfo.NodeCycles;
-import org.graalvm.compiler.nodeinfo.NodeSize;
-
-public class AArchHotSpotNodeCostProvider extends HotSpotNodeCostProvider {
-
-    @Override
-    public NodeCycles cycles(Node n) {
-        return super.cycles(n);
-    }
-
-    @Override
-    public NodeSize size(Node n) {
-        return super.size(n);
-    }
-}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackendFactory.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackendFactory.java	Wed Apr 19 04:10:56 2017 +0000
@@ -46,10 +46,8 @@
 import org.graalvm.compiler.hotspot.meta.HotSpotSnippetReflectionProvider;
 import org.graalvm.compiler.hotspot.meta.HotSpotStampProvider;
 import org.graalvm.compiler.hotspot.meta.HotSpotSuitesProvider;
-import org.graalvm.compiler.hotspot.nodes.HotSpotNodeCostProvider;
 import org.graalvm.compiler.hotspot.word.HotSpotWordTypes;
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
-import org.graalvm.compiler.nodes.spi.NodeCostProvider;
 import org.graalvm.compiler.nodes.spi.Replacements;
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
@@ -108,7 +106,6 @@
         HotSpotSuitesProvider suites;
         HotSpotWordTypes wordTypes;
         Plugins plugins;
-        NodeCostProvider nodeCostProvider;
         BytecodeProvider bytecodeProvider;
         try (InitTimer t = timer("create providers")) {
             try (InitTimer rt = timer("create HotSpotRegisters provider")) {
@@ -126,11 +123,8 @@
             try (InitTimer rt = timer("create Lowerer provider")) {
                 lowerer = createLowerer(graalRuntime, metaAccess, foreignCalls, registers, constantReflection, target);
             }
-            try (InitTimer rt = timer("create NodeCost provider")) {
-                nodeCostProvider = createNodeCostProvider(target);
-            }
             HotSpotStampProvider stampProvider = new HotSpotStampProvider();
-            Providers p = new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, null, stampProvider, nodeCostProvider);
+            Providers p = new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, null, stampProvider);
 
             try (InitTimer rt = timer("create SnippetReflection provider")) {
                 snippetReflection = createSnippetReflection(graalRuntime, constantReflection, wordTypes);
@@ -148,7 +142,7 @@
             try (InitTimer rt = timer("create Suites provider")) {
                 suites = createSuites(config, graalRuntime, compilerConfiguration, plugins, registers, replacements, options);
             }
-            providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, replacements, nodeCostProvider, suites, registers,
+            providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, replacements, suites, registers,
                             snippetReflection, wordTypes,
                             plugins);
         }
@@ -201,10 +195,6 @@
         return new AMD64HotSpotLoweringProvider(runtime, metaAccess, foreignCalls, registers, constantReflection, target);
     }
 
-    protected HotSpotNodeCostProvider createNodeCostProvider(TargetDescription target) {
-        return new AMD64HotSpotNodeCostProvider(target);
-    }
-
     protected Value[] createNativeABICallerSaveRegisters(GraalHotSpotVMConfig config, RegisterConfig regConfig) {
         List<Register> callerSave = new ArrayList<>(regConfig.getAllocatableRegisters().asList());
         if (config.windowsOs) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLoweringProvider.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLoweringProvider.java	Wed Apr 19 04:10:56 2017 +0000
@@ -120,7 +120,7 @@
     }
 
     @Override
-    public boolean supportSubwordCompare(int bits) {
-        return true;
+    public Integer smallestCompareWidth() {
+        return 8;
     }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotNodeCostProvider.java	Tue Apr 18 20:10:55 2017 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-/*
- * Copyright (c) 2016, 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 org.graalvm.compiler.hotspot.amd64;
-
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_15;
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_50;
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_6;
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_80;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_30;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_4;
-
-import org.graalvm.compiler.graph.Node;
-import org.graalvm.compiler.hotspot.nodes.HotSpotNodeCostProvider;
-import org.graalvm.compiler.nodeinfo.NodeCycles;
-import org.graalvm.compiler.nodeinfo.NodeSize;
-import org.graalvm.compiler.nodes.ReturnNode;
-import org.graalvm.compiler.replacements.nodes.ArrayEqualsNode;
-import org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode;
-
-import jdk.vm.ci.amd64.AMD64;
-import jdk.vm.ci.amd64.AMD64.CPUFeature;
-import jdk.vm.ci.code.TargetDescription;
-
-public class AMD64HotSpotNodeCostProvider extends HotSpotNodeCostProvider {
-    private final boolean avx2;
-    private final boolean sse41;
-
-    public AMD64HotSpotNodeCostProvider(TargetDescription target) {
-        this.avx2 = ((AMD64) target.arch).getFeatures().contains(CPUFeature.AVX2);
-        this.sse41 = ((AMD64) target.arch).getFeatures().contains(CPUFeature.SSE4_1);
-    }
-
-    @Override
-    public NodeCycles cycles(Node n) {
-        if (n instanceof UnaryMathIntrinsicNode) {
-            UnaryMathIntrinsicNode u = (UnaryMathIntrinsicNode) n;
-            switch (u.getOperation()) {
-                case LOG:
-                case LOG10:
-                    return CYCLES_15;
-                default:
-                    break;
-            }
-        } else if (n instanceof ReturnNode) {
-            return CYCLES_6;
-        } else if (n instanceof ArrayEqualsNode) {
-            if (avx2) {
-                return CYCLES_50;
-            } else if (sse41) {
-                return CYCLES_80;
-            }
-        }
-        return super.cycles(n);
-    }
-
-    @Override
-    public NodeSize size(Node n) {
-        if (n instanceof UnaryMathIntrinsicNode) {
-            UnaryMathIntrinsicNode u = (UnaryMathIntrinsicNode) n;
-            switch (u.getOperation()) {
-                case LOG:
-                case LOG10:
-                    return SIZE_30;
-                default:
-                    break;
-            }
-        } else if (n instanceof ReturnNode) {
-            return SIZE_4;
-        }
-        return super.size(n);
-    }
-
-}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64RawNativeCallNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64RawNativeCallNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -23,7 +23,6 @@
 package org.graalvm.compiler.hotspot.amd64;
 
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_20;
 
 import org.graalvm.compiler.core.amd64.AMD64NodeLIRBuilder;
 import org.graalvm.compiler.core.common.type.RawPointerStamp;
@@ -32,6 +31,7 @@
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.graph.NodeInputList;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodeinfo.NodeSize;
 import org.graalvm.compiler.nodes.FixedWithNextNode;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.spi.LIRLowerable;
@@ -46,7 +46,7 @@
 import jdk.vm.ci.meta.ResolvedJavaType;
 import jdk.vm.ci.meta.Value;
 
-@NodeInfo(cycles = CYCLES_UNKNOWN, cyclesRationale = "Native call is a block hole", size = SIZE_20)
+@NodeInfo(cycles = CYCLES_UNKNOWN, cyclesRationale = "Native call is a block hole", size = NodeSize.SIZE_UNKNOWN)
 public final class AMD64RawNativeCallNode extends FixedWithNextNode implements LIRLowerable {
     public static final NodeClass<AMD64RawNativeCallNode> TYPE = NodeClass.create(AMD64RawNativeCallNode.class);
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackendFactory.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackendFactory.java	Wed Apr 19 04:10:56 2017 +0000
@@ -44,11 +44,9 @@
 import org.graalvm.compiler.hotspot.meta.HotSpotSnippetReflectionProvider;
 import org.graalvm.compiler.hotspot.meta.HotSpotStampProvider;
 import org.graalvm.compiler.hotspot.meta.HotSpotSuitesProvider;
-import org.graalvm.compiler.hotspot.nodes.HotSpotNodeCostProvider;
 import org.graalvm.compiler.hotspot.word.HotSpotWordTypes;
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import org.graalvm.compiler.nodes.spi.LoweringProvider;
-import org.graalvm.compiler.nodes.spi.NodeCostProvider;
 import org.graalvm.compiler.nodes.spi.Replacements;
 import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
 import org.graalvm.compiler.phases.util.Providers;
@@ -98,15 +96,14 @@
         HotSpotForeignCallsProvider foreignCalls = new SPARCHotSpotForeignCallsProvider(jvmciRuntime, runtime, metaAccess, codeCache, wordTypes, nativeABICallerSaveRegisters);
         LoweringProvider lowerer = createLowerer(runtime, metaAccess, foreignCalls, registers, constantReflection, target);
         HotSpotStampProvider stampProvider = new HotSpotStampProvider();
-        NodeCostProvider nodeCostProvider = new SPARCHotSpotNodeCostProvider();
-        Providers p = new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, null, stampProvider, nodeCostProvider);
+        Providers p = new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, null, stampProvider);
         HotSpotSnippetReflectionProvider snippetReflection = new HotSpotSnippetReflectionProvider(runtime, constantReflection, wordTypes);
         BytecodeProvider bytecodeProvider = new ClassfileBytecodeProvider(metaAccess, snippetReflection);
         HotSpotReplacementsImpl replacements = new HotSpotReplacementsImpl(runtime.getOptions(), p, snippetReflection, bytecodeProvider, target);
         Plugins plugins = createGraphBuilderPlugins(config, metaAccess, constantReflection, foreignCalls, stampProvider, snippetReflection, replacements, wordTypes);
         replacements.setGraphBuilderPlugins(plugins);
         HotSpotSuitesProvider suites = createSuites(config, runtime, compilerConfiguration, plugins, replacements);
-        HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, replacements, nodeCostProvider, suites, registers,
+        HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, replacements, suites, registers,
                         snippetReflection,
                         wordTypes, plugins);
 
@@ -142,10 +139,6 @@
         return new HotSpotRegisters(SPARC.g2, SPARC.g6, SPARC.sp);
     }
 
-    protected HotSpotNodeCostProvider createNodeCostProvider() {
-        return new SPARCHotSpotNodeCostProvider();
-    }
-
     @SuppressWarnings("unused")
     private static Value[] createNativeABICallerSaveRegisters(GraalHotSpotVMConfig config, RegisterConfig regConfig) {
         Set<Register> callerSavedRegisters = new HashSet<>();
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotNodeCostProvider.java	Tue Apr 18 20:10:55 2017 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-/*
- * Copyright (c) 2016, 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 org.graalvm.compiler.hotspot.sparc;
-
-import org.graalvm.compiler.graph.Node;
-import org.graalvm.compiler.hotspot.nodes.HotSpotNodeCostProvider;
-import org.graalvm.compiler.hotspot.nodes.JumpToExceptionHandlerNode;
-import org.graalvm.compiler.nodeinfo.NodeCycles;
-import org.graalvm.compiler.nodeinfo.NodeSize;
-import org.graalvm.compiler.nodes.ReturnNode;
-
-public class SPARCHotSpotNodeCostProvider extends HotSpotNodeCostProvider {
-
-    @Override
-    public NodeCycles cycles(Node n) {
-        if (n instanceof ReturnNode) {
-            return NodeCycles.CYCLES_6;
-        } else if (n instanceof JumpToExceptionHandlerNode) {
-            // restore caller window
-            return NodeCycles.CYCLES_3;
-        }
-        return super.cycles(n);
-    }
-
-    @Override
-    public NodeSize size(Node n) {
-        if (n instanceof ReturnNode) {
-            return NodeSize.SIZE_4;
-        } else if (n instanceof JumpToExceptionHandlerNode) {
-            // restore caller window
-            return NodeSize.SIZE_3;
-        }
-        return super.size(n);
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorld.java	Wed Apr 19 04:10:56 2017 +0000
@@ -0,0 +1,829 @@
+/*
+ * Copyright (c) 2013, 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
+ * 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 org.graalvm.compiler.hotspot.test;
+
+import static java.util.Collections.singletonList;
+import static org.graalvm.compiler.core.GraalCompilerOptions.ExitVMOnException;
+import static org.graalvm.compiler.core.GraalCompilerOptions.PrintBailout;
+import static org.graalvm.compiler.core.GraalCompilerOptions.PrintStackTraceOnException;
+import static org.graalvm.compiler.core.common.util.Util.Java8OrEarlier;
+import static org.graalvm.compiler.core.test.ReflectionOptionDescriptors.extractEntries;
+import static org.graalvm.compiler.hotspot.test.CompileTheWorld.Options.DESCRIPTORS;
+
+import java.io.Closeable;
+import java.io.File;
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.List;
+import java.util.ServiceLoader;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.stream.Collectors;
+
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.bytecode.Bytecodes;
+import org.graalvm.compiler.core.CompilerThreadFactory;
+import org.graalvm.compiler.core.CompilerThreadFactory.DebugConfigAccess;
+import org.graalvm.compiler.core.common.util.Util;
+import org.graalvm.compiler.core.test.ReflectionOptionDescriptors;
+import org.graalvm.compiler.debug.DebugEnvironment;
+import org.graalvm.compiler.debug.GraalDebugConfig;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.debug.MethodFilter;
+import org.graalvm.compiler.debug.TTY;
+import org.graalvm.compiler.debug.internal.MemUseTrackerImpl;
+import org.graalvm.compiler.hotspot.CompilationTask;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.HotSpotGraalCompiler;
+import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
+import org.graalvm.compiler.options.OptionDescriptors;
+import org.graalvm.compiler.options.OptionKey;
+import org.graalvm.compiler.options.OptionValues;
+import org.graalvm.compiler.options.OptionsParser;
+import org.graalvm.util.EconomicMap;
+
+import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider;
+import jdk.vm.ci.hotspot.HotSpotCompilationRequest;
+import jdk.vm.ci.hotspot.HotSpotInstalledCode;
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider;
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
+import jdk.vm.ci.meta.ConstantPool;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.runtime.JVMCI;
+import jdk.vm.ci.runtime.JVMCICompiler;
+import jdk.vm.ci.services.Services;
+
+/**
+ * This class implements compile-the-world functionality with JVMCI.
+ */
+public final class CompileTheWorld {
+
+    /**
+     * Magic token to denote that JDK classes are to be compiled. If {@link Util#Java8OrEarlier},
+     * then the classes in {@code rt.jar} are compiled. Otherwise the classes in the Java runtime
+     * image are compiled.
+     */
+    public static final String SUN_BOOT_CLASS_PATH = "sun.boot.class.path";
+
+    /**
+     * Magic token to denote the classes in the Java runtime image (i.e. in the {@code jrt:/} file
+     * system).
+     */
+    public static final String JRT_CLASS_PATH_ENTRY = "<jrt>";
+
+    /**
+     * @param options a space separated set of option value settings with each option setting in a
+     *            {@code -Dgraal.<name>=<value>} format but without the leading {@code -Dgraal.}.
+     *            Ignored if null.
+     */
+    public static EconomicMap<OptionKey<?>, Object> parseOptions(String options) {
+        if (options != null) {
+            EconomicMap<String, String> optionSettings = EconomicMap.create();
+            for (String optionSetting : options.split("\\s+|#")) {
+                OptionsParser.parseOptionSettingTo(optionSetting, optionSettings);
+            }
+            EconomicMap<OptionKey<?>, Object> values = OptionValues.newOptionMap();
+            ServiceLoader<OptionDescriptors> loader = ServiceLoader.load(OptionDescriptors.class, OptionDescriptors.class.getClassLoader());
+            OptionsParser.parseOptions(optionSettings, values, loader);
+            return values;
+        }
+        return EconomicMap.create();
+    }
+
+    private final HotSpotJVMCIRuntimeProvider jvmciRuntime;
+
+    private final HotSpotGraalCompiler compiler;
+
+    /**
+     * Class path denoting classes to compile.
+     *
+     * @see Options#Classpath
+     */
+    private final String inputClassPath;
+
+    /**
+     * Class index to start compilation at.
+     *
+     * @see Options#StartAt
+     */
+    private final int startAt;
+
+    /**
+     * Class index to stop compilation at.
+     *
+     * @see Options#StopAt
+     */
+    private final int stopAt;
+
+    /** Only compile methods matching one of the filters in this array if the array is non-null. */
+    private final MethodFilter[] methodFilters;
+
+    /** Exclude methods matching one of the filters in this array if the array is non-null. */
+    private final MethodFilter[] excludeMethodFilters;
+
+    // Counters
+    private int classFileCounter = 0;
+    private AtomicLong compiledMethodsCounter = new AtomicLong();
+    private AtomicLong compileTime = new AtomicLong();
+    private AtomicLong memoryUsed = new AtomicLong();
+
+    private boolean verbose;
+
+    /**
+     * Signal that the threads should start compiling in multithreaded mode.
+     */
+    private boolean running;
+
+    private ThreadPoolExecutor threadPool;
+
+    private OptionValues currentOptions;
+    private final EconomicMap<OptionKey<?>, Object> compilationOptions;
+
+    /**
+     * Creates a compile-the-world instance.
+     *
+     * @param files {@link File#pathSeparator} separated list of Zip/Jar files to compile
+     * @param startAt index of the class file to start compilation at
+     * @param stopAt index of the class file to stop compilation at
+     * @param methodFilters
+     * @param excludeMethodFilters
+     */
+    public CompileTheWorld(HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotGraalCompiler compiler, String files, int startAt, int stopAt, String methodFilters, String excludeMethodFilters,
+                    boolean verbose, OptionValues initialOptions, EconomicMap<OptionKey<?>, Object> compilationOptions) {
+        this.jvmciRuntime = jvmciRuntime;
+        this.compiler = compiler;
+        this.inputClassPath = files;
+        this.startAt = startAt;
+        this.stopAt = stopAt;
+        this.methodFilters = methodFilters == null || methodFilters.isEmpty() ? null : MethodFilter.parse(methodFilters);
+        this.excludeMethodFilters = excludeMethodFilters == null || excludeMethodFilters.isEmpty() ? null : MethodFilter.parse(excludeMethodFilters);
+        this.verbose = verbose;
+        EconomicMap<OptionKey<?>, Object> compilationOptionsCopy = EconomicMap.create(compilationOptions);
+        this.currentOptions = initialOptions;
+
+        // We don't want the VM to exit when a method fails to compile...
+        ExitVMOnException.update(compilationOptionsCopy, false);
+
+        // ...but we want to see exceptions.
+        PrintBailout.update(compilationOptionsCopy, true);
+        PrintStackTraceOnException.update(compilationOptionsCopy, true);
+
+        // By default only report statistics for the CTW threads themselves
+        if (!GraalDebugConfig.Options.DebugValueThreadFilter.hasBeenSet(initialOptions)) {
+            GraalDebugConfig.Options.DebugValueThreadFilter.update(compilationOptionsCopy, "^CompileTheWorld");
+        }
+        this.compilationOptions = EconomicMap.create(compilationOptionsCopy);
+    }
+
+    public CompileTheWorld(HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotGraalCompiler compiler, OptionValues options) {
+        this(jvmciRuntime, compiler, Options.Classpath.getValue(options),
+                        Options.StartAt.getValue(options),
+                        Options.StopAt.getValue(options),
+                        Options.MethodFilter.getValue(options),
+                        Options.ExcludeMethodFilter.getValue(options),
+                        Options.Verbose.getValue(options),
+                        options,
+                        parseOptions(Options.Config.getValue(options)));
+    }
+
+    /**
+     * Compiles all methods in all classes in {@link #inputClassPath}. If {@link #inputClassPath}
+     * equals {@link #SUN_BOOT_CLASS_PATH} the boot classes are used.
+     */
+    public void compile() throws Throwable {
+        if (SUN_BOOT_CLASS_PATH.equals(inputClassPath)) {
+            String bcpEntry = null;
+            if (Java8OrEarlier) {
+                final String[] entries = System.getProperty(SUN_BOOT_CLASS_PATH).split(File.pathSeparator);
+                for (int i = 0; i < entries.length && bcpEntry == null; i++) {
+                    String entry = entries[i];
+                    File entryFile = new File(entry);
+                    if (entryFile.getName().endsWith("rt.jar") && entryFile.isFile()) {
+                        bcpEntry = entry;
+                    }
+                }
+                if (bcpEntry == null) {
+                    throw new GraalError("Could not find rt.jar on boot class path %s", System.getProperty(SUN_BOOT_CLASS_PATH));
+                }
+            } else {
+                bcpEntry = JRT_CLASS_PATH_ENTRY;
+            }
+            compile(bcpEntry);
+        } else {
+            compile(inputClassPath);
+        }
+    }
+
+    public void println() {
+        println("");
+    }
+
+    public void println(String format, Object... args) {
+        println(String.format(format, args));
+    }
+
+    public void println(String s) {
+        println(verbose, s);
+    }
+
+    public static void println(boolean cond, String s) {
+        if (cond) {
+            TTY.println(s);
+        }
+    }
+
+    public void printStackTrace(Throwable t) {
+        if (verbose) {
+            t.printStackTrace(TTY.out);
+        }
+    }
+
+    @SuppressWarnings("unused")
+    private static void dummy() {
+    }
+
+    /**
+     * Abstraction over different types of class path entries.
+     */
+    abstract static class ClassPathEntry implements Closeable {
+        final String name;
+
+        ClassPathEntry(String name) {
+            this.name = name;
+        }
+
+        /**
+         * Creates a {@link ClassLoader} for loading classes from this entry.
+         */
+        public abstract ClassLoader createClassLoader() throws IOException;
+
+        /**
+         * Gets the list of classes available under this entry.
+         */
+        public abstract List<String> getClassNames() throws IOException;
+
+        @Override
+        public String toString() {
+            return name;
+        }
+
+        @Override
+        public void close() throws IOException {
+        }
+    }
+
+    /**
+     * A class path entry that is a normal file system directory.
+     */
+    static class DirClassPathEntry extends ClassPathEntry {
+
+        private final File dir;
+
+        DirClassPathEntry(String name) {
+            super(name);
+            dir = new File(name);
+            assert dir.isDirectory();
+        }
+
+        @Override
+        public ClassLoader createClassLoader() throws IOException {
+            URL url = dir.toURI().toURL();
+            return new URLClassLoader(new URL[]{url});
+        }
+
+        @Override
+        public List<String> getClassNames() throws IOException {
+            List<String> classNames = new ArrayList<>();
+            String root = dir.getPath();
+            SimpleFileVisitor<Path> visitor = new SimpleFileVisitor<Path>() {
+                @Override
+                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+                    if (attrs.isRegularFile()) {
+                        File path = file.toFile();
+                        if (path.getName().endsWith(".class")) {
+                            String pathString = path.getPath();
+                            assert pathString.startsWith(root);
+                            String classFile = pathString.substring(root.length() + 1);
+                            String className = classFile.replace(File.separatorChar, '.');
+                            classNames.add(className.replace('/', '.').substring(0, className.length() - ".class".length()));
+                        }
+                    }
+                    return super.visitFile(file, attrs);
+                }
+            };
+            Files.walkFileTree(dir.toPath(), visitor);
+            return classNames;
+        }
+    }
+
+    /**
+     * A class path entry that is a jar or zip file.
+     */
+    static class JarClassPathEntry extends ClassPathEntry {
+
+        private final JarFile jarFile;
+
+        JarClassPathEntry(String name) throws IOException {
+            super(name);
+            jarFile = new JarFile(name);
+        }
+
+        @Override
+        public ClassLoader createClassLoader() throws IOException {
+            URL url = new URL("jar", "", "file:" + name + "!/");
+            return new URLClassLoader(new URL[]{url});
+        }
+
+        @Override
+        public List<String> getClassNames() throws IOException {
+            Enumeration<JarEntry> e = jarFile.entries();
+            List<String> classNames = new ArrayList<>(jarFile.size());
+            while (e.hasMoreElements()) {
+                JarEntry je = e.nextElement();
+                if (je.isDirectory() || !je.getName().endsWith(".class")) {
+                    continue;
+                }
+                String className = je.getName().substring(0, je.getName().length() - ".class".length());
+                classNames.add(className.replace('/', '.'));
+            }
+            return classNames;
+        }
+
+        @Override
+        public void close() throws IOException {
+            jarFile.close();
+        }
+    }
+
+    /**
+     * A class path entry representing the {@code jrt:/} file system.
+     */
+    static class JRTClassPathEntry extends ClassPathEntry {
+
+        private final String limitModules;
+
+        JRTClassPathEntry(String name, String limitModules) {
+            super(name);
+            this.limitModules = limitModules;
+        }
+
+        @Override
+        public ClassLoader createClassLoader() throws IOException {
+            URL url = URI.create("jrt:/").toURL();
+            return new URLClassLoader(new URL[]{url});
+        }
+
+        @Override
+        public List<String> getClassNames() throws IOException {
+            Set<String> negative = new HashSet<>();
+            Set<String> positive = new HashSet<>();
+            if (limitModules != null && !limitModules.isEmpty()) {
+                for (String s : limitModules.split(",")) {
+                    if (s.startsWith("~")) {
+                        negative.add(s.substring(1));
+                    } else {
+                        positive.add(s);
+                    }
+                }
+            }
+            List<String> classNames = new ArrayList<>();
+            FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"), Collections.emptyMap());
+            Path top = fs.getPath("/modules/");
+            Files.find(top, Integer.MAX_VALUE,
+                            (path, attrs) -> attrs.isRegularFile()).forEach(p -> {
+                                int nameCount = p.getNameCount();
+                                if (nameCount > 2) {
+                                    String base = p.getName(nameCount - 1).toString();
+                                    if (base.endsWith(".class") && !base.equals("module-info.class")) {
+                                        String module = p.getName(1).toString();
+                                        if (positive.isEmpty() || positive.contains(module)) {
+                                            if (negative.isEmpty() || !negative.contains(module)) {
+                                                // Strip module prefix and convert to dotted form
+                                                String className = p.subpath(2, nameCount).toString().replace('/', '.');
+                                                // Strip ".class" suffix
+                                                className = className.replace('/', '.').substring(0, className.length() - ".class".length());
+                                                classNames.add(className);
+                                            }
+                                        }
+                                    }
+                                }
+                            });
+            return classNames;
+        }
+    }
+
+    private boolean isClassIncluded(String className) {
+        if (methodFilters != null && !MethodFilter.matchesClassName(methodFilters, className)) {
+            return false;
+        }
+        if (excludeMethodFilters != null && MethodFilter.matchesClassName(excludeMethodFilters, className)) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Compiles all methods in all classes in a given class path.
+     *
+     * @param classPath class path denoting classes to compile
+     * @throws IOException
+     */
+    @SuppressWarnings("try")
+    private void compile(String classPath) throws IOException {
+        final String[] entries = classPath.split(File.pathSeparator);
+        long start = System.currentTimeMillis();
+
+        try {
+            // compile dummy method to get compiler initialized outside of the
+            // config debug override.
+            HotSpotResolvedJavaMethod dummyMethod = (HotSpotResolvedJavaMethod) JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess().lookupJavaMethod(
+                            CompileTheWorld.class.getDeclaredMethod("dummy"));
+            int entryBCI = JVMCICompiler.INVOCATION_ENTRY_BCI;
+            boolean useProfilingInfo = false;
+            boolean installAsDefault = false;
+            CompilationTask task = new CompilationTask(jvmciRuntime, compiler, new HotSpotCompilationRequest(dummyMethod, entryBCI, 0L), useProfilingInfo, installAsDefault, currentOptions);
+            task.runCompilation();
+        } catch (NoSuchMethodException | SecurityException e1) {
+            printStackTrace(e1);
+        }
+
+        /*
+         * Always use a thread pool, even for single threaded mode since it simplifies the use of
+         * DebugValueThreadFilter to filter on the thread names.
+         */
+        int threadCount = 1;
+        if (Options.MultiThreaded.getValue(currentOptions)) {
+            threadCount = Options.Threads.getValue(currentOptions);
+            if (threadCount == 0) {
+                threadCount = Runtime.getRuntime().availableProcessors();
+            }
+        } else {
+            running = true;
+        }
+
+        OptionValues savedOptions = currentOptions;
+        currentOptions = new OptionValues(savedOptions, compilationOptions);
+        threadPool = new ThreadPoolExecutor(threadCount, threadCount, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(),
+                        new CompilerThreadFactory("CompileTheWorld", new DebugConfigAccess() {
+                            @Override
+                            public GraalDebugConfig getDebugConfig() {
+                                return DebugEnvironment.ensureInitialized(currentOptions, compiler.getGraalRuntime().getHostProviders().getSnippetReflection());
+                            }
+                        }));
+
+        try {
+            for (int i = 0; i < entries.length; i++) {
+                final String entry = entries[i];
+
+                ClassPathEntry cpe;
+                if (entry.endsWith(".zip") || entry.endsWith(".jar")) {
+                    cpe = new JarClassPathEntry(entry);
+                } else if (entry.equals(JRT_CLASS_PATH_ENTRY)) {
+                    cpe = new JRTClassPathEntry(entry, Options.LimitModules.getValue(currentOptions));
+                } else {
+                    if (!new File(entry).isDirectory()) {
+                        println("CompileTheWorld : Skipped classes in " + entry);
+                        println();
+                        continue;
+                    }
+                    cpe = new DirClassPathEntry(entry);
+                }
+
+                if (methodFilters == null || methodFilters.length == 0) {
+                    println("CompileTheWorld : Compiling all classes in " + entry);
+                } else {
+                    String include = Arrays.asList(methodFilters).stream().map(MethodFilter::toString).collect(Collectors.joining(", "));
+                    println("CompileTheWorld : Compiling all methods in " + entry + " matching one of the following filters: " + include);
+                }
+                if (excludeMethodFilters != null && excludeMethodFilters.length > 0) {
+                    String exclude = Arrays.asList(excludeMethodFilters).stream().map(MethodFilter::toString).collect(Collectors.joining(", "));
+                    println("CompileTheWorld : Excluding all methods matching one of the following filters: " + exclude);
+                }
+                println();
+
+                ClassLoader loader = cpe.createClassLoader();
+
+                for (String className : cpe.getClassNames()) {
+
+                    // Are we done?
+                    if (classFileCounter >= stopAt) {
+                        break;
+                    }
+
+                    classFileCounter++;
+
+                    if (className.startsWith("jdk.management.") || className.startsWith("jdk.internal.cmm.*")) {
+                        continue;
+                    }
+
+                    try {
+                        // Load and initialize class
+                        Class<?> javaClass = Class.forName(className, true, loader);
+
+                        // Pre-load all classes in the constant pool.
+                        try {
+                            HotSpotResolvedObjectType objectType = HotSpotResolvedObjectType.fromObjectClass(javaClass);
+                            ConstantPool constantPool = objectType.getConstantPool();
+                            for (int cpi = 1; cpi < constantPool.length(); cpi++) {
+                                constantPool.loadReferencedType(cpi, Bytecodes.LDC);
+                            }
+                        } catch (Throwable t) {
+                            // If something went wrong during pre-loading we just ignore it.
+                            if (isClassIncluded(className)) {
+                                println("Preloading failed for (%d) %s: %s", classFileCounter, className, t);
+                            }
+                            continue;
+                        }
+
+                        /*
+                         * Only check filters after class loading and resolution to mitigate impact
+                         * on reproducibility.
+                         */
+                        if (!isClassIncluded(className)) {
+                            continue;
+                        }
+
+                        // Are we compiling this class?
+                        MetaAccessProvider metaAccess = JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess();
+                        if (classFileCounter >= startAt) {
+                            println("CompileTheWorld (%d) : %s", classFileCounter, className);
+
+                            // Compile each constructor/method in the class.
+                            for (Constructor<?> constructor : javaClass.getDeclaredConstructors()) {
+                                HotSpotResolvedJavaMethod javaMethod = (HotSpotResolvedJavaMethod) metaAccess.lookupJavaMethod(constructor);
+                                if (canBeCompiled(javaMethod, constructor.getModifiers())) {
+                                    compileMethod(javaMethod);
+                                }
+                            }
+                            for (Method method : javaClass.getDeclaredMethods()) {
+                                HotSpotResolvedJavaMethod javaMethod = (HotSpotResolvedJavaMethod) metaAccess.lookupJavaMethod(method);
+                                if (canBeCompiled(javaMethod, method.getModifiers())) {
+                                    compileMethod(javaMethod);
+                                }
+                            }
+
+                            // Also compile the class initializer if it exists
+                            HotSpotResolvedJavaMethod clinit = (HotSpotResolvedJavaMethod) metaAccess.lookupJavaType(javaClass).getClassInitializer();
+                            if (clinit != null && canBeCompiled(clinit, clinit.getModifiers())) {
+                                compileMethod(clinit);
+                            }
+                        }
+                    } catch (Throwable t) {
+                        if (isClassIncluded(className)) {
+                            println("CompileTheWorld (%d) : Skipping %s %s", classFileCounter, className, t.toString());
+                            printStackTrace(t);
+                        }
+                    }
+                }
+                cpe.close();
+            }
+        } finally {
+            currentOptions = savedOptions;
+        }
+
+        if (!running) {
+            startThreads();
+        }
+        int wakeups = 0;
+        while (threadPool.getCompletedTaskCount() != threadPool.getTaskCount()) {
+            if (wakeups % 15 == 0) {
+                TTY.println("CompileTheWorld : Waiting for " + (threadPool.getTaskCount() - threadPool.getCompletedTaskCount()) + " compiles");
+            }
+            try {
+                threadPool.awaitTermination(1, TimeUnit.SECONDS);
+                wakeups++;
+            } catch (InterruptedException e) {
+            }
+        }
+        threadPool = null;
+
+        long elapsedTime = System.currentTimeMillis() - start;
+
+        println();
+        if (Options.MultiThreaded.getValue(currentOptions)) {
+            TTY.println("CompileTheWorld : Done (%d classes, %d methods, %d ms elapsed, %d ms compile time, %d bytes of memory used)", classFileCounter, compiledMethodsCounter.get(), elapsedTime,
+                            compileTime.get(), memoryUsed.get());
+        } else {
+            TTY.println("CompileTheWorld : Done (%d classes, %d methods, %d ms, %d bytes of memory used)", classFileCounter, compiledMethodsCounter.get(), compileTime.get(), memoryUsed.get());
+        }
+    }
+
+    private synchronized void startThreads() {
+        running = true;
+        // Wake up any waiting threads
+        notifyAll();
+    }
+
+    private synchronized void waitToRun() {
+        while (!running) {
+            try {
+                wait();
+            } catch (InterruptedException e) {
+            }
+        }
+    }
+
+    @SuppressWarnings("try")
+    private void compileMethod(HotSpotResolvedJavaMethod method) throws InterruptedException, ExecutionException {
+        if (methodFilters != null && !MethodFilter.matches(methodFilters, method)) {
+            return;
+        }
+        if (excludeMethodFilters != null && MethodFilter.matches(excludeMethodFilters, method)) {
+            return;
+        }
+        Future<?> task = threadPool.submit(new Runnable() {
+            @Override
+            public void run() {
+                waitToRun();
+                OptionValues savedOptions = currentOptions;
+                currentOptions = new OptionValues(savedOptions, compilationOptions);
+                try {
+                    compileMethod(method, classFileCounter);
+                } finally {
+                    currentOptions = savedOptions;
+                }
+            }
+        });
+        if (threadPool.getCorePoolSize() == 1) {
+            task.get();
+        }
+    }
+
+    /**
+     * Compiles a method and gathers some statistics.
+     */
+    private void compileMethod(HotSpotResolvedJavaMethod method, int counter) {
+        try {
+            long start = System.currentTimeMillis();
+            long allocatedAtStart = MemUseTrackerImpl.getCurrentThreadAllocatedBytes();
+            int entryBCI = JVMCICompiler.INVOCATION_ENTRY_BCI;
+            HotSpotCompilationRequest request = new HotSpotCompilationRequest(method, entryBCI, 0L);
+            // For more stable CTW execution, disable use of profiling information
+            boolean useProfilingInfo = false;
+            boolean installAsDefault = false;
+            CompilationTask task = new CompilationTask(jvmciRuntime, compiler, request, useProfilingInfo, installAsDefault, currentOptions);
+            task.runCompilation();
+
+            // Invalidate the generated code so the code cache doesn't fill up
+            HotSpotInstalledCode installedCode = task.getInstalledCode();
+            if (installedCode != null) {
+                installedCode.invalidate();
+            }
+
+            memoryUsed.getAndAdd(MemUseTrackerImpl.getCurrentThreadAllocatedBytes() - allocatedAtStart);
+            compileTime.getAndAdd(System.currentTimeMillis() - start);
+            compiledMethodsCounter.incrementAndGet();
+        } catch (Throwable t) {
+            // Catch everything and print a message
+            println("CompileTheWorld (%d) : Error compiling method: %s", counter, method.format("%H.%n(%p):%r"));
+            printStackTrace(t);
+        }
+    }
+
+    /**
+     * Determines if a method should be compiled (Cf. CompilationPolicy::can_be_compiled).
+     *
+     * @return true if it can be compiled, false otherwise
+     */
+    private boolean canBeCompiled(HotSpotResolvedJavaMethod javaMethod, int modifiers) {
+        if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) {
+            return false;
+        }
+        GraalHotSpotVMConfig c = compiler.getGraalRuntime().getVMConfig();
+        if (c.dontCompileHugeMethods && javaMethod.getCodeSize() > c.hugeMethodLimit) {
+            println(verbose || methodFilters != null,
+                            String.format("CompileTheWorld (%d) : Skipping huge method %s (use -XX:-DontCompileHugeMethods or -XX:HugeMethodLimit=%d to include it)", classFileCounter,
+                                            javaMethod.format("%H.%n(%p):%r"),
+                                            javaMethod.getCodeSize()));
+            return false;
+        }
+        // Allow use of -XX:CompileCommand=dontinline to exclude problematic methods
+        if (!javaMethod.canBeInlined()) {
+            return false;
+        }
+        // Skip @Snippets for now
+        for (Annotation annotation : javaMethod.getAnnotations()) {
+            if (annotation.annotationType().equals(Snippet.class)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    static class Options {
+        // @formatter:off
+        public static final OptionKey<Boolean> Help = new OptionKey<>(false);
+        public static final OptionKey<String> Classpath = new OptionKey<>(CompileTheWorld.SUN_BOOT_CLASS_PATH);
+        public static final OptionKey<Boolean> Verbose = new OptionKey<>(true);
+        /**
+         * Ignore Graal classes by default to avoid problems associated with compiling
+         * snippets and method substitutions.
+         */
+        public static final OptionKey<String> LimitModules = new OptionKey<>("~jdk.internal.vm.compiler");
+        public static final OptionKey<Integer> Iterations = new OptionKey<>(1);
+        public static final OptionKey<String> MethodFilter = new OptionKey<>(null);
+        public static final OptionKey<String> ExcludeMethodFilter = new OptionKey<>(null);
+        public static final OptionKey<Integer> StartAt = new OptionKey<>(1);
+        public static final OptionKey<Integer> StopAt = new OptionKey<>(Integer.MAX_VALUE);
+        public static final OptionKey<String> Config = new OptionKey<>(null);
+        public static final OptionKey<Boolean> MultiThreaded = new OptionKey<>(false);
+        public static final OptionKey<Integer> Threads = new OptionKey<>(0);
+
+        static final ReflectionOptionDescriptors DESCRIPTORS = new ReflectionOptionDescriptors(Options.class,
+                           "Help", "List options and their help messages and then exit.",
+                      "Classpath", "Class path denoting methods to compile. Default is to compile boot classes.",
+                        "Verbose", "Verbose operation.",
+                   "LimitModules", "Comma separated list of module names to which compilation should be limited. " +
+                                   "Module names can be prefixed with \"~\" to exclude the named module.",
+                     "Iterations", "The number of iterations to perform.",
+                   "MethodFilter", "Only compile methods matching this filter.",
+            "ExcludeMethodFilter", "Exclude methods matching this filter from compilation.",
+                        "StartAt", "First class to consider for compilation.",
+                         "StopAt", "Last class to consider for compilation.",
+                         "Config", "Option value overrides to use during compile the world. For example, " +
+                                   "to disable inlining and partial escape analysis specify 'PartialEscapeAnalysis=false Inline=false'. " +
+                                   "The format for each option is the same as on the command line just without the '-Dgraal.' prefix.",
+                  "MultiThreaded", "Run using multiple threads for compilation.",
+                        "Threads", "Number of threads to use for multithreaded execution. Defaults to Runtime.getRuntime().availableProcessors().");
+        // @formatter:on
+    }
+
+    public static OptionValues loadOptions(OptionValues initialValues) {
+        EconomicMap<OptionKey<?>, Object> values = OptionValues.newOptionMap();
+        List<OptionDescriptors> loader = singletonList(DESCRIPTORS);
+        OptionsParser.parseOptions(extractEntries(System.getProperties(), "CompileTheWorld.", true), values, loader);
+        OptionValues options = new OptionValues(initialValues, values);
+        if (Options.Help.getValue(options)) {
+            options.printHelp(loader, System.out, "CompileTheWorld.");
+            System.exit(0);
+        }
+        return options;
+    }
+
+    public static void main(String[] args) throws Throwable {
+        Services.exportJVMCITo(CompileTheWorld.class);
+        HotSpotJVMCIRuntime jvmciRuntime = HotSpotJVMCIRuntime.runtime();
+        HotSpotGraalCompiler compiler = (HotSpotGraalCompiler) jvmciRuntime.getCompiler();
+        HotSpotGraalRuntimeProvider graalRuntime = compiler.getGraalRuntime();
+        HotSpotCodeCacheProvider codeCache = graalRuntime.getHostProviders().getCodeCache();
+        OptionValues options = loadOptions(graalRuntime.getOptions());
+
+        int iterations = Options.Iterations.getValue(options);
+        for (int i = 0; i < iterations; i++) {
+            codeCache.resetCompilationStatistics();
+            TTY.println("CompileTheWorld : iteration " + i);
+
+            CompileTheWorld ctw = new CompileTheWorld(jvmciRuntime, compiler, options);
+            ctw.compile();
+        }
+        // This is required as non-daemon threads can be started by class initializers
+        System.exit(0);
+    }
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorldTest.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorldTest.java	Wed Apr 19 04:10:56 2017 +0000
@@ -24,7 +24,6 @@
 
 import static org.graalvm.compiler.core.GraalCompilerOptions.ExitVMOnException;
 import org.graalvm.compiler.core.test.GraalCompilerTest;
-import org.graalvm.compiler.hotspot.CompileTheWorld;
 import org.graalvm.compiler.hotspot.HotSpotGraalCompiler;
 import org.graalvm.compiler.options.OptionKey;
 import org.graalvm.compiler.options.OptionValues;
@@ -44,7 +43,7 @@
         boolean originalSetting = ExitVMOnException.getValue(getInitialOptions());
         // Compile a couple classes in rt.jar
         HotSpotJVMCIRuntimeProvider runtime = HotSpotJVMCIRuntime.runtime();
-        System.setProperty(CompileTheWorld.LIMITMODS_PROPERTY_NAME, "java.base");
+        System.setProperty("CompileTheWorld.LimitModules", "java.base");
         OptionValues initialOptions = getInitialOptions();
         EconomicMap<OptionKey<?>, Object> compilationOptions = CompileTheWorld.parseOptions("Inline=false");
         new CompileTheWorld(runtime, (HotSpotGraalCompiler) runtime.getCompiler(), CompileTheWorld.SUN_BOOT_CLASS_PATH, 1, 5, null, null, false, initialOptions, compilationOptions).compile();
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/MemoryUsageBenchmark.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/MemoryUsageBenchmark.java	Wed Apr 19 04:10:56 2017 +0000
@@ -28,10 +28,9 @@
 import org.graalvm.compiler.core.test.AllocSpy;
 import org.graalvm.compiler.debug.DebugEnvironment;
 import org.graalvm.compiler.hotspot.CompilationTask;
-import org.graalvm.compiler.hotspot.CompileTheWorld;
-import org.graalvm.compiler.hotspot.CompileTheWorldOptions;
 import org.graalvm.compiler.hotspot.HotSpotGraalCompiler;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.options.OptionValues;
 
 import jdk.vm.ci.hotspot.HotSpotCompilationRequest;
 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
@@ -51,7 +50,7 @@
  * Memory analysis for a {@link CompileTheWorld} execution can also be performed. For example:
  *
  * <pre>
- *     mx --vm server vm -XX:-UseJVMCIClassLoader -Dgraal.CompileTheWorldClasspath=$HOME/SPECjvm2008/SPECjvm2008.jar -cp @org.graalvm.compiler.hotspot.test org.graalvm.compiler.hotspot.test.MemoryUsageBenchmark
+ *     mx vm -XX:-UseJVMCIClassLoader -DCompileTheWorld.Classpath=$HOME/SPECjvm2008/SPECjvm2008.jar -cp @org.graalvm.compiler.hotspot.test org.graalvm.compiler.hotspot.test.MemoryUsageBenchmark
  * </pre>
  */
 public class MemoryUsageBenchmark extends HotSpotGraalCompilerTest {
@@ -181,9 +180,10 @@
     public void run() {
         compileAndTime("simple");
         compileAndTime("complex");
-        if (CompileTheWorldOptions.CompileTheWorldClasspath.getValue(getInitialOptions()) != CompileTheWorld.SUN_BOOT_CLASS_PATH) {
+        OptionValues options = CompileTheWorld.loadOptions(getInitialOptions());
+        if (CompileTheWorld.Options.Classpath.getValue(options) != CompileTheWorld.SUN_BOOT_CLASS_PATH) {
             HotSpotJVMCIRuntimeProvider runtime = HotSpotJVMCIRuntime.runtime();
-            CompileTheWorld ctw = new CompileTheWorld(runtime, (HotSpotGraalCompiler) runtime.getCompiler(), getInitialOptions());
+            CompileTheWorld ctw = new CompileTheWorld(runtime, (HotSpotGraalCompiler) runtime.getCompiler(), options);
             try {
                 ctw.compile();
             } catch (Throwable e) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/OptionsInFileTest.java	Wed Apr 19 04:10:56 2017 +0000
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2013, 2016, 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 org.graalvm.compiler.hotspot.test;
+
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.Dump;
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.MethodFilter;
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.PrintGraph;
+import static org.graalvm.compiler.test.SubprocessUtil.formatExecutedCommand;
+import static org.graalvm.compiler.test.SubprocessUtil.getVMCommandLine;
+import static org.graalvm.compiler.test.SubprocessUtil.withoutDebuggerArguments;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Tests reading options from a file specified by the {@code graal.options.file}.
+ */
+public class OptionsInFileTest extends GraalCompilerTest {
+    @Test
+    public void test() throws IOException {
+        List<String> args = withoutDebuggerArguments(getVMCommandLine());
+
+        String methodFilterValue = "a very unlikely method name";
+        String debugFilterValue = "a very unlikely debug scope";
+        File optionsFile = File.createTempFile("options", ".properties").getAbsoluteFile();
+        try {
+            Assert.assertFalse(methodFilterValue.equals(MethodFilter.getDefaultValue()));
+            Assert.assertFalse(debugFilterValue.equals(PrintGraph.getDefaultValue()));
+            Assert.assertTrue(PrintGraph.getDefaultValue());
+
+            try (PrintStream out = new PrintStream(new FileOutputStream(optionsFile))) {
+                out.println(MethodFilter.getName() + "=" + methodFilterValue);
+                out.println(Dump.getName() + "=" + debugFilterValue);
+                out.println(PrintGraph.getName() + " = false");
+            }
+
+            args.add("-Dgraal.options.file=" + optionsFile);
+            args.add("-XX:+JVMCIPrintProperties");
+
+            ProcessBuilder processBuilder = new ProcessBuilder(args);
+            processBuilder.redirectErrorStream(true);
+            Process process = processBuilder.start();
+            BufferedReader stdout = new BufferedReader(new InputStreamReader(process.getInputStream()));
+
+            String[] expected = {
+                            "graal.MethodFilter := \"a very unlikely method name\"",
+                            "graal.Dump := \"a very unlikely debug scope\"",
+                            "graal.PrintGraph := false"};
+
+            List<String> outputLines = new ArrayList<>();
+
+            String line;
+            while ((line = stdout.readLine()) != null) {
+                outputLines.add(line);
+                for (int i = 0; i < expected.length; i++) {
+                    if (expected[i] != null && line.contains(expected[i])) {
+                        expected[i] = null;
+                    }
+                }
+            }
+            String dashes = "-------------------------------------------------------";
+            for (int i = 0; i < expected.length; i++) {
+                if (expected[i] != null) {
+                    Assert.fail(String.format("Did not find '%s' in output of command:%n%s", expected[i], formatExecutedCommand(args, outputLines, dashes, dashes)));
+                }
+            }
+        } finally {
+            optionsFile.delete();
+        }
+    }
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompileTheWorld.java	Tue Apr 18 20:10:55 2017 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,777 +0,0 @@
-/*
- * Copyright (c) 2013, 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
- * 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 org.graalvm.compiler.hotspot;
-
-import static org.graalvm.compiler.core.GraalCompilerOptions.ExitVMOnException;
-import static org.graalvm.compiler.core.GraalCompilerOptions.PrintBailout;
-import static org.graalvm.compiler.core.GraalCompilerOptions.PrintStackTraceOnException;
-import static org.graalvm.compiler.core.common.util.Util.Java8OrEarlier;
-import static org.graalvm.compiler.hotspot.CompileTheWorldOptions.CompileTheWorldClasspath;
-import static org.graalvm.compiler.hotspot.CompileTheWorldOptions.CompileTheWorldConfig;
-import static org.graalvm.compiler.hotspot.CompileTheWorldOptions.CompileTheWorldExcludeMethodFilter;
-import static org.graalvm.compiler.hotspot.CompileTheWorldOptions.CompileTheWorldMethodFilter;
-import static org.graalvm.compiler.hotspot.CompileTheWorldOptions.CompileTheWorldStartAt;
-import static org.graalvm.compiler.hotspot.CompileTheWorldOptions.CompileTheWorldStopAt;
-import static org.graalvm.compiler.hotspot.CompileTheWorldOptions.CompileTheWorldVerbose;
-
-import java.io.Closeable;
-import java.io.File;
-import java.io.IOException;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.channels.FileChannel;
-import java.nio.file.FileSystems;
-import java.nio.file.FileVisitResult;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.SimpleFileVisitor;
-import java.nio.file.StandardOpenOption;
-import java.nio.file.attribute.BasicFileAttributes;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Enumeration;
-import java.util.HashSet;
-import java.util.List;
-import java.util.ServiceLoader;
-import java.util.Set;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
-import java.util.stream.Collectors;
-
-import org.graalvm.compiler.api.replacements.Snippet;
-import org.graalvm.compiler.bytecode.Bytecodes;
-import org.graalvm.compiler.core.CompilerThreadFactory;
-import org.graalvm.compiler.core.CompilerThreadFactory.DebugConfigAccess;
-import org.graalvm.compiler.core.common.util.Util;
-import org.graalvm.compiler.debug.DebugEnvironment;
-import org.graalvm.compiler.debug.GraalDebugConfig;
-import org.graalvm.compiler.debug.MethodFilter;
-import org.graalvm.compiler.debug.TTY;
-import org.graalvm.compiler.debug.internal.MemUseTrackerImpl;
-import org.graalvm.compiler.options.OptionDescriptors;
-import org.graalvm.compiler.options.OptionKey;
-import org.graalvm.compiler.options.OptionValues;
-import org.graalvm.compiler.options.OptionsParser;
-import org.graalvm.util.EconomicMap;
-
-import jdk.vm.ci.hotspot.HotSpotCompilationRequest;
-import jdk.vm.ci.hotspot.HotSpotInstalledCode;
-import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
-import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider;
-import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
-import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
-import jdk.vm.ci.meta.ConstantPool;
-import jdk.vm.ci.meta.MetaAccessProvider;
-import jdk.vm.ci.runtime.JVMCI;
-import jdk.vm.ci.runtime.JVMCICompiler;
-import jdk.vm.ci.services.Services;
-
-/**
- * This class implements compile-the-world functionality with JVMCI.
- */
-public final class CompileTheWorld {
-
-    /**
-     * Magic token to denote that JDK classes are to be compiled. If {@link Util#Java8OrEarlier},
-     * then the classes in {@code rt.jar} are compiled. Otherwise the classes in {@code
-     * <java.home>/lib/modules} are compiled.
-     */
-    public static final String SUN_BOOT_CLASS_PATH = "sun.boot.class.path";
-
-    /**
-     * @param options a space separated set of option value settings with each option setting in a
-     *            {@code -Dgraal.<name>=<value>} format but without the leading {@code -Dgraal.}.
-     *            Ignored if null.
-     */
-    public static EconomicMap<OptionKey<?>, Object> parseOptions(String options) {
-        if (options != null) {
-            EconomicMap<String, String> optionSettings = EconomicMap.create();
-            for (String optionSetting : options.split("\\s+|#")) {
-                OptionsParser.parseOptionSettingTo(optionSetting, optionSettings);
-            }
-            EconomicMap<OptionKey<?>, Object> values = OptionValues.newOptionMap();
-            ServiceLoader<OptionDescriptors> loader = ServiceLoader.load(OptionDescriptors.class, OptionDescriptors.class.getClassLoader());
-            OptionsParser.parseOptions(optionSettings, values, loader);
-            return values;
-        }
-        return EconomicMap.create();
-    }
-
-    private final HotSpotJVMCIRuntimeProvider jvmciRuntime;
-
-    private final HotSpotGraalCompiler compiler;
-
-    /**
-     * Class path denoting classes to compile.
-     *
-     * @see CompileTheWorldOptions#CompileTheWorldClasspath
-     */
-    private final String inputClassPath;
-
-    /**
-     * Class index to start compilation at.
-     *
-     * @see CompileTheWorldOptions#CompileTheWorldStartAt
-     */
-    private final int startAt;
-
-    /**
-     * Class index to stop compilation at.
-     *
-     * @see CompileTheWorldOptions#CompileTheWorldStopAt
-     */
-    private final int stopAt;
-
-    /** Only compile methods matching one of the filters in this array if the array is non-null. */
-    private final MethodFilter[] methodFilters;
-
-    /** Exclude methods matching one of the filters in this array if the array is non-null. */
-    private final MethodFilter[] excludeMethodFilters;
-
-    // Counters
-    private int classFileCounter = 0;
-    private AtomicLong compiledMethodsCounter = new AtomicLong();
-    private AtomicLong compileTime = new AtomicLong();
-    private AtomicLong memoryUsed = new AtomicLong();
-
-    private boolean verbose;
-
-    /**
-     * Signal that the threads should start compiling in multithreaded mode.
-     */
-    private boolean running;
-
-    private ThreadPoolExecutor threadPool;
-
-    private OptionValues currentOptions;
-    private final EconomicMap<OptionKey<?>, Object> compilationOptions;
-
-    /**
-     * Creates a compile-the-world instance.
-     *
-     * @param files {@link File#pathSeparator} separated list of Zip/Jar files to compile
-     * @param startAt index of the class file to start compilation at
-     * @param stopAt index of the class file to stop compilation at
-     * @param methodFilters
-     * @param excludeMethodFilters
-     */
-    public CompileTheWorld(HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotGraalCompiler compiler, String files, int startAt, int stopAt, String methodFilters, String excludeMethodFilters,
-                    boolean verbose, OptionValues initialOptions, EconomicMap<OptionKey<?>, Object> compilationOptions) {
-        this.jvmciRuntime = jvmciRuntime;
-        this.compiler = compiler;
-        this.inputClassPath = files;
-        this.startAt = startAt;
-        this.stopAt = stopAt;
-        this.methodFilters = methodFilters == null || methodFilters.isEmpty() ? null : MethodFilter.parse(methodFilters);
-        this.excludeMethodFilters = excludeMethodFilters == null || excludeMethodFilters.isEmpty() ? null : MethodFilter.parse(excludeMethodFilters);
-        this.verbose = verbose;
-        EconomicMap<OptionKey<?>, Object> compilationOptionsCopy = EconomicMap.create(compilationOptions);
-        this.currentOptions = initialOptions;
-
-        // We don't want the VM to exit when a method fails to compile...
-        ExitVMOnException.update(compilationOptionsCopy, false);
-
-        // ...but we want to see exceptions.
-        PrintBailout.update(compilationOptionsCopy, true);
-        PrintStackTraceOnException.update(compilationOptionsCopy, true);
-
-        // By default only report statistics for the CTW threads themselves
-        if (!GraalDebugConfig.Options.DebugValueThreadFilter.hasBeenSet(initialOptions)) {
-            GraalDebugConfig.Options.DebugValueThreadFilter.update(compilationOptionsCopy, "^CompileTheWorld");
-        }
-        this.compilationOptions = EconomicMap.create(compilationOptionsCopy);
-    }
-
-    public CompileTheWorld(HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotGraalCompiler compiler, OptionValues options) {
-        this(jvmciRuntime, compiler, CompileTheWorldClasspath.getValue(options),
-                        CompileTheWorldStartAt.getValue(options),
-                        CompileTheWorldStopAt.getValue(options),
-                        CompileTheWorldMethodFilter.getValue(options),
-                        CompileTheWorldExcludeMethodFilter.getValue(options),
-                        CompileTheWorldVerbose.getValue(options),
-                        options,
-                        parseOptions(CompileTheWorldConfig.getValue(options)));
-    }
-
-    /**
-     * Compiles all methods in all classes in {@link #inputClassPath}. If {@link #inputClassPath}
-     * equals {@link #SUN_BOOT_CLASS_PATH} the boot class path is used.
-     */
-    public void compile() throws Throwable {
-        if (SUN_BOOT_CLASS_PATH.equals(inputClassPath)) {
-            String bcpEntry = null;
-            if (Java8OrEarlier) {
-                final String[] entries = System.getProperty(SUN_BOOT_CLASS_PATH).split(File.pathSeparator);
-                for (int i = 0; i < entries.length && bcpEntry == null; i++) {
-                    String entry = entries[i];
-                    File entryFile = new File(entry);
-                    // We stop at rt.jar, unless it is the first boot class path entry.
-                    if (entryFile.getName().endsWith("rt.jar") && entryFile.isFile()) {
-                        bcpEntry = entry;
-                    }
-                }
-            } else {
-                bcpEntry = System.getProperty("java.home") + "/lib/modules".replace('/', File.separatorChar);
-            }
-            compile(bcpEntry);
-        } else {
-            compile(inputClassPath);
-        }
-    }
-
-    public void println() {
-        println("");
-    }
-
-    public void println(String format, Object... args) {
-        println(String.format(format, args));
-    }
-
-    public void println(String s) {
-        println(verbose, s);
-    }
-
-    public static void println(boolean cond, String s) {
-        if (cond) {
-            TTY.println(s);
-        }
-    }
-
-    public void printStackTrace(Throwable t) {
-        if (verbose) {
-            t.printStackTrace(TTY.out);
-        }
-    }
-
-    @SuppressWarnings("unused")
-    private static void dummy() {
-    }
-
-    /**
-     * Abstraction over different types of class path entries.
-     */
-    abstract static class ClassPathEntry implements Closeable {
-        final String name;
-
-        ClassPathEntry(String name) {
-            this.name = name;
-        }
-
-        /**
-         * Creates a {@link ClassLoader} for loading classes from this entry.
-         */
-        public abstract ClassLoader createClassLoader() throws IOException;
-
-        /**
-         * Gets the list of classes available under this entry.
-         */
-        public abstract List<String> getClassNames() throws IOException;
-
-        @Override
-        public String toString() {
-            return name;
-        }
-
-        @Override
-        public void close() throws IOException {
-        }
-    }
-
-    /**
-     * A class path entry that is a normal file system directory.
-     */
-    static class DirClassPathEntry extends ClassPathEntry {
-
-        private final File dir;
-
-        DirClassPathEntry(String name) {
-            super(name);
-            dir = new File(name);
-            assert dir.isDirectory();
-        }
-
-        @Override
-        public ClassLoader createClassLoader() throws IOException {
-            URL url = dir.toURI().toURL();
-            return new URLClassLoader(new URL[]{url});
-        }
-
-        @Override
-        public List<String> getClassNames() throws IOException {
-            List<String> classNames = new ArrayList<>();
-            String root = dir.getPath();
-            SimpleFileVisitor<Path> visitor = new SimpleFileVisitor<Path>() {
-                @Override
-                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
-                    if (attrs.isRegularFile()) {
-                        File path = file.toFile();
-                        if (path.getName().endsWith(".class")) {
-                            String pathString = path.getPath();
-                            assert pathString.startsWith(root);
-                            String classFile = pathString.substring(root.length() + 1);
-                            String className = classFile.replace(File.separatorChar, '.');
-                            classNames.add(className.replace('/', '.').substring(0, className.length() - ".class".length()));
-                        }
-                    }
-                    return super.visitFile(file, attrs);
-                }
-            };
-            Files.walkFileTree(dir.toPath(), visitor);
-            return classNames;
-        }
-    }
-
-    /**
-     * A class path entry that is a jar or zip file.
-     */
-    static class JarClassPathEntry extends ClassPathEntry {
-
-        private final JarFile jarFile;
-
-        JarClassPathEntry(String name) throws IOException {
-            super(name);
-            jarFile = new JarFile(name);
-        }
-
-        @Override
-        public ClassLoader createClassLoader() throws IOException {
-            URL url = new URL("jar", "", "file:" + name + "!/");
-            return new URLClassLoader(new URL[]{url});
-        }
-
-        @Override
-        public List<String> getClassNames() throws IOException {
-            Enumeration<JarEntry> e = jarFile.entries();
-            List<String> classNames = new ArrayList<>(jarFile.size());
-            while (e.hasMoreElements()) {
-                JarEntry je = e.nextElement();
-                if (je.isDirectory() || !je.getName().endsWith(".class")) {
-                    continue;
-                }
-                String className = je.getName().substring(0, je.getName().length() - ".class".length());
-                classNames.add(className.replace('/', '.'));
-            }
-            return classNames;
-        }
-
-        @Override
-        public void close() throws IOException {
-            jarFile.close();
-        }
-    }
-
-    /**
-     * Name of the property that limits the set of modules processed by CompileTheWorld.
-     */
-    public static final String LIMITMODS_PROPERTY_NAME = "CompileTheWorld.limitmods";
-
-    /**
-     * A class path entry that is a jimage file.
-     */
-    static class ImageClassPathEntry extends ClassPathEntry {
-
-        private final File jimage;
-
-        ImageClassPathEntry(String name) {
-            super(name);
-            jimage = new File(name);
-            assert jimage.isFile();
-        }
-
-        @Override
-        public ClassLoader createClassLoader() throws IOException {
-            URL url = jimage.toURI().toURL();
-            return new URLClassLoader(new URL[]{url});
-        }
-
-        @Override
-        public List<String> getClassNames() throws IOException {
-            String prop = System.getProperty(LIMITMODS_PROPERTY_NAME);
-            Set<String> limitmods = prop == null ? null : new HashSet<>(Arrays.asList(prop.split(",")));
-            List<String> classNames = new ArrayList<>();
-            String[] entries = readJimageEntries();
-            for (String e : entries) {
-                if (e.endsWith(".class") && !e.endsWith("module-info.class")) {
-                    assert e.charAt(0) == '/' : e;
-                    int endModule = e.indexOf('/', 1);
-                    assert endModule != -1 : e;
-                    if (limitmods != null) {
-                        String module = e.substring(1, endModule);
-                        if (!limitmods.contains(module)) {
-                            continue;
-                        }
-                    }
-                    // Strip the module prefix and convert to dotted form
-                    String className = e.substring(endModule + 1).replace('/', '.');
-                    // Strip ".class" suffix
-                    className = className.replace('/', '.').substring(0, className.length() - ".class".length());
-                    classNames.add(className);
-                }
-            }
-            return classNames;
-        }
-
-        private String[] readJimageEntries() {
-            try {
-                // Use reflection so this can be compiled on JDK8
-                Path path = FileSystems.getDefault().getPath(name);
-                Method open = Class.forName("jdk.internal.jimage.BasicImageReader").getDeclaredMethod("open", Path.class);
-                Object reader = open.invoke(null, path);
-                Method getEntryNames = reader.getClass().getDeclaredMethod("getEntryNames");
-                getEntryNames.setAccessible(true);
-                String[] entries = (String[]) getEntryNames.invoke(reader);
-                return entries;
-            } catch (Exception e) {
-                TTY.println("Error reading entries from " + name + ": " + e);
-                return new String[0];
-            }
-        }
-    }
-
-    /**
-     * Determines if a given path denotes a jimage file.
-     *
-     * @param path file path
-     * @return {@code true} if the 4 byte integer (in native endianness) at the start of
-     *         {@code path}'s contents is {@code 0xCAFEDADA}
-     */
-    static boolean isJImage(String path) {
-        try {
-            FileChannel channel = FileChannel.open(Paths.get(path), StandardOpenOption.READ);
-            ByteBuffer map = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());
-            map.order(ByteOrder.nativeOrder()).asIntBuffer().get(0);
-            int magic = map.asIntBuffer().get(0);
-            if (magic == 0xCAFEDADA) {
-                return true;
-            }
-        } catch (IOException e) {
-        }
-        return false;
-    }
-
-    /**
-     * Compiles all methods in all classes in a given class path.
-     *
-     * @param classPath class path denoting classes to compile
-     * @throws IOException
-     */
-    @SuppressWarnings("try")
-    private void compile(String classPath) throws IOException {
-        final String[] entries = classPath.split(File.pathSeparator);
-        long start = System.currentTimeMillis();
-
-        try {
-            // compile dummy method to get compiler initialized outside of the
-            // config debug override.
-            HotSpotResolvedJavaMethod dummyMethod = (HotSpotResolvedJavaMethod) JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess().lookupJavaMethod(
-                            CompileTheWorld.class.getDeclaredMethod("dummy"));
-            int entryBCI = JVMCICompiler.INVOCATION_ENTRY_BCI;
-            boolean useProfilingInfo = false;
-            boolean installAsDefault = false;
-            CompilationTask task = new CompilationTask(jvmciRuntime, compiler, new HotSpotCompilationRequest(dummyMethod, entryBCI, 0L), useProfilingInfo, installAsDefault, currentOptions);
-            task.runCompilation();
-        } catch (NoSuchMethodException | SecurityException e1) {
-            printStackTrace(e1);
-        }
-
-        /*
-         * Always use a thread pool, even for single threaded mode since it simplifies the use of
-         * DebugValueThreadFilter to filter on the thread names.
-         */
-        int threadCount = 1;
-        if (CompileTheWorldOptions.CompileTheWorldMultiThreaded.getValue(currentOptions)) {
-            threadCount = CompileTheWorldOptions.CompileTheWorldThreads.getValue(currentOptions);
-            if (threadCount == 0) {
-                threadCount = Runtime.getRuntime().availableProcessors();
-            }
-        } else {
-            running = true;
-        }
-
-        OptionValues savedOptions = currentOptions;
-        currentOptions = new OptionValues(savedOptions, compilationOptions);
-        threadPool = new ThreadPoolExecutor(threadCount, threadCount, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(),
-                        new CompilerThreadFactory("CompileTheWorld", new DebugConfigAccess() {
-                            @Override
-                            public GraalDebugConfig getDebugConfig() {
-                                return DebugEnvironment.ensureInitialized(currentOptions, compiler.getGraalRuntime().getHostProviders().getSnippetReflection());
-                            }
-                        }));
-
-        try {
-            for (int i = 0; i < entries.length; i++) {
-                final String entry = entries[i];
-
-                ClassPathEntry cpe;
-                if (entry.endsWith(".zip") || entry.endsWith(".jar")) {
-                    cpe = new JarClassPathEntry(entry);
-                } else if (isJImage(entry)) {
-                    assert !Java8OrEarlier;
-                    cpe = new ImageClassPathEntry(entry);
-                } else {
-                    if (!new File(entry).isDirectory()) {
-                        println("CompileTheWorld : Skipped classes in " + entry);
-                        println();
-                        continue;
-                    }
-                    cpe = new DirClassPathEntry(entry);
-                }
-
-                if (methodFilters == null || methodFilters.length == 0) {
-                    println("CompileTheWorld : Compiling all classes in " + entry);
-                } else {
-                    String include = Arrays.asList(methodFilters).stream().map(MethodFilter::toString).collect(Collectors.joining(", "));
-                    println("CompileTheWorld : Compiling all methods in " + entry + " matching one of the following filters: " + include);
-                }
-                if (excludeMethodFilters != null && excludeMethodFilters.length > 0) {
-                    String exclude = Arrays.asList(excludeMethodFilters).stream().map(MethodFilter::toString).collect(Collectors.joining(", "));
-                    println("CompileTheWorld : Excluding all methods matching one of the following filters: " + exclude);
-                }
-                println();
-
-                ClassLoader loader = cpe.createClassLoader();
-
-                for (String className : cpe.getClassNames()) {
-
-                    // Are we done?
-                    if (classFileCounter >= stopAt) {
-                        break;
-                    }
-
-                    classFileCounter++;
-
-                    if (className.startsWith("jdk.management.") || className.startsWith("jdk.internal.cmm.*")) {
-                        continue;
-                    }
-
-                    try {
-                        // Load and initialize class
-                        Class<?> javaClass = Class.forName(className, true, loader);
-
-                        // Pre-load all classes in the constant pool.
-                        try {
-                            HotSpotResolvedObjectType objectType = HotSpotResolvedObjectType.fromObjectClass(javaClass);
-                            ConstantPool constantPool = objectType.getConstantPool();
-                            for (int cpi = 1; cpi < constantPool.length(); cpi++) {
-                                constantPool.loadReferencedType(cpi, Bytecodes.LDC);
-                            }
-                        } catch (Throwable t) {
-                            // If something went wrong during pre-loading we just ignore it.
-                            println("Preloading failed for (%d) %s: %s", classFileCounter, className, t);
-                        }
-
-                        /*
-                         * Only check filters after class loading and resolution to mitigate impact
-                         * on reproducibility.
-                         */
-                        if (methodFilters != null && !MethodFilter.matchesClassName(methodFilters, className)) {
-                            continue;
-                        }
-                        if (excludeMethodFilters != null && MethodFilter.matchesClassName(excludeMethodFilters, className)) {
-                            continue;
-                        }
-
-                        // Are we compiling this class?
-                        MetaAccessProvider metaAccess = JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess();
-                        if (classFileCounter >= startAt) {
-                            println("CompileTheWorld (%d) : %s", classFileCounter, className);
-
-                            // Compile each constructor/method in the class.
-                            for (Constructor<?> constructor : javaClass.getDeclaredConstructors()) {
-                                HotSpotResolvedJavaMethod javaMethod = (HotSpotResolvedJavaMethod) metaAccess.lookupJavaMethod(constructor);
-                                if (canBeCompiled(javaMethod, constructor.getModifiers())) {
-                                    compileMethod(javaMethod);
-                                }
-                            }
-                            for (Method method : javaClass.getDeclaredMethods()) {
-                                HotSpotResolvedJavaMethod javaMethod = (HotSpotResolvedJavaMethod) metaAccess.lookupJavaMethod(method);
-                                if (canBeCompiled(javaMethod, method.getModifiers())) {
-                                    compileMethod(javaMethod);
-                                }
-                            }
-
-                            // Also compile the class initializer if it exists
-                            HotSpotResolvedJavaMethod clinit = (HotSpotResolvedJavaMethod) metaAccess.lookupJavaType(javaClass).getClassInitializer();
-                            if (clinit != null && canBeCompiled(clinit, clinit.getModifiers())) {
-                                compileMethod(clinit);
-                            }
-                        }
-                    } catch (Throwable t) {
-                        println("CompileTheWorld (%d) : Skipping %s %s", classFileCounter, className, t.toString());
-                        printStackTrace(t);
-                    }
-                }
-                cpe.close();
-            }
-        } finally {
-            currentOptions = savedOptions;
-        }
-
-        if (!running) {
-            startThreads();
-        }
-        int wakeups = 0;
-        while (threadPool.getCompletedTaskCount() != threadPool.getTaskCount()) {
-            if (wakeups % 15 == 0) {
-                TTY.println("CompileTheWorld : Waiting for " + (threadPool.getTaskCount() - threadPool.getCompletedTaskCount()) + " compiles");
-            }
-            try {
-                threadPool.awaitTermination(1, TimeUnit.SECONDS);
-                wakeups++;
-            } catch (InterruptedException e) {
-            }
-        }
-        threadPool = null;
-
-        long elapsedTime = System.currentTimeMillis() - start;
-
-        println();
-        if (CompileTheWorldOptions.CompileTheWorldMultiThreaded.getValue(currentOptions)) {
-            TTY.println("CompileTheWorld : Done (%d classes, %d methods, %d ms elapsed, %d ms compile time, %d bytes of memory used)", classFileCounter, compiledMethodsCounter.get(), elapsedTime,
-                            compileTime.get(), memoryUsed.get());
-        } else {
-            TTY.println("CompileTheWorld : Done (%d classes, %d methods, %d ms, %d bytes of memory used)", classFileCounter, compiledMethodsCounter.get(), compileTime.get(), memoryUsed.get());
-        }
-    }
-
-    private synchronized void startThreads() {
-        running = true;
-        // Wake up any waiting threads
-        notifyAll();
-    }
-
-    private synchronized void waitToRun() {
-        while (!running) {
-            try {
-                wait();
-            } catch (InterruptedException e) {
-            }
-        }
-    }
-
-    @SuppressWarnings("try")
-    private void compileMethod(HotSpotResolvedJavaMethod method) throws InterruptedException, ExecutionException {
-        if (methodFilters != null && !MethodFilter.matches(methodFilters, method)) {
-            return;
-        }
-        if (excludeMethodFilters != null && MethodFilter.matches(excludeMethodFilters, method)) {
-            return;
-        }
-        Future<?> task = threadPool.submit(new Runnable() {
-            @Override
-            public void run() {
-                waitToRun();
-                OptionValues savedOptions = currentOptions;
-                currentOptions = new OptionValues(savedOptions, compilationOptions);
-                try {
-                    compileMethod(method, classFileCounter);
-                } finally {
-                    currentOptions = savedOptions;
-                }
-            }
-        });
-        if (threadPool.getCorePoolSize() == 1) {
-            task.get();
-        }
-    }
-
-    /**
-     * Compiles a method and gathers some statistics.
-     */
-    private void compileMethod(HotSpotResolvedJavaMethod method, int counter) {
-        try {
-            long start = System.currentTimeMillis();
-            long allocatedAtStart = MemUseTrackerImpl.getCurrentThreadAllocatedBytes();
-            int entryBCI = JVMCICompiler.INVOCATION_ENTRY_BCI;
-            HotSpotCompilationRequest request = new HotSpotCompilationRequest(method, entryBCI, 0L);
-            // For more stable CTW execution, disable use of profiling information
-            boolean useProfilingInfo = false;
-            boolean installAsDefault = false;
-            CompilationTask task = new CompilationTask(jvmciRuntime, compiler, request, useProfilingInfo, installAsDefault, currentOptions);
-            task.runCompilation();
-
-            // Invalidate the generated code so the code cache doesn't fill up
-            HotSpotInstalledCode installedCode = task.getInstalledCode();
-            if (installedCode != null) {
-                installedCode.invalidate();
-            }
-
-            memoryUsed.getAndAdd(MemUseTrackerImpl.getCurrentThreadAllocatedBytes() - allocatedAtStart);
-            compileTime.getAndAdd(System.currentTimeMillis() - start);
-            compiledMethodsCounter.incrementAndGet();
-        } catch (Throwable t) {
-            // Catch everything and print a message
-            println("CompileTheWorld (%d) : Error compiling method: %s", counter, method.format("%H.%n(%p):%r"));
-            printStackTrace(t);
-        }
-    }
-
-    /**
-     * Determines if a method should be compiled (Cf. CompilationPolicy::can_be_compiled).
-     *
-     * @return true if it can be compiled, false otherwise
-     */
-    private boolean canBeCompiled(HotSpotResolvedJavaMethod javaMethod, int modifiers) {
-        if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) {
-            return false;
-        }
-        GraalHotSpotVMConfig c = compiler.getGraalRuntime().getVMConfig();
-        if (c.dontCompileHugeMethods && javaMethod.getCodeSize() > c.hugeMethodLimit) {
-            println(verbose || methodFilters != null,
-                            String.format("CompileTheWorld (%d) : Skipping huge method %s (use -XX:-DontCompileHugeMethods or -XX:HugeMethodLimit=%d to include it)", classFileCounter,
-                                            javaMethod.format("%H.%n(%p):%r"),
-                                            javaMethod.getCodeSize()));
-            return false;
-        }
-        // Allow use of -XX:CompileCommand=dontinline to exclude problematic methods
-        if (!javaMethod.canBeInlined()) {
-            return false;
-        }
-        // Skip @Snippets for now
-        for (Annotation annotation : javaMethod.getAnnotations()) {
-            if (annotation.annotationType().equals(Snippet.class)) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    public static void main(String[] args) throws Throwable {
-        Services.exportJVMCITo(CompileTheWorld.class);
-        HotSpotGraalCompiler compiler = (HotSpotGraalCompiler) HotSpotJVMCIRuntime.runtime().getCompiler();
-        compiler.compileTheWorld();
-    }
-}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompileTheWorldOptions.java	Tue Apr 18 20:10:55 2017 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-/*
- * Copyright (c) 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
- * 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 org.graalvm.compiler.hotspot;
-
-import org.graalvm.compiler.options.Option;
-import org.graalvm.compiler.options.OptionType;
-import org.graalvm.compiler.options.OptionKey;
-
-/**
- * Options related to {@link CompileTheWorld}.
- *
- * Note: This must be a top level class to work around for
- * <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=477597">Eclipse bug 477597</a>.
- */
-public class CompileTheWorldOptions {
-    // @formatter:off
-    @Option(help = "Class path denoting methods to compile", type = OptionType.Debug)
-    public static final OptionKey<String> CompileTheWorldClasspath = new OptionKey<>(CompileTheWorld.SUN_BOOT_CLASS_PATH);
-    @Option(help = "Verbose CompileTheWorld operation", type = OptionType.Debug)
-    public static final OptionKey<Boolean> CompileTheWorldVerbose = new OptionKey<>(true);
-    @Option(help = "The number of CompileTheWorld iterations to perform", type = OptionType.Debug)
-    public static final OptionKey<Integer> CompileTheWorldIterations = new OptionKey<>(1);
-    @Option(help = "Only compile methods matching this filter", type = OptionType.Debug)
-    public static final OptionKey<String> CompileTheWorldMethodFilter = new OptionKey<>(null);
-    @Option(help = "Exclude methods matching this filter from compilation", type = OptionType.Debug)
-    public static final OptionKey<String> CompileTheWorldExcludeMethodFilter = new OptionKey<>(null);
-    @Option(help = "First class to consider when using -XX:+CompileTheWorld", type = OptionType.Debug)
-    public static final OptionKey<Integer> CompileTheWorldStartAt = new OptionKey<>(1);
-    @Option(help = "Last class to consider when using -XX:+CompileTheWorld", type = OptionType.Debug)
-    public static final OptionKey<Integer> CompileTheWorldStopAt = new OptionKey<>(Integer.MAX_VALUE);
-    @Option(help = "Option value overrides to use during compile the world. For example, " +
-                   "to disable inlining and partial escape analysis specify 'PartialEscapeAnalysis=false Inline=false'. " +
-                   "The format for each option is the same as on the command line just without the '-Dgraal.' prefix.", type = OptionType.Debug)
-    public static final OptionKey<String> CompileTheWorldConfig = new OptionKey<>(null);
-
-    @Option(help = "Run CTW using as many threads as there are processors on the system", type = OptionType.Debug)
-    public static final OptionKey<Boolean> CompileTheWorldMultiThreaded = new OptionKey<>(false);
-    @Option(help = "Number of threads to use for multithreaded CTW.  Defaults to Runtime.getRuntime().availableProcessors()", type = OptionType.Debug)
-    public static final OptionKey<Integer> CompileTheWorldThreads = new OptionKey<>(0);
-    // @formatter:on
-}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompiler.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompiler.java	Wed Apr 19 04:10:56 2017 +0000
@@ -39,7 +39,6 @@
 import org.graalvm.compiler.debug.DebugConfigScope;
 import org.graalvm.compiler.debug.DebugEnvironment;
 import org.graalvm.compiler.debug.GraalDebugConfig;
-import org.graalvm.compiler.debug.TTY;
 import org.graalvm.compiler.debug.TopLevelDebugConfig;
 import org.graalvm.compiler.debug.internal.method.MethodMetricsRootScopeInfo;
 import org.graalvm.compiler.hotspot.CompilationCounters.Options;
@@ -63,7 +62,6 @@
 
 import jdk.vm.ci.code.CompilationRequest;
 import jdk.vm.ci.code.CompilationRequestResult;
-import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider;
 import jdk.vm.ci.hotspot.HotSpotCompilationRequest;
 import jdk.vm.ci.hotspot.HotSpotCompilationRequestResult;
 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider;
@@ -135,19 +133,6 @@
         }
     }
 
-    public void compileTheWorld() throws Throwable {
-        HotSpotCodeCacheProvider codeCache = (HotSpotCodeCacheProvider) jvmciRuntime.getHostJVMCIBackend().getCodeCache();
-        int iterations = CompileTheWorldOptions.CompileTheWorldIterations.getValue(graalRuntime.getOptions());
-        for (int i = 0; i < iterations; i++) {
-            codeCache.resetCompilationStatistics();
-            TTY.println("CompileTheWorld : iteration " + i);
-            this.graalRuntime.getVMConfig();
-            CompileTheWorld ctw = new CompileTheWorld(jvmciRuntime, this, graalRuntime.getOptions());
-            ctw.compile();
-        }
-        System.exit(0);
-    }
-
     public CompilationResult compile(ResolvedJavaMethod method, int entryBCI, boolean useProfilingInfo, CompilationIdentifier compilationId, OptionValues options) {
         HotSpotBackend backend = graalRuntime.getHostBackend();
         HotSpotProviders providers = backend.getProviders();
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalOptionValues.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalOptionValues.java	Wed Apr 19 04:10:56 2017 +0000
@@ -39,7 +39,6 @@
 import org.graalvm.compiler.options.OptionsParser;
 import org.graalvm.compiler.serviceprovider.ServiceProvider;
 import org.graalvm.util.EconomicMap;
-import org.graalvm.util.MapCursor;
 
 import jdk.vm.ci.common.InitTimer;
 
@@ -117,9 +116,8 @@
                         Properties props = new Properties();
                         props.load(fr);
                         EconomicMap<String, String> optionSettings = EconomicMap.create();
-                        MapCursor<String, String> cursor = optionSettings.getEntries();
-                        while (cursor.advance()) {
-                            optionSettings.put(cursor.getKey(), cursor.getValue());
+                        for (Map.Entry<Object, Object> e : props.entrySet()) {
+                            optionSettings.put((String) e.getKey(), (String) e.getValue());
                         }
                         try {
                             OptionsParser.parseOptions(optionSettings, values, loader);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotHostBackend.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotHostBackend.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,9 +22,11 @@
  */
 package org.graalvm.compiler.hotspot;
 
+import static jdk.vm.ci.code.CodeUtil.K;
 import static jdk.vm.ci.code.CodeUtil.getCallingConvention;
 import static jdk.vm.ci.common.InitTimer.timer;
 
+import org.graalvm.compiler.core.common.NumUtil;
 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
 import org.graalvm.compiler.hotspot.meta.HotSpotHostForeignCallsProvider;
 import org.graalvm.compiler.hotspot.meta.HotSpotLoweringProvider;
@@ -109,7 +111,7 @@
             // is greater than a page.
 
             int pageSize = config.vmPageSize;
-            int bangEnd = config.stackShadowPages * pageSize;
+            int bangEnd = NumUtil.roundUp(config.stackShadowPages * 4 * K, pageSize);
 
             // This is how far the previous frame's stack banging extended.
             int bangEndSafe = bangEnd;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/NodeCostDumpUtil.java	Wed Apr 19 04:10:56 2017 +0000
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2016, 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 org.graalvm.compiler.hotspot;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+import java.util.stream.Collectors;
+
+import org.graalvm.compiler.debug.CSVUtil;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.spi.Virtualizable;
+
+public class NodeCostDumpUtil {
+
+    private static final String prefix1 = "com.oracle.";
+    private static final String prefix2 = "org.graalvm.";
+    private static final String FMT = CSVUtil.buildFormatString("%s", "%s", "%s", "%s", "%s", "%s", "%s", "%s");
+
+    private static String getArgumentRegex(String arg) {
+        if (arg.length() == 0) {
+            return null;
+        }
+        try {
+            Pattern.compile(arg);
+            return arg;
+        } catch (PatternSyntaxException e) {
+            // silently ignore
+            System.err.println("Invalid regex given, defaulting to \".*\" regex..");
+            return null;
+        }
+    }
+
+    public static void main(String[] args) {
+        if (args.length != 1) {
+            System.err.println("NodeCostDumpUtil expects exactly one argument, the node name regex to match against.");
+            System.exit(-1);
+        }
+        final String pattern = getArgumentRegex(args[0]);
+        String version = System.getProperty("java.specification.version");
+        if (version.compareTo("1.9") >= 0) {
+            System.err.printf("NodeCostDumpUtil does not support JDK versions greater than 1.8, current version is %s.\n", version);
+            System.exit(-1);
+        }
+        String[] jvmciCP = System.getProperty("jvmci.class.path.append").split(File.pathSeparator);
+        String[] primarySuiteCP = System.getProperty("primary.suite.cp").split(File.pathSeparator);
+        ClassLoader applicationClassLoader = Thread.currentThread().getContextClassLoader();
+        HashSet<Class<?>> classes = new HashSet<>();
+        try {
+            Set<String> uniquePaths = new HashSet<>(Arrays.asList(primarySuiteCP));
+            uniquePaths.addAll(Arrays.asList(jvmciCP));
+            for (String path : uniquePaths) {
+                if (new File(path).exists()) {
+                    if (path.endsWith(".jar")) {
+                        try (FileSystem jarFileSystem = FileSystems.newFileSystem(URI.create("jar:file:" + path), Collections.emptyMap())) {
+                            initAllClasses(jarFileSystem.getPath("/"), applicationClassLoader, classes);
+                        }
+                    } else {
+                        initAllClasses(FileSystems.getDefault().getPath(path), applicationClassLoader, classes);
+                    }
+                }
+            }
+        } catch (IOException ex) {
+            GraalError.shouldNotReachHere();
+        }
+        System.err.printf("Loaded %d classes...\n", classes.size());
+        List<Class<?>> nodeClasses = new ArrayList<>();
+        for (Class<?> loaded : classes) {
+            if (Node.class.isAssignableFrom(loaded) && !loaded.isArray()) {
+                nodeClasses.add(loaded);
+            }
+        }
+        System.err.printf("Loaded %s node classes...\n", nodeClasses.size());
+        List<NodeClass<?>> nc = new ArrayList<>();
+        for (Class<?> nodeClass : nodeClasses) {
+            Field f;
+            try {
+                f = nodeClass.getField("TYPE");
+                f.setAccessible(true);
+                Object val = f.get(null);
+                NodeClass<?> nodeType = (NodeClass<?>) val;
+                nc.add(nodeType);
+            } catch (Throwable t) {
+                // Silently ignore problems here
+            }
+        }
+        System.err.printf("Read TYPE field from %s node classes...\n", nc.size());
+        nc = nc.stream().filter(x -> x != null).collect(Collectors.toList());
+        nc.sort((x, y) -> {
+            String a = x.getJavaClass().getName();
+            String b = y.getJavaClass().getName();
+            return a.compareTo(b);
+        });
+        CSVUtil.Escape.println(System.out, FMT, "NodeName", "Size", "Overrides Size Method", "Cycles", "Overrides Cycles Method", "Canonicalizable", "MemoryCheckPoint", "Virtualizable");
+        for (NodeClass<?> nodeclass : nc) {
+            String packageStrippedName = null;
+            try {
+                packageStrippedName = nodeclass.getJavaClass().getCanonicalName().replace(prefix1, "").replace(prefix2, "");
+            } catch (Throwable t) {
+                // do nothing
+                continue;
+            }
+            if (pattern != null && !packageStrippedName.matches(pattern)) {
+                continue;
+            }
+            boolean overridesSizeMethod = false;
+            boolean overridesCyclesMethod = false;
+            Class<?> c = nodeclass.getJavaClass();
+            try {
+                c.getDeclaredMethod("estimatedNodeSize");
+                overridesSizeMethod = true;
+            } catch (Throwable t) {
+                // do nothing
+            }
+            try {
+                c.getDeclaredMethod("estimatedNodeCycles");
+                overridesCyclesMethod = true;
+            } catch (Throwable t) {
+                // do nothing
+            }
+            CSVUtil.Escape.println(System.out, FMT, packageStrippedName, nodeclass.size(), overridesSizeMethod, nodeclass.cycles(), overridesCyclesMethod, canonicalizable(c), memoryCheckPoint(c),
+                            virtualizable(c));
+        }
+    }
+
+    private static boolean canonicalizable(Class<?> c) {
+        return Canonicalizable.class.isAssignableFrom(c);
+    }
+
+    private static boolean virtualizable(Class<?> c) {
+        return Virtualizable.class.isAssignableFrom(c);
+    }
+
+    private static boolean memoryCheckPoint(Class<?> c) {
+        return MemoryCheckpoint.class.isAssignableFrom(c);
+    }
+
+    private static void initAllClasses(final Path root, ClassLoader classLoader, HashSet<Class<?>> classes) {
+        try {
+            Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
+                @Override
+                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+                    String className = root.relativize(file).toString();
+                    ClassLoader c = classLoader;
+                    if (className.endsWith(".class")) {
+                        String prefix = prefixed(className);
+                        if (prefix != null) {
+                            String stripped = stripClassName(className);
+                            c = new URLClassLoader(new URL[]{new File(constructURLPart(stripped, className, prefix)).toURI().toURL()}, classLoader);
+                            className = constructClazzPart(stripped, prefix);
+                        } else {
+                            String clazzPart = className.replace('/', '.');
+                            className = clazzPart.substring(0, clazzPart.length() - ".class".length());
+                        }
+                        try {
+                            Class<?> systemClass = Class.forName(className, false, c);
+                            if (systemClass.getEnclosingClass() != null) {
+                                try {
+                                    classes.add(systemClass.getEnclosingClass());
+                                } catch (Throwable t) {
+                                    // do nothing
+                                }
+                            }
+                            classes.add(systemClass);
+                        } catch (Throwable ignored) {
+                        }
+                    }
+                    return FileVisitResult.CONTINUE;
+                }
+            });
+        } catch (IOException ex) {
+            GraalError.shouldNotReachHere();
+        }
+    }
+
+    private static String prefixed(String className) {
+        if (className.contains(prefix1) && className.indexOf(prefix1) > 0) {
+            return prefix1;
+        } else if (className.contains(prefix2) && className.indexOf(prefix2) > 0) {
+            return prefix2;
+        }
+        return null;
+    }
+
+    private static String stripClassName(String className) {
+        return className.replace('/', '.');
+    }
+
+    private static String constructClazzPart(String stripped, String prefix) {
+        String clazzPart = stripped.substring(stripped.lastIndexOf(prefix), stripped.length());
+        return clazzPart.substring(0, clazzPart.length() - ".class".length());
+    }
+
+    private static String constructURLPart(String stripped, String className, String prefix) {
+        return className.substring(0, stripped.lastIndexOf(prefix));
+    }
+
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java	Wed Apr 19 04:10:56 2017 +0000
@@ -252,7 +252,7 @@
             @Override
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) {
                 ValueNode javaClass = receiver.get();
-                LogicNode condition = b.recursiveAppend(InstanceOfDynamicNode.create(b.getAssumptions(), b.getConstantReflection(), javaClass, object, true));
+                LogicNode condition = b.append(InstanceOfDynamicNode.create(b.getAssumptions(), b.getConstantReflection(), javaClass, object, true));
                 if (condition.isTautology()) {
                     b.addPush(JavaKind.Object, object);
                 } else {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotProviders.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotProviders.java	Wed Apr 19 04:10:56 2017 +0000
@@ -27,7 +27,6 @@
 import org.graalvm.compiler.hotspot.word.HotSpotWordTypes;
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import org.graalvm.compiler.nodes.spi.LoweringProvider;
-import org.graalvm.compiler.nodes.spi.NodeCostProvider;
 import org.graalvm.compiler.nodes.spi.Replacements;
 import org.graalvm.compiler.phases.tiers.SuitesProvider;
 import org.graalvm.compiler.phases.util.Providers;
@@ -49,10 +48,10 @@
     private final Plugins graphBuilderPlugins;
 
     public HotSpotProviders(MetaAccessProvider metaAccess, HotSpotCodeCacheProvider codeCache, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantField,
-                    HotSpotForeignCallsProvider foreignCalls, LoweringProvider lowerer, Replacements replacements, NodeCostProvider nodeCostProvider, SuitesProvider suites,
+                    HotSpotForeignCallsProvider foreignCalls, LoweringProvider lowerer, Replacements replacements, SuitesProvider suites,
                     HotSpotRegistersProvider registers,
                     SnippetReflectionProvider snippetReflection, HotSpotWordTypes wordTypes, Plugins graphBuilderPlugins) {
-        super(metaAccess, codeCache, constantReflection, constantField, foreignCalls, lowerer, replacements, new HotSpotStampProvider(), nodeCostProvider);
+        super(metaAccess, codeCache, constantReflection, constantField, foreignCalls, lowerer, replacements, new HotSpotStampProvider());
         this.suites = suites;
         this.registers = registers;
         this.snippetReflection = snippetReflection;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotWordOperationPlugin.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotWordOperationPlugin.java	Wed Apr 19 04:10:56 2017 +0000
@@ -117,7 +117,7 @@
                 ValueNode pointer = args[0];
                 assert pointer.stamp() instanceof MetaspacePointerStamp;
 
-                LogicNode isNull = b.add(IsNullNode.create(pointer));
+                LogicNode isNull = b.addWithInputs(IsNullNode.create(pointer));
                 b.addPush(returnKind, ConditionalNode.create(isNull, b.add(forBoolean(true)), b.add(forBoolean(false))));
                 break;
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/ComputeObjectAddressNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/ComputeObjectAddressNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,12 +22,12 @@
  */
 package org.graalvm.compiler.hotspot.nodes;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1;
 
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodeinfo.NodeSize;
 import org.graalvm.compiler.nodes.FixedWithNextNode;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.debug.ControlFlowAnchored;
@@ -40,7 +40,7 @@
  * A high-level intrinsic for getting an address inside of an object. During lowering it will be
  * moved next to any uses to avoid creating a derived pointer that is live across a safepoint.
  */
-@NodeInfo(cycles = CYCLES_3, size = SIZE_2)
+@NodeInfo(cycles = CYCLES_1, size = NodeSize.SIZE_1)
 public final class ComputeObjectAddressNode extends FixedWithNextNode implements Lowerable, ControlFlowAnchored {
     public static final NodeClass<ComputeObjectAddressNode> TYPE = NodeClass.create(ComputeObjectAddressNode.class);
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/DeoptimizeCallerNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/DeoptimizeCallerNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,8 +22,8 @@
  */
 package org.graalvm.compiler.hotspot.nodes;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_3;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8;
 
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.NodeClass;
@@ -39,7 +39,7 @@
 /**
  * Removes the current frame and tail calls the uncommon trap routine.
  */
-@NodeInfo(shortName = "DeoptCaller", nameTemplate = "DeoptCaller {p#reason/s}", cycles = CYCLES_1, size = SIZE_3)
+@NodeInfo(shortName = "DeoptCaller", nameTemplate = "DeoptCaller {p#reason/s}", cycles = CYCLES_8, size = SIZE_8)
 public final class DeoptimizeCallerNode extends ControlSinkNode implements LIRLowerable {
 
     public static final NodeClass<DeoptimizeCallerNode> TYPE = NodeClass.create(DeoptimizeCallerNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/G1ArrayRangePostWriteBarrier.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/G1ArrayRangePostWriteBarrier.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,14 +22,14 @@
  */
 package org.graalvm.compiler.hotspot.nodes;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_100;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_100;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_64;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_64;
 
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
 import org.graalvm.compiler.nodes.ValueNode;
 
-@NodeInfo(cycles = CYCLES_100, size = SIZE_100)
+@NodeInfo(cycles = CYCLES_64, size = SIZE_64)
 public class G1ArrayRangePostWriteBarrier extends ArrayRangeWriteBarrier {
     public static final NodeClass<G1ArrayRangePostWriteBarrier> TYPE = NodeClass.create(G1ArrayRangePostWriteBarrier.class);
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/G1ArrayRangePreWriteBarrier.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/G1ArrayRangePreWriteBarrier.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,14 +22,14 @@
  */
 package org.graalvm.compiler.hotspot.nodes;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_100;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_100;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_64;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_64;
 
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
 import org.graalvm.compiler.nodes.ValueNode;
 
-@NodeInfo(cycles = CYCLES_100, size = SIZE_100)
+@NodeInfo(cycles = CYCLES_64, size = SIZE_64)
 public final class G1ArrayRangePreWriteBarrier extends ArrayRangeWriteBarrier {
     public static final NodeClass<G1ArrayRangePreWriteBarrier> TYPE = NodeClass.create(G1ArrayRangePreWriteBarrier.class);
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/G1PostWriteBarrier.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/G1PostWriteBarrier.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,15 +22,15 @@
  */
 package org.graalvm.compiler.hotspot.nodes;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_50;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_50;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_64;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_64;
 
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.memory.address.AddressNode;
 
-@NodeInfo(cycles = CYCLES_50, size = SIZE_50)
+@NodeInfo(cycles = CYCLES_64, size = SIZE_64)
 public class G1PostWriteBarrier extends ObjectWriteBarrier {
 
     public static final NodeClass<G1PostWriteBarrier> TYPE = NodeClass.create(G1PostWriteBarrier.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/G1PreWriteBarrier.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/G1PreWriteBarrier.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,8 +22,8 @@
  */
 package org.graalvm.compiler.hotspot.nodes;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_50;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_50;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_64;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_64;
 
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.InputType;
@@ -33,7 +33,7 @@
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.memory.address.AddressNode;
 
-@NodeInfo(cycles = CYCLES_50, size = SIZE_50)
+@NodeInfo(cycles = CYCLES_64, size = SIZE_64)
 public final class G1PreWriteBarrier extends ObjectWriteBarrier implements DeoptimizingNode.DeoptBefore {
 
     public static final NodeClass<G1PreWriteBarrier> TYPE = NodeClass.create(G1PreWriteBarrier.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/G1ReferentFieldReadBarrier.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/G1ReferentFieldReadBarrier.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,8 +22,8 @@
  */
 package org.graalvm.compiler.hotspot.nodes;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_50;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_50;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_64;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_64;
 
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
@@ -36,7 +36,7 @@
  * {@code UnsafeLoadNode}). The return value of the read is passed to the snippet implementing the
  * read barrier and consequently is added to the SATB queue if the concurrent marker is enabled.
  */
-@NodeInfo(cycles = CYCLES_50, size = SIZE_50)
+@NodeInfo(cycles = CYCLES_64, size = SIZE_64)
 public final class G1ReferentFieldReadBarrier extends ObjectWriteBarrier {
     public static final NodeClass<G1ReferentFieldReadBarrier> TYPE = NodeClass.create(G1ReferentFieldReadBarrier.class);
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/HotSpotNodeCostProvider.java	Tue Apr 18 20:10:55 2017 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 2016, 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 org.graalvm.compiler.hotspot.nodes;
-
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_20;
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_30;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_20;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_30;
-
-import org.graalvm.compiler.graph.Node;
-import org.graalvm.compiler.hotspot.replacements.ObjectCloneNode;
-import org.graalvm.compiler.nodeinfo.NodeCycles;
-import org.graalvm.compiler.nodeinfo.NodeSize;
-import org.graalvm.compiler.nodes.spi.DefaultNodeCostProvider;
-import org.graalvm.compiler.nodes.type.StampTool;
-
-import jdk.vm.ci.meta.ResolvedJavaType;
-
-public abstract class HotSpotNodeCostProvider extends DefaultNodeCostProvider {
-
-    @Override
-    public NodeSize size(Node n) {
-        if (n instanceof ObjectCloneNode) {
-            ResolvedJavaType type = StampTool.typeOrNull(((ObjectCloneNode) n).getObject());
-            if (type != null) {
-                if (type.isArray()) {
-                    return SIZE_30;
-                } else {
-                    return SIZE_20;
-                }
-            }
-        }
-        return super.size(n);
-    }
-
-    @Override
-    public NodeCycles cycles(Node n) {
-        if (n instanceof ObjectCloneNode) {
-            ResolvedJavaType type = StampTool.typeOrNull(((ObjectCloneNode) n).getObject());
-            if (type != null) {
-                if (type.isArray()) {
-                    return CYCLES_30;
-                } else {
-                    return CYCLES_20;
-                }
-            }
-        }
-        return super.cycles(n);
-    }
-
-}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/JumpToExceptionHandlerInCallerNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/JumpToExceptionHandlerInCallerNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,7 +22,7 @@
  */
 package org.graalvm.compiler.hotspot.nodes;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_15;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8;
 
 import org.graalvm.compiler.core.common.type.StampFactory;
@@ -40,7 +40,7 @@
  * Sets up the {@linkplain HotSpotBackend#EXCEPTION_HANDLER_IN_CALLER arguments} expected by an
  * exception handler in the caller's frame, removes the current frame and jumps to said handler.
  */
-@NodeInfo(cycles = CYCLES_15, size = SIZE_8)
+@NodeInfo(cycles = CYCLES_8, size = SIZE_8)
 public final class JumpToExceptionHandlerInCallerNode extends ControlSinkNode implements LIRLowerable {
 
     public static final NodeClass<JumpToExceptionHandlerInCallerNode> TYPE = NodeClass.create(JumpToExceptionHandlerInCallerNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/JumpToExceptionHandlerNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/JumpToExceptionHandlerNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/SerialArrayRangeWriteBarrier.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/SerialArrayRangeWriteBarrier.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,14 +22,14 @@
  */
 package org.graalvm.compiler.hotspot.nodes;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_15;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_20;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8;
 
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
 import org.graalvm.compiler.nodes.ValueNode;
 
-@NodeInfo(cycles = CYCLES_15, size = SIZE_20)
+@NodeInfo(cycles = CYCLES_8, size = SIZE_8)
 public final class SerialArrayRangeWriteBarrier extends ArrayRangeWriteBarrier {
 
     public static final NodeClass<SerialArrayRangeWriteBarrier> TYPE = NodeClass.create(SerialArrayRangeWriteBarrier.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/SerialWriteBarrier.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/SerialWriteBarrier.java	Wed Apr 19 04:10:56 2017 +0000
@@ -23,13 +23,13 @@
 package org.graalvm.compiler.hotspot.nodes;
 
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_3;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_4;
 
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
 import org.graalvm.compiler.nodes.memory.address.AddressNode;
 
-@NodeInfo(cycles = CYCLES_8, size = SIZE_3)
+@NodeInfo(cycles = CYCLES_8, size = SIZE_4)
 public class SerialWriteBarrier extends ObjectWriteBarrier {
 
     public static final NodeClass<SerialWriteBarrier> TYPE = NodeClass.create(SerialWriteBarrier.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/EncodedSymbolNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/EncodedSymbolNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,6 +22,9 @@
  */
 package org.graalvm.compiler.hotspot.nodes.aot;
 
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
+
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.Node;
@@ -38,7 +41,7 @@
 
 import jdk.vm.ci.meta.Constant;
 
-@NodeInfo
+@NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
 public final class EncodedSymbolNode extends FloatingNode implements Canonicalizable {
 
     public static final NodeClass<EncodedSymbolNode> TYPE = NodeClass.create(EncodedSymbolNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/InitializeKlassNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/InitializeKlassNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,8 +22,8 @@
  */
 package org.graalvm.compiler.hotspot.nodes.aot;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_20;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_4;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_16;
 
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
@@ -32,7 +32,7 @@
 import org.graalvm.compiler.nodes.spi.Lowerable;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 
-@NodeInfo(cycles = CYCLES_3, size = SIZE_20)
+@NodeInfo(cycles = CYCLES_4, size = SIZE_16)
 public class InitializeKlassNode extends DeoptimizingFixedWithNextNode implements Lowerable {
     public static final NodeClass<InitializeKlassNode> TYPE = NodeClass.create(InitializeKlassNode.class);
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/InitializeKlassStubCall.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/InitializeKlassStubCall.java	Wed Apr 19 04:10:56 2017 +0000
@@ -23,7 +23,7 @@
 package org.graalvm.compiler.hotspot.nodes.aot;
 
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_20;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_16;
 
 import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.graph.Node;
@@ -51,7 +51,7 @@
 /**
  * A call to the VM via a regular stub.
  */
-@NodeInfo(allowedUsageTypes = {InputType.Memory}, cycles = CYCLES_UNKNOWN, size = SIZE_20)
+@NodeInfo(allowedUsageTypes = {InputType.Memory}, cycles = CYCLES_UNKNOWN, size = SIZE_16)
 public class InitializeKlassStubCall extends AbstractMemoryCheckpoint implements LIRLowerable, Canonicalizable, DeoptimizingNode.DeoptBefore, MemoryCheckpoint.Single {
     public static final NodeClass<InitializeKlassStubCall> TYPE = NodeClass.create(InitializeKlassStubCall.class);
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/LoadConstantIndirectlyFixedNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/LoadConstantIndirectlyFixedNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,8 +22,8 @@
  */
 package org.graalvm.compiler.hotspot.nodes.aot;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_3;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_4;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
 
 import org.graalvm.compiler.core.common.PermanentBailoutException;
 import org.graalvm.compiler.graph.Node;
@@ -46,7 +46,7 @@
 import jdk.vm.ci.meta.Constant;
 import jdk.vm.ci.meta.Value;
 
-@NodeInfo(cycles = CYCLES_3, size = SIZE_3)
+@NodeInfo(cycles = CYCLES_4, size = SIZE_1)
 public class LoadConstantIndirectlyFixedNode extends FixedWithNextNode implements Canonicalizable, LIRLowerable {
 
     public static final NodeClass<LoadConstantIndirectlyFixedNode> TYPE = NodeClass.create(LoadConstantIndirectlyFixedNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/LoadConstantIndirectlyNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/LoadConstantIndirectlyNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,8 +22,8 @@
  */
 package org.graalvm.compiler.hotspot.nodes.aot;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_3;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_4;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
 
 import org.graalvm.compiler.core.common.PermanentBailoutException;
 import org.graalvm.compiler.graph.Node;
@@ -45,7 +45,7 @@
 import jdk.vm.ci.meta.Constant;
 import jdk.vm.ci.meta.Value;
 
-@NodeInfo(cycles = CYCLES_3, size = SIZE_3)
+@NodeInfo(cycles = CYCLES_4, size = SIZE_1)
 public class LoadConstantIndirectlyNode extends FloatingNode implements Canonicalizable, LIRLowerable {
 
     public static final NodeClass<LoadConstantIndirectlyNode> TYPE = NodeClass.create(LoadConstantIndirectlyNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/LoadMethodCountersIndirectlyNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/LoadMethodCountersIndirectlyNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,8 +22,8 @@
  */
 package org.graalvm.compiler.hotspot.nodes.aot;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_3;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_4;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_4;
 
 import org.graalvm.compiler.core.common.PermanentBailoutException;
 import org.graalvm.compiler.graph.Node;
@@ -46,7 +46,7 @@
 import jdk.vm.ci.meta.Constant;
 import jdk.vm.ci.meta.Value;
 
-@NodeInfo(cycles = CYCLES_3, size = SIZE_3)
+@NodeInfo(cycles = CYCLES_4, size = SIZE_4)
 public class LoadMethodCountersIndirectlyNode extends FloatingNode implements Canonicalizable, LIRLowerable {
 
     public static final NodeClass<LoadMethodCountersIndirectlyNode> TYPE = NodeClass.create(LoadMethodCountersIndirectlyNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/LoadMethodCountersNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/LoadMethodCountersNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,10 +22,8 @@
  */
 package org.graalvm.compiler.hotspot.nodes.aot;
 
-import jdk.vm.ci.meta.ResolvedJavaMethod;
-
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_3;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_4;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_4;
 
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.graph.NodeClass;
@@ -37,7 +35,9 @@
 import org.graalvm.compiler.nodes.spi.LIRLowerable;
 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
 
-@NodeInfo(cycles = CYCLES_3, size = SIZE_3)
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+@NodeInfo(cycles = CYCLES_4, size = SIZE_4)
 public class LoadMethodCountersNode extends FloatingNode implements LIRLowerable {
     public static final NodeClass<LoadMethodCountersNode> TYPE = NodeClass.create(LoadMethodCountersNode.class);
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveConstantNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveConstantNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,8 +22,8 @@
  */
 package org.graalvm.compiler.hotspot.nodes.aot;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_20;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_4;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_16;
 
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction;
@@ -33,7 +33,7 @@
 import org.graalvm.compiler.nodes.spi.Lowerable;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 
-@NodeInfo(cycles = CYCLES_3, size = SIZE_20)
+@NodeInfo(cycles = CYCLES_4, size = SIZE_16)
 public class ResolveConstantNode extends FloatingNode implements Lowerable {
     public static final NodeClass<ResolveConstantNode> TYPE = NodeClass.create(ResolveConstantNode.class);
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveConstantStubCall.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveConstantStubCall.java	Wed Apr 19 04:10:56 2017 +0000
@@ -23,7 +23,7 @@
 package org.graalvm.compiler.hotspot.nodes.aot;
 
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_20;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_16;
 
 import org.graalvm.compiler.core.common.PermanentBailoutException;
 import org.graalvm.compiler.graph.Node;
@@ -49,7 +49,7 @@
 /**
  * A call to the VM via a regular stub.
  */
-@NodeInfo(cycles = CYCLES_UNKNOWN, size = SIZE_20)
+@NodeInfo(cycles = CYCLES_UNKNOWN, size = SIZE_16)
 public class ResolveConstantStubCall extends DeoptimizingStubCall implements Canonicalizable, LIRLowerable {
     public static final NodeClass<ResolveConstantStubCall> TYPE = NodeClass.create(ResolveConstantStubCall.class);
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveMethodAndLoadCountersNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveMethodAndLoadCountersNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,10 +22,8 @@
  */
 package org.graalvm.compiler.hotspot.nodes.aot;
 
-import jdk.vm.ci.meta.ResolvedJavaMethod;
-
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_20;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_4;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_16;
 
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.hotspot.nodes.type.MethodCountersPointerStamp;
@@ -35,7 +33,9 @@
 import org.graalvm.compiler.nodes.spi.Lowerable;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 
-@NodeInfo(cycles = CYCLES_3, size = SIZE_20)
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+@NodeInfo(cycles = CYCLES_4, size = SIZE_16)
 public class ResolveMethodAndLoadCountersNode extends FloatingNode implements Lowerable {
     public static final NodeClass<ResolveMethodAndLoadCountersNode> TYPE = NodeClass.create(ResolveMethodAndLoadCountersNode.class);
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveMethodAndLoadCountersStubCall.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveMethodAndLoadCountersStubCall.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,11 +22,8 @@
  */
 package org.graalvm.compiler.hotspot.nodes.aot;
 
-import jdk.vm.ci.meta.Constant;
-import jdk.vm.ci.meta.Value;
-
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_20;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_16;
 
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeClass;
@@ -45,10 +42,13 @@
 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
 import org.graalvm.compiler.nodes.util.GraphUtil;
 
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.Value;
+
 /**
  * A call to the VM via a regular stub.
  */
-@NodeInfo(cycles = CYCLES_UNKNOWN, size = SIZE_20)
+@NodeInfo(cycles = CYCLES_UNKNOWN, size = SIZE_16)
 public class ResolveMethodAndLoadCountersStubCall extends DeoptimizingStubCall implements Canonicalizable, LIRLowerable {
     public static final NodeClass<ResolveMethodAndLoadCountersStubCall> TYPE = NodeClass.create(ResolveMethodAndLoadCountersStubCall.class);
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/ProfileNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/ProfileNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,6 +22,9 @@
  */
 package org.graalvm.compiler.hotspot.nodes.profiling;
 
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
+
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.graph.iterators.NodeIterable;
@@ -37,7 +40,7 @@
 
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 
-@NodeInfo
+@NodeInfo(cycles = CYCLES_IGNORED, cyclesRationale = "profiling should be ignored", size = SIZE_IGNORED, sizeRationale = "profiling should be ignored")
 public class ProfileNode extends DeoptimizingFixedWithNextNode implements Lowerable {
     public static class Options {
         @Option(help = "Control probabilistic profiling on AMD64", type = OptionType.Expert)//
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/ProfileWithNotificationNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/ProfileWithNotificationNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,15 +22,12 @@
  */
 package org.graalvm.compiler.hotspot.nodes.profiling;
 
-import jdk.vm.ci.meta.ResolvedJavaMethod;
-
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_10;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_50;
-
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
 
-@NodeInfo(cycles = CYCLES_10, size = SIZE_50)
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+@NodeInfo
 public class ProfileWithNotificationNode extends ProfileNode {
     public static final NodeClass<ProfileWithNotificationNode> TYPE = NodeClass.create(ProfileWithNotificationNode.class);
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ClassGetHubNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ClassGetHubNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,7 +22,7 @@
  */
 package org.graalvm.compiler.hotspot.replacements;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_4;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
 
 import jdk.vm.ci.meta.JavaKind;
@@ -63,7 +63,7 @@
  * handled by
  * {@link ReadNode#canonicalizeRead(ValueNode, AddressNode, LocationIdentity, CanonicalizerTool)}.
  */
-@NodeInfo(cycles = CYCLES_4, size = SIZE_1)
+@NodeInfo(cycles = CYCLES_1, size = SIZE_1)
 public final class ClassGetHubNode extends FloatingNode implements Lowerable, Canonicalizable, ConvertNode {
     public static final NodeClass<ClassGetHubNode> TYPE = NodeClass.create(ClassGetHubNode.class);
     @Input protected ValueNode clazz;
@@ -80,7 +80,7 @@
     @SuppressWarnings("unused")
     public static boolean intrinsify(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode clazz) {
         ValueNode clazzValue = create(clazz, b.getMetaAccess(), b.getConstantReflection(), false);
-        b.push(JavaKind.Object, b.recursiveAppend(clazzValue));
+        b.push(JavaKind.Object, b.append(clazzValue));
         return true;
     }
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HubGetClassNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HubGetClassNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,7 +22,7 @@
  */
 package org.graalvm.compiler.hotspot.replacements;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_4;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
 
 import org.graalvm.compiler.core.common.GraalOptions;
@@ -51,7 +51,7 @@
  * Read {@code Klass::_java_mirror} and incorporate non-null type information into stamp. This is
  * also used by {@link ClassGetHubNode} to eliminate chains of {@code klass._java_mirror._klass}.
  */
-@NodeInfo(cycles = CYCLES_4, size = SIZE_1)
+@NodeInfo(cycles = CYCLES_1, size = SIZE_1)
 public final class HubGetClassNode extends FloatingNode implements Lowerable, Canonicalizable, ConvertNode {
     public static final NodeClass<HubGetClassNode> TYPE = NodeClass.create(HubGetClassNode.class);
     @Input protected ValueNode hub;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/KlassLayoutHelperNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/KlassLayoutHelperNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,7 +22,7 @@
  */
 package org.graalvm.compiler.hotspot.replacements;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_4;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
 
 import jdk.vm.ci.meta.ConstantReflectionProvider;
@@ -54,7 +54,7 @@
  * Read {@code Klass::_layout_helper} and incorporate any useful stamp information based on any type
  * information in {@code klass}.
  */
-@NodeInfo(cycles = CYCLES_4, size = SIZE_1)
+@NodeInfo(cycles = CYCLES_1, size = SIZE_1)
 public final class KlassLayoutHelperNode extends FloatingNode implements Canonicalizable, Lowerable {
 
     public static final NodeClass<KlassLayoutHelperNode> TYPE = NodeClass.create(KlassLayoutHelperNode.class);
@@ -75,7 +75,7 @@
     @SuppressWarnings("unused")
     public static boolean intrinsify(GraphBuilderContext b, ResolvedJavaMethod method, @InjectedNodeParameter GraalHotSpotVMConfig config, ValueNode klass) {
         ValueNode valueNode = create(config, klass, b.getConstantReflection(), b.getMetaAccess());
-        b.push(JavaKind.Int, b.recursiveAppend(valueNode));
+        b.push(JavaKind.Int, b.append(valueNode));
         return true;
     }
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ReflectionGetCallerClassNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ReflectionGetCallerClassNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,9 +22,6 @@
  */
 package org.graalvm.compiler.hotspot.replacements;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_20;
-
 import org.graalvm.compiler.core.common.type.StampPair;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.graph.Node;
@@ -47,7 +44,7 @@
 import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 
-@NodeInfo(cycles = CYCLES_UNKNOWN, cyclesRationale = "This node can be lowered to a call", size = SIZE_20)
+@NodeInfo
 public final class ReflectionGetCallerClassNode extends MacroStateSplitNode implements Canonicalizable, Lowerable {
 
     public static final NodeClass<ReflectionGetCallerClassNode> TYPE = NodeClass.create(ReflectionGetCallerClassNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/UnsafeArrayCopyNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/UnsafeArrayCopyNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -23,8 +23,8 @@
 package org.graalvm.compiler.hotspot.replacements.arraycopy;
 
 import static org.graalvm.compiler.core.common.LocationIdentity.any;
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_200;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_200;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_256;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_64;
 
 import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.core.common.type.StampFactory;
@@ -43,7 +43,7 @@
 
 import jdk.vm.ci.meta.JavaKind;
 
-@NodeInfo(allowedUsageTypes = {InputType.Memory}, cycles = CYCLES_200, size = SIZE_200)
+@NodeInfo(allowedUsageTypes = {InputType.Memory}, cycles = CYCLES_256, size = SIZE_64)
 public final class UnsafeArrayCopyNode extends ArrayRangeWriteNode implements Lowerable, MemoryCheckpoint.Single, MemoryAccess {
 
     public static final NodeClass<UnsafeArrayCopyNode> TYPE = NodeClass.create(UnsafeArrayCopyNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BciBlockMapping.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BciBlockMapping.java	Wed Apr 19 04:10:56 2017 +0000
@@ -437,8 +437,6 @@
     private static final int LOOP_HEADER_INITIAL_CAPACITY = 4;
 
     private int blocksNotYetAssignedId;
-    public int returnCount;
-    private int returnBci;
 
     /**
      * Creates a new BlockMap instance from {@code code}.
@@ -452,10 +450,6 @@
         return this.blocks;
     }
 
-    public int getReturnCount() {
-        return this.returnCount;
-    }
-
     /**
      * Builds the block map and conservative CFG and numbers blocks.
      */
@@ -533,9 +527,7 @@
                 case DRETURN: // fall through
                 case ARETURN: // fall through
                 case RETURN: {
-                    returnCount++;
                     current = null;
-                    returnBci = bci;
                     break;
                 }
                 case ATHROW: {
@@ -832,7 +824,7 @@
 
         // Purge null entries for unreached blocks and sort blocks such that loop bodies are always
         // consecutively in the array.
-        int blockCount = maxBlocks - blocksNotYetAssignedId + 2;
+        int blockCount = maxBlocks - blocksNotYetAssignedId + 1;
         BciBlock[] newBlocks = new BciBlock[blockCount];
         int next = 0;
         for (int i = 0; i < blocks.length; ++i) {
@@ -845,13 +837,7 @@
                 }
             }
         }
-
-        // Add return block.
-        BciBlock returnBlock = new BciBlock();
-        returnBlock.startBci = returnBci;
-        returnBlock.endBci = returnBci;
-        returnBlock.setId(newBlocks.length - 2);
-        newBlocks[newBlocks.length - 2] = returnBlock;
+        assert next == newBlocks.length - 1;
 
         // Add unwind block.
         ExceptionDispatchBlock unwindBlock = new ExceptionDispatchBlock();
@@ -1066,10 +1052,6 @@
         return startBlock;
     }
 
-    public BciBlock getReturnBlock() {
-        return blocks[blocks.length - 2];
-    }
-
     public ExceptionDispatchBlock getUnwindBlock() {
         return (ExceptionDispatchBlock) blocks[blocks.length - 1];
     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java	Wed Apr 19 04:10:56 2017 +0000
@@ -251,6 +251,8 @@
 import static org.graalvm.compiler.java.BytecodeParserOptions.TraceInlineDuringParsing;
 import static org.graalvm.compiler.java.BytecodeParserOptions.TraceParserPlugins;
 import static org.graalvm.compiler.java.BytecodeParserOptions.UseGuardedIntrinsics;
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.FAST_PATH_PROBABILITY;
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.SLOW_PATH_PROBABILITY;
 import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_DURING_PARSING;
 import static org.graalvm.compiler.nodes.type.StampTool.isPointerNonNull;
 
@@ -399,6 +401,7 @@
 import org.graalvm.compiler.nodes.util.GraphUtil;
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.util.ValueMergeUtil;
 import org.graalvm.util.EconomicMap;
 import org.graalvm.util.Equivalence;
 
@@ -578,6 +581,16 @@
         }
     }
 
+    protected static class ReturnToCallerData {
+        protected final ValueNode returnValue;
+        protected final FixedWithNextNode beforeReturnNode;
+
+        protected ReturnToCallerData(ValueNode returnValue, FixedWithNextNode beforeReturnNode) {
+            this.returnValue = returnValue;
+            this.beforeReturnNode = beforeReturnNode;
+        }
+    }
+
     private final GraphBuilderPhase.Instance graphBuilderInstance;
     protected final StructuredGraph graph;
     protected final OptionValues options;
@@ -593,8 +606,7 @@
 
     private ValueNode methodSynchronizedObject;
 
-    private ValueNode returnValue;
-    private FixedWithNextNode beforeReturnNode;
+    private List<ReturnToCallerData> returnDataList;
     private ValueNode unwindValue;
     private FixedWithNextNode beforeUnwindNode;
 
@@ -641,14 +653,6 @@
         return graphBuilderInstance;
     }
 
-    public ValueNode getReturnValue() {
-        return returnValue;
-    }
-
-    public FixedWithNextNode getBeforeReturnNode() {
-        return this.beforeReturnNode;
-    }
-
     public ValueNode getUnwindValue() {
         return unwindValue;
     }
@@ -1114,15 +1118,15 @@
     }
 
     protected LogicNode genObjectEquals(ValueNode x, ValueNode y) {
-        return ObjectEqualsNode.create(x, y, constantReflection);
+        return ObjectEqualsNode.create(constantReflection, metaAccess, options, x, y);
     }
 
     protected LogicNode genIntegerEquals(ValueNode x, ValueNode y) {
-        return IntegerEqualsNode.create(x, y);
+        return IntegerEqualsNode.create(constantReflection, metaAccess, options, null, x, y);
     }
 
     protected LogicNode genIntegerLessThan(ValueNode x, ValueNode y) {
-        return IntegerLessThanNode.create(x, y);
+        return IntegerLessThanNode.create(constantReflection, metaAccess, options, null, x, y);
     }
 
     protected ValueNode genUnique(ValueNode x) {
@@ -1200,7 +1204,7 @@
         BytecodeExceptionNode exception = graph.add(new BytecodeExceptionNode(metaAccess, NullPointerException.class));
         AbstractBeginNode falseSucc = graph.add(new BeginNode());
         ValueNode nonNullReceiver = graph.addOrUnique(PiNode.create(receiver, objectNonNull(), falseSucc));
-        append(new IfNode(graph.addOrUniqueWithInputs(IsNullNode.create(receiver)), exception, falseSucc, 0.01));
+        append(new IfNode(graph.addOrUniqueWithInputs(IsNullNode.create(receiver)), exception, falseSucc, SLOW_PATH_PROBABILITY));
         lastInstr = falseSucc;
 
         exception.setStateAfter(createFrameState(bci(), exception));
@@ -1212,7 +1216,7 @@
     protected void emitExplicitBoundsCheck(ValueNode index, ValueNode length) {
         AbstractBeginNode trueSucc = graph.add(new BeginNode());
         BytecodeExceptionNode exception = graph.add(new BytecodeExceptionNode(metaAccess, ArrayIndexOutOfBoundsException.class, index));
-        append(new IfNode(genUnique(IntegerBelowNode.create(index, length)), trueSucc, exception, 0.99));
+        append(new IfNode(genUnique(IntegerBelowNode.create(constantReflection, metaAccess, options, null, index, length)), trueSucc, exception, FAST_PATH_PROBABILITY));
         lastInstr = trueSucc;
 
         exception.setStateAfter(createFrameState(bci(), exception));
@@ -1608,7 +1612,7 @@
             LoadHubNode hub = graph.unique(new LoadHubNode(stampProvider, nonNullReceiver));
             LoadMethodNode actual = append(new LoadMethodNode(methodStamp, targetMethod, receiverType, method.getDeclaringClass(), hub));
             ConstantNode expected = graph.unique(ConstantNode.forConstant(methodStamp, targetMethod.getEncoding(), getMetaAccess()));
-            LogicNode compare = graph.addOrUniqueWithInputs(CompareNode.createCompareNode(Condition.EQ, actual, expected, constantReflection));
+            LogicNode compare = graph.addOrUniqueWithInputs(CompareNode.createCompareNode(constantReflection, metaAccess, options, null, Condition.EQ, actual, expected));
 
             JavaTypeProfile profile = null;
             if (profilingInfo != null && this.optimisticOpts.useTypeCheckHints(getOptions())) {
@@ -1632,7 +1636,7 @@
 
             AbstractBeginNode intrinsicBranch = graph.add(new BeginNode());
             AbstractBeginNode nonIntrinsicBranch = graph.add(new BeginNode());
-            append(new IfNode(compare, intrinsicBranch, nonIntrinsicBranch, 0.01));
+            append(new IfNode(compare, intrinsicBranch, nonIntrinsicBranch, FAST_PATH_PROBABILITY));
             lastInstr = intrinsicBranch;
             return new IntrinsicGuard(currentLastInstr, intrinsicReceiver, mark, nonIntrinsicBranch, profile);
         } else {
@@ -1959,13 +1963,30 @@
             startFrameState.initializeFromArgumentsArray(args);
             parser.build(this.lastInstr, startFrameState);
 
-            FixedWithNextNode calleeBeforeReturnNode = parser.getBeforeReturnNode();
-            this.lastInstr = calleeBeforeReturnNode;
-            JavaKind calleeReturnKind = targetMethod.getSignature().getReturnKind();
-            if (calleeBeforeReturnNode != null) {
-                ValueNode calleeReturnValue = parser.getReturnValue();
+            if (parser.returnDataList == null) {
+                /* Callee does not return. */
+                lastInstr = null;
+            } else {
+                ValueNode calleeReturnValue;
+                MergeNode returnMergeNode = null;
+                if (parser.returnDataList.size() == 1) {
+                    /* Callee has a single return, we can continue parsing at that point. */
+                    ReturnToCallerData singleReturnData = parser.returnDataList.get(0);
+                    lastInstr = singleReturnData.beforeReturnNode;
+                    calleeReturnValue = singleReturnData.returnValue;
+                } else {
+                    assert parser.returnDataList.size() > 1;
+                    /* Callee has multiple returns, we need to insert a control flow merge. */
+                    returnMergeNode = graph.add(new MergeNode());
+                    calleeReturnValue = ValueMergeUtil.mergeValueProducers(returnMergeNode, parser.returnDataList, returnData -> returnData.beforeReturnNode, returnData -> returnData.returnValue);
+                }
+
                 if (calleeReturnValue != null) {
-                    frameState.push(calleeReturnKind.getStackKind(), calleeReturnValue);
+                    frameState.push(targetMethod.getSignature().getReturnKind().getStackKind(), calleeReturnValue);
+                }
+                if (returnMergeNode != null) {
+                    returnMergeNode.setStateAfter(createFrameState(stream.nextBCI(), returnMergeNode));
+                    lastInstr = finishInstruction(returnMergeNode, frameState);
                 }
             }
 
@@ -2028,27 +2049,18 @@
                 }
             }
         }
+
+        frameState.setRethrowException(false);
+        frameState.clearStack();
+        beforeReturn(returnVal, returnKind);
         if (parent == null) {
-            frameState.setRethrowException(false);
-            frameState.clearStack();
-            beforeReturn(returnVal, returnKind);
             append(new ReturnNode(returnVal));
         } else {
-            if (blockMap.getReturnCount() == 1 || !controlFlowSplit) {
-                // There is only a single return.
-                beforeReturn(returnVal, returnKind);
-                this.returnValue = returnVal;
-                this.beforeReturnNode = this.lastInstr;
-                this.lastInstr = null;
-            } else {
-                frameState.setRethrowException(false);
-                frameState.clearStack();
-                if (returnVal != null) {
-                    frameState.push(returnKind, returnVal);
-                }
-                assert blockMap.getReturnCount() > 1;
-                appendGoto(blockMap.getReturnBlock());
+            if (returnDataList == null) {
+                returnDataList = new ArrayList<>();
             }
+            returnDataList.add(new ReturnToCallerData(returnVal, lastInstr));
+            lastInstr = null;
         }
     }
 
@@ -2122,7 +2134,7 @@
         JsrScope scope = currentBlock.getJsrScope();
         int retAddress = scope.nextReturnAddress();
         ConstantNode returnBciNode = getJsrConstant(retAddress);
-        LogicNode guard = IntegerEqualsNode.create(local, returnBciNode);
+        LogicNode guard = IntegerEqualsNode.create(constantReflection, metaAccess, options, null, local, returnBciNode);
         guard = graph.addOrUniqueWithInputs(guard);
         append(new FixedGuardNode(guard, JavaSubroutineMismatch, InvalidateReprofile));
         if (!successor.getJsrScope().equals(scope.pop())) {
@@ -2182,18 +2194,6 @@
         if (v.graph() != null) {
             return v;
         }
-        T added = graph.addOrUnique(v);
-        if (added == v) {
-            updateLastInstruction(v);
-        }
-        return added;
-    }
-
-    @Override
-    public <T extends ValueNode> T recursiveAppend(T v) {
-        if (v.graph() != null) {
-            return v;
-        }
         T added = graph.addOrUniqueWithInputs(v);
         if (added == v) {
             updateLastInstruction(v);
@@ -2429,9 +2429,7 @@
                 setMergeStateAfter(block, firstInstruction);
             }
 
-            if (block == blockMap.getReturnBlock()) {
-                handleReturnBlock();
-            } else if (block == blockMap.getUnwindBlock()) {
+            if (block == blockMap.getUnwindBlock()) {
                 handleUnwindBlock((ExceptionDispatchBlock) block);
             } else if (block instanceof ExceptionDispatchBlock) {
                 createExceptionDispatch((ExceptionDispatchBlock) block);
@@ -2454,15 +2452,6 @@
         }
     }
 
-    private void handleReturnBlock() {
-        JavaKind returnKind = method.getSignature().getReturnKind().getStackKind();
-        ValueNode x = returnKind == JavaKind.Void ? null : frameState.pop(returnKind);
-        assert frameState.stackSize() == 0;
-        beforeReturn(x, returnKind);
-        this.returnValue = x;
-        this.beforeReturnNode = this.lastInstr;
-    }
-
     private void setMergeStateAfter(BciBlock block, FixedWithNextNode firstInstruction) {
         AbstractMergeNode abstractMergeNode = (AbstractMergeNode) firstInstruction;
         if (abstractMergeNode.stateAfter() == null) {
@@ -3144,7 +3133,7 @@
             default:
                 throw shouldNotReachHere();
         }
-        frameState.push(kind, recursiveAppend(v));
+        frameState.push(kind, append(v));
     }
 
     private void genIntegerDivOp(JavaKind kind, int opcode) {
@@ -3191,7 +3180,7 @@
             default:
                 throw shouldNotReachHere();
         }
-        frameState.push(kind, recursiveAppend(v));
+        frameState.push(kind, append(v));
     }
 
     private void genLogicOp(JavaKind kind, int opcode) {
@@ -3214,7 +3203,7 @@
             default:
                 throw shouldNotReachHere();
         }
-        frameState.push(kind, recursiveAppend(v));
+        frameState.push(kind, append(v));
     }
 
     private void genCompareOp(JavaKind kind, boolean isUnorderedLess) {
@@ -3233,7 +3222,7 @@
         if (from != from.getStackKind()) {
             input = append(genNarrow(input, from.getBitCount()));
         }
-        frameState.push(to, recursiveAppend(genSignExtend(input, to.getBitCount())));
+        frameState.push(to, append(genSignExtend(input, to.getBitCount())));
     }
 
     private void genZeroExtend(JavaKind from, JavaKind to) {
@@ -3254,7 +3243,7 @@
         int delta = getStream().readIncrement();
         ValueNode x = frameState.loadLocal(index, JavaKind.Int);
         ValueNode y = appendConstant(JavaConstant.forInt(delta));
-        frameState.storeLocal(index, JavaKind.Int, recursiveAppend(genIntegerAdd(x, y)));
+        frameState.storeLocal(index, JavaKind.Int, append(genIntegerAdd(x, y)));
     }
 
     private void genIfZero(Condition cond) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/RedundantMoveElimination.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/RedundantMoveElimination.java	Wed Apr 19 04:10:56 2017 +0000
@@ -376,7 +376,7 @@
         @SuppressWarnings("try")
         private int updateState(final int[] state, LIRInstruction op, int initValueNum) {
 
-            try (final Indent indent = Debug.logAndIndent("update state for op %s, initial value num = %d", op, initValueNum)) {
+            try (Indent indent = Debug.logAndIndent("update state for op %s, initial value num = %d", op, initValueNum)) {
                 if (isEligibleMove(op)) {
                     /*
                      * Handle the special case of a move instruction
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScan.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScan.java	Wed Apr 19 04:10:56 2017 +0000
@@ -750,11 +750,7 @@
                 }
             }
         }
-        Debug.dump(Debug.BASIC_LEVEL, new LinearScanIntervalDumper(Arrays.copyOf(intervals, intervalsSize)), label);
-    }
-
-    public void printLir(String label, @SuppressWarnings("unused") boolean hirValid) {
-        Debug.dump(Debug.INFO_LEVEL, ir, label);
+        Debug.dump(Debug.VERBOSE_LEVEL, new LinearScanIntervalDumper(Arrays.copyOf(intervals, intervalsSize)), label);
     }
 
     boolean verify() {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanAllocationPhase.java	Wed Apr 19 04:10:56 2017 +0000
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2017, 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 org.graalvm.compiler.lir.alloc.lsra;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import static org.graalvm.compiler.lir.phases.AllocationPhase.AllocationContext;
+import org.graalvm.compiler.lir.phases.LIRPhase;
+
+import jdk.vm.ci.code.TargetDescription;
+
+abstract class LinearScanAllocationPhase {
+
+    final CharSequence getName() {
+        return LIRPhase.createName(getClass());
+    }
+
+    @Override
+    public final String toString() {
+        return getName().toString();
+    }
+
+    public final void apply(TargetDescription target, LIRGenerationResult lirGenRes, AllocationContext context) {
+        apply(target, lirGenRes, context, true);
+    }
+
+    @SuppressWarnings("try")
+    public final void apply(TargetDescription target, LIRGenerationResult lirGenRes, AllocationContext context, boolean dumpLIR) {
+        try (Scope s = Debug.scope(getName(), this)) {
+            run(target, lirGenRes, context);
+            if (dumpLIR && Debug.isDumpEnabled(Debug.VERBOSE_LEVEL)) {
+                Debug.dump(Debug.VERBOSE_LEVEL, lirGenRes.getLIR(), "After %s", getName());
+            }
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+
+    protected abstract void run(TargetDescription target, LIRGenerationResult lirGenRes, AllocationContext context);
+
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanAssignLocationsPhase.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanAssignLocationsPhase.java	Wed Apr 19 04:10:56 2017 +0000
@@ -46,7 +46,7 @@
 import org.graalvm.compiler.lir.StandardOp.ValueMoveOp;
 import org.graalvm.compiler.lir.Variable;
 import org.graalvm.compiler.lir.gen.LIRGenerationResult;
-import org.graalvm.compiler.lir.phases.AllocationPhase;
+import org.graalvm.compiler.lir.phases.AllocationPhase.AllocationContext;
 
 import jdk.vm.ci.code.TargetDescription;
 import jdk.vm.ci.meta.AllocatableValue;
@@ -55,7 +55,7 @@
 /**
  * Phase 7: Assign register numbers back to LIR.
  */
-public class LinearScanAssignLocationsPhase extends AllocationPhase {
+public class LinearScanAssignLocationsPhase extends LinearScanAllocationPhase {
 
     protected final LinearScan allocator;
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanEliminateSpillMovePhase.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanEliminateSpillMovePhase.java	Wed Apr 19 04:10:56 2017 +0000
@@ -41,7 +41,7 @@
 import org.graalvm.compiler.lir.alloc.lsra.Interval.SpillState;
 import org.graalvm.compiler.lir.alloc.lsra.LinearScan.IntervalPredicate;
 import org.graalvm.compiler.lir.gen.LIRGenerationResult;
-import org.graalvm.compiler.lir.phases.AllocationPhase;
+import org.graalvm.compiler.lir.phases.AllocationPhase.AllocationContext;
 import org.graalvm.compiler.options.NestedBooleanOptionKey;
 import org.graalvm.compiler.options.Option;
 import org.graalvm.compiler.options.OptionKey;
@@ -50,7 +50,7 @@
 import jdk.vm.ci.code.TargetDescription;
 import jdk.vm.ci.meta.AllocatableValue;
 
-public class LinearScanEliminateSpillMovePhase extends AllocationPhase {
+public class LinearScanEliminateSpillMovePhase extends LinearScanAllocationPhase {
 
     public static class Options {
         // @formatter:off
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanLifetimeAnalysisPhase.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanLifetimeAnalysisPhase.java	Wed Apr 19 04:10:56 2017 +0000
@@ -36,8 +36,8 @@
 import java.util.BitSet;
 import java.util.EnumSet;
 
+import org.graalvm.compiler.core.common.LIRKind;
 import org.graalvm.compiler.core.common.PermanentBailoutException;
-import org.graalvm.compiler.core.common.LIRKind;
 import org.graalvm.compiler.core.common.alloc.ComputeBlockOrder;
 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
 import org.graalvm.compiler.core.common.util.BitMap2D;
@@ -56,7 +56,7 @@
 import org.graalvm.compiler.lir.alloc.lsra.Interval.SpillState;
 import org.graalvm.compiler.lir.alloc.lsra.LinearScan.BlockData;
 import org.graalvm.compiler.lir.gen.LIRGenerationResult;
-import org.graalvm.compiler.lir.phases.AllocationPhase;
+import org.graalvm.compiler.lir.phases.AllocationPhase.AllocationContext;
 import org.graalvm.util.EconomicSet;
 import org.graalvm.util.Equivalence;
 
@@ -70,7 +70,7 @@
 import jdk.vm.ci.meta.Value;
 import jdk.vm.ci.meta.ValueKind;
 
-public class LinearScanLifetimeAnalysisPhase extends AllocationPhase {
+public class LinearScanLifetimeAnalysisPhase extends LinearScanAllocationPhase {
 
     protected final LinearScan allocator;
 
@@ -84,7 +84,7 @@
     @Override
     protected void run(TargetDescription target, LIRGenerationResult lirGenRes, AllocationContext context) {
         numberInstructions();
-        allocator.printLir("Before register allocation", true);
+        Debug.dump(Debug.VERBOSE_LEVEL, lirGenRes.getLIR(), "Before register allocation");
         computeLocalLiveSets();
         computeGlobalLiveSets();
         buildIntervals(DetailedAsserts.getValue(allocator.getOptions()));
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanOptimizeSpillPositionPhase.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanOptimizeSpillPositionPhase.java	Wed Apr 19 04:10:56 2017 +0000
@@ -27,6 +27,7 @@
 import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue;
 
 import java.util.Iterator;
+
 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
 import org.graalvm.compiler.debug.Debug;
 import org.graalvm.compiler.debug.DebugCounter;
@@ -36,12 +37,12 @@
 import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
 import org.graalvm.compiler.lir.alloc.lsra.Interval.SpillState;
 import org.graalvm.compiler.lir.gen.LIRGenerationResult;
-import org.graalvm.compiler.lir.phases.AllocationPhase;
+import org.graalvm.compiler.lir.phases.AllocationPhase.AllocationContext;
 
 import jdk.vm.ci.code.TargetDescription;
 import jdk.vm.ci.meta.AllocatableValue;
 
-public final class LinearScanOptimizeSpillPositionPhase extends AllocationPhase {
+public final class LinearScanOptimizeSpillPositionPhase extends LinearScanAllocationPhase {
 
     private static final DebugCounter betterSpillPos = Debug.counter("BetterSpillPosition");
     private static final DebugCounter betterSpillPosWithLowerProbability = Debug.counter("BetterSpillPositionWithLowerProbability");
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanRegisterAllocationPhase.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanRegisterAllocationPhase.java	Wed Apr 19 04:10:56 2017 +0000
@@ -25,12 +25,12 @@
 import org.graalvm.compiler.debug.Debug;
 import org.graalvm.compiler.debug.Indent;
 import org.graalvm.compiler.lir.gen.LIRGenerationResult;
-import org.graalvm.compiler.lir.phases.AllocationPhase;
+import org.graalvm.compiler.lir.phases.AllocationPhase.AllocationContext;
 import org.graalvm.util.Pair;
 
 import jdk.vm.ci.code.TargetDescription;
 
-public final class LinearScanRegisterAllocationPhase extends AllocationPhase {
+public final class LinearScanRegisterAllocationPhase extends LinearScanAllocationPhase {
 
     private final LinearScan allocator;
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanResolveDataFlowPhase.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanResolveDataFlowPhase.java	Wed Apr 19 04:10:56 2017 +0000
@@ -31,7 +31,7 @@
 import org.graalvm.compiler.lir.LIRInstruction;
 import org.graalvm.compiler.lir.StandardOp;
 import org.graalvm.compiler.lir.gen.LIRGenerationResult;
-import org.graalvm.compiler.lir.phases.AllocationPhase;
+import org.graalvm.compiler.lir.phases.AllocationPhase.AllocationContext;
 
 import jdk.vm.ci.code.TargetDescription;
 
@@ -40,7 +40,7 @@
  *
  * Insert moves at edges between blocks if intervals have been split.
  */
-public class LinearScanResolveDataFlowPhase extends AllocationPhase {
+public class LinearScanResolveDataFlowPhase extends LinearScanAllocationPhase {
 
     protected final LinearScan allocator;
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceAllocationPhase.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceAllocationPhase.java	Wed Apr 19 04:10:56 2017 +0000
@@ -112,13 +112,13 @@
     public final void apply(TargetDescription target, LIRGenerationResult lirGenRes, Trace trace, C context, boolean dumpTrace) {
         try (Scope s = Debug.scope(getName(), this)) {
             try (DebugCloseable a = timer.start(); DebugCloseable c = memUseTracker.start()) {
-                if (dumpTrace && Debug.isDumpEnabled(TraceBuilderPhase.TRACE_DUMP_LEVEL + 1)) {
-                    Debug.dump(TraceBuilderPhase.TRACE_DUMP_LEVEL + 1, trace, "%s before (Trace%s: %s)", getName(), trace.getId(), trace);
+                if (dumpTrace && Debug.isDumpEnabled(Debug.DETAILED_LEVEL)) {
+                    Debug.dump(Debug.DETAILED_LEVEL, trace, "Before %s (Trace%s: %s)", getName(), trace.getId(), trace);
                 }
                 run(target, lirGenRes, trace, context);
                 allocatedTraces.increment();
-                if (dumpTrace && Debug.isDumpEnabled(TraceBuilderPhase.TRACE_DUMP_LEVEL)) {
-                    Debug.dump(TraceBuilderPhase.TRACE_DUMP_LEVEL, trace, "%s (Trace%s: %s)", getName(), trace.getId(), trace);
+                if (dumpTrace && Debug.isDumpEnabled(Debug.VERBOSE_LEVEL)) {
+                    Debug.dump(Debug.VERBOSE_LEVEL, trace, "After %s (Trace%s: %s)", getName(), trace.getId(), trace);
                 }
             }
         } catch (Throwable e) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceBuilderPhase.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceBuilderPhase.java	Wed Apr 19 04:10:56 2017 +0000
@@ -64,9 +64,6 @@
         // @formatter:on
     }
 
-    private static final int TRACE_LOG_LEVEL = Debug.BASIC_LEVEL;
-    public static final int TRACE_DUMP_LEVEL = Debug.VERBOSE_LEVEL;
-
     @Override
     protected void run(TargetDescription target, LIRGenerationResult lirGenRes, AllocationContext context) {
         AbstractBlockBase<?>[] linearScanOrder = lirGenRes.getLIR().linearScanOrder();
@@ -76,15 +73,15 @@
 
         final TraceBuilderResult traceBuilderResult = getTraceBuilderResult(lir, startBlock, linearScanOrder);
 
-        if (Debug.isLogEnabled(TRACE_LOG_LEVEL)) {
+        if (Debug.isLogEnabled(Debug.BASIC_LEVEL)) {
             ArrayList<Trace> traces = traceBuilderResult.getTraces();
             for (int i = 0; i < traces.size(); i++) {
                 Trace trace = traces.get(i);
-                Debug.log(TRACE_LOG_LEVEL, "Trace %5d: %s%s", i, trace, isTrivialTrace(lirGenRes.getLIR(), trace) ? " (trivial)" : "");
+                Debug.log(Debug.BASIC_LEVEL, "Trace %5d: %s%s", i, trace, isTrivialTrace(lirGenRes.getLIR(), trace) ? " (trivial)" : "");
             }
         }
         TraceStatisticsPrinter.printTraceStatistics(traceBuilderResult, lirGenRes.getCompilationUnitName());
-        Debug.dump(TRACE_DUMP_LEVEL, traceBuilderResult, "After TraceBuilding");
+        Debug.dump(Debug.VERBOSE_LEVEL, traceBuilderResult, "TraceBuilderResult");
         context.contextAdd(traceBuilderResult);
     }
 
@@ -93,7 +90,7 @@
 
         OptionValues options = lir.getOptions();
         TraceBuilder selectedTraceBuilder = Options.TraceBuilding.getValue(options);
-        Debug.log(TRACE_LOG_LEVEL, "Building Traces using %s", selectedTraceBuilder);
+        Debug.log(Debug.BASIC_LEVEL, "Building Traces using %s", selectedTraceBuilder);
         switch (Options.TraceBuilding.getValue(options)) {
             case SingleBlock:
                 return SingleBlockTraceBuilder.computeTraces(startBlock, linearScanOrder, pred);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceGlobalMoveResolutionPhase.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceGlobalMoveResolutionPhase.java	Wed Apr 19 04:10:56 2017 +0000
@@ -45,7 +45,6 @@
 import org.graalvm.compiler.lir.alloc.trace.TraceAllocationPhase.TraceAllocationContext;
 import org.graalvm.compiler.lir.gen.LIRGenerationResult;
 import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory;
-import org.graalvm.compiler.lir.phases.LIRPhase;
 import org.graalvm.compiler.lir.ssa.SSAUtil;
 
 import jdk.vm.ci.code.Architecture;
@@ -54,7 +53,10 @@
 import jdk.vm.ci.meta.AllocatableValue;
 import jdk.vm.ci.meta.Value;
 
-public final class TraceGlobalMoveResolutionPhase extends LIRPhase<TraceAllocationPhase.TraceAllocationContext> {
+public final class TraceGlobalMoveResolutionPhase {
+
+    private TraceGlobalMoveResolutionPhase() {
+    }
 
     /**
      * Abstract move resolver interface for testing.
@@ -63,8 +65,8 @@
         public abstract void addMapping(Value src, AllocatableValue dst, Value fromStack);
     }
 
-    @Override
-    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, TraceAllocationContext context) {
+    public static void resolve(TargetDescription target, LIRGenerationResult lirGenRes, TraceAllocationContext context) {
+        Debug.dump(Debug.VERBOSE_LEVEL, lirGenRes.getLIR(), "Before TraceGlobalMoveResultion");
         MoveFactory spillMoveFactory = context.spillMoveFactory;
         resolveGlobalDataFlow(context.resultTraces, lirGenRes, spillMoveFactory, target.arch, context.livenessInfo);
     }
@@ -191,4 +193,5 @@
             moveResolver.addMapping(from, to, fromStack);
         }
     }
+
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceRegisterAllocationPhase.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceRegisterAllocationPhase.java	Wed Apr 19 04:10:56 2017 +0000
@@ -31,7 +31,6 @@
 import org.graalvm.compiler.debug.DebugCounter;
 import org.graalvm.compiler.debug.Indent;
 import org.graalvm.compiler.lir.LIR;
-import org.graalvm.compiler.lir.LIRInstruction;
 import org.graalvm.compiler.lir.alloc.trace.TraceAllocationPhase.TraceAllocationContext;
 import org.graalvm.compiler.lir.gen.LIRGenerationResult;
 import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory;
@@ -64,8 +63,6 @@
         // @formatter:on
     }
 
-    private static final TraceGlobalMoveResolutionPhase TRACE_GLOBAL_MOVE_RESOLUTION_PHASE = new TraceGlobalMoveResolutionPhase();
-
     private static final DebugCounter tracesCounter = Debug.counter("TraceRA[traces]");
 
     public static final DebugCounter globalStackSlots = Debug.counter("TraceRA[GlobalStackSlots]");
@@ -89,7 +86,6 @@
         final TraceRegisterAllocationPolicy plan = DefaultTraceRegisterAllocationPolicy.allocationPolicy(target, lirGenRes, spillMoveFactory, registerAllocationConfig, cachedStackSlots, resultTraces,
                         neverSpillConstant, livenessInfo, lir.getOptions());
 
-        Debug.dump(Debug.INFO_LEVEL, lir, "Before TraceRegisterAllocation");
         try (Scope s0 = Debug.scope("AllocateTraces", resultTraces, livenessInfo)) {
             for (Trace trace : resultTraces.getTraces()) {
                 tracesCounter.increment();
@@ -101,12 +97,8 @@
         } catch (Throwable e) {
             throw Debug.handle(e);
         }
-        if (Debug.isDumpEnabled(Debug.INFO_LEVEL)) {
-            unnumberInstructions(lir);
-            Debug.dump(Debug.INFO_LEVEL, lir, "After trace allocation");
-        }
 
-        TRACE_GLOBAL_MOVE_RESOLUTION_PHASE.apply(target, lirGenRes, traceContext);
+        TraceGlobalMoveResolutionPhase.resolve(target, lirGenRes, traceContext);
         deconstructSSAForm(lir);
     }
 
@@ -124,11 +116,4 @@
         }
     }
 
-    private static void unnumberInstructions(LIR lir) {
-        for (AbstractBlockBase<?> block : lir.getControlFlowGraph().getBlocks()) {
-            for (LIRInstruction op : lir.getLIRforBlock(block)) {
-                op.setId(-1);
-            }
-        }
-    }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanAllocationPhase.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanAllocationPhase.java	Wed Apr 19 04:10:56 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, 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
@@ -23,19 +23,41 @@
 package org.graalvm.compiler.lir.alloc.trace.lsra;
 
 import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
+import org.graalvm.compiler.core.common.alloc.Trace;
 import org.graalvm.compiler.core.common.alloc.TraceBuilderResult;
-import org.graalvm.compiler.lir.alloc.trace.TraceAllocationPhase;
+import org.graalvm.compiler.debug.Debug;
 import org.graalvm.compiler.lir.alloc.trace.lsra.TraceLinearScanPhase.TraceLinearScan;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
 import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory;
+import org.graalvm.compiler.lir.phases.LIRPhase;
+
+import jdk.vm.ci.code.TargetDescription;
 
-abstract class TraceLinearScanAllocationPhase extends TraceAllocationPhase<TraceLinearScanAllocationPhase.TraceLinearScanAllocationContext> {
+abstract class TraceLinearScanAllocationPhase {
+
+    final CharSequence getName() {
+        return LIRPhase.createName(getClass());
+    }
 
-    static final class TraceLinearScanAllocationContext extends TraceAllocationPhase.TraceAllocationContext {
-        public final TraceLinearScan allocator;
+    @Override
+    public final String toString() {
+        return getName().toString();
+    }
 
-        TraceLinearScanAllocationContext(MoveFactory spillMoveFactory, RegisterAllocationConfig registerAllocationConfig, TraceBuilderResult traceBuilderResult, TraceLinearScan allocator) {
-            super(spillMoveFactory, registerAllocationConfig, traceBuilderResult, allocator.getGlobalLivenessInfo());
-            this.allocator = allocator;
+    final void apply(TargetDescription target, LIRGenerationResult lirGenRes, Trace trace, MoveFactory spillMoveFactory, RegisterAllocationConfig registerAllocationConfig,
+                    TraceBuilderResult traceBuilderResult, TraceLinearScan allocator) {
+        apply(target, lirGenRes, trace, spillMoveFactory, registerAllocationConfig, traceBuilderResult, allocator, true);
+    }
+
+    final void apply(TargetDescription target, LIRGenerationResult lirGenRes, Trace trace, MoveFactory spillMoveFactory, RegisterAllocationConfig registerAllocationConfig,
+                    TraceBuilderResult traceBuilderResult, TraceLinearScan allocator, boolean dumpLIR) {
+        run(target, lirGenRes, trace, spillMoveFactory, registerAllocationConfig, traceBuilderResult, allocator);
+        if (dumpLIR && Debug.isDumpEnabled(Debug.DETAILED_LEVEL)) {
+            Debug.dump(Debug.DETAILED_LEVEL, trace, "After %s (Trace%s)", getName(), trace.getId());
         }
     }
+
+    abstract void run(TargetDescription target, LIRGenerationResult lirGenRes, Trace trace, MoveFactory spillMoveFactory, RegisterAllocationConfig registerAllocationConfig,
+                    TraceBuilderResult traceBuilderResult, TraceLinearScan allocator);
+
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanAssignLocationsPhase.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanAssignLocationsPhase.java	Wed Apr 19 04:10:56 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, 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
@@ -33,7 +33,9 @@
 import java.util.Collections;
 import java.util.EnumSet;
 
+import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
 import org.graalvm.compiler.core.common.alloc.Trace;
+import org.graalvm.compiler.core.common.alloc.TraceBuilderResult;
 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
 import org.graalvm.compiler.debug.Debug;
 import org.graalvm.compiler.debug.GraalError;
@@ -69,9 +71,8 @@
 final class TraceLinearScanAssignLocationsPhase extends TraceLinearScanAllocationPhase {
 
     @Override
-    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, Trace trace, TraceLinearScanAllocationContext context) {
-        TraceLinearScan allocator = context.allocator;
-        MoveFactory spillMoveFactory = context.spillMoveFactory;
+    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, Trace trace, MoveFactory spillMoveFactory, RegisterAllocationConfig registerAllocationConfig,
+                    TraceBuilderResult traceBuilderResult, TraceLinearScan allocator) {
         new Assigner(allocator, spillMoveFactory).assign();
     }
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanEliminateSpillMovePhase.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanEliminateSpillMovePhase.java	Wed Apr 19 04:10:56 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, 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
@@ -29,6 +29,7 @@
 
 import java.util.ArrayList;
 
+import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
 import org.graalvm.compiler.core.common.alloc.Trace;
 import org.graalvm.compiler.core.common.alloc.TraceBuilderResult;
 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
@@ -44,6 +45,7 @@
 import org.graalvm.compiler.lir.alloc.trace.lsra.TraceLinearScanPhase.IntervalPredicate;
 import org.graalvm.compiler.lir.alloc.trace.lsra.TraceLinearScanPhase.TraceLinearScan;
 import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory;
 
 import jdk.vm.ci.code.TargetDescription;
 import jdk.vm.ci.meta.AllocatableValue;
@@ -59,9 +61,8 @@
     };
 
     @Override
-    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, Trace trace, TraceLinearScanAllocationContext context) {
-        TraceBuilderResult traceBuilderResult = context.resultTraces;
-        TraceLinearScan allocator = context.allocator;
+    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, Trace trace, MoveFactory spillMoveFactory, RegisterAllocationConfig registerAllocationConfig,
+                    TraceBuilderResult traceBuilderResult, TraceLinearScan allocator) {
         boolean shouldEliminateSpillMoves = shouldEliminateSpillMoves(traceBuilderResult, allocator);
         eliminateSpillMoves(allocator, shouldEliminateSpillMoves, traceBuilderResult);
     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanLifetimeAnalysisPhase.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanLifetimeAnalysisPhase.java	Wed Apr 19 04:10:56 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, 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
@@ -39,6 +39,7 @@
 import java.util.EnumSet;
 
 import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
 import org.graalvm.compiler.core.common.alloc.Trace;
 import org.graalvm.compiler.core.common.alloc.TraceBuilderResult;
 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
@@ -78,14 +79,12 @@
 public final class TraceLinearScanLifetimeAnalysisPhase extends TraceLinearScanAllocationPhase {
 
     @Override
-    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, Trace trace, TraceLinearScanAllocationContext context) {
-        TraceBuilderResult traceBuilderResult = context.resultTraces;
-        TraceLinearScan allocator = context.allocator;
+    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, Trace trace, MoveFactory spillMoveFactory, RegisterAllocationConfig registerAllocationConfig,
+                    TraceBuilderResult traceBuilderResult, TraceLinearScan allocator) {
         new Analyser(allocator, traceBuilderResult).analyze();
     }
 
     public static final class Analyser {
-        private static final int DUMP_DURING_ANALYSIS_LEVEL = 4;
         private final TraceLinearScan allocator;
         private final TraceBuilderResult traceBuilderResult;
         private int numInstructions;
@@ -534,7 +533,7 @@
                         AbstractBlockBase<?> pred = blockId == 0 ? null : blocks[blockId - 1];
                         handleBlockBegin(block, pred);
                     }
-                    if (Debug.isDumpEnabled(DUMP_DURING_ANALYSIS_LEVEL)) {
+                    if (Debug.isDumpEnabled(Debug.VERY_DETAILED_LEVEL)) {
                         allocator.printIntervals("After Block " + block);
                     }
                 }   // end of block iteration
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanPhase.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanPhase.java	Wed Apr 19 04:10:56 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2017, 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
@@ -56,11 +56,9 @@
 import org.graalvm.compiler.lir.alloc.trace.GlobalLivenessInfo;
 import org.graalvm.compiler.lir.alloc.trace.TraceAllocationPhase;
 import org.graalvm.compiler.lir.alloc.trace.TraceAllocationPhase.TraceAllocationContext;
-import org.graalvm.compiler.lir.alloc.trace.TraceBuilderPhase;
 import org.graalvm.compiler.lir.alloc.trace.TraceRegisterAllocationPhase;
 import org.graalvm.compiler.lir.alloc.trace.TraceUtil;
 import org.graalvm.compiler.lir.alloc.trace.lsra.TraceInterval.RegisterPriority;
-import org.graalvm.compiler.lir.alloc.trace.lsra.TraceLinearScanAllocationPhase.TraceLinearScanAllocationContext;
 import org.graalvm.compiler.lir.debug.IntervalDumper;
 import org.graalvm.compiler.lir.debug.IntervalDumper.IntervalVisitor;
 import org.graalvm.compiler.lir.framemap.FrameMapBuilder;
@@ -588,37 +586,35 @@
 
         @SuppressWarnings("try")
         protected void allocate(TargetDescription target, LIRGenerationResult lirGenRes, TraceAllocationContext traceContext) {
+            MoveFactory spillMoveFactory = traceContext.spillMoveFactory;
+            RegisterAllocationConfig registerAllocationConfig = traceContext.registerAllocationConfig;
             /*
              * This is the point to enable debug logging for the whole register allocation.
              */
             try (Indent indent = Debug.logAndIndent("LinearScan allocate")) {
-                TraceLinearScanAllocationContext context = new TraceLinearScanAllocationContext(traceContext.spillMoveFactory, traceContext.registerAllocationConfig, traceBuilderResult, this);
-
-                TRACE_LINEAR_SCAN_LIFETIME_ANALYSIS_PHASE.apply(target, lirGenRes, trace, context, false);
+                TRACE_LINEAR_SCAN_LIFETIME_ANALYSIS_PHASE.apply(target, lirGenRes, trace, spillMoveFactory, registerAllocationConfig, traceBuilderResult, this, false);
 
                 try (Scope s = Debug.scope("AfterLifetimeAnalysis", this)) {
 
-                    printLir("Before register allocation", true);
+                    printLir("After instruction numbering");
                     printIntervals("Before register allocation");
 
                     sortIntervalsBeforeAllocation();
                     sortFixedIntervalsBeforeAllocation();
 
-                    TRACE_LINEAR_SCAN_REGISTER_ALLOCATION_PHASE.apply(target, lirGenRes, trace, context, false);
+                    TRACE_LINEAR_SCAN_REGISTER_ALLOCATION_PHASE.apply(target, lirGenRes, trace, spillMoveFactory, registerAllocationConfig, traceBuilderResult, this, false);
                     printIntervals("After register allocation");
 
                     // resolve intra-trace data-flow
-                    TRACE_LINEAR_SCAN_RESOLVE_DATA_FLOW_PHASE.apply(target, lirGenRes, trace, context, false);
-                    Debug.dump(TraceBuilderPhase.TRACE_DUMP_LEVEL, sortedBlocks(), "%s", TRACE_LINEAR_SCAN_RESOLVE_DATA_FLOW_PHASE.getName());
+                    TRACE_LINEAR_SCAN_RESOLVE_DATA_FLOW_PHASE.apply(target, lirGenRes, trace, spillMoveFactory, registerAllocationConfig, traceBuilderResult, this);
 
                     // eliminate spill moves
                     OptionValues options = getOptions();
                     if (Options.LIROptTraceRAEliminateSpillMoves.getValue(options)) {
-                        TRACE_LINEAR_SCAN_ELIMINATE_SPILL_MOVE_PHASE.apply(target, lirGenRes, trace, context, false);
-                        Debug.dump(TraceBuilderPhase.TRACE_DUMP_LEVEL, sortedBlocks(), "%s", TRACE_LINEAR_SCAN_ELIMINATE_SPILL_MOVE_PHASE.getName());
+                        TRACE_LINEAR_SCAN_ELIMINATE_SPILL_MOVE_PHASE.apply(target, lirGenRes, trace, spillMoveFactory, registerAllocationConfig, traceBuilderResult, this);
                     }
 
-                    TRACE_LINEAR_SCAN_ASSIGN_LOCATIONS_PHASE.apply(target, lirGenRes, trace, context, false);
+                    TRACE_LINEAR_SCAN_ASSIGN_LOCATIONS_PHASE.apply(target, lirGenRes, trace, spillMoveFactory, registerAllocationConfig, traceBuilderResult, this, false);
 
                     if (DetailedAsserts.getValue(options)) {
                         verifyIntervals();
@@ -629,9 +625,9 @@
             }
         }
 
-        public void printLir(String label, @SuppressWarnings("unused") boolean hirValid) {
-            if (Debug.isDumpEnabled(TraceBuilderPhase.TRACE_DUMP_LEVEL)) {
-                Debug.dump(TraceBuilderPhase.TRACE_DUMP_LEVEL, sortedBlocks(), label);
+        public void printLir(String label) {
+            if (Debug.isDumpEnabled(Debug.DETAILED_LEVEL)) {
+                Debug.dump(Debug.DETAILED_LEVEL, sortedBlocks(), "%s (Trace%d)", label, trace.getId());
             }
         }
 
@@ -1051,7 +1047,7 @@
 
         @SuppressWarnings("try")
         public void printIntervals(String label) {
-            if (Debug.isDumpEnabled(TraceBuilderPhase.TRACE_DUMP_LEVEL)) {
+            if (Debug.isDumpEnabled(Debug.DETAILED_LEVEL)) {
                 if (Debug.isLogEnabled()) {
                     try (Indent indent = Debug.logAndIndent("intervals %s", label)) {
                         for (FixedInterval interval : fixedIntervals) {
@@ -1073,7 +1069,7 @@
                         }
                     }
                 }
-                Debug.dump(Debug.INFO_LEVEL, this, label);
+                Debug.dump(Debug.DETAILED_LEVEL, this, "%s (Trace%d)", label, trace.getId());
             }
         }
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanRegisterAllocationPhase.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanRegisterAllocationPhase.java	Wed Apr 19 04:10:56 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, 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
@@ -22,19 +22,22 @@
  */
 package org.graalvm.compiler.lir.alloc.trace.lsra;
 
+import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
 import org.graalvm.compiler.core.common.alloc.Trace;
+import org.graalvm.compiler.core.common.alloc.TraceBuilderResult;
 import org.graalvm.compiler.debug.Debug;
 import org.graalvm.compiler.debug.Indent;
 import org.graalvm.compiler.lir.alloc.trace.lsra.TraceLinearScanPhase.TraceLinearScan;
 import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory;
 
 import jdk.vm.ci.code.TargetDescription;
 
 final class TraceLinearScanRegisterAllocationPhase extends TraceLinearScanAllocationPhase {
 
     @Override
-    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, Trace trace, TraceLinearScanAllocationContext context) {
-        TraceLinearScan allocator = context.allocator;
+    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, Trace trace, MoveFactory spillMoveFactory, RegisterAllocationConfig registerAllocationConfig,
+                    TraceBuilderResult traceBuilderResult, TraceLinearScan allocator) {
         allocateRegisters(allocator);
     }
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanResolveDataFlowPhase.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanResolveDataFlowPhase.java	Wed Apr 19 04:10:56 2017 +0000
@@ -31,6 +31,7 @@
 
 import java.util.ArrayList;
 
+import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
 import org.graalvm.compiler.core.common.alloc.Trace;
 import org.graalvm.compiler.core.common.alloc.TraceBuilderResult;
 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
@@ -45,6 +46,7 @@
 import org.graalvm.compiler.lir.alloc.trace.GlobalLivenessInfo;
 import org.graalvm.compiler.lir.alloc.trace.lsra.TraceLinearScanPhase.TraceLinearScan;
 import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory;
 import org.graalvm.compiler.lir.ssa.SSAUtil;
 
 import jdk.vm.ci.code.TargetDescription;
@@ -58,9 +60,8 @@
 final class TraceLinearScanResolveDataFlowPhase extends TraceLinearScanAllocationPhase {
 
     @Override
-    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, Trace trace, TraceLinearScanAllocationContext context) {
-        TraceBuilderResult traceBuilderResult = context.resultTraces;
-        TraceLinearScan allocator = context.allocator;
+    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, Trace trace, MoveFactory spillMoveFactory, RegisterAllocationConfig registerAllocationConfig,
+                    TraceBuilderResult traceBuilderResult, TraceLinearScan allocator) {
         new Resolver(allocator, traceBuilderResult).resolveDataFlow(trace, allocator.sortedBlocks());
     }
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/LIRPhase.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/LIRPhase.java	Wed Apr 19 04:10:56 2017 +0000
@@ -113,8 +113,8 @@
         try (Scope s = Debug.scope(getName(), this)) {
             try (DebugCloseable a = timer.start(); DebugCloseable c = memUseTracker.start()) {
                 run(target, lirGenRes, context);
-                if (dumpLIR && Debug.isDumpEnabled(Debug.BASIC_LEVEL)) {
-                    Debug.dump(Debug.BASIC_LEVEL, lirGenRes.getLIR(), "%s", getName());
+                if (dumpLIR && Debug.isEnabled()) {
+                    dumpAfter(lirGenRes);
                 }
             }
         } catch (Throwable e) {
@@ -122,6 +122,15 @@
         }
     }
 
+    private void dumpAfter(LIRGenerationResult lirGenRes) {
+        boolean isStage = this instanceof LIRPhaseSuite;
+        if (!isStage) {
+            if (Debug.isDumpEnabled(Debug.INFO_LEVEL)) {
+                Debug.dump(Debug.INFO_LEVEL, lirGenRes.getLIR(), "After %s", getName());
+            }
+        }
+    }
+
     protected abstract void run(TargetDescription target, LIRGenerationResult lirGenRes, C context);
 
     public static CharSequence createName(Class<?> clazz) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/LSStackSlotAllocator.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/LSStackSlotAllocator.java	Wed Apr 19 04:10:56 2017 +0000
@@ -103,6 +103,7 @@
     }
 
     private static final class Allocator {
+
         private final LIR lir;
         private final FrameMapBuilderTool frameMapBuilder;
         private final StackInterval[] stackSlotMap;
@@ -131,7 +132,7 @@
 
         @SuppressWarnings("try")
         private void allocate() {
-            Debug.dump(Debug.INFO_LEVEL, lir, "After StackSlot numbering");
+            Debug.dump(Debug.VERBOSE_LEVEL, lir, "After StackSlot numbering");
 
             long currentFrameSize = StackSlotAllocatorUtil.allocatedFramesize.isEnabled() ? frameMapBuilder.getFrameMap().currentFrameSize() : 0;
             EconomicSet<LIRInstruction> usePos;
@@ -145,14 +146,14 @@
                     assert verifyIntervals();
                 }
             }
-            if (Debug.isDumpEnabled(Debug.INFO_LEVEL)) {
+            if (Debug.isDumpEnabled(Debug.VERBOSE_LEVEL)) {
                 dumpIntervals("Before stack slot allocation");
             }
             // step 4: allocate stack slots
             try (DebugCloseable t = AllocateSlotsTimer.start()) {
                 allocateStackSlots();
             }
-            if (Debug.isDumpEnabled(Debug.INFO_LEVEL)) {
+            if (Debug.isDumpEnabled(Debug.VERBOSE_LEVEL)) {
                 dumpIntervals("After stack slot allocation");
             }
 
@@ -160,7 +161,6 @@
             try (DebugCloseable t = AssignSlotsTimer.start()) {
                 assignStackSlots(usePos);
             }
-            Debug.dump(Debug.INFO_LEVEL, lir, "After StackSlot assignment");
             if (StackSlotAllocatorUtil.allocatedFramesize.isEnabled()) {
                 StackSlotAllocatorUtil.allocatedFramesize.add(frameMapBuilder.getFrameMap().currentFrameSize() - currentFrameSize);
             }
@@ -434,7 +434,7 @@
         }
 
         private void dumpIntervals(String label) {
-            Debug.dump(Debug.INFO_LEVEL, new StackIntervalDumper(Arrays.copyOf(stackSlotMap, stackSlotMap.length)), label);
+            Debug.dump(Debug.VERBOSE_LEVEL, new StackIntervalDumper(Arrays.copyOf(stackSlotMap, stackSlotMap.length)), label);
         }
 
     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopEx.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopEx.java	Wed Apr 19 04:10:56 2017 +0000
@@ -69,8 +69,9 @@
 import org.graalvm.compiler.nodes.debug.ControlFlowAnchored;
 import org.graalvm.compiler.nodes.extended.ValueAnchorNode;
 import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.util.EconomicMap;
+import org.graalvm.util.EconomicSet;
 import org.graalvm.util.Equivalence;
-import org.graalvm.util.EconomicMap;
 
 import jdk.vm.ci.code.BytecodeFrame;
 
@@ -296,7 +297,7 @@
     }
 
     public void nodesInLoopBranch(NodeBitMap branchNodes, AbstractBeginNode branch) {
-        Collection<AbstractBeginNode> blocks = new LinkedList<>();
+        EconomicSet<AbstractBeginNode> blocks = EconomicSet.create();
         Collection<LoopExitNode> exits = new LinkedList<>();
         Queue<Block> work = new LinkedList<>();
         ControlFlowGraph cfg = loopsData().getCFG();
@@ -304,9 +305,9 @@
         while (!work.isEmpty()) {
             Block b = work.remove();
             if (loop().getExits().contains(b)) {
+                assert !exits.contains(b.getBeginNode());
                 exits.add((LoopExitNode) b.getBeginNode());
-            } else {
-                blocks.add(b.getBeginNode());
+            } else if (blocks.add(b.getBeginNode())) {
                 Block d = b.getDominatedSibling();
                 while (d != null) {
                     if (loop.getBlocks().contains(d)) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodeinfo/src/org/graalvm/compiler/nodeinfo/NodeCycles.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodeinfo/src/org/graalvm/compiler/nodeinfo/NodeCycles.java	Wed Apr 19 04:10:56 2017 +0000
@@ -52,28 +52,58 @@
     CYCLES_0(0),
     CYCLES_1(1),
     CYCLES_2(2),
-    CYCLES_3(3),
     CYCLES_4(4),
-    CYCLES_5(5),
-    CYCLES_6(6),
     CYCLES_8(8),
-    CYCLES_10(10),
-    CYCLES_15(15),
-    CYCLES_20(20),
-    CYCLES_30(30),
-    CYCLES_40(40),
-    CYCLES_50(50),
-    CYCLES_80(80),
-    CYCLES_100(100),
-    CYCLES_200(200),
-    CYCLES_500(500);
+    CYCLES_16(16),
+    CYCLES_32(32),
+    CYCLES_64(64),
+    CYCLES_128(128),
+    CYCLES_256(256),
+    CYCLES_512(512),
+    CYCLES_1024(1024);
 
-    public final int estimatedCPUCycles;
+    public final int value;
 
-    NodeCycles(int estimatedCPUCycles) {
-        this.estimatedCPUCycles = estimatedCPUCycles;
+    NodeCycles(int value) {
+        this.value = value;
     }
 
     public static final int IGNORE_CYCLES_CONTRACT_FACTOR = 0xFFFF;
 
+    public static NodeCycles compute(NodeCycles base, int opCount) {
+        assert opCount >= 0;
+        if (opCount == 0) {
+            return CYCLES_0;
+        }
+        assert base.ordinal() > CYCLES_0.ordinal();
+        int log2 = log2(base.value * opCount);
+        NodeCycles[] values = values();
+        for (int i = base.ordinal(); i < values.length; i++) {
+            if (log2(values[i].value) == log2) {
+                return values[i];
+            }
+        }
+        return CYCLES_1024;
+    }
+
+    public static NodeCycles compute(int rawValue) {
+        assert rawValue >= 0;
+        if (rawValue == 0) {
+            return CYCLES_0;
+        }
+        NodeCycles[] values = values();
+        for (int i = CYCLES_0.ordinal(); i < values.length - 1; i++) {
+            if (values[i].value >= rawValue && rawValue <= values[i + 1].value) {
+                int r1 = values[i].value;
+                int r2 = values[i + 1].value;
+                int diff = r2 - r1;
+                return rawValue - r1 > diff / 2 ? values[i + 1] : values[i];
+            }
+        }
+        return CYCLES_1024;
+    }
+
+    private static int log2(int val) {
+        return (Integer.SIZE - 1) - Integer.numberOfLeadingZeros(val);
+    }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodeinfo/src/org/graalvm/compiler/nodeinfo/NodeSize.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodeinfo/src/org/graalvm/compiler/nodeinfo/NodeSize.java	Wed Apr 19 04:10:56 2017 +0000
@@ -47,31 +47,65 @@
      */
     SIZE_IGNORED(0),
     /**
-     * Nodes that do not require any code to be generated in order to be "executed", e.g. a phi
+     * Nodes that do not require any code to be generated in order to be "executed", e.g. a pinode
      * node.
      */
     SIZE_0(0),
     SIZE_1(1),
     SIZE_2(2),
-    SIZE_3(3),
     SIZE_4(4),
-    SIZE_6(6),
     SIZE_8(8),
-    SIZE_10(10),
-    SIZE_15(15),
-    SIZE_20(20),
-    SIZE_30(30),
-    SIZE_40(40),
-    SIZE_50(50),
-    SIZE_80(80),
-    SIZE_100(100),
-    SIZE_200(200);
+    SIZE_16(16),
+    SIZE_32(32),
+    SIZE_64(64),
+    SIZE_128(128),
+    SIZE_256(256),
+    SIZE_512(512),
+    SIZE_1024(1024);
 
-    public final int estimatedCodeSize;
+    public final int value;
 
-    NodeSize(int estimatedCodeSize) {
-        this.estimatedCodeSize = estimatedCodeSize;
+    NodeSize(int value) {
+        this.value = value;
     }
 
     public static final int IGNORE_SIZE_CONTRACT_FACTOR = 0xFFFF;
+
+    public static NodeSize compute(NodeSize base, int opCount) {
+        assert opCount >= 0;
+        if (opCount == 0) {
+            return SIZE_0;
+        }
+        assert base.ordinal() > SIZE_0.ordinal();
+        int log2 = log2(base.value * opCount);
+        NodeSize[] values = values();
+        for (int i = base.ordinal(); i < values.length; i++) {
+            if (log2(values[i].value) == log2) {
+                return values[i];
+            }
+        }
+        return SIZE_1024;
+    }
+
+    public static NodeSize compute(int rawValue) {
+        assert rawValue >= 0;
+        if (rawValue == 0) {
+            return SIZE_0;
+        }
+        assert rawValue > 0;
+        NodeSize[] values = values();
+        for (int i = SIZE_0.ordinal(); i < values.length - 1; i++) {
+            if (values[i].value >= rawValue && rawValue <= values[i + 1].value) {
+                int r1 = values[i].value;
+                int r2 = values[i + 1].value;
+                int diff = r2 - r1;
+                return rawValue - r1 > diff / 2 ? values[i + 1] : values[i];
+            }
+        }
+        return SIZE_1024;
+    }
+
+    private static int log2(int val) {
+        return (Integer.SIZE - 1) - Integer.numberOfLeadingZeros(val);
+    }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/BreakpointNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/BreakpointNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,6 +22,9 @@
  */
 package org.graalvm.compiler.nodes;
 
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
+
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.graph.NodeInputList;
@@ -47,7 +50,7 @@
  * Note that the signature is arbitrary. It's sole purpose is to capture values you may want to
  * inspect in the native debugger when the breakpoint is hit.
  */
-@NodeInfo
+@NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
 public final class BreakpointNode extends FixedWithNextNode implements LIRLowerable {
 
     public static final NodeClass<BreakpointNode> TYPE = NodeClass.create(BreakpointNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FrameState.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FrameState.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,12 +22,14 @@
  */
 package org.graalvm.compiler.nodes;
 
+import static jdk.vm.ci.code.BytecodeFrame.getPlaceholderBciName;
+import static jdk.vm.ci.code.BytecodeFrame.isPlaceholderBci;
 import static org.graalvm.compiler.nodeinfo.InputType.Association;
 import static org.graalvm.compiler.nodeinfo.InputType.State;
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
-import static jdk.vm.ci.code.BytecodeFrame.getPlaceholderBciName;
-import static jdk.vm.ci.code.BytecodeFrame.isPlaceholderBci;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -78,7 +80,7 @@
      */
     public static final ValueNode TWO_SLOT_MARKER = new TwoSlotMarker();
 
-    @NodeInfo
+    @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
     private static final class TwoSlotMarker extends ValueNode {
         public static final NodeClass<TwoSlotMarker> TYPE = NodeClass.create(TwoSlotMarker.class);
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java	Wed Apr 19 04:10:56 2017 +0000
@@ -573,7 +573,7 @@
         return resultScope;
     }
 
-    private InvokeData readInvokeData(MethodScope methodScope, int invokeOrderId, Invoke invoke) {
+    protected InvokeData readInvokeData(MethodScope methodScope, int invokeOrderId, Invoke invoke) {
         ResolvedJavaType contextType = (ResolvedJavaType) readObject(methodScope);
         int callTargetOrderId = readOrderId(methodScope);
         int stateAfterOrderId = readOrderId(methodScope);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphEncoder.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphEncoder.java	Wed Apr 19 04:10:56 2017 +0000
@@ -427,8 +427,8 @@
             GraphComparison.verifyGraphsEqual(originalGraph, decodedGraph);
         } catch (Throwable ex) {
             try (Debug.Scope scope = Debug.scope("GraphEncoder")) {
-                Debug.forceDump(originalGraph, "Original Graph");
-                Debug.forceDump(decodedGraph, "Decoded Graph");
+                Debug.dump(Debug.VERBOSE_LEVEL, originalGraph, "Original Graph");
+                Debug.dump(Debug.VERBOSE_LEVEL, decodedGraph, "Decoded Graph");
             }
             throw ex;
         }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -25,7 +25,13 @@
 import static org.graalvm.compiler.nodeinfo.InputType.Extension;
 import static org.graalvm.compiler.nodeinfo.InputType.Memory;
 import static org.graalvm.compiler.nodeinfo.InputType.State;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_64;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_64;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
 
 import java.util.Map;
@@ -35,7 +41,9 @@
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeCycles;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodeinfo.NodeSize;
 import org.graalvm.compiler.nodeinfo.Verbosity;
 import org.graalvm.compiler.nodes.extended.ForeignCallNode;
 import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
@@ -227,4 +235,34 @@
     public ValueNode classInit() {
         return classInit;
     }
+
+    @Override
+    public NodeCycles estimatedNodeCycles() {
+        switch (callTarget().invokeKind()) {
+            case Interface:
+                return CYCLES_64;
+            case Special:
+            case Static:
+                return CYCLES_2;
+            case Virtual:
+                return CYCLES_8;
+            default:
+                return CYCLES_UNKNOWN;
+        }
+    }
+
+    @Override
+    public NodeSize estimatedNodeSize() {
+        switch (callTarget().invokeKind()) {
+            case Interface:
+                return SIZE_64;
+            case Special:
+            case Static:
+                return SIZE_2;
+            case Virtual:
+                return SIZE_8;
+            default:
+                return SIZE_UNKNOWN;
+        }
+    }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoopEndNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoopEndNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -24,13 +24,16 @@
 
 import static org.graalvm.compiler.nodeinfo.InputType.Association;
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
 
 import java.util.Collections;
 
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeCycles;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodeinfo.NodeSize;
 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
 
 /**
@@ -135,4 +138,21 @@
     public Iterable<? extends Node> cfgSuccessors() {
         return Collections.emptyList();
     }
+
+    @Override
+    public NodeCycles estimatedNodeCycles() {
+        if (canSafepoint()) {
+            // jmp+read
+            return CYCLES_2;
+        }
+        return super.estimatedNodeCycles();
+    }
+
+    @Override
+    public NodeSize estimatedNodeSize() {
+        if (canSafepoint()) {
+            return NodeSize.SIZE_2;
+        }
+        return super.estimatedNodeSize();
+    }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PauseNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PauseNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,16 +22,20 @@
  */
 package org.graalvm.compiler.nodes;
 
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
+
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.NodeClass;
-import org.graalvm.compiler.nodeinfo.NodeCycles;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
 import org.graalvm.compiler.nodeinfo.NodeSize;
 import org.graalvm.compiler.nodes.spi.LIRLowerable;
 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
 
 /** A node that results in a platform dependent pause instruction being emitted. */
-@NodeInfo(cycles = NodeCycles.CYCLES_500, size = NodeSize.SIZE_1)
+// @formatter:off
+@NodeInfo(cycles = CYCLES_IGNORED,
+          size = NodeSize.SIZE_1)
+// @formatter:on
 public final class PauseNode extends FixedWithNextNode implements LIRLowerable {
 
     public static final NodeClass<PauseNode> TYPE = NodeClass.create(PauseNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PiNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PiNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -128,7 +128,7 @@
         if (value == null) {
             value = new PiNode(object, stamp, anchor);
         }
-        b.push(JavaKind.Object, b.recursiveAppend(value));
+        b.push(JavaKind.Object, b.append(value));
         return true;
     }
 
@@ -139,7 +139,7 @@
         if (value == null) {
             value = new PiNode(object, stamp);
         }
-        b.push(JavaKind.Object, b.recursiveAppend(value));
+        b.push(JavaKind.Object, b.append(value));
         return true;
     }
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ReturnNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ReturnNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -23,8 +23,8 @@
 package org.graalvm.compiler.nodes;
 
 import static org.graalvm.compiler.nodeinfo.InputType.Extension;
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
 
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.IterableNodeType;
@@ -37,7 +37,7 @@
 import jdk.vm.ci.code.TargetDescription;
 import jdk.vm.ci.meta.JavaKind;
 
-@NodeInfo(cycles = CYCLES_UNKNOWN, size = SIZE_UNKNOWN)
+@NodeInfo(cycles = CYCLES_2, size = SIZE_2, cyclesRationale = "Restore frame + ret", sizeRationale = "Restore frame + ret")
 public final class ReturnNode extends ControlSinkNode implements LIRLowerable, IterableNodeType {
 
     public static final NodeClass<ReturnNode> TYPE = NodeClass.create(ReturnNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/SafepointNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/SafepointNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,8 +22,8 @@
  */
 package org.graalvm.compiler.nodes;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_6;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
 
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.NodeClass;
@@ -37,9 +37,9 @@
  * Marks a position in the graph where a safepoint should be emitted.
  */
 // @formatter:off
-@NodeInfo(cycles = CYCLES_UNKNOWN,
-          cyclesRationale = "We don't know how long a safepoint would take if it is executed",
-          size = SIZE_6)
+@NodeInfo(cycles = CYCLES_2,
+          cyclesRationale = "read",
+          size = SIZE_1)
 // @formatter:on
 public final class SafepointNode extends DeoptimizingFixedWithNextNode implements Lowerable, LIRLowerable {
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/SimplifyingGraphDecoder.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/SimplifyingGraphDecoder.java	Wed Apr 19 04:10:56 2017 +0000
@@ -111,10 +111,10 @@
         }
 
         @Override
-        public boolean supportSubwordCompare(int bits) {
-            // to be safe, just report false here
+        public Integer smallestCompareWidth() {
+            // to be safe, just report null here
             // there will be more opportunities for this optimization later
-            return false;
+            return null;
         }
     }
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/UnwindNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/UnwindNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -23,7 +23,7 @@
 package org.graalvm.compiler.nodes;
 
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_4;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8;
 
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.NodeClass;
@@ -38,7 +38,7 @@
 /**
  * Unwinds the current frame to an exception handler in the caller frame.
  */
-@NodeInfo(cycles = CYCLES_8, size = SIZE_4)
+@NodeInfo(cycles = CYCLES_8, size = SIZE_8, cyclesRationale = "stub call", sizeRationale = "stub call")
 public final class UnwindNode extends ControlSinkNode implements Lowerable, LIRLowerable {
 
     public static final NodeClass<UnwindNode> TYPE = NodeClass.create(UnwindNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/AbsNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/AbsNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,7 +22,7 @@
  */
 package org.graalvm.compiler.nodes.calc;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
 
 import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
@@ -38,7 +38,7 @@
 /**
  * Absolute value.
  */
-@NodeInfo(cycles = CYCLES_3, size = SIZE_1)
+@NodeInfo(cycles = CYCLES_2, size = SIZE_1)
 public final class AbsNode extends UnaryArithmeticNode<Abs> implements ArithmeticLIRLowerable, NarrowableArithmeticNode {
     public static final NodeClass<AbsNode> TYPE = NodeClass.create(AbsNode.class);
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/CompareNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/CompareNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -25,6 +25,7 @@
 import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1;
 
+import jdk.vm.ci.meta.MetaAccessProvider;
 import org.graalvm.compiler.core.common.calc.Condition;
 import org.graalvm.compiler.core.common.type.AbstractObjectStamp;
 import org.graalvm.compiler.core.common.type.AbstractPointerStamp;
@@ -32,7 +33,6 @@
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.graph.spi.Canonicalizable;
-import org.graalvm.compiler.graph.spi.CanonicalizerTool;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
 import org.graalvm.compiler.nodes.BinaryOpLogicNode;
 import org.graalvm.compiler.nodes.ConstantNode;
@@ -45,6 +45,7 @@
 import jdk.vm.ci.meta.Constant;
 import jdk.vm.ci.meta.ConstantReflectionProvider;
 import jdk.vm.ci.meta.PrimitiveConstant;
+import org.graalvm.compiler.options.OptionValues;
 
 @NodeInfo(cycles = CYCLES_1)
 public abstract class CompareNode extends BinaryOpLogicNode implements Canonicalizable.Binary<ValueNode> {
@@ -83,74 +84,6 @@
         return this.unorderedIsTrue;
     }
 
-    private ValueNode optimizeConditional(Constant constant, ConditionalNode conditionalNode, ConstantReflectionProvider constantReflection, Condition cond) {
-        Constant trueConstant = conditionalNode.trueValue().asConstant();
-        Constant falseConstant = conditionalNode.falseValue().asConstant();
-
-        if (falseConstant != null && trueConstant != null && constantReflection != null) {
-            boolean trueResult = cond.foldCondition(trueConstant, constant, constantReflection, unorderedIsTrue());
-            boolean falseResult = cond.foldCondition(falseConstant, constant, constantReflection, unorderedIsTrue());
-
-            if (trueResult == falseResult) {
-                return LogicConstantNode.forBoolean(trueResult);
-            } else {
-                if (trueResult) {
-                    assert falseResult == false;
-                    return conditionalNode.condition();
-                } else {
-                    assert falseResult == true;
-                    return LogicNegationNode.create(conditionalNode.condition());
-
-                }
-            }
-        }
-        return this;
-    }
-
-    protected ValueNode optimizeNormalizeCmp(Constant constant, NormalizeCompareNode normalizeNode, boolean mirrored) {
-        throw new GraalError("NormalizeCompareNode connected to %s (%s %s %s)", this, constant, normalizeNode, mirrored);
-    }
-
-    @Override
-    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
-        ConstantReflectionProvider constantReflection = tool.getConstantReflection();
-        LogicNode constantCondition = tryConstantFold(condition(), forX, forY, constantReflection, unorderedIsTrue());
-        if (constantCondition != null) {
-            return constantCondition;
-        }
-        ValueNode result;
-        if (forX.isConstant()) {
-            if ((result = canonicalizeSymmetricConstant(tool, forX.asConstant(), forY, true)) != this) {
-                return result;
-            }
-        } else if (forY.isConstant()) {
-            if ((result = canonicalizeSymmetricConstant(tool, forY.asConstant(), forX, false)) != this) {
-                return result;
-            }
-        } else if (forX instanceof ConvertNode && forY instanceof ConvertNode) {
-            ConvertNode convertX = (ConvertNode) forX;
-            ConvertNode convertY = (ConvertNode) forY;
-            if (convertX.preservesOrder(condition()) && convertY.preservesOrder(condition()) && convertX.getValue().stamp().isCompatible(convertY.getValue().stamp())) {
-                boolean supported = true;
-                if (convertX.getValue().stamp() instanceof IntegerStamp) {
-                    IntegerStamp intStamp = (IntegerStamp) convertX.getValue().stamp();
-                    supported = tool.supportSubwordCompare(intStamp.getBits());
-                }
-
-                if (supported) {
-                    boolean multiUsage = (convertX.asNode().hasMoreThanOneUsage() || convertY.asNode().hasMoreThanOneUsage());
-                    if ((forX instanceof ZeroExtendNode || forX instanceof SignExtendNode) && multiUsage) {
-                        // Do not perform for zero or sign extend if there are multiple usages of
-                        // the value.
-                        return this;
-                    }
-                    return duplicateModified(convertX.getValue(), convertY.getValue());
-                }
-            }
-        }
-        return this;
-    }
-
     public static LogicNode tryConstantFold(Condition condition, ValueNode forX, ValueNode forY, ConstantReflectionProvider constantReflection, boolean unorderedIsTrue) {
         if (forX.isConstant() && forY.isConstant() && (constantReflection != null || forX.asConstant() instanceof PrimitiveConstant)) {
             return LogicConstantNode.forBoolean(condition.foldCondition(forX.asConstant(), forY.asConstant(), constantReflection, unorderedIsTrue));
@@ -175,56 +108,129 @@
         return condition == Condition.EQ;
     }
 
-    protected abstract LogicNode duplicateModified(ValueNode newX, ValueNode newY);
-
-    protected ValueNode canonicalizeSymmetricConstant(CanonicalizerTool tool, Constant constant, ValueNode nonConstant, boolean mirrored) {
-        if (nonConstant instanceof ConditionalNode) {
-            return optimizeConditional(constant, (ConditionalNode) nonConstant, tool.getConstantReflection(), mirrored ? condition().mirror() : condition());
-        } else if (nonConstant instanceof NormalizeCompareNode) {
-            return optimizeNormalizeCmp(constant, (NormalizeCompareNode) nonConstant, mirrored);
-        } else if (nonConstant instanceof ConvertNode) {
-            ConvertNode convert = (ConvertNode) nonConstant;
-            boolean multiUsage = (convert.asNode().hasMoreThanOneUsage() && convert.getValue().hasExactlyOneUsage());
-            if ((convert instanceof ZeroExtendNode || convert instanceof SignExtendNode) && multiUsage) {
-                // Do not perform for zero or sign extend if it could introduce
-                // new live values.
-                return this;
+    public abstract static class CompareOp {
+        public LogicNode canonical(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, Condition condition,
+                        boolean unorderedIsTrue, ValueNode forX, ValueNode forY) {
+            LogicNode constantCondition = tryConstantFold(condition, forX, forY, constantReflection, unorderedIsTrue);
+            if (constantCondition != null) {
+                return constantCondition;
             }
-
-            boolean supported = true;
-            if (convert.getValue().stamp() instanceof IntegerStamp) {
-                IntegerStamp intStamp = (IntegerStamp) convert.getValue().stamp();
-                supported = tool.supportSubwordCompare(intStamp.getBits());
-            }
+            LogicNode result;
+            if (forX.isConstant()) {
+                if ((result = canonicalizeSymmetricConstant(constantReflection, metaAccess, options, smallestCompareWidth, condition, forX.asConstant(), forY, true, unorderedIsTrue)) != null) {
+                    return result;
+                }
+            } else if (forY.isConstant()) {
+                if ((result = canonicalizeSymmetricConstant(constantReflection, metaAccess, options, smallestCompareWidth, condition, forY.asConstant(), forX, false, unorderedIsTrue)) != null) {
+                    return result;
+                }
+            } else if (forX instanceof ConvertNode && forY instanceof ConvertNode) {
+                ConvertNode convertX = (ConvertNode) forX;
+                ConvertNode convertY = (ConvertNode) forY;
+                if (convertX.preservesOrder(condition) && convertY.preservesOrder(condition) && convertX.getValue().stamp().isCompatible(convertY.getValue().stamp())) {
+                    boolean supported = true;
+                    if (convertX.getValue().stamp() instanceof IntegerStamp) {
+                        IntegerStamp intStamp = (IntegerStamp) convertX.getValue().stamp();
+                        supported = smallestCompareWidth != null && intStamp.getBits() >= smallestCompareWidth;
+                    }
 
-            if (supported) {
-                ConstantNode newConstant = canonicalConvertConstant(tool, convert, constant);
-                if (newConstant != null) {
-                    if (mirrored) {
-                        return duplicateModified(newConstant, convert.getValue());
-                    } else {
-                        return duplicateModified(convert.getValue(), newConstant);
+                    if (supported) {
+                        boolean multiUsage = (convertX.asNode().hasMoreThanOneUsage() || convertY.asNode().hasMoreThanOneUsage());
+                        if ((forX instanceof ZeroExtendNode || forX instanceof SignExtendNode) && multiUsage) {
+                            // Do not perform for zero or sign extend if there are multiple usages
+                            // of the value.
+                            return null;
+                        }
+                        return duplicateModified(convertX.getValue(), convertY.getValue(), unorderedIsTrue);
                     }
                 }
             }
+            return null;
+        }
+
+        protected LogicNode canonicalizeSymmetricConstant(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth,
+                        Condition condition, Constant constant, ValueNode nonConstant, boolean mirrored, boolean unorderedIsTrue) {
+            if (nonConstant instanceof ConditionalNode) {
+                return optimizeConditional(constant, (ConditionalNode) nonConstant, constantReflection, mirrored ? condition.mirror() : condition, unorderedIsTrue);
+            } else if (nonConstant instanceof NormalizeCompareNode) {
+                return optimizeNormalizeCompare(constantReflection, metaAccess, options, smallestCompareWidth, constant, (NormalizeCompareNode) nonConstant, mirrored);
+            } else if (nonConstant instanceof ConvertNode) {
+                ConvertNode convert = (ConvertNode) nonConstant;
+                boolean multiUsage = (convert.asNode().hasMoreThanOneUsage() && convert.getValue().hasExactlyOneUsage());
+                if ((convert instanceof ZeroExtendNode || convert instanceof SignExtendNode) && multiUsage) {
+                    // Do not perform for zero or sign extend if it could introduce
+                    // new live values.
+                    return null;
+                }
+
+                boolean supported = true;
+                if (convert.getValue().stamp() instanceof IntegerStamp) {
+                    IntegerStamp intStamp = (IntegerStamp) convert.getValue().stamp();
+                    supported = smallestCompareWidth != null && intStamp.getBits() > smallestCompareWidth;
+                }
+
+                if (supported) {
+                    ConstantNode newConstant = canonicalConvertConstant(constantReflection, metaAccess, options, condition, convert, constant);
+                    if (newConstant != null) {
+                        if (mirrored) {
+                            return duplicateModified(newConstant, convert.getValue(), unorderedIsTrue);
+                        } else {
+                            return duplicateModified(convert.getValue(), newConstant, unorderedIsTrue);
+                        }
+                    }
+                }
+            }
+
+            return null;
         }
 
-        return this;
-    }
+        private static ConstantNode canonicalConvertConstant(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Condition condition,
+                        ConvertNode convert, Constant constant) {
+            if (convert.preservesOrder(condition, constant, constantReflection)) {
+                Constant reverseConverted = convert.reverse(constant, constantReflection);
+                if (reverseConverted != null && convert.convert(reverseConverted, constantReflection).equals(constant)) {
+                    if (GeneratePIC.getValue(options)) {
+                        // We always want uncompressed constants
+                        return null;
+                    }
+                    return ConstantNode.forConstant(convert.getValue().stamp(), reverseConverted, metaAccess);
+                }
+            }
+            return null;
+        }
+
+        @SuppressWarnings("unused")
+        protected LogicNode optimizeNormalizeCompare(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth,
+                        Constant constant, NormalizeCompareNode normalizeNode, boolean mirrored) {
+            throw new GraalError("NormalizeCompareNode connected to %s (%s %s %s)", this, constant, normalizeNode, mirrored);
+        }
 
-    private ConstantNode canonicalConvertConstant(CanonicalizerTool tool, ConvertNode convert, Constant constant) {
-        ConstantReflectionProvider constantReflection = tool.getConstantReflection();
-        if (convert.preservesOrder(condition(), constant, constantReflection)) {
-            Constant reverseConverted = convert.reverse(constant, constantReflection);
-            if (reverseConverted != null && convert.convert(reverseConverted, constantReflection).equals(constant)) {
-                if (GeneratePIC.getValue(tool.getOptions())) {
-                    // We always want uncompressed constants
-                    return null;
+        private static LogicNode optimizeConditional(Constant constant, ConditionalNode conditionalNode, ConstantReflectionProvider constantReflection, Condition cond, boolean unorderedIsTrue) {
+            Constant trueConstant = conditionalNode.trueValue().asConstant();
+            Constant falseConstant = conditionalNode.falseValue().asConstant();
+
+            if (falseConstant != null && trueConstant != null && constantReflection != null) {
+                boolean trueResult = cond.foldCondition(trueConstant, constant, constantReflection, unorderedIsTrue);
+                boolean falseResult = cond.foldCondition(falseConstant, constant, constantReflection, unorderedIsTrue);
+
+                if (trueResult == falseResult) {
+                    return LogicConstantNode.forBoolean(trueResult);
+                } else {
+                    if (trueResult) {
+                        assert falseResult == false;
+                        return conditionalNode.condition();
+                    } else {
+                        assert falseResult == true;
+                        return LogicNegationNode.create(conditionalNode.condition());
+
+                    }
                 }
-                return ConstantNode.forConstant(convert.getValue().stamp(), reverseConverted, tool.getMetaAccess());
             }
+
+            return null;
         }
-        return null;
+
+        protected abstract LogicNode duplicateModified(ValueNode newW, ValueNode newY, boolean unorderedIsTrue);
     }
 
     public static LogicNode createCompareNode(StructuredGraph graph, Condition condition, ValueNode x, ValueNode y, ConstantReflectionProvider constantReflection) {
@@ -258,4 +264,39 @@
 
         return comparison;
     }
+
+    public static LogicNode createCompareNode(StructuredGraph graph, ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth,
+                    Condition condition, ValueNode x, ValueNode y) {
+        LogicNode result = createCompareNode(constantReflection, metaAccess, options, smallestCompareWidth, condition, x, y);
+        return (result.graph() == null ? graph.addOrUniqueWithInputs(result) : result);
+    }
+
+    public static LogicNode createCompareNode(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth,
+                    Condition condition, ValueNode x, ValueNode y) {
+        assert x.getStackKind() == y.getStackKind();
+        assert condition.isCanonical();
+        assert !x.getStackKind().isNumericFloat();
+
+        LogicNode comparison;
+        if (condition == Condition.EQ) {
+            if (x.stamp() instanceof AbstractObjectStamp) {
+                assert smallestCompareWidth == null;
+                comparison = ObjectEqualsNode.create(constantReflection, metaAccess, options, x, y);
+            } else if (x.stamp() instanceof AbstractPointerStamp) {
+                comparison = PointerEqualsNode.create(x, y);
+            } else {
+                assert x.getStackKind().isNumericInteger();
+                comparison = IntegerEqualsNode.create(constantReflection, metaAccess, options, smallestCompareWidth, x, y);
+            }
+        } else if (condition == Condition.LT) {
+            assert x.getStackKind().isNumericInteger();
+            comparison = IntegerLessThanNode.create(constantReflection, metaAccess, options, smallestCompareWidth, x, y);
+        } else {
+            assert condition == Condition.BT;
+            assert x.getStackKind().isNumericInteger();
+            comparison = IntegerBelowNode.create(constantReflection, metaAccess, options, smallestCompareWidth, x, y);
+        }
+
+        return comparison;
+    }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/DivNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/DivNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,6 +22,8 @@
  */
 package org.graalvm.compiler.nodes.calc;
 
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_32;
+
 import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp;
 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Div;
@@ -29,7 +31,6 @@
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.graph.spi.CanonicalizerTool;
 import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
-import org.graalvm.compiler.nodeinfo.NodeCycles;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
 import org.graalvm.compiler.nodes.ConstantNode;
 import org.graalvm.compiler.nodes.ValueNode;
@@ -39,7 +40,7 @@
 import jdk.vm.ci.meta.Constant;
 import jdk.vm.ci.meta.PrimitiveConstant;
 
-@NodeInfo(shortName = "/", cycles = NodeCycles.CYCLES_30)
+@NodeInfo(shortName = "/", cycles = CYCLES_32)
 public class DivNode extends BinaryArithmeticNode<Div> {
 
     public static final NodeClass<DivNode> TYPE = NodeClass.create(DivNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FloatConvertNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FloatConvertNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,7 +22,7 @@
  */
 package org.graalvm.compiler.nodes.calc;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_5;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
 
 import java.util.EnumMap;
 
@@ -46,7 +46,7 @@
  * A {@code FloatConvert} converts between integers and floating point numbers according to Java
  * semantics.
  */
-@NodeInfo(cycles = CYCLES_5)
+@NodeInfo(cycles = CYCLES_8)
 public final class FloatConvertNode extends UnaryArithmeticNode<FloatConvertOp> implements ConvertNode, Lowerable, ArithmeticLIRLowerable {
     public static final NodeClass<FloatConvertNode> TYPE = NodeClass.create(FloatConvertNode.class);
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FloatEqualsNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FloatEqualsNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,26 +22,31 @@
  */
 package org.graalvm.compiler.nodes.calc;
 
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.TriState;
 import org.graalvm.compiler.core.common.calc.Condition;
 import org.graalvm.compiler.core.common.type.FloatStamp;
 import org.graalvm.compiler.core.common.type.IntegerStamp;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.graph.spi.Canonicalizable.BinaryCommutative;
 import org.graalvm.compiler.graph.spi.CanonicalizerTool;
-import org.graalvm.compiler.nodeinfo.NodeCycles;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
 import org.graalvm.compiler.nodes.LogicConstantNode;
 import org.graalvm.compiler.nodes.LogicNode;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.options.OptionValues;
 
-import jdk.vm.ci.meta.TriState;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
 
-@NodeInfo(shortName = "==", cycles = NodeCycles.CYCLES_3)
+@NodeInfo(shortName = "==", cycles = CYCLES_2)
 public final class FloatEqualsNode extends CompareNode implements BinaryCommutative<ValueNode> {
     public static final NodeClass<FloatEqualsNode> TYPE = NodeClass.create(FloatEqualsNode.class);
+    private static final FloatEqualsOp OP = new FloatEqualsOp();
 
     public FloatEqualsNode(ValueNode x, ValueNode y) {
         super(TYPE, Condition.EQ, false, x, y);
@@ -58,6 +63,15 @@
         }
     }
 
+    public static LogicNode create(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth,
+                    ValueNode x, ValueNode y) {
+        LogicNode value = OP.canonical(constantReflection, metaAccess, options, smallestCompareWidth, Condition.EQ, false, x, y);
+        if (value != null) {
+            return value;
+        }
+        return create(x, y);
+    }
+
     @Override
     public boolean isIdentityComparison() {
         FloatStamp xStamp = (FloatStamp) x.stamp();
@@ -72,33 +86,46 @@
     }
 
     @Override
-    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
-        ValueNode result = super.canonical(tool, forX, forY);
-        if (result != this) {
-            return result;
-        }
-        Stamp xStampGeneric = forX.stamp();
-        Stamp yStampGeneric = forY.stamp();
-        if (xStampGeneric instanceof FloatStamp && yStampGeneric instanceof FloatStamp) {
-            FloatStamp xStamp = (FloatStamp) xStampGeneric;
-            FloatStamp yStamp = (FloatStamp) yStampGeneric;
-            if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY) && xStamp.isNonNaN() && yStamp.isNonNaN()) {
-                return LogicConstantNode.tautology();
-            } else if (xStamp.alwaysDistinct(yStamp)) {
-                return LogicConstantNode.contradiction();
-            }
+    public Node canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        ValueNode value = OP.canonical(tool.getConstantReflection(), tool.getMetaAccess(), tool.getOptions(), tool.smallestCompareWidth(), Condition.EQ, unorderedIsTrue, forX, forY);
+        if (value != null) {
+            return value;
         }
         return this;
     }
 
-    @Override
-    protected CompareNode duplicateModified(ValueNode newX, ValueNode newY) {
-        if (newX.stamp() instanceof FloatStamp && newY.stamp() instanceof FloatStamp) {
-            return new FloatEqualsNode(newX, newY);
-        } else if (newX.stamp() instanceof IntegerStamp && newY.stamp() instanceof IntegerStamp) {
-            return new IntegerEqualsNode(newX, newY);
+    public static class FloatEqualsOp extends CompareOp {
+
+        @Override
+        public LogicNode canonical(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, Condition condition,
+                        boolean unorderedIsTrue, ValueNode forX, ValueNode forY) {
+            LogicNode result = super.canonical(constantReflection, metaAccess, options, smallestCompareWidth, condition, unorderedIsTrue, forX, forY);
+            if (result != null) {
+                return result;
+            }
+            Stamp xStampGeneric = forX.stamp();
+            Stamp yStampGeneric = forY.stamp();
+            if (xStampGeneric instanceof FloatStamp && yStampGeneric instanceof FloatStamp) {
+                FloatStamp xStamp = (FloatStamp) xStampGeneric;
+                FloatStamp yStamp = (FloatStamp) yStampGeneric;
+                if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY) && xStamp.isNonNaN() && yStamp.isNonNaN()) {
+                    return LogicConstantNode.tautology();
+                } else if (xStamp.alwaysDistinct(yStamp)) {
+                    return LogicConstantNode.contradiction();
+                }
+            }
+            return null;
         }
-        throw GraalError.shouldNotReachHere();
+
+        @Override
+        protected CompareNode duplicateModified(ValueNode newX, ValueNode newY, boolean unorderedIsTrue) {
+            if (newX.stamp() instanceof FloatStamp && newY.stamp() instanceof FloatStamp) {
+                return new FloatEqualsNode(newX, newY);
+            } else if (newX.stamp() instanceof IntegerStamp && newY.stamp() instanceof IntegerStamp) {
+                return new IntegerEqualsNode(newX, newY);
+            }
+            throw GraalError.shouldNotReachHere();
+        }
     }
 
     @Override
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FloatLessThanNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FloatLessThanNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,25 +22,30 @@
  */
 package org.graalvm.compiler.nodes.calc;
 
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.TriState;
 import org.graalvm.compiler.core.common.calc.Condition;
 import org.graalvm.compiler.core.common.type.FloatStamp;
 import org.graalvm.compiler.core.common.type.IntegerStamp;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.graph.spi.CanonicalizerTool;
-import org.graalvm.compiler.nodeinfo.NodeCycles;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
 import org.graalvm.compiler.nodes.LogicConstantNode;
 import org.graalvm.compiler.nodes.LogicNode;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.options.OptionValues;
 
-import jdk.vm.ci.meta.TriState;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
 
-@NodeInfo(shortName = "<", cycles = NodeCycles.CYCLES_3)
+@NodeInfo(shortName = "<", cycles = CYCLES_2)
 public final class FloatLessThanNode extends CompareNode {
     public static final NodeClass<FloatLessThanNode> TYPE = NodeClass.create(FloatLessThanNode.class);
+    private static final FloatLessThanOp OP = new FloatLessThanOp();
 
     public FloatLessThanNode(ValueNode x, ValueNode y, boolean unorderedIsTrue) {
         super(TYPE, Condition.LT, unorderedIsTrue, x, y);
@@ -52,31 +57,52 @@
         LogicNode result = CompareNode.tryConstantFoldPrimitive(Condition.LT, x, y, unorderedIsTrue);
         if (result != null) {
             return result;
-        } else {
-            return new FloatLessThanNode(x, y, unorderedIsTrue);
         }
+        return new FloatLessThanNode(x, y, unorderedIsTrue);
+    }
+
+    public static LogicNode create(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth,
+                    ValueNode x, ValueNode y, boolean unorderedIsTrue) {
+        LogicNode result = OP.canonical(constantReflection, metaAccess, options, smallestCompareWidth, Condition.LT, unorderedIsTrue, x, y);
+        if (result != null) {
+            return result;
+        }
+        return create(x, y, unorderedIsTrue);
     }
 
     @Override
-    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
-        ValueNode result = super.canonical(tool, forX, forY);
-        if (result != this) {
-            return result;
-        }
-        if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY) && !unorderedIsTrue()) {
-            return LogicConstantNode.contradiction();
+    public Node canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        ValueNode value = OP.canonical(tool.getConstantReflection(), tool.getMetaAccess(), tool.getOptions(), tool.smallestCompareWidth(), Condition.LT, unorderedIsTrue, forX, forY);
+        if (value != null) {
+            return value;
         }
         return this;
     }
 
-    @Override
-    protected CompareNode duplicateModified(ValueNode newX, ValueNode newY) {
-        if (newX.stamp() instanceof FloatStamp && newY.stamp() instanceof FloatStamp) {
-            return new FloatLessThanNode(newX, newY, unorderedIsTrue);
-        } else if (newX.stamp() instanceof IntegerStamp && newY.stamp() instanceof IntegerStamp) {
-            return new IntegerLessThanNode(newX, newY);
+    public static class FloatLessThanOp extends CompareOp {
+
+        @Override
+        public LogicNode canonical(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, Condition condition,
+                        boolean unorderedIsTrue, ValueNode forX, ValueNode forY) {
+            LogicNode result = super.canonical(constantReflection, metaAccess, options, smallestCompareWidth, condition, unorderedIsTrue, forX, forY);
+            if (result != null) {
+                return result;
+            }
+            if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY) && !unorderedIsTrue) {
+                return LogicConstantNode.contradiction();
+            }
+            return null;
         }
-        throw GraalError.shouldNotReachHere();
+
+        @Override
+        protected CompareNode duplicateModified(ValueNode newX, ValueNode newY, boolean unorderedIsTrue) {
+            if (newX.stamp() instanceof FloatStamp && newY.stamp() instanceof FloatStamp) {
+                return new FloatLessThanNode(newX, newY, unorderedIsTrue);
+            } else if (newX.stamp() instanceof IntegerStamp && newY.stamp() instanceof IntegerStamp) {
+                return new IntegerLessThanNode(newX, newY);
+            }
+            throw GraalError.shouldNotReachHere();
+        }
     }
 
     @Override
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerBelowNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerBelowNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,16 +22,21 @@
  */
 package org.graalvm.compiler.nodes.calc;
 
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
 import org.graalvm.compiler.core.common.NumUtil;
 import org.graalvm.compiler.core.common.calc.Condition;
 import org.graalvm.compiler.core.common.type.IntegerStamp;
 import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
 import org.graalvm.compiler.nodes.LogicNode;
 import org.graalvm.compiler.nodes.ValueNode;
 
 import jdk.vm.ci.code.CodeUtil;
+import org.graalvm.compiler.options.OptionValues;
 
 @NodeInfo(shortName = "|<|")
 public final class IntegerBelowNode extends IntegerLowerThanNode {
@@ -48,13 +53,29 @@
         return OP.create(x, y);
     }
 
+    public static LogicNode create(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, ValueNode x, ValueNode y) {
+        LogicNode value = OP.canonical(constantReflection, metaAccess, options, smallestCompareWidth, OP.getCondition(), false, x, y);
+        if (value != null) {
+            return value;
+        }
+        return create(x, y);
+    }
+
     @Override
-    protected CompareNode duplicateModified(ValueNode newX, ValueNode newY) {
-        assert newX.stamp() instanceof IntegerStamp && newY.stamp() instanceof IntegerStamp;
-        return new IntegerBelowNode(newX, newY);
+    public Node canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        ValueNode value = OP.canonical(tool.getConstantReflection(), tool.getMetaAccess(), tool.getOptions(), tool.smallestCompareWidth(), OP.getCondition(), false, forX, forY);
+        if (value != null) {
+            return value;
+        }
+        return this;
     }
 
     public static class BelowOp extends LowerOp {
+        @Override
+        protected CompareNode duplicateModified(ValueNode newX, ValueNode newY, boolean unorderedIsTrue) {
+            assert newX.stamp() instanceof IntegerStamp && newY.stamp() instanceof IntegerStamp;
+            return new IntegerBelowNode(newX, newY);
+        }
 
         @Override
         protected long upperBound(IntegerStamp stamp) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerDivRemNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerDivRemNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,8 +22,8 @@
  */
 package org.graalvm.compiler.nodes.calc;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_40;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_32;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
 
 import org.graalvm.compiler.core.common.type.IntegerStamp;
 import org.graalvm.compiler.core.common.type.Stamp;
@@ -33,7 +33,7 @@
 import org.graalvm.compiler.nodes.spi.Lowerable;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 
-@NodeInfo(cycles = CYCLES_40, size = SIZE_2)
+@NodeInfo(cycles = CYCLES_32, size = SIZE_1)
 public abstract class IntegerDivRemNode extends FixedBinaryNode implements Lowerable {
 
     public static final NodeClass<IntegerDivRemNode> TYPE = NodeClass.create(IntegerDivRemNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerEqualsNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerEqualsNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,12 +22,15 @@
  */
 package org.graalvm.compiler.nodes.calc;
 
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
 import org.graalvm.compiler.core.common.calc.Condition;
 import org.graalvm.compiler.core.common.type.AbstractPointerStamp;
 import org.graalvm.compiler.core.common.type.FloatStamp;
 import org.graalvm.compiler.core.common.type.IntegerStamp;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.graph.spi.Canonicalizable.BinaryCommutative;
 import org.graalvm.compiler.graph.spi.CanonicalizerTool;
@@ -43,10 +46,12 @@
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.PrimitiveConstant;
 import jdk.vm.ci.meta.TriState;
+import org.graalvm.compiler.options.OptionValues;
 
 @NodeInfo(shortName = "==")
 public final class IntegerEqualsNode extends CompareNode implements BinaryCommutative<ValueNode> {
     public static final NodeClass<IntegerEqualsNode> TYPE = NodeClass.create(IntegerEqualsNode.class);
+    private static final IntegerEqualsOp OP = new IntegerEqualsOp();
 
     public IntegerEqualsNode(ValueNode x, ValueNode y) {
         super(TYPE, Condition.EQ, false, x, y);
@@ -58,165 +63,201 @@
         LogicNode result = CompareNode.tryConstantFoldPrimitive(Condition.EQ, x, y, false);
         if (result != null) {
             return result;
-        } else {
-            if (x instanceof ConditionalNode) {
-                ConditionalNode conditionalNode = (ConditionalNode) x;
-                if (conditionalNode.trueValue() == y) {
-                    return conditionalNode.condition();
-                }
-                if (conditionalNode.falseValue() == y) {
-                    return LogicNegationNode.create(conditionalNode.condition());
-                }
-            } else if (y instanceof ConditionalNode) {
-                ConditionalNode conditionalNode = (ConditionalNode) y;
-                if (conditionalNode.trueValue() == x) {
-                    return conditionalNode.condition();
-                }
-                if (conditionalNode.falseValue() == x) {
-                    return LogicNegationNode.create(conditionalNode.condition());
-                }
+        }
+        if (x instanceof ConditionalNode) {
+            ConditionalNode conditionalNode = (ConditionalNode) x;
+            if (conditionalNode.trueValue() == y) {
+                return conditionalNode.condition();
+            }
+            if (conditionalNode.falseValue() == y) {
+                return LogicNegationNode.create(conditionalNode.condition());
+            }
+        } else if (y instanceof ConditionalNode) {
+            ConditionalNode conditionalNode = (ConditionalNode) y;
+            if (conditionalNode.trueValue() == x) {
+                return conditionalNode.condition();
             }
+            if (conditionalNode.falseValue() == x) {
+                return LogicNegationNode.create(conditionalNode.condition());
+            }
+        }
+        return new IntegerEqualsNode(x, y).maybeCommuteInputs();
+    }
 
-            return new IntegerEqualsNode(x, y).maybeCommuteInputs();
+    public static LogicNode create(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, ValueNode x, ValueNode y) {
+        LogicNode value = OP.canonical(constantReflection, metaAccess, options, smallestCompareWidth, Condition.EQ, false, x, y);
+        if (value != null) {
+            return value;
         }
+        return create(x, y);
     }
 
     @Override
-    protected ValueNode optimizeNormalizeCmp(Constant constant, NormalizeCompareNode normalizeNode, boolean mirrored) {
-        PrimitiveConstant primitive = (PrimitiveConstant) constant;
-        if (primitive.getJavaKind() == JavaKind.Int && primitive.asInt() == 0) {
-            ValueNode a = mirrored ? normalizeNode.getY() : normalizeNode.getX();
-            ValueNode b = mirrored ? normalizeNode.getX() : normalizeNode.getY();
-
-            if (normalizeNode.getX().getStackKind() == JavaKind.Double || normalizeNode.getX().getStackKind() == JavaKind.Float) {
-                return new FloatEqualsNode(a, b);
-            } else {
-                return new IntegerEqualsNode(a, b);
-            }
+    public Node canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        ValueNode value = OP.canonical(tool.getConstantReflection(), tool.getMetaAccess(), tool.getOptions(), tool.smallestCompareWidth(), Condition.EQ, false, forX, forY);
+        if (value != null) {
+            return value;
         }
         return this;
     }
 
-    @Override
-    protected CompareNode duplicateModified(ValueNode newX, ValueNode newY) {
-        if (newX.stamp() instanceof FloatStamp && newY.stamp() instanceof FloatStamp) {
-            return new FloatEqualsNode(newX, newY);
-        } else if (newX.stamp() instanceof IntegerStamp && newY.stamp() instanceof IntegerStamp) {
-            return new IntegerEqualsNode(newX, newY);
-        } else if (newX.stamp() instanceof AbstractPointerStamp && newY.stamp() instanceof AbstractPointerStamp) {
-            return new IntegerEqualsNode(newX, newY);
-        }
-        throw GraalError.shouldNotReachHere();
-    }
+    public static class IntegerEqualsOp extends CompareOp {
+        @Override
+        protected LogicNode optimizeNormalizeCompare(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth,
+                        Constant constant, NormalizeCompareNode normalizeNode, boolean mirrored) {
+            PrimitiveConstant primitive = (PrimitiveConstant) constant;
+            ValueNode a = normalizeNode.getX();
+            ValueNode b = normalizeNode.getY();
+            long cst = primitive.asLong();
 
-    @Override
-    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
-        if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
-            return LogicConstantNode.tautology();
-        } else if (forX.stamp().alwaysDistinct(forY.stamp())) {
-            return LogicConstantNode.contradiction();
-        }
-        if (forX instanceof AddNode && forY instanceof AddNode) {
-            AddNode addX = (AddNode) forX;
-            AddNode addY = (AddNode) forY;
-            ValueNode v1 = null;
-            ValueNode v2 = null;
-            if (addX.getX() == addY.getX()) {
-                v1 = addX.getY();
-                v2 = addY.getY();
-            } else if (addX.getX() == addY.getY()) {
-                v1 = addX.getY();
-                v2 = addY.getX();
-            } else if (addX.getY() == addY.getX()) {
-                v1 = addX.getX();
-                v2 = addY.getY();
-            } else if (addX.getY() == addY.getY()) {
-                v1 = addX.getX();
-                v2 = addY.getX();
-            }
-            if (v1 != null) {
-                assert v2 != null;
-                return create(v1, v2);
+            if (cst == 0) {
+                if (normalizeNode.getX().getStackKind() == JavaKind.Double || normalizeNode.getX().getStackKind() == JavaKind.Float) {
+                    return FloatEqualsNode.create(constantReflection, metaAccess, options, smallestCompareWidth, a, b);
+                } else {
+                    return IntegerEqualsNode.create(constantReflection, metaAccess, options, smallestCompareWidth, a, b);
+                }
+            } else if (cst == 1) {
+                if (normalizeNode.getX().getStackKind() == JavaKind.Double || normalizeNode.getX().getStackKind() == JavaKind.Float) {
+                    return FloatLessThanNode.create(b, a, !normalizeNode.isUnorderedLess);
+                } else {
+                    return IntegerLessThanNode.create(constantReflection, metaAccess, options, smallestCompareWidth, b, a);
+                }
+            } else if (cst == -1) {
+                if (normalizeNode.getX().getStackKind() == JavaKind.Double || normalizeNode.getX().getStackKind() == JavaKind.Float) {
+                    return FloatLessThanNode.create(a, b, normalizeNode.isUnorderedLess);
+                } else {
+                    return IntegerLessThanNode.create(constantReflection, metaAccess, options, smallestCompareWidth, a, b);
+                }
+            } else {
+                return LogicConstantNode.contradiction();
             }
         }
-        return super.canonical(tool, forX, forY);
-    }
+
+        @Override
+        protected CompareNode duplicateModified(ValueNode newX, ValueNode newY, boolean unorderedIsTrue) {
+            if (newX.stamp() instanceof FloatStamp && newY.stamp() instanceof FloatStamp) {
+                return new FloatEqualsNode(newX, newY);
+            } else if (newX.stamp() instanceof IntegerStamp && newY.stamp() instanceof IntegerStamp) {
+                return new IntegerEqualsNode(newX, newY);
+            } else if (newX.stamp() instanceof AbstractPointerStamp && newY.stamp() instanceof AbstractPointerStamp) {
+                return new IntegerEqualsNode(newX, newY);
+            }
+            throw GraalError.shouldNotReachHere();
+        }
+
+        @Override
+        public LogicNode canonical(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, Condition condition,
+                        boolean unorderedIsTrue, ValueNode forX, ValueNode forY) {
+            if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
+                return LogicConstantNode.tautology();
+            } else if (forX.stamp().alwaysDistinct(forY.stamp())) {
+                return LogicConstantNode.contradiction();
+            }
+            if (forX instanceof AddNode && forY instanceof AddNode) {
+                AddNode addX = (AddNode) forX;
+                AddNode addY = (AddNode) forY;
+                ValueNode v1 = null;
+                ValueNode v2 = null;
+                if (addX.getX() == addY.getX()) {
+                    v1 = addX.getY();
+                    v2 = addY.getY();
+                } else if (addX.getX() == addY.getY()) {
+                    v1 = addX.getY();
+                    v2 = addY.getX();
+                } else if (addX.getY() == addY.getX()) {
+                    v1 = addX.getX();
+                    v2 = addY.getY();
+                } else if (addX.getY() == addY.getY()) {
+                    v1 = addX.getX();
+                    v2 = addY.getX();
+                }
+                if (v1 != null) {
+                    assert v2 != null;
+                    return create(v1, v2);
+                }
+            }
+            return super.canonical(constantReflection, metaAccess, options, smallestCompareWidth, condition, unorderedIsTrue, forX, forY);
+        }
 
-    @Override
-    protected ValueNode canonicalizeSymmetricConstant(CanonicalizerTool tool, Constant constant, ValueNode nonConstant, boolean mirrored) {
-        if (constant instanceof PrimitiveConstant) {
-            PrimitiveConstant primitiveConstant = (PrimitiveConstant) constant;
-            IntegerStamp nonConstantStamp = ((IntegerStamp) nonConstant.stamp());
-            if ((primitiveConstant.asLong() == 1 && nonConstantStamp.upperBound() == 1 && nonConstantStamp.lowerBound() == 0) ||
-                            (primitiveConstant.asLong() == -1 && nonConstantStamp.upperBound() == 0 && nonConstantStamp.lowerBound() == -1)) {
-                // nonConstant can only be 0 or 1 (respective -1), test against 0 instead of 1
-                // (respective -1) for a more canonical graph and also to allow for faster execution
-                // on specific platforms.
-                return LogicNegationNode.create(IntegerEqualsNode.create(nonConstant, ConstantNode.forIntegerKind(nonConstant.getStackKind(), 0)));
-            } else if (primitiveConstant.asLong() == 0) {
-                if (nonConstant instanceof AndNode) {
-                    AndNode andNode = (AndNode) nonConstant;
-                    return new IntegerTestNode(andNode.getX(), andNode.getY());
-                } else if (nonConstant instanceof SubNode) {
-                    SubNode subNode = (SubNode) nonConstant;
-                    return IntegerEqualsNode.create(subNode.getX(), subNode.getY());
-                } else if (nonConstant instanceof ShiftNode && nonConstant.stamp() instanceof IntegerStamp) {
-                    if (nonConstant instanceof LeftShiftNode) {
-                        LeftShiftNode shift = (LeftShiftNode) nonConstant;
-                        if (shift.getY().isConstant()) {
-                            int mask = shift.getShiftAmountMask();
-                            int amount = shift.getY().asJavaConstant().asInt() & mask;
-                            if (shift.getX().getStackKind() == JavaKind.Int) {
-                                return new IntegerTestNode(shift.getX(), ConstantNode.forInt(-1 >>> amount));
-                            } else {
-                                assert shift.getX().getStackKind() == JavaKind.Long;
-                                return new IntegerTestNode(shift.getX(), ConstantNode.forLong(-1L >>> amount));
+        @Override
+        protected LogicNode canonicalizeSymmetricConstant(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth,
+                        Condition condition, Constant constant, ValueNode nonConstant, boolean mirrored, boolean unorderedIsTrue) {
+            if (constant instanceof PrimitiveConstant) {
+                PrimitiveConstant primitiveConstant = (PrimitiveConstant) constant;
+                IntegerStamp nonConstantStamp = ((IntegerStamp) nonConstant.stamp());
+                if ((primitiveConstant.asLong() == 1 && nonConstantStamp.upperBound() == 1 && nonConstantStamp.lowerBound() == 0) ||
+                                (primitiveConstant.asLong() == -1 && nonConstantStamp.upperBound() == 0 && nonConstantStamp.lowerBound() == -1)) {
+                    // nonConstant can only be 0 or 1 (respective -1), test against 0 instead of 1
+                    // (respective -1) for a more canonical graph and also to allow for faster
+                    // execution
+                    // on specific platforms.
+                    return LogicNegationNode.create(
+                                    IntegerEqualsNode.create(constantReflection, metaAccess, options, smallestCompareWidth, nonConstant, ConstantNode.forIntegerKind(nonConstant.getStackKind(), 0)));
+                } else if (primitiveConstant.asLong() == 0) {
+                    if (nonConstant instanceof AndNode) {
+                        AndNode andNode = (AndNode) nonConstant;
+                        return new IntegerTestNode(andNode.getX(), andNode.getY());
+                    } else if (nonConstant instanceof SubNode) {
+                        SubNode subNode = (SubNode) nonConstant;
+                        return IntegerEqualsNode.create(constantReflection, metaAccess, options, smallestCompareWidth, subNode.getX(), subNode.getY());
+                    } else if (nonConstant instanceof ShiftNode && nonConstant.stamp() instanceof IntegerStamp) {
+                        if (nonConstant instanceof LeftShiftNode) {
+                            LeftShiftNode shift = (LeftShiftNode) nonConstant;
+                            if (shift.getY().isConstant()) {
+                                int mask = shift.getShiftAmountMask();
+                                int amount = shift.getY().asJavaConstant().asInt() & mask;
+                                if (shift.getX().getStackKind() == JavaKind.Int) {
+                                    return new IntegerTestNode(shift.getX(), ConstantNode.forInt(-1 >>> amount));
+                                } else {
+                                    assert shift.getX().getStackKind() == JavaKind.Long;
+                                    return new IntegerTestNode(shift.getX(), ConstantNode.forLong(-1L >>> amount));
+                                }
                             }
-                        }
-                    } else if (nonConstant instanceof RightShiftNode) {
-                        RightShiftNode shift = (RightShiftNode) nonConstant;
-                        if (shift.getY().isConstant() && ((IntegerStamp) shift.getX().stamp()).isPositive()) {
-                            int mask = shift.getShiftAmountMask();
-                            int amount = shift.getY().asJavaConstant().asInt() & mask;
-                            if (shift.getX().getStackKind() == JavaKind.Int) {
-                                return new IntegerTestNode(shift.getX(), ConstantNode.forInt(-1 << amount));
-                            } else {
-                                assert shift.getX().getStackKind() == JavaKind.Long;
-                                return new IntegerTestNode(shift.getX(), ConstantNode.forLong(-1L << amount));
+                        } else if (nonConstant instanceof RightShiftNode) {
+                            RightShiftNode shift = (RightShiftNode) nonConstant;
+                            if (shift.getY().isConstant() && ((IntegerStamp) shift.getX().stamp()).isPositive()) {
+                                int mask = shift.getShiftAmountMask();
+                                int amount = shift.getY().asJavaConstant().asInt() & mask;
+                                if (shift.getX().getStackKind() == JavaKind.Int) {
+                                    return new IntegerTestNode(shift.getX(), ConstantNode.forInt(-1 << amount));
+                                } else {
+                                    assert shift.getX().getStackKind() == JavaKind.Long;
+                                    return new IntegerTestNode(shift.getX(), ConstantNode.forLong(-1L << amount));
+                                }
                             }
-                        }
-                    } else if (nonConstant instanceof UnsignedRightShiftNode) {
-                        UnsignedRightShiftNode shift = (UnsignedRightShiftNode) nonConstant;
-                        if (shift.getY().isConstant()) {
-                            int mask = shift.getShiftAmountMask();
-                            int amount = shift.getY().asJavaConstant().asInt() & mask;
-                            if (shift.getX().getStackKind() == JavaKind.Int) {
-                                return new IntegerTestNode(shift.getX(), ConstantNode.forInt(-1 << amount));
-                            } else {
-                                assert shift.getX().getStackKind() == JavaKind.Long;
-                                return new IntegerTestNode(shift.getX(), ConstantNode.forLong(-1L << amount));
+                        } else if (nonConstant instanceof UnsignedRightShiftNode) {
+                            UnsignedRightShiftNode shift = (UnsignedRightShiftNode) nonConstant;
+                            if (shift.getY().isConstant()) {
+                                int mask = shift.getShiftAmountMask();
+                                int amount = shift.getY().asJavaConstant().asInt() & mask;
+                                if (shift.getX().getStackKind() == JavaKind.Int) {
+                                    return new IntegerTestNode(shift.getX(), ConstantNode.forInt(-1 << amount));
+                                } else {
+                                    assert shift.getX().getStackKind() == JavaKind.Long;
+                                    return new IntegerTestNode(shift.getX(), ConstantNode.forLong(-1L << amount));
+                                }
                             }
                         }
                     }
                 }
-            }
-            if (nonConstant instanceof AddNode) {
-                AddNode addNode = (AddNode) nonConstant;
-                if (addNode.getY().isJavaConstant()) {
-                    return new IntegerEqualsNode(addNode.getX(), ConstantNode.forIntegerStamp(nonConstantStamp, primitiveConstant.asLong() - addNode.getY().asJavaConstant().asLong()));
+                if (nonConstant instanceof AddNode) {
+                    AddNode addNode = (AddNode) nonConstant;
+                    if (addNode.getY().isJavaConstant()) {
+                        return new IntegerEqualsNode(addNode.getX(), ConstantNode.forIntegerStamp(nonConstantStamp, primitiveConstant.asLong() - addNode.getY().asJavaConstant().asLong()));
+                    }
+                }
+                if (nonConstant instanceof AndNode) {
+                    /*
+                     * a & c == c is the same as a & c != 0, if c is a single bit.
+                     */
+                    AndNode andNode = (AndNode) nonConstant;
+                    if (Long.bitCount(((PrimitiveConstant) constant).asLong()) == 1 && andNode.getY().isConstant() && andNode.getY().asJavaConstant().equals(constant)) {
+                        return new LogicNegationNode(new IntegerTestNode(andNode.getX(), andNode.getY()));
+                    }
                 }
             }
-            if (nonConstant instanceof AndNode) {
-                /*
-                 * a & c == c is the same as a & c != 0, if c is a single bit.
-                 */
-                AndNode andNode = (AndNode) nonConstant;
-                if (Long.bitCount(((PrimitiveConstant) constant).asLong()) == 1 && andNode.getY().isConstant() && andNode.getY().asJavaConstant().equals(constant)) {
-                    return new LogicNegationNode(new IntegerTestNode(andNode.getX(), andNode.getY()));
-                }
-            }
+            return super.canonicalizeSymmetricConstant(constantReflection, metaAccess, options, smallestCompareWidth, condition, constant, nonConstant, mirrored, unorderedIsTrue);
         }
-        return super.canonicalizeSymmetricConstant(tool, constant, nonConstant, mirrored);
     }
 
     @Override
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerLessThanNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerLessThanNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -24,15 +24,20 @@
 
 import static org.graalvm.compiler.core.common.calc.Condition.LT;
 
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
 import org.graalvm.compiler.core.common.NumUtil;
 import org.graalvm.compiler.core.common.calc.Condition;
 import org.graalvm.compiler.core.common.type.FloatStamp;
 import org.graalvm.compiler.core.common.type.IntegerStamp;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
 import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.LogicConstantNode;
 import org.graalvm.compiler.nodes.LogicNegationNode;
 import org.graalvm.compiler.nodes.LogicNode;
 import org.graalvm.compiler.nodes.ValueNode;
@@ -42,6 +47,7 @@
 import jdk.vm.ci.meta.JavaConstant;
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.PrimitiveConstant;
+import org.graalvm.compiler.options.OptionValues;
 
 @NodeInfo(shortName = "<")
 public final class IntegerLessThanNode extends IntegerLowerThanNode {
@@ -58,19 +64,20 @@
         return OP.create(x, y);
     }
 
+    public static LogicNode create(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth,
+                    ValueNode x, ValueNode y) {
+        LogicNode value = OP.canonical(constantReflection, metaAccess, options, smallestCompareWidth, OP.getCondition(), false, x, y);
+        if (value != null) {
+            return value;
+        }
+        return create(x, y);
+    }
+
     @Override
-    protected ValueNode optimizeNormalizeCmp(Constant constant, NormalizeCompareNode normalizeNode, boolean mirrored) {
-        PrimitiveConstant primitive = (PrimitiveConstant) constant;
-        assert condition() == LT;
-        if (primitive.getJavaKind() == JavaKind.Int && primitive.asInt() == 0) {
-            ValueNode a = mirrored ? normalizeNode.getY() : normalizeNode.getX();
-            ValueNode b = mirrored ? normalizeNode.getX() : normalizeNode.getY();
-
-            if (normalizeNode.getX().getStackKind() == JavaKind.Double || normalizeNode.getX().getStackKind() == JavaKind.Float) {
-                return new FloatLessThanNode(a, b, mirrored ^ normalizeNode.isUnorderedLess);
-            } else {
-                return new IntegerLessThanNode(a, b);
-            }
+    public Node canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        ValueNode value = OP.canonical(tool.getConstantReflection(), tool.getMetaAccess(), tool.getOptions(), tool.smallestCompareWidth(), OP.getCondition(), false, forX, forY);
+        if (value != null) {
+            return value;
         }
         return this;
     }
@@ -89,17 +96,69 @@
         return (((x ^ y) & (x ^ r)) < 0) || r > maxValue;
     }
 
-    @Override
-    protected CompareNode duplicateModified(ValueNode newX, ValueNode newY) {
-        if (newX.stamp() instanceof FloatStamp && newY.stamp() instanceof FloatStamp) {
-            return new FloatLessThanNode(newX, newY, true);
-        } else if (newX.stamp() instanceof IntegerStamp && newY.stamp() instanceof IntegerStamp) {
-            return new IntegerLessThanNode(newX, newY);
+    public static class LessThanOp extends LowerOp {
+        @Override
+        protected CompareNode duplicateModified(ValueNode newX, ValueNode newY, boolean unorderedIsTrue) {
+            if (newX.stamp() instanceof FloatStamp && newY.stamp() instanceof FloatStamp) {
+                return new FloatLessThanNode(newX, newY, unorderedIsTrue); // TODO: Is the last arg
+                                                                           // supposed to be true?
+            } else if (newX.stamp() instanceof IntegerStamp && newY.stamp() instanceof IntegerStamp) {
+                return new IntegerLessThanNode(newX, newY);
+            }
+            throw GraalError.shouldNotReachHere();
         }
-        throw GraalError.shouldNotReachHere();
-    }
 
-    public static class LessThanOp extends LowerOp {
+        @Override
+        protected LogicNode optimizeNormalizeCompare(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth,
+                        Constant constant, NormalizeCompareNode normalizeNode, boolean mirrored) {
+            PrimitiveConstant primitive = (PrimitiveConstant) constant;
+            /* @formatter:off
+             * a NC b < c  (not mirrored)
+             * cases for c:
+             *  0         -> a < b
+             *  [MIN, -1] -> false
+             *  1         -> a <= b
+             *  [2, MAX]  -> true
+             * unordered-is-less means unordered-is-true.
+             *
+             * c < a NC b  (mirrored)
+             * cases for c:
+             *  0         -> a > b
+             *  [1, MAX]  -> false
+             *  -1        -> a >= b
+             *  [MIN, -2] -> true
+             * unordered-is-less means unordered-is-false.
+             *
+             *  We can handle mirroring by swapping a & b and negating the constant.
+             *  @formatter:on
+             */
+            ValueNode a = mirrored ? normalizeNode.getY() : normalizeNode.getX();
+            ValueNode b = mirrored ? normalizeNode.getX() : normalizeNode.getY();
+            long cst = mirrored ? -primitive.asLong() : primitive.asLong();
+
+            if (cst == 0) {
+                if (normalizeNode.getX().getStackKind() == JavaKind.Double || normalizeNode.getX().getStackKind() == JavaKind.Float) {
+                    return FloatLessThanNode.create(constantReflection, metaAccess, options, smallestCompareWidth, a, b, mirrored ^ normalizeNode.isUnorderedLess);
+                } else {
+                    return IntegerLessThanNode.create(constantReflection, metaAccess, options, smallestCompareWidth, a, b);
+                }
+            } else if (cst == 1) {
+                // a <= b <=> !(a > b)
+                LogicNode compare;
+                if (normalizeNode.getX().getStackKind() == JavaKind.Double || normalizeNode.getX().getStackKind() == JavaKind.Float) {
+                    // since we negate, we have to reverse the unordered result
+                    compare = FloatLessThanNode.create(constantReflection, metaAccess, options, smallestCompareWidth, b, a, mirrored == normalizeNode.isUnorderedLess);
+                } else {
+                    compare = IntegerLessThanNode.create(constantReflection, metaAccess, options, smallestCompareWidth, b, a);
+                }
+                return LogicNegationNode.create(compare);
+            } else if (cst <= -1) {
+                return LogicConstantNode.contradiction();
+            } else {
+                assert cst >= 2;
+                return LogicConstantNode.tautology();
+            }
+        }
 
         @Override
         protected LogicNode findSynonym(ValueNode forX, ValueNode forY) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerLowerThanNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerLowerThanNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,11 +22,12 @@
  */
 package org.graalvm.compiler.nodes.calc;
 
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
 import org.graalvm.compiler.core.common.calc.Condition;
 import org.graalvm.compiler.core.common.type.IntegerStamp;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.graph.NodeClass;
-import org.graalvm.compiler.graph.spi.CanonicalizerTool;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
 import org.graalvm.compiler.nodes.ConstantNode;
 import org.graalvm.compiler.nodes.LogicConstantNode;
@@ -36,6 +37,7 @@
 import org.graalvm.compiler.nodes.util.GraphUtil;
 
 import jdk.vm.ci.meta.TriState;
+import org.graalvm.compiler.options.OptionValues;
 
 /**
  * Common super-class for "a < b" comparisons both {@linkplain IntegerLowerThanNode signed} and
@@ -56,19 +58,6 @@
     }
 
     @Override
-    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
-        ValueNode result = super.canonical(tool, forX, forY);
-        if (result != this) {
-            return result;
-        }
-        LogicNode synonym = getOp().findSynonym(forX, forY);
-        if (synonym != null) {
-            return synonym;
-        }
-        return this;
-    }
-
-    @Override
     public Stamp getSucceedingStampForX(boolean negated, Stamp xStampGeneric, Stamp yStampGeneric) {
         return getSucceedingStampForX(negated, !negated, xStampGeneric, yStampGeneric, getX(), getY());
     }
@@ -125,7 +114,21 @@
         return getOp().tryFold(xStampGeneric, yStampGeneric);
     }
 
-    public abstract static class LowerOp {
+    public abstract static class LowerOp extends CompareOp {
+        @Override
+        public LogicNode canonical(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, Condition condition,
+                        boolean unorderedIsTrue, ValueNode forX, ValueNode forY) {
+            LogicNode result = super.canonical(constantReflection, metaAccess, options, smallestCompareWidth, condition, unorderedIsTrue, forX, forY);
+            if (result != null) {
+                return result;
+            }
+            LogicNode synonym = findSynonym(forX, forY);
+            if (synonym != null) {
+                return synonym;
+            }
+            return null;
+        }
+
         protected abstract long upperBound(IntegerStamp stamp);
 
         protected abstract long lowerBound(IntegerStamp stamp);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/MulNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/MulNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,6 +22,8 @@
  */
 package org.graalvm.compiler.nodes.calc;
 
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+
 import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp;
 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Mul;
@@ -30,7 +32,6 @@
 import org.graalvm.compiler.graph.spi.Canonicalizable.BinaryCommutative;
 import org.graalvm.compiler.graph.spi.CanonicalizerTool;
 import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
-import org.graalvm.compiler.nodeinfo.NodeCycles;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
 import org.graalvm.compiler.nodes.ConstantNode;
 import org.graalvm.compiler.nodes.ValueNode;
@@ -41,7 +42,7 @@
 import jdk.vm.ci.meta.PrimitiveConstant;
 import jdk.vm.ci.meta.Value;
 
-@NodeInfo(shortName = "*", cycles = NodeCycles.CYCLES_3)
+@NodeInfo(shortName = "*", cycles = CYCLES_2)
 public class MulNode extends BinaryArithmeticNode<Mul> implements NarrowableArithmeticNode, BinaryCommutative<ValueNode> {
 
     public static final NodeClass<MulNode> TYPE = NodeClass.create(MulNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NormalizeCompareNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NormalizeCompareNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,6 +22,8 @@
  */
 package org.graalvm.compiler.nodes.calc;
 
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
+
 import org.graalvm.compiler.core.common.calc.Condition;
 import org.graalvm.compiler.core.common.type.FloatStamp;
 import org.graalvm.compiler.core.common.type.Stamp;
@@ -30,7 +32,6 @@
 import org.graalvm.compiler.graph.spi.CanonicalizerTool;
 import org.graalvm.compiler.nodeinfo.NodeCycles;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
-import org.graalvm.compiler.nodeinfo.NodeSize;
 import org.graalvm.compiler.nodes.ConstantNode;
 import org.graalvm.compiler.nodes.LogicConstantNode;
 import org.graalvm.compiler.nodes.LogicNode;
@@ -46,7 +47,7 @@
  * of the inputs is NaN), the result is 1 if isUnorderedLess is false and -1 if isUnorderedLess is
  * true.
  */
-@NodeInfo(cycles = NodeCycles.CYCLES_2, size = NodeSize.SIZE_4)
+@NodeInfo(cycles = NodeCycles.CYCLES_2, size = SIZE_2)
 public final class NormalizeCompareNode extends BinaryNode implements Lowerable {
 
     public static final NodeClass<NormalizeCompareNode> TYPE = NodeClass.create(NormalizeCompareNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ObjectEqualsNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ObjectEqualsNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -48,11 +48,13 @@
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.ResolvedJavaType;
+import org.graalvm.compiler.options.OptionValues;
 
 @NodeInfo(shortName = "==")
 public final class ObjectEqualsNode extends PointerEqualsNode implements Virtualizable {
 
     public static final NodeClass<ObjectEqualsNode> TYPE = NodeClass.create(ObjectEqualsNode.class);
+    private static final ObjectEqualsOp OP = new ObjectEqualsOp();
 
     public ObjectEqualsNode(ValueNode x, ValueNode y) {
         super(TYPE, x, y);
@@ -73,19 +75,50 @@
         }
     }
 
+    public static LogicNode create(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, ValueNode x, ValueNode y) {
+        LogicNode result = OP.canonical(constantReflection, metaAccess, options, null, Condition.EQ, false, x, y);
+        if (result != null) {
+            return result;
+        }
+        return create(x, y, constantReflection);
+    }
+
     @Override
-    protected ValueNode canonicalizeSymmetricConstant(CanonicalizerTool tool, Constant constant, ValueNode nonConstant, boolean mirrored) {
-        ResolvedJavaType type = tool.getConstantReflection().asJavaType(constant);
-        if (type != null && nonConstant instanceof GetClassNode) {
-            GetClassNode getClassNode = (GetClassNode) nonConstant;
-            ValueNode object = getClassNode.getObject();
-            assert ((ObjectStamp) object.stamp()).nonNull();
-            if (!type.isPrimitive() && (type.isConcrete() || type.isArray())) {
-                return InstanceOfNode.create(TypeReference.createExactTrusted(type), object);
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        ValueNode value = OP.canonical(tool.getConstantReflection(), tool.getMetaAccess(), tool.getOptions(), tool.smallestCompareWidth(), Condition.EQ, false, forX, forY);
+        if (value != null) {
+            return value;
+        }
+        return this;
+    }
+
+    public static class ObjectEqualsOp extends PointerEqualsOp {
+
+        @Override
+        protected LogicNode canonicalizeSymmetricConstant(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth,
+                        Condition condition, Constant constant, ValueNode nonConstant, boolean mirrored, boolean unorderedIsTrue) {
+            ResolvedJavaType type = constantReflection.asJavaType(constant);
+            if (type != null && nonConstant instanceof GetClassNode) {
+                GetClassNode getClassNode = (GetClassNode) nonConstant;
+                ValueNode object = getClassNode.getObject();
+                assert ((ObjectStamp) object.stamp()).nonNull();
+                if (!type.isPrimitive() && (type.isConcrete() || type.isArray())) {
+                    return InstanceOfNode.create(TypeReference.createExactTrusted(type), object);
+                }
+                return LogicConstantNode.forBoolean(false);
             }
-            return LogicConstantNode.forBoolean(false);
+            return super.canonicalizeSymmetricConstant(constantReflection, metaAccess, options, smallestCompareWidth, condition, constant, nonConstant, mirrored, unorderedIsTrue);
         }
-        return super.canonicalizeSymmetricConstant(tool, constant, nonConstant, mirrored);
+
+        @Override
+        protected CompareNode duplicateModified(ValueNode newX, ValueNode newY, boolean unorderedIsTrue) {
+            if (newX.stamp() instanceof ObjectStamp && newY.stamp() instanceof ObjectStamp) {
+                return new ObjectEqualsNode(newX, newY);
+            } else if (newX.stamp() instanceof AbstractPointerStamp && newY.stamp() instanceof AbstractPointerStamp) {
+                return new PointerEqualsNode(newX, newY);
+            }
+            throw GraalError.shouldNotReachHere();
+        }
     }
 
     private void virtualizeNonVirtualComparison(VirtualObjectNode virtual, ValueNode other, VirtualizerTool tool) {
@@ -150,14 +183,4 @@
             }
         }
     }
-
-    @Override
-    protected CompareNode duplicateModified(ValueNode newX, ValueNode newY) {
-        if (newX.stamp() instanceof ObjectStamp && newY.stamp() instanceof ObjectStamp) {
-            return new ObjectEqualsNode(newX, newY);
-        } else if (newX.stamp() instanceof AbstractPointerStamp && newY.stamp() instanceof AbstractPointerStamp) {
-            return new PointerEqualsNode(newX, newY);
-        }
-        throw GraalError.shouldNotReachHere();
-    }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/PointerEqualsNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/PointerEqualsNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,10 +22,13 @@
  */
 package org.graalvm.compiler.nodes.calc;
 
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
 import org.graalvm.compiler.core.common.calc.Condition;
 import org.graalvm.compiler.core.common.type.AbstractPointerStamp;
 import org.graalvm.compiler.core.common.type.ObjectStamp;
 import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.graph.spi.Canonicalizable.BinaryCommutative;
 import org.graalvm.compiler.graph.spi.CanonicalizerTool;
@@ -41,11 +44,13 @@
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.meta.ResolvedJavaType;
 import jdk.vm.ci.meta.TriState;
+import org.graalvm.compiler.options.OptionValues;
 
 @NodeInfo(shortName = "==")
 public class PointerEqualsNode extends CompareNode implements BinaryCommutative<ValueNode> {
 
     public static final NodeClass<PointerEqualsNode> TYPE = NodeClass.create(PointerEqualsNode.class);
+    private static final PointerEqualsOp OP = new PointerEqualsOp();
 
     public PointerEqualsNode(ValueNode x, ValueNode y) {
         this(TYPE, x, y);
@@ -65,44 +70,62 @@
         assert y.stamp() instanceof AbstractPointerStamp;
     }
 
-    /**
-     * Determines if this is a comparison used to determine whether dispatching on a receiver could
-     * select a certain method and if so, returns {@code true} if the answer is guaranteed to be
-     * false. Otherwise, returns {@code false}.
-     */
-    private boolean isAlwaysFailingVirtualDispatchTest(ValueNode forX, ValueNode forY) {
-        if (forY.isConstant()) {
-            if (forX instanceof LoadMethodNode && condition == Condition.EQ) {
-                LoadMethodNode lm = ((LoadMethodNode) forX);
-                if (lm.getMethod().getEncoding().equals(forY.asConstant())) {
-                    if (lm.getHub() instanceof LoadHubNode) {
-                        ValueNode object = ((LoadHubNode) lm.getHub()).getValue();
-                        ResolvedJavaType type = StampTool.typeOrNull(object);
-                        ResolvedJavaType declaringClass = lm.getMethod().getDeclaringClass();
-                        if (type != null && !type.equals(declaringClass) && declaringClass.isAssignableFrom(type)) {
-                            ResolvedJavaMethod override = type.resolveMethod(lm.getMethod(), lm.getCallerType());
-                            if (override != null && !override.equals(lm.getMethod())) {
-                                assert declaringClass.isAssignableFrom(override.getDeclaringClass());
-                                return true;
+    @Override
+    public Node canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        ValueNode value = OP.canonical(tool.getConstantReflection(), tool.getMetaAccess(), tool.getOptions(), tool.smallestCompareWidth(), Condition.EQ, false, forX, forY);
+        if (value != null) {
+            return value;
+        }
+        return this;
+    }
+
+    public static class PointerEqualsOp extends CompareOp {
+
+        /**
+         * Determines if this is a comparison used to determine whether dispatching on a receiver
+         * could select a certain method and if so, returns {@code true} if the answer is guaranteed
+         * to be false. Otherwise, returns {@code false}.
+         */
+        private static boolean isAlwaysFailingVirtualDispatchTest(Condition condition, ValueNode forX, ValueNode forY) {
+            if (forY.isConstant()) {
+                if (forX instanceof LoadMethodNode && condition == Condition.EQ) {
+                    LoadMethodNode lm = ((LoadMethodNode) forX);
+                    if (lm.getMethod().getEncoding().equals(forY.asConstant())) {
+                        if (lm.getHub() instanceof LoadHubNode) {
+                            ValueNode object = ((LoadHubNode) lm.getHub()).getValue();
+                            ResolvedJavaType type = StampTool.typeOrNull(object);
+                            ResolvedJavaType declaringClass = lm.getMethod().getDeclaringClass();
+                            if (type != null && !type.equals(declaringClass) && declaringClass.isAssignableFrom(type)) {
+                                ResolvedJavaMethod override = type.resolveMethod(lm.getMethod(), lm.getCallerType());
+                                if (override != null && !override.equals(lm.getMethod())) {
+                                    assert declaringClass.isAssignableFrom(override.getDeclaringClass());
+                                    return true;
+                                }
                             }
                         }
                     }
                 }
             }
+            return false;
         }
-        return false;
-    }
 
-    @Override
-    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
-        LogicNode result = findSynonym(forX, forY);
-        if (result != null) {
-            return result;
+        @Override
+        public LogicNode canonical(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, Condition condition,
+                        boolean unorderedIsTrue, ValueNode forX, ValueNode forY) {
+            LogicNode result = findSynonym(forX, forY);
+            if (result != null) {
+                return result;
+            }
+            if (isAlwaysFailingVirtualDispatchTest(condition, forX, forY)) {
+                return LogicConstantNode.contradiction();
+            }
+            return super.canonical(constantReflection, metaAccess, options, smallestCompareWidth, condition, unorderedIsTrue, forX, forY);
         }
-        if (isAlwaysFailingVirtualDispatchTest(forX, forY)) {
-            return LogicConstantNode.contradiction();
+
+        @Override
+        protected CompareNode duplicateModified(ValueNode newX, ValueNode newY, boolean unorderedIsTrue) {
+            return new PointerEqualsNode(newX, newY);
         }
-        return super.canonical(tool, forX, forY);
     }
 
     public static LogicNode findSynonym(ValueNode forX, ValueNode forY) {
@@ -120,11 +143,6 @@
     }
 
     @Override
-    protected CompareNode duplicateModified(ValueNode newX, ValueNode newY) {
-        return new PointerEqualsNode(newX, newY);
-    }
-
-    @Override
     public Stamp getSucceedingStampForX(boolean negated, Stamp xStamp, Stamp yStamp) {
         if (!negated) {
             Stamp newStamp = xStamp.join(yStamp);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/RemNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/RemNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,18 +22,19 @@
  */
 package org.graalvm.compiler.nodes.calc;
 
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
+
 import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Rem;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
-import org.graalvm.compiler.nodeinfo.NodeCycles;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.spi.Lowerable;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
 
-@NodeInfo(shortName = "%", cycles = NodeCycles.CYCLES_30/* div */)
+@NodeInfo(shortName = "%", cycles = CYCLES_8/* div */)
 public class RemNode extends BinaryArithmeticNode<Rem> implements Lowerable {
 
     public static final NodeClass<RemNode> TYPE = NodeClass.create(RemNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SqrtNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SqrtNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,7 +22,7 @@
  */
 package org.graalvm.compiler.nodes.calc;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_30;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_16;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
 
 import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
@@ -37,7 +37,7 @@
 /**
  * Square root.
  */
-@NodeInfo(cycles = CYCLES_30, size = SIZE_1)
+@NodeInfo(cycles = CYCLES_16, size = SIZE_1)
 public final class SqrtNode extends UnaryArithmeticNode<Sqrt> implements ArithmeticLIRLowerable {
 
     public static final NodeClass<SqrtNode> TYPE = NodeClass.create(SqrtNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/DynamicCounterNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/DynamicCounterNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,8 +22,8 @@
  */
 package org.graalvm.compiler.nodes.debug;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_20;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_10;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
 
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.debug.GraalError;
@@ -47,7 +47,12 @@
  * A unique counter will be created for each unique name passed to the constructor. Depending on the
  * value of withContext, the name of the root method is added to the counter's name.
  */
-@NodeInfo(size = SIZE_10, cycles = CYCLES_20)
+//@formatter:off
+@NodeInfo(size = SIZE_IGNORED,
+          sizeRationale = "Node is a debugging node that should not be used in production.",
+          cycles = CYCLES_IGNORED,
+          cyclesRationale = "Node is a debugging node that should not be used in production.")
+//@formatter:on
 public class DynamicCounterNode extends FixedWithNextNode implements LIRLowerable {
 
     public static final NodeClass<DynamicCounterNode> TYPE = NodeClass.create(DynamicCounterNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/VerifyHeapNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/VerifyHeapNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,8 +22,8 @@
  */
 package org.graalvm.compiler.nodes.debug;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_30;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_50;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
 
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.NodeClass;
@@ -38,7 +38,12 @@
  * A node for platform dependent verification of the Java heap. Intended to be used for debugging
  * heap corruption issues.
  */
-@NodeInfo(cycles = CYCLES_30, size = SIZE_50)
+//@formatter:off
+@NodeInfo(size = SIZE_IGNORED,
+        sizeRationale = "Node is a debugging node that should not be used in production.",
+        cycles = CYCLES_IGNORED,
+        cyclesRationale = "Node is a debugging node that should not be used in production.")
+//@formatter:on
 public final class VerifyHeapNode extends FixedWithNextNode implements Lowerable {
 
     public static final NodeClass<VerifyHeapNode> TYPE = NodeClass.create(VerifyHeapNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BoxNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BoxNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,8 +22,7 @@
  */
 package org.graalvm.compiler.nodes.extended;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_20;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_20;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8;
 
 import java.util.Collections;
 
@@ -32,6 +31,7 @@
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.graph.spi.Canonicalizable;
 import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeCycles;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
 import org.graalvm.compiler.nodes.FixedWithNextNode;
 import org.graalvm.compiler.nodes.ValueNode;
@@ -50,7 +50,7 @@
  * This node represents the boxing of a primitive value. This corresponds to a call to the valueOf
  * methods in Integer, Long, etc.
  */
-@NodeInfo(cycles = CYCLES_20, size = SIZE_20)
+@NodeInfo(cycles = NodeCycles.CYCLES_8, size = SIZE_8)
 public class BoxNode extends FixedWithNextNode implements VirtualizableAllocation, Lowerable, Canonicalizable.Unary<ValueNode> {
 
     public static final NodeClass<BoxNode> TYPE = NodeClass.create(BoxNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BytecodeExceptionNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BytecodeExceptionNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,8 +22,8 @@
  */
 package org.graalvm.compiler.nodes.extended;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_20;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8;
 
 import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
@@ -46,9 +46,9 @@
  * either a {@linkplain ForeignCallDescriptor foreign} call or a pre-allocated exception object.
  */
 // @formatter:off
-@NodeInfo(cycles = CYCLES_UNKNOWN,
+@NodeInfo(cycles = CYCLES_8,
           cyclesRationale = "Node will be lowered to a foreign call.",
-          size = SIZE_20)
+          size = SIZE_8)
 // @formatter:on
 public final class BytecodeExceptionNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single {
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/ForeignCallNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/ForeignCallNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -24,8 +24,8 @@
 
 import static org.graalvm.compiler.nodeinfo.InputType.Memory;
 import static org.graalvm.compiler.nodeinfo.InputType.State;
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_20;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
 
 import java.util.List;
 
@@ -60,9 +60,10 @@
 // @formatter:off
 @NodeInfo(nameTemplate = "ForeignCall#{p#descriptor/s}",
           allowedUsageTypes = Memory,
-          cycles = CYCLES_UNKNOWN,
-          cyclesRationale = "A foreign call is a block box in terms of time spent in the callee.",
-          size = SIZE_20)
+          cycles = CYCLES_2,
+          cyclesRationale = "Rough estimation of the call operation itself.",
+          size = SIZE_2,
+          sizeRationale = "Rough estimation of the call operation itself.")
 // @formatter:on
 public class ForeignCallNode extends AbstractMemoryCheckpoint implements LIRLowerable, DeoptimizingNode.DeoptDuring, MemoryCheckpoint.Multi {
     public static final NodeClass<ForeignCallNode> TYPE = NodeClass.create(ForeignCallNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/LoadMethodNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/LoadMethodNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,7 +22,7 @@
  */
 package org.graalvm.compiler.nodes.extended;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
 
 import org.graalvm.compiler.core.common.type.Stamp;
@@ -49,7 +49,7 @@
 /**
  * Loads a method from the virtual method table of a given hub.
  */
-@NodeInfo(cycles = CYCLES_3, size = SIZE_1)
+@NodeInfo(cycles = CYCLES_2, size = SIZE_1)
 public final class LoadMethodNode extends FixedWithNextNode implements Lowerable, Canonicalizable {
 
     public static final NodeClass<LoadMethodNode> TYPE = NodeClass.create(LoadMethodNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/MembarNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/MembarNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -23,7 +23,7 @@
 package org.graalvm.compiler.nodes.extended;
 
 import static org.graalvm.compiler.nodeinfo.InputType.Memory;
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_20;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
 
 import org.graalvm.compiler.core.common.LocationIdentity;
@@ -38,7 +38,7 @@
 /**
  * Creates a memory barrier.
  */
-@NodeInfo(nameTemplate = "Membar#{p#location/s}", allowedUsageTypes = Memory, cycles = CYCLES_20, size = SIZE_2)
+@NodeInfo(nameTemplate = "Membar#{p#location/s}", allowedUsageTypes = Memory, cycles = CYCLES_2, size = SIZE_2)
 public final class MembarNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Single {
 
     public static final NodeClass<MembarNode> TYPE = NodeClass.create(MembarNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawStoreNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawStoreNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2017, 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
@@ -23,7 +23,7 @@
 package org.graalvm.compiler.nodes.extended;
 
 import static org.graalvm.compiler.nodeinfo.InputType.State;
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
 
 import org.graalvm.compiler.core.common.LocationIdentity;
@@ -51,7 +51,7 @@
  * Store of a value at a location specified as an offset relative to an object. No null check is
  * performed before the store.
  */
-@NodeInfo(cycles = CYCLES_3, size = SIZE_1)
+@NodeInfo(cycles = CYCLES_2, size = SIZE_1)
 public final class RawStoreNode extends UnsafeAccessNode implements StateSplit, Lowerable, Virtualizable, MemoryCheckpoint.Single {
 
     public static final NodeClass<RawStoreNode> TYPE = NodeClass.create(RawStoreNode.class);
@@ -124,8 +124,7 @@
                 int entryIndex = virtual.entryIndexForOffset(off, accessKind());
                 if (entryIndex != -1) {
                     JavaKind entryKind = virtual.entryKind(entryIndex);
-                    ValueNode entry = tool.getEntry(virtual, entryIndex);
-                    if (entry.getStackKind() == value.getStackKind() || entryKind == accessKind()) {
+                    if (entryKind == accessKind() || entryKind == accessKind().getStackKind()) {
                         tool.setVirtualEntry(virtual, entryIndex, value(), true);
                         tool.delete();
                     } else {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/SwitchNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/SwitchNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,7 +22,13 @@
  */
 package org.graalvm.compiler.nodes.extended;
 
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_64;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_64;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
 
 import java.util.Arrays;
@@ -35,7 +41,9 @@
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.graph.NodeSuccessorList;
 import org.graalvm.compiler.graph.spi.SimplifierTool;
+import org.graalvm.compiler.nodeinfo.NodeCycles;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodeinfo.NodeSize;
 import org.graalvm.compiler.nodes.AbstractBeginNode;
 import org.graalvm.compiler.nodes.ControlSplitNode;
 import org.graalvm.compiler.nodes.ValueNode;
@@ -242,4 +250,33 @@
     }
 
     public abstract Stamp getValueStampForSuccessor(AbstractBeginNode beginNode);
+
+    @Override
+    public NodeCycles estimatedNodeCycles() {
+        if (keyCount() == 1) {
+            // if
+            return CYCLES_2;
+        } else if (isSorted()) {
+            // good heuristic
+            return CYCLES_8;
+        } else {
+            // not so good
+            return CYCLES_64;
+        }
+    }
+
+    @Override
+    public NodeSize estimatedNodeSize() {
+        if (keyCount() == 1) {
+            // if
+            return SIZE_2;
+        } else if (isSorted()) {
+            // good heuristic
+            return SIZE_8;
+        } else {
+            // not so good
+            return SIZE_64;
+        }
+    }
+
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnboxNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnboxNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,8 +22,8 @@
  */
 package org.graalvm.compiler.nodes.extended;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_100;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_50;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
 
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.NodeClass;
@@ -46,7 +46,7 @@
 import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.ResolvedJavaType;
 
-@NodeInfo(cycles = CYCLES_100, size = SIZE_50)
+@NodeInfo(cycles = CYCLES_2, size = SIZE_2)
 public final class UnboxNode extends FixedWithNextNode implements Virtualizable, Lowerable, Canonicalizable.Unary<ValueNode> {
 
     public static final NodeClass<UnboxNode> TYPE = NodeClass.create(UnboxNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderContext.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderContext.java	Wed Apr 19 04:10:56 2017 +0000
@@ -107,7 +107,7 @@
             assert !(value instanceof StateSplit) || ((StateSplit) value).stateAfter() != null;
             return value;
         }
-        T equivalentValue = recursiveAppend(value);
+        T equivalentValue = append(value);
         if (equivalentValue instanceof StateSplit) {
             StateSplit stateSplit = (StateSplit) equivalentValue;
             if (stateSplit.stateAfter() == null && stateSplit.hasSideEffect()) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderTool.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderTool.java	Wed Apr 19 04:10:56 2017 +0000
@@ -38,19 +38,12 @@
 public interface GraphBuilderTool {
 
     /**
-     * Raw operation for adding a node to the graph.
-     *
-     * @return either the node added or an equivalent node
-     */
-    <T extends ValueNode> T append(T value);
-
-    /**
      * Adds the given node to the graph and also adds recursively all referenced inputs.
      *
      * @param value the node to be added to the graph
      * @return either the node added or an equivalent node
      */
-    <T extends ValueNode> T recursiveAppend(T value);
+    <T extends ValueNode> T append(T value);
 
     StampProvider getStampProvider();
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AbstractNewObjectNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AbstractNewObjectNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,8 +22,8 @@
  */
 package org.graalvm.compiler.nodes.java;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_20;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_20;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8;
 
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.graph.NodeClass;
@@ -36,7 +36,7 @@
 /**
  * The {@code AbstractNewObjectNode} is the base class for the new instance and new array nodes.
  */
-@NodeInfo(cycles = CYCLES_20, size = SIZE_20)
+@NodeInfo(cycles = CYCLES_8, cyclesRationale = "tlab alloc + header init", size = SIZE_8)
 public abstract class AbstractNewObjectNode extends DeoptimizingFixedWithNextNode implements Lowerable {
 
     public static final NodeClass<AbstractNewObjectNode> TYPE = NodeClass.create(AbstractNewObjectNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AccessFieldNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AccessFieldNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,12 +22,14 @@
  */
 package org.graalvm.compiler.nodes.java;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_15;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_10;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
 
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodeinfo.NodeSize;
 import org.graalvm.compiler.nodeinfo.Verbosity;
 import org.graalvm.compiler.nodes.FixedWithNextNode;
 import org.graalvm.compiler.nodes.ValueNode;
@@ -39,7 +41,7 @@
 /**
  * The base class of all instructions that access fields.
  */
-@NodeInfo(cycles = CYCLES_15, size = SIZE_10)
+@NodeInfo(cycles = CYCLES_2, size = SIZE_1)
 public abstract class AccessFieldNode extends FixedWithNextNode implements Lowerable {
 
     public static final NodeClass<AccessFieldNode> TYPE = NodeClass.create(AccessFieldNode.class);
@@ -110,4 +112,12 @@
         assertTrue((object == null) == isStatic(), "static field must not have object, instance field must have object");
         return super.verify();
     }
+
+    @Override
+    public NodeSize estimatedNodeSize() {
+        if (field.isVolatile()) {
+            return SIZE_2;
+        }
+        return super.estimatedNodeSize();
+    }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AtomicReadAndAddNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AtomicReadAndAddNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -24,8 +24,8 @@
 
 import static org.graalvm.compiler.nodeinfo.InputType.Association;
 import static org.graalvm.compiler.nodeinfo.InputType.Memory;
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_10;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_3;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
 
 import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.core.common.type.StampFactory;
@@ -44,7 +44,7 @@
 /**
  * Represents an atomic read-and-add operation like {@link Unsafe#getAndAddInt(Object, long, int)}.
  */
-@NodeInfo(allowedUsageTypes = Memory, cycles = CYCLES_10, size = SIZE_3)
+@NodeInfo(allowedUsageTypes = Memory, cycles = CYCLES_8, size = SIZE_2)
 public final class AtomicReadAndAddNode extends AbstractMemoryCheckpoint implements LIRLowerable, MemoryCheckpoint.Single {
 
     public static final NodeClass<AtomicReadAndAddNode> TYPE = NodeClass.create(AtomicReadAndAddNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AtomicReadAndWriteNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AtomicReadAndWriteNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,8 +22,8 @@
  */
 package org.graalvm.compiler.nodes.java;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_10;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_4;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
 
 import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.core.common.type.StampFactory;
@@ -42,7 +42,7 @@
  * Represents an atomic read-and-write operation like {@link Unsafe#getAndSetInt(Object, long, int)}
  * .
  */
-@NodeInfo(cycles = CYCLES_10, size = SIZE_4)
+@NodeInfo(cycles = CYCLES_8, size = SIZE_2)
 public final class AtomicReadAndWriteNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single {
 
     public static final NodeClass<AtomicReadAndWriteNode> TYPE = NodeClass.create(AtomicReadAndWriteNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ClassIsAssignableFromNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ClassIsAssignableFromNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,8 +22,8 @@
  */
 package org.graalvm.compiler.nodes.java;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_30;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_30;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_32;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_32;
 
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.graph.Node;
@@ -46,7 +46,7 @@
  * against instances. This is used, for instance, to intrinsify
  * {@link Class#isAssignableFrom(Class)} .
  */
-@NodeInfo(cycles = CYCLES_30, size = SIZE_30)
+@NodeInfo(cycles = CYCLES_32, size = SIZE_32)
 public final class ClassIsAssignableFromNode extends BinaryOpLogicNode implements Canonicalizable.Binary<ValueNode>, Lowerable {
 
     public static final NodeClass<ClassIsAssignableFromNode> TYPE = NodeClass.create(ClassIsAssignableFromNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ExceptionObjectNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ExceptionObjectNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -23,7 +23,7 @@
 package org.graalvm.compiler.nodes.java;
 
 import static org.graalvm.compiler.nodeinfo.InputType.Memory;
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_10;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8;
 
 import org.graalvm.compiler.core.common.LocationIdentity;
@@ -47,7 +47,7 @@
  * The entry to an exception handler with the exception coming from a call (as opposed to a local
  * throw instruction or implicit exception).
  */
-@NodeInfo(allowedUsageTypes = Memory, cycles = CYCLES_10, size = SIZE_8)
+@NodeInfo(allowedUsageTypes = Memory, cycles = CYCLES_8, size = SIZE_8)
 public final class ExceptionObjectNode extends BeginStateSplitNode implements Lowerable, MemoryCheckpoint.Single {
     public static final NodeClass<ExceptionObjectNode> TYPE = NodeClass.create(ExceptionObjectNode.class);
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/FinalFieldBarrierNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/FinalFieldBarrierNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,10 +22,10 @@
  */
 package org.graalvm.compiler.nodes.java;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_20;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
 import static jdk.vm.ci.code.MemoryBarriers.LOAD_STORE;
 import static jdk.vm.ci.code.MemoryBarriers.STORE_STORE;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
 
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.NodeClass;
@@ -39,7 +39,7 @@
 import org.graalvm.compiler.nodes.spi.VirtualizerTool;
 import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
 
-@NodeInfo(cycles = CYCLES_20, size = SIZE_2)
+@NodeInfo(cycles = CYCLES_2, size = SIZE_2)
 public class FinalFieldBarrierNode extends FixedWithNextNode implements Virtualizable, Lowerable {
     public static final NodeClass<FinalFieldBarrierNode> TYPE = NodeClass.create(FinalFieldBarrierNode.class);
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/InstanceOfDynamicNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/InstanceOfDynamicNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,8 +22,8 @@
  */
 package org.graalvm.compiler.nodes.java;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_30;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_30;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_32;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_32;
 
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.core.common.type.TypeReference;
@@ -50,7 +50,7 @@
  * known at compile time. This is used, for instance, to intrinsify {@link Class#isInstance(Object)}
  * .
  */
-@NodeInfo(cycles = CYCLES_30, size = SIZE_30)
+@NodeInfo(cycles = CYCLES_32, size = SIZE_32)
 public class InstanceOfDynamicNode extends BinaryOpLogicNode implements Canonicalizable.Binary<ValueNode>, Lowerable {
     public static final NodeClass<InstanceOfDynamicNode> TYPE = NodeClass.create(InstanceOfDynamicNode.class);
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/InstanceOfNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/InstanceOfNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -23,8 +23,8 @@
 package org.graalvm.compiler.nodes.java;
 
 import static org.graalvm.compiler.nodeinfo.InputType.Anchor;
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_15;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_15;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8;
 
 import org.graalvm.compiler.core.common.type.ObjectStamp;
 import org.graalvm.compiler.core.common.type.Stamp;
@@ -52,7 +52,7 @@
 /**
  * The {@code InstanceOfNode} represents an instanceof test.
  */
-@NodeInfo(cycles = CYCLES_15, size = SIZE_15)
+@NodeInfo(cycles = CYCLES_8, size = SIZE_8)
 public class InstanceOfNode extends UnaryOpLogicNode implements Lowerable, Virtualizable {
     public static final NodeClass<InstanceOfNode> TYPE = NodeClass.create(InstanceOfNode.class);
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoadExceptionObjectNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoadExceptionObjectNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,7 +22,7 @@
  */
 package org.graalvm.compiler.nodes.java;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_10;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8;
 
 import org.graalvm.compiler.core.common.type.Stamp;
@@ -32,7 +32,7 @@
 import org.graalvm.compiler.nodes.spi.Lowerable;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 
-@NodeInfo(cycles = CYCLES_10, size = SIZE_8)
+@NodeInfo(cycles = CYCLES_8, size = SIZE_8)
 public final class LoadExceptionObjectNode extends AbstractStateSplit implements Lowerable {
 
     public static final NodeClass<LoadExceptionObjectNode> TYPE = NodeClass.create(LoadExceptionObjectNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoadFieldNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoadFieldNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -23,6 +23,7 @@
 package org.graalvm.compiler.nodes.java;
 
 import static org.graalvm.compiler.graph.iterators.NodePredicates.isNotA;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
 
 import jdk.vm.ci.meta.ConstantReflectionProvider;
 import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
@@ -32,6 +33,7 @@
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.graph.spi.Canonicalizable;
 import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeCycles;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
 import org.graalvm.compiler.nodes.ConstantNode;
 import org.graalvm.compiler.nodes.DeoptimizeNode;
@@ -195,4 +197,12 @@
         this.updateUsages(object, newObject);
         this.object = newObject;
     }
+
+    @Override
+    public NodeCycles estimatedNodeCycles() {
+        if (field.isVolatile()) {
+            return CYCLES_2;
+        }
+        return super.estimatedNodeCycles();
+    }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LogicCompareAndSwapNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LogicCompareAndSwapNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,7 +22,7 @@
  */
 package org.graalvm.compiler.nodes.java;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_30;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8;
 
 import org.graalvm.compiler.core.common.LIRKind;
@@ -44,7 +44,7 @@
  *
  * This version returns a boolean indicating is the CAS was successful or not.
  */
-@NodeInfo(cycles = CYCLES_30, size = SIZE_8)
+@NodeInfo(cycles = CYCLES_8, size = SIZE_8)
 public final class LogicCompareAndSwapNode extends AbstractCompareAndSwapNode {
     public static final NodeClass<LogicCompareAndSwapNode> TYPE = NodeClass.create(LogicCompareAndSwapNode.class);
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MethodCallTargetNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MethodCallTargetNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -132,8 +132,11 @@
             return targetMethod;
         }
 
-        Assumptions assumptions = receiver.graph().getAssumptions();
-        TypeReference type = StampTool.typeReferenceOrNull(receiver);
+        return devirtualizeCall(invokeKind, targetMethod, contextType, receiver.graph().getAssumptions(), receiver.stamp());
+    }
+
+    public static ResolvedJavaMethod devirtualizeCall(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ResolvedJavaType contextType, Assumptions assumptions, Stamp receiverStamp) {
+        TypeReference type = StampTool.typeReferenceOrNull(receiverStamp);
         if (type == null && invokeKind == InvokeKind.Virtual) {
             // For virtual calls, we are guaranteed to receive a correct receiver type.
             type = TypeReference.createTrusted(assumptions, targetMethod.getDeclaringClass());
@@ -155,7 +158,6 @@
                 return uniqueConcreteMethod.getResult();
             }
         }
-
         return null;
     }
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MonitorEnterNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MonitorEnterNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,8 +22,8 @@
  */
 package org.graalvm.compiler.nodes.java;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_100;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_100;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_64;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_64;
 
 import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.graph.IterableNodeType;
@@ -41,7 +41,7 @@
 /**
  * The {@code MonitorEnterNode} represents the acquisition of a monitor.
  */
-@NodeInfo(cycles = CYCLES_100, size = SIZE_100)
+@NodeInfo(cycles = CYCLES_64, size = SIZE_64)
 public class MonitorEnterNode extends AccessMonitorNode implements Virtualizable, Lowerable, IterableNodeType, MonitorEnter, MemoryCheckpoint.Single {
 
     public static final NodeClass<MonitorEnterNode> TYPE = NodeClass.create(MonitorEnterNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MonitorExitNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MonitorExitNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,8 +22,8 @@
  */
 package org.graalvm.compiler.nodes.java;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_50;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_100;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_64;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_64;
 
 import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.graph.IterableNodeType;
@@ -43,7 +43,7 @@
  * a synchronized method, then the return value of the method will be referenced via the edge
  * {@link #escapedReturnValue}, so that it will be materialized before releasing the monitor.
  */
-@NodeInfo(cycles = CYCLES_50, size = SIZE_100)
+@NodeInfo(cycles = CYCLES_64, size = SIZE_64)
 public final class MonitorExitNode extends AccessMonitorNode implements Virtualizable, Lowerable, IterableNodeType, MonitorExit, MemoryCheckpoint.Single {
 
     public static final NodeClass<MonitorExitNode> TYPE = NodeClass.create(MonitorExitNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/NewMultiArrayNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/NewMultiArrayNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,8 +22,8 @@
  */
 package org.graalvm.compiler.nodes.java;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_50;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_50;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8;
 
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.core.common.type.TypeReference;
@@ -42,7 +42,7 @@
 /**
  * The {@code NewMultiArrayNode} represents an allocation of a multi-dimensional object array.
  */
-@NodeInfo(cycles = CYCLES_50, size = SIZE_50)
+@NodeInfo(cycles = CYCLES_8, size = SIZE_8)
 public class NewMultiArrayNode extends DeoptimizingFixedWithNextNode implements Lowerable, ArrayLengthProvider {
 
     public static final NodeClass<NewMultiArrayNode> TYPE = NodeClass.create(NewMultiArrayNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/RawMonitorEnterNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/RawMonitorEnterNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,8 +22,8 @@
  */
 package org.graalvm.compiler.nodes.java;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_80;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_80;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_64;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_64;
 
 import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.core.common.type.ObjectStamp;
@@ -44,9 +44,9 @@
  * already be non-null and the hub is an additional parameter to the node.
  */
 // @formatter:off
-@NodeInfo(cycles = CYCLES_80,
+@NodeInfo(cycles = CYCLES_64,
           cyclesRationale = "Rough estimation of the enter operation",
-          size = SIZE_80)
+          size = SIZE_64)
 // @formatter:on
 public final class RawMonitorEnterNode extends AccessMonitorNode implements Virtualizable, Lowerable, IterableNodeType, MonitorEnter, MemoryCheckpoint.Single {
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/RegisterFinalizerNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/RegisterFinalizerNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -24,7 +24,7 @@
 
 import static org.graalvm.compiler.nodeinfo.InputType.State;
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_20;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8;
 import static org.graalvm.compiler.nodes.java.ForeignCallDescriptors.REGISTER_FINALIZER;
 
 import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
@@ -54,7 +54,7 @@
 // @formatter:off
 @NodeInfo(cycles = CYCLES_UNKNOWN,
           cyclesRationale = "We cannot estimate the time of a runtime call.",
-          size = SIZE_20,
+          size = SIZE_8,
           sizeRationale = "Rough estimation for register handling & calling")
 // @formatter:on
 public final class RegisterFinalizerNode extends AbstractStateSplit implements Canonicalizable.Unary<ValueNode>, LIRLowerable, Virtualizable, DeoptimizingNode.DeoptAfter {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/StoreFieldNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/StoreFieldNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,9 +22,12 @@
  */
 package org.graalvm.compiler.nodes.java;
 
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
+
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeCycles;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
 import org.graalvm.compiler.nodes.ConstantNode;
 import org.graalvm.compiler.nodes.FrameState;
@@ -103,4 +106,12 @@
     public FrameState getState() {
         return stateAfter;
     }
+
+    @Override
+    public NodeCycles estimatedNodeCycles() {
+        if (field.isVolatile()) {
+            return CYCLES_8;
+        }
+        return super.estimatedNodeCycles();
+    }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/UnsafeCompareAndSwapNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/UnsafeCompareAndSwapNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -24,7 +24,7 @@
 
 import static org.graalvm.compiler.nodeinfo.InputType.Memory;
 import static org.graalvm.compiler.nodeinfo.InputType.Value;
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_30;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8;
 
 import org.graalvm.compiler.core.common.LocationIdentity;
@@ -43,7 +43,7 @@
  * Represents an atomic compare-and-swap operation The result is a boolean that contains whether the
  * value matched the expected value.
  */
-@NodeInfo(allowedUsageTypes = {Value, Memory}, cycles = CYCLES_30, size = SIZE_8)
+@NodeInfo(allowedUsageTypes = {Value, Memory}, cycles = CYCLES_8, size = SIZE_8)
 public final class UnsafeCompareAndSwapNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single {
 
     public static final NodeClass<UnsafeCompareAndSwapNode> TYPE = NodeClass.create(UnsafeCompareAndSwapNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ValueCompareAndSwapNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ValueCompareAndSwapNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,7 +22,7 @@
  */
 package org.graalvm.compiler.nodes.java;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_30;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8;
 
 import org.graalvm.compiler.core.common.LocationIdentity;
@@ -37,7 +37,7 @@
  * A special purpose store node that differs from {@link LogicCompareAndSwapNode} in that it returns
  * either the expected value or the compared against value instead of a boolean.
  */
-@NodeInfo(cycles = CYCLES_30, size = SIZE_8)
+@NodeInfo(cycles = CYCLES_8, size = SIZE_8)
 public final class ValueCompareAndSwapNode extends AbstractCompareAndSwapNode {
     public static final NodeClass<ValueCompareAndSwapNode> TYPE = NodeClass.create(ValueCompareAndSwapNode.class);
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/AbstractWriteNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/AbstractWriteNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,7 +22,7 @@
  */
 package org.graalvm.compiler.nodes.memory;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
 
 import org.graalvm.compiler.core.common.LocationIdentity;
@@ -38,7 +38,7 @@
 import org.graalvm.compiler.nodes.extended.GuardingNode;
 import org.graalvm.compiler.nodes.memory.address.AddressNode;
 
-@NodeInfo(allowedUsageTypes = {InputType.Memory, InputType.Guard}, cycles = CYCLES_3, size = SIZE_1)
+@NodeInfo(allowedUsageTypes = {InputType.Memory, InputType.Guard}, cycles = CYCLES_2, size = SIZE_1)
 public abstract class AbstractWriteNode extends FixedAccessNode implements StateSplit, MemoryCheckpoint.Single, MemoryAccess, GuardingNode {
 
     public static final NodeClass<AbstractWriteNode> TYPE = NodeClass.create(AbstractWriteNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/DefaultNodeCostProvider.java	Tue Apr 18 20:10:55 2017 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,195 +0,0 @@
-/*
- * Copyright (c) 2016, 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 org.graalvm.compiler.nodes.spi;
-
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1;
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_100;
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_15;
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_20;
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_30;
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_4;
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_40;
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_80;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_10;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_100;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_15;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_200;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_30;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_4;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_50;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_6;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_80;
-
-import org.graalvm.compiler.graph.Node;
-import org.graalvm.compiler.nodeinfo.NodeCycles;
-import org.graalvm.compiler.nodeinfo.NodeSize;
-import org.graalvm.compiler.nodes.CallTargetNode;
-import org.graalvm.compiler.nodes.Invoke;
-import org.graalvm.compiler.nodes.LoopEndNode;
-import org.graalvm.compiler.nodes.extended.IntegerSwitchNode;
-import org.graalvm.compiler.nodes.extended.SwitchNode;
-import org.graalvm.compiler.nodes.java.AccessFieldNode;
-import org.graalvm.compiler.nodes.virtual.CommitAllocationNode;
-
-/*
- * Certain node costs can not, based on the meta information encoded in the node properties,
- * be computed before a real node is instantiated. E.g. the type of a call in Java heavily
- * influences the cost of an invocation and thus must be decided dynamically.
- */
-public abstract class DefaultNodeCostProvider implements NodeCostProvider {
-
-    @Override
-    public final int getEstimatedCodeSize(Node n) {
-        return size(n).estimatedCodeSize;
-    }
-
-    @Override
-    public final int getEstimatedCPUCycles(Node n) {
-        return cycles(n).estimatedCPUCycles;
-    }
-
-    @Override
-    public NodeSize size(Node n) {
-        if (n instanceof Invoke) {
-            /*
-             * Code size for the invoke itself is a very weak approximation.
-             */
-            Invoke ivk = (Invoke) n;
-            CallTargetNode mct = ivk.callTarget();
-            switch (mct.invokeKind()) {
-                case Interface:
-                    return SIZE_50;
-                case Special:
-                case Static:
-                    return SIZE_2;
-                case Virtual:
-                    return SIZE_4;
-                default:
-                    break;
-            }
-        } else if (n instanceof CommitAllocationNode) {
-            CommitAllocationNode commit = (CommitAllocationNode) n;
-            /*
-             * very weak approximation, current problem is node size is an enum and we cannot
-             * dynamically instantiate a new case like nrOfAllocs*allocationCodeSize
-             */
-            int nrOfAllocs = commit.getVirtualObjects().size();
-            if (nrOfAllocs < 5) {
-                return SIZE_80;
-            } else if (nrOfAllocs < 10) {
-                return SIZE_100;
-            } else {
-                return SIZE_200;
-            }
-        } else if (n instanceof AccessFieldNode) {
-            if (((AccessFieldNode) n).field().isVolatile()) {
-                // membar size is added
-                return SIZE_10;
-            }
-        } else if (n instanceof LoopEndNode) {
-            if (((LoopEndNode) n).canSafepoint()) {
-                return SIZE_6;
-            }
-        } else if (n instanceof SwitchNode) {
-            SwitchNode x = (SwitchNode) n;
-            int keyCount = x.keyCount();
-            if (keyCount == 0) {
-                return SIZE_1;
-            } else {
-                if (keyCount == 1) {
-                    // if
-                    return SIZE_2;
-                } else if (x instanceof IntegerSwitchNode && x.isSorted()) {
-                    // good heuristic
-                    return SIZE_15;
-                } else {
-                    // not so good
-                    return SIZE_30;
-                }
-            }
-        }
-
-        return n.getNodeClass().size();
-    }
-
-    @Override
-    public NodeCycles cycles(Node n) {
-        if (n instanceof Invoke) {
-            Invoke ivk = (Invoke) n;
-            CallTargetNode mct = ivk.callTarget();
-            switch (mct.invokeKind()) {
-                case Interface:
-                    return CYCLES_100;
-                case Special:
-                case Static:
-                    return CYCLES_2;
-                case Virtual:
-                    return CYCLES_4;
-                default:
-                    break;
-            }
-        } else if (n instanceof CommitAllocationNode) {
-            CommitAllocationNode commit = (CommitAllocationNode) n;
-            /*
-             * very weak approximation, current problem is node cycles is an enum and we cannot
-             * dynamically instantiate a new case like nrOfAllocs*allocationCost
-             */
-            int nrOfAllocs = commit.getVirtualObjects().size();
-            if (nrOfAllocs < 5) {
-                return CYCLES_20;
-            } else if (nrOfAllocs < 10) {
-                return CYCLES_40;
-            } else {
-                return CYCLES_80;
-            }
-        } else if (n instanceof AccessFieldNode) {
-            if (((AccessFieldNode) n).field().isVolatile()) {
-                // membar cycles is added
-                return CYCLES_30;
-            }
-        } else if (n instanceof SwitchNode) {
-            SwitchNode x = (SwitchNode) n;
-            int keyCount = x.keyCount();
-            if (keyCount == 0) {
-                return CYCLES_1;
-            } else {
-                if (keyCount == 1) {
-                    // if
-                    return CYCLES_2;
-                } else if (x instanceof IntegerSwitchNode && x.isSorted()) {
-                    // good heuristic
-                    return CYCLES_15;
-                } else {
-                    // not so good
-                    return CYCLES_30;
-                }
-            }
-        }
-
-        return n.getNodeClass().cycles();
-    }
-
-}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/LoweringProvider.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/LoweringProvider.java	Wed Apr 19 04:10:56 2017 +0000
@@ -46,11 +46,10 @@
     ValueNode reconstructArrayIndex(JavaKind elementKind, AddressNode address);
 
     /**
-     * Indicates whether the target platform supports comparison of integers of a particular bit
-     * width. This check is used by optimizations that might introduce subword compares.
+     * Indicates the smallest width for comparing an integer value on the target platform.
      */
-    default boolean supportSubwordCompare(int bits) {
+    default Integer smallestCompareWidth() {
         // most platforms only support 32 and 64 bit compares
-        return bits >= 32;
+        return 32;
     }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/LoweringTool.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/LoweringTool.java	Wed Apr 19 04:10:56 2017 +0000
@@ -49,8 +49,6 @@
 
     StampProvider getStampProvider();
 
-    NodeCostProvider getNodeCostProvider();
-
     GuardingNode createGuard(FixedNode before, LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action);
 
     GuardingNode createGuard(FixedNode before, LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, JavaConstant speculation, boolean negated);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/NodeCostProvider.java	Tue Apr 18 20:10:55 2017 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 2016, 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 org.graalvm.compiler.nodes.spi;
-
-import org.graalvm.compiler.graph.Node;
-import org.graalvm.compiler.nodeinfo.NodeCycles;
-import org.graalvm.compiler.nodeinfo.NodeInfo;
-import org.graalvm.compiler.nodeinfo.NodeSize;
-
-/**
- * A provider that enables overriding and customization of the {@link NodeCycles} and
- * {@link NodeSize} values for a {@linkplain Node node}.
- */
-public interface NodeCostProvider {
-
-    /**
-     * Gets the estimated size of machine code generated for {@code n}.
-     */
-    int getEstimatedCodeSize(Node n);
-
-    /**
-     * Gets the estimated execution cost for {@code n} in terms of CPU cycles.
-     */
-    int getEstimatedCPUCycles(Node n);
-
-    /**
-     * @see NodeInfo#size()
-     */
-    NodeSize size(Node n);
-
-    /**
-     * @see NodeInfo#cycles()
-     */
-    NodeCycles cycles(Node n);
-
-}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java	Wed Apr 19 04:10:56 2017 +0000
@@ -877,11 +877,11 @@
         }
 
         @Override
-        public boolean supportSubwordCompare(int bits) {
+        public Integer smallestCompareWidth() {
             if (loweringProvider != null) {
-                return loweringProvider.supportSubwordCompare(bits);
+                return loweringProvider.smallestCompareWidth();
             } else {
-                return false;
+                return null;
             }
         }
     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/CommitAllocationNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/CommitAllocationNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -38,11 +38,15 @@
 import org.graalvm.compiler.graph.NodeInputList;
 import org.graalvm.compiler.graph.spi.Simplifiable;
 import org.graalvm.compiler.graph.spi.SimplifierTool;
+import org.graalvm.compiler.nodeinfo.NodeCycles;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodeinfo.NodeSize;
 import org.graalvm.compiler.nodeinfo.Verbosity;
 import org.graalvm.compiler.nodes.FixedWithNextNode;
 import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.java.AbstractNewObjectNode;
 import org.graalvm.compiler.nodes.java.MonitorIdNode;
+import org.graalvm.compiler.nodes.memory.WriteNode;
 import org.graalvm.compiler.nodes.spi.Lowerable;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 import org.graalvm.compiler.nodes.spi.VirtualizableAllocation;
@@ -227,4 +231,28 @@
             ensureVirtual = newEnsureVirtual;
         }
     }
+
+    @Override
+    public NodeCycles estimatedNodeCycles() {
+        List<VirtualObjectNode> v = getVirtualObjects();
+        int fieldWriteCount = 0;
+        for (int i = 0; i < v.size(); i++) {
+            fieldWriteCount += v.get(i).entryCount();
+        }
+        int rawValueWrites = NodeCycles.compute(WriteNode.TYPE.cycles(), fieldWriteCount).value;
+        int rawValuesTlabBumps = AbstractNewObjectNode.TYPE.cycles().value;
+        return NodeCycles.compute(rawValueWrites + rawValuesTlabBumps);
+    }
+
+    @Override
+    public NodeSize estimatedNodeSize() {
+        List<VirtualObjectNode> v = getVirtualObjects();
+        int fieldWriteCount = 0;
+        for (int i = 0; i < v.size(); i++) {
+            fieldWriteCount += v.get(i).entryCount();
+        }
+        int rawValueWrites = NodeSize.compute(WriteNode.TYPE.size(), fieldWriteCount).value;
+        int rawValuesTlabBumps = AbstractNewObjectNode.TYPE.size().value;
+        return NodeSize.compute(rawValueWrites + rawValuesTlabBumps);
+    }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/CanonicalizerPhase.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/CanonicalizerPhase.java	Wed Apr 19 04:10:56 2017 +0000
@@ -180,6 +180,11 @@
         }
 
         @Override
+        public boolean checkContract() {
+            return false;
+        }
+
+        @Override
         protected void run(StructuredGraph graph) {
             boolean wholeGraph = newNodesMark == null || newNodesMark.isStart();
             if (initWorkingSet == null) {
@@ -497,8 +502,8 @@
             }
 
             @Override
-            public boolean supportSubwordCompare(int bits) {
-                return context.getLowerer().supportSubwordCompare(bits);
+            public Integer smallestCompareWidth() {
+                return context.getLowerer().smallestCompareWidth();
             }
 
             @Override
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FixReadsPhase.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FixReadsPhase.java	Wed Apr 19 04:10:56 2017 +0000
@@ -88,6 +88,11 @@
     private boolean replaceInputsWithConstants;
     private Phase schedulePhase;
 
+    @Override
+    public float codeSizeIncrease() {
+        return 2.0f;
+    }
+
     private static class FixReadsClosure extends ScheduledNodeIterator {
 
         @Override
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/LoweringPhase.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/LoweringPhase.java	Wed Apr 19 04:10:56 2017 +0000
@@ -66,7 +66,6 @@
 import org.graalvm.compiler.nodes.spi.Lowerable;
 import org.graalvm.compiler.nodes.spi.LoweringProvider;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
-import org.graalvm.compiler.nodes.spi.NodeCostProvider;
 import org.graalvm.compiler.nodes.spi.Replacements;
 import org.graalvm.compiler.nodes.spi.StampProvider;
 import org.graalvm.compiler.options.OptionValues;
@@ -209,11 +208,6 @@
             return lastFixedNode;
         }
 
-        @Override
-        public NodeCostProvider getNodeCostProvider() {
-            return context.getNodeCostProvider();
-        }
-
         private void setLastFixedNode(FixedWithNextNode n) {
             assert n.isAlive() : n;
             lastFixedNode = n;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java	Wed Apr 19 04:10:56 2017 +0000
@@ -29,7 +29,6 @@
 import java.lang.reflect.Constructor;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.function.Function;
 
 import org.graalvm.compiler.api.replacements.MethodSubstitution;
 import org.graalvm.compiler.core.common.GraalOptions;
@@ -58,9 +57,7 @@
 import org.graalvm.compiler.nodes.BeginNode;
 import org.graalvm.compiler.nodes.CallTargetNode;
 import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
-import org.graalvm.compiler.nodes.ControlSinkNode;
 import org.graalvm.compiler.nodes.DeoptimizeNode;
-import org.graalvm.compiler.nodes.EndNode;
 import org.graalvm.compiler.nodes.FixedGuardNode;
 import org.graalvm.compiler.nodes.FixedNode;
 import org.graalvm.compiler.nodes.FixedWithNextNode;
@@ -72,7 +69,6 @@
 import org.graalvm.compiler.nodes.LogicNode;
 import org.graalvm.compiler.nodes.MergeNode;
 import org.graalvm.compiler.nodes.ParameterNode;
-import org.graalvm.compiler.nodes.PhiNode;
 import org.graalvm.compiler.nodes.PiNode;
 import org.graalvm.compiler.nodes.ReturnNode;
 import org.graalvm.compiler.nodes.StartNode;
@@ -80,7 +76,6 @@
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.UnwindNode;
 import org.graalvm.compiler.nodes.ValueNode;
-import org.graalvm.compiler.nodes.ValuePhiNode;
 import org.graalvm.compiler.nodes.calc.IsNullNode;
 import org.graalvm.compiler.nodes.extended.ForeignCallNode;
 import org.graalvm.compiler.nodes.extended.GuardingNode;
@@ -93,6 +88,7 @@
 import org.graalvm.compiler.nodes.util.GraphUtil;
 import org.graalvm.compiler.phases.common.inlining.info.InlineInfo;
 import org.graalvm.compiler.phases.common.util.HashSetNodeEventListener;
+import org.graalvm.compiler.phases.util.ValueMergeUtil;
 import org.graalvm.util.EconomicMap;
 import org.graalvm.util.EconomicSet;
 import org.graalvm.util.Equivalence;
@@ -108,7 +104,7 @@
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.meta.ResolvedJavaType;
 
-public class InliningUtil {
+public class InliningUtil extends ValueMergeUtil {
 
     private static final String inliningDecisionsScopeString = "InliningDecisions";
 
@@ -686,48 +682,6 @@
         return nonReplaceableFrameState;
     }
 
-    public static ValueNode mergeReturns(AbstractMergeNode merge, List<? extends ReturnNode> returnNodes) {
-        return mergeValueProducers(merge, returnNodes, returnNode -> returnNode.result());
-    }
-
-    public static <T extends ControlSinkNode> ValueNode mergeValueProducers(AbstractMergeNode merge, List<? extends T> valueProducers, Function<T, ValueNode> valueFunction) {
-        ValueNode singleResult = null;
-        PhiNode phiResult = null;
-        for (T valueProducer : valueProducers) {
-            ValueNode result = valueFunction.apply(valueProducer);
-            if (result != null) {
-                if (phiResult == null && (singleResult == null || singleResult == result)) {
-                    /* Only one result value, so no need yet for a phi node. */
-                    singleResult = result;
-                } else if (phiResult == null) {
-                    /* Found a second result value, so create phi node. */
-                    phiResult = merge.graph().addWithoutUnique(new ValuePhiNode(result.stamp().unrestricted(), merge));
-                    for (int i = 0; i < merge.forwardEndCount(); i++) {
-                        phiResult.addInput(singleResult);
-                    }
-                    phiResult.addInput(result);
-
-                } else {
-                    /* Multiple return values, just add to existing phi node. */
-                    phiResult.addInput(result);
-                }
-            }
-
-            // create and wire up a new EndNode
-            EndNode endNode = merge.graph().add(new EndNode());
-            merge.addForwardEnd(endNode);
-            valueProducer.replaceAndDelete(endNode);
-        }
-
-        if (phiResult != null) {
-            assert phiResult.verify();
-            phiResult.inferStamp();
-            return phiResult;
-        } else {
-            return singleResult;
-        }
-    }
-
     /**
      * Ensure that all states are either {@link BytecodeFrame#INVALID_FRAMESTATE_BCI} or one of
      * {@link BytecodeFrame#AFTER_BCI} or {@link BytecodeFrame#BEFORE_BCI}. Mixing of before and
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/BasePhase.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/BasePhase.java	Wed Apr 19 04:10:56 2017 +0000
@@ -40,7 +40,6 @@
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.phases.contract.NodeCostUtil;
 import org.graalvm.compiler.phases.contract.PhaseSizeContract;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 
 /**
  * Base class for all compiler phases. Subclasses should be stateless. There will be one global
@@ -193,10 +192,8 @@
             OptionValues options = graph.getOptions();
             boolean verifySizeContract = PhaseOptions.VerifyGraalPhasesSize.getValue(options) && checkContract();
             if (verifySizeContract) {
-                if (context instanceof PhaseContext) {
-                    sizeBefore = NodeCostUtil.computeGraphSize(graph, ((PhaseContext) context).getNodeCostProvider());
-                    before = graph.getMark();
-                }
+                sizeBefore = NodeCostUtil.computeGraphSize(graph);
+                before = graph.getMark();
             }
             BasePhase<?> enclosingPhase = null;
             if (dumpGraph && Debug.isEnabled()) {
@@ -206,11 +203,9 @@
             this.run(graph, context);
             executionCount.increment();
             if (verifySizeContract) {
-                if (context instanceof PhaseContext) {
-                    if (!before.isCurrent()) {
-                        int sizeAfter = NodeCostUtil.computeGraphSize(graph, ((PhaseContext) context).getNodeCostProvider());
-                        NodeCostUtil.phaseFulfillsSizeContract(graph, sizeBefore, sizeAfter, this);
-                    }
+                if (!before.isCurrent()) {
+                    int sizeAfter = NodeCostUtil.computeGraphSize(graph);
+                    NodeCostUtil.phaseFulfillsSizeContract(graph, sizeBefore, sizeAfter, this);
                 }
             }
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/contract/NodeCostUtil.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/contract/NodeCostUtil.java	Wed Apr 19 04:10:56 2017 +0000
@@ -35,7 +35,6 @@
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.cfg.Block;
 import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
-import org.graalvm.compiler.nodes.spi.NodeCostProvider;
 import org.graalvm.compiler.phases.schedule.SchedulePhase;
 
 import jdk.vm.ci.meta.ResolvedJavaMethod;
@@ -46,18 +45,18 @@
     private static final DebugCounter sizeVerificationCount = Debug.counter("GraphCostVerificationCount_Size");
 
     @SuppressWarnings("try")
-    public static int computeGraphSize(StructuredGraph graph, NodeCostProvider nodeCostProvider) {
+    public static int computeGraphSize(StructuredGraph graph) {
         sizeComputationCount.increment();
         int size = 0;
         for (Node n : graph.getNodes()) {
-            size += nodeCostProvider.getEstimatedCodeSize(n);
+            size += n.estimatedNodeSize().value;
         }
         assert size >= 0;
         return size;
     }
 
     @SuppressWarnings("try")
-    public static double computeGraphCycles(StructuredGraph graph, NodeCostProvider nodeCostProvider, boolean fullSchedule) {
+    public static double computeGraphCycles(StructuredGraph graph, boolean fullSchedule) {
         Function<Block, Iterable<? extends Node>> blockToNodes;
         ControlFlowGraph cfg;
         if (fullSchedule) {
@@ -81,12 +80,12 @@
         try (Debug.Scope s = Debug.scope("NodeCostSummary")) {
             for (Block block : cfg.getBlocks()) {
                 for (Node n : blockToNodes.apply(block)) {
-                    double probWeighted = nodeCostProvider.getEstimatedCPUCycles(n) * block.probability();
+                    double probWeighted = n.estimatedNodeCycles().value * block.probability();
                     assert Double.isFinite(probWeighted);
                     weightedCycles += probWeighted;
                     if (Debug.isLogEnabled()) {
-                        Debug.log("Node %s contributes cycles:%f size:%d to graph %s [block prob:%f]", n, nodeCostProvider.getEstimatedCPUCycles(n) * block.probability(),
-                                        nodeCostProvider.getEstimatedCodeSize(n), graph, block.probability());
+                        Debug.log("Node %s contributes cycles:%f size:%d to graph %s [block prob:%f]", n, n.estimatedNodeCycles().value * block.probability(),
+                                        n.estimatedNodeSize().value, graph, block.probability());
                     }
                 }
             }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/contract/VerifyNodeCosts.java	Wed Apr 19 04:10:56 2017 +0000
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2017, 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 org.graalvm.compiler.phases.contract;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.function.Predicate;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeCycles;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodeinfo.NodeSize;
+import org.graalvm.compiler.phases.VerifyPhase;
+
+/**
+ * Utility class that verifies that every {@link Class} extending {@link Node} specifies non default
+ * values for {@link NodeCycles} and {@link NodeSize} in its {@link NodeInfo} annotation.
+ */
+public class VerifyNodeCosts {
+
+    public static void verifyNodeClass(Class<?> clazz) {
+        Class<?> nodeClass = Node.class;
+        if (nodeClass.isAssignableFrom(clazz)) {
+            if (!clazz.isAnnotationPresent(NodeInfo.class)) {
+                throw new VerifyPhase.VerificationError("%s.java extends Node.java but does not specify a NodeInfo annotation.", clazz.getName());
+            }
+
+            if (!Modifier.isAbstract(clazz.getModifiers())) {
+                boolean cyclesSet = walkCHUntil(getType(clazz), getType(nodeClass), cur -> {
+                    return cur.cycles() != NodeCycles.CYCLES_UNSET;
+                });
+                boolean sizeSet = walkCHUntil(getType(clazz), getType(nodeClass), cur -> {
+                    return cur.size() != NodeSize.SIZE_UNSET;
+                });
+                if (!cyclesSet) {
+                    throw new VerifyPhase.VerificationError("%s.java does not specify a NodeCycles value in its class hierarchy.", clazz.getName());
+                }
+                if (!sizeSet) {
+                    throw new VerifyPhase.VerificationError("%s.java does not specify a NodeSize value in its class hierarchy.", clazz.getName());
+                }
+            }
+        }
+    }
+
+    private static NodeClass<?> getType(Class<?> c) {
+        Field f;
+        try {
+            f = c.getField("TYPE");
+            f.setAccessible(true);
+            Object val = f.get(null);
+            NodeClass<?> nodeType = (NodeClass<?>) val;
+            return nodeType;
+        } catch (Throwable t) {
+            throw new VerifyPhase.VerificationError("%s.java does not specify a TYPE field.", c.getName());
+        }
+    }
+
+    private static boolean walkCHUntil(NodeClass<?> start, NodeClass<?> until, Predicate<NodeClass<?>> p) {
+        NodeClass<?> cur = start;
+        while (cur != until && cur != null) {
+            if (p.test(cur)) {
+                return true;
+            }
+            cur = cur.getSuperNodeClass();
+        }
+        return false;
+    }
+
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/tiers/PhaseContext.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/tiers/PhaseContext.java	Wed Apr 19 04:10:56 2017 +0000
@@ -24,7 +24,6 @@
 
 import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
 import org.graalvm.compiler.nodes.spi.LoweringProvider;
-import org.graalvm.compiler.nodes.spi.NodeCostProvider;
 import org.graalvm.compiler.nodes.spi.Replacements;
 import org.graalvm.compiler.nodes.spi.StampProvider;
 import org.graalvm.compiler.phases.util.Providers;
@@ -40,22 +39,19 @@
     private final LoweringProvider lowerer;
     private final Replacements replacements;
     private final StampProvider stampProvider;
-    private final NodeCostProvider nodeCostProvider;
 
     public PhaseContext(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider, LoweringProvider lowerer, Replacements replacements,
-                    StampProvider stampProvider, NodeCostProvider nodeCostProvider) {
+                    StampProvider stampProvider) {
         this.metaAccess = metaAccess;
         this.constantReflection = constantReflection;
         this.constantFieldProvider = constantFieldProvider;
         this.lowerer = lowerer;
         this.replacements = replacements;
         this.stampProvider = stampProvider;
-        this.nodeCostProvider = nodeCostProvider;
     }
 
     public PhaseContext(Providers providers) {
-        this(providers.getMetaAccess(), providers.getConstantReflection(), providers.getConstantFieldProvider(), providers.getLowerer(), providers.getReplacements(), providers.getStampProvider(),
-                        providers.getNodeCostProvider());
+        this(providers.getMetaAccess(), providers.getConstantReflection(), providers.getConstantFieldProvider(), providers.getLowerer(), providers.getReplacements(), providers.getStampProvider());
     }
 
     public MetaAccessProvider getMetaAccess() {
@@ -82,7 +78,4 @@
         return stampProvider;
     }
 
-    public NodeCostProvider getNodeCostProvider() {
-        return nodeCostProvider;
-    }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/Providers.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/Providers.java	Wed Apr 19 04:10:56 2017 +0000
@@ -26,7 +26,6 @@
 import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
 import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
 import org.graalvm.compiler.nodes.spi.LoweringProvider;
-import org.graalvm.compiler.nodes.spi.NodeCostProvider;
 import org.graalvm.compiler.nodes.spi.Replacements;
 import org.graalvm.compiler.nodes.spi.StampProvider;
 import org.graalvm.compiler.phases.tiers.PhaseContext;
@@ -48,10 +47,9 @@
     private final ForeignCallsProvider foreignCalls;
     private final Replacements replacements;
     private final StampProvider stampProvider;
-    private final NodeCostProvider nodeCostProvider;
 
     public Providers(MetaAccessProvider metaAccess, CodeCacheProvider codeCache, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider,
-                    ForeignCallsProvider foreignCalls, LoweringProvider lowerer, Replacements replacements, StampProvider stampProvider, NodeCostProvider nodeCostProvider) {
+                    ForeignCallsProvider foreignCalls, LoweringProvider lowerer, Replacements replacements, StampProvider stampProvider) {
         this.metaAccess = metaAccess;
         this.codeCache = codeCache;
         this.constantReflection = constantReflection;
@@ -60,17 +58,16 @@
         this.lowerer = lowerer;
         this.replacements = replacements;
         this.stampProvider = stampProvider;
-        this.nodeCostProvider = nodeCostProvider;
     }
 
     public Providers(Providers copyFrom) {
         this(copyFrom.getMetaAccess(), copyFrom.getCodeCache(), copyFrom.getConstantReflection(), copyFrom.getConstantFieldProvider(), copyFrom.getForeignCalls(), copyFrom.getLowerer(),
-                        copyFrom.getReplacements(), copyFrom.getStampProvider(), copyFrom.getNodeCostProvider());
+                        copyFrom.getReplacements(), copyFrom.getStampProvider());
     }
 
     public Providers(PhaseContext copyFrom) {
         this(copyFrom.getMetaAccess(), null, copyFrom.getConstantReflection(), copyFrom.getConstantFieldProvider(), null, copyFrom.getLowerer(), copyFrom.getReplacements(),
-                        copyFrom.getStampProvider(), copyFrom.getNodeCostProvider());
+                        copyFrom.getStampProvider());
     }
 
     @Override
@@ -109,39 +106,35 @@
         return stampProvider;
     }
 
-    public NodeCostProvider getNodeCostProvider() {
-        return nodeCostProvider;
-    }
-
     public Providers copyWith(MetaAccessProvider substitution) {
-        return new Providers(substitution, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, replacements, stampProvider, nodeCostProvider);
+        return new Providers(substitution, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, replacements, stampProvider);
     }
 
     public Providers copyWith(CodeCacheProvider substitution) {
-        return new Providers(metaAccess, substitution, constantReflection, constantFieldProvider, foreignCalls, lowerer, replacements, stampProvider, nodeCostProvider);
+        return new Providers(metaAccess, substitution, constantReflection, constantFieldProvider, foreignCalls, lowerer, replacements, stampProvider);
     }
 
     public Providers copyWith(ConstantReflectionProvider substitution) {
-        return new Providers(metaAccess, codeCache, substitution, constantFieldProvider, foreignCalls, lowerer, replacements, stampProvider, nodeCostProvider);
+        return new Providers(metaAccess, codeCache, substitution, constantFieldProvider, foreignCalls, lowerer, replacements, stampProvider);
     }
 
     public Providers copyWith(ConstantFieldProvider substitution) {
-        return new Providers(metaAccess, codeCache, constantReflection, substitution, foreignCalls, lowerer, replacements, stampProvider, nodeCostProvider);
+        return new Providers(metaAccess, codeCache, constantReflection, substitution, foreignCalls, lowerer, replacements, stampProvider);
     }
 
     public Providers copyWith(ForeignCallsProvider substitution) {
-        return new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, substitution, lowerer, replacements, stampProvider, nodeCostProvider);
+        return new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, substitution, lowerer, replacements, stampProvider);
     }
 
     public Providers copyWith(LoweringProvider substitution) {
-        return new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, substitution, replacements, stampProvider, nodeCostProvider);
+        return new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, substitution, replacements, stampProvider);
     }
 
     public Providers copyWith(Replacements substitution) {
-        return new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, substitution, stampProvider, nodeCostProvider);
+        return new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, substitution, stampProvider);
     }
 
     public Providers copyWith(StampProvider substitution) {
-        return new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, replacements, substitution, nodeCostProvider);
+        return new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, replacements, substitution);
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/ValueMergeUtil.java	Wed Apr 19 04:10:56 2017 +0000
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2017, 2017, 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 org.graalvm.compiler.phases.util;
+
+import java.util.List;
+import java.util.function.Function;
+
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.ControlSinkNode;
+import org.graalvm.compiler.nodes.EndNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.PhiNode;
+import org.graalvm.compiler.nodes.ReturnNode;
+import org.graalvm.compiler.nodes.UnwindNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.ValuePhiNode;
+
+public class ValueMergeUtil {
+
+    public static ValueNode mergeReturns(AbstractMergeNode merge, List<? extends ReturnNode> returnNodes) {
+        return mergeValueProducers(merge, returnNodes, null, returnNode -> returnNode.result());
+    }
+
+    public static <T> ValueNode mergeValueProducers(AbstractMergeNode merge, List<? extends T> valueProducers, Function<T, FixedWithNextNode> lastInstrFunction, Function<T, ValueNode> valueFunction) {
+        ValueNode singleResult = null;
+        PhiNode phiResult = null;
+        for (T valueProducer : valueProducers) {
+            ValueNode result = valueFunction.apply(valueProducer);
+            if (result != null) {
+                if (phiResult == null && (singleResult == null || singleResult == result)) {
+                    /* Only one result value, so no need yet for a phi node. */
+                    singleResult = result;
+                } else if (phiResult == null) {
+                    /* Found a second result value, so create phi node. */
+                    phiResult = merge.graph().addWithoutUnique(new ValuePhiNode(result.stamp().unrestricted(), merge));
+                    for (int i = 0; i < merge.forwardEndCount(); i++) {
+                        phiResult.addInput(singleResult);
+                    }
+                    phiResult.addInput(result);
+
+                } else {
+                    /* Multiple return values, just add to existing phi node. */
+                    phiResult.addInput(result);
+                }
+            }
+
+            // create and wire up a new EndNode
+            EndNode endNode = merge.graph().add(new EndNode());
+            merge.addForwardEnd(endNode);
+            if (lastInstrFunction == null) {
+                assert valueProducer instanceof ReturnNode || valueProducer instanceof UnwindNode;
+                ((ControlSinkNode) valueProducer).replaceAndDelete(endNode);
+            } else {
+                FixedWithNextNode lastInstr = lastInstrFunction.apply(valueProducer);
+                lastInstr.setNext(endNode);
+            }
+        }
+
+        if (phiResult != null) {
+            assert phiResult.verify();
+            phiResult.inferStamp();
+            return phiResult;
+        } else {
+            return singleResult;
+        }
+    }
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/BinaryGraphPrinter.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/BinaryGraphPrinter.java	Wed Apr 19 04:10:56 2017 +0000
@@ -510,6 +510,14 @@
                     props.put("probability-exception", t);
                 }
             }
+
+            try {
+                props.put("NodeCost-Size", node.estimatedNodeSize());
+                props.put("NodeCost-Cycles", node.estimatedNodeCycles());
+            } catch (Throwable t) {
+                props.put("node-cost-exception", t.getMessage());
+            }
+
             if (nodeToBlocks != null) {
                 Object block = getBlockForNode(node, nodeToBlocks);
                 if (block != null) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinterDumpHandler.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinterDumpHandler.java	Wed Apr 19 04:10:56 2017 +0000
@@ -49,6 +49,7 @@
 import org.graalvm.compiler.debug.internal.DebugScope;
 import org.graalvm.compiler.graph.Graph;
 import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.phases.contract.NodeCostUtil;
 
 import jdk.vm.ci.meta.JavaMethod;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
@@ -175,6 +176,12 @@
                 properties.put("scope", Debug.currentScope());
                 if (graph instanceof StructuredGraph) {
                     properties.put("compilationIdentifier", ((StructuredGraph) graph).compilationId());
+                    try {
+                        int size = NodeCostUtil.computeGraphSize((StructuredGraph) graph);
+                        properties.put("node-cost graph size", size);
+                    } catch (Throwable t) {
+                        properties.put("node-cost-exception", t.getMessage());
+                    }
                 }
                 addCFGFileName(properties);
                 printer.print(graph, nextDumpId() + ":" + message, properties);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/IdealGraphPrinter.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/IdealGraphPrinter.java	Wed Apr 19 04:10:56 2017 +0000
@@ -231,6 +231,13 @@
                 printProperty("hasPredecessor", "true");
             }
 
+            try {
+                printProperty("NodeCost-Size", node.estimatedNodeSize().toString());
+                printProperty("NodeCost-Cycles", node.estimatedNodeCycles().toString());
+            } catch (Throwable t) {
+                props.put("node-cost-exception", t.getMessage());
+            }
+
             for (Entry<Object, Object> entry : props.entrySet()) {
                 String key = entry.getKey().toString();
                 Object value = entry.getValue();
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64CountLeadingZerosNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64CountLeadingZerosNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,7 +22,7 @@
  */
 package org.graalvm.compiler.replacements.aarch64;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_6;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
 
 import org.graalvm.compiler.core.common.type.IntegerStamp;
@@ -42,7 +42,7 @@
 import jdk.vm.ci.meta.JavaConstant;
 import jdk.vm.ci.meta.JavaKind;
 
-@NodeInfo(cycles = CYCLES_6, size = SIZE_1)
+@NodeInfo(cycles = CYCLES_2, size = SIZE_1)
 public final class AArch64CountLeadingZerosNode extends UnaryNode implements ArithmeticLIRLowerable {
 
     public static final NodeClass<AArch64CountLeadingZerosNode> TYPE = NodeClass.create(AArch64CountLeadingZerosNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64CountTrailingZerosNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64CountTrailingZerosNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,7 +22,7 @@
  */
 package org.graalvm.compiler.replacements.aarch64;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
 
 import org.graalvm.compiler.core.common.type.IntegerStamp;
@@ -45,7 +45,7 @@
 /**
  * Count the number of trailing zeros using the {@code rbit; clz} instructions.
  */
-@NodeInfo(cycles = CYCLES_3, size = SIZE_2)
+@NodeInfo(cycles = CYCLES_2, size = SIZE_2)
 public final class AArch64CountTrailingZerosNode extends UnaryNode implements ArithmeticLIRLowerable {
     public static final NodeClass<AArch64CountTrailingZerosNode> TYPE = NodeClass.create(AArch64CountTrailingZerosNode.class);
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64GraphBuilderPlugins.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64GraphBuilderPlugins.java	Wed Apr 19 04:10:56 2017 +0000
@@ -99,7 +99,7 @@
         r.register2("pow", Double.TYPE, Double.TYPE, new InvocationPlugin() {
             @Override
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) {
-                b.push(JavaKind.Double, b.recursiveAppend(BinaryMathIntrinsicNode.create(x, y, BinaryMathIntrinsicNode.BinaryOperation.POW)));
+                b.push(JavaKind.Double, b.append(BinaryMathIntrinsicNode.create(x, y, BinaryMathIntrinsicNode.BinaryOperation.POW)));
                 return true;
             }
         });
@@ -109,7 +109,7 @@
         r.register1(name, Double.TYPE, new InvocationPlugin() {
             @Override
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
-                b.push(JavaKind.Double, b.recursiveAppend(UnaryMathIntrinsicNode.create(value, operation)));
+                b.push(JavaKind.Double, b.append(UnaryMathIntrinsicNode.create(value, operation)));
                 return true;
             }
         });
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64CountLeadingZerosNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64CountLeadingZerosNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,7 +22,7 @@
  */
 package org.graalvm.compiler.replacements.amd64;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
 
 import org.graalvm.compiler.core.common.type.IntegerStamp;
@@ -45,7 +45,7 @@
 /**
  * Count the number of leading zeros using the {@code lzcntq} or {@code lzcntl} instructions.
  */
-@NodeInfo(cycles = CYCLES_3, size = SIZE_1)
+@NodeInfo(cycles = CYCLES_2, size = SIZE_1)
 public final class AMD64CountLeadingZerosNode extends UnaryNode implements ArithmeticLIRLowerable {
     public static final NodeClass<AMD64CountLeadingZerosNode> TYPE = NodeClass.create(AMD64CountLeadingZerosNode.class);
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64CountTrailingZerosNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64CountTrailingZerosNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,7 +22,7 @@
  */
 package org.graalvm.compiler.replacements.amd64;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
 
 import org.graalvm.compiler.core.common.type.IntegerStamp;
@@ -45,7 +45,7 @@
 /**
  * Count the number of trailing zeros using the {@code tzcntq} or {@code tzcntl} instructions.
  */
-@NodeInfo(cycles = CYCLES_3, size = SIZE_1)
+@NodeInfo(cycles = CYCLES_2, size = SIZE_1)
 public final class AMD64CountTrailingZerosNode extends UnaryNode implements ArithmeticLIRLowerable {
     public static final NodeClass<AMD64CountTrailingZerosNode> TYPE = NodeClass.create(AMD64CountTrailingZerosNode.class);
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64FloatConvertNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64FloatConvertNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,7 +22,7 @@
  */
 package org.graalvm.compiler.replacements.amd64;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_5;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
 
 import org.graalvm.compiler.core.common.calc.FloatConvert;
@@ -42,7 +42,7 @@
  * of the {@link FloatConvertNode} which, on AMD64 needs a {@link AMD64FloatConvertNode} plus some
  * fixup code that handles the corner cases that differ between AMD64 and Java.
  */
-@NodeInfo(cycles = CYCLES_5, size = SIZE_1)
+@NodeInfo(cycles = CYCLES_8, size = SIZE_1)
 public final class AMD64FloatConvertNode extends UnaryArithmeticNode<FloatConvertOp> implements ArithmeticLIRLowerable {
     public static final NodeClass<AMD64FloatConvertNode> TYPE = NodeClass.create(AMD64FloatConvertNode.class);
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java	Wed Apr 19 04:10:56 2017 +0000
@@ -118,7 +118,7 @@
             r.register1("bitCount", type, new InvocationPlugin() {
                 @Override
                 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
-                    b.push(JavaKind.Int, b.recursiveAppend(new BitCountNode(value).canonical(null)));
+                    b.push(JavaKind.Int, b.append(new BitCountNode(value).canonical(null)));
                     return true;
                 }
             });
@@ -152,7 +152,7 @@
         r.register1(name, Double.TYPE, new InvocationPlugin() {
             @Override
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
-                b.push(JavaKind.Double, b.recursiveAppend(UnaryMathIntrinsicNode.create(value, operation)));
+                b.push(JavaKind.Double, b.append(UnaryMathIntrinsicNode.create(value, operation)));
                 return true;
             }
         });
@@ -162,7 +162,7 @@
         r.register2(name, Double.TYPE, Double.TYPE, new InvocationPlugin() {
             @Override
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) {
-                b.push(JavaKind.Double, b.recursiveAppend(BinaryMathIntrinsicNode.create(x, y, operation)));
+                b.push(JavaKind.Double, b.append(BinaryMathIntrinsicNode.create(x, y, operation)));
                 return true;
             }
         });
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringIndexOfNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringIndexOfNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,14 +22,15 @@
  */
 package org.graalvm.compiler.replacements.amd64;
 
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_256;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_64;
+
 import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.graph.NodeInputList;
 import org.graalvm.compiler.nodeinfo.InputType;
-import org.graalvm.compiler.nodeinfo.NodeCycles;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
-import org.graalvm.compiler.nodeinfo.NodeSize;
 import org.graalvm.compiler.nodes.FixedWithNextNode;
 import org.graalvm.compiler.nodes.NamedLocationIdentity;
 import org.graalvm.compiler.nodes.ValueNode;
@@ -43,7 +44,7 @@
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.Value;
 
-@NodeInfo(size = NodeSize.SIZE_50, cycles = NodeCycles.CYCLES_200)
+@NodeInfo(size = SIZE_64, cycles = CYCLES_256)
 public class AMD64StringIndexOfNode extends FixedWithNextNode implements LIRLowerable, MemoryAccess {
     public static final NodeClass<AMD64StringIndexOfNode> TYPE = NodeClass.create(AMD64StringIndexOfNode.class);
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sparc/src/org/graalvm/compiler/replacements/sparc/SPARCGraphBuilderPlugins.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sparc/src/org/graalvm/compiler/replacements/sparc/SPARCGraphBuilderPlugins.java	Wed Apr 19 04:10:56 2017 +0000
@@ -70,7 +70,7 @@
         r.register1("bitCount", type, new InvocationPlugin() {
             @Override
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
-                b.push(JavaKind.Int, b.recursiveAppend(new BitCountNode(value).canonical(null)));
+                b.push(JavaKind.Int, b.append(new BitCountNode(value).canonical(null)));
                 return true;
             }
         });
@@ -87,7 +87,7 @@
         r.register2("pow", Double.TYPE, Double.TYPE, new InvocationPlugin() {
             @Override
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) {
-                b.push(JavaKind.Double, b.recursiveAppend(BinaryMathIntrinsicNode.create(x, y, BinaryMathIntrinsicNode.BinaryOperation.POW)));
+                b.push(JavaKind.Double, b.append(BinaryMathIntrinsicNode.create(x, y, BinaryMathIntrinsicNode.BinaryOperation.POW)));
                 return true;
             }
         });
@@ -97,7 +97,7 @@
         r.register1(name, Double.TYPE, new InvocationPlugin() {
             @Override
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
-                b.push(JavaKind.Double, b.recursiveAppend(UnaryMathIntrinsicNode.create(value, operation)));
+                b.push(JavaKind.Double, b.append(UnaryMathIntrinsicNode.create(value, operation)));
                 return true;
             }
         });
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PEGraphDecoderTest.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PEGraphDecoderTest.java	Wed Apr 19 04:10:56 2017 +0000
@@ -135,7 +135,7 @@
             registerPlugins(graphBuilderConfig.getPlugins().getInvocationPlugins());
             targetGraph = new StructuredGraph.Builder(getInitialOptions(), AllowAssumptions.YES).method(testMethod).build();
             CachingPEGraphDecoder decoder = new CachingPEGraphDecoder(getTarget().arch, targetGraph, getProviders(), graphBuilderConfig, OptimisticOptimizations.NONE, AllowAssumptions.YES,
-                            getInitialOptions(), null, null, new InlineInvokePlugin[]{new InlineAll()}, null);
+                            getInitialOptions(), null, null, new InlineInvokePlugin[]{new InlineAll()}, null, null);
 
             decoder.decode(testMethod);
             Debug.dump(Debug.BASIC_LEVEL, targetGraph, "Target Graph");
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java	Wed Apr 19 04:10:56 2017 +0000
@@ -36,6 +36,7 @@
 import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
 import org.graalvm.compiler.nodes.graphbuilderconf.LoopExplosionPlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.NodePlugin;
 import org.graalvm.compiler.nodes.graphbuilderconf.ParameterPlugin;
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.phases.OptimisticOptimizations;
@@ -62,9 +63,9 @@
 
     public CachingPEGraphDecoder(Architecture architecture, StructuredGraph graph, Providers providers, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts,
                     AllowAssumptions allowAssumptions, OptionValues options, LoopExplosionPlugin loopExplosionPlugin, InvocationPlugins invocationPlugins, InlineInvokePlugin[] inlineInvokePlugins,
-                    ParameterPlugin parameterPlugin) {
+                    ParameterPlugin parameterPlugin, NodePlugin[] nodePlugins) {
         super(architecture, graph, providers.getMetaAccess(), providers.getConstantReflection(), providers.getConstantFieldProvider(), providers.getStampProvider(), options, loopExplosionPlugin,
-                        invocationPlugins, inlineInvokePlugins, parameterPlugin);
+                        invocationPlugins, inlineInvokePlugins, parameterPlugin, nodePlugins);
 
         this.providers = providers;
         this.graphBuilderConfig = graphBuilderConfig;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/GraphKit.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/GraphKit.java	Wed Apr 19 04:10:56 2017 +0000
@@ -158,16 +158,7 @@
 
     @Override
     public <T extends ValueNode> T append(T node) {
-        T result = graph.addOrUnique(changeToWord(node));
-        if (result instanceof FixedNode) {
-            updateLastFixed((FixedNode) result);
-        }
-        return result;
-    }
-
-    @Override
-    public <T extends ValueNode> T recursiveAppend(T node) {
-        T result = graph.addOrUniqueWithInputs(node);
+        T result = graph.addOrUniqueWithInputs(changeToWord(node));
         if (result instanceof FixedNode) {
             updateLastFixed((FixedNode) result);
         }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/IntrinsicGraphBuilder.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/IntrinsicGraphBuilder.java	Wed Apr 19 04:10:56 2017 +0000
@@ -145,18 +145,6 @@
         if (v.graph() != null) {
             return v;
         }
-        T added = graph.addOrUnique(v);
-        if (added == v) {
-            updateLastInstruction(v);
-        }
-        return added;
-    }
-
-    @Override
-    public <T extends ValueNode> T recursiveAppend(T v) {
-        if (v.graph() != null) {
-            return v;
-        }
         T added = graph.addOrUniqueWithInputs(v);
         if (added == v) {
             updateLastInstruction(v);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/MethodHandlePlugin.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/MethodHandlePlugin.java	Wed Apr 19 04:10:56 2017 +0000
@@ -73,7 +73,7 @@
                 CallTargetNode callTarget = invoke.callTarget();
                 NodeInputList<ValueNode> argumentsList = callTarget.arguments();
                 for (int i = 0; i < argumentsList.size(); ++i) {
-                    argumentsList.initialize(i, b.recursiveAppend(argumentsList.get(i)));
+                    argumentsList.initialize(i, b.append(argumentsList.get(i)));
                 }
 
                 boolean inlineEverything = false;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java	Wed Apr 19 04:10:56 2017 +0000
@@ -37,6 +37,7 @@
 import org.graalvm.compiler.core.common.PermanentBailoutException;
 import org.graalvm.compiler.core.common.cfg.CFGVerifier;
 import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
+import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.core.common.type.StampPair;
 import org.graalvm.compiler.debug.Debug;
@@ -81,9 +82,17 @@
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.InvocationPluginReceiver;
 import org.graalvm.compiler.nodes.graphbuilderconf.LoopExplosionPlugin;
 import org.graalvm.compiler.nodes.graphbuilderconf.LoopExplosionPlugin.LoopExplosionKind;
+import org.graalvm.compiler.nodes.graphbuilderconf.NodePlugin;
 import org.graalvm.compiler.nodes.graphbuilderconf.ParameterPlugin;
+import org.graalvm.compiler.nodes.java.LoadFieldNode;
+import org.graalvm.compiler.nodes.java.LoadIndexedNode;
 import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
 import org.graalvm.compiler.nodes.java.MonitorIdNode;
+import org.graalvm.compiler.nodes.java.NewArrayNode;
+import org.graalvm.compiler.nodes.java.NewInstanceNode;
+import org.graalvm.compiler.nodes.java.NewMultiArrayNode;
+import org.graalvm.compiler.nodes.java.StoreFieldNode;
+import org.graalvm.compiler.nodes.java.StoreIndexedNode;
 import org.graalvm.compiler.nodes.spi.StampProvider;
 import org.graalvm.compiler.nodes.util.GraphUtil;
 import org.graalvm.compiler.options.Option;
@@ -91,6 +100,8 @@
 import org.graalvm.compiler.options.OptionType;
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.phases.common.inlining.InliningUtil;
+import org.graalvm.util.EconomicMap;
+import org.graalvm.util.Equivalence;
 
 import jdk.vm.ci.code.Architecture;
 import jdk.vm.ci.code.BailoutException;
@@ -102,7 +113,9 @@
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.JavaType;
 import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaField;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
 
 /**
  * A graph decoder that performs partial evaluation, i.e., that performs method inlining and
@@ -118,6 +131,8 @@
  */
 public abstract class PEGraphDecoder extends SimplifyingGraphDecoder {
 
+    private static final Object CACHED_NULL_VALUE = new Object();
+
     public static class Options {
         @Option(help = "Maximum inlining depth during partial evaluation before reporting an infinite recursion")//
         public static final OptionKey<Integer> InliningDepthError = new OptionKey<>(1000);
@@ -229,11 +244,6 @@
         }
 
         @Override
-        public <T extends ValueNode> T recursiveAppend(T value) {
-            throw unimplemented();
-        }
-
-        @Override
         public void push(JavaKind kind, ValueNode value) {
             throw unimplemented();
         }
@@ -295,7 +305,7 @@
         protected boolean invokeConsumed;
 
         public PEAppendGraphBuilderContext(PEMethodScope inlineScope, FixedWithNextNode lastInstr) {
-            super(inlineScope, inlineScope.invokeData.invoke);
+            super(inlineScope, inlineScope.invokeData != null ? inlineScope.invokeData.invoke : null);
             this.lastInstr = lastInstr;
         }
 
@@ -322,7 +332,7 @@
                 return v;
             }
             try (DebugCloseable position = withNodeSoucePosition()) {
-                T added = getGraph().addOrUnique(v);
+                T added = getGraph().addOrUniqueWithInputs(v);
                 if (added == v) {
                     updateLastInstruction(v);
                 }
@@ -337,21 +347,6 @@
             return null;
         }
 
-        @SuppressWarnings("try")
-        @Override
-        public <T extends ValueNode> T recursiveAppend(T v) {
-            if (v.graph() != null) {
-                return v;
-            }
-            try (DebugCloseable position = withNodeSoucePosition()) {
-                T added = getGraph().addOrUniqueWithInputs(v);
-                if (added == v) {
-                    updateLastInstruction(v);
-                }
-                return added;
-            }
-        }
-
         private <T extends ValueNode> void updateLastInstruction(T v) {
             if (v instanceof FixedNode) {
                 FixedNode fixedNode = (FixedNode) v;
@@ -380,6 +375,56 @@
         }
     }
 
+    /**
+     * A graph builder context that allows appending one node to the graph. If a node is appended,
+     * the target fixed node is replaced with the new node, and clients must afterwards call commit
+     * to complete the replacement.
+     *
+     * This graph builder context is intended to be used with the {@link NodePlugin} objects passed
+     * to the graph decoder.
+     */
+    protected class PEOnDemandAppendGraphBuilderContext extends PEAppendGraphBuilderContext {
+        private final FixedNode targetNode;
+        private FixedWithNextNode predecessor;
+
+        public PEOnDemandAppendGraphBuilderContext(PEMethodScope inlineScope, FixedNode targetNode) {
+            super(inlineScope, targetNode.predecessor() instanceof FixedWithNextNode ? (FixedWithNextNode) targetNode.predecessor() : null);
+            this.targetNode = targetNode;
+            this.predecessor = targetNode.predecessor() instanceof FixedWithNextNode ? (FixedWithNextNode) targetNode.predecessor() : null;
+        }
+
+        @Override
+        public void push(JavaKind kind, ValueNode value) {
+            super.push(kind, value);
+        }
+
+        private void checkPopLastInstruction() {
+            if (predecessor != null) {
+                targetNode.replaceAtPredecessor(null);
+                lastInstr = predecessor;
+                predecessor = null;
+            }
+        }
+
+        @Override
+        public <T extends ValueNode> T append(T v) {
+            checkPopLastInstruction();
+            return super.append(v);
+        }
+
+        public FixedNode commit(LoopScope loopScope, int nodeOrderId, FixedWithNextNode oldAsFixedWithNextNode) {
+            registerNode(loopScope, nodeOrderId, pushedNode, true, false);
+            targetNode.replaceAtUsages(pushedNode);
+            if (oldAsFixedWithNextNode != null) {
+                FixedNode successor = oldAsFixedWithNextNode.next();
+                successor.replaceAtPredecessor(null);
+                lastInstr.setNext(successor);
+                deleteFixedNode(targetNode);
+            }
+            return lastInstr;
+        }
+    }
+
     @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
     static class ExceptionPlaceholderNode extends ValueNode {
         public static final NodeClass<ExceptionPlaceholderNode> TYPE = NodeClass.create(ExceptionPlaceholderNode.class);
@@ -389,21 +434,55 @@
         }
     }
 
+    protected static class SpecialCallTargetCacheKey {
+        private final InvokeKind invokeKind;
+        private final ResolvedJavaMethod targetMethod;
+        private final ResolvedJavaType contextType;
+        private final Stamp receiverStamp;
+
+        public SpecialCallTargetCacheKey(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ResolvedJavaType contextType, Stamp receiverStamp) {
+            this.invokeKind = invokeKind;
+            this.targetMethod = targetMethod;
+            this.contextType = contextType;
+            this.receiverStamp = receiverStamp;
+        }
+
+        @Override
+        public int hashCode() {
+            return invokeKind.hashCode() ^ targetMethod.hashCode() ^ contextType.hashCode() ^ receiverStamp.hashCode();
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof SpecialCallTargetCacheKey) {
+                SpecialCallTargetCacheKey key = (SpecialCallTargetCacheKey) obj;
+                return key.invokeKind.equals(this.invokeKind) && key.targetMethod.equals(this.targetMethod) && key.contextType.equals(this.contextType) && key.receiverStamp.equals(this.receiverStamp);
+            }
+            return false;
+        }
+    }
+
     protected final OptionValues options;
     private final LoopExplosionPlugin loopExplosionPlugin;
     private final InvocationPlugins invocationPlugins;
     private final InlineInvokePlugin[] inlineInvokePlugins;
     private final ParameterPlugin parameterPlugin;
+    private final NodePlugin[] nodePlugins;
+    private final EconomicMap<SpecialCallTargetCacheKey, Object> specialCallTargetCache;
+    private final EconomicMap<ResolvedJavaMethod, Object> invocationPluginCache;
 
     public PEGraphDecoder(Architecture architecture, StructuredGraph graph, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider,
                     StampProvider stampProvider, OptionValues options, LoopExplosionPlugin loopExplosionPlugin, InvocationPlugins invocationPlugins, InlineInvokePlugin[] inlineInvokePlugins,
-                    ParameterPlugin parameterPlugin) {
+                    ParameterPlugin parameterPlugin, NodePlugin[] nodePlugins) {
         super(architecture, graph, metaAccess, constantReflection, constantFieldProvider, stampProvider, true);
         this.loopExplosionPlugin = loopExplosionPlugin;
         this.invocationPlugins = invocationPlugins;
         this.inlineInvokePlugins = inlineInvokePlugins;
         this.parameterPlugin = parameterPlugin;
         this.options = options;
+        this.nodePlugins = nodePlugins;
+        this.specialCallTargetCache = EconomicMap.create(Equivalence.DEFAULT);
+        this.invocationPluginCache = EconomicMap.create(Equivalence.DEFAULT);
     }
 
     protected static LoopExplosionKind loopExplosionKind(ResolvedJavaMethod method, LoopExplosionPlugin loopExplosionPlugin) {
@@ -496,7 +575,7 @@
 
     protected LoopScope trySimplifyInvoke(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, MethodCallTargetNode callTarget) {
         // attempt to devirtualize the call
-        ResolvedJavaMethod specialCallTarget = MethodCallTargetNode.findSpecialCallTarget(callTarget.invokeKind(), callTarget.receiver(), callTarget.targetMethod(), invokeData.contextType);
+        ResolvedJavaMethod specialCallTarget = getSpecialCallTarget(invokeData, callTarget);
         if (specialCallTarget != null) {
             callTarget.setTargetMethod(specialCallTarget);
             callTarget.setInvokeKind(InvokeKind.Special);
@@ -522,15 +601,39 @@
         return null;
     }
 
+    private ResolvedJavaMethod getSpecialCallTarget(InvokeData invokeData, MethodCallTargetNode callTarget) {
+        if (callTarget.invokeKind().isDirect()) {
+            return null;
+        }
+
+        // check for trivial cases (e.g. final methods, nonvirtual methods)
+        if (callTarget.targetMethod().canBeStaticallyBound()) {
+            return callTarget.targetMethod();
+        }
+
+        SpecialCallTargetCacheKey key = new SpecialCallTargetCacheKey(callTarget.invokeKind(), callTarget.targetMethod(), invokeData.contextType, callTarget.receiver().stamp());
+        Object specialCallTarget = specialCallTargetCache.get(key);
+        if (specialCallTarget == null) {
+            specialCallTarget = MethodCallTargetNode.devirtualizeCall(key.invokeKind, key.targetMethod, key.contextType, graph.getAssumptions(),
+                            key.receiverStamp);
+            if (specialCallTarget == null) {
+                specialCallTarget = CACHED_NULL_VALUE;
+            }
+            specialCallTargetCache.put(key, specialCallTarget);
+        }
+
+        return specialCallTarget == CACHED_NULL_VALUE ? null : (ResolvedJavaMethod) specialCallTarget;
+    }
+
     protected boolean tryInvocationPlugin(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, MethodCallTargetNode callTarget) {
-        if (invocationPlugins == null) {
+        if (invocationPlugins == null || invocationPlugins.size() == 0) {
             return false;
         }
 
         Invoke invoke = invokeData.invoke;
 
         ResolvedJavaMethod targetMethod = callTarget.targetMethod();
-        InvocationPlugin invocationPlugin = invocationPlugins.lookupInvocation(targetMethod);
+        InvocationPlugin invocationPlugin = getInvocationPlugin(targetMethod);
         if (invocationPlugin == null) {
             return false;
         }
@@ -570,6 +673,19 @@
         }
     }
 
+    private InvocationPlugin getInvocationPlugin(ResolvedJavaMethod targetMethod) {
+        Object invocationPlugin = invocationPluginCache.get(targetMethod);
+        if (invocationPlugin == null) {
+            invocationPlugin = invocationPlugins.lookupInvocation(targetMethod);
+            if (invocationPlugin == null) {
+                invocationPlugin = CACHED_NULL_VALUE;
+            }
+            invocationPluginCache.put(targetMethod, invocationPlugin);
+        }
+
+        return invocationPlugin == CACHED_NULL_VALUE ? null : (InvocationPlugin) invocationPlugin;
+    }
+
     protected LoopScope tryInline(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, MethodCallTargetNode callTarget) {
         if (!callTarget.invokeKind().isDirect()) {
             return null;
@@ -674,7 +790,7 @@
                  */
                 MergeNode unwindMergeNode = graph.add(new MergeNode());
                 exceptionValue = InliningUtil.mergeValueProducers(unwindMergeNode, getMatchingNodes(returnAndUnwindNodes, returnNodeCount > 0, UnwindNode.class, unwindNodeCount),
-                                unwindNode -> unwindNode.exception());
+                                null, unwindNode -> unwindNode.exception());
                 unwindMergeNode.setNext(unwindReplacement);
 
                 ensureExceptionStateDecoded(inlineScope);
@@ -812,28 +928,140 @@
     @Override
     protected void handleFixedNode(MethodScope s, LoopScope loopScope, int nodeOrderId, FixedNode node) {
         PEMethodScope methodScope = (PEMethodScope) s;
+        FixedNode replacedNode = node;
+
         if (node instanceof ForeignCallNode) {
             ForeignCallNode foreignCall = (ForeignCallNode) node;
             if (foreignCall.getBci() == BytecodeFrame.UNKNOWN_BCI && methodScope.invokeData != null) {
                 foreignCall.setBci(methodScope.invokeData.invoke.bci());
             }
+        } else if (nodePlugins != null && nodePlugins.length > 0) {
+            if (node instanceof LoadFieldNode) {
+                PEOnDemandAppendGraphBuilderContext graphBuilderContext = new PEOnDemandAppendGraphBuilderContext(methodScope, node);
+                LoadFieldNode loadFieldNode = (LoadFieldNode) node;
+                ResolvedJavaField field = loadFieldNode.field();
+                if (loadFieldNode.isStatic()) {
+                    for (NodePlugin nodePlugin : nodePlugins) {
+                        if (nodePlugin.handleLoadStaticField(graphBuilderContext, field)) {
+                            replacedNode = graphBuilderContext.commit(loopScope, nodeOrderId, loadFieldNode);
+                            break;
+                        }
+                    }
+                } else {
+                    ValueNode object = loadFieldNode.object();
+                    for (NodePlugin nodePlugin : nodePlugins) {
+                        if (nodePlugin.handleLoadField(graphBuilderContext, object, field)) {
+                            replacedNode = graphBuilderContext.commit(loopScope, nodeOrderId, loadFieldNode);
+                            break;
+                        }
+                    }
+                }
+            } else if (node instanceof StoreFieldNode) {
+                PEOnDemandAppendGraphBuilderContext graphBuilderContext = new PEOnDemandAppendGraphBuilderContext(methodScope, node);
+                StoreFieldNode storeFieldNode = (StoreFieldNode) node;
+                ResolvedJavaField field = storeFieldNode.field();
+                if (storeFieldNode.isStatic()) {
+                    ValueNode value = storeFieldNode.value();
+                    for (NodePlugin nodePlugin : nodePlugins) {
+                        if (nodePlugin.handleStoreStaticField(graphBuilderContext, field, value)) {
+                            replacedNode = graphBuilderContext.commit(loopScope, nodeOrderId, storeFieldNode);
+                            break;
+                        }
+                    }
+                } else {
+                    ValueNode object = storeFieldNode.object();
+                    ValueNode value = storeFieldNode.value();
+                    for (NodePlugin nodePlugin : nodePlugins) {
+                        if (nodePlugin.handleStoreField(graphBuilderContext, object, field, value)) {
+                            replacedNode = graphBuilderContext.commit(loopScope, nodeOrderId, storeFieldNode);
+                            break;
+                        }
+                    }
+                }
+            } else if (node instanceof LoadIndexedNode) {
+                PEOnDemandAppendGraphBuilderContext graphBuilderContext = new PEOnDemandAppendGraphBuilderContext(methodScope, node);
+                LoadIndexedNode loadIndexedNode = (LoadIndexedNode) node;
+                ValueNode array = loadIndexedNode.array();
+                ValueNode index = loadIndexedNode.index();
+                for (NodePlugin nodePlugin : nodePlugins) {
+                    if (nodePlugin.handleLoadIndexed(graphBuilderContext, array, index, loadIndexedNode.elementKind())) {
+                        replacedNode = graphBuilderContext.commit(loopScope, nodeOrderId, loadIndexedNode);
+                        break;
+                    }
+                }
+            } else if (node instanceof StoreIndexedNode) {
+                PEOnDemandAppendGraphBuilderContext graphBuilderContext = new PEOnDemandAppendGraphBuilderContext(methodScope, node);
+                StoreIndexedNode storeIndexedNode = (StoreIndexedNode) node;
+                ValueNode array = storeIndexedNode.array();
+                ValueNode index = storeIndexedNode.index();
+                ValueNode value = storeIndexedNode.value();
+                for (NodePlugin nodePlugin : nodePlugins) {
+                    if (nodePlugin.handleStoreIndexed(graphBuilderContext, array, index, storeIndexedNode.elementKind(), value)) {
+                        replacedNode = graphBuilderContext.commit(loopScope, nodeOrderId, storeIndexedNode);
+                        break;
+                    }
+                }
+            } else if (node instanceof NewInstanceNode) {
+                PEOnDemandAppendGraphBuilderContext graphBuilderContext = new PEOnDemandAppendGraphBuilderContext(methodScope, node);
+                NewInstanceNode newInstanceNode = (NewInstanceNode) node;
+                ResolvedJavaType type = newInstanceNode.instanceClass();
+                for (NodePlugin nodePlugin : nodePlugins) {
+                    if (nodePlugin.handleNewInstance(graphBuilderContext, type)) {
+                        replacedNode = graphBuilderContext.commit(loopScope, nodeOrderId, newInstanceNode);
+                        break;
+                    }
+                }
+            } else if (node instanceof NewArrayNode) {
+                PEOnDemandAppendGraphBuilderContext graphBuilderContext = new PEOnDemandAppendGraphBuilderContext(methodScope, node);
+                NewArrayNode newArrayNode = (NewArrayNode) node;
+                ResolvedJavaType elementType = newArrayNode.elementType();
+                ValueNode length = newArrayNode.length();
+                for (NodePlugin nodePlugin : nodePlugins) {
+                    if (nodePlugin.handleNewArray(graphBuilderContext, elementType, length)) {
+                        replacedNode = graphBuilderContext.commit(loopScope, nodeOrderId, newArrayNode);
+                        break;
+                    }
+                }
+            } else if (node instanceof NewMultiArrayNode) {
+                PEOnDemandAppendGraphBuilderContext graphBuilderContext = new PEOnDemandAppendGraphBuilderContext(methodScope, node);
+                NewMultiArrayNode newArrayNode = (NewMultiArrayNode) node;
+                ResolvedJavaType elementType = newArrayNode.type();
+                ValueNode[] dimensions = newArrayNode.dimensions().toArray(new ValueNode[0]);
+                for (NodePlugin nodePlugin : nodePlugins) {
+                    if (nodePlugin.handleNewMultiArray(graphBuilderContext, elementType, dimensions)) {
+                        replacedNode = graphBuilderContext.commit(loopScope, nodeOrderId, newArrayNode);
+                        break;
+                    }
+                }
+            }
         }
 
-        NodeSourcePosition pos = node.getNodeSourcePosition();
+        NodeSourcePosition pos = replacedNode.getNodeSourcePosition();
         if (pos != null && methodScope.isInlinedMethod()) {
             NodeSourcePosition newPosition = pos.addCaller(methodScope.getCallerBytecodePosition());
-            try (DebugCloseable scope = node.graph().withNodeSourcePosition(newPosition)) {
-                super.handleFixedNode(s, loopScope, nodeOrderId, node);
+            try (DebugCloseable scope = replacedNode.graph().withNodeSourcePosition(newPosition)) {
+                super.handleFixedNode(s, loopScope, nodeOrderId, replacedNode);
             }
-            if (node.isAlive()) {
-                node.setNodeSourcePosition(newPosition);
+            if (replacedNode.isAlive()) {
+                replacedNode.setNodeSourcePosition(newPosition);
             }
         } else {
-            super.handleFixedNode(s, loopScope, nodeOrderId, node);
+            super.handleFixedNode(s, loopScope, nodeOrderId, replacedNode);
         }
 
     }
 
+    private static void deleteFixedNode(FixedNode node) {
+        FrameState frameState = null;
+        if (node instanceof StateSplit) {
+            frameState = ((StateSplit) node).stateAfter();
+        }
+        node.safeDelete();
+        if (frameState != null && frameState.hasNoUsages()) {
+            frameState.safeDelete();
+        }
+    }
+
     @Override
     protected Node handleFloatingNodeBeforeAdd(MethodScope s, LoopScope loopScope, Node n) {
         PEMethodScope methodScope = (PEMethodScope) s;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetLowerableMemoryNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetLowerableMemoryNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,6 +22,9 @@
  */
 package org.graalvm.compiler.replacements;
 
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
+
 import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.graph.NodeClass;
@@ -36,7 +39,7 @@
 import org.graalvm.compiler.nodes.spi.Lowerable;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 
-@NodeInfo
+@NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
 public class SnippetLowerableMemoryNode extends FixedWithNextNode implements Lowerable, MemoryAccess {
     public static final NodeClass<SnippetLowerableMemoryNode> TYPE = NodeClass.create(SnippetLowerableMemoryNode.class);
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java	Wed Apr 19 04:10:56 2017 +0000
@@ -284,21 +284,21 @@
         r.register1("reverseBytes", type, new InvocationPlugin() {
             @Override
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
-                b.push(kind, b.recursiveAppend(new ReverseBytesNode(value).canonical(null)));
+                b.push(kind, b.append(new ReverseBytesNode(value).canonical(null)));
                 return true;
             }
         });
         r.register2("divideUnsigned", type, type, new InvocationPlugin() {
             @Override
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode dividend, ValueNode divisor) {
-                b.push(kind, b.recursiveAppend(new UnsignedDivNode(dividend, divisor).canonical(null)));
+                b.push(kind, b.append(new UnsignedDivNode(dividend, divisor).canonical(null)));
                 return true;
             }
         });
         r.register2("remainderUnsigned", type, type, new InvocationPlugin() {
             @Override
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode dividend, ValueNode divisor) {
-                b.push(kind, b.recursiveAppend(new UnsignedRemNode(dividend, divisor).canonical(null)));
+                b.push(kind, b.append(new UnsignedRemNode(dividend, divisor).canonical(null)));
                 return true;
             }
         });
@@ -313,7 +313,7 @@
                 ReverseBytesNode reverse = b.add(new ReverseBytesNode(value));
                 RightShiftNode rightShift = b.add(new RightShiftNode(reverse, b.add(ConstantNode.forInt(16))));
                 ZeroExtendNode charCast = b.add(new ZeroExtendNode(b.add(new NarrowNode(rightShift, 16)), 32));
-                b.push(JavaKind.Char, b.recursiveAppend(charCast.canonical(null)));
+                b.push(JavaKind.Char, b.append(charCast.canonical(null)));
                 return true;
             }
         });
@@ -328,7 +328,7 @@
                 ReverseBytesNode reverse = b.add(new ReverseBytesNode(value));
                 RightShiftNode rightShift = b.add(new RightShiftNode(reverse, b.add(ConstantNode.forInt(16))));
                 SignExtendNode charCast = b.add(new SignExtendNode(b.add(new NarrowNode(rightShift, 16)), 32));
-                b.push(JavaKind.Short, b.recursiveAppend(charCast.canonical(null)));
+                b.push(JavaKind.Short, b.append(charCast.canonical(null)));
                 return true;
             }
         });
@@ -339,14 +339,14 @@
         r.register1("floatToRawIntBits", float.class, new InvocationPlugin() {
             @Override
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
-                b.push(JavaKind.Int, b.recursiveAppend(new ReinterpretNode(JavaKind.Int, value).canonical(null)));
+                b.push(JavaKind.Int, b.append(new ReinterpretNode(JavaKind.Int, value).canonical(null)));
                 return true;
             }
         });
         r.register1("intBitsToFloat", int.class, new InvocationPlugin() {
             @Override
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
-                b.push(JavaKind.Float, b.recursiveAppend(new ReinterpretNode(JavaKind.Float, value).canonical(null)));
+                b.push(JavaKind.Float, b.append(new ReinterpretNode(JavaKind.Float, value).canonical(null)));
                 return true;
             }
         });
@@ -357,14 +357,14 @@
         r.register1("doubleToRawLongBits", double.class, new InvocationPlugin() {
             @Override
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
-                b.push(JavaKind.Long, b.recursiveAppend(new ReinterpretNode(JavaKind.Long, value).canonical(null)));
+                b.push(JavaKind.Long, b.append(new ReinterpretNode(JavaKind.Long, value).canonical(null)));
                 return true;
             }
         });
         r.register1("longBitsToDouble", long.class, new InvocationPlugin() {
             @Override
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
-                b.push(JavaKind.Double, b.recursiveAppend(new ReinterpretNode(JavaKind.Double, value).canonical(null)));
+                b.push(JavaKind.Double, b.append(new ReinterpretNode(JavaKind.Double, value).canonical(null)));
                 return true;
             }
         });
@@ -402,21 +402,21 @@
 
             @Override
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
-                b.push(JavaKind.Float, b.recursiveAppend(new AbsNode(value).canonical(null)));
+                b.push(JavaKind.Float, b.append(new AbsNode(value).canonical(null)));
                 return true;
             }
         });
         r.register1("abs", Double.TYPE, new InvocationPlugin() {
             @Override
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
-                b.push(JavaKind.Double, b.recursiveAppend(new AbsNode(value).canonical(null)));
+                b.push(JavaKind.Double, b.append(new AbsNode(value).canonical(null)));
                 return true;
             }
         });
         r.register1("sqrt", Double.TYPE, new InvocationPlugin() {
             @Override
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
-                b.push(JavaKind.Double, b.recursiveAppend(new SqrtNode(value).canonical(null)));
+                b.push(JavaKind.Double, b.append(new SqrtNode(value).canonical(null)));
                 return true;
             }
         });
@@ -465,7 +465,7 @@
                 cond = cond.negate();
             }
 
-            LogicNode compare = CompareNode.createCompareNode(graph, cond, lhs, rhs, b.getConstantReflection());
+            LogicNode compare = CompareNode.createCompareNode(graph, b.getConstantReflection(), b.getMetaAccess(), b.getOptions(), null, cond, lhs, rhs);
             b.addPush(JavaKind.Boolean, new ConditionalNode(compare, trueValue, falseValue));
             return true;
         }
@@ -533,16 +533,16 @@
         r.register2("isInstance", Receiver.class, Object.class, new InvocationPlugin() {
             @Override
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver type, ValueNode object) {
-                LogicNode condition = b.recursiveAppend(InstanceOfDynamicNode.create(b.getAssumptions(), b.getConstantReflection(), type.get(), object, false));
-                b.push(JavaKind.Boolean, b.recursiveAppend(new ConditionalNode(condition).canonical(null)));
+                LogicNode condition = b.append(InstanceOfDynamicNode.create(b.getAssumptions(), b.getConstantReflection(), type.get(), object, false));
+                b.push(JavaKind.Boolean, b.append(new ConditionalNode(condition).canonical(null)));
                 return true;
             }
         });
         r.register2("isAssignableFrom", Receiver.class, Class.class, new InvocationPlugin() {
             @Override
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver type, ValueNode otherType) {
-                ClassIsAssignableFromNode condition = b.recursiveAppend(new ClassIsAssignableFromNode(type.get(), otherType));
-                b.push(JavaKind.Boolean, b.recursiveAppend(new ConditionalNode(condition).canonical(null)));
+                ClassIsAssignableFromNode condition = b.append(new ClassIsAssignableFromNode(type.get(), otherType));
+                b.push(JavaKind.Boolean, b.append(new ConditionalNode(condition).canonical(null)));
                 return true;
             }
         });
@@ -884,7 +884,8 @@
                             b.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter));
                         } else if (falseCount == 0 || trueCount == 0) {
                             boolean expected = falseCount == 0;
-                            LogicNode condition = b.addWithInputs(IntegerEqualsNode.create(result, b.add(ConstantNode.forBoolean(!expected))));
+                            LogicNode condition = b.addWithInputs(
+                                            IntegerEqualsNode.create(b.getConstantReflection(), b.getMetaAccess(), b.getOptions(), null, result, b.add(ConstantNode.forBoolean(!expected))));
                             b.append(new FixedGuardNode(condition, DeoptimizationReason.UnreachedCode, DeoptimizationAction.InvalidateReprofile, true));
                             newResult = b.add(ConstantNode.forBoolean(expected));
                         } else {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StringIndexOfNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StringIndexOfNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,11 +22,12 @@
  */
 package org.graalvm.compiler.replacements;
 
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_256;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_64;
+
 import org.graalvm.compiler.core.common.type.StampPair;
 import org.graalvm.compiler.graph.NodeClass;
-import org.graalvm.compiler.nodeinfo.NodeCycles;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
-import org.graalvm.compiler.nodeinfo.NodeSize;
 import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
@@ -34,7 +35,7 @@
 
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 
-@NodeInfo(size = NodeSize.SIZE_50, cycles = NodeCycles.CYCLES_200)
+@NodeInfo(size = SIZE_64, cycles = CYCLES_256)
 public class StringIndexOfNode extends MacroStateSplitNode {
     public static final NodeClass<StringIndexOfNode> TYPE = NodeClass.create(StringIndexOfNode.class);
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayEqualsNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayEqualsNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -23,8 +23,8 @@
 package org.graalvm.compiler.replacements.nodes;
 
 import static org.graalvm.compiler.nodeinfo.InputType.Memory;
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_100;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_50;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1024;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1024;
 
 import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.core.common.type.StampFactory;
@@ -57,7 +57,7 @@
 /**
  * Compares two arrays with the same length.
  */
-@NodeInfo(cycles = CYCLES_100, size = SIZE_50)
+@NodeInfo(cycles = CYCLES_1024, size = SIZE_1024)
 public final class ArrayEqualsNode extends FixedWithNextNode implements LIRLowerable, Canonicalizable, Virtualizable, MemoryAccess {
 
     public static final NodeClass<ArrayEqualsNode> TYPE = NodeClass.create(ArrayEqualsNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicArrayCopyNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicArrayCopyNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -25,8 +25,8 @@
 import static org.graalvm.compiler.core.common.LocationIdentity.any;
 import static org.graalvm.compiler.nodeinfo.InputType.Memory;
 import static org.graalvm.compiler.nodeinfo.InputType.State;
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_200;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_100;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_256;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_64;
 
 import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.core.common.type.StampFactory;
@@ -55,7 +55,7 @@
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.ResolvedJavaType;
 
-@NodeInfo(cycles = CYCLES_200, size = SIZE_100)
+@NodeInfo(cycles = CYCLES_256, size = SIZE_64)
 public class BasicArrayCopyNode extends AbstractMemoryCheckpoint implements Virtualizable, MemoryCheckpoint.Single, MemoryAccess, Lowerable, DeoptimizingNode.DeoptDuring {
 
     public static final NodeClass<BasicArrayCopyNode> TYPE = NodeClass.create(BasicArrayCopyNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicObjectCloneNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicObjectCloneNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,6 +22,9 @@
  */
 package org.graalvm.compiler.replacements.nodes;
 
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8;
+
 import java.util.Collections;
 
 import org.graalvm.compiler.core.common.type.ObjectStamp;
@@ -46,7 +49,7 @@
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.meta.ResolvedJavaType;
 
-@NodeInfo
+@NodeInfo(cycles = CYCLES_8, size = SIZE_8)
 public abstract class BasicObjectCloneNode extends MacroStateSplitNode implements VirtualizableAllocation, ArrayLengthProvider {
 
     public static final NodeClass<BasicObjectCloneNode> TYPE = NodeClass.create(BasicObjectCloneNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BitCountNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BitCountNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,7 +22,7 @@
  */
 package org.graalvm.compiler.replacements.nodes;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
 
 import org.graalvm.compiler.core.common.type.IntegerStamp;
@@ -42,7 +42,7 @@
 import jdk.vm.ci.meta.JavaConstant;
 import jdk.vm.ci.meta.JavaKind;
 
-@NodeInfo(cycles = CYCLES_3, size = SIZE_1)
+@NodeInfo(cycles = CYCLES_2, size = SIZE_1)
 public final class BitCountNode extends UnaryNode implements ArithmeticLIRLowerable {
 
     public static final NodeClass<BitCountNode> TYPE = NodeClass.create(BitCountNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BitScanForwardNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BitScanForwardNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,7 +22,7 @@
  */
 package org.graalvm.compiler.replacements.nodes;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
 
 import org.graalvm.compiler.core.common.type.IntegerStamp;
@@ -47,7 +47,7 @@
  * Determines the index of the least significant "1" bit. Note that the result is undefined if the
  * input is zero.
  */
-@NodeInfo(cycles = CYCLES_3, size = SIZE_1)
+@NodeInfo(cycles = CYCLES_2, size = SIZE_1)
 public final class BitScanForwardNode extends UnaryNode implements ArithmeticLIRLowerable {
 
     public static final NodeClass<BitScanForwardNode> TYPE = NodeClass.create(BitScanForwardNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BitScanReverseNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BitScanReverseNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,7 +22,7 @@
  */
 package org.graalvm.compiler.replacements.nodes;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
 
 import org.graalvm.compiler.core.common.type.IntegerStamp;
@@ -47,7 +47,7 @@
  * Determines the index of the most significant "1" bit. Note that the result is undefined if the
  * input is zero.
  */
-@NodeInfo(cycles = CYCLES_3, size = SIZE_1)
+@NodeInfo(cycles = CYCLES_2, size = SIZE_1)
 public final class BitScanReverseNode extends UnaryNode implements ArithmeticLIRLowerable {
 
     public static final NodeClass<BitScanReverseNode> TYPE = NodeClass.create(BitScanReverseNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/DirectStoreNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/DirectStoreNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,7 +22,7 @@
  */
 package org.graalvm.compiler.replacements.nodes;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_3;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
 
 import org.graalvm.compiler.core.common.LIRKind;
@@ -43,7 +43,7 @@
  * A special purpose store node that differs from {@link RawStoreNode} in that it is not a
  * {@link StateSplit} and takes a computed address instead of an object.
  */
-@NodeInfo(cycles = CYCLES_3, size = SIZE_1)
+@NodeInfo(cycles = CYCLES_2, size = SIZE_1)
 public final class DirectStoreNode extends FixedWithNextNode implements LIRLowerable {
 
     public static final NodeClass<DirectStoreNode> TYPE = NodeClass.create(DirectStoreNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -138,7 +138,7 @@
     @SuppressWarnings("try")
     protected StructuredGraph lowerReplacement(final StructuredGraph replacementGraph, LoweringTool tool) {
         final PhaseContext c = new PhaseContext(tool.getMetaAccess(), tool.getConstantReflection(), tool.getConstantFieldProvider(), tool.getLowerer(), tool.getReplacements(),
-                        tool.getStampProvider(), tool.getNodeCostProvider());
+                        tool.getStampProvider());
         if (!graph().hasValueProxies()) {
             new RemoveValueProxyPhase().apply(replacementGraph);
         }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ReadRegisterNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ReadRegisterNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,8 +22,8 @@
  */
 package org.graalvm.compiler.replacements.nodes;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
 
 import org.graalvm.compiler.core.common.LIRKind;
 import org.graalvm.compiler.core.common.type.Stamp;
@@ -42,7 +42,7 @@
 /**
  * Access the value of a specific register.
  */
-@NodeInfo(nameTemplate = "ReadRegister %{p#register}", cycles = CYCLES_1, size = SIZE_1)
+@NodeInfo(nameTemplate = "ReadRegister %{p#register}", cycles = CYCLES_0, size = SIZE_0)
 public final class ReadRegisterNode extends FixedWithNextNode implements LIRLowerable {
 
     public static final NodeClass<ReadRegisterNode> TYPE = NodeClass.create(ReadRegisterNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/UnaryMathIntrinsicNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/UnaryMathIntrinsicNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,7 +22,7 @@
  */
 package org.graalvm.compiler.replacements.nodes;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_64;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
 
 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
@@ -46,7 +46,7 @@
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.Value;
 
-@NodeInfo(nameTemplate = "MathIntrinsic#{p#operation/s}", cycles = CYCLES_UNKNOWN, size = SIZE_1)
+@NodeInfo(nameTemplate = "MathIntrinsic#{p#operation/s}", cycles = CYCLES_64, size = SIZE_1)
 public final class UnaryMathIntrinsicNode extends UnaryNode implements ArithmeticLIRLowerable, Lowerable {
 
     public static final NodeClass<UnaryMathIntrinsicNode> TYPE = NodeClass.create(UnaryMathIntrinsicNode.class);
@@ -197,4 +197,5 @@
 
     @NodeIntrinsic
     public static native double compute(double value, @ConstantNodeParameter UnaryOperation op);
+
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/WriteRegisterNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/WriteRegisterNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,6 +22,9 @@
  */
 package org.graalvm.compiler.replacements.nodes;
 
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
@@ -37,7 +40,7 @@
 /**
  * Changes the value of a specific register.
  */
-@NodeInfo(nameTemplate = "WriteRegister %{p#register}")
+@NodeInfo(nameTemplate = "WriteRegister %{p#register}", cycles = CYCLES_2, size = SIZE_1)
 public final class WriteRegisterNode extends FixedWithNextNode implements LIRLowerable {
 
     public static final NodeClass<WriteRegisterNode> TYPE = NodeClass.create(WriteRegisterNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/IntegerMulExactSplitNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/IntegerMulExactSplitNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,6 +22,8 @@
  */
 package org.graalvm.compiler.replacements.nodes.arithmetic;
 
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_4;
+
 import org.graalvm.compiler.core.common.type.IntegerStamp;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.graph.NodeClass;
@@ -34,7 +36,7 @@
 
 import jdk.vm.ci.meta.Value;
 
-@NodeInfo
+@NodeInfo(cycles = CYCLES_4, cyclesRationale = "mul + cmp")
 public final class IntegerMulExactSplitNode extends IntegerExactArithmeticSplitNode {
     public static final NodeClass<IntegerMulExactSplitNode> TYPE = NodeClass.create(IntegerMulExactSplitNode.class);
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/UnsignedMulHighNode.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/UnsignedMulHighNode.java	Wed Apr 19 04:10:56 2017 +0000
@@ -22,8 +22,8 @@
  */
 package org.graalvm.compiler.replacements.nodes.arithmetic;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_4;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_4;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
 
 import java.util.function.BiFunction;
 
@@ -43,7 +43,7 @@
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.Value;
 
-@NodeInfo(shortName = "|*H|", cycles = CYCLES_4, cyclesRationale = "mul + mov", size = SIZE_4)
+@NodeInfo(shortName = "|*H|", cycles = CYCLES_2, size = SIZE_2)
 public final class UnsignedMulHighNode extends BinaryNode implements ArithmeticLIRLowerable {
 
     public static final NodeClass<UnsignedMulHighNode> TYPE = NodeClass.create(UnsignedMulHighNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/VirtualizerToolImpl.java	Tue Apr 18 20:10:55 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/VirtualizerToolImpl.java	Wed Apr 19 04:10:56 2017 +0000
@@ -258,11 +258,11 @@
     }
 
     @Override
-    public boolean supportSubwordCompare(int bits) {
+    public Integer smallestCompareWidth() {
         if (loweringProvider != null) {
-            return loweringProvider.supportSubwordCompare(bits);
+            return loweringProvider.smallestCompareWidth();
         } else {
-            return false;
+            return null;
         }
     }
 }