changeset 16201:6140fd60abe9

Merge.
author Doug Simon <doug.simon@oracle.com>
date Tue, 24 Jun 2014 23:29:13 +0200
parents 38bb9b5b8544 (current diff) 8fde32ece68e (diff)
children 04c0c507d123
files graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java mx/mx_graal.py
diffstat 118 files changed, 1429 insertions(+), 524 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java	Tue Jun 24 23:29:13 2014 +0200
@@ -417,7 +417,7 @@
         return builder -> {
             LIRKind writeKind = getLIRGeneratorTool().getLIRKind(root.value().stamp());
             Value address = root.location().generateAddress(builder, getLIRGeneratorTool(), operand(root.object()));
-            Value v = operand(narrow.getInput());
+            Value v = operand(narrow.getValue());
             getLIRGeneratorTool().emitStore(writeKind, address, v, state(root));
             return null;
         };
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/ObjectStamp.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/ObjectStamp.java	Tue Jun 24 23:29:13 2014 +0200
@@ -64,4 +64,13 @@
         }
         return false;
     }
+
+    @Override
+    public Constant asConstant() {
+        if (alwaysNull()) {
+            return Constant.NULL_OBJECT;
+        } else {
+            return null;
+        }
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FloatOptimizationTest.java	Tue Jun 24 23:29:13 2014 +0200
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.test;
+
+import org.junit.*;
+
+/**
+ * Check for incorrect elimination of 0.0 and -0.0 from computations. They can affect the sign of
+ * the result of an add or substract.
+ */
+public class FloatOptimizationTest extends GraalCompilerTest {
+
+    @Test
+    public void test1() {
+        test("test1Snippet", -0.0);
+    }
+
+    @SuppressWarnings("all")
+    public static double test1Snippet(double x) {
+        return x + 0.0;
+    }
+
+    @Test
+    public void test2() {
+        test("test2Snippet", -0.0f);
+    }
+
+    @SuppressWarnings("all")
+    public static double test2Snippet(float x) {
+        return x + 0.0f;
+    }
+
+    @Test
+    public void test3() {
+        test("test3Snippet", -0.0);
+    }
+
+    @SuppressWarnings("all")
+    public static double test3Snippet(double x) {
+        return x - -0.0;
+    }
+
+    @Test
+    public void test4() {
+        test("test4Snippet", -0.0f);
+    }
+
+    @SuppressWarnings("all")
+    public static double test4Snippet(float x) {
+        return x - -0.0f;
+    }
+
+    @Override
+    protected void assertDeepEquals(String message, Object expected, Object actual, double delta) {
+        if (expected instanceof Double && actual instanceof Double) {
+            double e = (double) expected;
+            double a = (double) actual;
+            if (Double.doubleToRawLongBits(a) != Double.doubleToRawLongBits(e)) {
+                Assert.fail((message == null ? "" : message) + "raw double bits not equal " + Double.doubleToRawLongBits(a) + " != " + Double.doubleToRawLongBits(e));
+            }
+        } else {
+            super.assertDeepEquals(message, expected, actual, delta);
+        }
+    }
+}
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java	Tue Jun 24 23:29:13 2014 +0200
@@ -55,19 +55,19 @@
  * This class traverses the HIR instructions and generates LIR instructions from them.
  */
 @MatchableNode(nodeClass = ConstantNode.class, shareable = true)
-@MatchableNode(nodeClass = FloatConvertNode.class, inputs = {"input"})
+@MatchableNode(nodeClass = FloatConvertNode.class, inputs = {"value"})
 @MatchableNode(nodeClass = FloatSubNode.class, inputs = {"x", "y"})
 @MatchableNode(nodeClass = FloatingReadNode.class, inputs = {"object", "location"})
 @MatchableNode(nodeClass = IfNode.class, inputs = {"condition"})
 @MatchableNode(nodeClass = IntegerSubNode.class, inputs = {"x", "y"})
 @MatchableNode(nodeClass = LeftShiftNode.class, inputs = {"x", "y"})
-@MatchableNode(nodeClass = NarrowNode.class, inputs = {"input"})
+@MatchableNode(nodeClass = NarrowNode.class, inputs = {"value"})
 @MatchableNode(nodeClass = ReadNode.class, inputs = {"object", "location"})
 @MatchableNode(nodeClass = ReinterpretNode.class, inputs = {"value"})
-@MatchableNode(nodeClass = SignExtendNode.class, inputs = {"input"})
+@MatchableNode(nodeClass = SignExtendNode.class, inputs = {"value"})
 @MatchableNode(nodeClass = UnsignedRightShiftNode.class, inputs = {"x", "y"})
 @MatchableNode(nodeClass = WriteNode.class, inputs = {"object", "location", "value"})
-@MatchableNode(nodeClass = ZeroExtendNode.class, inputs = {"input"})
+@MatchableNode(nodeClass = ZeroExtendNode.class, inputs = {"value"})
 @MatchableNode(nodeClass = AndNode.class, inputs = {"x", "y"}, commutative = true)
 @MatchableNode(nodeClass = FloatAddNode.class, inputs = {"x", "y"}, commutative = true)
 @MatchableNode(nodeClass = FloatEqualsNode.class, inputs = {"x", "y"}, commutative = true)
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/ComplexMatchValue.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/ComplexMatchValue.java	Tue Jun 24 23:29:13 2014 +0200
@@ -37,7 +37,7 @@
      * This is the Value of a node which was matched as part of a complex match. The value isn't
      * actually useable but this marks it as having been evaluated.
      */
-    @SuppressWarnings("serial") public static Value INTERIOR_MATCH = new Value(LIRKind.Illegal) {
+    @SuppressWarnings("serial") public static final Value INTERIOR_MATCH = new Value(LIRKind.Illegal) {
 
         @Override
         public String toString() {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java	Tue Jun 24 23:29:13 2014 +0200
@@ -68,9 +68,6 @@
         for (int i = 0; i < names.length; i++) {
             for (NodeClass.Position position : nodeClass.getFirstLevelInputPositions()) {
                 String name = nodeClass.getName(position);
-                if (name.endsWith("#NDF")) {
-                    name = name.substring(0, name.length() - 4);
-                }
                 if (name.equals(names[i])) {
                     result[i] = position;
                     break;
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Tue Jun 24 23:29:13 2014 +0200
@@ -559,12 +559,13 @@
                     assert assertTrue(result, "not found in usages, old input: %s", oldInput);
                 }
             }
+            maybeNotifyChanged(this);
             if (newInput != null) {
                 if (newInput.recordsUsages()) {
-                    maybeNotifyChanged(this);
                     newInput.addUsage(this);
                 }
-            } else if (oldInput != null && oldInput.recordsUsages() && oldInput.usages().isEmpty()) {
+            }
+            if (oldInput != null && oldInput.recordsUsages() && oldInput.usages().isEmpty()) {
                 maybeNotifyZeroInputs(oldInput);
             }
         }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Tue Jun 24 23:29:13 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -298,9 +298,6 @@
                 }
                 types.put(offset, inputAnnotation.value());
                 names.put(offset, field.getName());
-                if (inputAnnotation.value() != InputType.Value) {
-                    fieldNames.put(offset, field.getName() + "#NDF");
-                }
             } else if (field.isAnnotationPresent(Node.Successor.class)) {
                 if (SUCCESSOR_LIST_CLASS.isAssignableFrom(type)) {
                     GraalInternalError.guarantee(Modifier.isFinal(field.getModifiers()), "NodeSuccessorList successor field % should be final", field);
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeWorkList.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeWorkList.java	Tue Jun 24 23:29:13 2014 +0200
@@ -50,6 +50,8 @@
 
     public abstract void add(Node node);
 
+    public abstract boolean contains(Node node);
+
     private abstract class QueueConsumingIterator implements Iterator<Node> {
 
         protected void dropDeleted() {
@@ -140,6 +142,20 @@
             }
         }
 
+        @Override
+        public boolean contains(Node node) {
+            if (inQueue != null) {
+                return inQueue.isMarked(node);
+            } else {
+                for (Node queuedNode : worklist) {
+                    if (queuedNode == node) {
+                        return true;
+                    }
+                }
+                return false;
+            }
+        }
+
         private boolean checkInfiniteWork(Node node) {
             if (lastPull == node) {
                 if (firstNoChange == null) {
@@ -186,6 +202,11 @@
         }
 
         @Override
+        public boolean contains(Node node) {
+            return visited.isMarked(node);
+        }
+
+        @Override
         public Iterator<Node> iterator() {
             return new QueueConsumingIterator() {
                 @Override
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/spi/SimplifierTool.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/spi/SimplifierTool.java	Tue Jun 24 23:29:13 2014 +0200
@@ -35,4 +35,6 @@
      * Adds a node to the worklist independent of whether it has already been on the worklist.
      */
     void addToWorkList(Node node);
+
+    void addToWorkList(Iterable<? extends Node> nodes);
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java	Tue Jun 24 23:29:13 2014 +0200
@@ -63,7 +63,7 @@
             result = ((PiNode) result).getOriginalNode();
         }
         if (result instanceof CompressionNode) {
-            result = ((CompressionNode) result).getInput();
+            result = ((CompressionNode) result).getValue();
         }
         return result;
     }
@@ -223,7 +223,7 @@
     boolean canFormCompressedMemory(CompressionNode compress, ConstantLocationNode location) {
         HotSpotVMConfig config = HotSpotGraalRuntime.runtime().getConfig();
         if (config.useCompressedOops && compress.getEncoding().shift <= 3 && NumUtil.isInt(location.getDisplacement())) {
-            Stamp compressedStamp = compress.getInput().stamp();
+            Stamp compressedStamp = compress.getValue().stamp();
             if (compressedStamp instanceof NarrowOopStamp) {
                 return true;
             } else if (compressedStamp instanceof IntegerStamp) {
@@ -236,7 +236,7 @@
 
     private AMD64AddressValue makeCompressedAddress(CompressionNode compress, ConstantLocationNode location) {
         assert canFormCompressedMemory(compress, location);
-        AMD64AddressValue address = getGen().emitAddress(getGen().getProviders().getRegisters().getHeapBaseRegister().asValue(), location.getDisplacement(), operand(compress.getInput()),
+        AMD64AddressValue address = getGen().emitAddress(getGen().getProviders().getRegisters().getHeapBaseRegister().asValue(), location.getDisplacement(), operand(compress.getValue()),
                         1 << compress.getEncoding().shift);
         return address;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotForeignCallLinkage.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotForeignCallLinkage.java	Tue Jun 24 23:29:13 2014 +0200
@@ -269,4 +269,12 @@
     public boolean needsJavaFrameAnchor() {
         return canDeoptimize() || transition == Transition.LEAF_SP;
     }
+
+    public CompilationResult getStubCompilationResult(final Backend backend) {
+        return stub.getCompilationResult(backend);
+    }
+
+    public Stub getStub() {
+        return stub;
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Tue Jun 24 23:29:13 2014 +0200
@@ -169,7 +169,7 @@
         @Option(help = "The runtime configuration to use")
         static final OptionValue<String> GraalRuntime = new OptionValue<>("");
 
-        @Option(help = "File to which logging is sent.  %p in the name will be replaced with a string the process, usually the process id.")
+        @Option(help = "File to which logging is sent.  A %p in the name will be replaced with a string identifying the process, usually the process id.")
         public static final PrintStreamOption LogFile = new PrintStreamOption();
         // @formatter:on
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotNodeLIRBuilder.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotNodeLIRBuilder.java	Tue Jun 24 23:29:13 2014 +0200
@@ -32,7 +32,7 @@
  * This interface defines the contract a HotSpot backend LIR generator needs to fulfill in addition
  * to abstract methods from {@link LIRGenerator} and {@link NodeLIRBuilderTool}.
  */
-@MatchableNode(nodeClass = CompressionNode.class, inputs = {"input"})
+@MatchableNode(nodeClass = CompressionNode.class, inputs = {"value"})
 public interface HotSpotNodeLIRBuilder {
 
     void emitPatchReturnAddress(ValueNode address);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Tue Jun 24 23:29:13 2014 +0200
@@ -1424,9 +1424,9 @@
     @HotSpotVMValue(expression = "GraalRuntime::dynamic_new_array", get = HotSpotVMValue.Type.ADDRESS) @Stable public long dynamicNewArrayAddress;
     @HotSpotVMValue(expression = "GraalRuntime::dynamic_new_instance", get = HotSpotVMValue.Type.ADDRESS) @Stable public long dynamicNewInstanceAddress;
     @HotSpotVMValue(expression = "GraalRuntime::thread_is_interrupted", get = HotSpotVMValue.Type.ADDRESS) @Stable public long threadIsInterruptedAddress;
-    @HotSpotVMValue(expression = "GraalRuntime::vm_message", get = HotSpotVMValue.Type.ADDRESS) @Stable public long vmMessageAddress;
+    @HotSpotVMValue(expression = "GraalRuntime::vm_message", signature = "(unsigned char, long, long, long, long)", get = HotSpotVMValue.Type.ADDRESS) @Stable public long vmMessageAddress;
     @HotSpotVMValue(expression = "GraalRuntime::identity_hash_code", get = HotSpotVMValue.Type.ADDRESS) @Stable public long identityHashCodeAddress;
-    @HotSpotVMValue(expression = "GraalRuntime::exception_handler_for_pc", get = HotSpotVMValue.Type.ADDRESS) @Stable public long exceptionHandlerForPcAddress;
+    @HotSpotVMValue(expression = "GraalRuntime::exception_handler_for_pc", signature = "(JavaThread*)", get = HotSpotVMValue.Type.ADDRESS) @Stable public long exceptionHandlerForPcAddress;
     @HotSpotVMValue(expression = "GraalRuntime::monitorenter", get = HotSpotVMValue.Type.ADDRESS) @Stable public long monitorenterAddress;
     @HotSpotVMValue(expression = "GraalRuntime::monitorexit", get = HotSpotVMValue.Type.ADDRESS) @Stable public long monitorexitAddress;
     @HotSpotVMValue(expression = "GraalRuntime::create_null_exception", get = HotSpotVMValue.Type.ADDRESS) @Stable public long createNullPointerExceptionAddress;
@@ -1452,9 +1452,9 @@
 
     @HotSpotVMValue(expression = "(jint) GraalCounterSize") @Stable public int graalCountersSize;
 
-    @HotSpotVMValue(expression = "Deoptimization::fetch_unroll_info", get = HotSpotVMValue.Type.ADDRESS) @Stable public long deoptimizationFetchUnrollInfo;
+    @HotSpotVMValue(expression = "Deoptimization::fetch_unroll_info", signature = "(JavaThread*)", get = HotSpotVMValue.Type.ADDRESS) @Stable public long deoptimizationFetchUnrollInfo;
     @HotSpotVMValue(expression = "Deoptimization::uncommon_trap", get = HotSpotVMValue.Type.ADDRESS) @Stable public long deoptimizationUncommonTrap;
-    @HotSpotVMValue(expression = "Deoptimization::unpack_frames", get = HotSpotVMValue.Type.ADDRESS) @Stable public long deoptimizationUnpackFrames;
+    @HotSpotVMValue(expression = "Deoptimization::unpack_frames", signature = "(JavaThread*, int)", get = HotSpotVMValue.Type.ADDRESS) @Stable public long deoptimizationUnpackFrames;
 
     @HotSpotVMConstant(name = "Deoptimization::Reason_none") @Stable public int deoptReasonNone;
     @HotSpotVMConstant(name = "Deoptimization::Reason_null_check") @Stable public int deoptReasonNullCheck;
@@ -1599,4 +1599,35 @@
             }
         }
     }
+
+    /**
+     * Returns the name of the C/C++ function that is associated (via HotSpotVMValue annotation)
+     * with the HotSpotVMConfig object's field containing {@code foreignCalltargetAddress}; returns
+     * null if no field holds the provided address.
+     *
+     * @param foreignCallTargetAddress address of foreign call target
+     * @return C/C++ symbol name or null
+     */
+    public String getCSymbol(long foreignCallTargetAddress) {
+        for (Field f : HotSpotVMConfig.class.getDeclaredFields()) {
+            if (f.isAnnotationPresent(HotSpotVMValue.class)) {
+                HotSpotVMValue annotation = f.getAnnotation(HotSpotVMValue.class);
+
+                if (annotation.get() == HotSpotVMValue.Type.ADDRESS) {
+                    try {
+                        if (foreignCallTargetAddress == f.getLong(this)) {
+                            return (annotation.expression() + annotation.signature());
+                        }
+                    } catch (IllegalArgumentException e1) {
+                        // TODO Auto-generated catch block
+                        e1.printStackTrace();
+                    } catch (IllegalAccessException e1) {
+                        // TODO Auto-generated catch block
+                        e1.printStackTrace();
+                    }
+                }
+            }
+        }
+        return null;
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java	Tue Jun 24 23:29:13 2014 +0200
@@ -87,7 +87,7 @@
      * @return the metaspace Method result or 0 is there is no unique concrete method for
      *         {@code metaspaceMethod}
      */
-    long findUniqueConcreteMethod(long metaspaceMethod);
+    long findUniqueConcreteMethod(long actualHolderMetaspaceKlass, long metaspaceMethod);
 
     /**
      * Returns the implementor for the given interface class.
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java	Tue Jun 24 23:29:13 2014 +0200
@@ -68,7 +68,7 @@
     public native boolean hasBalancedMonitors(long metaspaceMethod);
 
     @Override
-    public native long findUniqueConcreteMethod(long metaspaceMethod);
+    public native long findUniqueConcreteMethod(long actualHolderMetaspaceKlass, long metaspaceMethod);
 
     @Override
     public native long getKlassImplementor(long metaspaceKlass);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java	Tue Jun 24 23:29:13 2014 +0200
@@ -229,6 +229,12 @@
                 return runtime.getHostProviders().getMetaAccess().lookupJavaType((Class<?>) obj);
             }
         }
+        if (constant instanceof HotSpotMetaspaceConstant) {
+            Object obj = HotSpotMetaspaceConstant.getMetaspaceObject(constant);
+            if (obj instanceof HotSpotResolvedObjectType) {
+                return (ResolvedJavaType) obj;
+            }
+        }
         return null;
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java	Tue Jun 24 23:29:13 2014 +0200
@@ -175,4 +175,9 @@
         registerArrayCopy(Kind.Object, c.oopArraycopy, c.oopAlignedArraycopy, c.oopDisjointArraycopy, c.oopAlignedDisjointArraycopy);
         registerArrayCopy(Kind.Object, c.oopArraycopyUninit, c.oopAlignedArraycopyUninit, c.oopDisjointArraycopyUninit, c.oopAlignedDisjointArraycopyUninit, true);
     }
+
+    public HotSpotForeignCallLinkage getForeignCall(ForeignCallDescriptor descriptor) {
+        assert foreignCalls != null : descriptor;
+        return foreignCalls.get(descriptor);
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java	Tue Jun 24 23:29:13 2014 +0200
@@ -23,6 +23,7 @@
 package com.oracle.graal.hotspot.meta;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodes.*;
@@ -40,6 +41,8 @@
 
     IndexedLocationNode createArrayLocation(Graph graph, Kind elementKind, ValueNode index, boolean initialization);
 
+    Stamp loadStamp(Stamp stamp, Kind kind);
+
     ValueNode implicitLoadConvert(StructuredGraph graph, Kind kind, ValueNode value);
 
     ValueNode implicitStoreConvert(StructuredGraph graph, Kind kind, ValueNode value);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java	Tue Jun 24 23:29:13 2014 +0200
@@ -350,8 +350,8 @@
         return runtime().getCompilerToVM().getStackTraceElement(metaspaceMethod, bci);
     }
 
-    public ResolvedJavaMethod uniqueConcreteMethod() {
-        if (holder.isInterface()) {
+    public ResolvedJavaMethod uniqueConcreteMethod(HotSpotResolvedObjectType receiver) {
+        if (receiver.isInterface()) {
             // Cannot trust interfaces. Because of:
             // interface I { void foo(); }
             // class A { public void foo() {} }
@@ -362,7 +362,7 @@
             // seeing A.foo().
             return null;
         }
-        final long uniqueConcreteMethod = runtime().getCompilerToVM().findUniqueConcreteMethod(metaspaceMethod);
+        final long uniqueConcreteMethod = runtime().getCompilerToVM().findUniqueConcreteMethod(receiver.getMetaspaceKlass(), metaspaceMethod);
         if (uniqueConcreteMethod == 0) {
             return null;
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java	Tue Jun 24 23:29:13 2014 +0200
@@ -459,7 +459,26 @@
 
     @Override
     public ResolvedJavaMethod findUniqueConcreteMethod(ResolvedJavaMethod method) {
-        return ((HotSpotResolvedJavaMethod) method).uniqueConcreteMethod();
+        HotSpotResolvedJavaMethod hmethod = (HotSpotResolvedJavaMethod) method;
+        HotSpotResolvedObjectType declaredHolder = hmethod.getDeclaringClass();
+        /*
+         * Sometimes the receiver type in the graph hasn't stabilized to a subtype of declared
+         * holder, usually because of phis, so make sure that the type is related to the declared
+         * type before using it for lookup.
+         */
+        if (!declaredHolder.isAssignableFrom(this) || this.isArray() || this.equals(declaredHolder)) {
+            return hmethod.uniqueConcreteMethod(declaredHolder);
+        }
+        /*
+         * The holder may be a subtype of the decaredHolder so make sure to resolve the method to
+         * the correct method for the subtype.
+         */
+        HotSpotResolvedJavaMethod newMethod = (HotSpotResolvedJavaMethod) resolveMethod(hmethod, this);
+        if (newMethod != null && !hmethod.equals(newMethod)) {
+            hmethod = newMethod;
+        }
+
+        return hmethod.uniqueConcreteMethod(this);
     }
 
     /**
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CompressionNode.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CompressionNode.java	Tue Jun 24 23:29:13 2014 +0200
@@ -152,12 +152,12 @@
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
-        if (getInput().isConstant()) {
-            return ConstantNode.forConstant(stamp(), evalConst(getInput().asConstant()), tool.getMetaAccess(), graph());
-        } else if (getInput() instanceof CompressionNode) {
-            CompressionNode other = (CompressionNode) getInput();
+        if (getValue().isConstant()) {
+            return ConstantNode.forConstant(stamp(), evalConst(getValue().asConstant()), tool.getMetaAccess(), graph());
+        } else if (getValue() instanceof CompressionNode) {
+            CompressionNode other = (CompressionNode) getValue();
             if (op != other.op && encoding.equals(other.encoding)) {
-                return other.getInput();
+                return other.getValue();
             }
         }
         return this;
@@ -167,8 +167,8 @@
     public void generate(NodeLIRBuilderTool gen) {
         HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen.getLIRGeneratorTool();
         boolean nonNull;
-        if (getInput().stamp() instanceof AbstractObjectStamp) {
-            nonNull = StampTool.isObjectNonNull(getInput().stamp());
+        if (getValue().stamp() instanceof AbstractObjectStamp) {
+            nonNull = StampTool.isObjectNonNull(getValue().stamp());
         } else {
             // metaspace pointers are never null
             nonNull = true;
@@ -177,10 +177,10 @@
         Value result;
         switch (op) {
             case Compress:
-                result = hsGen.emitCompress(gen.operand(getInput()), encoding, nonNull);
+                result = hsGen.emitCompress(gen.operand(getValue()), encoding, nonNull);
                 break;
             case Uncompress:
-                result = hsGen.emitUncompress(gen.operand(getInput()), encoding, nonNull);
+                result = hsGen.emitUncompress(gen.operand(getValue()), encoding, nonNull);
                 break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/type/NarrowOopStamp.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/type/NarrowOopStamp.java	Tue Jun 24 23:29:13 2014 +0200
@@ -26,6 +26,7 @@
 import com.oracle.graal.compiler.common.spi.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.hotspot.HotSpotVMConfig.CompressEncoding;
+import com.oracle.graal.hotspot.meta.*;
 
 public class NarrowOopStamp extends AbstractObjectStamp {
 
@@ -100,4 +101,13 @@
         }
         return super.equals(other);
     }
+
+    @Override
+    public Constant asConstant() {
+        if (alwaysNull()) {
+            return HotSpotCompressedNullConstant.COMPRESSED_NULL;
+        } else {
+            return null;
+        }
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java	Tue Jun 24 23:29:13 2014 +0200
@@ -501,7 +501,7 @@
                     graph.addAfterFixed(graph.start(), invoke);
 
                     StructuredGraph inlineeGraph = providers.getReplacements().getSnippet(initCounter.getMethod());
-                    InliningUtil.inline(invoke, inlineeGraph, false);
+                    InliningUtil.inline(invoke, inlineeGraph, false, null);
 
                     List<ReturnNode> rets = graph.getNodes(ReturnNode.class).snapshot();
                     for (ReturnNode ret : rets) {
@@ -520,7 +520,7 @@
                         inlineeGraph = template(args).copySpecializedGraph();
 
                         // inlineeGraph = replacements.getSnippet(checkCounter.getMethod());
-                        InliningUtil.inline(invoke, inlineeGraph, false);
+                        InliningUtil.inline(invoke, inlineeGraph, false, null);
                     }
                 }
             }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java	Tue Jun 24 23:29:13 2014 +0200
@@ -64,6 +64,11 @@
     protected InstalledCode code;
 
     /**
+     * Compilation result from which {@link #code} was created.
+     */
+    protected CompilationResult compResult;
+
+    /**
      * The registers destroyed by this stub.
      */
     private Set<Register> destroyedRegisters;
@@ -152,7 +157,7 @@
                 CallingConvention incomingCc = linkage.getIncomingCallingConvention();
                 TargetDescription target = codeCache.getTarget();
 
-                final CompilationResult compResult = new CompilationResult();
+                compResult = new CompilationResult();
                 try (Scope s0 = Debug.scope("StubCompilation", graph, providers.getCodeCache())) {
                     Assumptions assumptions = new Assumptions(OptAssumptions.getValue());
                     SchedulePhase schedule = emitFrontEnd(providers, target, graph, assumptions, null, providers.getSuites().getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL,
@@ -182,6 +187,18 @@
             }
             assert code != null : "error installing stub " + this;
         }
+
         return code;
     }
+
+    /**
+     * Gets the compilation result for this stub, compiling it first if necessary, and installing it
+     * in code.
+     */
+    public synchronized CompilationResult getCompilationResult(final Backend backend) {
+        if (code == null) {
+            getCode(backend);
+        }
+        return compResult;
+    }
 }
--- a/graal/com.oracle.graal.hotspotvmconfig/src/com/oracle/graal/hotspotvmconfig/HotSpotVMValue.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.hotspotvmconfig/src/com/oracle/graal/hotspotvmconfig/HotSpotVMValue.java	Tue Jun 24 23:29:13 2014 +0200
@@ -45,6 +45,13 @@
         VALUE
     }
 
+    /**
+     * If {@link #expression} is a C++ function name, {@link #signature} represents the signature of
+     * the function.
+     *
+     */
+    String signature() default "";
+
     Type get() default Type.VALUE;
 
     /**
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java	Tue Jun 24 23:29:13 2014 +0200
@@ -67,11 +67,6 @@
         return value;
     }
 
-    @Override
-    public boolean recordsUsages() {
-        return true;
-    }
-
     /**
      * Gathers all the {@link ConstantNode}s that are inputs to the
      * {@linkplain StructuredGraph#getNodes() live nodes} in a given graph.
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Tue Jun 24 23:29:13 2014 +0200
@@ -560,11 +560,11 @@
             }
             boolean negateConditionalCondition;
             ValueNode otherValue;
-            if (constant == conditional.x()) {
-                otherValue = conditional.y();
+            if (constant == conditional.trueValue()) {
+                otherValue = conditional.falseValue();
                 negateConditionalCondition = false;
-            } else if (constant == conditional.y()) {
-                otherValue = conditional.x();
+            } else if (constant == conditional.falseValue()) {
+                otherValue = conditional.trueValue();
                 negateConditionalCondition = true;
             } else {
                 return null;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java	Tue Jun 24 23:29:13 2014 +0200
@@ -298,7 +298,7 @@
                             }
                         }
                         if (tool != null) {
-                            otherPhi.usages().forEach(tool::addToWorkList);
+                            tool.addToWorkList(otherPhi.usages());
                         }
                         otherPhi.replaceAtUsages(phi);
                         GraphUtil.killWithUnusedFloatingInputs(otherPhi);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java	Tue Jun 24 23:29:13 2014 +0200
@@ -164,7 +164,7 @@
         if (singleValue != null) {
             for (Node node : usages().snapshot()) {
                 if (node instanceof ProxyNode && ((ProxyNode) node).proxyPoint() instanceof LoopExitNode && ((LoopExitNode) ((ProxyNode) node).proxyPoint()).loopBegin() == merge) {
-                    node.usages().forEach(tool::addToWorkList);
+                    tool.addToWorkList(node.usages());
                     graph().replaceFloating((FloatingNode) node, singleValue);
                 }
             }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/TypeProfileProxyNode.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/TypeProfileProxyNode.java	Tue Jun 24 23:29:13 2014 +0200
@@ -35,17 +35,12 @@
 /**
  * A node that attaches a type profile to a proxied input node.
  */
-public final class TypeProfileProxyNode extends FloatingNode implements Canonicalizable, IterableNodeType, ValueProxy {
+public final class TypeProfileProxyNode extends UnaryNode implements Canonicalizable, IterableNodeType, ValueProxy {
 
-    @Input private ValueNode object;
     private final JavaTypeProfile profile;
     private transient ResolvedJavaType lastCheckedType;
     private transient JavaTypeProfile lastCheckedProfile;
 
-    public ValueNode getObject() {
-        return object;
-    }
-
     public static ValueNode create(ValueNode object, JavaTypeProfile profile) {
         if (StampTool.isExactType(object)) {
             return object;
@@ -61,9 +56,8 @@
         return object.graph().addWithoutUnique(new TypeProfileProxyNode(object, profile));
     }
 
-    private TypeProfileProxyNode(ValueNode object, JavaTypeProfile profile) {
-        super(object.stamp());
-        this.object = object;
+    private TypeProfileProxyNode(ValueNode value, JavaTypeProfile profile) {
+        super(value.stamp(), value);
         this.profile = profile;
     }
 
@@ -73,16 +67,16 @@
 
     @Override
     public boolean inferStamp() {
-        return updateStamp(object.stamp());
+        return updateStamp(getValue().stamp());
     }
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
-        if (StampTool.isExactType(object)) {
+        if (StampTool.isExactType(getValue())) {
             // The profile is useless - we know the type!
-            return object;
-        } else if (object instanceof TypeProfileProxyNode) {
-            TypeProfileProxyNode other = (TypeProfileProxyNode) object;
+            return getValue();
+        } else if (getValue() instanceof TypeProfileProxyNode) {
+            TypeProfileProxyNode other = (TypeProfileProxyNode) getValue();
             JavaTypeProfile otherProfile = other.getProfile();
             if (otherProfile == lastCheckedProfile) {
                 // We have already incorporated the knowledge about this profile => abort.
@@ -93,33 +87,33 @@
             if (newProfile.equals(otherProfile)) {
                 // We are useless - just use the other proxy node.
                 Debug.log("Canonicalize with other proxy node.");
-                return object;
+                return getValue();
             }
             if (newProfile != this.profile) {
                 Debug.log("Improved profile via other profile.");
-                return TypeProfileProxyNode.create(object, newProfile);
+                return TypeProfileProxyNode.create(getValue(), newProfile);
             }
-        } else if (StampTool.typeOrNull(object) != null) {
-            ResolvedJavaType type = StampTool.typeOrNull(object);
+        } else if (StampTool.typeOrNull(getValue()) != null) {
+            ResolvedJavaType type = StampTool.typeOrNull(getValue());
             ResolvedJavaType uniqueConcrete = type.findUniqueConcreteSubtype();
             if (uniqueConcrete != null) {
                 // Profile is useless => remove.
                 Debug.log("Profile useless, there is enough static type information available.");
-                return object;
+                return getValue();
             }
             if (Objects.equals(type, lastCheckedType)) {
                 // We have already incorporate the knowledge about this type => abort.
                 return this;
             }
             lastCheckedType = type;
-            JavaTypeProfile newProfile = this.profile.restrict(type, StampTool.isObjectNonNull(object));
+            JavaTypeProfile newProfile = this.profile.restrict(type, StampTool.isObjectNonNull(getValue()));
             if (newProfile != this.profile) {
                 Debug.log("Improved profile via static type information.");
                 if (newProfile.getTypes().length == 0) {
                     // Only null profiling is not beneficial enough to keep the node around.
-                    return object;
+                    return getValue();
                 }
-                return TypeProfileProxyNode.create(object, newProfile);
+                return TypeProfileProxyNode.create(getValue(), newProfile);
             }
         }
         return this;
@@ -127,6 +121,6 @@
 
     @Override
     public ValueNode getOriginalNode() {
-        return object;
+        return getValue();
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java	Tue Jun 24 23:29:13 2014 +0200
@@ -71,7 +71,7 @@
             if (x() instanceof SignExtendNode) {
                 SignExtendNode ext = (SignExtendNode) x();
                 if (rawY == ((1L << ext.getInputBits()) - 1)) {
-                    ValueNode result = graph().unique(new ZeroExtendNode(ext.getInput(), ext.getResultBits()));
+                    ValueNode result = graph().unique(new ZeroExtendNode(ext.getValue(), ext.getResultBits()));
                     return result;
                 }
             }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Tue Jun 24 23:29:13 2014 +0200
@@ -115,8 +115,8 @@
         } else if (x() instanceof ConvertNode && y() instanceof ConvertNode) {
             ConvertNode convertX = (ConvertNode) x();
             ConvertNode convertY = (ConvertNode) y();
-            if (convertX.preservesOrder(condition()) && convertY.preservesOrder(condition()) && convertX.getInput().stamp().isCompatible(convertY.getInput().stamp())) {
-                return graph().unique(duplicateModified(convertX.getInput(), convertY.getInput()));
+            if (convertX.preservesOrder(condition()) && convertY.preservesOrder(condition()) && convertX.getValue().stamp().isCompatible(convertY.getValue().stamp())) {
+                return graph().unique(duplicateModified(convertX.getValue(), convertY.getValue()));
             }
 
         }
@@ -126,20 +126,18 @@
     protected abstract CompareNode duplicateModified(ValueNode newX, ValueNode newY);
 
     protected Node canonicalizeSymmetricConstant(CanonicalizerTool tool, Constant constant, ValueNode nonConstant, boolean mirrored) {
-        if (nonConstant instanceof BinaryNode) {
-            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);
-            }
+        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;
             ConstantNode newConstant = canonicalConvertConstant(tool, convert, constant);
             if (newConstant != null) {
                 if (mirrored) {
-                    return graph().unique(duplicateModified(newConstant, convert.getInput()));
+                    return graph().unique(duplicateModified(newConstant, convert.getValue()));
                 } else {
-                    return graph().unique(duplicateModified(convert.getInput(), newConstant));
+                    return graph().unique(duplicateModified(convert.getValue(), newConstant));
                 }
             }
         }
@@ -150,7 +148,7 @@
         if (convert.preservesOrder(condition())) {
             Constant reverseConverted = convert.reverse(constant);
             if (convert.convert(reverseConverted).equals(constant)) {
-                return ConstantNode.forConstant(convert.getInput().stamp(), reverseConverted, tool.getMetaAccess(), convert.graph());
+                return ConstantNode.forConstant(convert.getValue().stamp(), reverseConverted, tool.getMetaAccess(), convert.graph());
             }
         }
         return null;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java	Tue Jun 24 23:29:13 2014 +0200
@@ -37,9 +37,11 @@
  * The {@code ConditionalNode} class represents a comparison that yields one of two values. Note
  * that these nodes are not built directly from the bytecode but are introduced by canonicalization.
  */
-public final class ConditionalNode extends BinaryNode implements Canonicalizable, LIRLowerable {
+public final class ConditionalNode extends FloatingNode implements Canonicalizable, LIRLowerable {
 
     @Input(InputType.Condition) private LogicNode condition;
+    @Input private ValueNode trueValue;
+    @Input private ValueNode falseValue;
 
     public LogicNode condition() {
         return condition;
@@ -50,38 +52,40 @@
     }
 
     public ConditionalNode(LogicNode condition, ValueNode trueValue, ValueNode falseValue) {
-        super(trueValue.stamp().meet(falseValue.stamp()), trueValue, falseValue);
+        super(trueValue.stamp().meet(falseValue.stamp()));
         assert trueValue.stamp().isCompatible(falseValue.stamp());
         this.condition = condition;
+        this.trueValue = trueValue;
+        this.falseValue = falseValue;
     }
 
     @Override
     public boolean inferStamp() {
-        return updateStamp(x().stamp().meet(y().stamp()));
+        return updateStamp(trueValue.stamp().meet(falseValue.stamp()));
     }
 
     public ValueNode trueValue() {
-        return x();
+        return trueValue;
     }
 
     public ValueNode falseValue() {
-        return y();
+        return falseValue;
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
+    public ValueNode canonical(CanonicalizerTool tool) {
         if (condition instanceof LogicNegationNode) {
             LogicNegationNode negated = (LogicNegationNode) condition;
             return graph().unique(new ConditionalNode(negated.getInput(), falseValue(), trueValue()));
         }
 
         // this optimizes the case where a value that can only be 0 or 1 is materialized to 0 or 1
-        if (x().isConstant() && y().isConstant() && condition instanceof IntegerEqualsNode) {
+        if (trueValue().isConstant() && falseValue().isConstant() && condition instanceof IntegerEqualsNode) {
             IntegerEqualsNode equals = (IntegerEqualsNode) condition;
             if (equals.y().isConstant() && equals.y().asConstant().equals(Constant.INT_0) && equals.x().stamp() instanceof IntegerStamp) {
                 IntegerStamp equalsXStamp = (IntegerStamp) equals.x().stamp();
                 if (equalsXStamp.upMask() == 1) {
-                    if (x().asConstant().equals(Constant.INT_0) && y().asConstant().equals(Constant.INT_1)) {
+                    if (trueValue().asConstant().equals(Constant.INT_0) && falseValue().asConstant().equals(Constant.INT_1)) {
                         return IntegerConvertNode.convertUnsigned(equals.x(), stamp());
                     }
                 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java	Tue Jun 24 23:29:13 2014 +0200
@@ -31,17 +31,10 @@
 /**
  * Represents a conversion between primitive types.
  */
-public abstract class ConvertNode extends FloatingNode implements ArithmeticOperation {
-
-    @Input private ValueNode input;
+public abstract class ConvertNode extends UnaryNode implements ArithmeticOperation {
 
-    protected ConvertNode(Stamp stamp, ValueNode input) {
-        super(stamp);
-        this.input = input;
-    }
-
-    public ValueNode getInput() {
-        return input;
+    protected ConvertNode(Stamp stamp, ValueNode value) {
+        super(stamp, value);
     }
 
     public abstract Constant convert(Constant c);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatAddNode.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatAddNode.java	Tue Jun 24 23:29:13 2014 +0200
@@ -55,12 +55,8 @@
         }
         if (x().isConstant()) {
             return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
-        } else if (y().isConstant()) {
-            Constant c = y().asConstant();
-            if ((c.getKind() == Kind.Float && c.asFloat() == 0.0f) || (c.getKind() == Kind.Double && c.asDouble() == 0.0)) {
-                return x();
-            }
         }
+        // Constant 0.0 can't be eliminated since it can affect the sign of the result.
         return this;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatConvertNode.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatConvertNode.java	Tue Jun 24 23:29:13 2014 +0200
@@ -95,7 +95,7 @@
 
     @Override
     public boolean inferStamp() {
-        return updateStamp(createStamp(op, getInput()));
+        return updateStamp(createStamp(op, getValue()));
     }
 
     private static Constant convert(FloatConvert op, Constant value) {
@@ -148,12 +148,12 @@
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
-        if (getInput().isConstant()) {
-            return ConstantNode.forPrimitive(evalConst(getInput().asConstant()), graph());
-        } else if (getInput() instanceof FloatConvertNode) {
-            FloatConvertNode other = (FloatConvertNode) getInput();
+        if (getValue().isConstant()) {
+            return ConstantNode.forPrimitive(evalConst(getValue().asConstant()), graph());
+        } else if (getValue() instanceof FloatConvertNode) {
+            FloatConvertNode other = (FloatConvertNode) getValue();
             if (other.isLossless() && other.op == this.op.reverse()) {
-                return other.getInput();
+                return other.getValue();
             }
         }
         return this;
@@ -164,6 +164,6 @@
     }
 
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        builder.setResult(this, gen.emitFloatConvert(op, builder.operand(getInput())));
+        builder.setResult(this, gen.emitFloatConvert(op, builder.operand(getValue())));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatSubNode.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatSubNode.java	Tue Jun 24 23:29:13 2014 +0200
@@ -55,23 +55,8 @@
         }
         if (x().isConstant() && y().isConstant()) {
             return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
-        } else if (y().isConstant()) {
-            Constant c = y().asConstant();
-            if (c.getKind() == Kind.Float) {
-                float f = c.asFloat();
-                if (f == 0.0f) {
-                    return x();
-                }
-                return graph().unique(new FloatAddNode(stamp(), x(), ConstantNode.forFloat(-f, graph()), isStrictFP()));
-            } else {
-                assert c.getKind() == Kind.Double;
-                double d = c.asDouble();
-                if (d == 0.0) {
-                    return x();
-                }
-                return graph().unique(new FloatAddNode(stamp(), x(), ConstantNode.forDouble(-d, graph()), isStrictFP()));
-            }
         }
+        // Constant 0.0 can't be eliminated since it can affect the sign of the result.
         return this;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java	Tue Jun 24 23:29:13 2014 +0200
@@ -82,9 +82,9 @@
             }
         }
         if (x() instanceof NegateNode) {
-            return IntegerArithmeticNode.sub(graph(), y(), ((NegateNode) x()).x());
+            return IntegerArithmeticNode.sub(graph(), y(), ((NegateNode) x()).getValue());
         } else if (y() instanceof NegateNode) {
-            return IntegerArithmeticNode.sub(graph(), x(), ((NegateNode) y()).x());
+            return IntegerArithmeticNode.sub(graph(), x(), ((NegateNode) y()).getValue());
         }
         return this;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerConvertNode.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerConvertNode.java	Tue Jun 24 23:29:13 2014 +0200
@@ -45,8 +45,8 @@
     }
 
     public int getInputBits() {
-        if (getInput().stamp() instanceof IntegerStamp) {
-            return ((IntegerStamp) getInput().stamp()).getBits();
+        if (getValue().stamp() instanceof IntegerStamp) {
+            return ((IntegerStamp) getValue().stamp()).getBits();
         } else {
             return 0;
         }
@@ -61,12 +61,12 @@
     }
 
     protected ValueNode canonicalConvert() {
-        if (getInput().stamp() instanceof IntegerStamp) {
-            int inputBits = ((IntegerStamp) getInput().stamp()).getBits();
+        if (getValue().stamp() instanceof IntegerStamp) {
+            int inputBits = ((IntegerStamp) getValue().stamp()).getBits();
             if (inputBits == resultBits) {
-                return getInput();
-            } else if (getInput().isConstant()) {
-                Constant ret = evalConst(getInput().asConstant());
+                return getValue();
+            } else if (getValue().isConstant()) {
+                Constant ret = evalConst(getValue().asConstant());
                 return ConstantNode.forIntegerBits(resultBits, ret.asLong(), graph());
             }
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java	Tue Jun 24 23:29:13 2014 +0200
@@ -112,7 +112,7 @@
             return BinaryNode.reassociate(this, ValueNode.isConstantPredicate());
         }
         if (y() instanceof NegateNode) {
-            return IntegerArithmeticNode.add(graph(), x(), ((NegateNode) y()).x());
+            return IntegerArithmeticNode.add(graph(), x(), ((NegateNode) y()).getValue());
         }
         return this;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java	Tue Jun 24 23:29:13 2014 +0200
@@ -68,31 +68,31 @@
             return ret;
         }
 
-        if (getInput() instanceof NarrowNode) {
+        if (getValue() instanceof NarrowNode) {
             // zzzzzzzz yyyyxxxx -(narrow)-> yyyyxxxx -(narrow)-> xxxx
             // ==> zzzzzzzz yyyyxxxx -(narrow)-> xxxx
-            NarrowNode other = (NarrowNode) getInput();
-            return graph().unique(new NarrowNode(other.getInput(), getResultBits()));
-        } else if (getInput() instanceof IntegerConvertNode) {
+            NarrowNode other = (NarrowNode) getValue();
+            return graph().unique(new NarrowNode(other.getValue(), getResultBits()));
+        } else if (getValue() instanceof IntegerConvertNode) {
             // SignExtendNode or ZeroExtendNode
-            IntegerConvertNode other = (IntegerConvertNode) getInput();
+            IntegerConvertNode other = (IntegerConvertNode) getValue();
             if (getResultBits() == other.getInputBits()) {
                 // xxxx -(extend)-> yyyy xxxx -(narrow)-> xxxx
                 // ==> no-op
-                return other.getInput();
+                return other.getValue();
             } else if (getResultBits() < other.getInputBits()) {
                 // yyyyxxxx -(extend)-> zzzzzzzz yyyyxxxx -(narrow)-> xxxx
                 // ==> yyyyxxxx -(narrow)-> xxxx
-                return graph().unique(new NarrowNode(other.getInput(), getResultBits()));
+                return graph().unique(new NarrowNode(other.getValue(), getResultBits()));
             } else {
                 if (other instanceof SignExtendNode) {
                     // sxxx -(sign-extend)-> ssssssss sssssxxx -(narrow)-> sssssxxx
                     // ==> sxxx -(sign-extend)-> sssssxxx
-                    return graph().unique(new SignExtendNode(other.getInput(), getResultBits()));
+                    return graph().unique(new SignExtendNode(other.getValue(), getResultBits()));
                 } else if (other instanceof ZeroExtendNode) {
                     // xxxx -(zero-extend)-> 00000000 00000xxx -(narrow)-> 0000xxxx
                     // ==> xxxx -(zero-extend)-> 0000xxxx
-                    return graph().unique(new ZeroExtendNode(other.getInput(), getResultBits()));
+                    return graph().unique(new ZeroExtendNode(other.getValue(), getResultBits()));
                 }
             }
         }
@@ -102,11 +102,11 @@
 
     @Override
     public boolean inferStamp() {
-        return updateStamp(StampTool.narrowingConversion(getInput().stamp(), getResultBits()));
+        return updateStamp(StampTool.narrowingConversion(getValue().stamp(), getResultBits()));
     }
 
     @Override
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        builder.setResult(this, gen.emitNarrow(builder.operand(getInput()), getResultBits()));
+        builder.setResult(this, gen.emitNarrow(builder.operand(getValue()), getResultBits()));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java	Tue Jun 24 23:29:13 2014 +0200
@@ -34,27 +34,20 @@
 /**
  * The {@code NegateNode} node negates its operand.
  */
-public final class NegateNode extends FloatingNode implements Canonicalizable, ArithmeticLIRLowerable, NarrowableArithmeticNode {
-
-    @Input private ValueNode x;
-
-    public ValueNode x() {
-        return x;
-    }
+public final class NegateNode extends UnaryNode implements Canonicalizable, ArithmeticLIRLowerable, NarrowableArithmeticNode {
 
     @Override
     public boolean inferStamp() {
-        return updateStamp(StampTool.negate(x().stamp()));
+        return updateStamp(StampTool.negate(getValue().stamp()));
     }
 
     /**
      * Creates new NegateNode instance.
      *
-     * @param x the instruction producing the value that is input to this instruction
+     * @param value the instruction producing the value that is input to this instruction
      */
-    public NegateNode(ValueNode x) {
-        super(StampTool.negate(x.stamp()));
-        this.x = x;
+    public NegateNode(ValueNode value) {
+        super(StampTool.negate(value.stamp()), value);
     }
 
     public Constant evalConst(Constant... inputs) {
@@ -76,14 +69,14 @@
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
-        if (x().isConstant()) {
-            return ConstantNode.forPrimitive(evalConst(x.asConstant()), graph());
+        if (getValue().isConstant()) {
+            return ConstantNode.forPrimitive(evalConst(getValue().asConstant()), graph());
         }
-        if (x() instanceof NegateNode) {
-            return ((NegateNode) x()).x();
+        if (getValue() instanceof NegateNode) {
+            return ((NegateNode) getValue()).getValue();
         }
-        if (x() instanceof IntegerSubNode) {
-            IntegerSubNode sub = (IntegerSubNode) x;
+        if (getValue() instanceof IntegerSubNode) {
+            IntegerSubNode sub = (IntegerSubNode) getValue();
             return IntegerArithmeticNode.sub(graph(), sub.y(), sub.x());
         }
         return this;
@@ -91,6 +84,6 @@
 
     @Override
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        builder.setResult(this, gen.emitNegate(builder.operand(x())));
+        builder.setResult(this, gen.emitNegate(builder.operand(getValue())));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NotNode.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NotNode.java	Tue Jun 24 23:29:13 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -34,17 +34,11 @@
 /**
  * Binary negation of long or integer values.
  */
-public final class NotNode extends FloatingNode implements Canonicalizable, ArithmeticLIRLowerable, NarrowableArithmeticNode {
-
-    @Input private ValueNode x;
-
-    public ValueNode x() {
-        return x;
-    }
+public final class NotNode extends UnaryNode implements Canonicalizable, ArithmeticLIRLowerable, NarrowableArithmeticNode {
 
     @Override
     public boolean inferStamp() {
-        return updateStamp(StampTool.not(x().stamp()));
+        return updateStamp(StampTool.not(getValue().stamp()));
     }
 
     @Override
@@ -59,23 +53,22 @@
      * @param x the instruction producing the value that is input to this instruction
      */
     public NotNode(ValueNode x) {
-        super(StampTool.not(x.stamp()));
-        this.x = x;
+        super(StampTool.not(x.stamp()), x);
     }
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
-        if (x().isConstant()) {
-            return ConstantNode.forPrimitive(evalConst(x().asConstant()), graph());
+        if (getValue().isConstant()) {
+            return ConstantNode.forPrimitive(evalConst(getValue().asConstant()), graph());
         }
-        if (x() instanceof NotNode) {
-            return ((NotNode) x()).x();
+        if (getValue() instanceof NotNode) {
+            return ((NotNode) getValue()).getValue();
         }
         return this;
     }
 
     @Override
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        builder.setResult(this, gen.emitNot(builder.operand(x())));
+        builder.setResult(this, gen.emitNot(builder.operand(getValue())));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ReinterpretNode.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ReinterpretNode.java	Tue Jun 24 23:29:13 2014 +0200
@@ -36,22 +36,15 @@
  * of a primitive value to some other incompatible stamp. The new stamp must have the same width as
  * the old stamp.
  */
-public class ReinterpretNode extends FloatingNode implements Canonicalizable, ArithmeticLIRLowerable {
-
-    @Input private ValueNode value;
-
-    public ValueNode value() {
-        return value;
-    }
+public class ReinterpretNode extends UnaryNode implements Canonicalizable, ArithmeticLIRLowerable {
 
     private ReinterpretNode(Kind to, ValueNode value) {
         this(StampFactory.forKind(to), value);
     }
 
     public ReinterpretNode(Stamp to, ValueNode value) {
-        super(to);
+        super(to, value);
         assert to instanceof PrimitiveStamp;
-        this.value = value;
     }
 
     public Constant evalConst(Constant... inputs) {
@@ -89,15 +82,15 @@
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
-        if (value.isConstant()) {
-            return ConstantNode.forPrimitive(evalConst(value.asConstant()), graph());
+        if (getValue().isConstant()) {
+            return ConstantNode.forPrimitive(evalConst(getValue().asConstant()), graph());
         }
-        if (stamp().isCompatible(value.stamp())) {
-            return value;
+        if (stamp().isCompatible(getValue().stamp())) {
+            return getValue();
         }
-        if (value instanceof ReinterpretNode) {
-            ReinterpretNode reinterpret = (ReinterpretNode) value;
-            return value.graph().unique(new ReinterpretNode(stamp(), reinterpret.value()));
+        if (getValue() instanceof ReinterpretNode) {
+            ReinterpretNode reinterpret = (ReinterpretNode) getValue();
+            return getValue().graph().unique(new ReinterpretNode(stamp(), reinterpret.getValue()));
         }
         return this;
     }
@@ -105,7 +98,7 @@
     @Override
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
         LIRKind kind = gen.getLIRKind(stamp());
-        builder.setResult(this, gen.emitReinterpret(kind, builder.operand(value())));
+        builder.setResult(this, gen.emitReinterpret(kind, builder.operand(getValue())));
     }
 
     public static ValueNode reinterpret(Kind toKind, ValueNode value) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SignExtendNode.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SignExtendNode.java	Tue Jun 24 23:29:13 2014 +0200
@@ -74,26 +74,26 @@
             return ret;
         }
 
-        if (getInput() instanceof SignExtendNode) {
+        if (getValue() instanceof SignExtendNode) {
             // sxxx -(sign-extend)-> ssss sxxx -(sign-extend)-> ssssssss sssssxxx
             // ==> sxxx -(sign-extend)-> ssssssss sssssxxx
-            SignExtendNode other = (SignExtendNode) getInput();
-            return graph().unique(new SignExtendNode(other.getInput(), getResultBits()));
-        } else if (getInput() instanceof ZeroExtendNode) {
-            ZeroExtendNode other = (ZeroExtendNode) getInput();
+            SignExtendNode other = (SignExtendNode) getValue();
+            return graph().unique(new SignExtendNode(other.getValue(), getResultBits()));
+        } else if (getValue() instanceof ZeroExtendNode) {
+            ZeroExtendNode other = (ZeroExtendNode) getValue();
             if (other.getResultBits() > other.getInputBits()) {
                 // sxxx -(zero-extend)-> 0000 sxxx -(sign-extend)-> 00000000 0000sxxx
                 // ==> sxxx -(zero-extend)-> 00000000 0000sxxx
-                return graph().unique(new ZeroExtendNode(other.getInput(), getResultBits()));
+                return graph().unique(new ZeroExtendNode(other.getValue(), getResultBits()));
             }
         }
 
-        if (getInput().stamp() instanceof IntegerStamp) {
-            IntegerStamp inputStamp = (IntegerStamp) getInput().stamp();
+        if (getValue().stamp() instanceof IntegerStamp) {
+            IntegerStamp inputStamp = (IntegerStamp) getValue().stamp();
             if ((inputStamp.upMask() & (1L << (getInputBits() - 1))) == 0L) {
                 // 0xxx -(sign-extend)-> 0000 0xxx
                 // ==> 0xxx -(zero-extend)-> 0000 0xxx
-                return graph().unique(new ZeroExtendNode(getInput(), getResultBits()));
+                return graph().unique(new ZeroExtendNode(getValue(), getResultBits()));
             }
         }
 
@@ -102,11 +102,11 @@
 
     @Override
     public boolean inferStamp() {
-        return updateStamp(StampTool.signExtend(getInput().stamp(), getResultBits()));
+        return updateStamp(StampTool.signExtend(getValue().stamp(), getResultBits()));
     }
 
     @Override
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        builder.setResult(this, gen.emitSignExtend(builder.operand(getInput()), getInputBits(), getResultBits()));
+        builder.setResult(this, gen.emitSignExtend(builder.operand(getValue()), getInputBits(), getResultBits()));
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnaryNode.java	Tue Jun 24 23:29:13 2014 +0200
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes.calc;
+
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.nodes.*;
+
+/**
+ * The {@code UnaryNode} class is the base of arithmetic and bit logic operations with exactly one
+ * input.
+ */
+public abstract class UnaryNode extends FloatingNode {
+
+    @Input private ValueNode value;
+
+    public ValueNode getValue() {
+        return value;
+    }
+
+    /**
+     * Creates a new UnaryNode instance.
+     *
+     * @param stamp the result type of this instruction
+     * @param value the input instruction
+     */
+    public UnaryNode(Stamp stamp, ValueNode value) {
+        super(stamp);
+        this.value = value;
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedDivNode.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedDivNode.java	Tue Jun 24 23:29:13 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -36,7 +36,6 @@
     /**
      * Used by {@code NodeIntrinsic} in {@code UnsignedMathSubstitutions}.
      */
-    @SuppressWarnings("unused")
     private UnsignedDivNode(Kind kind, ValueNode x, ValueNode y) {
         this(StampFactory.forKind(kind), x, y);
     }
@@ -79,4 +78,10 @@
     public boolean canDeoptimize() {
         return !(y().stamp() instanceof IntegerStamp) || ((IntegerStamp) y().stamp()).contains(0);
     }
+
+    @NodeIntrinsic
+    public static native int unsignedDivide(@ConstantNodeParameter Kind kind, int a, int b);
+
+    @NodeIntrinsic
+    public static native long unsignedDivide(@ConstantNodeParameter Kind kind, long a, long b);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRemNode.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRemNode.java	Tue Jun 24 23:29:13 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -36,7 +36,6 @@
     /**
      * Used by {@code NodeIntrinsic} in {@code UnsignedMathSubstitutions}.
      */
-    @SuppressWarnings("unused")
     private UnsignedRemNode(Kind kind, ValueNode x, ValueNode y) {
         this(StampFactory.forKind(kind), x, y);
     }
@@ -78,4 +77,10 @@
     public boolean canDeoptimize() {
         return !(y().stamp() instanceof IntegerStamp) || ((IntegerStamp) y().stamp()).contains(0);
     }
+
+    @NodeIntrinsic
+    public static native int unsignedRemainder(@ConstantNodeParameter Kind kind, int a, int b);
+
+    @NodeIntrinsic
+    public static native long unsignedRemainder(@ConstantNodeParameter Kind kind, long a, long b);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ZeroExtendNode.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ZeroExtendNode.java	Tue Jun 24 23:29:13 2014 +0200
@@ -84,22 +84,22 @@
             return ret;
         }
 
-        if (getInput() instanceof ZeroExtendNode) {
+        if (getValue() instanceof ZeroExtendNode) {
             // xxxx -(zero-extend)-> 0000 xxxx -(zero-extend)-> 00000000 0000xxxx
             // ==> xxxx -(zero-extend)-> 00000000 0000xxxx
-            ZeroExtendNode other = (ZeroExtendNode) getInput();
-            return graph().unique(new ZeroExtendNode(other.getInput(), getResultBits()));
+            ZeroExtendNode other = (ZeroExtendNode) getValue();
+            return graph().unique(new ZeroExtendNode(other.getValue(), getResultBits()));
         }
-        if (getInput() instanceof NarrowNode) {
-            NarrowNode narrow = (NarrowNode) getInput();
-            Stamp inputStamp = narrow.getInput().stamp();
+        if (getValue() instanceof NarrowNode) {
+            NarrowNode narrow = (NarrowNode) getValue();
+            Stamp inputStamp = narrow.getValue().stamp();
             if (inputStamp instanceof IntegerStamp && inputStamp.isCompatible(stamp())) {
                 IntegerStamp istamp = (IntegerStamp) inputStamp;
                 long mask = IntegerStamp.defaultMask(PrimitiveStamp.getBits(narrow.stamp()));
                 if (((istamp.upMask() | istamp.downMask()) & ~mask) == 0) {
                     // The original value is in the range of the masked zero extended result so
                     // simply return the original input.
-                    return narrow.getInput();
+                    return narrow.getValue();
                 }
             }
         }
@@ -109,11 +109,11 @@
 
     @Override
     public boolean inferStamp() {
-        return updateStamp(StampTool.zeroExtend(getInput().stamp(), getResultBits()));
+        return updateStamp(StampTool.zeroExtend(getValue().stamp(), getResultBits()));
     }
 
     @Override
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        builder.setResult(this, gen.emitZeroExtend(builder.operand(getInput()), getInputBits(), getResultBits()));
+        builder.setResult(this, gen.emitZeroExtend(builder.operand(getValue()), getInputBits(), getResultBits()));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java	Tue Jun 24 23:29:13 2014 +0200
@@ -39,14 +39,12 @@
  * This node represents the boxing of a primitive value. This corresponds to a call to the valueOf
  * methods in Integer, Long, etc.
  */
-public class BoxNode extends FloatingNode implements VirtualizableAllocation, Lowerable, Canonicalizable {
+public class BoxNode extends UnaryNode implements VirtualizableAllocation, Lowerable, Canonicalizable {
 
-    @Input private ValueNode value;
     private final Kind boxingKind;
 
     public BoxNode(ValueNode value, ResolvedJavaType resultType, Kind boxingKind) {
-        super(StampFactory.exactNonNull(resultType));
-        this.value = value;
+        super(StampFactory.exactNonNull(resultType), value);
         this.boxingKind = boxingKind;
     }
 
@@ -54,10 +52,6 @@
         return boxingKind;
     }
 
-    public ValueNode getValue() {
-        return value;
-    }
-
     @Override
     public void lower(LoweringTool tool) {
         tool.getLowerer().lower(this, tool);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadMethodNode.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadMethodNode.java	Tue Jun 24 23:29:13 2014 +0200
@@ -24,13 +24,16 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
 
 /**
  * Loads a method from the virtual method table of a given hub.
  */
-public final class LoadMethodNode extends FixedWithNextNode implements Lowerable {
+public final class LoadMethodNode extends FixedWithNextNode implements Lowerable, Canonicalizable {
 
     @Input private ValueNode hub;
     private final ResolvedJavaMethod method;
@@ -55,6 +58,50 @@
         tool.getLowerer().lower(this, tool);
     }
 
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (hub instanceof LoadHubNode) {
+            ValueNode object = ((LoadHubNode) hub).object();
+            ResolvedJavaType type = StampTool.typeOrNull(object);
+            if (StampTool.isExactType(object)) {
+                return resolveExactMethod(tool, type);
+            }
+            if (type != null && tool.assumptions().useOptimisticAssumptions()) {
+                ResolvedJavaMethod resolvedMethod = type.findUniqueConcreteMethod(method);
+                if (resolvedMethod != null && !type.isInterface() && method.getDeclaringClass().isAssignableFrom(type)) {
+                    tool.assumptions().recordConcreteMethod(method, type, resolvedMethod);
+                    return ConstantNode.forConstant(resolvedMethod.getEncoding(), tool.getMetaAccess(), graph());
+                }
+            }
+        }
+        if (hub.isConstant()) {
+            return resolveExactMethod(tool, tool.getConstantReflection().asJavaType(hub.asConstant()));
+        }
+
+        return this;
+    }
+
+    /**
+     * Find the method which would be loaded.
+     *
+     * @param tool
+     * @param type the exact type of object being loaded from
+     * @return the method which would be invoked for {@code type} or null if it doesn't implement
+     *         the method
+     */
+    private Node resolveExactMethod(CanonicalizerTool tool, ResolvedJavaType type) {
+        ResolvedJavaMethod newMethod = type.resolveMethod(method, type);
+        if (newMethod == null) {
+            /*
+             * This really represent a misuse of LoadMethod since we're loading from a class which
+             * isn't known to implement the original method but for now at least fold it away.
+             */
+            return ConstantNode.forConstant(Constant.NULL_OBJECT, null, graph());
+        } else {
+            return ConstantNode.forConstant(newMethod.getEncoding(), tool.getMetaAccess(), graph());
+        }
+    }
+
     public ResolvedJavaMethod getMethod() {
         return method;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java	Tue Jun 24 23:29:13 2014 +0200
@@ -30,14 +30,12 @@
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
 
-public class UnboxNode extends FloatingNode implements Virtualizable, Lowerable, Canonicalizable {
+public class UnboxNode extends UnaryNode implements Virtualizable, Lowerable, Canonicalizable {
 
-    @Input private ValueNode value;
     private final Kind boxingKind;
 
     public UnboxNode(ValueNode value, Kind boxingKind) {
-        super(StampFactory.forKind(boxingKind.getStackKind()));
-        this.value = value;
+        super(StampFactory.forKind(boxingKind.getStackKind()), value);
         this.boxingKind = boxingKind;
     }
 
@@ -45,10 +43,6 @@
         return boxingKind;
     }
 
-    public ValueNode getValue() {
-        return value;
-    }
-
     @Override
     public void lower(LoweringTool tool) {
         tool.getLowerer().lower(this, tool);
@@ -56,7 +50,7 @@
 
     @Override
     public void virtualize(VirtualizerTool tool) {
-        State state = tool.getObjectState(value);
+        State state = tool.getObjectState(getValue());
         if (state != null && state.getState() == EscapeState.Virtual) {
             ResolvedJavaType objectType = state.getVirtualObject().type();
             ResolvedJavaType expectedType = tool.getMetaAccessProvider().lookupJavaType(boxingKind.toBoxedJavaClass());
@@ -68,14 +62,14 @@
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
-        if (value.isConstant()) {
-            Constant constant = value.asConstant();
+        if (getValue().isConstant()) {
+            Constant constant = getValue().asConstant();
             Constant unboxed = tool.getConstantReflection().unboxPrimitive(constant);
             if (unboxed != null && unboxed.getKind() == boxingKind) {
                 return ConstantNode.forConstant(unboxed, tool.getMetaAccess(), graph());
             }
-        } else if (value instanceof BoxNode) {
-            BoxNode box = (BoxNode) value;
+        } else if (getValue() instanceof BoxNode) {
+            BoxNode box = (BoxNode) getValue();
             if (boxingKind == box.getBoxingKind()) {
                 return box.getValue();
             }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java	Tue Jun 24 23:29:13 2014 +0200
@@ -141,9 +141,12 @@
             ValueNode receiver = receiver();
             ResolvedJavaType type = StampTool.typeOrNull(receiver);
             if (type != null && (invoke().stateAfter() != null || invoke().stateDuring() != null)) {
-                // either the holder class is exact, or the receiver object has an exact type
+                /*
+                 * either the holder class is exact, or the receiver object has an exact type, or
+                 * it's an array type
+                 */
                 ResolvedJavaMethod resolvedMethod = type.resolveMethod(targetMethod, invoke().getContextType());
-                if (resolvedMethod != null && (resolvedMethod.canBeStaticallyBound() || StampTool.isExactType(receiver))) {
+                if (resolvedMethod != null && (resolvedMethod.canBeStaticallyBound() || StampTool.isExactType(receiver) || type.isArray())) {
                     invokeKind = InvokeKind.Special;
                     targetMethod = resolvedMethod;
                     return this;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampTool.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampTool.java	Tue Jun 24 23:29:13 2014 +0200
@@ -195,7 +195,7 @@
         return add(stamp1, (IntegerStamp) StampTool.negate(stamp2));
     }
 
-    private static Stamp stampForMask(int bits, long downMask, long upMask) {
+    public static Stamp stampForMask(int bits, long downMask, long upMask) {
         long lowerBound;
         long upperBound;
         if (((upMask >>> (bits - 1)) & 1) == 0) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Tue Jun 24 23:29:13 2014 +0200
@@ -94,13 +94,13 @@
             } else if (merge instanceof LoopBeginNode && ((LoopBeginNode) merge).loopEnds().isEmpty()) {
                 // not a loop anymore
                 if (tool != null) {
-                    merge.phis().forEach(phi -> phi.usages().forEach(tool::addToWorkList));
+                    merge.phis().forEach(phi -> tool.addToWorkList(phi.usages()));
                 }
                 graph.reduceDegenerateLoopBegin((LoopBeginNode) merge);
             } else if (merge.phiPredecessorCount() == 1) {
                 // not a merge anymore
                 if (tool != null) {
-                    merge.phis().forEach(phi -> phi.usages().forEach(tool::addToWorkList));
+                    merge.phis().forEach(phi -> tool.addToWorkList(phi.usages()));
                 }
                 graph.reduceTrivialMerge(merge);
             }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Tue Jun 24 23:29:13 2014 +0200
@@ -234,7 +234,9 @@
                 METRIC_CANONICALIZATION_CONSIDERED_NODES.increment();
                 try (Scope s = Debug.scope("CanonicalizeNode", node)) {
                     Node canonical = node.canonical(tool);
-                    return performReplacement(node, canonical);
+                    if (performReplacement(node, canonical)) {
+                        return true;
+                    }
                 } catch (Throwable e) {
                     throw Debug.handle(e);
                 }
@@ -248,8 +250,9 @@
                 } catch (Throwable e) {
                     throw Debug.handle(e);
                 }
+                return node.isDeleted();
             }
-            return node.isDeleted();
+            return false;
         }
 
 // @formatter:off
@@ -378,6 +381,10 @@
                 workList.add(node);
             }
 
+            public void addToWorkList(Iterable<? extends Node> nodes) {
+                workList.addAll(nodes);
+            }
+
             @Override
             public void removeIfUnused(Node node) {
                 GraphUtil.tryKillUnused(node);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CleanTypeProfileProxyPhase.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CleanTypeProfileProxyPhase.java	Tue Jun 24 23:29:13 2014 +0200
@@ -30,7 +30,7 @@
     @Override
     protected void run(StructuredGraph graph) {
         for (TypeProfileProxyNode proxy : graph.getNodes(TypeProfileProxyNode.class)) {
-            graph.replaceFloating(proxy, proxy.getObject());
+            graph.replaceFloating(proxy, proxy.getValue());
         }
         assert graph.getNodes(TypeProfileProxyNode.class).count() == 0;
     }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/EquationalReasoner.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/EquationalReasoner.java	Tue Jun 24 23:29:13 2014 +0200
@@ -629,7 +629,7 @@
         }
         TypeProfileProxyNode profile = (TypeProfileProxyNode) object;
         ObjectStamp outgoinStamp = (ObjectStamp) profile.stamp();
-        ObjectStamp payloadStamp = (ObjectStamp) profile.getObject().stamp();
+        ObjectStamp payloadStamp = (ObjectStamp) profile.getValue().stamp();
         if (payloadStamp.nonNull() && !outgoinStamp.nonNull()) {
             profile.setStamp(FlowUtil.asNonNullStamp(outgoinStamp));
         }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Tue Jun 24 23:29:13 2014 +0200
@@ -223,8 +223,10 @@
      * @param inlineGraph the graph that the invoke will be replaced with
      * @param receiverNullCheck true if a null check needs to be generated for non-static inlinings,
      *            false if no such check is required
+     * @param canonicalizedNodes if non-null then append to this list any nodes which should be
+     *            canonicalized after inlining
      */
-    public static Map<Node, Node> inline(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck) {
+    public static Map<Node, Node> inline(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck, List<Node> canonicalizedNodes) {
         final NodeInputList<ValueNode> parameters = invoke.callTarget().arguments();
         FixedNode invokeNode = invoke.asNode();
         StructuredGraph graph = invokeNode.graph();
@@ -339,7 +341,7 @@
                 }
                 MergeNode merge = graph.add(new MergeNode());
                 merge.setStateAfter(stateAfter);
-                ValueNode returnValue = mergeReturns(merge, returnDuplicates);
+                ValueNode returnValue = mergeReturns(merge, returnDuplicates, canonicalizedNodes);
                 invokeNode.replaceAtUsages(returnValue);
                 merge.setNext(n);
             }
@@ -438,7 +440,7 @@
         }
     }
 
-    public static ValueNode mergeReturns(MergeNode merge, List<? extends ReturnNode> returnNodes) {
+    public static ValueNode mergeReturns(MergeNode merge, List<? extends ReturnNode> returnNodes, List<Node> canonicalizedNodes) {
         PhiNode returnValuePhi = null;
 
         for (ReturnNode returnNode : returnNodes) {
@@ -449,6 +451,9 @@
             if (returnNode.result() != null) {
                 if (returnValuePhi == null) {
                     returnValuePhi = merge.graph().addWithoutUnique(new ValuePhiNode(returnNode.result().stamp().unrestricted(), merge));
+                    if (canonicalizedNodes != null) {
+                        canonicalizedNodes.add(returnValuePhi);
+                    }
                 }
                 returnValuePhi.addInput(returnNode.result());
             }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/AbstractInlineInfo.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/AbstractInlineInfo.java	Tue Jun 24 23:29:13 2014 +0200
@@ -33,9 +33,6 @@
 import com.oracle.graal.phases.common.inlining.info.elem.Inlineable;
 import com.oracle.graal.phases.common.inlining.info.elem.InlineableMacroNode;
 import com.oracle.graal.phases.common.inlining.info.elem.InlineableGraph;
-import com.oracle.graal.phases.common.inlining.walker.CallsiteHolder;
-import com.oracle.graal.phases.common.inlining.walker.CallsiteHolderDummy;
-import com.oracle.graal.phases.common.inlining.walker.CallsiteHolderExplorable;
 import com.oracle.graal.phases.tiers.HighTierContext;
 
 public abstract class AbstractInlineInfo implements InlineInfo {
@@ -57,22 +54,22 @@
     }
 
     protected static Collection<Node> inline(Invoke invoke, ResolvedJavaMethod concrete, Inlineable inlineable, Assumptions assumptions, boolean receiverNullCheck) {
-        Collection<Node> parameterUsages = new ArrayList<>();
+        List<Node> canonicalizeNodes = new ArrayList<>();
         if (inlineable instanceof InlineableGraph) {
             StructuredGraph calleeGraph = ((InlineableGraph) inlineable).getGraph();
-            Map<Node, Node> duplicateMap = InliningUtil.inline(invoke, calleeGraph, receiverNullCheck);
-            getInlinedParameterUsages(parameterUsages, calleeGraph, duplicateMap);
+            Map<Node, Node> duplicateMap = InliningUtil.inline(invoke, calleeGraph, receiverNullCheck, canonicalizeNodes);
+            getInlinedParameterUsages(canonicalizeNodes, calleeGraph, duplicateMap);
         } else {
             assert inlineable instanceof InlineableMacroNode;
 
             Class<? extends FixedWithNextNode> macroNodeClass = ((InlineableMacroNode) inlineable).getMacroNodeClass();
             FixedWithNextNode macroNode = InliningUtil.inlineMacroNode(invoke, concrete, macroNodeClass);
-            parameterUsages.add(macroNode);
+            canonicalizeNodes.add(macroNode);
         }
 
         InliningUtil.InlinedBytecodes.add(concrete.getCodeSize());
         assumptions.recordMethodContents(concrete);
-        return parameterUsages;
+        return canonicalizeNodes;
     }
 
     public static void getInlinedParameterUsages(Collection<Node> parameterUsages, StructuredGraph calleeGraph, Map<Node, Node> duplicateMap) {
@@ -93,14 +90,14 @@
         }
     }
 
-    public final CallsiteHolder buildCallsiteHolderForElement(int index, double invokeProbability, double invokeRelevance) {
-        Inlineable elem = inlineableElementAt(index);
-        if (elem instanceof InlineableGraph) {
-            InlineableGraph ig = (InlineableGraph) elem;
-            return new CallsiteHolderExplorable(ig.getGraph(), invokeProbability * probabilityAt(index), invokeRelevance * relevanceAt(index));
-        } else {
-            assert elem instanceof InlineableMacroNode;
-            return CallsiteHolderDummy.DUMMY_CALLSITE_HOLDER;
+    public final int determineNodeCount() {
+        int nodes = 0;
+        for (int i = 0; i < numberOfMethods(); i++) {
+            Inlineable elem = inlineableElementAt(i);
+            if (elem != null) {
+                nodes += elem.getNodeCount();
+            }
         }
+        return nodes;
     }
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/InlineInfo.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/InlineInfo.java	Tue Jun 24 23:29:13 2014 +0200
@@ -32,7 +32,6 @@
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.phases.common.CanonicalizerPhase;
 import com.oracle.graal.phases.common.inlining.info.elem.Inlineable;
-import com.oracle.graal.phases.common.inlining.walker.CallsiteHolder;
 import com.oracle.graal.phases.tiers.HighTierContext;
 import com.oracle.graal.phases.util.Providers;
 
@@ -88,5 +87,5 @@
 
     void populateInlinableElements(HighTierContext context, Assumptions calleeAssumptions, CanonicalizerPhase canonicalizer);
 
-    CallsiteHolder buildCallsiteHolderForElement(int index, double invokeProbability, double invokeRelevance);
+    int determineNodeCount();
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/MultiTypeGuardInlineInfo.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/MultiTypeGuardInlineInfo.java	Tue Jun 24 23:29:13 2014 +0200
@@ -272,13 +272,16 @@
             }
         }
 
-        Collection<Node> parameterUsages = new ArrayList<>();
+        Collection<Node> canonicalizeNodes = new ArrayList<>();
         // do the actual inlining for every invoke
         for (int i = 0; i < numberOfMethods; i++) {
             Invoke invokeForInlining = (Invoke) successors[i].next();
-            parameterUsages.addAll(inline(invokeForInlining, methodAt(i), inlineableElementAt(i), assumptions, false));
+            canonicalizeNodes.addAll(inline(invokeForInlining, methodAt(i), inlineableElementAt(i), assumptions, false));
         }
-        return parameterUsages;
+        if (returnValuePhi != null) {
+            canonicalizeNodes.add(returnValuePhi);
+        }
+        return canonicalizeNodes;
     }
 
     private int getTypeCount(int concreteMethodIndex) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/Inlineable.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/Inlineable.java	Tue Jun 24 23:29:13 2014 +0200
@@ -32,6 +32,8 @@
 public interface Inlineable {
 
     static Inlineable getInlineableElement(final ResolvedJavaMethod method, Invoke invoke, HighTierContext context, CanonicalizerPhase canonicalizer) {
+        assert method != null;
+        assert invoke != null;
         Class<? extends FixedWithNextNode> macroNodeClass = InliningUtil.getMacroNodeClass(context.getReplacements(), method);
         if (macroNodeClass != null) {
             return new InlineableMacroNode(macroNodeClass);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/AbstractInliningPolicy.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/AbstractInliningPolicy.java	Tue Jun 24 23:29:13 2014 +0200
@@ -100,17 +100,6 @@
         return size;
     }
 
-    protected static int determineNodeCount(InlineInfo info) {
-        int nodes = 0;
-        for (int i = 0; i < info.numberOfMethods(); i++) {
-            Inlineable elem = info.inlineableElementAt(i);
-            if (elem != null) {
-                nodes += elem.getNodeCount();
-            }
-        }
-        return nodes;
-    }
-
     protected static double determineInvokeProbability(ToDoubleFunction<FixedNode> probabilities, InlineInfo info) {
         double invokeProbability = 0;
         for (int i = 0; i < info.numberOfMethods(); i++) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/GreedyInliningPolicy.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/GreedyInliningPolicy.java	Tue Jun 24 23:29:13 2014 +0200
@@ -30,6 +30,7 @@
 import com.oracle.graal.nodes.spi.Replacements;
 import com.oracle.graal.phases.common.inlining.InliningUtil;
 import com.oracle.graal.phases.common.inlining.info.InlineInfo;
+import com.oracle.graal.phases.common.inlining.walker.MethodInvocation;
 
 import java.util.Map;
 import java.util.function.ToDoubleFunction;
@@ -54,8 +55,12 @@
     }
 
     @Override
-    public boolean isWorthInlining(ToDoubleFunction<FixedNode> probabilities, Replacements replacements, InlineInfo info, int inliningDepth, double probability, double relevance,
-                    boolean fullyProcessed) {
+    public boolean isWorthInlining(ToDoubleFunction<FixedNode> probabilities, Replacements replacements, MethodInvocation invocation, int inliningDepth, boolean fullyProcessed) {
+
+        final InlineInfo info = invocation.callee();
+        final double probability = invocation.probability();
+        final double relevance = invocation.relevance();
+
         if (InlineEverything.getValue()) {
             InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "inline everything");
             return true;
@@ -72,7 +77,7 @@
         }
 
         double inliningBonus = getInliningBonus(info);
-        int nodes = determineNodeCount(info);
+        int nodes = info.determineNodeCount();
         int lowLevelGraphSize = previousLowLevelGraphSize(info);
 
         if (SmallCompiledLowLevelGraphSize.getValue() > 0 && lowLevelGraphSize > SmallCompiledLowLevelGraphSize.getValue() * inliningBonus) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/InlineEverythingPolicy.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/InlineEverythingPolicy.java	Tue Jun 24 23:29:13 2014 +0200
@@ -26,7 +26,7 @@
 import com.oracle.graal.nodes.FixedNode;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.spi.Replacements;
-import com.oracle.graal.phases.common.inlining.info.InlineInfo;
+import com.oracle.graal.phases.common.inlining.walker.MethodInvocation;
 
 import java.util.function.ToDoubleFunction;
 
@@ -41,8 +41,7 @@
         return true;
     }
 
-    public boolean isWorthInlining(ToDoubleFunction<FixedNode> probabilities, Replacements replacements, InlineInfo info, int inliningDepth, double probability, double relevance,
-                    boolean fullyProcessed) {
+    public boolean isWorthInlining(ToDoubleFunction<FixedNode> probabilities, Replacements replacements, MethodInvocation invocation, int inliningDepth, boolean fullyProcessed) {
         return true;
     }
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/InliningPolicy.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/InliningPolicy.java	Tue Jun 24 23:29:13 2014 +0200
@@ -25,7 +25,7 @@
 import com.oracle.graal.nodes.FixedNode;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.spi.Replacements;
-import com.oracle.graal.phases.common.inlining.info.InlineInfo;
+import com.oracle.graal.phases.common.inlining.walker.MethodInvocation;
 
 import java.util.function.ToDoubleFunction;
 
@@ -33,5 +33,5 @@
 
     boolean continueInlining(StructuredGraph graph);
 
-    boolean isWorthInlining(ToDoubleFunction<FixedNode> probabilities, Replacements replacements, InlineInfo info, int inliningDepth, double probability, double relevance, boolean fullyProcessed);
+    boolean isWorthInlining(ToDoubleFunction<FixedNode> probabilities, Replacements replacements, MethodInvocation invocation, int inliningDepth, boolean fullyProcessed);
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/CallsiteHolderExplorable.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/CallsiteHolderExplorable.java	Tue Jun 24 23:29:13 2014 +0200
@@ -24,12 +24,10 @@
 
 import com.oracle.graal.api.meta.MetaUtil;
 import com.oracle.graal.api.meta.ResolvedJavaMethod;
-import com.oracle.graal.nodes.FixedNode;
-import com.oracle.graal.nodes.Invoke;
-import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.graph.FixedNodeProbabilityCache;
 
-import java.util.LinkedList;
+import java.util.*;
 import java.util.function.ToDoubleFunction;
 
 import static com.oracle.graal.compiler.common.GraalOptions.CapInheritedRelevance;
@@ -52,19 +50,30 @@
  */
 public final class CallsiteHolderExplorable extends CallsiteHolder {
 
+    /**
+     * Graph in which inlining may be performed at one or more of the callsites containined in
+     * {@link #remainingInvokes}
+     */
     private final StructuredGraph graph;
+
     private final LinkedList<Invoke> remainingInvokes;
     private final double probability;
     private final double relevance;
 
+    /**
+     * @see #getFixedParams()
+     */
+    private final Set<ParameterNode> fixedParams;
+
     private final ToDoubleFunction<FixedNode> probabilities;
     private final ComputeInliningRelevance computeInliningRelevance;
 
-    public CallsiteHolderExplorable(StructuredGraph graph, double probability, double relevance) {
+    public CallsiteHolderExplorable(StructuredGraph graph, double probability, double relevance, BitSet freshlyInstantiatedArguments) {
         assert graph != null;
         this.graph = graph;
         this.probability = probability;
         this.relevance = relevance;
+        this.fixedParams = fixedParamsAt(freshlyInstantiatedArguments);
         remainingInvokes = new InliningIterator(graph).apply();
         if (remainingInvokes.isEmpty()) {
             probabilities = null;
@@ -74,6 +83,65 @@
             computeInliningRelevance = new ComputeInliningRelevance(graph, probabilities);
             computeProbabilities();
         }
+        assert repOK();
+    }
+
+    /**
+     * @see #getFixedParams()
+     */
+    @SuppressWarnings("unchecked")
+    private Set<ParameterNode> fixedParamsAt(BitSet freshlyInstantiatedArguments) {
+        if (freshlyInstantiatedArguments == null || freshlyInstantiatedArguments.isEmpty()) {
+            return Collections.EMPTY_SET;
+        }
+        Set<ParameterNode> result = new HashSet<>();
+        for (ParameterNode p : graph.getNodes(ParameterNode.class)) {
+            if (freshlyInstantiatedArguments.get(p.index())) {
+                result.add(p);
+            }
+        }
+        return result;
+    }
+
+    /**
+     * <p>
+     * Parameters for which the callsite targeting {@link #graph()} provides "fixed" arguments. That
+     * callsite isn't referenced by this instance. Instead, it belongs to the graph of the caller of
+     * this {@link CallsiteHolderExplorable}
+     * </p>
+     *
+     * <p>
+     * Constant arguments don't contribute to fixed-params: those params have been removed already,
+     * see {@link com.oracle.graal.phases.common.inlining.info.elem.InlineableGraph}.
+     * </p>
+     *
+     * <p>
+     * Instead, fixed-params are those receiving freshly instantiated arguments (possibly
+     * instantiated several levels up in the call-hierarchy)
+     * </p>
+     * */
+    public Set<ParameterNode> getFixedParams() {
+        return fixedParams;
+    }
+
+    public boolean repOK() {
+        for (Invoke invoke : remainingInvokes) {
+            if (!invoke.asNode().isAlive() || !containsInvoke(invoke)) {
+                assert false;
+                return false;
+            }
+            if (!allArgsNonNull(invoke)) {
+                assert false;
+                return false;
+            }
+        }
+        for (ParameterNode fixedParam : fixedParams) {
+            if (!containsParam(fixedParam)) {
+                assert false;
+                return false;
+            }
+        }
+        return true;
     }
 
     @Override
@@ -99,6 +167,16 @@
         remainingInvokes.push(invoke);
     }
 
+    public static boolean allArgsNonNull(Invoke invoke) {
+        for (ValueNode arg : invoke.callTarget().arguments()) {
+            if (arg == null) {
+                assert false;
+                return false;
+            }
+        }
+        return true;
+    }
+
     public boolean containsInvoke(Invoke invoke) {
         for (Invoke i : graph().getInvokes()) {
             if (i == invoke) {
@@ -108,6 +186,15 @@
         return false;
     }
 
+    public boolean containsParam(ParameterNode param) {
+        for (ParameterNode p : graph.getNodes(ParameterNode.class)) {
+            if (p == param) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     public void computeProbabilities() {
         computeInliningRelevance.compute();
     }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java	Tue Jun 24 23:29:13 2014 +0200
@@ -34,7 +34,9 @@
 import com.oracle.graal.graph.Graph;
 import com.oracle.graal.graph.Node;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.AbstractNewObjectNode;
 import com.oracle.graal.nodes.java.MethodCallTargetNode;
+import com.oracle.graal.nodes.virtual.VirtualObjectNode;
 import com.oracle.graal.phases.OptimisticOptimizations;
 import com.oracle.graal.phases.common.CanonicalizerPhase;
 import com.oracle.graal.phases.common.inlining.InliningUtil;
@@ -110,8 +112,12 @@
         this.maxGraphs = 1;
 
         Assumptions rootAssumptions = context.getAssumptions();
-        invocationQueue.push(new MethodInvocation(null, rootAssumptions, 1.0, 1.0));
-        graphQueue.push(new CallsiteHolderExplorable(rootGraph, 1.0, 1.0));
+        invocationQueue.push(new MethodInvocation(null, rootAssumptions, 1.0, 1.0, null));
+        graphQueue.push(new CallsiteHolderExplorable(rootGraph, 1.0, 1.0, null));
+    }
+
+    public static boolean isFreshInstantiation(ValueNode arg) {
+        return (arg instanceof AbstractNewObjectNode) || (arg instanceof VirtualObjectNode);
     }
 
     private String checkTargetConditionsHelper(ResolvedJavaMethod method) {
@@ -419,7 +425,7 @@
         Assumptions callerAssumptions = parentInvocation.assumptions();
         metricInliningConsidered.increment();
 
-        if (inliningPolicy.isWorthInlining(probabilities, context.getReplacements(), calleeInfo, inliningDepth, calleeInvocation.probability(), calleeInvocation.relevance(), true)) {
+        if (inliningPolicy.isWorthInlining(probabilities, context.getReplacements(), calleeInvocation, inliningDepth, true)) {
             doInline(callerCallsiteHolder, calleeInvocation, callerAssumptions);
             return true;
         }
@@ -468,11 +474,53 @@
             info.populateInlinableElements(context, calleeAssumptions, canonicalizer);
             double invokeProbability = callsiteHolder.invokeProbability(invoke);
             double invokeRelevance = callsiteHolder.invokeRelevance(invoke);
-            MethodInvocation methodInvocation = new MethodInvocation(info, calleeAssumptions, invokeProbability, invokeRelevance);
+            MethodInvocation methodInvocation = new MethodInvocation(info, calleeAssumptions, invokeProbability, invokeRelevance, freshlyInstantiatedArguments(invoke, callsiteHolder.getFixedParams()));
             pushInvocationAndGraphs(methodInvocation);
         }
     }
 
+    /**
+     * <p>
+     * A freshly instantiated argument is either:
+     * <uL>
+     * <li>an {@link InliningData#isFreshInstantiation(com.oracle.graal.nodes.ValueNode)}</li>
+     * <li>a fixed-param, ie a {@link ParameterNode} receiving a freshly instantiated argument</li>
+     * </uL>
+     * </p>
+     *
+     * @return the positions of freshly instantiated arguments in the argument list of the
+     *         <code>invoke</code>, or null if no such positions exist.
+     */
+    public static BitSet freshlyInstantiatedArguments(Invoke invoke, Set<ParameterNode> fixedParams) {
+        assert fixedParams != null;
+        assert paramsAndInvokeAreInSameGraph(invoke, fixedParams);
+        BitSet result = null;
+        int argIdx = 0;
+        for (ValueNode arg : invoke.callTarget().arguments()) {
+            assert arg != null;
+            if (isFreshInstantiation(arg) || fixedParams.contains(arg)) {
+                if (result == null) {
+                    result = new BitSet();
+                }
+                result.set(argIdx);
+            }
+            argIdx++;
+        }
+        return result;
+    }
+
+    private static boolean paramsAndInvokeAreInSameGraph(Invoke invoke, Set<ParameterNode> fixedParams) {
+        if (fixedParams.isEmpty()) {
+            return true;
+        }
+        for (ParameterNode p : fixedParams) {
+            if (p.graph() != invoke.asNode().graph()) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     public int graphCount() {
         return graphQueue.size();
     }
@@ -523,10 +571,8 @@
         InlineInfo info = methodInvocation.callee();
         maxGraphs += info.numberOfMethods();
         assert graphQueue.size() <= maxGraphs;
-        double invokeProbability = methodInvocation.probability();
-        double invokeRelevance = methodInvocation.relevance();
         for (int i = 0; i < info.numberOfMethods(); i++) {
-            CallsiteHolder ch = info.buildCallsiteHolderForElement(i, invokeProbability, invokeRelevance);
+            CallsiteHolder ch = methodInvocation.buildCallsiteHolderForElement(i);
             assert (ch == DUMMY_CALLSITE_HOLDER) || !contains(ch.graph());
             graphQueue.push(ch);
             assert graphQueue.size() <= maxGraphs;
@@ -636,8 +682,7 @@
 
         final MethodInvocation currentInvocation = currentInvocation();
 
-        final boolean backtrack = (!currentInvocation.isRoot() && !inliningPolicy.isWorthInlining(probabilities, context.getReplacements(), currentInvocation.callee(), inliningDepth(),
-                        currentInvocation.probability(), currentInvocation.relevance(), false));
+        final boolean backtrack = (!currentInvocation.isRoot() && !inliningPolicy.isWorthInlining(probabilities, context.getReplacements(), currentInvocation, inliningDepth(), false));
         if (backtrack) {
             int remainingGraphs = currentInvocation.totalGraphs() - currentInvocation.processedGraphs();
             assert remainingGraphs > 0;
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/MethodInvocation.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/MethodInvocation.java	Tue Jun 24 23:29:13 2014 +0200
@@ -28,6 +28,11 @@
 import com.oracle.graal.nodes.CallTargetNode;
 import com.oracle.graal.nodes.java.MethodCallTargetNode;
 import com.oracle.graal.phases.common.inlining.info.InlineInfo;
+import com.oracle.graal.phases.common.inlining.info.elem.Inlineable;
+import com.oracle.graal.phases.common.inlining.info.elem.InlineableGraph;
+import com.oracle.graal.phases.common.inlining.info.elem.InlineableMacroNode;
+
+import java.util.BitSet;
 
 /**
  * <p>
@@ -49,11 +54,39 @@
 
     private int processedGraphs;
 
-    public MethodInvocation(InlineInfo info, Assumptions assumptions, double probability, double relevance) {
+    /**
+     * <p>
+     * The immutable positions of freshly instantiated arguments (ie, positions in
+     * <code>callee.invoke.callTarget.arguments</code>).
+     * </p>
+     *
+     * <p>
+     * A freshly instantiated argument is either:
+     * <uL>
+     * <li>an {@link InliningData#isFreshInstantiation(com.oracle.graal.nodes.ValueNode)}</li>
+     * <li>a fixed-param of the graph containing the callsite (ie, of <code>callee.graph()</code>
+     * that contains <code>callee.invoke</code>)</li>
+     * </uL>
+     * </p>
+     *
+     * <p>
+     * Given those positions, the
+     * {@link com.oracle.graal.phases.common.inlining.walker.CallsiteHolderExplorable} instantiated
+     * in {@link #buildCallsiteHolderForElement(int)} can determine which of <i>its</i> parameters
+     * are fixed.
+     * </p>
+     */
+    private final BitSet freshlyInstantiatedArguments;
+
+    private final int sizeFreshArgs;
+
+    public MethodInvocation(InlineInfo info, Assumptions assumptions, double probability, double relevance, BitSet freshlyInstantiatedArguments) {
         this.callee = info;
         this.assumptions = assumptions;
         this.probability = probability;
         this.relevance = relevance;
+        this.freshlyInstantiatedArguments = freshlyInstantiatedArguments;
+        this.sizeFreshArgs = freshlyInstantiatedArguments == null ? 0 : freshlyInstantiatedArguments.cardinality();
     }
 
     public void incrementProcessedGraphs() {
@@ -90,6 +123,27 @@
         return callee == null;
     }
 
+    public BitSet getFreshlyInstantiatedArguments() {
+        return freshlyInstantiatedArguments;
+    }
+
+    public int getSizeFreshArgs() {
+        return sizeFreshArgs;
+    }
+
+    public CallsiteHolder buildCallsiteHolderForElement(int index) {
+        Inlineable elem = callee.inlineableElementAt(index);
+        if (elem instanceof InlineableGraph) {
+            InlineableGraph ig = (InlineableGraph) elem;
+            final double invokeProbability = probability * callee.probabilityAt(index);
+            final double invokeRelevance = relevance * callee.relevanceAt(index);
+            return new CallsiteHolderExplorable(ig.getGraph(), invokeProbability, invokeRelevance, freshlyInstantiatedArguments);
+        } else {
+            assert elem instanceof InlineableMacroNode;
+            return CallsiteHolderDummy.DUMMY_CALLSITE_HOLDER;
+        }
+    }
+
     @Override
     public String toString() {
         if (isRoot()) {
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java	Tue Jun 24 23:29:13 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -299,6 +299,7 @@
             for (Position pos : directInputPositions) {
                 writeByte(pos.getSubIndex() == NodeClass.NOT_ITERABLE ? 0 : 1);
                 writePoolObject(nodeClass.getName(pos));
+                writePoolObject(nodeClass.getInputType(pos));
             }
             Collection<Position> directSuccessorPositions = nodeClass.getFirstLevelSuccessorPositions();
             writeShort((char) directSuccessorPositions.size());
--- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertSnippets.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertSnippets.java	Tue Jun 24 23:29:13 2014 +0200
@@ -181,8 +181,8 @@
             StructuredGraph graph = convert.graph();
 
             Arguments args = new Arguments(key, graph.getGuardsStage(), tool.getLoweringStage());
-            args.add("input", convert.getInput());
-            args.add("result", graph.unique(new AMD64FloatConvertNode(convert.stamp(), convert.getOp(), convert.getInput())));
+            args.add("input", convert.getValue());
+            args.add("result", graph.unique(new AMD64FloatConvertNode(convert.stamp(), convert.getOp(), convert.getValue())));
 
             SnippetTemplate template = template(args);
             Debug.log("Lowering %s in %s: node=%s, template=%s, arguments=%s", convert.getOp(), graph, convert, template, args);
--- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64FloatConvertNode.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64FloatConvertNode.java	Tue Jun 24 23:29:13 2014 +0200
@@ -36,15 +36,13 @@
  * 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.
  */
-public class AMD64FloatConvertNode extends FloatingNode implements ArithmeticLIRLowerable {
+public class AMD64FloatConvertNode extends UnaryNode implements ArithmeticLIRLowerable {
 
     private final FloatConvert op;
-    @Input private ValueNode value;
 
     public AMD64FloatConvertNode(Stamp stamp, FloatConvert op, ValueNode value) {
-        super(stamp);
+        super(stamp, value);
         this.op = op;
-        this.value = value;
     }
 
     public Constant evalConst(Constant... inputs) {
@@ -53,6 +51,6 @@
     }
 
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        builder.setResult(this, gen.emitFloatConvert(op, builder.operand(value)));
+        builder.setResult(this, gen.emitFloatConvert(op, builder.operand(getValue())));
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/BitOpNodesTest.java	Tue Jun 24 23:29:13 2014 +0200
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.replacements.test;
+
+import org.junit.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.compiler.test.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
+import com.oracle.graal.phases.tiers.*;
+
+public class BitOpNodesTest extends GraalCompilerTest {
+
+    private static final int INT_CONSTANT_1 = 0x80100010;
+    private static final int INT_CONSTANT_2 = 0x00011110;
+    private static final int INT_CONSTANT_3 = 0x00000000;
+
+    private static final long LONG_CONSTANT_1 = 0x8000000000100010L;
+    private static final long LONG_CONSTANT_2 = 0x0000000000011110L;
+    private static final long LONG_CONSTANT_3 = 0x0000000000000000L;
+
+    public static long dummyField;
+
+    /*
+     * Tests for BitCountNode canonicalizations.
+     */
+
+    public static int bitCountIntConstantSnippet() {
+        return Integer.bitCount(INT_CONSTANT_1) + Integer.bitCount(INT_CONSTANT_2) + Integer.bitCount(INT_CONSTANT_3);
+    }
+
+    @Test
+    public void testBitCountIntConstant() {
+        ValueNode result = parseAndInline("bitCountIntConstantSnippet");
+        Assert.assertEquals(7, result.asConstant().asInt());
+    }
+
+    public static int bitCountLongConstantSnippet() {
+        return Long.bitCount(LONG_CONSTANT_1) + Long.bitCount(LONG_CONSTANT_2) + Long.bitCount(LONG_CONSTANT_3);
+    }
+
+    public static int bitCountIntSnippet(int v) {
+        return Integer.bitCount(v & 0xFFFFFF | 0xFF);
+    }
+
+    @Test
+    public void testBitCountInt() {
+        ValueNode result = parseAndInline("bitCountIntSnippet");
+        Assert.assertEquals(StampFactory.forInteger(Kind.Int, 8, 24), result.stamp());
+    }
+
+    public static int bitCountIntEmptySnippet(int v) {
+        return Integer.bitCount(v & 0xFFFFFF);
+    }
+
+    @Test
+    public void testBitCountIntEmpty() {
+        ValueNode result = parseAndInline("bitCountIntEmptySnippet");
+        Assert.assertEquals(StampFactory.forInteger(Kind.Int, 0, 24), result.stamp());
+    }
+
+    @Test
+    public void testBitCountLongConstant() {
+        ValueNode result = parseAndInline("bitCountLongConstantSnippet");
+        Assert.assertEquals(7, result.asConstant().asInt());
+    }
+
+    public static int bitCountLongSnippet(long v) {
+        return Long.bitCount(v & 0xFFFFFFFFFFL | 0xFFL);
+    }
+
+    @Test
+    public void testBitCountLong() {
+        ValueNode result = parseAndInline("bitCountLongSnippet");
+        Assert.assertEquals(StampFactory.forInteger(Kind.Int, 8, 40), result.stamp());
+    }
+
+    public static int bitCountLongEmptySnippet(long v) {
+        return Long.bitCount(v & 0xFFFFFFFFFFL);
+    }
+
+    @Test
+    public void testBitCountLongEmpty() {
+        ValueNode result = parseAndInline("bitCountLongEmptySnippet");
+        Assert.assertEquals(StampFactory.forInteger(Kind.Int, 0, 40), result.stamp());
+    }
+
+    /*
+     * Tests for BitScanForwardNode
+     */
+
+    public static int scanForwardIntConstantSnippet() {
+        return Integer.numberOfTrailingZeros(INT_CONSTANT_1) + Integer.numberOfTrailingZeros(INT_CONSTANT_2) + Integer.numberOfTrailingZeros(INT_CONSTANT_3);
+    }
+
+    @Test
+    public void testScanForwardIntConstant() {
+        ValueNode result = parseAndInline("scanForwardIntConstantSnippet");
+        Assert.assertEquals(40, result.asConstant().asInt());
+    }
+
+    public static int scanForwardIntSnippet(int v) {
+        return Integer.numberOfTrailingZeros(v & 0xFFF0 | 0xFF00);
+    }
+
+    @Test
+    public void testScanForwardInt() {
+        ValueNode result = parseAndInline("scanForwardIntSnippet");
+        Assert.assertEquals(StampFactory.forInteger(Kind.Int, 4, 8), result.stamp());
+    }
+
+    public static int scanForwardLongConstantSnippet() {
+        return Long.numberOfTrailingZeros(LONG_CONSTANT_1) + Long.numberOfTrailingZeros(LONG_CONSTANT_2) + Long.numberOfTrailingZeros(LONG_CONSTANT_3);
+    }
+
+    @Test
+    public void testScanForwardLongConstant() {
+        ValueNode result = parseAndInline("scanForwardLongConstantSnippet");
+        Assert.assertEquals(72, result.asConstant().asInt());
+    }
+
+    public static int scanForwardLongSnippet(long v) {
+        return Long.numberOfTrailingZeros(v & 0xFFFF000000L | 0xFF00000000L);
+    }
+
+    @Test
+    public void testScanForwardLong() {
+        ValueNode result = parseAndInline("scanForwardLongSnippet");
+        Assert.assertEquals(StampFactory.forInteger(Kind.Int, 24, 32), result.stamp());
+    }
+
+    public static int scanForwardLongEmptySnippet(long v) {
+        int result = Long.numberOfTrailingZeros(v & 0xFFFF000000L);
+        dummyField = result;
+        return result;
+    }
+
+    @Test
+    public void testScanForwardLongEmpty() {
+        ValueNode result = parseAndInline("scanForwardLongEmptySnippet");
+        Assert.assertEquals(StampFactory.forInteger(Kind.Int, -1, 64), result.stamp());
+    }
+
+    /*
+     * Tests for BitScanReverseNode
+     */
+
+    public static int scanReverseIntConstantSnippet() {
+        return Integer.numberOfLeadingZeros(INT_CONSTANT_1) + Integer.numberOfLeadingZeros(INT_CONSTANT_2) + Integer.numberOfLeadingZeros(INT_CONSTANT_3);
+    }
+
+    @Test
+    public void testScanReverseIntConstant() {
+        ValueNode result = parseAndInline("scanReverseIntConstantSnippet");
+        Assert.assertEquals(47, result.asConstant().asInt());
+    }
+
+    public static int scanReverseIntSnippet(int v) {
+        return Integer.numberOfLeadingZeros(v & 0xFFF0 | 0xFF0);
+    }
+
+    @Test
+    public void testScanReverseInt() {
+        ValueNode result = parseAndInline("scanReverseIntSnippet");
+        Assert.assertEquals(StampFactory.forInteger(Kind.Int, 16, 20), result.stamp());
+    }
+
+    public static int scanReverseLongConstantSnippet() {
+        return Long.numberOfLeadingZeros(LONG_CONSTANT_1) + Long.numberOfLeadingZeros(LONG_CONSTANT_2) + Long.numberOfLeadingZeros(LONG_CONSTANT_3);
+    }
+
+    @Test
+    public void testScanReverseLongConstant() {
+        ValueNode result = parseAndInline("scanReverseLongConstantSnippet");
+        Assert.assertEquals(111, result.asConstant().asInt());
+    }
+
+    public static int scanReverseLongSnippet(long v) {
+        int result = Long.numberOfLeadingZeros(v & 0xFFF0);
+        dummyField = result;
+        return result;
+    }
+
+    @Test
+    public void testScanReverseLong() {
+        ValueNode result = parseAndInline("scanReverseLongSnippet");
+        Assert.assertEquals(StampFactory.forInteger(Kind.Int, 48, 64), result.stamp());
+    }
+
+    public static int scanReverseLongEmptySnippet(long v) {
+        int result = Long.numberOfLeadingZeros(v & 0xFFFF000000L);
+        dummyField = result;
+        return result;
+    }
+
+    @Test
+    public void testScanReverseLongEmpty() {
+        ValueNode result = parseAndInline("scanReverseLongEmptySnippet");
+        Assert.assertEquals(StampFactory.forInteger(Kind.Int, 24, 64), result.stamp());
+    }
+
+    private ValueNode parseAndInline(String name) {
+        StructuredGraph graph = parse(name);
+        HighTierContext context = new HighTierContext(getProviders(), new Assumptions(false), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.NONE);
+        CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true);
+        canonicalizer.apply(graph, context);
+        new InliningPhase(canonicalizer).apply(graph, context);
+        canonicalizer.apply(graph, context);
+        Assert.assertEquals(1, graph.getNodes(ReturnNode.class).count());
+        return graph.getNodes(ReturnNode.class).first().result();
+    }
+}
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java	Tue Jun 24 23:29:13 2014 +0200
@@ -114,7 +114,7 @@
             SignExtendNode convert = (SignExtendNode) location.getIndex();
             Assert.assertEquals(convert.getInputBits(), 32);
             Assert.assertEquals(convert.getResultBits(), 64);
-            Assert.assertEquals(graph.getParameter(1), convert.getInput());
+            Assert.assertEquals(graph.getParameter(1), convert.getValue());
         } else {
             Assert.assertEquals(graph.getParameter(1), location.getIndex());
         }
@@ -138,7 +138,7 @@
             SignExtendNode convert = (SignExtendNode) location.getIndex();
             Assert.assertEquals(convert.getInputBits(), 32);
             Assert.assertEquals(convert.getResultBits(), 64);
-            Assert.assertEquals(graph.getParameter(1), convert.getInput());
+            Assert.assertEquals(graph.getParameter(1), convert.getValue());
         } else {
             Assert.assertEquals(graph.getParameter(1), location.getIndex());
         }
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java	Tue Jun 24 23:29:13 2014 +0200
@@ -125,7 +125,7 @@
             SignExtendNode convert = (SignExtendNode) location.getIndex();
             Assert.assertEquals(convert.getInputBits(), 32);
             Assert.assertEquals(convert.getResultBits(), 64);
-            Assert.assertEquals(graph.getParameter(1), convert.getInput());
+            Assert.assertEquals(graph.getParameter(1), convert.getValue());
         } else {
             Assert.assertEquals(graph.getParameter(1), location.getIndex());
         }
@@ -154,7 +154,7 @@
             SignExtendNode convert = (SignExtendNode) location.getIndex();
             Assert.assertEquals(convert.getInputBits(), 32);
             Assert.assertEquals(convert.getResultBits(), 64);
-            Assert.assertEquals(graph.getParameter(1), convert.getInput());
+            Assert.assertEquals(graph.getParameter(1), convert.getValue());
         } else {
             Assert.assertEquals(graph.getParameter(1), location.getIndex());
         }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultJavaLoweringProvider.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultJavaLoweringProvider.java	Tue Jun 24 23:29:13 2014 +0200
@@ -109,7 +109,7 @@
         StructuredGraph graph = loadField.graph();
         ResolvedJavaField field = loadField.field();
         ValueNode object = loadField.isStatic() ? staticFieldBase(graph, field) : loadField.object();
-        Stamp loadStamp = loadStamp(loadField.stamp(), field.getKind(), true);
+        Stamp loadStamp = loadStamp(loadField.stamp(), field.getKind());
         ConstantLocationNode location = createFieldLocation(graph, field, false);
         assert location != null : "Field that is loaded must not be eliminated";
 
@@ -158,7 +158,7 @@
         StructuredGraph graph = loadIndexed.graph();
         Kind elementKind = loadIndexed.elementKind();
         LocationNode location = createArrayLocation(graph, elementKind, loadIndexed.index(), false);
-        Stamp loadStamp = loadStamp(loadIndexed.stamp(), elementKind, true);
+        Stamp loadStamp = loadStamp(loadIndexed.stamp(), elementKind);
 
         ReadNode memoryRead = graph.add(new ReadNode(loadIndexed.array(), location, loadStamp, BarrierType.NONE));
         ValueNode readValue = implicitLoadConvert(graph, elementKind, memoryRead);
@@ -503,6 +503,10 @@
 
     protected abstract LocationIdentity initLocationIdentity();
 
+    public Stamp loadStamp(Stamp stamp, Kind kind) {
+        return loadStamp(stamp, kind, true);
+    }
+
     protected Stamp loadStamp(Stamp stamp, Kind kind, @SuppressWarnings("unused") boolean compressible) {
         switch (kind) {
             case Boolean:
@@ -580,7 +584,7 @@
             SignExtendNode extend = (SignExtendNode) offset;
             if (extend.getResultBits() == 64) {
                 signExtend = true;
-                offset = extend.getInput();
+                offset = extend.getValue();
             }
         }
         if (offset instanceof IntegerAddNode) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java	Tue Jun 24 23:29:13 2014 +0200
@@ -208,7 +208,7 @@
         ResolvedJavaMethod method = ((MethodCallTargetNode) invoke.callTarget()).targetMethod();
         ReplacementsImpl repl = new ReplacementsImpl(providers, snippetReflection, new Assumptions(false), providers.getCodeCache().getTarget());
         StructuredGraph calleeGraph = repl.makeGraph(method, null, method, null, FrameStateProcessing.CollapseFrameForSingleSideEffect);
-        InliningUtil.inline(invoke, calleeGraph, false);
+        InliningUtil.inline(invoke, calleeGraph, false, null);
     }
 
     protected void pushStructure(Structure structure) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/IntegerSubstitutions.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/IntegerSubstitutions.java	Tue Jun 24 23:29:13 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,7 +22,9 @@
  */
 package com.oracle.graal.replacements;
 
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.replacements.nodes.*;
 
 @ClassSubstitution(Integer.class)
@@ -53,4 +55,14 @@
     public static int bitCount(int i) {
         return BitCountNode.bitCount(i);
     }
+
+    @MethodSubstitution
+    public static int divideUnsigned(int dividend, int divisor) {
+        return UnsignedDivNode.unsignedDivide(Kind.Int, dividend, divisor);
+    }
+
+    @MethodSubstitution
+    public static int remainderUnsigned(int dividend, int divisor) {
+        return UnsignedRemNode.unsignedRemainder(Kind.Int, dividend, divisor);
+    }
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/LongSubstitutions.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/LongSubstitutions.java	Tue Jun 24 23:29:13 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,7 +22,9 @@
  */
 package com.oracle.graal.replacements;
 
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.replacements.nodes.*;
 
 @ClassSubstitution(Long.class)
@@ -53,4 +55,14 @@
     public static int bitCount(long i) {
         return BitCountNode.bitCount(i);
     }
+
+    @MethodSubstitution
+    public static long divideUnsigned(long dividend, long divisor) {
+        return UnsignedDivNode.unsignedDivide(Kind.Long, dividend, divisor);
+    }
+
+    @MethodSubstitution
+    public static long remainderUnsigned(long dividend, long divisor) {
+        return UnsignedRemNode.unsignedRemainder(Kind.Long, dividend, divisor);
+    }
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Tue Jun 24 23:29:13 2014 +0200
@@ -589,7 +589,7 @@
                         if (isInlinable(substitutedMethod)) {
                             final StructuredGraph originalGraph = buildInitialGraph(substitutedMethod);
                             Mark mark = graph.getMark();
-                            InliningUtil.inline(callTarget.invoke(), originalGraph, true);
+                            InliningUtil.inline(callTarget.invoke(), originalGraph, true, null);
                             for (MethodCallTargetNode inlinedCallTarget : graph.getNewNodes(mark).filter(MethodCallTargetNode.class)) {
                                 if (doNotInline == null) {
                                     doNotInline = new HashSet<>();
@@ -623,7 +623,7 @@
                                     targetGraph = parseGraph(callee, policy, inliningDepth + 1);
                                 }
                                 Object beforeInlineData = beforeInline(callTarget, targetGraph);
-                                InliningUtil.inline(callTarget.invoke(), targetGraph, true);
+                                InliningUtil.inline(callTarget.invoke(), targetGraph, true, null);
                                 Debug.dump(graph, "after inlining %s", callee);
                                 afterInline(graph, targetGraph, beforeInlineData);
                             }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Tue Jun 24 23:29:13 2014 +0200
@@ -705,7 +705,7 @@
             this.memoryMap = memMaps.get(0);
         } else {
             MergeNode merge = snippet.add(new MergeNode());
-            ValueNode returnValue = InliningUtil.mergeReturns(merge, returnNodes);
+            ValueNode returnValue = InliningUtil.mergeReturns(merge, returnNodes, null);
             this.returnNode = snippet.add(new ReturnNode(returnValue));
             this.memoryMap = FloatingReadPhase.mergeMemoryMaps(merge, memMaps);
             merge.setNext(this.returnNode);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitCountNode.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitCountNode.java	Tue Jun 24 23:29:13 2014 +0200
@@ -30,19 +30,25 @@
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
 
-public class BitCountNode extends FloatingNode implements LIRLowerable, Canonicalizable {
-
-    @Input private ValueNode value;
+public class BitCountNode extends UnaryNode implements LIRLowerable, Canonicalizable {
 
     public BitCountNode(ValueNode value) {
-        super(StampFactory.forInteger(Kind.Int, 0, ((PrimitiveStamp) value.stamp()).getBits()));
-        this.value = value;
+        super(StampFactory.forInteger(Kind.Int, 0, ((PrimitiveStamp) value.stamp()).getBits()), value);
+        assert value.getKind() == Kind.Int || value.getKind() == Kind.Long;
+    }
+
+    @Override
+    public boolean inferStamp() {
+        IntegerStamp valueStamp = (IntegerStamp) getValue().stamp();
+        assert (valueStamp.downMask() & IntegerStamp.defaultMask(valueStamp.getBits())) == valueStamp.downMask();
+        assert (valueStamp.upMask() & IntegerStamp.defaultMask(valueStamp.getBits())) == valueStamp.upMask();
+        return updateStamp(StampFactory.forInteger(Kind.Int, bitCount(valueStamp.downMask()), bitCount(valueStamp.upMask())));
     }
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
-        if (value.isConstant()) {
-            Constant c = value.asConstant();
+        if (getValue().isConstant()) {
+            Constant c = getValue().asConstant();
             if (c.getKind() == Kind.Int) {
                 return ConstantNode.forInt(Integer.bitCount(c.asInt()), graph());
             } else if (c.getKind() == Kind.Long) {
@@ -64,7 +70,7 @@
 
     @Override
     public void generate(NodeLIRBuilderTool gen) {
-        Value result = gen.getLIRGeneratorTool().emitBitCount(gen.operand(value));
+        Value result = gen.getLIRGeneratorTool().emitBitCount(gen.operand(getValue()));
         gen.setResult(this, result);
     }
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanForwardNode.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanForwardNode.java	Tue Jun 24 23:29:13 2014 +0200
@@ -24,32 +24,34 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
 
-public class BitScanForwardNode extends FloatingNode implements LIRLowerable, Canonicalizable {
-
-    @Input private ValueNode value;
+public class BitScanForwardNode extends UnaryNode implements LIRLowerable {
 
     public BitScanForwardNode(ValueNode value) {
-        super(StampFactory.forInteger(Kind.Int, 0, ((PrimitiveStamp) value.stamp()).getBits()));
-        this.value = value;
+        super(StampFactory.forInteger(Kind.Int, 0, ((PrimitiveStamp) value.stamp()).getBits()), value);
+        assert value.getKind() == Kind.Int || value.getKind() == Kind.Long;
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (value.isConstant()) {
-            Constant c = value.asConstant();
-            if (c.getKind() == Kind.Int) {
-                return ConstantNode.forInt(Integer.numberOfTrailingZeros(c.asInt()), graph());
-            } else if (c.getKind() == Kind.Long) {
-                return ConstantNode.forInt(Long.numberOfTrailingZeros(c.asLong()), graph());
-            }
+    public boolean inferStamp() {
+        IntegerStamp valueStamp = (IntegerStamp) getValue().stamp();
+        int min;
+        int max;
+        long mask = IntegerStamp.defaultMask(valueStamp.getBits());
+        int firstAlwaysSetBit = scan(valueStamp.downMask() & mask);
+        if (firstAlwaysSetBit == -1) {
+            int lastMaybeSetBit = BitScanReverseNode.scan(valueStamp.upMask() & mask);
+            min = -1;
+            max = lastMaybeSetBit;
+        } else {
+            int firstMaybeSetBit = scan(valueStamp.upMask() & mask);
+            min = firstMaybeSetBit;
+            max = firstAlwaysSetBit;
         }
-        return this;
+        return updateStamp(StampFactory.forInteger(Kind.Int, min, max));
     }
 
     @NodeIntrinsic
@@ -71,7 +73,7 @@
 
     @Override
     public void generate(NodeLIRBuilderTool gen) {
-        Value result = gen.getLIRGeneratorTool().emitBitScanForward(gen.operand(value));
+        Value result = gen.getLIRGeneratorTool().emitBitScanForward(gen.operand(getValue()));
         gen.setResult(this, result);
     }
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanReverseNode.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanReverseNode.java	Tue Jun 24 23:29:13 2014 +0200
@@ -24,32 +24,32 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
 
-public class BitScanReverseNode extends FloatingNode implements LIRLowerable, Canonicalizable {
-
-    @Input private ValueNode value;
+public class BitScanReverseNode extends UnaryNode implements LIRLowerable {
 
     public BitScanReverseNode(ValueNode value) {
-        super(StampFactory.forInteger(Kind.Int, 0, ((PrimitiveStamp) value.stamp()).getBits()));
-        this.value = value;
+        super(StampFactory.forInteger(Kind.Int, 0, ((PrimitiveStamp) value.stamp()).getBits()), value);
+        assert value.getKind() == Kind.Int || value.getKind() == Kind.Long;
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (value.isConstant()) {
-            Constant c = value.asConstant();
-            if (c.getKind() == Kind.Int) {
-                return ConstantNode.forInt(31 - Integer.numberOfLeadingZeros(c.asInt()), graph());
-            } else if (c.getKind() == Kind.Long) {
-                return ConstantNode.forInt(63 - Long.numberOfLeadingZeros(c.asLong()), graph());
-            }
+    public boolean inferStamp() {
+        IntegerStamp valueStamp = (IntegerStamp) getValue().stamp();
+        int min;
+        int max;
+        long mask = IntegerStamp.defaultMask(valueStamp.getBits());
+        int lastAlwaysSetBit = scan(valueStamp.downMask() & mask);
+        if (lastAlwaysSetBit == -1) {
+            min = -1;
+        } else {
+            min = lastAlwaysSetBit;
         }
-        return this;
+        int lastMaybeSetBit = scan(valueStamp.upMask() & mask);
+        max = lastMaybeSetBit;
+        return updateStamp(StampFactory.forInteger(Kind.Int, min, max));
     }
 
     @NodeIntrinsic
@@ -78,7 +78,7 @@
 
     @Override
     public void generate(NodeLIRBuilderTool gen) {
-        Value result = gen.getLIRGeneratorTool().emitBitScanReverse(gen.operand(value));
+        Value result = gen.getLIRGeneratorTool().emitBitScanReverse(gen.operand(getValue()));
         gen.setResult(this, result);
     }
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Tue Jun 24 23:29:13 2014 +0200
@@ -142,7 +142,7 @@
                     ((Lowerable) nonNullReceiver).lower(tool);
                 }
             }
-            InliningUtil.inline(invoke, replacementGraph, false);
+            InliningUtil.inline(invoke, replacementGraph, false, null);
             Debug.dump(graph(), "After inlining replacement %s", replacementGraph);
         } else {
             invoke.lower(tool);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReverseBytesNode.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReverseBytesNode.java	Tue Jun 24 23:29:13 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,33 +24,31 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
 
-public class ReverseBytesNode extends FloatingNode implements LIRLowerable, Canonicalizable {
-
-    @Input private ValueNode value;
+public class ReverseBytesNode extends UnaryNode implements LIRLowerable {
 
     public ReverseBytesNode(ValueNode value) {
-        super(StampFactory.forKind(value.getKind()));
-        assert getKind().isNumericInteger();
-        this.value = value;
+        super(StampFactory.forKind(value.getKind()), value);
+        assert getKind() == Kind.Int || getKind() == Kind.Long;
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (value.isConstant()) {
-            long v = value.asConstant().asLong();
-            if (getKind().getStackKind() == Kind.Int) {
-                return ConstantNode.forInt(Integer.reverseBytes((int) v), graph());
-            } else if (getKind() == Kind.Long) {
-                return ConstantNode.forLong(Long.reverseBytes(v), graph());
-            }
+    public boolean inferStamp() {
+        IntegerStamp valueStamp = (IntegerStamp) getValue().stamp();
+        Stamp newStamp;
+        if (getKind() == Kind.Int) {
+            long mask = IntegerStamp.defaultMask(Kind.Int.getBitCount());
+            newStamp = StampTool.stampForMask(valueStamp.getBits(), reverse((int) valueStamp.downMask()) & mask, reverse((int) valueStamp.upMask()) & mask);
+        } else if (getKind() == Kind.Long) {
+            newStamp = StampTool.stampForMask(valueStamp.getBits(), reverse(valueStamp.downMask()), reverse(valueStamp.upMask()));
+        } else {
+            return false;
         }
-        return this;
+        return updateStamp(newStamp);
     }
 
     @NodeIntrinsic
@@ -65,7 +63,7 @@
 
     @Override
     public void generate(NodeLIRBuilderTool gen) {
-        Value result = gen.getLIRGeneratorTool().emitByteSwap(gen.operand(value));
+        Value result = gen.getLIRGeneratorTool().emitByteSwap(gen.operand(getValue()));
         gen.setResult(this, result);
     }
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Tue Jun 24 23:29:13 2014 +0200
@@ -214,7 +214,7 @@
                                     expansionLogger.preExpand(methodCallTargetNode, inlineGraph);
                                 }
                                 List<Node> canonicalizedNodes = methodCallTargetNode.invoke().asNode().usages().snapshot();
-                                Map<Node, Node> inlined = InliningUtil.inline(methodCallTargetNode.invoke(), inlineGraph, false);
+                                Map<Node, Node> inlined = InliningUtil.inline(methodCallTargetNode.invoke(), inlineGraph, false, canonicalizedNodes);
                                 if (TraceTruffleExpansion.getValue()) {
                                     expansionLogger.postExpand(inlined);
                                 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java	Tue Jun 24 23:29:13 2014 +0200
@@ -244,7 +244,7 @@
                             ", must annotate such calls with @CompilerDirectives.SlowPath!"));
         }
         Invoke invoke = methodCallTargetNode.invoke();
-        InliningUtil.inline(invoke, inlineGraph, true);
+        InliningUtil.inline(invoke, inlineGraph, true, null);
     }
 
     private boolean tryCutOffRuntimeExceptions(MethodCallTargetNode methodCallTargetNode) {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Tue Jun 24 23:29:13 2014 +0200
@@ -154,7 +154,7 @@
     }
 
     private static String formatSourceSection(SourceSection sourceSection) {
-        return sourceSection != null ? sourceSection.toString() : "n/a";
+        return sourceSection != null ? sourceSection.getShortDescription() : "n/a";
     }
 
     public CompilationResult compileMethodHelper(StructuredGraph graph, Assumptions assumptions, String name, SpeculationLog speculationLog, InstalledCode predefinedInstalledCode) {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/ReplaceIntrinsicsPhase.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/ReplaceIntrinsicsPhase.java	Tue Jun 24 23:29:13 2014 +0200
@@ -54,7 +54,7 @@
                     } else {
                         StructuredGraph inlineGraph = replacements.getMethodSubstitution(methodCallTarget.targetMethod());
                         if (inlineGraph != null) {
-                            InliningUtil.inline(methodCallTarget.invoke(), inlineGraph, true);
+                            InliningUtil.inline(methodCallTarget.invoke(), inlineGraph, true, null);
                             Debug.dump(graph, "After inlining %s", methodCallTarget.targetMethod().toString());
                         }
                     }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExecutionContext.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExecutionContext.java	Tue Jun 24 23:29:13 2014 +0200
@@ -109,6 +109,16 @@
     }
 
     /**
+     * Has a {@link Probe} been created that is uniquely associated with a particular source code
+     * location.
+     *
+     * @return a probe uniquely associated with an extent of guest language source code.
+     */
+    public final boolean hasProbe(SourceSection sourceSection) {
+        return probeManager.hasProbe(sourceSection);
+    }
+
+    /**
      * Returns all existing probes with specific tag, or all probes if {@code tag = null}; empty
      * collection if no probes found.
      */
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleOptions.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleOptions.java	Tue Jun 24 23:29:13 2014 +0200
@@ -72,6 +72,13 @@
      */
     public static NodeCost TraceRewritesFilterToCost = parseNodeInfoKind(System.getProperty("truffle.TraceRewritesFilterToCost"));
 
+    /**
+     * Enables the dumping of Node creations and AST rewrites in JSON format.
+     * <p>
+     * Can be set with {@code -Dtruffle.TraceASTJSON=true}.
+     */
+    public static final boolean TraceASTJSON = Boolean.getBoolean("truffle.TraceASTJSON");
+
     private static NodeCost parseNodeInfoKind(String kind) {
         if (kind == null) {
             return null;
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/ProbeManager.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/ProbeManager.java	Tue Jun 24 23:29:13 2014 +0200
@@ -119,6 +119,11 @@
         return probe;
     }
 
+    public boolean hasProbe(SourceSection sourceSection) {
+        assert sourceSection != null;
+        return srcToProbe.get(sourceSection) != null;
+    }
+
     public Collection<Probe> findProbesTaggedAs(PhylumTag tag) {
         final List<Probe> probes = new ArrayList<>();
         for (Probe probe : srcToProbe.values()) {
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java	Tue Jun 24 23:29:13 2014 +0200
@@ -31,6 +31,7 @@
 
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.source.*;
+import com.oracle.truffle.api.utilities.*;
 
 /**
  * Abstract base class for all Truffle nodes.
@@ -58,12 +59,15 @@
     }
 
     protected Node() {
-        CompilerAsserts.neverPartOfCompilation();
+        this(null);
     }
 
     protected Node(SourceSection sourceSection) {
         CompilerAsserts.neverPartOfCompilation();
         this.sourceSection = sourceSection;
+        if (TruffleOptions.TraceASTJSON) {
+            JSONHelper.dumpNewNode(this);
+        }
     }
 
     /**
@@ -169,6 +173,9 @@
         }
         boolean isInserted = newChild.parent == null;
         newChild.parent = this;
+        if (TruffleOptions.TraceASTJSON) {
+            JSONHelper.dumpNewChild(this, newChild);
+        }
         newChild.adoptHelper();
         if (isInserted) {
             newChild.onAdopt();
@@ -273,6 +280,9 @@
             this.parent.adoptUnadoptedHelper(newNode);
         }
         reportReplace(this, newNode, reason);
+        if (TruffleOptions.TraceASTJSON) {
+            JSONHelper.dumpReplaceChild(this, newNode, reason);
+        }
         onReplace(newNode, reason);
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/JSONHelper.java	Tue Jun 24 23:29:13 2014 +0200
@@ -0,0 +1,122 @@
+/*
+ * 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.utilities;
+
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.source.*;
+
+/**
+ * Helper function that allows to dump the AST during creation to a JSON format.
+ */
+public class JSONHelper {
+
+    private static StringBuilder AstJsonDumpBuilder = new StringBuilder();
+
+    public static void dumpNewChild(Node parentNode, Node childNode) {
+        if (AstJsonDumpBuilder != null) {
+            AstJsonDumpBuilder.append("{ \"action\": \"insertNode\", \"parentId\": \"" + getID(parentNode) + "\", \"newId\": \"" + getID(childNode) + "\" },\n");
+        }
+    }
+
+    public static void dumpReplaceChild(Node oldNode, Node newNode, CharSequence reason) {
+        if (AstJsonDumpBuilder != null) {
+            AstJsonDumpBuilder.append("{ \"action\": \"replaceNode\", \"oldId\": \"" + getID(oldNode) + "\", \"newId\": \"" + getID(newNode) + "\", \"reason\": " + quote(reason) + " },\n");
+        }
+    }
+
+    public static void dumpNewNode(Node newNode) {
+        if (AstJsonDumpBuilder != null) {
+            AstJsonDumpBuilder.append("{ \"action\": \"createNode\", \"newId\": \"" + getID(newNode) + "\", \"type\": \"" + getType(newNode) + "\", \"description\": \"" + newNode.getDescription() +
+                            "\", \"language\": \"" + newNode.getLanguage() + "\"" + getSourceSectionInfo(newNode) + " },\n");
+        }
+    }
+
+    private static String getSourceSectionInfo(Node newNode) {
+        SourceSection sourceSection = newNode.getSourceSection();
+        if (sourceSection != null) {
+            return ", \"identifier\": \"" + sourceSection.getIdentifier() + "\" ";
+        } else {
+            return "";
+        }
+    }
+
+    public static String getResult() {
+        return AstJsonDumpBuilder.toString();
+    }
+
+    private static String getID(Node newChild) {
+        return String.valueOf(newChild.hashCode());
+    }
+
+    private static String getType(Node node) {
+        return node.getClass().getSimpleName();
+    }
+
+    private static String quote(CharSequence value) {
+        StringBuilder builder = new StringBuilder(value.length() + 2);
+        builder.append('"');
+        for (int i = 0; i < value.length(); i++) {
+            char c = value.charAt(i);
+            switch (c) {
+                case '"':
+                    builder.append("\\\"");
+                    break;
+                case '\\':
+                    builder.append("\\\\");
+                    break;
+                case '\b':
+                    builder.append("\\b");
+                    break;
+                case '\f':
+                    builder.append("\\f");
+                    break;
+                case '\n':
+                    builder.append("\\n");
+                    break;
+                case '\r':
+                    builder.append("\\r");
+                    break;
+                case '\t':
+                    builder.append("\\t");
+                    break;
+                default: {
+                    if (c < ' ') {
+                        builder.append("\\u00");
+                        builder.append(Character.forDigit((c >> 4) & 0xF, 16));
+                        builder.append(Character.forDigit(c & 0xF, 16));
+                    } else {
+                        builder.append(c);
+                    }
+                }
+            }
+        }
+        builder.append('"');
+        return builder.toString();
+    }
+
+    public static void restart() {
+        AstJsonDumpBuilder = new StringBuilder();
+    }
+}
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBlockNode.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBlockNode.java	Tue Jun 24 23:29:13 2014 +0200
@@ -41,10 +41,6 @@
     @Children private final SLStatementNode[] bodyNodes;
 
     public SLBlockNode(SLStatementNode[] bodyNodes) {
-        /*
-         * It is a Truffle requirement to call adoptChildren(), which performs all the necessary
-         * steps to add the new children to the node tree.
-         */
         this.bodyNodes = bodyNodes;
     }
 
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLFunctionBodyNode.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLFunctionBodyNode.java	Tue Jun 24 23:29:13 2014 +0200
@@ -50,10 +50,6 @@
     private final BranchProfile nullTaken = new BranchProfile();
 
     public SLFunctionBodyNode(SLStatementNode bodyNode) {
-        /*
-         * It is a Truffle requirement to call adoptChild(), which performs all the necessary steps
-         * to add the new child to the node tree.
-         */
         this.bodyNode = bodyNode;
     }
 
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLIfNode.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLIfNode.java	Tue Jun 24 23:29:13 2014 +0200
@@ -53,10 +53,6 @@
     private final BranchProfile elseTaken = new BranchProfile();
 
     public SLIfNode(SLExpressionNode conditionNode, SLStatementNode thenPartNode, SLStatementNode elsePartNode) {
-        /*
-         * It is a Truffle requirement to call adoptChild(), which performs all the necessary steps
-         * to add the new child to the node tree.
-         */
         this.conditionNode = conditionNode;
         this.thenPartNode = thenPartNode;
         this.elsePartNode = elsePartNode;
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLWhileNode.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLWhileNode.java	Tue Jun 24 23:29:13 2014 +0200
@@ -51,10 +51,6 @@
     private final BranchProfile breakTaken = new BranchProfile();
 
     public SLWhileNode(SLExpressionNode conditionNode, SLStatementNode bodyNode) {
-        /*
-         * It is a Truffle requirement to call adoptChild(), which performs all the necessary steps
-         * to add the new child to the node tree.
-         */
         this.conditionNode = conditionNode;
         this.bodyNode = bodyNode;
     }
--- a/mx/mx_graal.py	Tue Jun 24 23:24:02 2014 +0200
+++ b/mx/mx_graal.py	Tue Jun 24 23:29:13 2014 +0200
@@ -1868,6 +1868,20 @@
 def isGraalEnabled(vm):
     return vm != 'original' and not vm.endswith('nograal')
 
+def jol(args):
+    """Java Object Layout"""
+    jolurl = "http://lafo.ssw.uni-linz.ac.at/truffle/jol/jol-internals.jar"
+    joljar = "lib/jol-internals.jar"
+    if not exists(joljar):
+        mx.download(joljar, [jolurl])
+
+    candidates = mx.findclass(args, logToConsole=False, matcher=lambda s, classname: s == classname or classname.endswith('.' + s) or classname.endswith('$' + s))
+    if len(candidates) > 10:
+        print "Found %d candidates. Please be more precise." % (len(candidates))
+        return
+
+    vm(['-javaagent:' + joljar, '-cp', os.pathsep.join([mx.classpath(), joljar]), "org.openjdk.jol.MainObjectInternals"] + candidates)
+
 def site(args):
     """create a website containing javadoc and the project dependency graph"""
 
@@ -2094,7 +2108,8 @@
         'vmfg': [vmfg, '[-options] class [args...]'],
         'deoptalot' : [deoptalot, '[n]'],
         'longtests' : [longtests, ''],
-        'sl' : [sl, '[SL args|@VM options]']
+        'sl' : [sl, '[SL args|@VM options]'],
+        'jol' : [jol, ''],
     }
 
     mx.add_argument('--jacoco', help='instruments com.oracle.* classes using JaCoCo', default='off', choices=['off', 'on', 'append'])
--- a/mxtool/mx.py	Tue Jun 24 23:24:02 2014 +0200
+++ b/mxtool/mx.py	Tue Jun 24 23:29:13 2014 +0200
@@ -4488,7 +4488,7 @@
         return kwargs.pop(0)
     return None
 
-def findclass(args, logToConsole=True):
+def findclass(args, logToConsole=True, matcher=lambda string, classname: string in classname):
     """find all classes matching a given substring"""
     matches = []
     for entry, filename in classpath_walk(includeBootClasspath=True):
@@ -4499,7 +4499,7 @@
                 classname = filename.replace(os.sep, '.')
             classname = classname[:-len('.class')]
             for a in args:
-                if a in classname:
+                if matcher(a, classname):
                     matches.append(classname)
                     if logToConsole:
                         log(classname)
--- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputEdge.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputEdge.java	Tue Jun 24 23:29:13 2014 +0200
@@ -68,29 +68,31 @@
     private final int from;
     private final int to;
     private final String label;
+    private final String type;
     private State state;
 
     public InputEdge(char toIndex, int from, int to) {
-        this((char) 0, toIndex, from, to, null);
+        this((char) 0, toIndex, from, to, null, null);
     }
 
     public InputEdge(char fromIndex, char toIndex, int from, int to) {
-        this(fromIndex, toIndex, from, to, null);
+        this(fromIndex, toIndex, from, to, null, null);
     }
 
-    public InputEdge(char fromIndex, char toIndex, int from, int to, String label) {
+    public InputEdge(char fromIndex, char toIndex, int from, int to, String label, String type) {
         this.toIndex = toIndex;
         this.fromIndex = fromIndex;
         this.from = from;
         this.to = to;
         this.state = State.SAME;
         this.label = label;
+        this.type = type;
     }
 
     static WeakHashMap<InputEdge, WeakReference<InputEdge>> immutableCache = new WeakHashMap<>();
 
-    public static synchronized InputEdge createImmutable(char fromIndex, char toIndex, int from, int to, String label) {
-        InputEdge edge = new InputEdge(fromIndex, toIndex, from, to, label, State.IMMUTABLE);
+    public static synchronized InputEdge createImmutable(char fromIndex, char toIndex, int from, int to, String label, String type) {
+        InputEdge edge = new InputEdge(fromIndex, toIndex, from, to, label, type, State.IMMUTABLE);
         WeakReference<InputEdge> result = immutableCache.get(edge);
         if (result != null) {
             InputEdge edge2 = result.get();
@@ -102,13 +104,14 @@
         return edge;
     }
 
-    public InputEdge(char fromIndex, char toIndex, int from, int to, String label, State state) {
+    public InputEdge(char fromIndex, char toIndex, int from, int to, String label, String type, State state) {
         this.toIndex = toIndex;
         this.fromIndex = fromIndex;
         this.from = from;
         this.to = to;
         this.state = state;
         this.label = label;
+        this.type = type;
     }
 
     public State getState() {
@@ -145,6 +148,10 @@
     public String getLabel() {
         return label;
     }
+    
+    public String getType() {
+        return type;
+    }
 
     @Override
     public boolean equals(Object o) {
--- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/BinaryParser.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/BinaryParser.java	Tue Jun 24 23:29:13 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -215,12 +215,20 @@
         }
     }
     
+    private static class TypedPort extends Port {
+        public final EnumValue type;
+        private TypedPort(boolean isList, String name, EnumValue type) {
+            super(isList, name);
+            this.type = type;
+        }
+    }
+    
     private static class NodeClass {
         public final String className;
         public final String nameTemplate;
-        public final List<Port> inputs;
+        public final List<TypedPort> inputs;
         public final List<Port> sux;
-        private NodeClass(String className, String nameTemplate, List<Port> inputs, List<Port> sux) {
+        private NodeClass(String className, String nameTemplate, List<TypedPort> inputs, List<Port> sux) {
             this.className = className;
             this.nameTemplate = nameTemplate;
             this.inputs = inputs;
@@ -464,11 +472,12 @@
                 String className = readString();
                 String nameTemplate = readString();
                 int inputCount = readShort();
-                List<Port> inputs = new ArrayList<>(inputCount);
+                List<TypedPort> inputs = new ArrayList<>(inputCount);
                 for (int i = 0; i < inputCount; i++) {
                     boolean isList = readByte() != 0;
                     String name = readPoolObject(String.class);
-                    inputs.add(new Port(isList, name));
+                    EnumValue inputType = readPoolObject(EnumValue.class);
+                    inputs.add(new TypedPort(isList, name, inputType));
                 }
                 int suxCount = readShort();
                 List<Port> sux = new ArrayList<>(suxCount);
@@ -726,20 +735,20 @@
             }
             int edgesStart = edges.size();
             int portNum = 0;
-            for (Port p : nodeClass.inputs) {
+            for (TypedPort p : nodeClass.inputs) {
                 if (p.isList) {
                     int size = readShort();
                     for (int j = 0; j < size; j++) {
                         int in = readInt();
                         if (in >= 0) {
-                            edges.add(new Edge(in, id, (char) (preds + portNum), p.name + "[" + j + "]", true));
+                            edges.add(new Edge(in, id, (char) (preds + portNum), p.name + "[" + j + "]", p.type.toString(Length.S), true));
                             portNum++;
                         }
                     }
                 } else {
                     int in = readInt();
                     if (in >= 0) {
-                        edges.add(new Edge(in, id, (char) (preds + portNum), p.name, true));
+                        edges.add(new Edge(in, id, (char) (preds + portNum), p.name, p.type.toString(Length.S), true));
                         portNum++;
                     }
                 }
@@ -752,14 +761,14 @@
                     for (int j = 0; j < size; j++) {
                         int sux = readInt();
                         if (sux >= 0) {
-                            edges.add(new Edge(id, sux, (char) portNum, p.name + "[" + j + "]", false));
+                            edges.add(new Edge(id, sux, (char) portNum, p.name + "[" + j + "]", "Successor", false));
                             portNum++;
                         }
                     }
                 } else {
                     int sux = readInt();
                     if (sux >= 0) {
-                        edges.add(new Edge(id, sux, (char) portNum, p.name, false));
+                        edges.add(new Edge(id, sux, (char) portNum, p.name, "Successor", false));
                         portNum++;
                     }
                 }
@@ -780,7 +789,7 @@
         for (Edge e : edges) {
             char fromIndex = e.input ? 1 : e.num;
             char toIndex = e.input ? e.num : 0;
-            graph.addEdge(InputEdge.createImmutable(fromIndex, toIndex, e.from, e.to, e.label));
+            graph.addEdge(InputEdge.createImmutable(fromIndex, toIndex, e.from, e.to, e.label, e.type));
         }
     }
     
@@ -845,14 +854,16 @@
         final int to;
         final char num;
         final String label;
+        final String type;
         final boolean input;
         public Edge(int from, int to) {
-            this(from, to, (char) 0, null, false);
+            this(from, to, (char) 0, null, null, false);
         }
-        public Edge(int from, int to, char num, String label, boolean input) {
+        public Edge(int from, int to, char num, String label, String type, boolean input) {
             this.from = from;
             this.to = to;
             this.label = label != null ? label.intern() : label;
+            this.type = type != null ? type.intern() : type;
             this.num = num;
             this.input = input;
         }
--- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/Parser.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/Parser.java	Tue Jun 24 23:29:13 2014 +0200
@@ -410,7 +410,7 @@
                 throw new SAXException(e);
             }
 
-            InputEdge conn = new InputEdge((char) fromIndex, (char) toIndex, from, to, label);
+            InputEdge conn = new InputEdge((char) fromIndex, (char) toIndex, from, to, label, "");
             return start(conn);
         }
 
--- a/src/share/tools/IdealGraphVisualizer/Difference/src/com/sun/hotspot/igv/difference/Difference.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/src/share/tools/IdealGraphVisualizer/Difference/src/com/sun/hotspot/igv/difference/Difference.java	Tue Jun 24 23:29:13 2014 +0200
@@ -211,7 +211,7 @@
             if (nodeFrom == null || nodeTo == null) {
                 System.out.println("Unexpected edge : " + from + " -> " + to);
             } else {
-                InputEdge newEdge = new InputEdge(fromIndex, toIndex, nodeFrom.getId(), nodeTo.getId());
+                InputEdge newEdge = new InputEdge(fromIndex, toIndex, nodeFrom.getId(), nodeTo.getId(), e.getLabel(), e.getType());
                 if (!newEdges.contains(newEdge)) {
                     markAsDeleted(newEdge);
                     newEdges.add(newEdge);
@@ -231,7 +231,7 @@
             if (nodeFrom == null || nodeTo == null) {
                 System.out.println("Unexpected edge : " + from + " -> " + to);
             } else {
-                InputEdge newEdge = new InputEdge(fromIndex, toIndex, nodeFrom.getId(), nodeTo.getId());
+                InputEdge newEdge = new InputEdge(fromIndex, toIndex, nodeFrom.getId(), nodeTo.getId(), e.getLabel(), e.getType());
                 if (!newEdges.contains(newEdge)) {
                     markAsNew(newEdge);
                     newEdges.add(newEdge);
--- a/src/share/tools/IdealGraphVisualizer/Filter/src/com/sun/hotspot/igv/filter/CombineFilter.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/src/share/tools/IdealGraphVisualizer/Filter/src/com/sun/hotspot/igv/filter/CombineFilter.java	Tue Jun 24 23:29:13 2014 +0200
@@ -97,7 +97,7 @@
 
                         for (InputSlot s : f.getInputSlots()) {
                             for (Connection c : s.getConnections()) {
-                                Connection newConn = diagram.createConnection(slot, c.getOutputSlot(), c.getLabel());
+                                Connection newConn = diagram.createConnection(slot, c.getOutputSlot(), c.getLabel(), c.getType());
                                 newConn.setColor(c.getColor());
                                 newConn.setStyle(c.getStyle());
                             }
@@ -154,7 +154,7 @@
                                     }
                                 }
                                 for (Connection c : nextSlot.getConnections()) {
-                                    Connection newConn = diagram.createConnection(c.getInputSlot(), slot, c.getLabel());
+                                    Connection newConn = diagram.createConnection(c.getInputSlot(), slot, c.getLabel(), c.getType());
                                     newConn.setColor(c.getColor());
                                     newConn.setStyle(c.getStyle());
                                 }
--- a/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/GraalEdgeColorFilter.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/GraalEdgeColorFilter.java	Tue Jun 24 23:29:13 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,6 +31,7 @@
 import com.sun.hotspot.igv.graph.Figure;
 import com.sun.hotspot.igv.graph.InputSlot;
 import java.awt.Color;
+import java.util.HashMap;
 import java.util.List;
 import java.util.regex.Pattern;
 
@@ -41,9 +42,8 @@
  */
 public class GraalEdgeColorFilter extends AbstractFilter {
 
-    private Color successorColor = Color.BLUE;
-    private Color usageColor = Color.RED;
-    private Color memoryColor = Color.GREEN;
+    private HashMap<String,Color> usageColor = new HashMap<>();
+    private Color otherUsageColor = Color.BLACK;
 
     public GraalEdgeColorFilter() {
     }
@@ -56,66 +56,43 @@
     @Override
     public void apply(Diagram d) {
         List<Figure> figures = d.getFigures();
-        Pattern ndf = Pattern.compile(".*#NDF(\\[[0-9]*\\])?");
         for (Figure f : figures) {
-            Properties p = f.getProperties();
-            int predCount;
-            String predCountString = p.get("predecessorCount");
-            if (predCountString != null) {
-                predCount = Integer.parseInt(predCountString);
-            } else if (Boolean.parseBoolean(p.get("hasPredecessor"))) {
-                predCount = 1;
-            } else {
-                predCount = 0;
-            }
             for (InputSlot is : f.getInputSlots()) {
-                Color color;
-                ConnectionStyle style = ConnectionStyle.NORMAL;
-                if (is.getPosition() < predCount) {
-                    color = successorColor;
-                    style = ConnectionStyle.BOLD;
-                } else {
-                    color = usageColor;
-                }
-
-                is.setColor(color);
                 for (Connection c : is.getConnections()) {
-                    if (c.getLabel() == null || !ndf.matcher(c.getLabel()).matches()) {
-                        c.setColor(color);
-                        if (c.getStyle() != ConnectionStyle.DASHED) {
-                            c.setStyle(style);
+                    String type = c.getType();
+                    if (type == "Association" && "EndNode".equals(c.getOutputSlot().getFigure().getProperties().get("class"))) {
+                        type = "Successor";
+                    }
+                    
+                    if (type != null) {
+                        Color typeColor = usageColor.get(type);
+                        if (typeColor == null) {
+                            c.setColor(otherUsageColor);
+                        } else {
+                            c.setColor(typeColor);
                         }
-                    } else if ("EndNode".equals(c.getOutputSlot().getFigure().getProperties().get("class"))
-                            || "EndNode".equals(c.getOutputSlot().getProperties().get("class"))) {
-                        c.setColor(successorColor);
-                        c.setStyle(ConnectionStyle.BOLD);
+                        if (c.getStyle() != ConnectionStyle.DASHED && type == "Successor") {
+                            c.setStyle(ConnectionStyle.BOLD);
+                        }
                     }
                 }
             }
         }
     }
 
-    public Color getUsageColor() {
-        return usageColor;
-    }
-
-    public void setUsageColor(Color usageColor) {
-        this.usageColor = usageColor;
-    }
-
-    public void setMemoryColor(Color memoryColor) {
-        this.memoryColor = memoryColor;
+    public Color getUsageColor(String type) {
+        return usageColor.get(type);
     }
 
-    public Color getMemoryColor() {
-        return memoryColor;
+    public void setUsageColor(String type, Color usageColor) {
+        this.usageColor.put(type, usageColor);
     }
-
-    public Color getSuccessorColor() {
-        return successorColor;
+    
+    public Color getOtherUsageColor() {
+        return otherUsageColor;
     }
-
-    public void setSuccessorColor(Color successorColor) {
-        this.successorColor = successorColor;
+    
+    public void setOtherUsageColor(Color otherUsageColor) {
+        this.otherUsageColor = otherUsageColor;
     }
 }
--- a/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/edgeColor.filter	Tue Jun 24 23:24:02 2014 +0200
+++ b/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/edgeColor.filter	Tue Jun 24 23:29:13 2014 +0200
@@ -1,4 +1,5 @@
 var f = new com.sun.hotspot.igv.graal.filters.GraalEdgeColorFilter();
-f.setUsageColor(blue);
-f.setSuccessorColor(red);
+f.setUsageColor("Successor", red);
+f.setUsageColor("Value", blue);
+f.setUsageColor("Memory", new Color(0.0, 0.5, 0.0));
 f.apply(graph);
--- a/src/share/tools/IdealGraphVisualizer/Graph/src/com/sun/hotspot/igv/graph/Connection.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/src/share/tools/IdealGraphVisualizer/Graph/src/com/sun/hotspot/igv/graph/Connection.java	Tue Jun 24 23:29:13 2014 +0200
@@ -55,11 +55,13 @@
     private ConnectionStyle style;
     private List<Point> controlPoints;
     private String label;
+    private String type;
 
-    protected Connection(InputSlot inputSlot, OutputSlot outputSlot, String label) {
+    protected Connection(InputSlot inputSlot, OutputSlot outputSlot, String label, String type) {
         this.inputSlot = inputSlot;
         this.outputSlot = outputSlot;
         this.label = label;
+        this.type = type;
         this.inputSlot.connections.add(this);
         this.outputSlot.connections.add(this);
         controlPoints = new ArrayList<>();
@@ -105,6 +107,10 @@
     public String getLabel() {
         return label;
     }
+    
+    public String getType() {
+        return type;
+    }
 
     public void remove() {
         inputSlot.getFigure().removePredecessor(outputSlot.getFigure());
@@ -116,10 +122,12 @@
     public String getToolTipText() {
         StringBuilder builder = new StringBuilder();
         if (label != null) {
-            builder.append(label).append(": from ");
-        } else {
-            builder.append("From ");
+            builder.append(label).append(": ");
         }
+        if (type != null) {
+            builder.append(type).append(" ");
+        }
+        builder.append("from ");
         builder.append(getOutputSlot().getFigure().getSource().getSourceNodes().get(0).getId());
         builder.append(" to ");
         builder.append(getInputSlot().getFigure().getSource().getSourceNodes().get(0).getId());
--- a/src/share/tools/IdealGraphVisualizer/Graph/src/com/sun/hotspot/igv/graph/Diagram.java	Tue Jun 24 23:24:02 2014 +0200
+++ b/src/share/tools/IdealGraphVisualizer/Graph/src/com/sun/hotspot/igv/graph/Diagram.java	Tue Jun 24 23:29:13 2014 +0200
@@ -82,10 +82,10 @@
         return f;
     }
 
-    public Connection createConnection(InputSlot inputSlot, OutputSlot outputSlot, String label) {
+    public Connection createConnection(InputSlot inputSlot, OutputSlot outputSlot, String label, String type) {
         assert inputSlot.getFigure().getDiagram() == this;
         assert outputSlot.getFigure().getDiagram() == this;
-        return new Connection(inputSlot, outputSlot, label);
+        return new Connection(inputSlot, outputSlot, label, type);
     }
     
     public Map<InputNode, Set<Figure>> calcSourceToFigureRelation() {
@@ -145,7 +145,7 @@
             }
             InputSlot inputSlot = toFigure.getInputSlots().get(toIndex);
 
-            Connection c = d.createConnection(inputSlot, outputSlot, e.getLabel());
+            Connection c = d.createConnection(inputSlot, outputSlot, e.getLabel(), e.getType());
 
             if (e.getState() == InputEdge.State.NEW) {
                 c.setStyle(Connection.ConnectionStyle.BOLD);
--- a/src/share/vm/compiler/compileBroker.cpp	Tue Jun 24 23:24:02 2014 +0200
+++ b/src/share/vm/compiler/compileBroker.cpp	Tue Jun 24 23:29:13 2014 +0200
@@ -383,7 +383,7 @@
     st->print("%7d ", (int) st->time_stamp().milliseconds());  // print timestamp
   }
   // print compiler name if requested
-  if (CIPrintCompilerName) tty->print("%s:", CompileBroker::compiler_name(comp_level));
+  if (CIPrintCompilerName) st->print("%s:", CompileBroker::compiler_name(comp_level));
   st->print("%4d ", compile_id);    // print compilation number
 
   // For unloaded methods the transition to zombie occurs after the
@@ -805,7 +805,19 @@
 
 #if defined(COMPILERGRAAL)
   _compilers[1] = graal;
-  c2_count = UseGraalCompilationQueue ? 0 : FLAG_IS_DEFAULT(GraalThreads) ? c2_count : GraalThreads;
+  if (UseGraalCompilationQueue) {
+    c2_count = 0;
+  } else {
+    if (FLAG_IS_DEFAULT(GraalThreads)) {
+      if (!TieredCompilation && FLAG_IS_DEFAULT(BootstrapGraal) || BootstrapGraal) {
+        // Graal will bootstrap so give it the same number of threads
+        // as we would give the Java based compilation queue.
+        c2_count = os::active_processor_count();
+      }
+    } else {
+      c2_count = GraalThreads;
+    }
+  }
 #endif // COMPILERGRAAL
 
 #ifdef COMPILER2
--- a/src/share/vm/graal/graalCompiler.cpp	Tue Jun 24 23:24:02 2014 +0200
+++ b/src/share/vm/graal/graalCompiler.cpp	Tue Jun 24 23:29:13 2014 +0200
@@ -125,7 +125,9 @@
   if (!UseGraalCompilationQueue) {
     ResourceMark rm;
     HandleMark hm;
-    tty->print("Bootstrapping Graal");
+    if (PrintBootstrap) {
+      tty->print("Bootstrapping Graal");
+    }
     jlong start = os::javaTimeMillis();
 
     Array<Method*>* objectMethods = InstanceKlass::cast(SystemDictionary::Object_klass())->methods();
@@ -147,14 +149,17 @@
       os::sleep(THREAD, sleep_time, true);
       sleep_time = 100;
       qsize = CompileBroker::queue_size(CompLevel_full_optimization);
-      while (z < (_compiled / 100)) {
+      if (PrintBootstrap) {
+        while (z < (_compiled / 100)) {
           ++z;
           tty->print_raw(".");
+        }
       }
-
     } while (qsize != 0);
 
-    tty->print_cr(" in %d ms (compiled %d methods)", os::javaTimeMillis() - start, _compiled);
+    if (PrintBootstrap) {
+      tty->print_cr(" in %d ms (compiled %d methods)", os::javaTimeMillis() - start, _compiled);
+    }
   } else {
 
     TempNewSymbol name = SymbolTable::new_symbol("com/oracle/graal/hotspot/CompilationQueue", THREAD);
--- a/src/share/vm/graal/graalCompilerToVM.cpp	Tue Jun 24 23:24:02 2014 +0200
+++ b/src/share/vm/graal/graalCompilerToVM.cpp	Tue Jun 24 23:29:13 2014 +0200
@@ -194,9 +194,9 @@
   return (jlong) (address) method();
 }
 
-C2V_VMENTRY(jlong, findUniqueConcreteMethod, (JNIEnv *, jobject, jlong metaspace_method))
+C2V_VMENTRY(jlong, findUniqueConcreteMethod, (JNIEnv *, jobject, jlong metaspace_klass, jlong metaspace_method))
   methodHandle method = asMethod(metaspace_method);
-  KlassHandle holder = method->method_holder();
+  KlassHandle holder = asKlass(metaspace_klass);
   assert(!holder->is_interface(), "should be handled in Java code");
   ResourceMark rm;
   MutexLocker locker(Compile_lock);
@@ -1003,7 +1003,7 @@
   {CC"exceptionTableStart",                          CC"("METASPACE_METHOD")J",                                                FN_PTR(exceptionTableStart)},
   {CC"exceptionTableLength",                         CC"("METASPACE_METHOD")I",                                                FN_PTR(exceptionTableLength)},
   {CC"hasBalancedMonitors",                          CC"("METASPACE_METHOD")Z",                                                FN_PTR(hasBalancedMonitors)},
-  {CC"findUniqueConcreteMethod",                     CC"("METASPACE_METHOD")"METASPACE_METHOD,                                 FN_PTR(findUniqueConcreteMethod)},
+  {CC"findUniqueConcreteMethod",                     CC"("METASPACE_KLASS METASPACE_METHOD")"METASPACE_METHOD,                 FN_PTR(findUniqueConcreteMethod)},
   {CC"getKlassImplementor",                          CC"("METASPACE_KLASS")"METASPACE_KLASS,                                   FN_PTR(getKlassImplementor)},
   {CC"getStackTraceElement",                         CC"("METASPACE_METHOD"I)"STACK_TRACE_ELEMENT,                             FN_PTR(getStackTraceElement)},
   {CC"methodIsIgnoredBySecurityStackWalk",           CC"("METASPACE_METHOD")Z",                                                FN_PTR(methodIsIgnoredBySecurityStackWalk)},
--- a/src/share/vm/graal/graalGlobals.hpp	Tue Jun 24 23:24:02 2014 +0200
+++ b/src/share/vm/graal/graalGlobals.hpp	Tue Jun 24 23:29:13 2014 +0200
@@ -52,6 +52,9 @@
   COMPILERGRAAL_PRESENT(product(bool, BootstrapGraal, true,                 \
           "Bootstrap Graal before running Java main method"))               \
                                                                             \
+  COMPILERGRAAL_PRESENT(product(bool, PrintBootstrap, true,                 \
+          "Print Graal bootstrap progress and summary"))                    \
+                                                                            \
   COMPILERGRAAL_PRESENT(product(intx, GraalThreads, 1,                      \
           "Force number of Graal compiler threads to use"))                 \
                                                                             \
--- a/src/share/vm/runtime/sharedRuntime.cpp	Tue Jun 24 23:24:02 2014 +0200
+++ b/src/share/vm/runtime/sharedRuntime.cpp	Tue Jun 24 23:29:13 2014 +0200
@@ -886,7 +886,7 @@
             // If there's no PcDesc then we'll die way down inside of
             // deopt instead of just getting normal error reporting,
             // so only go there if it will succeed.
-            target_pc = deoptimize_for_implicit_exception(thread, pc, nm, Deoptimization::Reason_null_check);
+            return deoptimize_for_implicit_exception(thread, pc, nm, Deoptimization::Reason_null_check);
           } else {
 #endif
           target_pc = nm->continuation_for_implicit_exception(pc);
@@ -910,7 +910,7 @@
 #endif
 #ifdef GRAAL
         if (nm->is_compiled_by_graal() && nm->pc_desc_at(pc) != NULL) {
-          target_pc = deoptimize_for_implicit_exception(thread, pc, nm, Deoptimization::Reason_div0_check);
+          return deoptimize_for_implicit_exception(thread, pc, nm, Deoptimization::Reason_div0_check);
         } else {
 #endif
         target_pc = nm->continuation_for_implicit_exception(pc);
@@ -928,11 +928,17 @@
 
     assert(exception_kind == IMPLICIT_NULL || exception_kind == IMPLICIT_DIVIDE_BY_ZERO, "wrong implicit exception kind");
 
-    // for AbortVMOnException flag
-    NOT_PRODUCT(Exceptions::debug_check_abort("java.lang.NullPointerException"));
     if (exception_kind == IMPLICIT_NULL) {
+#ifndef PRODUCT
+      // for AbortVMOnException flag
+      Exceptions::debug_check_abort("java.lang.NullPointerException");
+#endif //PRODUCT
       Events::log_exception(thread, "Implicit null exception at " INTPTR_FORMAT " to " INTPTR_FORMAT, pc, target_pc);
     } else {
+#ifndef PRODUCT
+      // for AbortVMOnException flag
+      Exceptions::debug_check_abort("java.lang.ArithmeticException");
+#endif //PRODUCT
       Events::log_exception(thread, "Implicit division by zero exception at " INTPTR_FORMAT " to " INTPTR_FORMAT, pc, target_pc);
     }
     return target_pc;