changeset 20053:eea134855f85

Merge.
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Fri, 27 Mar 2015 17:02:53 +0100
parents d22307a9a025 (current diff) b7477f2df553 (diff)
children c816aca2a3db
files graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInlineInvokePlugin.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetClassLoader0Node.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetComponentTypeNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetModifiersNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetSuperclassNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassIsArrayNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassIsInterfaceNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassIsPrimitiveNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CallSiteSubstitutions.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/SelfReplacingMethodCallTargetNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MacroSubstitution.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableMacroNode.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/CallsiteHolderDummy.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MemoryAnchorNode.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/AssumptionNode.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/NeverInlineMacroNode.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeLoadMacroNode.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeStoreMacroNode.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/UnsafeTypeCastMacroNode.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/CompilerAssertsSubstitutions.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/OptimizedAssumptionSubstitutions.java
diffstat 148 files changed, 2818 insertions(+), 2308 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/DebugInfo.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/DebugInfo.java	Fri Mar 27 17:02:53 2015 +0100
@@ -24,6 +24,8 @@
 
 import java.util.*;
 
+import com.oracle.graal.api.meta.*;
+
 /**
  * Represents the debugging information for a particular point of execution. This information
  * includes:
@@ -40,6 +42,7 @@
 
     private final BytecodePosition bytecodePosition;
     private final ReferenceMap referenceMap;
+    @SuppressWarnings("unused") private final Value[] virtualObjectMapping;
     private RegisterSaveLayout calleeSaveInfo;
 
     /**
@@ -48,10 +51,16 @@
      * @param codePos the {@linkplain BytecodePosition code position} or {@linkplain BytecodeFrame
      *            frame} info
      * @param referenceMap the reference map
+     * @param virtualObjectMapping the mapping of {@link VirtualObject}s to their real values
      */
-    public DebugInfo(BytecodePosition codePos, ReferenceMap referenceMap) {
+    public DebugInfo(BytecodePosition codePos, ReferenceMap referenceMap, Value[] virtualObjectMapping) {
         this.bytecodePosition = codePos;
         this.referenceMap = referenceMap;
+        this.virtualObjectMapping = virtualObjectMapping;
+    }
+
+    public DebugInfo(BytecodePosition codePos) {
+        this(codePos, null, null);
     }
 
     /**
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Assumptions.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Assumptions.java	Fri Mar 27 17:02:53 2015 +0100
@@ -57,7 +57,7 @@
 
         public AssumptionResult(T result, Assumption... assumptions) {
             this.result = result;
-            this.assumptions = assumptions.clone();
+            this.assumptions = assumptions;
         }
 
         public AssumptionResult(T result) {
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaUtil.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaUtil.java	Fri Mar 27 17:02:53 2015 +0100
@@ -51,7 +51,7 @@
      */
     public static long getMemorySizeRecursive(MetaAccessProvider access, ConstantReflectionProvider constantReflection, JavaConstant constant, PrintStream out, int printTopN) {
         Set<JavaConstant> marked = new HashSet<>();
-        Stack<JavaConstant> stack = new Stack<>();
+        Deque<JavaConstant> stack = new ArrayDeque<>();
         if (constant.getKind() == Kind.Object && constant.isNonNull()) {
             marked.add(constant);
         }
@@ -120,7 +120,7 @@
         return sum;
     }
 
-    private static void pushConstant(Set<JavaConstant> marked, Stack<JavaConstant> stack, JavaConstant value) {
+    private static void pushConstant(Set<JavaConstant> marked, Deque<JavaConstant> stack, JavaConstant value) {
         if (value.isNonNull()) {
             if (!marked.contains(value)) {
                 marked.add(value);
--- a/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java	Fri Mar 27 17:02:53 2015 +0100
@@ -728,6 +728,7 @@
         public static final AMD64MOp IMUL = new AMD64MOp("IMUL", 0xF7, 5);
         public static final AMD64MOp DIV  = new AMD64MOp("DIV",  0xF7, 6);
         public static final AMD64MOp IDIV = new AMD64MOp("IDIV", 0xF7, 7);
+        public static final AMD64MOp INC  = new AMD64MOp("INC",  0xFF, 0);
         // @formatter:on
 
         private final int ext;
@@ -2412,4 +2413,12 @@
         emitOperandHelper(1, src);
     }
 
+    /**
+     * Emits an instruction which is considered to be illegal. This is used if we deliberately want
+     * to crash the program (debugging etc.).
+     */
+    public void illegal() {
+        emitByte(0x0f);
+        emitByte(0x0b);
+    }
 }
--- a/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java	Fri Mar 27 17:02:53 2015 +0100
@@ -1741,4 +1741,20 @@
     public void casxa(Register rs1, Register rs2, Register rd, Asi asi) {
         ld(Casxa, new SPARCAddress(rs1, rs2), rd, asi);
     }
+
+    @Override
+    public InstructionCounter getInstructionCounter() {
+        return new SPARCInstructionCounter(this);
+    }
+
+    public void patchAddImmediate(int position, int simm13) {
+        int inst = getInt(position);
+        assert SPARCAssembler.isSimm13(simm13) : simm13;
+        assert (inst >>> 30) == 0b10 : String.format("0x%x", inst);
+        assert ((inst >>> 18) & 0b11_1111) == 0 : String.format("0x%x", inst);
+        assert (inst & (1 << 13)) != 0 : String.format("0x%x", inst);
+        inst = inst & (~((1 << 13) - 1));
+        inst |= simm13 & ((1 << 12) - 1);
+        emitInt(inst, position);
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCInstructionCounter.java	Fri Mar 27 17:02:53 2015 +0100
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.asm.sparc;
+
+import java.util.*;
+
+import com.oracle.graal.asm.Assembler.InstructionCounter;
+
+public class SPARCInstructionCounter implements InstructionCounter {
+    // Use a treemap to keep the order in the output
+    private static final TreeMap<String, SPARCInstructionMatch> INSTRUCTION_MATCHER = new TreeMap<>();
+    static {
+        // @formatter:off
+        INSTRUCTION_MATCHER.put("nop", new SPARCInstructionMatch(0xFFFF_FFFF, 0x0100_0000));
+        INSTRUCTION_MATCHER.put("st", new OP3LowBitsMatcher(0b11, 0x4, 0x5, 0x6, 0x7, 0xe, 0xf));
+        INSTRUCTION_MATCHER.put("ld", new OP3LowBitsMatcher(0b11, 0x0, 0x1, 0x2, 0x3, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd));
+        INSTRUCTION_MATCHER.put("all", new SPARCInstructionMatch(0x0, 0x0));
+        // @formatter:on
+    }
+    private final SPARCAssembler asm;
+
+    public SPARCInstructionCounter(SPARCAssembler asm) {
+        super();
+        this.asm = asm;
+    }
+
+    @Override
+    public int[] countInstructions(String[] instructionTypes, int beginPc, int endPc) {
+        SPARCInstructionMatch[] matchers = new SPARCInstructionMatch[instructionTypes.length];
+        for (int i = 0; i < instructionTypes.length; i++) {
+            String typeName = instructionTypes[i];
+            matchers[i] = INSTRUCTION_MATCHER.get(typeName);
+            if (matchers[i] == null) {
+                throw new IllegalArgumentException(String.format("Unknown instruction class %s, supported types are: %s", typeName, INSTRUCTION_MATCHER.keySet()));
+            }
+        }
+        return countBetween(matchers, beginPc, endPc);
+    }
+
+    private int[] countBetween(SPARCInstructionMatch[] matchers, int startPc, int endPc) {
+        int[] counts = new int[matchers.length];
+        for (int p = startPc; p < endPc; p += 4) {
+            int instr = asm.getInt(p);
+            for (int i = 0; i < matchers.length; i++) {
+                SPARCInstructionMatch matcher = matchers[i];
+                if (matcher.matches(instr)) {
+                    counts[i]++;
+                }
+            }
+        }
+        return counts;
+    }
+
+    @Override
+    public String[] getSupportedInstructionTypes() {
+        return INSTRUCTION_MATCHER.keySet().toArray(new String[0]);
+    }
+
+    /**
+     * Tests the lower 3 bits of the op3 field.
+     */
+    private static class OP3LowBitsMatcher extends SPARCInstructionMatch {
+        private final int[] op3b03;
+        private final int op;
+
+        public OP3LowBitsMatcher(int op, int... op3b03) {
+            super(0, 0);
+            this.op = op;
+            this.op3b03 = op3b03;
+        }
+
+        @Override
+        public boolean matches(int instruction) {
+            if (instruction >>> 30 != op) {
+                return false;
+            }
+            int op3lo = (instruction >> 19) & ((1 << 4) - 1);
+            for (int op3Part : op3b03) {
+                if (op3Part == op3lo) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
+    private static class SPARCInstructionMatch {
+        private final int mask;
+        private final int[] patterns;
+
+        public SPARCInstructionMatch(int mask, int... patterns) {
+            super();
+            this.mask = mask;
+            this.patterns = patterns;
+        }
+
+        public boolean matches(int instruction) {
+            for (int pattern : patterns) {
+                if ((instruction & mask) == pattern) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+}
--- a/graal/com.oracle.graal.asm/src/com/oracle/graal/asm/Assembler.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.asm/src/com/oracle/graal/asm/Assembler.java	Fri Mar 27 17:02:53 2015 +0100
@@ -213,6 +213,10 @@
         return hint;
     }
 
+    public InstructionCounter getInstructionCounter() {
+        throw new UnsupportedOperationException("Instruction counter is not implemented for " + this);
+    }
+
     public static class LabelHint {
         private Label label;
         private int forPosition;
@@ -242,4 +246,14 @@
             return capturedTarget >= 0;
         }
     }
+
+    /**
+     * Instruction counter class which gives the user of the assembler to count different kinds of
+     * instructions in the generated assembler code.
+     */
+    public interface InstructionCounter {
+        String[] getSupportedInstructionTypes();
+
+        int[] countInstructions(String[] instructionTypes, int beginPc, int endPc);
+    }
 }
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/UnsafeAccess.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/UnsafeAccess.java	Fri Mar 27 17:02:53 2015 +0100
@@ -65,7 +65,7 @@
         if (address == 0) {
             return null;
         }
-        StringBuffer sb = new StringBuffer();
+        StringBuilder sb = new StringBuilder();
         for (int i = 0;; i++) {
             char c = (char) unsafe.getByte(address + i);
             if (c == 0) {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Fri Mar 27 17:02:53 2015 +0100
@@ -320,7 +320,14 @@
                 throw Debug.handle(e);
             }
             FrameMapBuilder frameMapBuilder = backend.newFrameMapBuilder(registerConfig);
-            LIRGenerationResult lirGenRes = backend.newLIRGenerationResult(lir, frameMapBuilder, graph.method(), stub);
+            String compilationUnitName;
+            ResolvedJavaMethod method = graph.method();
+            if (method == null) {
+                compilationUnitName = "<unknown>";
+            } else {
+                compilationUnitName = method.format("%H.%n(%p)");
+            }
+            LIRGenerationResult lirGenRes = backend.newLIRGenerationResult(compilationUnitName, lir, frameMapBuilder, graph.method(), stub);
             LIRGeneratorTool lirGen = backend.newLIRGenerator(cc, lirGenRes);
             NodeLIRBuilderTool nodeLirGen = backend.newNodeLIRBuilder(graph, lirGen);
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalDebugConfig.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalDebugConfig.java	Fri Mar 27 17:02:53 2015 +0100
@@ -40,13 +40,16 @@
     // @formatter:off
     @Option(help = "Pattern for scope(s) in which dumping is enabled (see DebugFilter and Debug.dump)", type = OptionType.Debug)
     public static final OptionValue<String> Dump = new OptionValue<>(null);
-    @Option(help = "Pattern for scope(s) in which metering is enabled (see DebugFilter and Debug.metric)", type = OptionType.Debug)
+    @Option(help = "Pattern for scope(s) in which metering is enabled (see DebugFilter and Debug.metric). " +
+                   "An empty value enables all metrics unconditionally.", type = OptionType.Debug)
     public static final OptionValue<String> Meter = new OptionValue<>(null);
-    @Option(help = "Pattern for scope(s) in which verification is enabled (see DebugFilter and Debug.verify)", type = OptionType.Debug)
+    @Option(help = "Pattern for scope(s) in which verification is enabled (see DebugFilter and Debug.verify).", type = OptionType.Debug)
     public static final OptionValue<String> Verify = new OptionValue<>(null);
-    @Option(help = "Pattern for scope(s) in which memory use tracking is enabled (see DebugFilter and Debug.metric)", type = OptionType.Debug)
+    @Option(help = "Pattern for scope(s) in which memory use tracking is enabled (see DebugFilter and Debug.metric). " +
+                   "An empty value enables all memory use trackers unconditionally.", type = OptionType.Debug)
     public static final OptionValue<String> TrackMemUse = new OptionValue<>(null);
-    @Option(help = "Pattern for scope(s) in which timing is enabled (see DebugFilter and Debug.timer)", type = OptionType.Debug)
+    @Option(help = "Pattern for scope(s) in which timing is enabled (see DebugFilter and Debug.timer). " +
+                   "An empty value enables all timers unconditionally.", type = OptionType.Debug)
     public static final OptionValue<String> Time = new OptionValue<>(null);
     @Option(help = "Pattern for scope(s) in which logging is enabled (see DebugFilter and Debug.log)", type = OptionType.Debug)
     public static final OptionValue<String> Log = new OptionValue<>(null);
@@ -63,6 +66,8 @@
     public static final OptionValue<String> DebugValueSummary = new OptionValue<>("Name");
     @Option(help = "Omit reporting 0-value metrics", type = OptionType.Debug)
     public static final OptionValue<Boolean> SuppressZeroDebugValues = new OptionValue<>(true);
+    @Option(help = "Only report debug values for maps which match the regular expression.", type = OptionType.Debug)
+    public static final OptionValue<String> DebugValueThreadFilter = new OptionValue<>(null);
     @Option(help = "Send Graal IR to dump handlers on error", type = OptionType.Debug)
     public static final OptionValue<Boolean> DumpOnError = new OptionValue<>(false);
     @Option(help = "Intercept also bailout exceptions", type = OptionType.Debug)
@@ -71,12 +76,20 @@
     public static final OptionValue<Boolean> LogVerbose = new OptionValue<>(false);
     // @formatter:on
 
-    public static boolean areDebugScopePatternsEnabled() {
-        return DumpOnError.getValue() || Dump.getValue() != null || Log.getValue() != null || areMetricsOrTimersEnabled();
+    public static boolean isNotEmpty(OptionValue<String> option) {
+        return option.getValue() != null && !option.getValue().isEmpty();
     }
 
-    public static boolean areMetricsOrTimersEnabled() {
-        return Meter.getValue() != null || Time.getValue() != null || TrackMemUse.getValue() != null;
+    public static boolean areDebugScopePatternsEnabled() {
+        return DumpOnError.getValue() || Dump.getValue() != null || Log.getValue() != null || areScopedMetricsOrTimersEnabled();
+    }
+
+    /**
+     * Determines if any of {@link #Meter}, {@link #Time} or {@link #TrackMemUse} has a non-null,
+     * non-empty value.
+     */
+    public static boolean areScopedMetricsOrTimersEnabled() {
+        return isNotEmpty(Meter) || isNotEmpty(Time) || isNotEmpty(TrackMemUse);
     }
 
     private final DebugFilter logFilter;
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/MethodFilter.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/MethodFilter.java	Fri Mar 27 17:02:53 2015 +0100
@@ -121,6 +121,18 @@
         return false;
     }
 
+    /**
+     * Determines if a given class name is matched by a given array of filters.
+     */
+    public static boolean matchesClassName(MethodFilter[] filters, String className) {
+        for (MethodFilter filter : filters) {
+            if (filter.matchesClassName(className)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     public MethodFilter(String sourcePattern) {
         String pattern = sourcePattern.trim();
 
@@ -162,7 +174,7 @@
         } else if (pattern.contains(".")) {
             return Pattern.compile(createGlobString(pattern));
         } else {
-            return Pattern.compile("([^\\.]*\\.)*" + createGlobString(pattern));
+            return Pattern.compile("([^\\.\\$]*[\\.\\$])*" + createGlobString(pattern));
         }
     }
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java	Fri Mar 27 17:02:53 2015 +0100
@@ -78,7 +78,7 @@
 
     public abstract LIRGeneratorTool newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes);
 
-    public abstract LIRGenerationResult newLIRGenerationResult(LIR lir, FrameMapBuilder frameMapBuilder, ResolvedJavaMethod method, Object stub);
+    public abstract LIRGenerationResult newLIRGenerationResult(String compilationUnitName, LIR lir, FrameMapBuilder frameMapBuilder, ResolvedJavaMethod method, Object stub);
 
     public abstract NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen);
 
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java	Fri Mar 27 17:02:53 2015 +0100
@@ -853,7 +853,7 @@
      * A disabled tracker has virtually no overhead.
      */
     public static DebugMemUseTracker memUseTracker(CharSequence name) {
-        if (!ENABLED) {
+        if (!isUnconditionalMemUseTrackingEnabled && !ENABLED) {
             return VOID_MEM_USE_TRACKER;
         }
         return createMemUseTracker("%s", name, null);
@@ -871,7 +871,7 @@
      * @see #metric(String, Object, Object)
      */
     public static DebugMemUseTracker memUseTracker(String format, Object arg) {
-        if (!ENABLED) {
+        if (!isUnconditionalMemUseTrackingEnabled && !ENABLED) {
             return VOID_MEM_USE_TRACKER;
         }
         return createMemUseTracker(format, arg, null);
@@ -898,7 +898,7 @@
      * @see #memUseTracker(CharSequence)
      */
     public static DebugMemUseTracker memUseTracker(String format, Object arg1, Object arg2) {
-        if (!ENABLED) {
+        if (!isUnconditionalMemUseTrackingEnabled && !ENABLED) {
             return VOID_MEM_USE_TRACKER;
         }
         return createMemUseTracker(format, arg1, arg2);
@@ -906,7 +906,7 @@
 
     private static DebugMemUseTracker createMemUseTracker(String format, Object arg1, Object arg2) {
         String name = formatDebugName(format, arg1, arg2);
-        return new MemUseTrackerImpl(name);
+        return new MemUseTrackerImpl(name, !isUnconditionalMemUseTrackingEnabled);
     }
 
     /**
@@ -920,7 +920,7 @@
      * A disabled metric has virtually no overhead.
      */
     public static DebugMetric metric(CharSequence name) {
-        if (enabledMetrics == null && !ENABLED) {
+        if (!areUnconditionalMetricsEnabled() && !ENABLED) {
             return VOID_METRIC;
         }
         return createMetric("%s", name, null);
@@ -963,7 +963,7 @@
      * @see #metric(String, Object, Object)
      */
     public static DebugMetric metric(String format, Object arg) {
-        if (enabledMetrics == null && !ENABLED) {
+        if (!areUnconditionalMetricsEnabled() && !ENABLED) {
             return VOID_METRIC;
         }
         return createMetric(format, arg, null);
@@ -990,7 +990,7 @@
      * @see #metric(CharSequence)
      */
     public static DebugMetric metric(String format, Object arg1, Object arg2) {
-        if (enabledMetrics == null && !ENABLED) {
+        if (!areUnconditionalMetricsEnabled() && !ENABLED) {
             return VOID_METRIC;
         }
         return createMetric(format, arg1, arg2);
@@ -1140,6 +1140,10 @@
         }
     };
 
+    public static final String ENABLE_UNSCOPED_TIMERS_PROPERTY_NAME = "graal.debug.unscopedTimers";
+    public static final String ENABLE_UNSCOPED_METRICS_PROPERTY_NAME = "graal.debug.unscopedMetrics";
+    public static final String ENABLE_UNSCOPED_MEM_USE_TRACKERS_PROPERTY_NAME = "graal.debug.unscopedMemUseTrackers";
+
     /**
      * @see #timer(CharSequence)
      */
@@ -1150,20 +1154,53 @@
      */
     public static final String ENABLE_METRIC_PROPERTY_NAME_PREFIX = "graal.debug.metric.";
 
+    /**
+     * Set of unconditionally enabled metrics. Possible values and their meanings:
+     * <ul>
+     * <li>{@code null}: no unconditionally enabled metrics</li>
+     * <li>{@code isEmpty()}: all metrics are unconditionally enabled</li>
+     * <li>{@code !isEmpty()}: use {@link #findMatch(Set, Set, String)} on this set and
+     * {@link #enabledMetricsSubstrings} to determine which metrics are unconditionally enabled</li>
+     * </ul>
+     */
     private static final Set<String> enabledMetrics;
+
+    /**
+     * Set of unconditionally enabled timers. Same interpretation of values as for
+     * {@link #enabledMetrics}.
+     */
     private static final Set<String> enabledTimers;
+
     private static final Set<String> enabledMetricsSubstrings = new HashSet<>();
     private static final Set<String> enabledTimersSubstrings = new HashSet<>();
 
+    /**
+     * Specifies if all mem use trackers are unconditionally enabled.
+     */
+    private static final boolean isUnconditionalMemUseTrackingEnabled;
+
     static {
         Set<String> metrics = new HashSet<>();
         Set<String> timers = new HashSet<>();
         parseMetricAndTimerSystemProperties(metrics, timers, enabledMetricsSubstrings, enabledTimersSubstrings);
-        enabledMetrics = metrics.isEmpty() && enabledMetricsSubstrings.isEmpty() ? null : metrics;
-        enabledTimers = timers.isEmpty() && enabledTimersSubstrings.isEmpty() ? null : timers;
+        metrics = metrics.isEmpty() && enabledMetricsSubstrings.isEmpty() ? null : metrics;
+        timers = timers.isEmpty() && enabledTimersSubstrings.isEmpty() ? null : timers;
+        if (metrics == null && Boolean.getBoolean(ENABLE_UNSCOPED_METRICS_PROPERTY_NAME)) {
+            metrics = Collections.emptySet();
+        }
+        if (timers == null && Boolean.getBoolean(ENABLE_UNSCOPED_TIMERS_PROPERTY_NAME)) {
+            timers = Collections.emptySet();
+        }
+        enabledMetrics = metrics;
+        enabledTimers = timers;
+        isUnconditionalMemUseTrackingEnabled = Boolean.getBoolean(ENABLE_UNSCOPED_MEM_USE_TRACKERS_PROPERTY_NAME);
     }
 
     private static boolean findMatch(Set<String> haystack, Set<String> haystackSubstrings, String needle) {
+        if (haystack.isEmpty()) {
+            // Empty haystack means match all
+            return true;
+        }
         if (haystack.contains(needle)) {
             return true;
         }
@@ -1224,7 +1261,7 @@
      * A disabled timer has virtually no overhead.
      */
     public static DebugTimer timer(CharSequence name) {
-        if (enabledTimers == null && !ENABLED) {
+        if (!areUnconditionalTimersEnabled() && !ENABLED) {
             return VOID_TIMER;
         }
         return createTimer("%s", name, null);
@@ -1242,7 +1279,7 @@
      * @see #timer(String, Object, Object)
      */
     public static DebugTimer timer(String format, Object arg) {
-        if (enabledTimers == null && !ENABLED) {
+        if (!areUnconditionalTimersEnabled() && !ENABLED) {
             return VOID_TIMER;
         }
         return createTimer(format, arg, null);
@@ -1269,7 +1306,7 @@
      * @see #timer(CharSequence)
      */
     public static DebugTimer timer(String format, Object arg1, Object arg2) {
-        if (enabledTimers == null && !ENABLED) {
+        if (!areUnconditionalTimersEnabled() && !ENABLED) {
             return VOID_TIMER;
         }
         return createTimer(format, arg1, arg2);
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/MemUseTrackerImpl.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/MemUseTrackerImpl.java	Fri Mar 27 17:02:53 2015 +0100
@@ -48,8 +48,8 @@
      */
     private static final ThreadLocal<CloseableCounterImpl> currentTracker = new ThreadLocal<>();
 
-    public MemUseTrackerImpl(String name) {
-        super(name, true, new DebugValue(name + "_Flat", true) {
+    public MemUseTrackerImpl(String name, boolean conditional) {
+        super(name, conditional, new DebugValue(name + "_Flat", conditional) {
 
             @Override
             public String toString(long value) {
--- a/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/test/matchers/NodeIterableContains.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/test/matchers/NodeIterableContains.java	Fri Mar 27 17:02:53 2015 +0100
@@ -35,19 +35,16 @@
     }
 
     public void describeTo(Description description) {
-        description.appendText("is a NodeIterable containing").appendValue(node);
+        description.appendText("is a NodeIterable containing ").appendValue(node);
     }
 
     public static <T extends Node> NodeIterableContains<T> contains(T node) {
         return new NodeIterableContains<>(node);
     }
 
-    public static <T extends Node> NodeIterableContains<T> d(T node) {
-        return new NodeIterableContains<>(node);
-    }
-
     @Override
-    protected boolean matchesSafely(NodeIterable<T> iterable, Description description) {
+    protected boolean matchesSafely(NodeIterable<T> iterable, Description mismatchDescription) {
+        mismatchDescription.appendText("is a NodeIterable that does not contain ").appendValue(node);
         return iterable.contains(node);
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/test/matchers/NodeIterableCount.java	Fri Mar 27 17:02:53 2015 +0100
@@ -0,0 +1,50 @@
+/*
+ * 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.graph.test.matchers;
+
+import org.hamcrest.*;
+
+import com.oracle.graal.graph.iterators.*;
+
+public class NodeIterableCount extends TypeSafeDiagnosingMatcher<NodeIterable<?>> {
+    private int count;
+
+    public NodeIterableCount(int count) {
+        this.count = count;
+    }
+
+    @Override
+    public void describeTo(Description description) {
+        description.appendText("is a NodeIterable containing ").appendValue(count).appendText(" elements");
+    }
+
+    public static NodeIterableCount hasCount(int count) {
+        return new NodeIterableCount(count);
+    }
+
+    @Override
+    protected boolean matchesSafely(NodeIterable<?> iterable, Description mismatchDescription) {
+        mismatchDescription.appendText("is a NodeIterable containing ").appendValue(iterable.count()).appendText(" elements");
+        return iterable.count() == count;
+    }
+}
--- a/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/test/matchers/NodeIterableIsEmpty.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/test/matchers/NodeIterableIsEmpty.java	Fri Mar 27 17:02:53 2015 +0100
@@ -27,12 +27,14 @@
 
 import com.oracle.graal.graph.iterators.*;
 
-public class NodeIterableIsEmpty extends BaseMatcher<NodeIterable<?>> {
+public class NodeIterableIsEmpty extends TypeSafeDiagnosingMatcher<NodeIterable<?>> {
 
     private static final NodeIterableIsEmpty INSTANCE = new NodeIterableIsEmpty();
 
-    public boolean matches(Object iterable) {
-        return iterable instanceof NodeIterable<?> && ((NodeIterable<?>) iterable).isEmpty();
+    @Override
+    public boolean matchesSafely(NodeIterable<?> iterable, Description mismatchDescription) {
+        mismatchDescription.appendText("is a non-empty NodeIterable");
+        return iterable.isEmpty();
     }
 
     public void describeTo(Description description) {
--- a/graal/com.oracle.graal.graph/.checkstyle_checks.xml	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.graph/.checkstyle_checks.xml	Fri Mar 27 17:02:53 2015 +0100
@@ -122,9 +122,13 @@
       <property name="format" value=" ,"/>
       <property name="message" value="illegal space before a comma"/>
       <property name="ignoreComments" value="true"/>
+      <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Checks for whitespace before a comma."/>
       <metadata name="com.atlassw.tools.eclipse.checkstyle.customMessage" value="Illegal whitespace before a comma."/>
-      <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Checks for whitespace before a comma."/>
     </module>
+    <module name="RegexpSinglelineJava">
+      <property name="format" value="new (Hashtable|Vector|Stack|StringBuffer)[^\w]"/>
+      <property name="message" value="Don't use old synchronized collection classes"/>
+    </module>    
   </module>
   <module name="RegexpHeader">
     <property name="header" value="/\*\n \* Copyright \(c\) (20[0-9][0-9], )?20[0-9][0-9], Oracle and/or its affiliates. All rights reserved.\n \* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n \*\n \* This code is free software; you can redistribute it and/or modify it\n \* under the terms of the GNU General Public License version 2 only, as\n \* published by the Free Software Foundation.\n \*\n \* This code is distributed in the hope that it will be useful, but WITHOUT\n \* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n \* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n \* version 2 for more details \(a copy is included in the LICENSE file that\n \* accompanied this code\).\n \*\n \* You should have received a copy of the GNU General Public License version\n \* 2 along with this work; if not, write to the Free Software Foundation,\n \* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n \*\n \* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n \* or visit www.oracle.com if you need additional information or have any\n \* questions.\n \*/\n"/>
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderContext.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderContext.java	Fri Mar 27 17:02:53 2015 +0100
@@ -25,6 +25,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 
@@ -59,16 +60,101 @@
         boolean isIntrinsic();
     }
 
+    /**
+     * Raw operation for adding a node to the graph when neither {@link #add},
+     * {@link #addPush(ValueNode)} nor {@link #addPush(Kind, ValueNode)} can be used.
+     *
+     * @return either the node added or an equivalent node
+     */
     <T extends ValueNode> T append(T value);
 
     /**
-     * Adds the given floating node to the graph and also adds recursively all referenced inputs.
+     * Adds the given node to the graph and also adds recursively all referenced inputs.
      *
-     * @param value the floating node to be added to the graph
+     * @param value the node to be added to the graph
      * @return either the node added or an equivalent node
      */
     <T extends ValueNode> T recursiveAppend(T value);
 
+    /**
+     * Pushes a given value to the frame state stack using an explicit kind. This should be used
+     * when {@code value.getKind()} is different from the kind that the bytecode instruction
+     * currently being parsed pushes to the stack.
+     *
+     * @param kind the kind to use when type checking this operation
+     * @param value the value to push to the stack. The value must already have been
+     *            {@linkplain #append(ValueNode) appended}.
+     */
+    void push(Kind kind, ValueNode value);
+
+    /**
+     * Adds a node to the graph. If the returned node is a {@link StateSplit} with a null
+     * {@linkplain StateSplit#stateAfter() frame state}, the frame state is initialized.
+     *
+     * @param value the value to add to the graph and push to the stack. The {@code value.getKind()}
+     *            kind is used when type checking this operation.
+     * @return a node equivalent to {@code value} in the graph
+     */
+    default <T extends ValueNode> T add(T value) {
+        if (value.graph() != null) {
+            assert !(value instanceof StateSplit) || ((StateSplit) value).stateAfter() != null;
+            return value;
+        }
+        T equivalentValue = append(value);
+        if (equivalentValue instanceof StateSplit) {
+            StateSplit stateSplit = (StateSplit) equivalentValue;
+            if (stateSplit.stateAfter() == null) {
+                stateSplit.setStateAfter(createStateAfter());
+            }
+        }
+        return equivalentValue;
+    }
+
+    /**
+     * Adds a node with a non-void kind to the graph, pushes it to the stack. If the returned node
+     * is a {@link StateSplit} with a null {@linkplain StateSplit#stateAfter() frame state}, the
+     * frame state is initialized.
+     *
+     * @param value the value to add to the graph and push to the stack. The {@code value.getKind()}
+     *            kind is used when type checking this operation.
+     * @return a node equivalent to {@code value} in the graph
+     */
+    default <T extends ValueNode> T addPush(T value) {
+        return addPush(value.getKind().getStackKind(), value);
+    }
+
+    /**
+     * Adds a node with a non-void kind to the graph, pushes it to the stack. If the returned node
+     * is a {@link StateSplit} with a null {@linkplain StateSplit#stateAfter() frame state}, the
+     * frame state is initialized.
+     *
+     * @param kind the kind to use when type checking this operation
+     * @param value the value to add to the graph and push to the stack
+     * @return a node equivalent to {@code value} in the graph
+     */
+    default <T extends ValueNode> T addPush(Kind kind, T value) {
+        T equivalentValue = value.graph() != null ? value : append(value);
+        push(kind.getStackKind(), equivalentValue);
+        if (equivalentValue instanceof StateSplit) {
+            StateSplit stateSplit = (StateSplit) equivalentValue;
+            if (stateSplit.stateAfter() == null) {
+                stateSplit.setStateAfter(createStateAfter());
+            }
+        }
+        return equivalentValue;
+    }
+
+    /**
+     * Handles an invocation that a plugin determines can replace the original invocation (i.e., the
+     * one for which the plugin was applied). This applies all standard graph builder processing to
+     * the replaced invocation including applying any relevant plugins to it.
+     *
+     * @param invokeKind the kind of the replacement invocation
+     * @param targetMethod the target of the replacement invocation
+     * @param args the arguments to the replacement invocation
+     */
+    void handleReplacedInvoke(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args);
+
     StampProvider getStampProvider();
 
     MetaAccessProvider getMetaAccess();
@@ -79,10 +165,12 @@
 
     SnippetReflectionProvider getSnippetReflection();
 
-    void push(Kind kind, ValueNode value);
-
     StructuredGraph getGraph();
 
+    /**
+     * Creates a snap shot of the current frame state with the BCI of the instruction after the one
+     * currently being parsed.
+     */
     FrameState createStateAfter();
 
     /**
@@ -106,6 +194,16 @@
     int bci();
 
     /**
+     * Gets the kind of invocation currently being parsed.
+     */
+    InvokeKind getInvokeKind();
+
+    /**
+     * Gets the return type of the invocation currently being parsed.
+     */
+    JavaType getInvokeReturnType();
+
+    /**
      * Gets the inline depth of this context. 0 implies this is the context for the
      * {@linkplain #getRootMethod() root method}.
      */
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugin.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugin.java	Fri Mar 27 17:02:53 2015 +0100
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.graphbuilderconf;
 
+import java.lang.invoke.*;
 import java.lang.reflect.*;
 
 import com.oracle.graal.api.meta.*;
@@ -35,45 +36,65 @@
 public interface InvocationPlugin extends GraphBuilderPlugin {
 
     /**
+     * Determines if this plugin is for a method with a polymorphic signature (e.g.
+     * {@link MethodHandle#invokeExact(Object...)}).
+     */
+    default boolean isSignaturePolymorphic() {
+        return false;
+    }
+
+    /**
+     * Handles invocation of a signature polymorphic method.
+     *
+     * @param receiver access to the receiver, {@code null} if {@code targetMethod} is static
+     * @param argsIncludingReceiver all arguments to the invocation include the raw receiver in
+     *            position 0 if {@code targetMethod} is not static
+     * @see #execute
+     */
+    default boolean applyPolymorphic(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode... argsIncludingReceiver) {
+        return defaultHandler(b, targetMethod, receiver, argsIncludingReceiver);
+    }
+
+    /**
      * @see #execute
      */
     default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
-        throw invalidHandler(b, targetMethod, receiver);
+        return defaultHandler(b, targetMethod, receiver);
     }
 
     /**
      * @see #execute
      */
     default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) {
-        throw invalidHandler(b, targetMethod, receiver, arg);
+        return defaultHandler(b, targetMethod, receiver, arg);
     }
 
     /**
      * @see #execute
      */
     default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg1, ValueNode arg2) {
-        throw invalidHandler(b, targetMethod, receiver, arg1, arg2);
+        return defaultHandler(b, targetMethod, receiver, arg1, arg2);
     }
 
     /**
      * @see #execute
      */
     default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg1, ValueNode arg2, ValueNode arg3) {
-        throw invalidHandler(b, targetMethod, receiver, arg1, arg2, arg3);
+        return defaultHandler(b, targetMethod, receiver, arg1, arg2, arg3);
     }
 
     /**
      * @see #execute
      */
     default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4) {
-        throw invalidHandler(b, targetMethod, receiver, arg1, arg2, arg3, arg4);
+        return defaultHandler(b, targetMethod, receiver, arg1, arg2, arg3, arg4);
     }
 
     /**
      * @see #execute
      */
     default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4, ValueNode arg5) {
-        throw invalidHandler(b, targetMethod, receiver, arg1, arg2, arg3, arg4, arg5);
+        return defaultHandler(b, targetMethod, receiver, arg1, arg2, arg3, arg4, arg5);
     }
 
     default ResolvedJavaMethod getSubstitute() {
@@ -82,56 +103,64 @@
 
     /**
      * Executes a given plugin against a set of invocation arguments by dispatching to the
-     * {@code apply(...)} method that matches the number of arguments.
+     * {@code apply(...)} method that matches the number of arguments or to
+     * {@link #applyPolymorphic} if {@code plugin} is {@linkplain #isSignaturePolymorphic()
+     * signature polymorphic}.
      *
      * @param targetMethod the method for which plugin is being applied
      * @param receiver access to the receiver, {@code null} if {@code targetMethod} is static
-     * @param args the remaining arguments
+     * @param argsIncludingReceiver all arguments to the invocation include the receiver in position
+     *            0 if {@code targetMethod} is not static
      * @return {@code true} if the plugin handled the invocation of {@code targetMethod}
      *         {@code false} if the graph builder should process the invoke further (e.g., by
      *         inlining it or creating an {@link Invoke} node). A plugin that does not handle an
      *         invocation must not modify the graph being constructed.
      */
-    static boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin plugin, Receiver receiver, ValueNode[] args) {
-        if (receiver != null) {
+    static boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin plugin, Receiver receiver, ValueNode[] argsIncludingReceiver) {
+        if (plugin.isSignaturePolymorphic()) {
+            return plugin.applyPolymorphic(b, targetMethod, receiver, argsIncludingReceiver);
+        } else if (receiver != null) {
             assert !targetMethod.isStatic();
-            assert args.length > 0;
-            if (args.length == 1) {
+            assert argsIncludingReceiver.length > 0;
+            if (argsIncludingReceiver.length == 1) {
                 return plugin.apply(b, targetMethod, receiver);
-            } else if (args.length == 2) {
-                return plugin.apply(b, targetMethod, receiver, args[1]);
-            } else if (args.length == 3) {
-                return plugin.apply(b, targetMethod, receiver, args[1], args[2]);
-            } else if (args.length == 4) {
-                return plugin.apply(b, targetMethod, receiver, args[1], args[2], args[3]);
-            } else if (args.length == 5) {
-                return plugin.apply(b, targetMethod, receiver, args[1], args[2], args[3], args[4]);
+            } else if (argsIncludingReceiver.length == 2) {
+                return plugin.apply(b, targetMethod, receiver, argsIncludingReceiver[1]);
+            } else if (argsIncludingReceiver.length == 3) {
+                return plugin.apply(b, targetMethod, receiver, argsIncludingReceiver[1], argsIncludingReceiver[2]);
+            } else if (argsIncludingReceiver.length == 4) {
+                return plugin.apply(b, targetMethod, receiver, argsIncludingReceiver[1], argsIncludingReceiver[2], argsIncludingReceiver[3]);
+            } else if (argsIncludingReceiver.length == 5) {
+                return plugin.apply(b, targetMethod, receiver, argsIncludingReceiver[1], argsIncludingReceiver[2], argsIncludingReceiver[3], argsIncludingReceiver[4]);
             } else {
-                throw plugin.invalidHandler(b, targetMethod, receiver, args);
+                return plugin.defaultHandler(b, targetMethod, receiver, argsIncludingReceiver);
             }
         } else {
             assert targetMethod.isStatic();
-            if (args.length == 0) {
+            if (argsIncludingReceiver.length == 0) {
                 return plugin.apply(b, targetMethod, null);
-            } else if (args.length == 1) {
-                return plugin.apply(b, targetMethod, null, args[0]);
-            } else if (args.length == 2) {
-                return plugin.apply(b, targetMethod, null, args[0], args[1]);
-            } else if (args.length == 3) {
-                return plugin.apply(b, targetMethod, null, args[0], args[1], args[2]);
-            } else if (args.length == 4) {
-                return plugin.apply(b, targetMethod, null, args[0], args[1], args[2], args[3]);
-            } else if (args.length == 5) {
-                return plugin.apply(b, targetMethod, null, args[0], args[1], args[2], args[3], args[4]);
+            } else if (argsIncludingReceiver.length == 1) {
+                return plugin.apply(b, targetMethod, null, argsIncludingReceiver[0]);
+            } else if (argsIncludingReceiver.length == 2) {
+                return plugin.apply(b, targetMethod, null, argsIncludingReceiver[0], argsIncludingReceiver[1]);
+            } else if (argsIncludingReceiver.length == 3) {
+                return plugin.apply(b, targetMethod, null, argsIncludingReceiver[0], argsIncludingReceiver[1], argsIncludingReceiver[2]);
+            } else if (argsIncludingReceiver.length == 4) {
+                return plugin.apply(b, targetMethod, null, argsIncludingReceiver[0], argsIncludingReceiver[1], argsIncludingReceiver[2], argsIncludingReceiver[3]);
+            } else if (argsIncludingReceiver.length == 5) {
+                return plugin.apply(b, targetMethod, null, argsIncludingReceiver[0], argsIncludingReceiver[1], argsIncludingReceiver[2], argsIncludingReceiver[3], argsIncludingReceiver[4]);
             } else {
-                throw plugin.invalidHandler(b, targetMethod, receiver, args);
+                return plugin.defaultHandler(b, targetMethod, receiver, argsIncludingReceiver);
             }
 
         }
     }
 
-    default Error invalidHandler(@SuppressWarnings("unused") GraphBuilderContext b, ResolvedJavaMethod targetMethod, @SuppressWarnings("unused") Receiver receiver, ValueNode... args) {
-        return new GraalInternalError("Invocation plugin for %s does not handle invocations with %d arguments", targetMethod.format("%H.%n(%p)"), args.length);
+    /**
+     * Handles an invocation when a specific {@code apply} method is not available.
+     */
+    default boolean defaultHandler(@SuppressWarnings("unused") GraphBuilderContext b, ResolvedJavaMethod targetMethod, @SuppressWarnings("unused") Receiver receiver, ValueNode... args) {
+        throw new GraalInternalError("Invocation plugin for %s does not handle invocations with %d arguments", targetMethod.format("%H.%n(%p)"), args.length);
     }
 
     default StackTraceElement getApplySourceLocation(MetaAccessProvider metaAccess) {
@@ -139,8 +168,10 @@
         for (Method m : c.getDeclaredMethods()) {
             if (m.getName().equals("apply")) {
                 return metaAccess.lookupJavaMethod(m).asStackTraceElement(0);
+            } else if (m.getName().equals("defaultHandler")) {
+                return metaAccess.lookupJavaMethod(m).asStackTraceElement(0);
             }
         }
-        throw new GraalInternalError("could not find method named \"apply\" in " + c.getName());
+        throw new GraalInternalError("could not find method named \"apply\" or \"defaultHandler\" in " + c.getName());
     }
 }
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/LoadFieldPlugin.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/LoadFieldPlugin.java	Fri Mar 27 17:02:53 2015 +0100
@@ -39,8 +39,8 @@
     default boolean tryConstantFold(GraphBuilderContext b, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ResolvedJavaField field, JavaConstant receiver) {
         JavaConstant result = constantReflection.readConstantFieldValue(field, receiver);
         if (result != null) {
-            ConstantNode constantNode = b.append(ConstantNode.forConstant(result, metaAccess));
-            b.push(constantNode.getKind().getStackKind(), constantNode);
+            ConstantNode constantNode = ConstantNode.forConstant(result, metaAccess);
+            b.addPush(constantNode.getKind().getStackKind(), constantNode);
             return true;
         }
         return false;
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Fri Mar 27 17:02:53 2015 +0100
@@ -78,8 +78,8 @@
     }
 
     @Override
-    public LIRGenerationResult newLIRGenerationResult(LIR lir, FrameMapBuilder frameMapBuilder, ResolvedJavaMethod method, Object stub) {
-        return new AMD64HotSpotLIRGenerationResult(lir, frameMapBuilder, stub);
+    public LIRGenerationResult newLIRGenerationResult(String compilationUnitName, LIR lir, FrameMapBuilder frameMapBuilder, ResolvedJavaMethod method, Object stub) {
+        return new AMD64HotSpotLIRGenerationResult(compilationUnitName, lir, frameMapBuilder, stub);
     }
 
     @Override
@@ -254,6 +254,9 @@
 
         // Emit the suffix
         emitCodeSuffix(installedCodeOwner, crb, asm, frameMap);
+
+        // Profile assembler instructions
+        profileInstructions(lir, crb);
     }
 
     /**
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCounterOp.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCounterOp.java	Fri Mar 27 17:02:53 2015 +0100
@@ -24,6 +24,11 @@
 
 import static com.oracle.graal.amd64.AMD64.*;
 import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.asm.NumUtil.*;
+import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.*;
+import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MOp.*;
+import static com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize.*;
+import static com.oracle.graal.compiler.common.GraalInternalError.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
@@ -54,7 +59,19 @@
         AMD64MacroAssembler masm = (AMD64MacroAssembler) crb.asm;
         TargetDescription target = crb.target;
 
-        Register scratch = rax;
+        Register scratch;
+        // It can happen that the rax register is the increment register, in this case we do not
+        // want to spill it to the stack.
+        if (!contains(increments, rax)) {
+            scratch = rax;
+        } else if (!contains(increments, rbx)) {
+            scratch = rbx;
+        } else {
+            // In this case rax and rbx are used as increment. Either we implement a third register
+            // or we implement a spillover the value from rax to rbx or vice versa during
+            // emitIncrement().
+            throw unimplemented("RAX and RBX are increment registers a the same time, spilling over the scratch register is not supported right now");
+        }
 
         // address for counters array
         AMD64Address countersArrayAddr = new AMD64Address(thread, config.graalCountersThreadOffset);
@@ -65,21 +82,39 @@
 
         // load counters array
         masm.movptr(countersArrayReg, countersArrayAddr);
-
-        forEachCounter((name, group, increment) -> emitIncrement(masm, target, countersArrayReg, name, group, increment));
+        CounterProcedure emitProcedure = (counterIndex, increment, displacement) -> emitIncrement(masm, countersArrayReg, increment, displacement);
+        forEachCounter(emitProcedure, target);
 
         // restore scratch register
         masm.movq(scratch, (AMD64Address) crb.asAddress(backupSlot));
     }
 
-    private void emitIncrement(AMD64MacroAssembler masm, TargetDescription target, Register countersArrayReg, String name, String group, Value increment) {
+    /**
+     * Tests if the array contains the register.
+     */
+    private static boolean contains(Value[] increments, Register register) {
+        for (Value increment : increments) {
+            if (isRegister(increment) && asRegister(increment).equals(register)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static void emitIncrement(AMD64MacroAssembler masm, Register countersArrayReg, Value incrementValue, int displacement) {
         // address for counter value
-        AMD64Address counterAddr = new AMD64Address(countersArrayReg, getDisplacementForLongIndex(target, getIndex(name, group, increment)));
+        AMD64Address counterAddr = new AMD64Address(countersArrayReg, displacement);
         // increment counter (in memory)
-        if (isConstant(increment)) {
-            masm.incrementl(counterAddr, asInt(asConstant(increment)));
+        if (isConstant(incrementValue)) {
+            int increment = asInt(asConstant(incrementValue));
+            if (increment == 1) {
+                INC.emit(masm, QWORD, counterAddr);
+            } else {
+                ADD.getMIOpcode(QWORD, isByte(increment)).emit(masm, QWORD, counterAddr, increment);
+            }
         } else {
-            masm.addq(counterAddr, asRegister(increment));
+            masm.addq(counterAddr, asRegister(incrementValue));
         }
+
     }
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerationResult.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerationResult.java	Fri Mar 27 17:02:53 2015 +0100
@@ -48,8 +48,8 @@
      */
     private Map<LIRFrameState, SaveRegistersOp> calleeSaveInfo = CollectionsFactory.newMap();
 
-    public AMD64HotSpotLIRGenerationResult(LIR lir, FrameMapBuilder frameMapBuilder, Object stub) {
-        super(lir, frameMapBuilder);
+    public AMD64HotSpotLIRGenerationResult(String compilationUnitName, LIR lir, FrameMapBuilder frameMapBuilder, Object stub) {
+        super(compilationUnitName, lir, frameMapBuilder);
         this.stub = stub;
     }
 
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java	Fri Mar 27 17:02:53 2015 +0100
@@ -80,8 +80,8 @@
     }
 
     @Override
-    public LIRGenerationResult newLIRGenerationResult(LIR lir, FrameMapBuilder frameMapBuilder, ResolvedJavaMethod method, Object stub) {
-        return new SPARCHotSpotLIRGenerationResult(lir, frameMapBuilder, stub);
+    public LIRGenerationResult newLIRGenerationResult(String compilationUnitName, LIR lir, FrameMapBuilder frameMapBuilder, ResolvedJavaMethod method, Object stub) {
+        return new SPARCHotSpotLIRGenerationResult(compilationUnitName, lir, frameMapBuilder, stub);
     }
 
     @Override
@@ -247,6 +247,8 @@
             crb.emit(lir);
         } while (i++ < 1);
 
+        profileInstructions(lir, crb);
+
         HotSpotFrameContext frameContext = (HotSpotFrameContext) crb.frameContext;
         HotSpotForeignCallsProvider foreignCalls = getProviders().getForeignCalls();
         if (!frameContext.isStub) {
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotCounterOp.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotCounterOp.java	Fri Mar 27 17:02:53 2015 +0100
@@ -23,11 +23,14 @@
 package com.oracle.graal.hotspot.sparc;
 
 import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.asm.sparc.SPARCAssembler.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.*;
 import com.oracle.graal.asm.sparc.*;
-import com.oracle.graal.asm.sparc.SPARCMacroAssembler.*;
+import com.oracle.graal.asm.sparc.SPARCMacroAssembler.ScratchRegister;
+import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setx;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.lir.*;
@@ -37,12 +40,16 @@
 public class SPARCHotSpotCounterOp extends HotSpotCounterOp {
     public static final LIRInstructionClass<SPARCHotSpotCounterOp> TYPE = LIRInstructionClass.create(SPARCHotSpotCounterOp.class);
 
+    private int[] counterPatchOffsets;
+
     public SPARCHotSpotCounterOp(String name, String group, Value increment, HotSpotRegistersProvider registers, HotSpotVMConfig config) {
         super(TYPE, name, group, increment, registers, config);
+        this.counterPatchOffsets = new int[1];
     }
 
     public SPARCHotSpotCounterOp(String[] names, String[] groups, Value[] increments, HotSpotRegistersProvider registers, HotSpotVMConfig config) {
         super(TYPE, names, groups, increments, registers, config);
+        this.counterPatchOffsets = new int[names.length];
     }
 
     @Override
@@ -57,19 +64,17 @@
 
             // load counters array
             masm.ldx(countersArrayAddr, countersArrayReg);
-
-            forEachCounter((name, group, increment) -> emitIncrement(masm, target, countersArrayReg, name, group, increment));
+            IncrementEmitter emitter = new IncrementEmitter(countersArrayReg, masm);
+            forEachCounter(emitter, target);
         }
     }
 
-    private void emitIncrement(SPARCMacroAssembler masm, TargetDescription target, Register countersArrayReg, String name, String group, Value increment) {
-        // address for counter
-        SPARCAddress counterAddr = new SPARCAddress(countersArrayReg, getDisplacementForLongIndex(target, getIndex(name, group, increment)));
-
+    private void emitIncrement(int counterIndex, SPARCMacroAssembler masm, SPARCAddress counterAddr, Value increment) {
         try (ScratchRegister scratch = masm.getScratchRegister()) {
             Register counterReg = scratch.getRegister();
             // load counter value
             masm.ldx(counterAddr, counterReg);
+            counterPatchOffsets[counterIndex] = masm.position();
             // increment counter
             if (isConstant(increment)) {
                 masm.add(counterReg, asInt(asConstant(increment)), counterReg);
@@ -80,4 +85,53 @@
             masm.stx(counterReg, counterAddr);
         }
     }
+
+    /**
+     * Patches the increment value in the instruction emitted by the
+     * {@link #emitIncrement(int, SPARCMacroAssembler, SPARCAddress, Value)} method. This method is
+     * used if patching is needed after assembly.
+     *
+     * @param asm
+     * @param increment
+     */
+    @Override
+    public void patchCounterIncrement(Assembler asm, int[] increment) {
+        for (int i = 0; i < increment.length; i++) {
+            int inst = counterPatchOffsets[i];
+            ((SPARCAssembler) asm).patchAddImmediate(inst, increment[i]);
+        }
+    }
+
+    public int[] getCounterPatchOffsets() {
+        return counterPatchOffsets;
+    }
+
+    private class IncrementEmitter implements CounterProcedure {
+        private int lastDisplacement = 0;
+        private final Register countersArrayReg;
+        private final SPARCMacroAssembler masm;
+
+        public IncrementEmitter(Register countersArrayReg, SPARCMacroAssembler masm) {
+            super();
+            this.countersArrayReg = countersArrayReg;
+            this.masm = masm;
+        }
+
+        public void apply(int counterIndex, Value increment, int displacement) {
+            SPARCAddress counterAddr;
+            int relativeDisplacement = displacement - lastDisplacement;
+            if (isSimm13(relativeDisplacement)) { // Displacement fits into ld instruction
+                counterAddr = new SPARCAddress(countersArrayReg, relativeDisplacement);
+            } else {
+                try (ScratchRegister scratch = masm.getScratchRegister()) {
+                    Register tempOffsetRegister = scratch.getRegister();
+                    new Setx(relativeDisplacement, tempOffsetRegister, false).emit(masm);
+                    masm.add(countersArrayReg, tempOffsetRegister, countersArrayReg);
+                }
+                lastDisplacement = displacement;
+                counterAddr = new SPARCAddress(countersArrayReg, 0);
+            }
+            emitIncrement(counterIndex, masm, counterAddr, increment);
+        }
+    }
 }
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerationResult.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerationResult.java	Fri Mar 27 17:02:53 2015 +0100
@@ -47,8 +47,8 @@
      */
     private Map<LIRFrameState, SaveRegistersOp> calleeSaveInfo = new HashMap<>();
 
-    public SPARCHotSpotLIRGenerationResult(LIR lir, FrameMapBuilder frameMapBuilder, Object stub) {
-        super(lir, frameMapBuilder);
+    public SPARCHotSpotLIRGenerationResult(String compilationUnitName, LIR lir, FrameMapBuilder frameMapBuilder, Object stub) {
+        super(compilationUnitName, lir, frameMapBuilder);
         this.stub = stub;
     }
 
@@ -67,5 +67,4 @@
     Map<LIRFrameState, SaveRegistersOp> getCalleeSaveInfo() {
         return calleeSaveInfo;
     }
-
 }
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/CompileTheWorldTest.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/CompileTheWorldTest.java	Fri Mar 27 17:02:53 2015 +0100
@@ -40,7 +40,7 @@
         boolean originalSetting = ExitVMOnException.getValue();
         // Compile a couple classes in rt.jar
         String file = System.getProperty("java.home") + "/lib/rt.jar";
-        new CompileTheWorld(file, new Config(null), 1, 5, false).compile();
+        new CompileTheWorld(file, new Config(null), 1, 5, null, false).compile();
         ExitVMOnException.setValue(originalSetting);
     }
 
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/CompressedOopTest.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/CompressedOopTest.java	Fri Mar 27 17:02:53 2015 +0100
@@ -299,8 +299,8 @@
 
     @Test
     public void test14() throws Exception {
-        HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("stringBufferTest", Object.class, Object.class);
-        StringBuffer buffer = new StringBuffer("TestTestTestTestTestTestTest");
+        HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("stringBuilderTest", Object.class, Object.class);
+        StringBuilder buffer = new StringBuilder("TestTestTestTestTestTestTest");
         Assert.assertTrue(buffer.length() == 28);
         String a = new String("TestTestTestTestTestTestTest");
         installedBenchmarkCode.executeVarargs(buffer, a.toCharArray());
@@ -308,8 +308,8 @@
         Assert.assertTrue(buffer.toString().equals("TestTestTestTestTestTestTestTestTestTestTestTestTestTest"));
     }
 
-    public static void stringBufferTest(Object c1, Object c2) {
-        StringBuffer source = (StringBuffer) c1;
+    public static void stringBuilderTest(Object c1, Object c2) {
+        StringBuilder source = (StringBuilder) c1;
         char[] add = (char[]) c2;
         for (int i = 0; i < add.length; i++) {
             source.append(add[i]);
@@ -318,12 +318,12 @@
 
     @Test
     public void test15() throws Exception {
-        HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("stringBufferTestIn");
+        HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("stringBuilderTestIn");
         installedBenchmarkCode.executeVarargs();
     }
 
-    public static void stringBufferTestIn() {
-        StringBuffer buffer = new StringBuffer("TestTestTestTestTestTestTest");
+    public static void stringBuilderTestIn() {
+        StringBuilder buffer = new StringBuilder("TestTestTestTestTestTestTest");
         Assert.assertTrue(buffer.length() == 28);
         String a = new String("TestTestTestTestTestTestTest");
         char[] add = a.toCharArray();
@@ -336,12 +336,12 @@
 
     @Test
     public void test16() throws Exception {
-        HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("stringBufferArrayCopy");
+        HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("stringBuilderArrayCopy");
         installedBenchmarkCode.executeVarargs();
     }
 
-    public static void stringBufferArrayCopy() {
-        StringBuffer buffer = new StringBuffer("TestTestTestTestTestTestTest");
+    public static void stringBuilderArrayCopy() {
+        StringBuilder buffer = new StringBuilder("TestTestTestTestTestTestTest");
         Assert.assertTrue(buffer.length() == 28);
         String a = new String("TestTestTestTestTestTestTest");
         char[] dst = new char[buffer.length() * 2];
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/MemoryUsageBenchmark.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/MemoryUsageBenchmark.java	Fri Mar 27 17:02:53 2015 +0100
@@ -63,7 +63,7 @@
             return cs.hashCode();
         }
 
-        if (cs instanceof StringBuffer) {
+        if (cs instanceof StringBuilder) {
             int[] hash = {0};
             cs.chars().forEach(c -> hash[0] += c);
             return hash[0];
@@ -180,7 +180,7 @@
         compileAndTime("complex");
         if (CompileTheWorldClasspath.getValue() != SUN_BOOT_CLASS_PATH) {
             CompileTheWorld ctw = new CompileTheWorld(CompileTheWorldClasspath.getValue(), new Config(CompileTheWorldConfig.getValue()), CompileTheWorldStartAt.getValue(),
-                            CompileTheWorldStopAt.getValue(), CompileTheWorldVerbose.getValue());
+                            CompileTheWorldStopAt.getValue(), CompileTheWorldMethodFilter.getValue(), CompileTheWorldVerbose.getValue());
             try {
                 ctw.compile();
             } catch (Throwable e) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java	Fri Mar 27 17:02:53 2015 +0100
@@ -34,6 +34,7 @@
 import java.util.concurrent.*;
 import java.util.concurrent.atomic.*;
 import java.util.jar.*;
+import java.util.stream.*;
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.bytecode.*;
@@ -41,6 +42,7 @@
 import com.oracle.graal.compiler.CompilerThreadFactory.DebugConfigAccess;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.internal.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.options.*;
 import com.oracle.graal.options.OptionUtils.OptionConsumer;
@@ -66,6 +68,8 @@
         public static final OptionValue<Boolean> CompileTheWorldVerbose = new OptionValue<>(true);
         @Option(help = "The number of CompileTheWorld iterations to perform", type = OptionType.Debug)
         public static final OptionValue<Integer> CompileTheWorldIterations = new OptionValue<>(1);
+        @Option(help = "Only compile methods matching this filter", type = OptionType.Debug)
+        public static final OptionValue<String> CompileTheWorldMethodFilter = new OptionValue<>(null);
         @Option(help = "First class to consider when using -XX:+CompileTheWorld", type = OptionType.Debug)
         public static final OptionValue<Integer> CompileTheWorldStartAt = new OptionValue<>(1);
         @Option(help = "Last class to consider when using -XX:+CompileTheWorld", type = OptionType.Debug)
@@ -75,8 +79,10 @@
                        "The format for each option is the same as on the command line just without the '-G:' prefix.", type = OptionType.Debug)
         public static final OptionValue<String> CompileTheWorldConfig = new OptionValue<>(null);
 
-        @Option(help = "Last class to consider when using -XX:+CompileTheWorld", type = OptionType.Debug)
+        @Option(help = "Run CTW using as many threads as there are processors on the system", type = OptionType.Debug)
         public static final OptionValue<Boolean> CompileTheWorldMultiThreaded = new OptionValue<>(false);
+        @Option(help = "Number of threads to use for multithreaded CTW.  Defaults to Runtime.getRuntime().availableProcessors()", type = OptionType.Debug)
+        public static final OptionValue<Integer> CompileTheWorldThreads = new OptionValue<>(0);
         // @formatter:on
 
         /**
@@ -149,6 +155,9 @@
     /** Class index to stop compilation at (see {@link Options#CompileTheWorldStopAt}). */
     private final int stopAt;
 
+    /** Only compile methods matching one of the filters in this array if the array is non-null. */
+    private final MethodFilter[] methodFilters;
+
     // Counters
     private int classFileCounter = 0;
     private AtomicLong compiledMethodsCounter = new AtomicLong();
@@ -158,6 +167,11 @@
     private boolean verbose;
     private final Config config;
 
+    /**
+     * Signal that the threads should start compiling in multithreaded mode.
+     */
+    private boolean running;
+
     private ThreadPoolExecutor threadPool;
 
     /**
@@ -167,10 +181,11 @@
      * @param startAt index of the class file to start compilation at
      * @param stopAt index of the class file to stop compilation at
      */
-    public CompileTheWorld(String files, Config config, int startAt, int stopAt, boolean verbose) {
+    public CompileTheWorld(String files, Config config, int startAt, int stopAt, String methodFilters, boolean verbose) {
         this.files = files;
         this.startAt = startAt;
         this.stopAt = stopAt;
+        this.methodFilters = methodFilters == null || methodFilters.isEmpty() ? null : MethodFilter.parse(methodFilters);
         this.verbose = verbose;
         this.config = config;
 
@@ -189,6 +204,11 @@
      * files from the boot class path.
      */
     public void compile() throws Throwable {
+        // By default only report statistics for the CTW threads themselves
+        if (GraalDebugConfig.DebugValueThreadFilter.hasInitialValue()) {
+            GraalDebugConfig.DebugValueThreadFilter.setValue("^CompileTheWorld");
+        }
+
         if (SUN_BOOT_CLASS_PATH.equals(files)) {
             final String[] entries = System.getProperty(SUN_BOOT_CLASS_PATH).split(File.pathSeparator);
             String bcpFiles = "";
@@ -234,15 +254,29 @@
         final String[] entries = fileList.split(File.pathSeparator);
         long start = System.currentTimeMillis();
 
-        if (Options.CompileTheWorldMultiThreaded.getValue()) {
-            CompilerThreadFactory factory = new CompilerThreadFactory("CompileTheWorld", new DebugConfigAccess() {
-                public GraalDebugConfig getDebugConfig() {
+        CompilerThreadFactory factory = new CompilerThreadFactory("CompileTheWorld", new DebugConfigAccess() {
+            public GraalDebugConfig getDebugConfig() {
+                if (Debug.isEnabled() && DebugScope.getConfig() == null) {
                     return DebugEnvironment.initialize(System.out);
                 }
-            });
-            int availableProcessors = Runtime.getRuntime().availableProcessors();
-            threadPool = new ThreadPoolExecutor(availableProcessors, availableProcessors, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), factory);
+                return null;
+            }
+        });
+
+        /*
+         * Always use a thread pool, even for single threaded mode since it simplifies the use of
+         * DebugValueThreadFilter to filter on the thread names.
+         */
+        int threadCount = 1;
+        if (Options.CompileTheWorldMultiThreaded.getValue()) {
+            threadCount = Options.CompileTheWorldThreads.getValue();
+            if (threadCount == 0) {
+                threadCount = Runtime.getRuntime().availableProcessors();
+            }
+        } else {
+            running = true;
         }
+        threadPool = new ThreadPoolExecutor(threadCount, threadCount, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), factory);
 
         try (OverrideScope s = config.apply()) {
             for (int i = 0; i < entries.length; i++) {
@@ -255,7 +289,12 @@
                     continue;
                 }
 
-                println("CompileTheWorld : Compiling all classes in " + entry);
+                if (methodFilters == null || methodFilters.length == 0) {
+                    println("CompileTheWorld : Compiling all classes in " + entry);
+                } else {
+                    println("CompileTheWorld : Compiling all methods in " + entry + " matching one of the following filters: " +
+                                    Arrays.asList(methodFilters).stream().map(MethodFilter::toString).collect(Collectors.joining(", ")));
+                }
                 println();
 
                 URL url = new URL("jar", "", "file:" + entry + "!/");
@@ -276,11 +315,16 @@
                     }
 
                     String className = je.getName().substring(0, je.getName().length() - ".class".length());
+                    String dottedClassName = className.replace('/', '.');
                     classFileCounter++;
 
+                    if (methodFilters != null && !MethodFilter.matchesClassName(methodFilters, dottedClassName)) {
+                        continue;
+                    }
+
                     try {
                         // Load and initialize class
-                        Class<?> javaClass = Class.forName(className.replace('/', '.'), true, loader);
+                        Class<?> javaClass = Class.forName(dottedClassName, true, loader);
 
                         // Pre-load all classes in the constant pool.
                         try {
@@ -321,22 +365,42 @@
             }
         }
 
-        if (threadPool != null) {
-            while (threadPool.getCompletedTaskCount() != threadPool.getTaskCount()) {
-                System.out.println("CompileTheWorld : Waiting for " + (threadPool.getTaskCount() - threadPool.getCompletedTaskCount()) + " compiles");
-                try {
-                    threadPool.awaitTermination(15, TimeUnit.SECONDS);
-                } catch (InterruptedException e) {
-                }
+        if (!running) {
+            startThreads();
+        }
+        while (threadPool.getCompletedTaskCount() != threadPool.getTaskCount()) {
+            TTY.println("CompileTheWorld : Waiting for " + (threadPool.getTaskCount() - threadPool.getCompletedTaskCount()) + " compiles");
+            try {
+                threadPool.awaitTermination(15, TimeUnit.SECONDS);
+            } catch (InterruptedException e) {
             }
-            threadPool = null;
         }
+        threadPool = null;
 
         long elapsedTime = System.currentTimeMillis() - start;
 
         println();
-        println("CompileTheWorld : Done (%d classes, %d methods, %d ms elapsed, %d ms compile time, %d bytes of memory used)", classFileCounter, compiledMethodsCounter.get(), elapsedTime,
-                        compileTime.get(), memoryUsed.get());
+        if (Options.CompileTheWorldMultiThreaded.getValue()) {
+            TTY.println("CompileTheWorld : Done (%d classes, %d methods, %d ms elapsed, %d ms compile time, %d bytes of memory used)", classFileCounter, compiledMethodsCounter.get(), elapsedTime,
+                            compileTime.get(), memoryUsed.get());
+        } else {
+            TTY.println("CompileTheWorld : Done (%d classes, %d methods, %d ms, %d bytes of memory used)", classFileCounter, compiledMethodsCounter.get(), compileTime.get(), memoryUsed.get());
+        }
+    }
+
+    private synchronized void startThreads() {
+        running = true;
+        // Wake up any waiting threads
+        notifyAll();
+    }
+
+    private synchronized void waitToRun() {
+        while (!running) {
+            try {
+                wait();
+            } catch (InterruptedException e) {
+            }
+        }
     }
 
     class CTWCompilationTask extends CompilationTask {
@@ -355,17 +419,20 @@
         }
     }
 
-    private void compileMethod(HotSpotResolvedJavaMethod method) {
-        if (threadPool != null) {
-            threadPool.submit(new Runnable() {
-                public void run() {
-                    try (OverrideScope s = config.apply()) {
-                        compileMethod(method, classFileCounter);
-                    }
+    private void compileMethod(HotSpotResolvedJavaMethod method) throws InterruptedException, ExecutionException {
+        if (methodFilters != null && !MethodFilter.matches(methodFilters, method)) {
+            return;
+        }
+        Future<?> task = threadPool.submit(new Runnable() {
+            public void run() {
+                waitToRun();
+                try (OverrideScope s = config.apply()) {
+                    compileMethod(method, classFileCounter);
                 }
-            });
-        } else {
-            compileMethod(method, classFileCounter);
+            }
+        });
+        if (threadPool.getCorePoolSize() == 1) {
+            task.get();
         }
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/DebugValuesPrinter.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/DebugValuesPrinter.java	Fri Mar 27 17:02:53 2015 +0100
@@ -26,6 +26,8 @@
 
 import java.io.*;
 import java.util.*;
+import java.util.regex.*;
+import java.util.stream.*;
 
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.debug.*;
@@ -51,6 +53,12 @@
                 if (summary == null) {
                     summary = "Complete";
                 }
+                if (DebugValueThreadFilter.getValue() != null && topLevelMaps.size() != 0) {
+                    topLevelMaps = topLevelMaps.stream().filter(map -> Pattern.compile(DebugValueThreadFilter.getValue()).matcher(map.getName()).find()).collect(Collectors.toList());
+                    if (topLevelMaps.size() == 0) {
+                        TTY.println("Warning: DebugValueThreadFilter=%s eliminated all maps so nothing will be printed", DebugValueThreadFilter.getValue());
+                    }
+                }
                 switch (summary) {
                     case "Name":
                         printSummary(topLevelMaps, sortedValues);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java	Fri Mar 27 17:02:53 2015 +0100
@@ -40,6 +40,7 @@
 import com.oracle.graal.lir.LIRInstruction.OperandMode;
 import com.oracle.graal.lir.StandardOp.LabelOp;
 import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
+import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.lir.framemap.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.options.*;
@@ -55,6 +56,9 @@
         // @formatter:off
         @Option(help = "Use Graal stubs instead of HotSpot stubs where possible")
         public static final OptionValue<Boolean> PreferGraalStubs = new OptionValue<>(false);
+        @Option(help = "Enables instruction profiling on assembler level. Valid values are a comma separated list of supported instructions." +
+                        " Compare with subclasses of Assembler.InstructionCounter.", type = OptionType.Debug)
+        public static final OptionValue<String> ASMInstructionProfiling = new OptionValue<>(null);
         // @formatter:on
     }
 
@@ -235,4 +239,10 @@
     public DisassemblerProvider getDisassembler() {
         return getProviders().getDisassembler();
     }
+
+    protected void profileInstructions(LIR lir, CompilationResultBuilder crb) {
+        if (HotSpotBackend.Options.ASMInstructionProfiling.getValue() != null) {
+            HotSpotInstructionProfiling.countInstructions(lir, crb.asm);
+        }
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCounterOp.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCounterOp.java	Fri Mar 27 17:02:53 2015 +0100
@@ -24,6 +24,8 @@
 
 import static com.oracle.graal.api.code.ValueUtil.*;
 
+import java.util.*;
+
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.*;
@@ -67,12 +69,42 @@
     }
 
     protected interface CounterProcedure {
-        void apply(String name, String group, Value increment);
+        /**
+         * Lambda interface for iterating over counters declared in this op.
+         *
+         * @param counterIndex Index in this CounterOp object.
+         * @param increment Value for increment
+         * @param displacement Displacement in bytes in the counter array
+         */
+        void apply(int counterIndex, Value increment, int displacement);
     }
 
-    protected void forEachCounter(CounterProcedure proc) {
-        for (int i = 0; i < names.length; i++) {
-            proc.apply(names[i], groups[i], increments[i]);
+    /**
+     * Calls the {@link CounterProcedure} for each counter in ascending order of their displacement
+     * in the counter array.
+     *
+     * @param proc The procedure to be called
+     * @param target Target architecture (used to calculate the array displacements)
+     */
+    protected void forEachCounter(CounterProcedure proc, TargetDescription target) {
+        if (names.length == 1) { // fast path
+            int arrayIndex = getIndex(names[0], groups[0], increments[0]);
+            int displacement = getDisplacementForLongIndex(target, arrayIndex);
+            proc.apply(0, increments[0], displacement);
+        } else { // Slow path with sort by displacements ascending
+            int[] displacements = new int[names.length];
+            HashMap<Integer, Integer> offsetMap = new HashMap<>(names.length);
+            for (int i = 0; i < names.length; i++) {
+                int arrayIndex = getIndex(names[i], groups[i], increments[i]);
+                displacements[i] = getDisplacementForLongIndex(target, arrayIndex);
+                offsetMap.put(displacements[i], i);
+            }
+            Arrays.sort(displacements);
+            // Now apply in order
+            for (int offset : displacements) {
+                int idx = offsetMap.get(offset);
+                proc.apply(idx, increments[idx], displacements[idx]);
+            }
         }
     }
 
@@ -86,6 +118,17 @@
         return BenchmarkCounters.getIndex(name, group, config);
     }
 
+    /**
+     * Patches the increment value in the instruction emitted by this instruction. Use only, if
+     * patching is needed after assembly.
+     *
+     * @param asm
+     * @param increment
+     */
+    public void patchCounterIncrement(Assembler asm, int[] increment) {
+        throw GraalInternalError.unimplemented();
+    }
+
     private static long asLong(JavaConstant value) {
         Kind kind = value.getKind();
         switch (kind) {
@@ -109,4 +152,11 @@
         return (int) l;
     }
 
+    public String[] getNames() {
+        return names;
+    }
+
+    public String[] getGroups() {
+        return groups;
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Fri Mar 27 17:02:53 2015 +0100
@@ -110,9 +110,9 @@
 
         this.compilerToVm = toVM;
 
-        if (Log.getValue() == null && Meter.getValue() == null && Time.getValue() == null && Dump.getValue() == null && Verify.getValue() == null) {
+        if (Log.getValue() == null && !areScopedMetricsOrTimersEnabled() && Dump.getValue() == null && Verify.getValue() == null) {
             if (MethodFilter.getValue() != null) {
-                TTY.println("WARNING: Ignoring MethodFilter option since Log, Meter, Time, Dump and Verify options are all null");
+                TTY.println("WARNING: Ignoring MethodFilter option since Log, Meter, Time, TrackMemUse, Dump and Verify options are all null");
             }
         }
 
@@ -133,7 +133,7 @@
             }
         }
 
-        if (Debug.areUnconditionalMetricsEnabled() || Debug.areUnconditionalTimersEnabled() || (Debug.isEnabled() && areMetricsOrTimersEnabled())) {
+        if (Debug.areUnconditionalMetricsEnabled() || Debug.areUnconditionalTimersEnabled() || (Debug.isEnabled() && areScopedMetricsOrTimersEnabled())) {
             // This must be created here to avoid loading the DebugValuesPrinter class
             // during shutdown() which in turn can cause a deadlock
             debugValuesPrinter = new DebugValuesPrinter();
@@ -552,7 +552,7 @@
             getCompilerToVM().resetCompilationStatistics();
             TTY.println("CompileTheWorld : iteration " + i);
             CompileTheWorld ctw = new CompileTheWorld(CompileTheWorldClasspath.getValue(), new Config(CompileTheWorldConfig.getValue()), CompileTheWorldStartAt.getValue(),
-                            CompileTheWorldStopAt.getValue(), CompileTheWorldVerbose.getValue());
+                            CompileTheWorldStopAt.getValue(), CompileTheWorldMethodFilter.getValue(), CompileTheWorldVerbose.getValue());
             ctw.compile();
         }
         System.exit(0);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java	Fri Mar 27 17:02:53 2015 +0100
@@ -88,7 +88,6 @@
                 }
                 if (BootstrapReplacements.getValue()) {
                     for (ResolvedJavaMethod method : replacements.getAllReplacements()) {
-                        replacements.getMacroSubstitution(method);
                         replacements.getMethodSubstitution(method);
                     }
                 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotInstructionProfiling.java	Fri Mar 27 17:02:53 2015 +0100
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.*;
+import com.oracle.graal.asm.Assembler.*;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.BlockEndOp;
+import com.oracle.graal.lir.StandardOp.LabelOp;
+import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.phases.*;
+
+public class HotSpotInstructionProfiling extends PostAllocationOptimizationPhase {
+    public static final String COUNTER_GROUP = "INSTRUCTION_COUNTER";
+    private final String[] instructionsToProfile;
+
+    public HotSpotInstructionProfiling(String instructionsToProfile) {
+        this.instructionsToProfile = instructionsToProfile.split(",");
+    }
+
+    @Override
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder,
+                    BenchmarkCounterFactory counterFactory) {
+        new Analyzer(lirGenRes.getCompilationUnitName(), lirGenRes.getLIR(), counterFactory).run();
+    }
+
+    private class Analyzer {
+        private final LIR lir;
+        private final BenchmarkCounterFactory counterFactory;
+        private final LIRInsertionBuffer buffer;
+        private final String compilationUnitName;
+
+        public Analyzer(String compilationUnitName, LIR lir, BenchmarkCounterFactory counterFactory) {
+            this.lir = lir;
+            this.compilationUnitName = compilationUnitName;
+            this.counterFactory = counterFactory;
+            this.buffer = new LIRInsertionBuffer();
+        }
+
+        public void run() {
+            for (AbstractBlockBase<?> block : lir.getControlFlowGraph().getBlocks()) {
+                doBlock(block);
+            }
+        }
+
+        public void doBlock(AbstractBlockBase<?> block) {
+            List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+            assert instructions.size() >= 2 : "Malformed block: " + block + ", " + instructions;
+            assert instructions.get(instructions.size() - 1) instanceof BlockEndOp : "Not a BlockEndOp: " + instructions.get(instructions.size() - 1);
+            assert !(instructions.get(instructions.size() - 2) instanceof BlockEndOp) : "Is a BlockEndOp: " + instructions.get(instructions.size() - 2);
+            assert instructions.get(0) instanceof LabelOp : "Not a LabelOp: " + instructions.get(0);
+            assert !(instructions.get(1) instanceof LabelOp) : "Is a LabelOp: " + instructions.get(1);
+            String[] names = new String[instructionsToProfile.length];
+            String[] groups = new String[instructionsToProfile.length];
+            Value[] increments = new Value[instructionsToProfile.length];
+            for (int i = 0; i < instructionsToProfile.length; i++) {
+                names[i] = compilationUnitName;
+                groups[i] = COUNTER_GROUP + " " + instructionsToProfile[i];
+                increments[i] = JavaConstant.INT_0;
+            }
+            HotSpotCounterOp op = (HotSpotCounterOp) counterFactory.createMultiBenchmarkCounter(names, groups, increments);
+            LIRInstruction inst = new InstructionCounterOp(op, instructionsToProfile);
+            assert inst != null;
+            buffer.init(instructions);
+            buffer.append(1, inst);
+            buffer.finish();
+        }
+    }
+
+    /**
+     * After assembly the {@link HotSpotBackend#profileInstructions(LIR, CompilationResultBuilder)}
+     * calls this method for patching the instruction counts into the coutner increment code.
+     */
+    public static void countInstructions(LIR lir, Assembler asm) {
+        InstructionCounterOp lastOp = null;
+        InstructionCounter counter = asm.getInstructionCounter();
+        for (AbstractBlockBase<?> block : lir.codeEmittingOrder()) {
+            for (LIRInstruction inst : lir.getLIRforBlock(block)) {
+                if (inst instanceof InstructionCounterOp) {
+                    InstructionCounterOp currentOp = (InstructionCounterOp) inst;
+
+                    if (lastOp != null) {
+                        int beginPc = lastOp.countOffsetEnd;
+                        int endPc = currentOp.countOffsetBegin;
+                        int[] instructionCounts = counter.countInstructions(lastOp.instructionsToProfile, beginPc, endPc);
+                        lastOp.delegate.patchCounterIncrement(asm, instructionCounts);
+                    }
+                    lastOp = ((InstructionCounterOp) inst);
+                }
+            }
+        }
+        if (lastOp != null) {
+            assert lastOp.countOffsetBegin < asm.position();
+            int beginPc = lastOp.countOffsetBegin;
+            int endPc = asm.position();
+            int[] instructionCounts = counter.countInstructions(lastOp.instructionsToProfile, beginPc, endPc);
+            lastOp.delegate.patchCounterIncrement(asm, instructionCounts);
+        }
+    }
+
+    public static class InstructionCounterOp extends LIRInstruction {
+        public static final LIRInstructionClass<InstructionCounterOp> TYPE = LIRInstructionClass.create(InstructionCounterOp.class);
+        private final HotSpotCounterOp delegate;
+        private final String[] instructionsToProfile;
+        private int countOffsetBegin;
+        private int countOffsetEnd;
+
+        public InstructionCounterOp(HotSpotCounterOp delegate, String[] instructionsToProfile) {
+            super(TYPE);
+            this.delegate = delegate;
+            this.instructionsToProfile = instructionsToProfile;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb) {
+            countOffsetBegin = crb.asm.position();
+            this.delegate.emitCode(crb);
+            countOffsetEnd = crb.asm.position();
+        }
+
+        public String[] getInstructionsToProfile() {
+            return instructionsToProfile;
+        }
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptions.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptions.java	Fri Mar 27 17:02:53 2015 +0100
@@ -63,6 +63,15 @@
         if (areDebugScopePatternsEnabled()) {
             System.setProperty(Debug.Initialization.INITIALIZER_PROPERTY_NAME, "true");
         }
+        if ("".equals(Meter.getValue())) {
+            System.setProperty(Debug.ENABLE_UNSCOPED_METRICS_PROPERTY_NAME, "true");
+        }
+        if ("".equals(Time.getValue())) {
+            System.setProperty(Debug.ENABLE_UNSCOPED_TIMERS_PROPERTY_NAME, "true");
+        }
+        if ("".equals(TrackMemUse.getValue())) {
+            System.setProperty(Debug.ENABLE_UNSCOPED_MEM_USE_TRACKERS_PROPERTY_NAME, "true");
+        }
     }
 
     /**
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java	Fri Mar 27 17:02:53 2015 +0100
@@ -28,9 +28,8 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.replacements.*;
-import com.oracle.graal.nodes.*;
+import com.oracle.graal.hotspot.word.*;
 import com.oracle.graal.phases.util.*;
 import com.oracle.graal.replacements.*;
 
@@ -48,6 +47,11 @@
     }
 
     @Override
+    protected boolean hasGenericInvocationPluginAnnotation(ResolvedJavaMethod method) {
+        return method.getAnnotation(HotSpotOperation.class) != null || super.hasGenericInvocationPluginAnnotation(method);
+    }
+
+    @Override
     protected ResolvedJavaMethod registerMethodSubstitution(ClassReplacements cr, Executable originalMethod, Method substituteMethod) {
         final Class<?> substituteClass = substituteMethod.getDeclaringClass();
         if (substituteClass == IntegerSubstitutions.class || substituteClass == LongSubstitutions.class) {
@@ -75,21 +79,4 @@
         }
         return super.registerMethodSubstitution(cr, originalMethod, substituteMethod);
     }
-
-    @Override
-    public Class<? extends FixedWithNextNode> getMacroSubstitution(ResolvedJavaMethod method) {
-        HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) method;
-        int intrinsicId = hsMethod.intrinsicId();
-        if (intrinsicId != 0) {
-            /*
-             * The methods of MethodHandle that need substitution are signature-polymorphic, i.e.,
-             * the VM replicates them for every signature that they are actually used for.
-             * Therefore, we cannot use the usual annotation-driven mechanism to define the
-             */
-            if (MethodHandleNode.lookupMethodHandleIntrinsic(method, providers.getConstantReflection().getMethodHandleAccess()) != null) {
-                return MethodHandleNode.class;
-            }
-        }
-        return super.getMacroSubstitution(method);
-    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java	Fri Mar 27 17:02:53 2015 +0100
@@ -24,6 +24,10 @@
 
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 
+import java.lang.invoke.*;
+
+import sun.reflect.*;
+
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
@@ -35,7 +39,9 @@
 import com.oracle.graal.graphbuilderconf.InvocationPlugins.Registration;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.hotspot.nodes.ClassQueryNode.Query;
 import com.oracle.graal.hotspot.replacements.*;
+import com.oracle.graal.hotspot.replacements.arraycopy.*;
 import com.oracle.graal.hotspot.word.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.HeapAccess.BarrierType;
@@ -60,7 +66,7 @@
      */
     public static Plugins create(HotSpotVMConfig config, HotSpotWordTypes wordTypes, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection,
                     SnippetReflectionProvider snippetReflection, ForeignCallsProvider foreignCalls, StampProvider stampProvider, ReplacementsImpl replacements, Architecture arch) {
-        InvocationPlugins invocationPlugins = new HotSpotInvocationPlugins(config, metaAccess);
+        InvocationPlugins invocationPlugins = new HotSpotInvocationPlugins(config, metaAccess, constantReflection.getMethodHandleAccess());
 
         Plugins plugins = new Plugins(invocationPlugins);
         NodeIntrinsificationPhase nodeIntrinsification = new NodeIntrinsificationPhase(metaAccess, constantReflection, snippetReflection, foreignCalls, stampProvider);
@@ -69,12 +75,15 @@
         plugins.setParameterPlugin(new HotSpotParameterPlugin(wordTypes));
         plugins.setLoadFieldPlugin(new HotSpotLoadFieldPlugin(metaAccess, constantReflection));
         plugins.setLoadIndexedPlugin(new HotSpotLoadIndexedPlugin(wordTypes));
-        plugins.setInlineInvokePlugin(new HotSpotInlineInvokePlugin(nodeIntrinsification, replacements));
-        plugins.setGenericInvocationPlugin(new DefaultGenericInvocationPlugin(nodeIntrinsification, wordOperationPlugin));
+        plugins.setInlineInvokePlugin(new DefaultInlineInvokePlugin(replacements));
+        plugins.setGenericInvocationPlugin(new DefaultGenericInvocationPlugin(metaAccess, nodeIntrinsification, wordOperationPlugin));
 
         registerObjectPlugins(invocationPlugins);
+        registerClassPlugins(invocationPlugins);
         registerSystemPlugins(invocationPlugins, foreignCalls);
         registerThreadPlugins(invocationPlugins, metaAccess, wordTypes, config);
+        registerCallSitePlugins(invocationPlugins);
+        registerReflectionPlugins(invocationPlugins);
         registerStableOptionPlugins(invocationPlugins);
         StandardGraphBuilderPlugins.registerInvocationPlugins(metaAccess, arch, invocationPlugins, !config.useHeapProfiler);
 
@@ -89,13 +98,79 @@
                 ObjectStamp objectStamp = (ObjectStamp) rcvr.stamp();
                 ValueNode mirror;
                 if (objectStamp.isExactType() && objectStamp.nonNull() && !GraalOptions.ImmutableCode.getValue()) {
-                    mirror = b.append(ConstantNode.forConstant(objectStamp.type().getJavaClass(), b.getMetaAccess()));
+                    mirror = ConstantNode.forConstant(objectStamp.type().getJavaClass(), b.getMetaAccess());
                 } else {
                     StampProvider stampProvider = b.getStampProvider();
-                    LoadHubNode hub = b.append(new LoadHubNode(stampProvider, rcvr));
-                    mirror = b.append(new HubGetClassNode(b.getMetaAccess(), hub));
+                    LoadHubNode hub = b.add(new LoadHubNode(stampProvider, rcvr));
+                    mirror = new HubGetClassNode(b.getMetaAccess(), hub);
+                }
+                b.addPush(Kind.Object, mirror);
+                return true;
+            }
+        });
+        r.register1("clone", Receiver.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
+                ValueNode object = receiver.get();
+                b.addPush(Kind.Object, new ObjectCloneNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnType(), object));
+                return true;
+            }
+        });
+    }
+
+    private static void registerClassPlugins(InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, Class.class);
+
+        for (Query query : Query.values()) {
+            r.register1(query.name(), Receiver.class, new InvocationPlugin() {
+                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
+                    ValueNode javaClass = receiver.get();
+                    ValueNode folded = ClassQueryNode.tryFold(javaClass, query, b.getMetaAccess(), b.getConstantReflection());
+                    if (folded != null) {
+                        b.addPush(query.returnKind, folded);
+                    } else {
+                        b.addPush(query.returnKind, new ClassQueryNode(b.getInvokeKind(), targetMethod, query, b.bci(), b.getInvokeReturnType(), javaClass));
+                    }
+                    return true;
                 }
-                b.push(Kind.Object, mirror);
+            });
+        }
+        r.register2("cast", Receiver.class, Object.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) {
+                ValueNode javaClass = receiver.get();
+                ValueNode folded = ClassCastNode.tryFold(javaClass, object, b.getConstantReflection(), b.getAssumptions());
+                if (folded != null) {
+                    b.addPush(Kind.Object, folded);
+                } else {
+                    b.addPush(Kind.Object, new ClassCastNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnType(), javaClass, object));
+                }
+                return true;
+            }
+        });
+    }
+
+    private static void registerCallSitePlugins(InvocationPlugins plugins) {
+        InvocationPlugin plugin = new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
+                ValueNode callSite = receiver.get();
+                ValueNode folded = CallSiteTargetNode.tryFold(callSite, b.getMetaAccess(), b.getAssumptions());
+                if (folded != null) {
+                    b.addPush(Kind.Object, folded);
+                } else {
+                    b.addPush(Kind.Object, new CallSiteTargetNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnType(), callSite));
+                }
+                return true;
+            }
+        };
+        plugins.register(plugin, ConstantCallSite.class, "getTarget", Receiver.class);
+        plugins.register(plugin, MutableCallSite.class, "getTarget", Receiver.class);
+        plugins.register(plugin, VolatileCallSite.class, "getTarget", Receiver.class);
+    }
+
+    private static void registerReflectionPlugins(InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, Reflection.class);
+        r.register0("getCallerClass", new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
+                b.addPush(new ReflectionGetCallerClassNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnType()));
                 return true;
             }
         });
@@ -105,17 +180,25 @@
         Registration r = new Registration(plugins, System.class);
         r.register0("currentTimeMillis", new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
-                ForeignCallNode foreignCall = new ForeignCallNode(foreignCalls, SystemSubstitutions.JAVA_TIME_MILLIS, StampFactory.forKind(Kind.Long));
-                b.push(Kind.Long, b.append(foreignCall));
-                foreignCall.setStateAfter(b.createStateAfter());
+                b.addPush(Kind.Long, new ForeignCallNode(foreignCalls, SystemSubstitutions.JAVA_TIME_MILLIS, StampFactory.forKind(Kind.Long)));
                 return true;
             }
         });
         r.register0("nanoTime", new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
-                ForeignCallNode foreignCall = new ForeignCallNode(foreignCalls, SystemSubstitutions.JAVA_TIME_NANOS, StampFactory.forKind(Kind.Long));
-                b.push(Kind.Long, b.append(foreignCall));
-                foreignCall.setStateAfter(b.createStateAfter());
+                b.addPush(Kind.Long, new ForeignCallNode(foreignCalls, SystemSubstitutions.JAVA_TIME_NANOS, StampFactory.forKind(Kind.Long)));
+                return true;
+            }
+        });
+        r.register1("identityHashCode", Object.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) {
+                b.addPush(new SystemIdentityHashCodeNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnType(), object));
+                return true;
+            }
+        });
+        r.register5("arraycopy", Object.class, int.class, Object.class, int.class, int.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode src, ValueNode srcPos, ValueNode dst, ValueNode dstPos, ValueNode length) {
+                b.add(new ArrayCopyNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnType(), src, srcPos, dst, dstPos, length));
                 return true;
             }
         });
@@ -125,13 +208,13 @@
         Registration r = new Registration(plugins, Thread.class);
         r.register0("currentThread", new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
-                CurrentJavaThreadNode thread = b.append(new CurrentJavaThreadNode(wordTypes.getWordKind()));
-                ConstantLocationNode location = b.append(new ConstantLocationNode(JAVA_THREAD_THREAD_OBJECT_LOCATION, config.threadObjectOffset));
+                CurrentJavaThreadNode thread = b.add(new CurrentJavaThreadNode(wordTypes.getWordKind()));
+                ConstantLocationNode location = b.add(new ConstantLocationNode(JAVA_THREAD_THREAD_OBJECT_LOCATION, config.threadObjectOffset));
                 boolean compressible = false;
                 ValueNode javaThread = WordOperationPlugin.readOp(b, Kind.Object, thread, location, BarrierType.NONE, compressible);
                 boolean exactType = compressible;
                 boolean nonNull = true;
-                b.push(Kind.Object, b.append(new PiNode(javaThread, metaAccess.lookupJavaType(Thread.class), exactType, nonNull)));
+                b.addPush(Kind.Object, new PiNode(javaThread, metaAccess.lookupJavaType(Thread.class), exactType, nonNull));
                 return true;
             }
         });
@@ -144,8 +227,7 @@
                 if (receiver.isConstant()) {
                     Object object = ((HotSpotObjectConstantImpl) receiver.get().asConstant()).object();
                     StableOptionValue<?> option = (StableOptionValue<?>) object;
-                    ConstantNode value = b.append(ConstantNode.forConstant(HotSpotObjectConstantImpl.forObject(option.getValue()), b.getMetaAccess()));
-                    b.push(Kind.Object, value);
+                    b.addPush(Kind.Object, ConstantNode.forConstant(HotSpotObjectConstantImpl.forObject(option.getValue()), b.getMetaAccess()));
                     return true;
                 }
                 return false;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInlineInvokePlugin.java	Fri Mar 27 15:43:31 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,89 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.meta;
-
-import static com.oracle.graal.compiler.common.GraalOptions.*;
-import static com.oracle.graal.java.AbstractBytecodeParser.Options.*;
-import static java.lang.String.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.graph.Node.NodeIntrinsic;
-import com.oracle.graal.graphbuilderconf.*;
-import com.oracle.graal.graphbuilderconf.GraphBuilderContext.Replacement;
-import com.oracle.graal.hotspot.word.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.replacements.*;
-import com.oracle.graal.word.*;
-
-public final class HotSpotInlineInvokePlugin implements InlineInvokePlugin {
-    private final ReplacementsImpl replacements;
-    private final NodeIntrinsificationPhase nodeIntrinsification;
-
-    public HotSpotInlineInvokePlugin(NodeIntrinsificationPhase nodeIntrinsification, ReplacementsImpl replacements) {
-        this.nodeIntrinsification = nodeIntrinsification;
-        this.replacements = replacements;
-    }
-
-    private static final int MAX_GRAPH_INLINING_DEPTH = 100; // more than enough
-
-    public InlineInfo getInlineInfo(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType) {
-        ResolvedJavaMethod subst = replacements.getMethodSubstitutionMethod(method);
-        if (subst != null) {
-            if (b.parsingReplacement() || InlineDuringParsing.getValue()) {
-                // Forced inlining of intrinsics
-                return new InlineInfo(subst, true, true);
-            }
-        }
-        if (b.parsingReplacement()) {
-            assert nodeIntrinsification.getIntrinsic(method) == null && method.getAnnotation(Word.Operation.class) == null && method.getAnnotation(HotSpotOperation.class) == null &&
-                            !nodeIntrinsification.isFoldable(method) : format("%s should have been handled by %s", method.format("%H.%n(%p)"), DefaultGenericInvocationPlugin.class.getName());
-
-            assert b.getDepth() < MAX_GRAPH_INLINING_DEPTH : "inlining limit exceeded";
-
-            if (method.getName().startsWith("$jacoco")) {
-                throw new GraalInternalError("Found call to JaCoCo instrumentation method " + method.format("%H.%n(%p)") + ". Placing \"//JaCoCo Exclude\" anywhere in " +
-                                b.getMethod().getDeclaringClass().getSourceFileName() + " should fix this.");
-            }
-
-            // Force inlining when parsing replacements
-            return new InlineInfo(method, true, true);
-        } else {
-            assert nodeIntrinsification.getIntrinsic(method) == null : String.format("@%s method %s must only be called from within a replacement%n%s", NodeIntrinsic.class.getSimpleName(),
-                            method.format("%h.%n"), b);
-            if (InlineDuringParsing.getValue() && method.hasBytecodes() && method.getCode().length <= TrivialInliningSize.getValue() && b.getDepth() < InlineDuringParsingMaxDepth.getValue()) {
-                return new InlineInfo(method, false, false);
-            }
-        }
-        return null;
-    }
-
-    public void notifyOfNoninlinedInvoke(GraphBuilderContext b, ResolvedJavaMethod method, Invoke invoke) {
-        if (b.parsingReplacement()) {
-            boolean compilingSnippet = b.getRootMethod().getAnnotation(Snippet.class) != null;
-            Replacement replacement = b.getReplacement();
-            assert compilingSnippet : format("All calls in the replacement %s must be inlined or intrinsified: found call to %s", replacement.getReplacementMethod().format("%H.%n(%p)"),
-                            method.format("%h.%n(%p)"));
-        }
-    }
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInvocationPlugins.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInvocationPlugins.java	Fri Mar 27 17:02:53 2015 +0100
@@ -22,14 +22,22 @@
  */
 package com.oracle.graal.hotspot.meta;
 
+import static com.oracle.graal.hotspot.meta.HotSpotMethodHandleAccessProvider.*;
+
+import java.lang.invoke.*;
+import java.util.*;
+
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.MethodHandleAccessProvider.IntrinsicMethod;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.graphbuilderconf.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.phases.*;
+import com.oracle.graal.hotspot.replacements.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.replacements.StandardGraphBuilderPlugins.BoxPlugin;
 
 /**
@@ -37,10 +45,12 @@
  */
 final class HotSpotInvocationPlugins extends InvocationPlugins {
     final HotSpotVMConfig config;
+    final MethodHandleAccessProvider methodHandleAccess;
 
-    public HotSpotInvocationPlugins(HotSpotVMConfig config, MetaAccessProvider metaAccess) {
+    public HotSpotInvocationPlugins(HotSpotVMConfig config, MetaAccessProvider metaAccess, MethodHandleAccessProvider methodHandleAccess) {
         super(metaAccess);
         this.config = config;
+        this.methodHandleAccess = methodHandleAccess;
     }
 
     @Override
@@ -74,6 +84,68 @@
         super.register(plugin, declaringClass, name, argumentTypes);
     }
 
+    private ResolvedJavaType methodHandleClass;
+    private final Map<IntrinsicMethod, InvocationPlugin> methodHandlePlugins = new EnumMap<>(IntrinsicMethod.class);
+
+    @Override
+    public InvocationPlugin lookupInvocation(ResolvedJavaMethod method) {
+        if (methodHandleClass == null) {
+            methodHandleClass = metaAccess.lookupJavaType(MethodHandle.class);
+        }
+        if (method.getDeclaringClass().equals(methodHandleClass)) {
+            HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) method;
+            int intrinsicId = hsMethod.intrinsicId();
+            if (intrinsicId != 0) {
+                /*
+                 * The methods of MethodHandle that need substitution are signature-polymorphic,
+                 * i.e., the VM replicates them for every signature that they are actually used for.
+                 */
+                IntrinsicMethod intrinsicMethod = getMethodHandleIntrinsic(intrinsicId);
+                if (intrinsicMethod != null) {
+                    InvocationPlugin plugin = methodHandlePlugins.get(intrinsicMethod);
+                    if (plugin == null) {
+                        plugin = new InvocationPlugin() {
+                            public boolean applyPolymorphic(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode... argsIncludingReceiver) {
+                                InvokeKind invokeKind = b.getInvokeKind();
+                                if (invokeKind != InvokeKind.Static) {
+                                    receiver.get();
+                                }
+                                JavaType invokeReturnType = b.getInvokeReturnType();
+                                InvokeNode invoke = MethodHandleNode.tryResolveTargetInvoke(b.getAssumptions(), b.getConstantReflection().getMethodHandleAccess(), intrinsicMethod, targetMethod,
+                                                b.bci(), invokeReturnType, argsIncludingReceiver);
+                                if (invoke == null) {
+                                    MethodHandleNode methodHandleNode = new MethodHandleNode(intrinsicMethod, invokeKind, targetMethod, b.bci(), invokeReturnType, argsIncludingReceiver);
+                                    if (invokeReturnType.getKind() == Kind.Void) {
+                                        b.add(methodHandleNode);
+                                    } else {
+                                        b.addPush(methodHandleNode);
+                                    }
+                                } else {
+                                    CallTargetNode callTarget = invoke.callTarget();
+                                    NodeInputList<ValueNode> argumentsList = callTarget.arguments();
+                                    ValueNode[] args = argumentsList.toArray(new ValueNode[argumentsList.size()]);
+                                    for (ValueNode arg : args) {
+                                        b.recursiveAppend(arg);
+                                    }
+                                    b.handleReplacedInvoke(invoke.getInvokeKind(), callTarget.targetMethod(), args);
+                                }
+                                return true;
+                            }
+
+                            public boolean isSignaturePolymorphic() {
+                                return true;
+                            }
+                        };
+                        methodHandlePlugins.put(intrinsicMethod, plugin);
+                    }
+                    return plugin;
+                }
+            }
+
+        }
+        return super.lookupInvocation(method);
+    }
+
     @Override
     public void checkNewNodes(GraphBuilderContext b, InvocationPlugin plugin, NodeIterable<Node> newNodes) {
         if (GraalOptions.ImmutableCode.getValue()) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoadFieldPlugin.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoadFieldPlugin.java	Fri Mar 27 17:02:53 2015 +0100
@@ -75,8 +75,7 @@
                 // HotSpotInlineInvokePlugin.notifyOfNoninlinedInvoke). Direct use of
                 // assertions in intrinsics is forbidden.
                 assert b.getMethod().getAnnotation(MethodSubstitution.class) == null : "cannot use assertions in " + b.getMethod().format("%H.%n(%p)");
-                ConstantNode trueNode = b.append(ConstantNode.forBoolean(true));
-                b.push(trueNode.getKind().getStackKind(), trueNode);
+                b.addPush(ConstantNode.forBoolean(true));
                 return true;
             }
             return tryReadField(b, staticField, null);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoadIndexedPlugin.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoadIndexedPlugin.java	Fri Mar 27 17:02:53 2015 +0100
@@ -54,9 +54,9 @@
                  */
                 Stamp componentStamp = wordTypes.getWordStamp(arrayType.getComponentType());
                 if (componentStamp instanceof MetaspacePointerStamp) {
-                    b.push(elementKind, b.append(new LoadIndexedPointerNode(componentStamp, array, index)));
+                    b.addPush(elementKind, new LoadIndexedPointerNode(componentStamp, array, index));
                 } else {
-                    b.push(elementKind, b.append(new LoadIndexedNode(array, index, wordTypes.getWordKind())));
+                    b.addPush(elementKind, new LoadIndexedNode(array, index, wordTypes.getWordKind()));
                 }
                 return true;
             }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodHandleAccessProvider.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodHandleAccessProvider.java	Fri Mar 27 17:02:53 2015 +0100
@@ -98,18 +98,23 @@
     public IntrinsicMethod lookupMethodHandleIntrinsic(ResolvedJavaMethod method) {
         int intrinsicId = ((HotSpotResolvedJavaMethodImpl) method).intrinsicId();
         if (intrinsicId != 0) {
-            HotSpotVMConfig config = runtime().getConfig();
-            if (intrinsicId == config.vmIntrinsicInvokeBasic) {
-                return IntrinsicMethod.INVOKE_BASIC;
-            } else if (intrinsicId == config.vmIntrinsicLinkToInterface) {
-                return IntrinsicMethod.LINK_TO_INTERFACE;
-            } else if (intrinsicId == config.vmIntrinsicLinkToSpecial) {
-                return IntrinsicMethod.LINK_TO_SPECIAL;
-            } else if (intrinsicId == config.vmIntrinsicLinkToStatic) {
-                return IntrinsicMethod.LINK_TO_STATIC;
-            } else if (intrinsicId == config.vmIntrinsicLinkToVirtual) {
-                return IntrinsicMethod.LINK_TO_VIRTUAL;
-            }
+            return getMethodHandleIntrinsic(intrinsicId);
+        }
+        return null;
+    }
+
+    public static IntrinsicMethod getMethodHandleIntrinsic(int intrinsicId) {
+        HotSpotVMConfig config = runtime().getConfig();
+        if (intrinsicId == config.vmIntrinsicInvokeBasic) {
+            return IntrinsicMethod.INVOKE_BASIC;
+        } else if (intrinsicId == config.vmIntrinsicLinkToInterface) {
+            return IntrinsicMethod.LINK_TO_INTERFACE;
+        } else if (intrinsicId == config.vmIntrinsicLinkToSpecial) {
+            return IntrinsicMethod.LINK_TO_SPECIAL;
+        } else if (intrinsicId == config.vmIntrinsicLinkToStatic) {
+            return IntrinsicMethod.LINK_TO_STATIC;
+        } else if (intrinsicId == config.vmIntrinsicLinkToVirtual) {
+            return IntrinsicMethod.LINK_TO_VIRTUAL;
         }
         return null;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectTypeImpl.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectTypeImpl.java	Fri Mar 27 17:02:53 2015 +0100
@@ -160,8 +160,9 @@
                 if (leafConcreteSubtype != null) {
                     assert !leafConcreteSubtype.getResult().equals(implementor);
                     AssumptionResult<ResolvedJavaType> newResult = new AssumptionResult<>(leafConcreteSubtype.getResult(), new ConcreteSubtype(this, implementor));
+                    // Accumulate leaf assumptions and return the combined result.
                     newResult.add(leafConcreteSubtype);
-                    return leafConcreteSubtype;
+                    return newResult;
                 }
                 return null;
             }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java	Fri Mar 27 17:02:53 2015 +0100
@@ -132,7 +132,11 @@
     }
 
     public LIRSuites createLIRSuites() {
-        return Suites.createDefaultLIRSuites();
+        LIRSuites suites = Suites.createDefaultLIRSuites();
+        String profileInstructions = HotSpotBackend.Options.ASMInstructionProfiling.getValue();
+        if (profileInstructions != null) {
+            suites.getPostAllocationOptimizationStage().appendPhase(new HotSpotInstructionProfiling(profileInstructions));
+        }
+        return suites;
     }
-
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotWordOperationPlugin.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotWordOperationPlugin.java	Fri Mar 27 17:02:53 2015 +0100
@@ -79,10 +79,10 @@
                 assert right.stamp() instanceof MetaspacePointerStamp : right + " " + right.stamp();
                 assert opcode == POINTER_EQ || opcode == POINTER_NE;
 
-                PointerEqualsNode comparison = b.append(new PointerEqualsNode(left, right));
-                ValueNode eqValue = b.append(forBoolean(opcode == POINTER_EQ));
-                ValueNode neValue = b.append(forBoolean(opcode == POINTER_NE));
-                b.push(returnStackKind, b.append(new ConditionalNode(comparison, eqValue, neValue)));
+                PointerEqualsNode comparison = b.add(new PointerEqualsNode(left, right));
+                ValueNode eqValue = b.add(forBoolean(opcode == POINTER_EQ));
+                ValueNode neValue = b.add(forBoolean(opcode == POINTER_NE));
+                b.addPush(returnStackKind, new ConditionalNode(comparison, eqValue, neValue));
                 break;
 
             case IS_NULL:
@@ -90,23 +90,23 @@
                 ValueNode pointer = args[0];
                 assert pointer.stamp() instanceof MetaspacePointerStamp;
 
-                IsNullNode isNull = b.append(new IsNullNode(pointer));
-                b.push(returnStackKind, b.append(new ConditionalNode(isNull, b.append(forBoolean(true)), b.append(forBoolean(false)))));
+                IsNullNode isNull = b.add(new IsNullNode(pointer));
+                b.addPush(returnStackKind, new ConditionalNode(isNull, b.add(forBoolean(true)), b.add(forBoolean(false))));
                 break;
 
             case FROM_POINTER:
                 assert args.length == 1;
-                b.push(returnStackKind, b.append(new PointerCastNode(StampFactory.forKind(wordKind), args[0])));
+                b.addPush(returnStackKind, new PointerCastNode(StampFactory.forKind(wordKind), args[0]));
                 break;
 
             case TO_KLASS_POINTER:
                 assert args.length == 1;
-                b.push(returnStackKind, b.append(new PointerCastNode(KlassPointerStamp.klass(), args[0])));
+                b.addPush(returnStackKind, new PointerCastNode(KlassPointerStamp.klass(), args[0]));
                 break;
 
             case TO_METHOD_POINTER:
                 assert args.length == 1;
-                b.push(returnStackKind, b.append(new PointerCastNode(MethodPointerStamp.method(), args[0])));
+                b.addPush(returnStackKind, new PointerCastNode(MethodPointerStamp.method(), args[0]));
                 break;
 
             case READ_KLASS_POINTER:
@@ -118,7 +118,7 @@
                 } else {
                     location = makeLocation(b, args[1], args[2]);
                 }
-                ReadNode read = b.append(new ReadNode(args[0], location, readStamp, BarrierType.NONE));
+                ReadNode read = b.add(new ReadNode(args[0], location, readStamp, BarrierType.NONE));
                 /*
                  * The read must not float outside its block otherwise it may float above an
                  * explicit zero check on its base address.
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassCastNode.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassCastNode.java	Fri Mar 27 17:02:53 2015 +0100
@@ -25,24 +25,23 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.hotspot.replacements.*;
 import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.replacements.nodes.*;
 
 /**
  * {@link MacroNode Macro node} for {@link Class#cast(Object)}.
- *
- * @see HotSpotClassSubstitutions#cast(Class, Object)
  */
 @NodeInfo
 public final class ClassCastNode extends MacroStateSplitNode implements Canonicalizable.Binary<ValueNode> {
 
     public static final NodeClass<ClassCastNode> TYPE = NodeClass.create(ClassCastNode.class);
 
-    public ClassCastNode(Invoke invoke) {
-        super(TYPE, invoke);
+    public ClassCastNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, JavaType returnType, ValueNode receiver, ValueNode object) {
+        super(TYPE, invokeKind, targetMethod, bci, returnType, receiver, object);
     }
 
     private ValueNode getJavaClass() {
@@ -63,12 +62,18 @@
 
     @Override
     public ValueNode canonical(CanonicalizerTool tool, ValueNode forJavaClass, ValueNode forObject) {
-        if (forJavaClass.isConstant()) {
-            ResolvedJavaType type = tool.getConstantReflection().asJavaType(forJavaClass.asConstant());
+        ValueNode folded = tryFold(forJavaClass, forObject, tool.getConstantReflection(), null);
+        return folded != null ? folded : this;
+    }
+
+    public static ValueNode tryFold(ValueNode javaClass, ValueNode object, ConstantReflectionProvider constantReflection, Assumptions assumptions) {
+        ValueNode value = GraphUtil.originalValue(javaClass);
+        if (value.isConstant()) {
+            ResolvedJavaType type = constantReflection.asJavaType(value.asConstant());
             if (type != null && !type.isPrimitive()) {
-                return new CheckCastNode(type, forObject, null, false);
+                return CheckCastNode.create(type, object, null, false, assumptions);
             }
         }
-        return this;
+        return null;
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetClassLoader0Node.java	Fri Mar 27 15:43:31 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +0,0 @@
-/*
- * 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.hotspot.nodes;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.hotspot.replacements.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.replacements.nodes.*;
-
-/**
- * {@link MacroNode Macro node} for {@link Class#getClassLoader0()}.
- *
- * @see HotSpotClassSubstitutions#getClassLoader0(Class)
- */
-@SuppressWarnings("javadoc")
-@NodeInfo
-public final class ClassGetClassLoader0Node extends MacroStateSplitNode implements Canonicalizable {
-
-    public static final NodeClass<ClassGetClassLoader0Node> TYPE = NodeClass.create(ClassGetClassLoader0Node.class);
-
-    public ClassGetClassLoader0Node(Invoke invoke) {
-        super(TYPE, invoke);
-    }
-
-    private ValueNode getJavaClass() {
-        return arguments.get(0);
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        ValueNode javaClass = getJavaClass();
-        if (javaClass.isConstant() && !GraalOptions.ImmutableCode.getValue()) {
-            HotSpotObjectConstant c = (HotSpotObjectConstant) javaClass.asConstant();
-            JavaConstant classLoader = c.getClassLoader();
-            if (classLoader != null) {
-                return ConstantNode.forConstant(classLoader, tool.getMetaAccess());
-            }
-        }
-        return this;
-    }
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetComponentTypeNode.java	Fri Mar 27 15:43:31 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.nodes;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.hotspot.replacements.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.replacements.nodes.*;
-
-/**
- * {@link MacroNode Macro node} for {@link Class#getComponentType()}.
- *
- * @see HotSpotClassSubstitutions#getComponentType(Class)
- */
-@NodeInfo
-public final class ClassGetComponentTypeNode extends MacroNode implements Canonicalizable {
-
-    public static final NodeClass<ClassGetComponentTypeNode> TYPE = NodeClass.create(ClassGetComponentTypeNode.class);
-
-    public ClassGetComponentTypeNode(Invoke invoke) {
-        super(TYPE, invoke);
-    }
-
-    private ValueNode getJavaClass() {
-        return arguments.get(0);
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        ValueNode javaClass = getJavaClass();
-        if (javaClass.isConstant()) {
-            HotSpotObjectConstant c = (HotSpotObjectConstant) javaClass.asConstant();
-            JavaConstant componentType = c.getComponentType();
-            if (componentType != null) {
-                return ConstantNode.forConstant(componentType, tool.getMetaAccess());
-            }
-        }
-        return this;
-    }
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetModifiersNode.java	Fri Mar 27 15:43:31 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +0,0 @@
-/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.nodes;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.hotspot.replacements.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.replacements.nodes.*;
-
-/**
- * {@link MacroNode Macro node} for {@link Class#getModifiers()}.
- *
- * @see HotSpotClassSubstitutions#getModifiers(Class)
- */
-@NodeInfo
-public final class ClassGetModifiersNode extends MacroNode implements Canonicalizable {
-    public static final NodeClass<ClassGetModifiersNode> TYPE = NodeClass.create(ClassGetModifiersNode.class);
-
-    public ClassGetModifiersNode(Invoke invoke) {
-        super(TYPE, invoke);
-    }
-
-    private ValueNode getJavaClass() {
-        return arguments.get(0);
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        ValueNode javaClass = getJavaClass();
-        if (javaClass.isConstant()) {
-            ConstantReflectionProvider constantReflection = tool.getConstantReflection();
-            ResolvedJavaType type = constantReflection.asJavaType(javaClass.asConstant());
-            if (type != null) {
-                return ConstantNode.forInt(type.getModifiers());
-            }
-        }
-        return this;
-    }
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetSuperclassNode.java	Fri Mar 27 15:43:31 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.nodes;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.hotspot.replacements.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.replacements.nodes.*;
-
-/**
- * {@link MacroNode Macro node} for {@link Class#getSuperclass()}.
- *
- * @see HotSpotClassSubstitutions#getSuperclass(Class)
- */
-@NodeInfo
-public final class ClassGetSuperclassNode extends MacroNode implements Canonicalizable {
-
-    public static final NodeClass<ClassGetSuperclassNode> TYPE = NodeClass.create(ClassGetSuperclassNode.class);
-
-    public ClassGetSuperclassNode(Invoke invoke) {
-        super(TYPE, invoke);
-    }
-
-    private ValueNode getJavaClass() {
-        return arguments.get(0);
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        ValueNode javaClass = getJavaClass();
-        if (javaClass.isConstant()) {
-            HotSpotObjectConstant c = (HotSpotObjectConstant) javaClass.asConstant();
-            JavaConstant superclass = c.getSuperclass();
-            if (superclass != null) {
-                return ConstantNode.forConstant(superclass, tool.getMetaAccess());
-            }
-        }
-        return this;
-    }
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassIsArrayNode.java	Fri Mar 27 15:43:31 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.nodes;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.hotspot.replacements.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.replacements.nodes.*;
-
-/**
- * {@link MacroNode Macro node} for {@link Class#isArray()}.
- *
- * @see HotSpotClassSubstitutions#isArray(Class)
- */
-@NodeInfo
-public final class ClassIsArrayNode extends MacroNode implements Canonicalizable {
-
-    public static final NodeClass<ClassIsArrayNode> TYPE = NodeClass.create(ClassIsArrayNode.class);
-
-    public ClassIsArrayNode(Invoke invoke) {
-        super(TYPE, invoke);
-    }
-
-    private ValueNode getJavaClass() {
-        return arguments.get(0);
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        ValueNode javaClass = getJavaClass();
-        if (javaClass.isConstant()) {
-            ConstantReflectionProvider constantReflection = tool.getConstantReflection();
-            ResolvedJavaType type = constantReflection.asJavaType(javaClass.asConstant());
-            if (type != null) {
-                return ConstantNode.forBoolean(type.isArray());
-            }
-        }
-        return this;
-    }
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassIsInterfaceNode.java	Fri Mar 27 15:43:31 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.nodes;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.hotspot.replacements.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.replacements.nodes.*;
-
-/**
- * {@link MacroNode Macro node} for {@link Class#isInterface()}.
- *
- * @see HotSpotClassSubstitutions#isInterface(Class)
- */
-@NodeInfo
-public final class ClassIsInterfaceNode extends MacroNode implements Canonicalizable {
-
-    public static final NodeClass<ClassIsInterfaceNode> TYPE = NodeClass.create(ClassIsInterfaceNode.class);
-
-    public ClassIsInterfaceNode(Invoke invoke) {
-        super(TYPE, invoke);
-    }
-
-    private ValueNode getJavaClass() {
-        return arguments.get(0);
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        ValueNode javaClass = getJavaClass();
-        if (javaClass.isConstant()) {
-            ConstantReflectionProvider constantReflection = tool.getConstantReflection();
-            ResolvedJavaType type = constantReflection.asJavaType(javaClass.asConstant());
-            if (type != null) {
-                return ConstantNode.forBoolean(type.isInterface());
-            }
-        }
-        return this;
-    }
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassIsPrimitiveNode.java	Fri Mar 27 15:43:31 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.nodes;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.hotspot.replacements.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.replacements.nodes.*;
-
-/**
- * {@link MacroNode Macro node} for {@link Class#isPrimitive()}.
- *
- * @see HotSpotClassSubstitutions#isPrimitive(Class)
- */
-@NodeInfo
-public final class ClassIsPrimitiveNode extends MacroNode implements Canonicalizable {
-
-    public static final NodeClass<ClassIsPrimitiveNode> TYPE = NodeClass.create(ClassIsPrimitiveNode.class);
-
-    public ClassIsPrimitiveNode(Invoke invoke) {
-        super(TYPE, invoke);
-    }
-
-    private ValueNode getJavaClass() {
-        return arguments.get(0);
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        ValueNode javaClass = getJavaClass();
-        if (javaClass.isConstant()) {
-            ConstantReflectionProvider constantReflection = tool.getConstantReflection();
-            ResolvedJavaType type = constantReflection.asJavaType(javaClass.asConstant());
-            if (type != null) {
-                return ConstantNode.forBoolean(type.isPrimitive());
-            }
-        }
-        return this;
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassQueryNode.java	Fri Mar 27 17:02:53 2015 +0100
@@ -0,0 +1,127 @@
+/*
+ * 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.hotspot.nodes;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.util.*;
+import com.oracle.graal.replacements.nodes.*;
+
+/**
+ * {@link MacroNode Macro node} for some basic query methods in {@link Class}.
+ */
+@NodeInfo
+public final class ClassQueryNode extends MacroStateSplitNode implements Canonicalizable {
+
+    /**
+     * The query methods in {@link Class} supported by {@link ClassQueryNode}.
+     */
+    public enum Query {
+        getClassLoader0(Kind.Object),
+        getComponentType(Kind.Object),
+        getSuperclass(Kind.Object),
+        getModifiers(Kind.Int),
+        isArray(Kind.Boolean),
+        isInterface(Kind.Boolean),
+        isPrimitive(Kind.Boolean);
+
+        private Query(Kind returnKind) {
+            this.returnKind = returnKind;
+        }
+
+        public final Kind returnKind;
+    }
+
+    public static final NodeClass<ClassQueryNode> TYPE = NodeClass.create(ClassQueryNode.class);
+
+    protected final Query query;
+
+    public ClassQueryNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, Query query, int bci, JavaType returnType, ValueNode receiver) {
+        super(TYPE, invokeKind, targetMethod, bci, returnType, receiver);
+        this.query = query;
+        assert query.returnKind == targetMethod.getSignature().getReturnKind();
+    }
+
+    private ValueNode getJavaClass() {
+        return arguments.get(0);
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        ValueNode value = tryFold(getJavaClass(), query, tool.getMetaAccess(), tool.getConstantReflection());
+        return value == null ? this : value;
+    }
+
+    public static ValueNode tryFold(ValueNode javaClass, Query query, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection) {
+        ValueNode value = GraphUtil.originalValue(javaClass);
+        if (value != null && value.isConstant()) {
+            if (query.returnKind == Kind.Object) {
+                if (GraalOptions.ImmutableCode.getValue()) {
+                    return null;
+                }
+                HotSpotObjectConstant c = (HotSpotObjectConstant) value.asConstant();
+                JavaConstant answer;
+                switch (query) {
+                    case getClassLoader0:
+                        answer = c.getClassLoader();
+                        break;
+                    case getComponentType:
+                        answer = c.getComponentType();
+                        break;
+                    case getSuperclass:
+                        answer = c.getSuperclass();
+                        break;
+                    default:
+                        GraalInternalError.shouldNotReachHere();
+                        answer = null;
+                }
+                if (answer != null) {
+                    return ConstantNode.forConstant(answer, metaAccess);
+                }
+            } else {
+                ResolvedJavaType type = constantReflection.asJavaType(value.asConstant());
+                if (type != null) {
+                    switch (query) {
+                        case isArray:
+                            return ConstantNode.forBoolean(type.isArray());
+                        case isPrimitive:
+                            return ConstantNode.forBoolean(type.isPrimitive());
+                        case isInterface:
+                            return ConstantNode.forBoolean(type.isInterface());
+                        case getModifiers:
+                            return ConstantNode.forInt(type.getModifiers());
+                        default:
+                            GraalInternalError.shouldNotReachHere();
+                    }
+                }
+            }
+        }
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ResolvedMethodHandleCallTargetNode.java	Fri Mar 27 17:02:53 2015 +0100
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.nodes;
+
+import java.lang.invoke.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.hotspot.replacements.*;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.spi.*;
+
+/**
+ * A call target that replaces itself in the graph when being lowered by restoring the original
+ * {@link MethodHandle} invocation target. This is required for when a {@link MethodHandle} call was
+ * resolved to a constant target but the target was not inlined. In that case, the original
+ * invocation must be restored with all of its original arguments. Why? HotSpot linkage for
+ * {@link MethodHandle} intrinsics (see {@code MethodHandles::generate_method_handle_dispatch})
+ * expects certain implicit arguments to be on the stack such as the MemberName suffix argument for
+ * a call to one of the MethodHandle.linkTo* methods. An
+ * {@linkplain MethodHandleNode#tryResolveTargetInvoke resolved} {@link MethodHandle} invocation
+ * drops these arguments which means the interpreter won't find them.
+ */
+@NodeInfo
+public final class ResolvedMethodHandleCallTargetNode extends MethodCallTargetNode implements Lowerable {
+
+    public static final NodeClass<ResolvedMethodHandleCallTargetNode> TYPE = NodeClass.create(ResolvedMethodHandleCallTargetNode.class);
+    protected final ResolvedJavaMethod originalTargetMethod;
+    protected final JavaType originalReturnType;
+    @Input NodeInputList<ValueNode> originalArguments;
+
+    public ResolvedMethodHandleCallTargetNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] arguments, JavaType returnType, ResolvedJavaMethod originalTargetMethod,
+                    ValueNode[] originalArguments, JavaType originalReturnType) {
+        super(TYPE, invokeKind, targetMethod, arguments, returnType);
+        this.originalTargetMethod = originalTargetMethod;
+        this.originalReturnType = originalReturnType;
+        this.originalArguments = new NodeInputList<>(this, originalArguments);
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        InvokeKind replacementInvokeKind = originalTargetMethod.isStatic() ? InvokeKind.Static : InvokeKind.Special;
+        MethodCallTargetNode replacement = graph().add(
+                        new MethodCallTargetNode(replacementInvokeKind, originalTargetMethod, originalArguments.toArray(new ValueNode[originalArguments.size()]), originalReturnType));
+
+        // Replace myself...
+        this.replaceAndDelete(replacement);
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        throw GraalInternalError.shouldNotReachHere("should have replaced itself");
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CallSiteSubstitutions.java	Fri Mar 27 15:43:31 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.replacements;
-
-import java.lang.invoke.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.api.runtime.*;
-import com.oracle.graal.nodes.spi.*;
-
-@ServiceProvider(ReplacementsProvider.class)
-public class CallSiteSubstitutions implements ReplacementsProvider {
-
-    @Override
-    public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider loweringProvider, SnippetReflectionProvider snippetReflection, Replacements replacements, TargetDescription target) {
-        replacements.registerSubstitutions(ConstantCallSite.class, ConstantCallSiteSubstitutions.class);
-        replacements.registerSubstitutions(MutableCallSite.class, MutableCallSiteSubstitutions.class);
-        replacements.registerSubstitutions(VolatileCallSite.class, VolatileCallSiteSubstitutions.class);
-    }
-
-    @ClassSubstitution(ConstantCallSite.class)
-    private static class ConstantCallSiteSubstitutions {
-
-        @MacroSubstitution(isStatic = false, macro = CallSiteTargetNode.class)
-        public static native MethodHandle getTarget(ConstantCallSite callSite);
-    }
-
-    @ClassSubstitution(MutableCallSite.class)
-    private static class MutableCallSiteSubstitutions {
-
-        @MacroSubstitution(isStatic = false, macro = CallSiteTargetNode.class)
-        public static native MethodHandle getTarget(MutableCallSite callSite);
-    }
-
-    @ClassSubstitution(VolatileCallSite.class)
-    private static class VolatileCallSiteSubstitutions {
-
-        @MacroSubstitution(isStatic = false, macro = CallSiteTargetNode.class)
-        public static native MethodHandle getTarget(VolatileCallSite callSite);
-    }
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CallSiteTargetNode.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CallSiteTargetNode.java	Fri Mar 27 17:02:53 2015 +0100
@@ -27,8 +27,10 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.replacements.nodes.*;
 
 @NodeInfo
@@ -36,18 +38,19 @@
 
     public static final NodeClass<CallSiteTargetNode> TYPE = NodeClass.create(CallSiteTargetNode.class);
 
-    public CallSiteTargetNode(Invoke invoke) {
-        super(TYPE, invoke);
+    public CallSiteTargetNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, JavaType returnType, ValueNode receiver) {
+        super(TYPE, invokeKind, targetMethod, bci, returnType, receiver);
     }
 
     private ValueNode getCallSite() {
         return arguments.get(0);
     }
 
-    private ConstantNode getConstantCallTarget(MetaAccessProvider metaAccess) {
-        if (getCallSite().isConstant() && !getCallSite().isNullConstant()) {
-            HotSpotObjectConstant c = (HotSpotObjectConstant) getCallSite().asConstant();
-            JavaConstant target = c.getCallSiteTarget(graph().getAssumptions());
+    public static ConstantNode tryFold(ValueNode initialCallSite, MetaAccessProvider metaAccess, Assumptions assumptions) {
+        ValueNode callSite = GraphUtil.originalValue(initialCallSite);
+        if (callSite.isConstant() && !callSite.isNullConstant()) {
+            HotSpotObjectConstant c = (HotSpotObjectConstant) callSite.asConstant();
+            JavaConstant target = c.getCallSiteTarget(assumptions);
             if (target != null) {
                 return ConstantNode.forConstant(target, metaAccess);
             }
@@ -57,7 +60,7 @@
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
-        ConstantNode target = getConstantCallTarget(tool.getMetaAccess());
+        ConstantNode target = tryFold(getCallSite(), tool.getMetaAccess(), graph().getAssumptions());
         if (target != null) {
             return target;
         }
@@ -67,7 +70,7 @@
 
     @Override
     public void lower(LoweringTool tool) {
-        ConstantNode target = getConstantCallTarget(tool.getMetaAccess());
+        ConstantNode target = tryFold(getCallSite(), tool.getMetaAccess(), graph().getAssumptions());
 
         if (target != null) {
             graph().replaceFixedWithFloating(this, target);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotClassSubstitutions.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotClassSubstitutions.java	Fri Mar 27 17:02:53 2015 +0100
@@ -27,10 +27,8 @@
 import java.lang.reflect.*;
 
 import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.hotspot.word.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.word.*;
 
 /**
@@ -39,7 +37,6 @@
 @ClassSubstitution(java.lang.Class.class)
 public class HotSpotClassSubstitutions {
 
-    @MacroSubstitution(macro = ClassGetModifiersNode.class, isStatic = false)
     @MethodSubstitution(isStatic = false, forced = true)
     public static int getModifiers(final Class<?> thisObj) {
         KlassPointer klass = ClassGetHubNode.readClass(thisObj);
@@ -51,8 +48,6 @@
         }
     }
 
-    // This MacroSubstitution should be removed once non-null klass pointers can be optimized
-    @MacroSubstitution(macro = ClassIsInterfaceNode.class, isStatic = false)
     @MethodSubstitution(isStatic = false, forced = true)
     public static boolean isInterface(final Class<?> thisObj) {
         KlassPointer klass = ClassGetHubNode.readClass(thisObj);
@@ -64,8 +59,6 @@
         }
     }
 
-    // This MacroSubstitution should be removed once non-null klass pointers can be optimized
-    @MacroSubstitution(macro = ClassIsArrayNode.class, isStatic = false)
     @MethodSubstitution(isStatic = false, forced = true)
     public static boolean isArray(final Class<?> thisObj) {
         KlassPointer klass = ClassGetHubNode.readClass(thisObj);
@@ -76,18 +69,14 @@
         }
     }
 
-    // This MacroSubstitution should be removed once non-null klass pointers can be optimized
-    @MacroSubstitution(macro = ClassIsPrimitiveNode.class, isStatic = false)
     @MethodSubstitution(isStatic = false, forced = true)
     public static boolean isPrimitive(final Class<?> thisObj) {
         KlassPointer klass = ClassGetHubNode.readClass(thisObj);
         return klass.isNull();
     }
 
-    @MacroSubstitution(macro = ClassGetClassLoader0Node.class, isStatic = false)
     public static native ClassLoader getClassLoader0(Class<?> thisObj);
 
-    @MacroSubstitution(macro = ClassGetSuperclassNode.class, isStatic = false)
     @MethodSubstitution(isStatic = false)
     public static Class<?> getSuperclass(final Class<?> thisObj) {
         KlassPointer klass = ClassGetHubNode.readClass(thisObj);
@@ -113,7 +102,6 @@
         return PiNode.asNonNullClass(klass.readObject(classMirrorOffset(), CLASS_MIRROR_LOCATION));
     }
 
-    @MacroSubstitution(macro = ClassGetComponentTypeNode.class, isStatic = false)
     @MethodSubstitution(isStatic = false)
     public static Class<?> getComponentType(final Class<?> thisObj) {
         KlassPointer klass = ClassGetHubNode.readClass(thisObj);
@@ -124,7 +112,4 @@
         }
         return null;
     }
-
-    @MacroSubstitution(macro = ClassCastNode.class, isStatic = false)
-    public static native Object cast(final Class<?> thisObj, Object obj);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleNode.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleNode.java	Fri Mar 27 17:02:53 2015 +0100
@@ -32,6 +32,7 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
@@ -47,52 +48,50 @@
 public final class MethodHandleNode extends MacroStateSplitNode implements Simplifiable {
     public static final NodeClass<MethodHandleNode> TYPE = NodeClass.create(MethodHandleNode.class);
 
-    // Replacement method data
-    protected ResolvedJavaMethod replacementTargetMethod;
-    protected JavaType replacementReturnType;
-    @Input NodeInputList<ValueNode> replacementArguments;
+    protected final IntrinsicMethod intrinsicMethod;
 
-    public MethodHandleNode(Invoke invoke) {
-        super(TYPE, invoke);
-        MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
-        // See if we need to save some replacement method data.
-        if (callTarget instanceof SelfReplacingMethodCallTargetNode) {
-            SelfReplacingMethodCallTargetNode selfReplacingMethodCallTargetNode = (SelfReplacingMethodCallTargetNode) callTarget;
-            replacementTargetMethod = selfReplacingMethodCallTargetNode.replacementTargetMethod();
-            replacementReturnType = selfReplacingMethodCallTargetNode.replacementReturnType();
-            replacementArguments = selfReplacingMethodCallTargetNode.replacementArguments();
-        } else {
-            // NodeInputList can't be null.
-            replacementArguments = new NodeInputList<>(this);
-        }
+    public MethodHandleNode(IntrinsicMethod intrinsicMethod, InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, JavaType returnType, ValueNode... arguments) {
+        super(TYPE, invokeKind, targetMethod, bci, returnType, arguments);
+        this.intrinsicMethod = intrinsicMethod;
     }
 
     /**
-     * Returns the method handle method intrinsic identifier for the provided method, or
-     * {@code null} if the method is not a method that can be handled by this class.
+     * Attempts to transform application of an intrinsifiable {@link MethodHandle} method into an
+     * invocation on another method with possibly transformed arguments.
+     *
+     * @param assumptions object for recording any speculations made during the transformation
+     * @param methodHandleAccess objects for accessing the implementation internals of a
+     *            {@link MethodHandle}
+     * @param intrinsicMethod denotes the intrinsifiable {@link MethodHandle} method being processed
+     * @param bci the BCI of the original {@link MethodHandle} call
+     * @param returnType return type of the original {@link MethodHandle} call
+     * @param arguments arguments to the original {@link MethodHandle} call
+     * @return a more direct invocation derived from the {@link MethodHandle} call or null
      */
-    public static IntrinsicMethod lookupMethodHandleIntrinsic(ResolvedJavaMethod method, MethodHandleAccessProvider methodHandleAccess) {
-        return methodHandleAccess.lookupMethodHandleIntrinsic(method);
+    public static InvokeNode tryResolveTargetInvoke(Assumptions assumptions, MethodHandleAccessProvider methodHandleAccess, IntrinsicMethod intrinsicMethod, ResolvedJavaMethod original, int bci,
+                    JavaType returnType, ValueNode... arguments) {
+        switch (intrinsicMethod) {
+            case INVOKE_BASIC:
+                return getInvokeBasicTarget(assumptions, intrinsicMethod, methodHandleAccess, original, bci, returnType, arguments);
+            case LINK_TO_STATIC:
+            case LINK_TO_SPECIAL:
+            case LINK_TO_VIRTUAL:
+            case LINK_TO_INTERFACE:
+                return getLinkToTarget(assumptions, intrinsicMethod, methodHandleAccess, original, bci, returnType, arguments);
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
     }
 
     @Override
     public void simplify(SimplifierTool tool) {
-        InvokeNode invoke;
-        IntrinsicMethod intrinsicMethod = lookupMethodHandleIntrinsic(targetMethod, tool.getConstantReflection().getMethodHandleAccess());
-        switch (intrinsicMethod) {
-            case INVOKE_BASIC:
-                invoke = getInvokeBasicTarget(tool, intrinsicMethod);
-                break;
-            case LINK_TO_STATIC:
-            case LINK_TO_SPECIAL:
-            case LINK_TO_VIRTUAL:
-            case LINK_TO_INTERFACE:
-                invoke = getLinkToTarget(tool, intrinsicMethod);
-                break;
-            default:
-                throw GraalInternalError.shouldNotReachHere();
-        }
+        MethodHandleAccessProvider methodHandleAccess = tool.getConstantReflection().getMethodHandleAccess();
+        ValueNode[] argumentsArray = arguments.toArray(new ValueNode[arguments.size()]);
+        InvokeNode invoke = tryResolveTargetInvoke(graph().getAssumptions(), methodHandleAccess, intrinsicMethod, targetMethod, bci, returnType, argumentsArray);
         if (invoke != null) {
+            assert invoke.graph() == null;
+            invoke = graph().addOrUniqueWithInputs(invoke);
+            invoke.setStateAfter(stateAfter());
             FixedNode currentNext = next();
             replaceAtUsages(invoke);
             GraphUtil.removeFixedWithUnusedInputs(this);
@@ -105,8 +104,8 @@
      *
      * @return the receiver argument node
      */
-    private ValueNode getReceiver() {
-        return arguments.first();
+    private static ValueNode getReceiver(ValueNode[] arguments) {
+        return arguments[0];
     }
 
     /**
@@ -114,8 +113,8 @@
      *
      * @return the MemberName argument node (which is the last argument)
      */
-    private ValueNode getMemberName() {
-        return arguments.last();
+    private static ValueNode getMemberName(ValueNode[] arguments) {
+        return arguments[arguments.length - 1];
     }
 
     /**
@@ -124,10 +123,11 @@
      *
      * @return invoke node for the {@link java.lang.invoke.MethodHandle} target
      */
-    protected InvokeNode getInvokeBasicTarget(SimplifierTool tool, IntrinsicMethod intrinsicMethod) {
-        ValueNode methodHandleNode = getReceiver();
+    private static InvokeNode getInvokeBasicTarget(Assumptions assumptions, IntrinsicMethod intrinsicMethod, MethodHandleAccessProvider methodHandleAccess, ResolvedJavaMethod original, int bci,
+                    JavaType returnType, ValueNode[] arguments) {
+        ValueNode methodHandleNode = getReceiver(arguments);
         if (methodHandleNode.isConstant()) {
-            return getTargetInvokeNode(tool.getConstantReflection().getMethodHandleAccess().resolveInvokeBasicTarget(methodHandleNode.asJavaConstant(), false), intrinsicMethod);
+            return getTargetInvokeNode(assumptions, intrinsicMethod, bci, returnType, arguments, methodHandleAccess.resolveInvokeBasicTarget(methodHandleNode.asJavaConstant(), true), original);
         }
         return null;
     }
@@ -140,10 +140,11 @@
      *
      * @return invoke node for the member name target
      */
-    protected InvokeNode getLinkToTarget(SimplifierTool tool, IntrinsicMethod intrinsicMethod) {
-        ValueNode memberNameNode = getMemberName();
+    private static InvokeNode getLinkToTarget(Assumptions assumptions, IntrinsicMethod intrinsicMethod, MethodHandleAccessProvider methodHandleAccess, ResolvedJavaMethod original, int bci,
+                    JavaType returnType, ValueNode[] arguments) {
+        ValueNode memberNameNode = getMemberName(arguments);
         if (memberNameNode.isConstant()) {
-            return getTargetInvokeNode(tool.getConstantReflection().getMethodHandleAccess().resolveLinkToTarget(memberNameNode.asJavaConstant()), intrinsicMethod);
+            return getTargetInvokeNode(assumptions, intrinsicMethod, bci, returnType, arguments, methodHandleAccess.resolveLinkToTarget(memberNameNode.asJavaConstant()), original);
         }
         return null;
     }
@@ -155,7 +156,8 @@
      * @param target the target, already loaded from the member name node
      * @return invoke node for the member name target
      */
-    private InvokeNode getTargetInvokeNode(ResolvedJavaMethod target, IntrinsicMethod intrinsicMethod) {
+    private static InvokeNode getTargetInvokeNode(Assumptions assumptions, IntrinsicMethod intrinsicMethod, int bci, JavaType returnType, ValueNode[] arguments, ResolvedJavaMethod target,
+                    ResolvedJavaMethod original) {
         if (target == null) {
             return null;
         }
@@ -171,34 +173,35 @@
         // Cast receiver to its type.
         if (!isStatic) {
             JavaType receiverType = target.getDeclaringClass();
-            maybeCastArgument(0, receiverType);
+            maybeCastArgument(arguments, 0, receiverType);
         }
 
         // Cast reference arguments to its type.
         for (int index = 0; index < signature.getParameterCount(false); index++) {
             JavaType parameterType = signature.getParameterType(index, target.getDeclaringClass());
-            maybeCastArgument(receiverSkip + index, parameterType);
+            maybeCastArgument(arguments, receiverSkip + index, parameterType);
         }
 
         if (target.canBeStaticallyBound()) {
-            return createTargetInvokeNode(target, intrinsicMethod);
+            return createTargetInvokeNode(intrinsicMethod, target, original, bci, returnType, arguments);
         }
 
         // Try to get the most accurate receiver type
         if (intrinsicMethod == IntrinsicMethod.LINK_TO_VIRTUAL || intrinsicMethod == IntrinsicMethod.LINK_TO_INTERFACE) {
-            ResolvedJavaType receiverType = StampTool.typeOrNull(getReceiver().stamp());
+            ValueNode receiver = getReceiver(arguments);
+            ResolvedJavaType receiverType = StampTool.typeOrNull(receiver.stamp());
             if (receiverType != null) {
                 AssumptionResult<ResolvedJavaMethod> concreteMethod = receiverType.findUniqueConcreteMethod(target);
                 if (concreteMethod != null) {
-                    graph().getAssumptions().record(concreteMethod);
-                    return createTargetInvokeNode(concreteMethod.getResult(), intrinsicMethod);
+                    assumptions.record(concreteMethod);
+                    return createTargetInvokeNode(intrinsicMethod, concreteMethod.getResult(), original, bci, returnType, arguments);
                 }
             }
         } else {
             AssumptionResult<ResolvedJavaMethod> concreteMethod = target.getDeclaringClass().findUniqueConcreteMethod(target);
             if (concreteMethod != null) {
-                graph().getAssumptions().record(concreteMethod);
-                return createTargetInvokeNode(concreteMethod.getResult(), intrinsicMethod);
+                assumptions.record(concreteMethod);
+                return createTargetInvokeNode(intrinsicMethod, concreteMethod.getResult(), original, bci, returnType, arguments);
             }
         }
 
@@ -212,15 +215,15 @@
      * @param index of the argument to be cast
      * @param type the type the argument should be cast to
      */
-    private void maybeCastArgument(int index, JavaType type) {
+    private static void maybeCastArgument(ValueNode[] arguments, int index, JavaType type) {
         if (type instanceof ResolvedJavaType) {
             ResolvedJavaType targetType = (ResolvedJavaType) type;
             if (!targetType.isPrimitive()) {
-                ValueNode argument = arguments.get(index);
+                ValueNode argument = arguments[index];
                 ResolvedJavaType argumentType = StampTool.typeOrNull(argument.stamp());
                 if (argumentType == null || (argumentType.isAssignableFrom(targetType) && !argumentType.equals(targetType))) {
-                    PiNode piNode = graph().unique(new PiNode(argument, StampFactory.declared(targetType)));
-                    arguments.set(index, piNode);
+                    PiNode piNode = new PiNode(argument, StampFactory.declared(targetType));
+                    arguments[index] = piNode;
                 }
             }
         }
@@ -228,57 +231,42 @@
 
     /**
      * Creates an {@link InvokeNode} for the given target method. The {@link CallTargetNode} passed
-     * to the InvokeNode is in fact a {@link SelfReplacingMethodCallTargetNode}.
+     * to the InvokeNode is in fact a {@link ResolvedMethodHandleCallTargetNode}.
      *
-     * @param target the method to be called
      * @return invoke node for the member name target
      */
-    private InvokeNode createTargetInvokeNode(ResolvedJavaMethod target, IntrinsicMethod intrinsicMethod) {
+    private static InvokeNode createTargetInvokeNode(IntrinsicMethod intrinsicMethod, ResolvedJavaMethod target, ResolvedJavaMethod original, int bci, JavaType returnType, ValueNode[] arguments) {
         InvokeKind targetInvokeKind = target.isStatic() ? InvokeKind.Static : InvokeKind.Special;
         JavaType targetReturnType = target.getSignature().getReturnType(null);
 
         // MethodHandleLinkTo* nodes have a trailing MemberName argument which
         // needs to be popped.
-        ValueNode[] originalArguments = arguments.toArray(new ValueNode[arguments.size()]);
         ValueNode[] targetArguments;
         switch (intrinsicMethod) {
             case INVOKE_BASIC:
-                targetArguments = originalArguments;
+                targetArguments = arguments;
                 break;
             case LINK_TO_STATIC:
             case LINK_TO_SPECIAL:
             case LINK_TO_VIRTUAL:
             case LINK_TO_INTERFACE:
-                targetArguments = Arrays.copyOfRange(originalArguments, 0, arguments.size() - 1);
+                targetArguments = Arrays.copyOfRange(arguments, 0, arguments.length - 1);
                 break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
 
-        // If there is already replacement information, use that instead.
-        MethodCallTargetNode callTarget;
-        if (replacementTargetMethod == null) {
-            callTarget = new SelfReplacingMethodCallTargetNode(targetInvokeKind, target, targetArguments, targetReturnType, getTargetMethod(), originalArguments, getReturnType());
-        } else {
-            ValueNode[] args = replacementArguments.toArray(new ValueNode[replacementArguments.size()]);
-            callTarget = new SelfReplacingMethodCallTargetNode(targetInvokeKind, target, targetArguments, targetReturnType, replacementTargetMethod, args, replacementReturnType);
-        }
-        graph().add(callTarget);
+        MethodCallTargetNode callTarget = new ResolvedMethodHandleCallTargetNode(targetInvokeKind, target, targetArguments, targetReturnType, original, arguments, returnType);
 
         // The call target can have a different return type than the invoker,
         // e.g. the target returns an Object but the invoker void. In this case
         // we need to use the stamp of the invoker. Note: always using the
         // invoker's stamp would be wrong because it's a less concrete type
         // (usually java.lang.Object).
-        InvokeNode invoke;
-        if (stamp() == StampFactory.forVoid()) {
-            invoke = new InvokeNode(callTarget, getBci(), stamp());
+        if (returnType.getKind() == Kind.Void) {
+            return new InvokeNode(callTarget, bci, StampFactory.forVoid());
         } else {
-            invoke = new InvokeNode(callTarget, getBci());
+            return new InvokeNode(callTarget, bci);
         }
-        graph().add(invoke);
-        invoke.setStateAfter(stateAfter());
-        return invoke;
     }
-
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java	Fri Mar 27 17:02:53 2015 +0100
@@ -31,6 +31,7 @@
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.java.*;
@@ -43,8 +44,8 @@
 
     public static final NodeClass<ObjectCloneNode> TYPE = NodeClass.create(ObjectCloneNode.class);
 
-    public ObjectCloneNode(Invoke invoke) {
-        super(TYPE, invoke);
+    public ObjectCloneNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, JavaType returnType, ValueNode receiver) {
+        super(TYPE, invokeKind, targetMethod, bci, returnType, receiver);
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectSubstitutions.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectSubstitutions.java	Fri Mar 27 17:02:53 2015 +0100
@@ -28,7 +28,6 @@
 import com.oracle.graal.hotspot.word.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.spi.*;
 
 /**
  * Substitutions for {@link java.lang.Object} methods.
@@ -51,7 +50,4 @@
     public static void init(Object thisObj) {
         RegisterFinalizerNode.register(thisObj);
     }
-
-    @MacroSubstitution(macro = ObjectCloneNode.class, isStatic = false, forced = true)
-    public static native Object clone(Object obj);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ReflectionGetCallerClassNode.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ReflectionGetCallerClassNode.java	Fri Mar 27 17:02:53 2015 +0100
@@ -31,6 +31,7 @@
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.replacements.nodes.*;
 
@@ -39,8 +40,8 @@
 
     public static final NodeClass<ReflectionGetCallerClassNode> TYPE = NodeClass.create(ReflectionGetCallerClassNode.class);
 
-    public ReflectionGetCallerClassNode(Invoke invoke) {
-        super(TYPE, invoke);
+    public ReflectionGetCallerClassNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, JavaType returnType, ValueNode... arguments) {
+        super(TYPE, invokeKind, targetMethod, bci, returnType, arguments);
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ReflectionSubstitutions.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ReflectionSubstitutions.java	Fri Mar 27 17:02:53 2015 +0100
@@ -29,7 +29,6 @@
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.hotspot.word.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
 
 /**
  * Substitutions for {@link sun.reflect.Reflection} methods.
@@ -37,9 +36,6 @@
 @ClassSubstitution(sun.reflect.Reflection.class)
 public class ReflectionSubstitutions {
 
-    @MacroSubstitution(macro = ReflectionGetCallerClassNode.class, optional = true)
-    public static native Class<?> getCallerClass();
-
     @MethodSubstitution
     public static int getClassAccessFlags(Class<?> aClass) {
         KlassPointer klass = ClassGetHubNode.readClass(GuardingPiNode.asNonNullClass(aClass));
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/SystemIdentityHashCodeNode.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/SystemIdentityHashCodeNode.java	Fri Mar 27 17:02:53 2015 +0100
@@ -29,6 +29,7 @@
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.replacements.nodes.*;
 
 @NodeInfo
@@ -36,8 +37,8 @@
 
     public static final NodeClass<SystemIdentityHashCodeNode> TYPE = NodeClass.create(SystemIdentityHashCodeNode.class);
 
-    public SystemIdentityHashCodeNode(Invoke invoke) {
-        super(TYPE, invoke);
+    public SystemIdentityHashCodeNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, JavaType returnType, ValueNode object) {
+        super(TYPE, invokeKind, targetMethod, bci, returnType, object);
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/SystemSubstitutions.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/SystemSubstitutions.java	Fri Mar 27 17:02:53 2015 +0100
@@ -27,8 +27,6 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.hotspot.replacements.arraycopy.*;
-import com.oracle.graal.nodes.spi.*;
 
 /**
  * Substitutions for {@link java.lang.System} methods.
@@ -39,10 +37,6 @@
     public static final ForeignCallDescriptor JAVA_TIME_MILLIS = new ForeignCallDescriptor("javaTimeMillis", long.class);
     public static final ForeignCallDescriptor JAVA_TIME_NANOS = new ForeignCallDescriptor("javaTimeNanos", long.class);
 
-    @MacroSubstitution(macro = ArrayCopyNode.class)
-    public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
-
-    @MacroSubstitution(macro = SystemIdentityHashCodeNode.class)
     @MethodSubstitution
     public static int identityHashCode(Object x) {
         if (probability(NOT_FREQUENT_PROBABILITY, x == null)) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopyNode.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopyNode.java	Fri Mar 27 17:02:53 2015 +0100
@@ -32,6 +32,7 @@
 import com.oracle.graal.loop.phases.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.phases.common.*;
@@ -43,8 +44,8 @@
 
     public static final NodeClass<ArrayCopyNode> TYPE = NodeClass.create(ArrayCopyNode.class);
 
-    public ArrayCopyNode(Invoke invoke) {
-        super(TYPE, invoke);
+    public ArrayCopyNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, JavaType returnType, ValueNode src, ValueNode srcPos, ValueNode dst, ValueNode dstPos, ValueNode length) {
+        super(TYPE, invokeKind, targetMethod, bci, returnType, src, srcPos, dst, dstPos, length);
     }
 
     private StructuredGraph selectSnippet(LoweringTool tool, final Replacements replacements) {
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Fri Mar 27 17:02:53 2015 +0100
@@ -296,7 +296,7 @@
             private final boolean explodeLoops;
             private final boolean mergeExplosions;
             private final Map<HIRFrameStateBuilder, Integer> mergeExplosionsMap;
-            private Stack<ExplodedLoopContext> explodeLoopsContext;
+            private Deque<ExplodedLoopContext> explodeLoopsContext;
             private int nextPeelIteration = 1;
             private boolean controlFlowSplit;
             private final InvocationPluginReceiver invocationPluginReceiver = new InvocationPluginReceiver(this);
@@ -452,7 +452,7 @@
             private void detectLoops(FixedNode startInstruction) {
                 NodeBitMap visited = currentGraph.createNodeBitMap();
                 NodeBitMap active = currentGraph.createNodeBitMap();
-                Stack<Node> stack = new Stack<>();
+                Deque<Node> stack = new ArrayDeque<>();
                 stack.add(startInstruction);
                 visited.mark(startInstruction);
                 while (!stack.isEmpty()) {
@@ -498,7 +498,7 @@
 
             private void insertLoopEnds(FixedNode startInstruction) {
                 NodeBitMap visited = currentGraph.createNodeBitMap();
-                Stack<Node> stack = new Stack<>();
+                Deque<Node> stack = new ArrayDeque<>();
                 stack.add(startInstruction);
                 visited.mark(startInstruction);
                 List<LoopBeginNode> loopBegins = new ArrayList<>();
@@ -538,7 +538,7 @@
 
             private void insertLoopExits(LoopBeginNode loopBegin, IdentityHashMap<LoopBeginNode, List<LoopBeginNode>> innerLoopsMap) {
                 NodeBitMap visited = currentGraph.createNodeBitMap();
-                Stack<Node> stack = new Stack<>();
+                Deque<Node> stack = new ArrayDeque<>();
                 for (LoopEndNode loopEnd : loopBegin.loopEnds()) {
                     stack.push(loopEnd);
                     visited.mark(loopEnd);
@@ -622,7 +622,7 @@
 
             private int iterateExplodedLoopHeader(BciBlock[] blocks, BciBlock header) {
                 if (explodeLoopsContext == null) {
-                    explodeLoopsContext = new Stack<>();
+                    explodeLoopsContext = new ArrayDeque<>();
                 }
 
                 ExplodedLoopContext context = new ExplodedLoopContext();
@@ -823,9 +823,7 @@
 
             @Override
             protected void genStoreIndexed(ValueNode array, ValueNode index, Kind kind, ValueNode value) {
-                StoreIndexedNode storeIndexed = new StoreIndexedNode(array, index, kind, value);
-                append(storeIndexed);
-                storeIndexed.setStateAfter(this.createStateAfter());
+                add(new StoreIndexedNode(array, index, kind, value));
             }
 
             @Override
@@ -1145,6 +1143,21 @@
                 }
             }
 
+            private InvokeKind currentInvokeKind;
+            private JavaType currentInvokeReturnType;
+
+            public InvokeKind getInvokeKind() {
+                return currentInvokeKind;
+            }
+
+            public JavaType getInvokeReturnType() {
+                return currentInvokeReturnType;
+            }
+
+            public void handleReplacedInvoke(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args) {
+                appendInvoke(invokeKind, targetMethod, args);
+            }
+
             private void appendInvoke(InvokeKind initialInvokeKind, ResolvedJavaMethod initialTargetMethod, ValueNode[] args) {
                 ResolvedJavaMethod targetMethod = initialTargetMethod;
                 InvokeKind invokeKind = initialInvokeKind;
@@ -1181,22 +1194,29 @@
                     }
                 }
 
-                if (tryGenericInvocationPlugin(args, targetMethod)) {
-                    if (TraceParserPlugins.getValue()) {
-                        traceWithContext("used generic invocation plugin for %s", targetMethod.format("%h.%n(%p)"));
+                try {
+                    currentInvokeReturnType = returnType;
+                    currentInvokeKind = invokeKind;
+                    if (tryGenericInvocationPlugin(args, targetMethod)) {
+                        if (TraceParserPlugins.getValue()) {
+                            traceWithContext("used generic invocation plugin for %s", targetMethod.format("%h.%n(%p)"));
+                        }
+                        return;
                     }
-                    return;
-                }
 
-                if (tryInvocationPlugin(args, targetMethod, resultType)) {
-                    if (TraceParserPlugins.getValue()) {
-                        traceWithContext("used invocation plugin for %s", targetMethod.format("%h.%n(%p)"));
+                    if (tryInvocationPlugin(args, targetMethod, resultType)) {
+                        if (TraceParserPlugins.getValue()) {
+                            traceWithContext("used invocation plugin for %s", targetMethod.format("%h.%n(%p)"));
+                        }
+                        return;
                     }
-                    return;
-                }
 
-                if (tryInline(args, targetMethod, invokeKind, returnType)) {
-                    return;
+                    if (tryInline(args, targetMethod, invokeKind, returnType)) {
+                        return;
+                    }
+                } finally {
+                    currentInvokeReturnType = null;
+                    currentInvokeKind = null;
                 }
 
                 MethodCallTargetNode callTarget = currentGraph.add(createMethodCallTarget(invokeKind, targetMethod, args, returnType));
@@ -1254,7 +1274,8 @@
 
                 boolean check(boolean pluginResult) {
                     if (pluginResult == true) {
-                        assert beforeStackSize + resultType.getSlotCount() == frameState.stackSize : error("plugin manipulated the stack incorrectly");
+                        int expectedStackSize = beforeStackSize + resultType.getSlotCount();
+                        assert expectedStackSize == frameState.stackSize : error("plugin manipulated the stack incorrectly: expected=%d, actual=%d", expectedStackSize, frameState.stackSize);
                         NodeIterable<Node> newNodes = currentGraph.getNewNodes(mark);
                         assert !needsNullCheck || isPointerNonNull(args[0].stamp()) : error("plugin needs to null check the receiver of %s: receiver=%s", targetMethod.format("%H.%n(%p)"), args[0]);
                         for (Node n : newNodes) {
@@ -1280,6 +1301,15 @@
             private boolean tryInvocationPlugin(ValueNode[] args, ResolvedJavaMethod targetMethod, Kind resultType) {
                 InvocationPlugin plugin = graphBuilderConfig.getPlugins().getInvocationPlugins().lookupInvocation(targetMethod);
                 if (plugin != null) {
+
+                    ReplacementContext context = this.replacementContext;
+                    if (context != null && context.isCallToOriginal(targetMethod)) {
+                        // Self recursive replacement means the original
+                        // method should be called.
+                        assert !targetMethod.hasBytecodes() : "TODO: when does this happen?";
+                        return false;
+                    }
+
                     InvocationPluginAssertions assertions = assertionsEnabled() ? new InvocationPluginAssertions(plugin, args, targetMethod, resultType) : null;
                     if (InvocationPlugin.execute(this, targetMethod, plugin, invocationPluginReceiver.init(targetMethod, args), args)) {
                         assert assertions.check(true);
@@ -1307,7 +1337,7 @@
                 return false;
             }
 
-            boolean inline(InlineInvokePlugin plugin, ResolvedJavaMethod targetMethod, InlineInfo inlineInfo, ValueNode[] args) {
+            public boolean inline(InlineInvokePlugin plugin, ResolvedJavaMethod targetMethod, InlineInfo inlineInfo, ValueNode[] args) {
                 int bci = bci();
                 ResolvedJavaMethod inlinedMethod = inlineInfo.methodToInline;
                 if (TraceInlineDuringParsing.getValue() || TraceParserPlugins.getValue()) {
@@ -1872,9 +1902,7 @@
             }
 
             private int findOperatingDimensionWithLoopExplosion(BciBlock block, HIRFrameStateBuilder state) {
-                int i;
-                for (i = explodeLoopsContext.size() - 1; i >= 0; --i) {
-                    ExplodedLoopContext context = explodeLoopsContext.elementAt(i);
+                for (ExplodedLoopContext context : explodeLoopsContext) {
                     if (context.header == block) {
 
                         if (this.mergeExplosions) {
@@ -2415,6 +2443,7 @@
             }
 
             public void push(Kind kind, ValueNode value) {
+                assert value.isAlive();
                 assert kind == kind.getStackKind();
                 frameState.push(kind, value);
             }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/UntrustedInterfaces.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/UntrustedInterfaces.java	Fri Mar 27 17:02:53 2015 +0100
@@ -23,7 +23,7 @@
 package com.oracle.graal.jtt.except;
 
 import org.junit.*;
-import org.objectweb.asm.*;
+import jdk.internal.org.objectweb.asm.*;
 
 import com.oracle.graal.jtt.*;
 
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/Switch02.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/Switch02.java	Fri Mar 27 17:02:53 2015 +0100
@@ -89,7 +89,7 @@
                 break;
             case (char) 0xFFFF - 21:
                 result = 858112498 / val;
-                x = new Hashtable<>();
+                x = new HashMap<>();
                 break;
             default:
                 result = 34324341 / val;
@@ -142,7 +142,7 @@
                 break;
             case (short) -0x7FFF + 21:
                 result = 858112498 / val;
-                x = new Hashtable<>();
+                x = new HashMap<>();
                 break;
             default:
                 result = 34324341 / val;
@@ -198,7 +198,7 @@
                 break;
             case (byte) -0x7F + 21:
                 result = 858112498 / val;
-                x = new Hashtable<>();
+                x = new HashMap<>();
                 break;
             default:
                 result = 34324341 / val;
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRFrameState.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRFrameState.java	Fri Mar 27 17:02:53 2015 +0100
@@ -130,7 +130,7 @@
      * @param canHaveRegisters True if there can be any register map entries.
      */
     public void initDebugInfo(FrameMap frameMap, boolean canHaveRegisters) {
-        debugInfo = new DebugInfo(topFrame, frameMap.initReferenceMap(canHaveRegisters));
+        debugInfo = new DebugInfo(topFrame, frameMap.initReferenceMap(canHaveRegisters), virtualObjects);
     }
 
     /**
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/SimpleInfopointOp.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/SimpleInfopointOp.java	Fri Mar 27 17:02:53 2015 +0100
@@ -39,6 +39,6 @@
 
     @Override
     public void emitCode(CompilationResultBuilder crb) {
-        crb.recordInfopoint(crb.asm.position(), new DebugInfo(position, null), reason);
+        crb.recordInfopoint(crb.asm.position(), new DebugInfo(position), reason);
     }
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerationResult.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerationResult.java	Fri Mar 27 17:02:53 2015 +0100
@@ -56,4 +56,6 @@
     boolean hasForeignCall();
 
     void setForeignCall(boolean b);
+
+    String getCompilationUnitName();
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerationResultBase.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerationResultBase.java	Fri Mar 27 17:02:53 2015 +0100
@@ -34,10 +34,15 @@
      * Records whether the code being generated makes at least one foreign call.
      */
     private boolean hasForeignCall;
+    /**
+     * Human readable name of this compilation unit.
+     */
+    private final String compilationUnitName;
 
-    public LIRGenerationResultBase(LIR lir, FrameMapBuilder frameMapBuilder) {
+    public LIRGenerationResultBase(String compilationUnitName, LIR lir, FrameMapBuilder frameMapBuilder) {
         this.lir = lir;
         this.frameMapBuilder = frameMapBuilder;
+        this.compilationUnitName = compilationUnitName;
     }
 
     public LIR getLIR() {
@@ -69,4 +74,8 @@
         assert frameMap != null : "getFrameMap() can only be used after calling buildFrameMap()!";
         return frameMap;
     }
+
+    public String getCompilationUnitName() {
+        return compilationUnitName;
+    }
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/profiling/MoveProfiling.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/profiling/MoveProfiling.java	Fri Mar 27 17:02:53 2015 +0100
@@ -136,12 +136,13 @@
             }
             String[] groups = new String[names.size()];
             Arrays.fill(groups, "Move Operations");
-
-            LIRInstruction inst = counterFactory.createMultiBenchmarkCounter(names.toArray(new String[0]), groups, increments.toArray(new Value[0]));
-            assert inst != null;
-            buffer.init(instructions);
-            buffer.append(1, inst);
-            buffer.finish();
+            if (names.size() > 0) { // Don't pollute LIR when nothing has to be done
+                LIRInstruction inst = counterFactory.createMultiBenchmarkCounter(names.toArray(new String[0]), groups, increments.toArray(new Value[0]));
+                assert inst != null;
+                buffer.init(instructions);
+                buffer.append(1, inst);
+                buffer.finish();
+            }
         }
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodeinfo/src/com/oracle/graal/nodeinfo/StructuralInput.java	Fri Mar 27 17:02:53 2015 +0100
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodeinfo;
+
+import java.lang.annotation.*;
+
+/**
+ * Marker type for describing node inputs in snippets that are not of type {@link InputType#Value}.
+ */
+public abstract class StructuralInput {
+
+    private StructuralInput() {
+        throw new Error("Illegal instance of StructuralInput. This class should be used in snippets only.");
+    }
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.TYPE)
+    public @interface MarkerType {
+        InputType value();
+    }
+
+    /**
+     * Marker type for {@link InputType#Memory} edges in snippets.
+     */
+    @MarkerType(InputType.Memory)
+    public abstract static class Memory extends StructuralInput {
+    }
+
+    /**
+     * Marker type for {@link InputType#Condition} edges in snippets.
+     */
+    @MarkerType(InputType.Condition)
+    public abstract static class Condition extends StructuralInput {
+    }
+
+    /**
+     * Marker type for {@link InputType#State} edges in snippets.
+     */
+    @MarkerType(InputType.State)
+    public abstract static class State extends StructuralInput {
+    }
+
+    /**
+     * Marker type for {@link InputType#Guard} edges in snippets.
+     */
+    @MarkerType(InputType.Guard)
+    public abstract static class Guard extends StructuralInput {
+    }
+
+    /**
+     * Marker type for {@link InputType#Anchor} edges in snippets.
+     */
+    @MarkerType(InputType.Anchor)
+    public abstract static class Anchor extends StructuralInput {
+    }
+
+    /**
+     * Marker type for {@link InputType#Association} edges in snippets.
+     */
+    @MarkerType(InputType.Association)
+    public abstract static class Association extends StructuralInput {
+    }
+
+    /**
+     * Marker type for {@link InputType#Extension} edges in snippets.
+     */
+    @MarkerType(InputType.Extension)
+    public abstract static class Extension extends StructuralInput {
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Fri Mar 27 17:02:53 2015 +0100
@@ -781,6 +781,8 @@
                 }
             }
         }
+        transferProxies(trueSuccessor(), trueMerge);
+        transferProxies(falseSuccessor(), falseMerge);
 
         cleanupMerge(tool, merge);
         cleanupMerge(tool, trueMerge);
@@ -789,6 +791,14 @@
         return true;
     }
 
+    private static void transferProxies(AbstractBeginNode successor, MergeNode falseMerge) {
+        if (falseMerge != null) {
+            for (ProxyNode proxy : successor.proxies().snapshot()) {
+                proxy.replaceFirstInput(successor, falseMerge);
+            }
+        }
+    }
+
     private void cleanupMerge(SimplifierTool tool, MergeNode merge) {
         if (merge != null && merge.isAlive()) {
             if (merge.forwardEndCount() == 0) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryAnchorNode.java	Fri Mar 27 17:02:53 2015 +0100
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes.extended;
+
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodeinfo.StructuralInput.Memory;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+
+@NodeInfo(allowedUsageTypes = {InputType.Memory})
+public final class MemoryAnchorNode extends FixedWithNextNode implements LIRLowerable, MemoryNode, Canonicalizable {
+
+    public static final NodeClass<MemoryAnchorNode> TYPE = NodeClass.create(MemoryAnchorNode.class);
+
+    public MemoryAnchorNode() {
+        super(TYPE, StampFactory.forVoid());
+    }
+
+    public void generate(NodeLIRBuilderTool generator) {
+        // Nothing to emit, since this node is used for structural purposes only.
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        return hasNoUsages() ? null : this;
+    }
+
+    @NodeIntrinsic
+    public static native Memory anchor();
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/SelfReplacingMethodCallTargetNode.java	Fri Mar 27 15:43:31 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,82 +0,0 @@
-/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes.java;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-
-/**
- * A SelfReplacingMethodCallTargetNode replaces itself in the graph when being lowered with a
- * {@link MethodCallTargetNode} that calls the stored replacement target method.
- *
- * This node is used for method handle call nodes which have a constant call target but are not
- * inlined.
- */
-@NodeInfo
-public final class SelfReplacingMethodCallTargetNode extends MethodCallTargetNode implements Lowerable {
-
-    public static final NodeClass<SelfReplacingMethodCallTargetNode> TYPE = NodeClass.create(SelfReplacingMethodCallTargetNode.class);
-    // Replacement method data
-    protected final ResolvedJavaMethod replacementTargetMethod;
-    protected final JavaType replacementReturnType;
-    @Input NodeInputList<ValueNode> replacementArguments;
-
-    public SelfReplacingMethodCallTargetNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] arguments, JavaType returnType, ResolvedJavaMethod replacementTargetMethod,
-                    ValueNode[] replacementArguments, JavaType replacementReturnType) {
-        super(TYPE, invokeKind, targetMethod, arguments, returnType);
-        this.replacementTargetMethod = replacementTargetMethod;
-        this.replacementReturnType = replacementReturnType;
-        this.replacementArguments = new NodeInputList<>(this, replacementArguments);
-    }
-
-    public ResolvedJavaMethod replacementTargetMethod() {
-        return replacementTargetMethod;
-    }
-
-    public JavaType replacementReturnType() {
-        return replacementReturnType;
-    }
-
-    public NodeInputList<ValueNode> replacementArguments() {
-        return replacementArguments;
-    }
-
-    @Override
-    public void lower(LoweringTool tool) {
-        InvokeKind replacementInvokeKind = replacementTargetMethod.isStatic() ? InvokeKind.Static : InvokeKind.Special;
-        MethodCallTargetNode replacement = graph().add(
-                        new MethodCallTargetNode(replacementInvokeKind, replacementTargetMethod, replacementArguments.toArray(new ValueNode[replacementArguments.size()]), replacementReturnType));
-
-        // Replace myself...
-        this.replaceAndDelete(replacement);
-    }
-
-    @Override
-    public void generate(NodeLIRBuilderTool gen) {
-        throw GraalInternalError.shouldNotReachHere("should have replaced itself");
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MacroSubstitution.java	Fri Mar 27 15:43:31 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,89 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes.spi;
-
-import java.lang.annotation.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.nodes.*;
-
-/**
- * Denotes a macro substitute method. This replaces a method invocation with an instance of the
- * {@link #macro() specified} node class.
- * <p>
- * A macro substitution can be combined with a {@link MethodSubstitution method substitution}. In
- * this case, if the macro is not removed during canonicalization, it is lowered via the method
- * substitution.
- * <p>
- * If a macro is not combined with a method substitution, it is lowered to an invocation of the
- * original method.
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.METHOD)
-public @interface MacroSubstitution {
-
-    /**
-     * Gets the name of the substituted method.
-     * <p>
-     * If the default value is specified for this element, then the name of the substituted method
-     * is same as the substitute method.
-     */
-    String value() default "";
-
-    /**
-     * Determines if the substituted method is static.
-     */
-    boolean isStatic() default true;
-
-    /**
-     * Gets the {@linkplain Signature#toMethodDescriptor signature} of the substituted method.
-     * <p>
-     * If the default value is specified for this element, then the signature of the substituted
-     * method is the same as the substitute method.
-     */
-    String signature() default "";
-
-    /**
-     * Determines if the substitution is for a method that may not be part of the runtime. For
-     * example, a method introduced in a later JDK version. Substitutions for such methods are
-     * omitted if the original method cannot be found.
-     */
-    boolean optional() default false;
-
-    /**
-     * The node class with which the method invocation should be replaced. It needs to be a subclass
-     * of {@link FixedWithNextNode}, and it is expected to provide a public constructor that takes
-     * an {@link InvokeNode} as a parameter.
-     */
-    Class<? extends FixedWithNextNode> macro();
-
-    /**
-     * Determines if this method should be substituted in all cases, even if inlining thinks it is
-     * not important.
-     *
-     * Note that this is still depending on whether inlining sees the correct call target, so it's
-     * only a hard guarantee for static and special invocations.
-     */
-    boolean forced() default false;
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java	Fri Mar 27 17:02:53 2015 +0100
@@ -47,7 +47,7 @@
      *
      * @param recursiveEntry if the snippet contains a call to this method, it's considered as
      *            recursive call and won't be processed for {@linkplain MethodSubstitution
-     *            substitutions} or {@linkplain MacroSubstitution macro nodes}.
+     *            substitutions}.
      * @param args arguments to the snippet if available, otherwise {@code null}
      * @return the snippet graph, if any, that is derived from {@code method}
      */
@@ -82,17 +82,8 @@
     ResolvedJavaMethod getMethodSubstitutionMethod(ResolvedJavaMethod method);
 
     /**
-     * Gets the node class with which a method invocation should be replaced.
-     *
-     * @param method target of an invocation
-     * @return the {@linkplain MacroSubstitution#macro() macro node class} associated with
-     *         {@code method} or null if there is no such association
-     */
-    Class<? extends FixedWithNextNode> getMacroSubstitution(ResolvedJavaMethod method);
-
-    /**
-     * Registers all the {@linkplain MethodSubstitution method} and {@linkplain MacroSubstitution
-     * macro} substitutions defined by a given class.
+     * Registers all the {@linkplain MethodSubstitution method} substitutions defined by a given
+     * class.
      *
      * @param original the original class for which substitutions are being registered. This must be
      *            the same type denoted by the {@link ClassSubstitution} annotation on
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DominatorConditionalEliminationPhase.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DominatorConditionalEliminationPhase.java	Fri Mar 27 17:02:53 2015 +0100
@@ -130,13 +130,13 @@
     private static class Instance {
 
         private final NodeMap<Info> map;
-        private final Stack<LoopExitNode> loopExits;
+        private final Deque<LoopExitNode> loopExits;
         private final Function<Block, Iterable<? extends Node>> blockToNodes;
         private final Function<Node, Block> nodeToBlock;
 
         public Instance(StructuredGraph graph, Function<Block, Iterable<? extends Node>> blockToNodes, Function<Node, Block> nodeToBlock) {
             map = graph.createNodeMap();
-            loopExits = new Stack<>();
+            loopExits = new ArrayDeque<>();
             this.blockToNodes = blockToNodes;
             this.nodeToBlock = nodeToBlock;
         }
@@ -282,8 +282,8 @@
                 }
                 Block guardBlock = nodeToBlock.apply(proxiedGuard);
                 assert guardBlock != null;
-                for (int i = 0; i < loopExits.size(); ++i) {
-                    LoopExitNode loopExitNode = loopExits.get(i);
+                for (Iterator<LoopExitNode> iter = loopExits.descendingIterator(); iter.hasNext();) {
+                    LoopExitNode loopExitNode = iter.next();
                     Block loopExitBlock = nodeToBlock.apply(loopExitNode);
                     if (guardBlock != loopExitBlock && AbstractControlFlowGraph.dominates(guardBlock, loopExitBlock)) {
                         Block loopBeginBlock = nodeToBlock.apply(loopExitNode.loopBegin());
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java	Fri Mar 27 17:02:53 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -255,6 +255,11 @@
 
         @Override
         protected MemoryMapImpl processNode(FixedNode node, MemoryMapImpl state) {
+            if (node instanceof MemoryAnchorNode) {
+                processAnchor((MemoryAnchorNode) node, state);
+                return state;
+            }
+
             if (node instanceof MemoryAccess) {
                 processAccess((MemoryAccess) node, state);
             }
@@ -274,6 +279,28 @@
             return state;
         }
 
+        /**
+         * Improve the memory graph by re-wiring all usages of a {@link MemoryAnchorNode} to the
+         * real last access location.
+         */
+        private static void processAnchor(MemoryAnchorNode anchor, MemoryMapImpl state) {
+            for (Node node : anchor.usages().snapshot()) {
+                if (node instanceof MemoryAccess) {
+                    MemoryAccess access = (MemoryAccess) node;
+                    if (access.getLastLocationAccess() == anchor) {
+                        MemoryNode lastLocationAccess = state.getLastLocationAccess(access.getLocationIdentity());
+                        if (lastLocationAccess != null) {
+                            access.setLastLocationAccess(lastLocationAccess);
+                        }
+                    }
+                }
+            }
+
+            if (anchor.hasNoUsages()) {
+                anchor.graph().removeFixed(anchor);
+            }
+        }
+
         private static void processAccess(MemoryAccess access, MemoryMapImpl state) {
             LocationIdentity locationIdentity = access.getLocationIdentity();
             if (!locationIdentity.equals(LocationIdentity.any())) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Fri Mar 27 17:02:53 2015 +0100
@@ -212,7 +212,7 @@
         if (callTarget.targetMethod() == null) {
             return "target method is null";
         }
-        assert invoke.stateAfter() != null;
+        assert invoke.stateAfter() != null : invoke;
         if (!invoke.useForInlining()) {
             return "the invoke is marked to be not used for inlining";
         }
@@ -574,17 +574,13 @@
     }
 
     public static boolean canIntrinsify(Replacements replacements, ResolvedJavaMethod target) {
-        return replacements.getMethodSubstitutionMethod(target) != null || getMacroNodeClass(replacements, target) != null;
+        return replacements.getMethodSubstitutionMethod(target) != null;
     }
 
     public static StructuredGraph getIntrinsicGraph(Replacements replacements, ResolvedJavaMethod target) {
         return replacements.getMethodSubstitution(target);
     }
 
-    public static Class<? extends FixedWithNextNode> getMacroNodeClass(Replacements replacements, ResolvedJavaMethod target) {
-        return replacements.getMacroSubstitution(target);
-    }
-
     public static FixedWithNextNode inlineMacroNode(Invoke invoke, ResolvedJavaMethod concrete, Class<? extends FixedWithNextNode> macroNodeClass) throws GraalInternalError {
         StructuredGraph graph = invoke.asNode().graph();
         if (!concrete.equals(((MethodCallTargetNode) invoke.callTarget()).targetMethod())) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/AbstractInlineInfo.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/AbstractInlineInfo.java	Fri Mar 27 17:02:53 2015 +0100
@@ -52,17 +52,10 @@
 
     protected static Collection<Node> inline(Invoke invoke, ResolvedJavaMethod concrete, Inlineable inlineable, boolean receiverNullCheck) {
         List<Node> canonicalizeNodes = new ArrayList<>();
-        if (inlineable instanceof InlineableGraph) {
-            StructuredGraph calleeGraph = ((InlineableGraph) inlineable).getGraph();
-            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);
-            canonicalizeNodes.add(macroNode);
-        }
+        assert inlineable instanceof InlineableGraph;
+        StructuredGraph calleeGraph = ((InlineableGraph) inlineable).getGraph();
+        Map<Node, Node> duplicateMap = InliningUtil.inline(invoke, calleeGraph, receiverNullCheck, canonicalizeNodes);
+        getInlinedParameterUsages(canonicalizeNodes, calleeGraph, duplicateMap);
 
         InliningUtil.InlinedBytecodes.add(concrete.getCodeSize());
         StructuredGraph graph = invoke.asNode().graph();
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/Inlineable.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/Inlineable.java	Fri Mar 27 17:02:53 2015 +0100
@@ -22,24 +22,17 @@
  */
 package com.oracle.graal.phases.common.inlining.info.elem;
 
-import com.oracle.graal.api.meta.ResolvedJavaMethod;
-import com.oracle.graal.nodes.FixedWithNextNode;
-import com.oracle.graal.nodes.Invoke;
-import com.oracle.graal.phases.common.CanonicalizerPhase;
-import com.oracle.graal.phases.common.inlining.InliningUtil;
-import com.oracle.graal.phases.tiers.HighTierContext;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.tiers.*;
 
 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);
-        } else {
-            return new InlineableGraph(method, invoke, context, canonicalizer);
-        }
+        return new InlineableGraph(method, invoke, context, canonicalizer);
     }
 
     int getNodeCount();
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableMacroNode.java	Fri Mar 27 15:43:31 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/*
- * 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.phases.common.inlining.info.elem;
-
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.nodes.FixedWithNextNode;
-import com.oracle.graal.nodes.Invoke;
-
-import java.util.Collections;
-
-public class InlineableMacroNode implements Inlineable {
-
-    private final Class<? extends FixedWithNextNode> macroNodeClass;
-
-    public InlineableMacroNode(Class<? extends FixedWithNextNode> macroNodeClass) {
-        this.macroNodeClass = macroNodeClass;
-    }
-
-    @Override
-    public int getNodeCount() {
-        return 1;
-    }
-
-    @Override
-    public Iterable<Invoke> getInvokes() {
-        return Collections.emptyList();
-    }
-
-    public Class<? extends FixedWithNextNode> getMacroNodeClass() {
-        return macroNodeClass;
-    }
-
-    public double getProbability(Invoke invoke) {
-        throw GraalInternalError.shouldNotReachHere("No invokes in inlineable");
-    }
-}
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/CallsiteHolderDummy.java	Fri Mar 27 15:43:31 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-/*
- * Copyright (c) 2011, 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.phases.common.inlining.walker;
-
-import com.oracle.graal.api.meta.ResolvedJavaMethod;
-import com.oracle.graal.nodes.StructuredGraph;
-
-import com.oracle.graal.phases.common.inlining.info.elem.InlineableMacroNode;
-
-/**
- * A {@link CallsiteHolder} that stands for an {@link InlineableMacroNode} in the stack realized by
- * {@link InliningData}.
- */
-public final class CallsiteHolderDummy extends CallsiteHolder {
-
-    public static final CallsiteHolderDummy DUMMY_CALLSITE_HOLDER = new CallsiteHolderDummy();
-
-    private CallsiteHolderDummy() {
-        // no instances other than the singleton
-    }
-
-    @Override
-    public ResolvedJavaMethod method() {
-        return null;
-    }
-
-    @Override
-    public boolean hasRemainingInvokes() {
-        return false;
-    }
-
-    @Override
-    public StructuredGraph graph() {
-        return null;
-    }
-
-    @Override
-    public String toString() {
-        return "<macro-node>";
-    }
-}
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java	Fri Mar 27 17:02:53 2015 +0100
@@ -23,7 +23,6 @@
 package com.oracle.graal.phases.common.inlining.walker;
 
 import static com.oracle.graal.compiler.common.GraalOptions.*;
-import static com.oracle.graal.phases.common.inlining.walker.CallsiteHolderDummy.*;
 
 import java.util.*;
 
@@ -560,7 +559,7 @@
         assert graphQueue.size() <= maxGraphs;
         for (int i = 0; i < info.numberOfMethods(); i++) {
             CallsiteHolder ch = methodInvocation.buildCallsiteHolderForElement(i);
-            assert (ch == DUMMY_CALLSITE_HOLDER) || !contains(ch.graph());
+            assert !contains(ch.graph());
             graphQueue.push(ch);
             assert graphQueue.size() <= maxGraphs;
         }
@@ -733,12 +732,8 @@
             }
             CallsiteHolder queuedTargetCH = iter.next();
             Inlineable targetIE = currentInvocation().callee().inlineableElementAt(i);
-            if (targetIE instanceof InlineableMacroNode) {
-                assert queuedTargetCH == DUMMY_CALLSITE_HOLDER;
-            } else {
-                InlineableGraph targetIG = (InlineableGraph) targetIE;
-                assert queuedTargetCH.method().equals(targetIG.getGraph().method());
-            }
+            InlineableGraph targetIG = (InlineableGraph) targetIE;
+            assert queuedTargetCH.method().equals(targetIG.getGraph().method());
         }
         return true;
     }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/MethodInvocation.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/MethodInvocation.java	Fri Mar 27 17:02:53 2015 +0100
@@ -123,15 +123,11 @@
 
     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;
-        }
+        assert 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);
     }
 
     @Override
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java	Fri Mar 27 17:02:53 2015 +0100
@@ -141,8 +141,9 @@
         }
         ControlFlowGraph cfg = schedule == null ? null : schedule.getCFG();
         BlockMap<List<Node>> blockToNodes = schedule == null ? null : schedule.getBlockToNodesMap();
+        NodeMap<Block> nodeToBlocks = schedule == null ? null : schedule.getNodeToBlockMap();
         List<Block> blocks = cfg == null ? null : cfg.getBlocks();
-        writeNodes(graph);
+        writeNodes(graph, nodeToBlocks);
         writeBlocks(blocks, blockToNodes);
     }
 
@@ -399,7 +400,7 @@
         return node.getId();
     }
 
-    private void writeNodes(Graph graph) throws IOException {
+    private void writeNodes(Graph graph, NodeMap<Block> nodeToBlocks) throws IOException {
         ToDoubleFunction<FixedNode> probabilities = null;
         if (PrintGraphProbabilities.getValue()) {
             try {
@@ -421,6 +422,16 @@
                     props.put("probability", t);
                 }
             }
+            if (nodeToBlocks != null) {
+                if (nodeToBlocks.isNew(node)) {
+                    props.put("node-to-block", "NEW (not in schedule)");
+                } else {
+                    Block block = nodeToBlocks.get(node);
+                    if (block != null) {
+                        props.put("node-to-block", block.getId());
+                    }
+                }
+            }
             writeInt(getNodeId(node));
             writePoolObject(nodeClass);
             writeByte(node.predecessor() == null ? 0 : 1);
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ReplacementsParseTest.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ReplacementsParseTest.java	Fri Mar 27 17:02:53 2015 +0100
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.replacements.test;
 
+import java.util.function.*;
+
 import org.junit.*;
 
 import com.oracle.graal.api.meta.*;
@@ -34,6 +36,9 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.runtime.*;
 
+/**
+ * Tests for expected behavior when parsing snippets and intrinsics.
+ */
 public class ReplacementsParseTest extends GraalCompilerTest {
 
     private static final Object THROW_EXCEPTION_MARKER = new Object() {
@@ -64,6 +69,10 @@
             }
             return res;
         }
+
+        static String identity(String s) {
+            return s;
+        }
     }
 
     @ClassSubstitution(TestMethods.class)
@@ -75,11 +84,17 @@
             return Math.nextAfter(xx, d);
         }
 
+        /**
+         * Tests partial intrinsification.
+         */
         @MethodSubstitution
         static String stringize(Object obj) {
             if (obj != null && obj.getClass() == String.class) {
                 return asNonNullString(obj);
             } else {
+                // A recursive call denotes exiting/deoptimizing
+                // out of the partial intrinsification to the
+                // slow/uncommon case.
                 return stringize(obj);
             }
         }
@@ -91,6 +106,17 @@
         @NodeIntrinsic(PiNode.class)
         private static native String asNonNullStringIntrinsic(Object object, @ConstantNodeParameter Class<?> toType, @ConstantNodeParameter boolean exactType, @ConstantNodeParameter boolean nonNull);
 
+        /**
+         * Tests that non-capturing lambdas are folded away.
+         */
+        @MethodSubstitution
+        static String identity(String value) {
+            return apply(s -> s, value);
+        }
+
+        private static String apply(Function<String, String> f, String value) {
+            return f.apply(value);
+        }
     }
 
     private static boolean substitutionsInstalled;
@@ -156,7 +182,7 @@
         test("callStringize", Boolean.TRUE);
     }
 
-    public Object callStringize(Object obj) {
+    public static Object callStringize(Object obj) {
         return TestMethods.stringize(obj);
     }
 
@@ -167,4 +193,14 @@
         test(method, null, Boolean.TRUE);
         test(method, null, THROW_EXCEPTION_MARKER);
     }
+
+    @Test
+    public void testLambda() {
+        test("callLambda", (String) null);
+        test("callLambda", "a string");
+    }
+
+    public static String callLambda(String value) {
+        return TestMethods.identity(value);
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/SubstitutionsTest.java	Fri Mar 27 17:02:53 2015 +0100
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.replacements.test;
+
+import static com.oracle.graal.nodeinfo.InputType.*;
+import static org.hamcrest.CoreMatchers.*;
+
+import org.junit.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.compiler.test.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.iterators.*;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodeinfo.StructuralInput.Guard;
+import com.oracle.graal.nodeinfo.StructuralInput.Memory;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.extended.*;
+
+public class SubstitutionsTest extends GraalCompilerTest {
+
+    @NodeInfo(allowedUsageTypes = {Memory})
+    private static class TestMemory extends FixedWithNextNode implements MemoryNode {
+        private static final NodeClass<TestMemory> TYPE = NodeClass.create(TestMemory.class);
+
+        public TestMemory() {
+            super(TYPE, StampFactory.forVoid());
+        }
+
+        @NodeIntrinsic
+        public static native Memory memory();
+    }
+
+    @NodeInfo(allowedUsageTypes = {Guard})
+    private static class TestGuard extends FloatingNode implements GuardingNode {
+        private static final NodeClass<TestGuard> TYPE = NodeClass.create(TestGuard.class);
+
+        @Input(Memory) MemoryNode memory;
+
+        public TestGuard(ValueNode memory) {
+            super(TYPE, StampFactory.forVoid());
+            this.memory = (MemoryNode) memory;
+        }
+
+        @NodeIntrinsic
+        public static native Guard guard(Memory memory);
+    }
+
+    @NodeInfo
+    private static class TestValue extends FloatingNode {
+        private static final NodeClass<TestValue> TYPE = NodeClass.create(TestValue.class);
+
+        @Input(Guard) GuardingNode guard;
+
+        public TestValue(ValueNode guard) {
+            super(TYPE, StampFactory.forKind(Kind.Int));
+            this.guard = (GuardingNode) guard;
+        }
+
+        @NodeIntrinsic
+        public static native int value(Guard guard);
+    }
+
+    private static class TestMethod {
+
+        public static int test() {
+            return 42;
+        }
+    }
+
+    @ClassSubstitution(TestMethod.class)
+    private static class TestMethodSubstitution {
+
+        @MethodSubstitution
+        public static int test() {
+            Memory memory = TestMemory.memory();
+            Guard guard = TestGuard.guard(memory);
+            return TestValue.value(guard);
+        }
+    }
+
+    private static boolean substitutionsInstalled;
+
+    public SubstitutionsTest() {
+        if (!substitutionsInstalled) {
+            getProviders().getReplacements().registerSubstitutions(TestMethod.class, TestMethodSubstitution.class);
+            substitutionsInstalled = true;
+        }
+    }
+
+    public static int callTest() {
+        return TestMethod.test();
+    }
+
+    @Override
+    protected boolean checkHighTierGraph(StructuredGraph graph) {
+        // Check that the graph contains the expected test nodes.
+        NodeIterable<ReturnNode> retNodes = graph.getNodes().filter(ReturnNode.class);
+        Assert.assertTrue("expected exactly one ReturnNode", retNodes.count() == 1);
+        ReturnNode ret = retNodes.first();
+
+        Assert.assertThat(ret.result(), instanceOf(TestValue.class));
+        TestValue value = (TestValue) ret.result();
+
+        Assert.assertThat(value.guard, instanceOf(TestGuard.class));
+        TestGuard guard = (TestGuard) value.guard;
+
+        Assert.assertThat(guard.memory, instanceOf(TestMemory.class));
+        TestMemory memory = (TestMemory) guard.memory;
+
+        // Remove the test nodes, replacing them by the constant 42.
+        // This implicitly makes sure that the rest of the graph is valid.
+        ret.replaceFirstInput(value, graph.unique(ConstantNode.forInt(42)));
+        value.safeDelete();
+        guard.safeDelete();
+        graph.removeFixed(memory);
+
+        return true;
+    }
+
+    @Test
+    public void snippetTest() {
+        test("callTest");
+    }
+}
--- a/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/NodeIntrinsicVerifier.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/NodeIntrinsicVerifier.java	Fri Mar 27 17:02:53 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -34,6 +34,8 @@
 import com.oracle.graal.graph.Node.ConstantNodeParameter;
 import com.oracle.graal.graph.Node.InjectedNodeParameter;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodeinfo.StructuralInput.MarkerType;
 
 public final class NodeIntrinsicVerifier extends AbstractVerifier {
 
@@ -55,6 +57,10 @@
         return env.getElementUtils().getTypeElement("com.oracle.graal.api.meta.ResolvedJavaType").asType();
     }
 
+    private TypeMirror structuralInputType() {
+        return env.getElementUtils().getTypeElement("com.oracle.graal.nodeinfo.StructuralInput").asType();
+    }
+
     public NodeIntrinsicVerifier(ProcessingEnvironment env) {
         super(env);
     }
@@ -100,6 +106,11 @@
             if (nodeClass.getModifiers().contains(Modifier.ABSTRACT)) {
                 env.getMessager().printMessage(Kind.ERROR, String.format("Cannot make @NodeIntrinsic for abstract node class %s.", nodeClass.getSimpleName()), element, annotation);
             } else {
+                TypeMirror ret = intrinsicMethod.getReturnType();
+                if (env.getTypeUtils().isAssignable(ret, structuralInputType())) {
+                    checkInputType(nodeClass, ret, element, annotation);
+                }
+
                 TypeMirror[] constructorSignature = constructorSignature(intrinsicMethod);
                 findConstructor(nodeClass, constructorSignature, intrinsicMethod, annotation);
             }
@@ -108,6 +119,39 @@
         }
     }
 
+    private void checkInputType(TypeElement nodeClass, TypeMirror returnType, Element element, AnnotationMirror annotation) {
+        InputType inputType = getInputType(returnType, element, annotation);
+        if (inputType != InputType.Value) {
+            boolean allowed = false;
+            InputType[] allowedTypes = nodeClass.getAnnotation(NodeInfo.class).allowedUsageTypes();
+            for (InputType allowedType : allowedTypes) {
+                if (inputType == allowedType) {
+                    allowed = true;
+                    break;
+                }
+            }
+            if (!allowed) {
+                env.getMessager().printMessage(Kind.ERROR, String.format("@NodeIntrinsic returns input type %s, but only %s is allowed.", inputType, Arrays.toString(allowedTypes)), element,
+                                annotation);
+            }
+        }
+    }
+
+    private InputType getInputType(TypeMirror type, Element element, AnnotationMirror annotation) {
+        TypeElement current = (TypeElement) env.getTypeUtils().asElement(type);
+        while (current != null) {
+            MarkerType markerType = current.getAnnotation(MarkerType.class);
+            if (markerType != null) {
+                return markerType.value();
+            }
+
+            current = (TypeElement) env.getTypeUtils().asElement(current.getSuperclass());
+        }
+
+        env.getMessager().printMessage(Kind.ERROR, String.format("The class %s is a subclass of StructuralInput, but isn't annotated with @MarkerType.", type), element, annotation);
+        return InputType.Value;
+    }
+
     private boolean isNodeType(TypeElement nodeClass) {
         return env.getTypeUtils().isSubtype(nodeClass.asType(), nodeType());
     }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultGenericInvocationPlugin.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultGenericInvocationPlugin.java	Fri Mar 27 17:02:53 2015 +0100
@@ -29,9 +29,12 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.graphbuilderconf.*;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodeinfo.StructuralInput.MarkerType;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.word.*;
@@ -44,15 +47,19 @@
     protected final NodeIntrinsificationPhase nodeIntrinsification;
     protected final WordOperationPlugin wordOperationPlugin;
 
-    public DefaultGenericInvocationPlugin(NodeIntrinsificationPhase nodeIntrinsification, WordOperationPlugin wordOperationPlugin) {
+    private final ResolvedJavaType structuralInputType;
+
+    public DefaultGenericInvocationPlugin(MetaAccessProvider metaAccess, NodeIntrinsificationPhase nodeIntrinsification, WordOperationPlugin wordOperationPlugin) {
         this.nodeIntrinsification = nodeIntrinsification;
         this.wordOperationPlugin = wordOperationPlugin;
+
+        this.structuralInputType = metaAccess.lookupJavaType(StructuralInput.class);
     }
 
     public boolean apply(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
-        if (wordOperationPlugin.apply(b, method, args)) {
+        if (b.parsingReplacement() && wordOperationPlugin.apply(b, method, args)) {
             return true;
-        } else if (b.parsingReplacement() || b.eagerResolving()) {
+        } else if (b.parsingReplacement()) {
             NodeIntrinsic intrinsic = nodeIntrinsification.getIntrinsic(method);
             if (intrinsic != null) {
                 Signature sig = method.getSignature();
@@ -78,8 +85,8 @@
                 if (!COULD_NOT_FOLD.equals(constant)) {
                     if (constant != null) {
                         // Replace the invoke with the result of the call
-                        ConstantNode res = b.append(ConstantNode.forConstant(constant, b.getMetaAccess()));
-                        b.push(res.getKind().getStackKind(), b.append(res));
+                        ConstantNode res = b.add(ConstantNode.forConstant(constant, b.getMetaAccess()));
+                        b.addPush(res.getKind().getStackKind(), res);
                     } else {
                         // This must be a void invoke
                         assert method.getSignature().getReturnKind() == Kind.Void;
@@ -91,6 +98,24 @@
         return false;
     }
 
+    private InputType getInputType(ObjectStamp stamp) {
+        ResolvedJavaType type = stamp.type();
+        if (type != null && structuralInputType.isAssignableFrom(type)) {
+            while (type != null) {
+                MarkerType markerType = type.getAnnotation(MarkerType.class);
+                if (markerType != null) {
+                    return markerType.value();
+                }
+
+                type = type.getSuperclass();
+            }
+
+            throw GraalInternalError.shouldNotReachHere(String.format("%s extends StructuralInput, but is not annotated with @MarkerType", stamp.type()));
+        } else {
+            return InputType.Value;
+        }
+    }
+
     protected boolean processNodeIntrinsic(GraphBuilderContext b, ResolvedJavaMethod method, NodeIntrinsic intrinsic, List<ValueNode> args, Kind returnKind, Stamp stamp) {
         ValueNode res = createNodeIntrinsic(b, method, intrinsic, args, stamp);
         if (res == null) {
@@ -98,18 +123,25 @@
         }
         if (res instanceof UnsafeCopyNode) {
             UnsafeCopyNode copy = (UnsafeCopyNode) res;
-            UnsafeLoadNode value = b.append(new UnsafeLoadNode(copy.sourceObject(), copy.sourceOffset(), copy.accessKind(), copy.getLocationIdentity()));
-            UnsafeStoreNode unsafeStore = new UnsafeStoreNode(copy.destinationObject(), copy.destinationOffset(), value, copy.accessKind(), copy.getLocationIdentity());
-            b.append(unsafeStore);
-            unsafeStore.setStateAfter(b.createStateAfter());
+            UnsafeLoadNode value = b.add(new UnsafeLoadNode(copy.sourceObject(), copy.sourceOffset(), copy.accessKind(), copy.getLocationIdentity()));
+            b.add(new UnsafeStoreNode(copy.destinationObject(), copy.destinationOffset(), value, copy.accessKind(), copy.getLocationIdentity()));
             return true;
         } else if (res instanceof ForeignCallNode) {
             ForeignCallNode foreign = (ForeignCallNode) res;
             foreign.setBci(b.bci());
         }
 
-        res = b.append(res);
-        if (returnKind != Kind.Void) {
+        res = b.add(res);
+
+        InputType inputType = InputType.Value;
+        if (returnKind == Kind.Object && stamp instanceof ObjectStamp) {
+            inputType = getInputType((ObjectStamp) stamp);
+        }
+
+        if (inputType != InputType.Value) {
+            assert res.isAllowedUsageType(inputType);
+            b.push(Kind.Object, res);
+        } else if (returnKind != Kind.Void) {
             assert res.getKind().getStackKind() != Kind.Void;
             b.push(returnKind.getStackKind(), res);
         } else {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultInlineInvokePlugin.java	Fri Mar 27 17:02:53 2015 +0100
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.replacements;
+
+import static com.oracle.graal.compiler.common.GraalOptions.*;
+import static com.oracle.graal.java.AbstractBytecodeParser.Options.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graphbuilderconf.*;
+import com.oracle.graal.nodes.*;
+
+public final class DefaultInlineInvokePlugin implements InlineInvokePlugin {
+    private final ReplacementsImpl replacements;
+
+    public DefaultInlineInvokePlugin(ReplacementsImpl replacements) {
+        this.replacements = replacements;
+    }
+
+    public InlineInfo getInlineInfo(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType) {
+        InlineInfo inlineInfo = replacements.getInlineInfo(b, method, args, returnType);
+        if (inlineInfo == null) {
+            if (InlineDuringParsing.getValue() && method.hasBytecodes() && method.getCode().length <= TrivialInliningSize.getValue() && b.getDepth() < InlineDuringParsingMaxDepth.getValue()) {
+                return new InlineInfo(method, false, false);
+            }
+        }
+        return inlineInfo;
+    }
+
+    public void notifyOfNoninlinedInvoke(GraphBuilderContext b, ResolvedJavaMethod method, Invoke invoke) {
+        replacements.notifyOfNoninlinedInvoke(b, method, invoke);
+    }
+}
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/MathSubstitutionsX86.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/MathSubstitutionsX86.java	Fri Mar 27 17:02:53 2015 +0100
@@ -27,7 +27,6 @@
 import com.oracle.graal.graph.Node.ConstantNodeParameter;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.replacements.nodes.*;
 import com.oracle.graal.replacements.nodes.MathIntrinsicNode.Operation;
 
@@ -42,7 +41,6 @@
     /**
      * Special cases from {@link Math#pow} and __ieee754_pow (in sharedRuntimeTrans.cpp).
      */
-    @MacroSubstitution(macro = MathPowNode.class)
     @MethodSubstitution(guard = MathGuard.class)
     public static double pow(double x, double y) {
         // If the second argument is positive or negative zero, then the result is 1.0.
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Fri Mar 27 17:02:53 2015 +0100
@@ -25,7 +25,9 @@
 import static com.oracle.graal.api.meta.MetaUtil.*;
 import static com.oracle.graal.compiler.GraalCompiler.*;
 import static com.oracle.graal.compiler.common.GraalOptions.*;
+import static com.oracle.graal.java.AbstractBytecodeParser.Options.*;
 import static com.oracle.graal.phases.common.DeadCodeEliminationPhase.Optionality.*;
+import static java.lang.String.*;
 
 import java.lang.reflect.*;
 import java.util.*;
@@ -42,8 +44,11 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.graphbuilderconf.*;
 import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import com.oracle.graal.graphbuilderconf.GraphBuilderContext.*;
+import com.oracle.graal.graphbuilderconf.InlineInvokePlugin.InlineInfo;
 import com.oracle.graal.java.AbstractBytecodeParser.IntrinsicContext;
 import com.oracle.graal.java.AbstractBytecodeParser.ReplacementContext;
 import com.oracle.graal.java.*;
@@ -56,8 +61,9 @@
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.phases.util.*;
+import com.oracle.graal.word.*;
 
-public class ReplacementsImpl implements Replacements {
+public class ReplacementsImpl implements Replacements, InlineInvokePlugin {
 
     public final Providers providers;
     public final SnippetReflectionProvider snippetReflection;
@@ -75,12 +81,61 @@
         this.graphBuilderPlugins = plugins;
     }
 
+    protected boolean hasGenericInvocationPluginAnnotation(ResolvedJavaMethod method) {
+        return nodeIntrinsificationPhase.getIntrinsic(method) != null || method.getAnnotation(Word.Operation.class) != null || nodeIntrinsificationPhase.isFoldable(method);
+    }
+
+    private static final int MAX_GRAPH_INLINING_DEPTH = 100; // more than enough
+
+    /**
+     * Determines whether a given method should be inlined based on whether it has a substitution or
+     * whether the inlining context is already within a substitution.
+     *
+     * @return an {@link InlineInfo} object specifying how {@code method} is to be inlined or null
+     *         if it should not be inlined based on substitution related criteria
+     */
+    public InlineInfo getInlineInfo(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType) {
+        ResolvedJavaMethod subst = getMethodSubstitutionMethod(method);
+        if (subst != null) {
+            if (b.parsingReplacement() || InlineDuringParsing.getValue()) {
+                // Forced inlining of intrinsics
+                return new InlineInfo(subst, true, true);
+            }
+            return null;
+        }
+        if (b.parsingReplacement()) {
+            assert !hasGenericInvocationPluginAnnotation(method) : format("%s should have been handled by %s", method.format("%H.%n(%p)"), DefaultGenericInvocationPlugin.class.getName());
+
+            assert b.getDepth() < MAX_GRAPH_INLINING_DEPTH : "inlining limit exceeded";
+
+            if (method.getName().startsWith("$jacoco")) {
+                throw new GraalInternalError("Found call to JaCoCo instrumentation method " + method.format("%H.%n(%p)") + ". Placing \"//JaCoCo Exclude\" anywhere in " +
+                                b.getMethod().getDeclaringClass().getSourceFileName() + " should fix this.");
+            }
+
+            // Force inlining when parsing replacements
+            return new InlineInfo(method, true, true);
+        } else {
+            assert nodeIntrinsificationPhase.getIntrinsic(method) == null : String.format("@%s method %s must only be called from within a replacement%n%s", NodeIntrinsic.class.getSimpleName(),
+                            method.format("%h.%n"), b);
+        }
+        return null;
+    }
+
+    public void notifyOfNoninlinedInvoke(GraphBuilderContext b, ResolvedJavaMethod method, Invoke invoke) {
+        if (b.parsingReplacement()) {
+            boolean compilingSnippet = b.getRootMethod().getAnnotation(Snippet.class) != null;
+            Replacement replacement = b.getReplacement();
+            assert compilingSnippet : format("All calls in the replacement %s must be inlined or intrinsified: found call to %s", replacement.getReplacementMethod().format("%H.%n(%p)"),
+                            method.format("%h.%n(%p)"));
+        }
+    }
+
     /**
      * Encapsulates method and macro substitutions for a single class.
      */
     protected class ClassReplacements {
         public final Map<ResolvedJavaMethod, ResolvedJavaMethod> methodSubstitutions = CollectionsFactory.newMap();
-        public final Map<ResolvedJavaMethod, Class<? extends FixedWithNextNode>> macroSubstitutions = CollectionsFactory.newMap();
         public final Set<ResolvedJavaMethod> forcedSubstitutions = new HashSet<>();
 
         public ClassReplacements(Class<?>[] substitutionClasses, AtomicReference<ClassReplacements> ref) {
@@ -94,8 +149,7 @@
                         return;
                     }
                     MethodSubstitution methodSubstitution = substituteMethod.getAnnotation(MethodSubstitution.class);
-                    MacroSubstitution macroSubstitution = substituteMethod.getAnnotation(MacroSubstitution.class);
-                    if (methodSubstitution == null && macroSubstitution == null) {
+                    if (methodSubstitution == null) {
                         continue;
                     }
 
@@ -110,9 +164,6 @@
                             guard = defaultGuard;
                         }
 
-                        if (macroSubstitution != null && macroSubstitution.isStatic() != methodSubstitution.isStatic()) {
-                            throw new GraalInternalError("Macro and method substitution must agree on isStatic attribute: " + substituteMethod);
-                        }
                         if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) {
                             throw new GraalInternalError("Substitution method must not be abstract or native: " + substituteMethod);
                         }
@@ -130,21 +181,6 @@
                             }
                         }
                     }
-                    // We don't have per method guards for macro substitutions but at
-                    // least respect the defaultGuard if there is one.
-                    if (macroSubstitution != null && (defaultGuard == null || defaultGuard.execute())) {
-                        String originalName = originalName(substituteMethod, macroSubstitution.value());
-                        JavaSignature originalSignature = originalSignature(substituteMethod, macroSubstitution.signature(), macroSubstitution.isStatic());
-                        Executable[] originalMethods = originalMethods(classSubstitution, macroSubstitution.optional(), originalName, originalSignature);
-                        for (Executable originalMethod : originalMethods) {
-                            if (originalMethod != null) {
-                                ResolvedJavaMethod original = registerMacroSubstitution(this, originalMethod, macroSubstitution.macro());
-                                if (original != null && macroSubstitution.forced() && shouldIntrinsify(original)) {
-                                    forcedSubstitutions.add(original);
-                                }
-                            }
-                        }
-                    }
                 }
             }
         }
@@ -321,11 +357,6 @@
 
     }
 
-    public Class<? extends FixedWithNextNode> getMacroSubstitution(ResolvedJavaMethod method) {
-        ClassReplacements cr = getClassReplacements(method.getDeclaringClass().getName());
-        return cr == null ? null : cr.macroSubstitutions.get(method);
-    }
-
     private SubstitutionGuard getGuard(Class<? extends SubstitutionGuard> guardClass) {
         if (guardClass != SubstitutionGuard.class) {
             Constructor<?>[] constructors = guardClass.getConstructors();
@@ -409,20 +440,6 @@
     }
 
     /**
-     * Registers a macro substitution.
-     *
-     * @param originalMethod a method or constructor being substituted
-     * @param macro the substitute macro node class
-     * @return the original method
-     */
-    protected ResolvedJavaMethod registerMacroSubstitution(ClassReplacements cr, Executable originalMethod, Class<? extends FixedWithNextNode> macro) {
-        MetaAccessProvider metaAccess = providers.getMetaAccess();
-        ResolvedJavaMethod originalJavaMethod = metaAccess.lookupJavaMethod(originalMethod);
-        cr.macroSubstitutions.put(originalJavaMethod, macro);
-        return originalJavaMethod;
-    }
-
-    /**
      * Creates a preprocessed graph for a snippet or method substitution.
      *
      * @param method the snippet or method substitution for which a graph will be created
@@ -770,7 +787,6 @@
         for (String internalName : classReplacements.keySet()) {
             ClassReplacements cr = getClassReplacements(internalName);
             result.addAll(cr.methodSubstitutions.keySet());
-            result.addAll(cr.macroSubstitutions.keySet());
         }
         return result;
     }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java	Fri Mar 27 17:02:53 2015 +0100
@@ -108,9 +108,7 @@
                 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset, ValueNode expected, ValueNode x) {
                     // Emits a null-check for the otherwise unused receiver
                     unsafe.get();
-                    CompareAndSwapNode compareAndSwap = new CompareAndSwapNode(object, offset, expected, x, kind, LocationIdentity.any());
-                    b.push(Kind.Boolean.getStackKind(), b.append(compareAndSwap));
-                    compareAndSwap.setStateAfter(b.createStateAfter());
+                    b.addPush(Kind.Int, new CompareAndSwapNode(object, offset, expected, x, kind, LocationIdentity.any()));
                     return true;
                 }
             });
@@ -120,9 +118,7 @@
                     public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset, ValueNode value) {
                         // Emits a null-check for the otherwise unused receiver
                         unsafe.get();
-                        AtomicReadAndWriteNode atomicReadWrite = new AtomicReadAndWriteNode(object, offset, value, kind, LocationIdentity.any());
-                        b.push(kind.getStackKind(), b.append(atomicReadWrite));
-                        atomicReadWrite.setStateAfter(b.createStateAfter());
+                        b.addPush(kind.getStackKind(), new AtomicReadAndWriteNode(object, offset, value, kind, LocationIdentity.any()));
                         return true;
                     }
                 });
@@ -131,9 +127,7 @@
                         public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset, ValueNode delta) {
                             // Emits a null-check for the otherwise unused receiver
                             unsafe.get();
-                            AtomicReadAndAddNode atomicReadAdd = new AtomicReadAndAddNode(object, offset, delta, LocationIdentity.any());
-                            b.push(kind.getStackKind(), b.append(atomicReadAdd));
-                            atomicReadAdd.setStateAfter(b.createStateAfter());
+                            b.addPush(kind.getStackKind(), new AtomicReadAndAddNode(object, offset, delta, LocationIdentity.any()));
                             return true;
                         }
                     });
@@ -186,9 +180,9 @@
         r.register1("reverseBytes", char.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
                 // return (char) (Integer.reverse(i) >> 16);
-                ReverseBytesNode reverse = b.append(new ReverseBytesNode(value));
-                RightShiftNode rightShift = b.append(new RightShiftNode(reverse, b.append(ConstantNode.forInt(16))));
-                ZeroExtendNode charCast = b.append(new ZeroExtendNode(b.append(new NarrowNode(rightShift, 16)), 32));
+                ReverseBytesNode reverse = b.add(new ReverseBytesNode(value));
+                RightShiftNode rightShift = b.add(new RightShiftNode(reverse, b.add(ConstantNode.forInt(16))));
+                ZeroExtendNode charCast = b.add(new ZeroExtendNode(b.add(new NarrowNode(rightShift, 16)), 32));
                 b.push(Kind.Char.getStackKind(), b.recursiveAppend(charCast.canonical(null, value)));
                 return true;
             }
@@ -200,9 +194,9 @@
         r.register1("reverseBytes", short.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
                 // return (short) (Integer.reverse(i) >> 16);
-                ReverseBytesNode reverse = b.append(new ReverseBytesNode(value));
-                RightShiftNode rightShift = b.append(new RightShiftNode(reverse, b.append(ConstantNode.forInt(16))));
-                SignExtendNode charCast = b.append(new SignExtendNode(b.append(new NarrowNode(rightShift, 16)), 32));
+                ReverseBytesNode reverse = b.add(new ReverseBytesNode(value));
+                RightShiftNode rightShift = b.add(new RightShiftNode(reverse, b.add(ConstantNode.forInt(16))));
+                SignExtendNode charCast = b.add(new SignExtendNode(b.add(new NarrowNode(rightShift, 16)), 32));
                 b.push(Kind.Short.getStackKind(), b.recursiveAppend(charCast.canonical(null, value)));
                 return true;
             }
@@ -261,6 +255,17 @@
                 return true;
             }
         });
+        r.register2("pow", Double.TYPE, Double.TYPE, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) {
+                ValueNode folded = MathPowNode.tryFold(x, y);
+                if (folded != null) {
+                    b.addPush(Kind.Double, folded);
+                } else {
+                    b.addPush(Kind.Double, new MathPowNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnType(), x, y));
+                }
+                return true;
+            }
+        });
         if (getAndSetEnabled(arch)) {
             r.register1("log", Double.TYPE, new InvocationPlugin() {
                 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
@@ -302,7 +307,7 @@
             }
 
             LogicNode compare = CompareNode.createCompareNode(graph, cond, lhs, rhs, b.getConstantReflection());
-            b.push(Kind.Boolean.getStackKind(), b.append(new ConditionalNode(compare, trueValue, falseValue)));
+            b.addPush(Kind.Boolean.getStackKind(), new ConditionalNode(compare, trueValue, falseValue));
             return true;
         }
     }
@@ -358,9 +363,7 @@
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
                 ValueNode object = receiver.get();
                 if (RegisterFinalizerNode.mayHaveFinalizer(object, b.getAssumptions())) {
-                    RegisterFinalizerNode registerFinalizer = new RegisterFinalizerNode(object);
-                    b.append(registerFinalizer);
-                    registerFinalizer.setStateAfter(b.createStateAfter());
+                    b.add(new RegisterFinalizerNode(object));
                 }
                 return true;
             }
@@ -371,7 +374,7 @@
         Registration r = new Registration(plugins, Class.class);
         r.register2("isInstance", Receiver.class, Object.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver type, ValueNode object) {
-                LogicNode condition = b.append(InstanceOfDynamicNode.create(b.getConstantReflection(), type.get(), object));
+                LogicNode condition = b.add(InstanceOfDynamicNode.create(b.getConstantReflection(), type.get(), object));
                 b.push(Kind.Boolean.getStackKind(), b.recursiveAppend(new ConditionalNode(condition).canonical(null)));
                 return true;
             }
@@ -383,18 +386,6 @@
                 return true;
             }
         });
-        r.register2("cast", Receiver.class, Object.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) {
-                if (receiver.isConstant()) {
-                    ResolvedJavaType type = b.getConstantReflection().asJavaType(receiver.get().asConstant());
-                    if (type != null && !type.isPrimitive()) {
-                        b.push(Kind.Object, b.append(CheckCastNode.create(type, object, null, false, b.getAssumptions())));
-                        return true;
-                    }
-                }
-                return false;
-            }
-        });
     }
 
     /**
@@ -409,18 +400,16 @@
         for (Class<?> c : new Class<?>[]{Node.class, NodeList.class}) {
             r.register2("get" + c.getSimpleName() + "Unsafe", Node.class, long.class, new InvocationPlugin() {
                 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode node, ValueNode offset) {
-                    ValueNode value = b.append(new UnsafeLoadNode(node, offset, Kind.Object, LocationIdentity.any()));
+                    ValueNode value = b.add(new UnsafeLoadNode(node, offset, Kind.Object, LocationIdentity.any()));
                     boolean exactType = false;
                     boolean nonNull = false;
-                    b.push(Kind.Object, b.append(new PiNode(value, metaAccess.lookupJavaType(c), exactType, nonNull)));
+                    b.addPush(Kind.Object, new PiNode(value, metaAccess.lookupJavaType(c), exactType, nonNull));
                     return true;
                 }
             });
             r.register3("put" + c.getSimpleName() + "Unsafe", Node.class, long.class, c, new InvocationPlugin() {
                 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode node, ValueNode offset, ValueNode value) {
-                    UnsafeStoreNode unsafeStore = new UnsafeStoreNode(node, offset, value, Kind.Object, LocationIdentity.any());
-                    b.append(unsafeStore);
-                    unsafeStore.setStateAfter(b.createStateAfter());
+                    b.add(new UnsafeStoreNode(node, offset, value, Kind.Object, LocationIdentity.any()));
                     return true;
                 }
             });
@@ -445,7 +434,7 @@
                 }
             }
             ResolvedJavaType resultType = b.getMetaAccess().lookupJavaType(kind.toBoxedJavaClass());
-            b.push(Kind.Object, b.append(new BoxNode(value, resultType, kind)));
+            b.addPush(Kind.Object, new BoxNode(value, resultType, kind));
             return true;
         }
 
@@ -472,7 +461,7 @@
                 }
             }
             ValueNode valueNode = UnboxNode.create(b.getMetaAccess(), b.getConstantReflection(), receiver.get(), kind);
-            b.push(kind.getStackKind(), b.append(valueNode));
+            b.addPush(kind.getStackKind(), valueNode);
             return true;
         }
 
@@ -495,7 +484,7 @@
         public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode address) {
             // Emits a null-check for the otherwise unused receiver
             unsafe.get();
-            b.push(returnKind.getStackKind(), b.append(new DirectReadNode(address, returnKind)));
+            b.addPush(returnKind.getStackKind(), new DirectReadNode(address, returnKind));
             return true;
         }
 
@@ -503,11 +492,11 @@
             // Emits a null-check for the otherwise unused receiver
             unsafe.get();
             if (isVolatile) {
-                b.append(new MembarNode(JMM_PRE_VOLATILE_READ));
+                b.add(new MembarNode(JMM_PRE_VOLATILE_READ));
             }
-            b.push(returnKind.getStackKind(), b.append(new UnsafeLoadNode(object, offset, returnKind, LocationIdentity.any())));
+            b.addPush(returnKind.getStackKind(), new UnsafeLoadNode(object, offset, returnKind, LocationIdentity.any()));
             if (isVolatile) {
-                b.append(new MembarNode(JMM_POST_VOLATILE_READ));
+                b.add(new MembarNode(JMM_POST_VOLATILE_READ));
             }
             return true;
         }
@@ -526,7 +515,7 @@
         public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode address, ValueNode value) {
             // Emits a null-check for the otherwise unused receiver
             unsafe.get();
-            b.append(new DirectStoreNode(address, value, kind));
+            b.add(new DirectStoreNode(address, value, kind));
             return true;
         }
 
@@ -534,13 +523,11 @@
             // Emits a null-check for the otherwise unused receiver
             unsafe.get();
             if (isVolatile) {
-                b.append(new MembarNode(JMM_PRE_VOLATILE_WRITE));
+                b.add(new MembarNode(JMM_PRE_VOLATILE_WRITE));
             }
-            UnsafeStoreNode unsafeStore = new UnsafeStoreNode(object, offset, value, kind, LocationIdentity.any());
-            b.append(unsafeStore);
-            unsafeStore.setStateAfter(b.createStateAfter());
+            b.add(new UnsafeStoreNode(object, offset, value, kind, LocationIdentity.any()));
             if (isVolatile) {
-                b.append(new MembarNode(JMM_PRE_VOLATILE_WRITE));
+                b.add(new MembarNode(JMM_PRE_VOLATILE_WRITE));
             }
             return true;
         }
@@ -550,42 +537,42 @@
         Registration r = new Registration(plugins, GraalDirectives.class);
         r.register0("deoptimize", new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
-                b.append(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.TransferToInterpreter));
+                b.add(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.TransferToInterpreter));
                 return true;
             }
         });
 
         r.register0("deoptimizeAndInvalidate", new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
-                b.append(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter));
+                b.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter));
                 return true;
             }
         });
 
         r.register0("inCompiledCode", new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
-                b.push(Kind.Int, b.append(ConstantNode.forInt(1)));
+                b.addPush(Kind.Int, ConstantNode.forInt(1));
                 return true;
             }
         });
 
         r.register0("controlFlowAnchor", new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
-                b.append(new ControlFlowAnchorNode());
+                b.add(new ControlFlowAnchorNode());
                 return true;
             }
         });
 
         r.register2("injectBranchProbability", double.class, boolean.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode probability, ValueNode condition) {
-                b.push(Kind.Int, b.append(new BranchProbabilityNode(probability, condition)));
+                b.addPush(Kind.Int, new BranchProbabilityNode(probability, condition));
                 return true;
             }
         });
 
         InvocationPlugin blackholePlugin = new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
-                b.append(new BlackholeNode(value));
+                b.add(new BlackholeNode(value));
                 return true;
             }
         };
@@ -598,7 +585,7 @@
                 final Kind stackKind = kind.getStackKind();
                 r.register1("opaque", javaClass, new InvocationPlugin() {
                     public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
-                        b.push(stackKind, b.append(new OpaqueNode(value)));
+                        b.addPush(stackKind, new OpaqueNode(value));
                         return true;
                     }
                 });
@@ -610,7 +597,7 @@
         InvocationPlugin blackholePlugin = new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver blackhole, ValueNode value) {
                 blackhole.get();
-                b.append(new BlackholeNode(value));
+                b.add(new BlackholeNode(value));
                 return true;
             }
         };
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/WordOperationPlugin.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/WordOperationPlugin.java	Fri Mar 27 17:02:53 2015 +0100
@@ -81,7 +81,7 @@
                 ValueNode left = args[0];
                 ValueNode right = operation.rightOperandIsInt() ? toUnsigned(b, args[1], Kind.Int) : fromSigned(b, args[1]);
 
-                b.push(returnStackKind, b.append(createBinaryNodeInstance(operation.node(), left, right)));
+                b.addPush(returnStackKind, createBinaryNodeInstance(operation.node(), left, right));
                 break;
 
             case COMPARISON:
@@ -91,7 +91,7 @@
 
             case NOT:
                 assert args.length == 1;
-                b.push(returnStackKind, b.append(new XorNode(args[0], b.append(forIntegerKind(wordKind, -1)))));
+                b.addPush(returnStackKind, new XorNode(args[0], b.add(forIntegerKind(wordKind, -1))));
                 break;
 
             case READ_POINTER:
@@ -133,7 +133,7 @@
             }
             case ZERO:
                 assert args.length == 0;
-                b.push(returnStackKind, b.append(forIntegerKind(wordKind, 0L)));
+                b.addPush(returnStackKind, forIntegerKind(wordKind, 0L));
                 break;
 
             case FROM_UNSIGNED:
@@ -158,18 +158,18 @@
 
             case FROM_OBJECT:
                 assert args.length == 1;
-                WordCastNode objectToWord = b.append(WordCastNode.objectToWord(args[0], wordKind));
+                WordCastNode objectToWord = b.add(WordCastNode.objectToWord(args[0], wordKind));
                 b.push(returnStackKind, objectToWord);
                 break;
 
             case FROM_ARRAY:
                 assert args.length == 2;
-                b.push(returnStackKind, b.append(new ComputeAddressNode(args[0], args[1], StampFactory.forKind(wordKind))));
+                b.addPush(returnStackKind, new ComputeAddressNode(args[0], args[1], StampFactory.forKind(wordKind)));
                 break;
 
             case TO_OBJECT:
                 assert args.length == 1;
-                WordCastNode wordToObject = b.append(WordCastNode.wordToObject(args[0], wordKind));
+                WordCastNode wordToObject = b.add(WordCastNode.wordToObject(args[0], wordKind));
                 b.push(returnStackKind, wordToObject);
                 break;
 
@@ -210,15 +210,15 @@
             comparison = new IntegerLessThanNode(a, b);
         }
 
-        ConstantNode trueValue = graph.append(forInt(1));
-        ConstantNode falseValue = graph.append(forInt(0));
+        ConstantNode trueValue = graph.add(forInt(1));
+        ConstantNode falseValue = graph.add(forInt(0));
 
         if (condition.canonicalNegate()) {
             ConstantNode temp = trueValue;
             trueValue = falseValue;
             falseValue = temp;
         }
-        ConditionalNode materialize = graph.append(new ConditionalNode(graph.append(comparison), trueValue, falseValue));
+        ConditionalNode materialize = graph.add(new ConditionalNode(graph.add(comparison), trueValue, falseValue));
         return materialize;
     }
 
@@ -231,7 +231,7 @@
     }
 
     public static ValueNode readOp(GraphBuilderContext b, Kind readKind, ValueNode base, LocationNode location, BarrierType barrierType, boolean compressible) {
-        JavaReadNode read = b.append(new JavaReadNode(readKind, base, location, barrierType, compressible));
+        JavaReadNode read = b.add(new JavaReadNode(readKind, base, location, barrierType, compressible));
         /*
          * The read must not float outside its block otherwise it may float above an explicit zero
          * check on its base address.
@@ -245,20 +245,18 @@
         final BarrierType barrier = (op == Opcode.WRITE_BARRIERED ? BarrierType.PRECISE : BarrierType.NONE);
         final boolean compressible = (op == Opcode.WRITE_OBJECT || op == Opcode.WRITE_BARRIERED);
         final boolean initialize = (op == Opcode.INITIALIZE);
-        JavaWriteNode writeNode = new JavaWriteNode(writeKind, base, value, location, barrier, compressible, initialize);
-        b.append(writeNode);
-        writeNode.setStateAfter(b.createStateAfter());
+        b.add(new JavaWriteNode(writeKind, base, value, location, barrier, compressible, initialize));
     }
 
     public LocationNode makeLocation(GraphBuilderContext b, ValueNode offset, LocationIdentity locationIdentity) {
-        return b.append(new IndexedLocationNode(locationIdentity, 0, fromSigned(b, offset), 1));
+        return b.add(new IndexedLocationNode(locationIdentity, 0, fromSigned(b, offset), 1));
     }
 
     public LocationNode makeLocation(GraphBuilderContext b, ValueNode offset, ValueNode locationIdentity) {
         if (locationIdentity.isConstant()) {
             return makeLocation(b, offset, snippetReflection.asObject(LocationIdentity.class, locationIdentity.asJavaConstant()));
         }
-        return b.append(new SnippetLocationNode(snippetReflection, locationIdentity, b.append(ConstantNode.forLong(0)), fromSigned(b, offset), b.append(ConstantNode.forInt(1))));
+        return b.add(new SnippetLocationNode(snippetReflection, locationIdentity, b.add(ConstantNode.forLong(0)), fromSigned(b, offset), b.add(ConstantNode.forInt(1))));
     }
 
     public ValueNode fromUnsigned(GraphBuilderContext b, ValueNode value) {
@@ -280,14 +278,14 @@
 
         if (toKind == Kind.Int) {
             assert value.getKind() == Kind.Long;
-            return b.append(new NarrowNode(value, 32));
+            return b.add(new NarrowNode(value, 32));
         } else {
             assert toKind == Kind.Long;
             assert value.getKind().getStackKind() == Kind.Int;
             if (unsigned) {
-                return b.append(new ZeroExtendNode(value, 64));
+                return b.add(new ZeroExtendNode(value, 64));
             } else {
-                return b.append(new SignExtendNode(value, 64));
+                return b.add(new SignExtendNode(value, 64));
             }
         }
     }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicArrayCopyNode.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicArrayCopyNode.java	Fri Mar 27 17:02:53 2015 +0100
@@ -27,6 +27,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.virtual.*;
@@ -36,8 +37,8 @@
 
     public static final NodeClass<BasicArrayCopyNode> TYPE = NodeClass.create(BasicArrayCopyNode.class);
 
-    public BasicArrayCopyNode(NodeClass<? extends BasicArrayCopyNode> c, Invoke invoke) {
-        super(c, invoke);
+    public BasicArrayCopyNode(NodeClass<? extends MacroNode> c, InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, JavaType returnType, ValueNode... arguments) {
+        super(c, invokeKind, targetMethod, bci, returnType, arguments);
     }
 
     protected ValueNode getSource() {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicObjectCloneNode.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicObjectCloneNode.java	Fri Mar 27 17:02:53 2015 +0100
@@ -30,6 +30,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.util.*;
@@ -40,8 +41,8 @@
 
     public static final NodeClass<BasicObjectCloneNode> TYPE = NodeClass.create(BasicObjectCloneNode.class);
 
-    protected BasicObjectCloneNode(NodeClass<? extends BasicObjectCloneNode> c, Invoke invoke) {
-        super(c, invoke);
+    public BasicObjectCloneNode(NodeClass<? extends MacroNode> c, InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, JavaType returnType, ValueNode... arguments) {
+        super(c, invokeKind, targetMethod, bci, returnType, arguments);
     }
 
     @Override
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Fri Mar 27 17:02:53 2015 +0100
@@ -42,9 +42,8 @@
 import com.oracle.graal.replacements.*;
 
 /**
- * Macro nodes can be used to temporarily replace an invoke (usually by using the
- * {@link MacroSubstitution} annotation). They can, for example, be used to implement constant
- * folding for known JDK functions like {@link Class#isInterface()}.<br/>
+ * Macro nodes can be used to temporarily replace an invoke. They can, for example, be used to
+ * implement constant folding for known JDK functions like {@link Class#isInterface()}.<br/>
  * <br/>
  * During lowering, multiple sources are queried in order to look for a replacement:
  * <ul>
@@ -77,6 +76,16 @@
         this.invokeKind = methodCallTarget.invokeKind();
     }
 
+    protected MacroNode(NodeClass<? extends MacroNode> c, InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, JavaType returnType, ValueNode... arguments) {
+        super(c, StampFactory.forKind(returnType.getKind()));
+        assert targetMethod.getSignature().getParameterCount(!targetMethod.isStatic()) == arguments.length;
+        this.arguments = new NodeInputList<>(this, arguments);
+        this.bci = bci;
+        this.targetMethod = targetMethod;
+        this.returnType = returnType;
+        this.invokeKind = invokeKind;
+    }
+
     public int getBci() {
         return bci;
     }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroStateSplitNode.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroStateSplitNode.java	Fri Mar 27 17:02:53 2015 +0100
@@ -28,6 +28,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.CallTargetNode.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 
@@ -41,9 +42,8 @@
     public static final NodeClass<MacroStateSplitNode> TYPE = NodeClass.create(MacroStateSplitNode.class);
     @OptionalInput(InputType.State) protected FrameState stateAfter;
 
-    public MacroStateSplitNode(NodeClass<? extends MacroStateSplitNode> c, Invoke invoke) {
-        super(c, invoke);
-        this.stateAfter = invoke.stateAfter();
+    protected MacroStateSplitNode(NodeClass<? extends MacroNode> c, InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, JavaType returnType, ValueNode... arguments) {
+        super(c, invokeKind, targetMethod, bci, returnType, arguments);
     }
 
     @Override
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathPowNode.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathPowNode.java	Fri Mar 27 17:02:53 2015 +0100
@@ -22,28 +22,34 @@
  */
 package com.oracle.graal.replacements.nodes;
 
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 
 @NodeInfo
 public final class MathPowNode extends MacroStateSplitNode implements Canonicalizable.Binary<ValueNode> {
 
     public static final NodeClass<MathPowNode> TYPE = NodeClass.create(MathPowNode.class);
 
-    public MathPowNode(Invoke i) {
-        super(TYPE, i);
+    public MathPowNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, JavaType returnType, ValueNode x, ValueNode y) {
+        super(TYPE, invokeKind, targetMethod, bci, returnType, x, y);
     }
 
     public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
-        if (forX.isConstant() && forY.isConstant()) {
-            double x = forX.asJavaConstant().asDouble();
-            double y = forY.asJavaConstant().asDouble();
-            return ConstantNode.forDouble(Math.pow(x, y));
-        } else {
-            return this;
+        ValueNode folded = tryFold(forX, forY);
+        return folded != null ? folded : this;
+    }
+
+    public static ValueNode tryFold(ValueNode x, ValueNode y) {
+        if (x.isConstant() && y.isConstant()) {
+            double xPrim = x.asJavaConstant().asDouble();
+            double yPrim = y.asJavaConstant().asDouble();
+            return ConstantNode.forDouble(Math.pow(xPrim, yPrim));
         }
+        return null;
     }
 
     public ValueNode getX() {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MemoryAnchorNode.java	Fri Mar 27 15:43:31 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.replacements.nodes;
-
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.spi.*;
-
-@NodeInfo(allowedUsageTypes = {InputType.Memory})
-public final class MemoryAnchorNode extends FixedWithNextNode implements LIRLowerable, MemoryNode, Canonicalizable {
-
-    public static final NodeClass<MemoryAnchorNode> TYPE = NodeClass.create(MemoryAnchorNode.class);
-
-    public MemoryAnchorNode() {
-        super(TYPE, StampFactory.forVoid());
-    }
-
-    public void generate(NodeLIRBuilderTool generator) {
-        // Nothing to emit, since this node is used for structural purposes only.
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        return hasNoUsages() ? null : this;
-    }
-}
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/PureFunctionMacroNode.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/PureFunctionMacroNode.java	Fri Mar 27 17:02:53 2015 +0100
@@ -27,6 +27,7 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 
 /**
  * This node class can be used to create {@link MacroNode}s for simple pure functions like
@@ -37,8 +38,8 @@
 
     public static final NodeClass<PureFunctionMacroNode> TYPE = NodeClass.create(PureFunctionMacroNode.class);
 
-    protected PureFunctionMacroNode(NodeClass<? extends PureFunctionMacroNode> c, Invoke invoke) {
-        super(c, invoke);
+    public PureFunctionMacroNode(NodeClass<? extends MacroNode> c, InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, JavaType returnType, ValueNode... arguments) {
+        super(c, invokeKind, targetMethod, bci, returnType, arguments);
     }
 
     /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/ConditionAnchoringTest.java	Fri Mar 27 17:02:53 2015 +0100
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.truffle.test;
+
+import static com.oracle.graal.graph.test.matchers.NodeIterableCount.*;
+import static com.oracle.graal.graph.test.matchers.NodeIterableIsEmpty.*;
+import static org.hamcrest.core.IsInstanceOf.*;
+import static org.junit.Assert.*;
+
+import org.junit.*;
+
+import sun.misc.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.test.*;
+import com.oracle.graal.graph.iterators.*;
+import com.oracle.graal.graphbuilderconf.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.spi.LoweringTool.StandardLoweringStage;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.tiers.*;
+import com.oracle.graal.truffle.nodes.*;
+import com.oracle.graal.truffle.substitutions.*;
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.unsafe.*;
+
+public class ConditionAnchoringTest extends GraalCompilerTest {
+    private static final UnsafeAccess access;
+    private static final long offset;
+    private static final Object location = new Object();
+
+    static {
+        Unsafe unsafe = com.oracle.graal.compiler.common.UnsafeAccess.unsafe;
+        access = Truffle.getRuntime().getCapability(UnsafeAccessFactory.class).createUnsafeAccess(unsafe);
+        long fieldOffset = 0;
+        try {
+            fieldOffset = unsafe.objectFieldOffset(CheckedObject.class.getDeclaredField("field"));
+        } catch (NoSuchFieldException | SecurityException e) {
+            e.printStackTrace();
+        }
+        offset = fieldOffset;
+    }
+
+    private static class CheckedObject {
+        int id;
+        int iid;
+        @SuppressWarnings("unused") int field;
+    }
+
+    public int checkedAccess(CheckedObject o) {
+        if (o.id == 42) {
+            return access.getInt(o, offset, o.id == 42, location);
+        }
+        return -1;
+    }
+
+    // test with a different kind of condition (not a comparison against a constant)
+    public int checkedAccess2(CheckedObject o) {
+        if (o.id == o.iid) {
+            return access.getInt(o, offset, o.id == o.iid, location);
+        }
+        return -1;
+    }
+
+    @Test
+    public void test() {
+        test("checkedAccess", 1);
+    }
+
+    @Test
+    public void test2() {
+        test("checkedAccess2", 2);
+    }
+
+    public void test(String name, int ids) {
+        StructuredGraph graph = parseEager(name, AllowAssumptions.YES);
+
+        NodeIterable<UnsafeLoadNode> unsafeNodes = graph.getNodes().filter(UnsafeLoadNode.class);
+        assertThat(unsafeNodes, hasCount(1));
+
+        // lower unsafe load
+        PhaseContext context = new PhaseContext(getProviders());
+        LoweringPhase lowering = new LoweringPhase(new CanonicalizerPhase(), StandardLoweringStage.HIGH_TIER);
+        lowering.apply(graph, context);
+
+        unsafeNodes = graph.getNodes().filter(UnsafeLoadNode.class);
+        NodeIterable<ConditionAnchorNode> conditionAnchors = graph.getNodes().filter(ConditionAnchorNode.class);
+        NodeIterable<ReadNode> reads = graph.getNodes().filter(ReadNode.class);
+        assertThat(unsafeNodes, isEmpty());
+        assertThat(conditionAnchors, hasCount(1));
+        assertThat(reads, hasCount(2 * ids + 1)); // 2 * ids id reads, 1 'field' access
+
+        // float reads and canonicalize to give a chance to conditions to GVN
+        FloatingReadPhase floatingReadPhase = new FloatingReadPhase();
+        floatingReadPhase.apply(graph);
+        CanonicalizerPhase canonicalizerPhase = new CanonicalizerPhase();
+        canonicalizerPhase.apply(graph, context);
+
+        NodeIterable<FloatingReadNode> floatingReads = graph.getNodes().filter(FloatingReadNode.class);
+        assertThat(floatingReads, hasCount(ids + 1)); // 1 id read, 1 'field' access
+
+        // apply DominatorConditionalEliminationPhase
+        DominatorConditionalEliminationPhase conditionalElimination = new DominatorConditionalEliminationPhase(false);
+        conditionalElimination.apply(graph);
+
+        floatingReads = graph.getNodes().filter(FloatingReadNode.class).filter(n -> ((FloatingReadNode) n).location().getLocationIdentity() instanceof ObjectLocationIdentity);
+        conditionAnchors = graph.getNodes().filter(ConditionAnchorNode.class);
+        assertThat(floatingReads, hasCount(1));
+        assertThat(conditionAnchors, isEmpty());
+        FloatingReadNode readNode = floatingReads.first();
+        assertThat(readNode.getGuard(), instanceOf(BeginNode.class));
+        assertThat(readNode.getGuard().asNode().predecessor(), instanceOf(IfNode.class));
+    }
+
+    @Override
+    protected GraphBuilderConfiguration editGraphBuilderConfiguration(GraphBuilderConfiguration conf) {
+        // get UnsafeAccessImpl.unsafeGetInt intrinsified
+        TruffleGraphBuilderPlugins.registerUnsafeAccessImplPlugins(conf.getPlugins().getInvocationPlugins());
+        // get UnsafeAccess.getInt inlined
+        conf.getPlugins().setInlineInvokePlugin(new InlineEverythingPlugin());
+        conf.getPlugins().setLoadFieldPlugin(new FoldLoadsPlugins(getMetaAccess(), getConstantReflection()));
+        return super.editGraphBuilderConfiguration(conf);
+    }
+
+    private static final class InlineEverythingPlugin implements InlineInvokePlugin {
+        public InlineInfo getInlineInfo(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType) {
+            assert method.hasBytecodes();
+            return new InlineInfo(method, false, false);
+        }
+    }
+
+    private static final class FoldLoadsPlugins implements LoadFieldPlugin {
+        private final MetaAccessProvider metaAccess;
+        private final ConstantReflectionProvider constantReflection;
+
+        public FoldLoadsPlugins(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection) {
+            this.metaAccess = metaAccess;
+            this.constantReflection = constantReflection;
+        }
+
+        public boolean apply(GraphBuilderContext graphBuilderContext, ValueNode receiver, ResolvedJavaField field) {
+            if (receiver.isConstant()) {
+                JavaConstant asJavaConstant = receiver.asJavaConstant();
+                return tryConstantFold(graphBuilderContext, metaAccess, constantReflection, field, asJavaConstant);
+            }
+            return false;
+        }
+
+        public boolean apply(GraphBuilderContext graphBuilderContext, ResolvedJavaField staticField) {
+            return tryConstantFold(graphBuilderContext, metaAccess, constantReflection, staticField, null);
+        }
+    }
+}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/FrameWithoutBoxing.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/FrameWithoutBoxing.java	Fri Mar 27 17:02:53 2015 +0100
@@ -274,24 +274,24 @@
     }
 
     private void verifySet(int slotIndex, byte tag) {
-        if (CompilerDirectives.inInterpreter() && slotIndex >= getTags().length) {
-            if (!resize()) {
-                throw new IllegalArgumentException(String.format("The frame slot '%s' is not known by the frame descriptor.", slotIndex));
-            }
-        }
+        checkSlotIndex(slotIndex);
         getTags()[slotIndex] = tag;
     }
 
     private void verifyGet(int slotIndex, byte tag) throws FrameSlotTypeException {
+        checkSlotIndex(slotIndex);
+        if (getTags()[slotIndex] != tag) {
+            CompilerDirectives.transferToInterpreter();
+            throw new FrameSlotTypeException();
+        }
+    }
+
+    private void checkSlotIndex(int slotIndex) {
         if (CompilerDirectives.inInterpreter() && slotIndex >= getTags().length) {
             if (!resize()) {
                 throw new IllegalArgumentException(String.format("The frame slot '%s' is not known by the frame descriptor.", slotIndex));
             }
         }
-        if (getTags()[slotIndex] != tag) {
-            CompilerDirectives.transferToInterpreter();
-            throw new FrameSlotTypeException();
-        }
     }
 
     private static long getPrimitiveOffset(int slotIndex) {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Fri Mar 27 17:02:53 2015 +0100
@@ -162,8 +162,8 @@
 
         public boolean apply(GraphBuilderContext builder, ResolvedJavaField staticField) {
             if (TruffleCompilerOptions.TruffleExcludeAssertions.getValue() && staticField.getName().equals("$assertionsDisabled")) {
-                ConstantNode trueNode = builder.append(ConstantNode.forBoolean(true));
-                builder.push(trueNode.getKind().getStackKind(), trueNode);
+                ConstantNode trueNode = builder.add(ConstantNode.forBoolean(true));
+                builder.addPush(trueNode);
                 return true;
             }
             return tryConstantFold(builder, providers.getMetaAccess(), providers.getConstantReflection(), staticField, null);
@@ -209,7 +209,7 @@
                     return inlineInfo;
                 }
             }
-            if (replacements != null && (replacements.getMethodSubstitutionMethod(original) != null || replacements.getMacroSubstitution(original) != null)) {
+            if (replacements != null && replacements.getMethodSubstitutionMethod(original) != null) {
                 return null;
             }
             assert !builder.parsingReplacement();
@@ -268,6 +268,9 @@
             if (targetMethod != null) {
                 // TODO maybe cast arguments
 
+                if (!targetMethod.canBeInlined()) {
+                    return null;
+                }
                 if (targetMethod.canBeStaticallyBound()) {
                     return new InlineInfo(targetMethod, false, false);
                 }
@@ -337,14 +340,9 @@
         new ConvertDeoptimizeToGuardPhase().apply(graph, tierContext);
 
         for (MethodCallTargetNode methodCallTargetNode : graph.getNodes(MethodCallTargetNode.TYPE)) {
-            Class<? extends FixedWithNextNode> macroSubstitution = providers.getReplacements().getMacroSubstitution(methodCallTargetNode.targetMethod());
-            if (macroSubstitution != null) {
-                InliningUtil.inlineMacroNode(methodCallTargetNode.invoke(), methodCallTargetNode.targetMethod(), macroSubstitution);
-            } else {
-                StructuredGraph inlineGraph = providers.getReplacements().getMethodSubstitution(methodCallTargetNode.targetMethod());
-                if (inlineGraph != null) {
-                    InliningUtil.inline(methodCallTargetNode.invoke(), inlineGraph, true, null);
-                }
+            StructuredGraph inlineGraph = providers.getReplacements().getMethodSubstitution(methodCallTargetNode.targetMethod());
+            if (inlineGraph != null) {
+                InliningUtil.inline(methodCallTargetNode.invoke(), inlineGraph, true, null);
             }
         }
 
@@ -359,6 +357,9 @@
         } catch (Throwable t) {
             Debug.handle(t);
         }
+
+        // recompute loop frequencies now that BranchProbabilities have had time to canonicalize
+        ComputeLoopFrequenciesClosure.compute(graph);
     }
 
     private void partialEvaluation(final OptimizedCallTarget callTarget, final StructuredGraph graph, PhaseContext baseContext, HighTierContext tierContext) {
@@ -513,12 +514,6 @@
                         }
 
                         Replacements replacements = providers.getReplacements();
-                        Class<? extends FixedWithNextNode> macroSubstitution = replacements.getMacroSubstitution(methodCallTargetNode.targetMethod());
-                        if (macroSubstitution != null) {
-                            InliningUtil.inlineMacroNode(methodCallTargetNode.invoke(), methodCallTargetNode.targetMethod(), macroSubstitution);
-                            changed = changedInIteration = true;
-                            continue;
-                        }
                         StructuredGraph inlineGraph = replacements.getMethodSubstitution(methodCallTargetNode.targetMethod());
 
                         ResolvedJavaMethod targetMethod = methodCallTargetNode.targetMethod();
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java	Fri Mar 27 17:02:53 2015 +0100
@@ -236,12 +236,7 @@
         for (Node newNode : graph.getNewNodes(mark)) {
             if (newNode instanceof MethodCallTargetNode) {
                 MethodCallTargetNode methodCallTargetNode = (MethodCallTargetNode) newNode;
-                Class<? extends FixedWithNextNode> macroSubstitution = providers.getReplacements().getMacroSubstitution(methodCallTargetNode.targetMethod());
-                if (macroSubstitution != null) {
-                    InliningUtil.inlineMacroNode(methodCallTargetNode.invoke(), methodCallTargetNode.targetMethod(), macroSubstitution);
-                } else {
-                    tryCutOffRuntimeExceptionsAndErrors(methodCallTargetNode);
-                }
+                tryCutOffRuntimeExceptionsAndErrors(methodCallTargetNode);
             }
         }
         return graph.getMark();
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleReplacements.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleReplacements.java	Fri Mar 27 17:02:53 2015 +0100
@@ -31,8 +31,6 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.util.*;
 import com.oracle.graal.replacements.*;
-import com.oracle.graal.truffle.substitutions.*;
-import com.oracle.truffle.api.*;
 
 /**
  * Custom {@link Replacements} for Truffle compilation.
@@ -44,15 +42,6 @@
     protected TruffleReplacements(Providers providers, SnippetReflectionProvider snippetReflection) {
         super(providers, snippetReflection, providers.getCodeCache().getTarget());
         this.graalReplacements = providers.getReplacements();
-
-        registerTruffleSubstitutions();
-    }
-
-    protected void registerTruffleSubstitutions() {
-        if (!TruffleCompilerOptions.FastPE.getValue()) {
-            registerSubstitutions(CompilerAsserts.class, CompilerAssertsSubstitutions.class);
-            registerSubstitutions(OptimizedAssumption.class, OptimizedAssumptionSubstitutions.class);
-        }
     }
 
     @Override
@@ -70,15 +59,6 @@
     }
 
     @Override
-    public Class<? extends FixedWithNextNode> getMacroSubstitution(ResolvedJavaMethod method) {
-        Class<? extends FixedWithNextNode> clazz = graalReplacements.getMacroSubstitution(method);
-        if (clazz == null) {
-            return super.getMacroSubstitution(method);
-        }
-        return clazz;
-    }
-
-    @Override
     public Collection<ResolvedJavaMethod> getAllReplacements() {
         throw GraalInternalError.shouldNotReachHere();
     }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/AssumptionNode.java	Fri Mar 27 15:43:31 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +0,0 @@
-/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.truffle.nodes;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.api.runtime.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.util.*;
-import com.oracle.graal.replacements.nodes.*;
-import com.oracle.graal.truffle.*;
-
-@NodeInfo
-public final class AssumptionNode extends MacroNode implements Simplifiable {
-
-    public static final NodeClass<AssumptionNode> TYPE = NodeClass.create(AssumptionNode.class);
-
-    public AssumptionNode(Invoke invoke) {
-        super(TYPE, invoke);
-        assert super.arguments.size() == 1;
-    }
-
-    private ValueNode getAssumption() {
-        return arguments.first();
-    }
-
-    private static SnippetReflectionProvider getSnippetReflection() {
-        /*
-         * This class requires access to the objects encapsulated in Constants, and therefore breaks
-         * the compiler-VM separation of object constants.
-         */
-        return Graal.getRequiredCapability(SnippetReflectionProvider.class);
-    }
-
-    @Override
-    public void lower(LoweringTool tool) {
-        throw new GraalInternalError(GraphUtil.approxSourceException(this, new RuntimeException("assumption could not be evaluated to a constant")));
-    }
-
-    @Override
-    public void simplify(SimplifierTool tool) {
-        ValueNode assumption = getAssumption();
-        Assumptions assumptions = graph().getAssumptions();
-        if (assumption.isConstant()) {
-            JavaConstant c = assumption.asJavaConstant();
-            assert c.getKind() == Kind.Object;
-            Object object = getSnippetReflection().asObject(Object.class, c);
-            OptimizedAssumption assumptionObject = (OptimizedAssumption) object;
-            StructuredGraph graph = graph();
-            if (assumptionObject.isValid()) {
-                assumptions.record(new AssumptionValidAssumption(assumptionObject));
-                if (super.getReturnType().getKind() == Kind.Boolean) {
-                    graph.replaceFixedWithFloating(this, ConstantNode.forBoolean(true, graph()));
-                } else {
-                    graph.removeFixed(this);
-                }
-            } else {
-                if (super.getReturnType().getKind() == Kind.Boolean) {
-                    graph.replaceFixedWithFloating(this, ConstantNode.forBoolean(false, graph()));
-                } else {
-                    tool.deleteBranch(this.next());
-                    this.replaceAndDelete(graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.None)));
-                }
-            }
-        }
-    }
-}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/NeverInlineMacroNode.java	Fri Mar 27 15:43:31 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.truffle.nodes.asserts;
-
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.replacements.nodes.*;
-
-@NodeInfo
-public final class NeverInlineMacroNode extends MacroStateSplitNode implements com.oracle.graal.graph.IterableNodeType {
-
-    public static final NodeClass<NeverInlineMacroNode> TYPE = NodeClass.create(NeverInlineMacroNode.class);
-
-    public NeverInlineMacroNode(Invoke invoke) {
-        super(TYPE, invoke);
-    }
-
-    @Override
-    public void lower(LoweringTool tool) {
-        InvokeNode invoke = createInvoke();
-        graph().replaceFixedWithFixed(this, invoke);
-        invoke.setUseForInlining(false);
-        invoke.lower(tool);
-    }
-}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/NeverPartOfCompilationNode.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/NeverPartOfCompilationNode.java	Fri Mar 27 17:02:53 2015 +0100
@@ -49,7 +49,4 @@
             throw GraphUtil.approxSourceException(neverPartOfCompilationNode, exception);
         }
     }
-
-    @NodeIntrinsic
-    public static native void apply(@ConstantNodeParameter String message);
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeLoadMacroNode.java	Fri Mar 27 15:43:31 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-/*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.truffle.nodes.typesystem;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.calc.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.replacements.nodes.*;
-import com.oracle.graal.truffle.nodes.*;
-
-/**
- * Macro node for CompilerDirectives#unsafeGetInt*.
- */
-@NodeInfo
-public final class CustomizedUnsafeLoadMacroNode extends MacroStateSplitNode implements Canonicalizable {
-    public static final NodeClass<CustomizedUnsafeLoadMacroNode> TYPE = NodeClass.create(CustomizedUnsafeLoadMacroNode.class);
-
-    private static final int ARGUMENT_COUNT = 4;
-    private static final int OBJECT_ARGUMENT_INDEX = 0;
-    private static final int OFFSET_ARGUMENT_INDEX = 1;
-    private static final int CONDITION_ARGUMENT_INDEX = 2;
-    private static final int LOCATION_ARGUMENT_INDEX = 3;
-
-    public CustomizedUnsafeLoadMacroNode(Invoke invoke) {
-        super(TYPE, invoke);
-        assert arguments.size() == ARGUMENT_COUNT;
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        ValueNode locationArgument = arguments.get(LOCATION_ARGUMENT_INDEX);
-        if (locationArgument.isConstant()) {
-            ValueNode objectArgument = arguments.get(OBJECT_ARGUMENT_INDEX);
-            ValueNode offsetArgument = arguments.get(OFFSET_ARGUMENT_INDEX);
-            ValueNode conditionArgument = arguments.get(CONDITION_ARGUMENT_INDEX);
-            LocationIdentity locationIdentity;
-            if (locationArgument.isNullConstant()) {
-                locationIdentity = LocationIdentity.any();
-            } else {
-                locationIdentity = ObjectLocationIdentity.create(locationArgument.asJavaConstant());
-            }
-            LogicNode compare = CompareNode.createCompareNode(Condition.EQ, conditionArgument, ConstantNode.forBoolean(true), tool.getConstantReflection());
-            Kind returnKind = this.getTargetMethod().getSignature().getReturnKind();
-            return new UnsafeLoadNode(objectArgument, offsetArgument, returnKind, locationIdentity, compare);
-        }
-        return this;
-    }
-}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeStoreMacroNode.java	Fri Mar 27 15:43:31 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +0,0 @@
-/*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.truffle.nodes.typesystem;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.replacements.nodes.*;
-import com.oracle.graal.truffle.nodes.*;
-
-/**
- * Macro node for method CompilerDirectives#unsafePut*.
- */
-@NodeInfo
-public final class CustomizedUnsafeStoreMacroNode extends MacroStateSplitNode implements Canonicalizable, StateSplit {
-    public static final NodeClass<CustomizedUnsafeStoreMacroNode> TYPE = NodeClass.create(CustomizedUnsafeStoreMacroNode.class);
-    private static final int ARGUMENT_COUNT = 4;
-    private static final int OBJECT_ARGUMENT_INDEX = 0;
-    private static final int OFFSET_ARGUMENT_INDEX = 1;
-    private static final int VALUE_ARGUMENT_INDEX = 2;
-    private static final int LOCATION_ARGUMENT_INDEX = 3;
-
-    public CustomizedUnsafeStoreMacroNode(Invoke invoke) {
-        super(TYPE, invoke);
-        assert arguments.size() == ARGUMENT_COUNT;
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        ValueNode locationArgument = arguments.get(LOCATION_ARGUMENT_INDEX);
-        if (locationArgument.isConstant()) {
-            ValueNode objectArgument = arguments.get(OBJECT_ARGUMENT_INDEX);
-            ValueNode offsetArgument = arguments.get(OFFSET_ARGUMENT_INDEX);
-            ValueNode valueArgument = arguments.get(VALUE_ARGUMENT_INDEX);
-            LocationIdentity locationIdentity;
-            if (locationArgument.isNullConstant()) {
-                locationIdentity = LocationIdentity.any();
-            } else {
-                locationIdentity = ObjectLocationIdentity.create(locationArgument.asJavaConstant());
-            }
-
-            return new UnsafeStoreNode(objectArgument, offsetArgument, valueArgument, this.getTargetMethod().getSignature().getParameterKind(VALUE_ARGUMENT_INDEX), locationIdentity, stateAfter());
-        }
-        return this;
-    }
-}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/UnsafeTypeCastMacroNode.java	Fri Mar 27 15:43:31 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.truffle.nodes.typesystem;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.calc.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.util.*;
-import com.oracle.graal.replacements.nodes.*;
-
-/**
- * Macro node for method CompilerDirectives#unsafeCast.
- */
-@NodeInfo
-public final class UnsafeTypeCastMacroNode extends MacroStateSplitNode implements Simplifiable {
-
-    public static final NodeClass<UnsafeTypeCastMacroNode> TYPE = NodeClass.create(UnsafeTypeCastMacroNode.class);
-    private static final int OBJECT_ARGUMENT_INDEX = 0;
-    private static final int CLASS_ARGUMENT_INDEX = 1;
-    private static final int CONDITION_ARGUMENT_INDEX = 2;
-    private static final int NONNULL_ARGUMENT_INDEX = 3;
-    private static final int ARGUMENT_COUNT = 4;
-
-    public UnsafeTypeCastMacroNode(Invoke invoke) {
-        super(TYPE, invoke);
-        assert arguments.size() == ARGUMENT_COUNT;
-    }
-
-    @Override
-    public void simplify(SimplifierTool tool) {
-        ValueNode classArgument = arguments.get(CLASS_ARGUMENT_INDEX);
-        ValueNode nonNullArgument = arguments.get(NONNULL_ARGUMENT_INDEX);
-        if (classArgument.isConstant() && nonNullArgument.isConstant()) {
-            ValueNode objectArgument = arguments.get(OBJECT_ARGUMENT_INDEX);
-            ValueNode conditionArgument = arguments.get(CONDITION_ARGUMENT_INDEX);
-            ResolvedJavaType lookupJavaType = tool.getConstantReflection().asJavaType(classArgument.asConstant());
-            tool.addToWorkList(usages());
-            if (lookupJavaType == null) {
-                replaceAtUsages(objectArgument);
-                GraphUtil.removeFixedWithUnusedInputs(this);
-            } else {
-                Stamp piStamp = StampFactory.declaredTrusted(lookupJavaType, nonNullArgument.asJavaConstant().asInt() != 0);
-                ConditionAnchorNode valueAnchorNode = graph().add(
-                                new ConditionAnchorNode(CompareNode.createCompareNode(graph(), Condition.EQ, conditionArgument, ConstantNode.forBoolean(true, graph()), tool.getConstantReflection())));
-                PiNode piCast = graph().unique(new PiNode(objectArgument, piStamp, valueAnchorNode));
-                replaceAtUsages(piCast);
-                graph().replaceFixedWithFixed(this, valueAnchorNode);
-            }
-        }
-    }
-}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/ReplaceIntrinsicsPhase.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/ReplaceIntrinsicsPhase.java	Fri Mar 27 17:02:53 2015 +0100
@@ -47,16 +47,10 @@
             if (methodCallTarget.isAlive()) {
                 InvokeKind invokeKind = methodCallTarget.invokeKind();
                 if (invokeKind.isDirect()) {
-                    Class<? extends FixedWithNextNode> macroSubstitution = replacements.getMacroSubstitution(methodCallTarget.targetMethod());
-                    if (macroSubstitution != null) {
-                        InliningUtil.inlineMacroNode(methodCallTarget.invoke(), methodCallTarget.targetMethod(), macroSubstitution);
+                    StructuredGraph inlineGraph = replacements.getMethodSubstitution(methodCallTarget.targetMethod());
+                    if (inlineGraph != null) {
+                        InliningUtil.inline(methodCallTarget.invoke(), inlineGraph, true, null);
                         Debug.dump(graph, "After inlining %s", methodCallTarget.targetMethod().toString());
-                    } else {
-                        StructuredGraph inlineGraph = replacements.getMethodSubstitution(methodCallTarget.targetMethod());
-                        if (inlineGraph != null) {
-                            InliningUtil.inline(methodCallTarget.invoke(), inlineGraph, true, null);
-                            Debug.dump(graph, "After inlining %s", methodCallTarget.targetMethod().toString());
-                        }
                     }
                 }
             }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/CompilerAssertsSubstitutions.java	Fri Mar 27 15:43:31 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,37 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.truffle.substitutions;
-
-import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.truffle.nodes.asserts.*;
-import com.oracle.truffle.api.*;
-
-@ClassSubstitution(CompilerAsserts.class)
-public class CompilerAssertsSubstitutions {
-
-    @MethodSubstitution
-    public static void neverPartOfCompilation(@SuppressWarnings("unused") String message) {
-        NeverPartOfCompilationNode.apply("Never part of compilation");
-    }
-
-}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/OptimizedAssumptionSubstitutions.java	Fri Mar 27 15:43:31 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.truffle.substitutions;
-
-import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.truffle.*;
-import com.oracle.graal.truffle.nodes.*;
-
-@ClassSubstitution(OptimizedAssumption.class)
-public class OptimizedAssumptionSubstitutions {
-
-    @MacroSubstitution(macro = AssumptionNode.class, isStatic = false, forced = true)
-    public static native void check(OptimizedAssumption assumption);
-
-    @MacroSubstitution(macro = AssumptionNode.class, isStatic = false, forced = true)
-    public static native boolean isValid(OptimizedAssumption assumption);
-}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java	Fri Mar 27 17:02:53 2015 +0100
@@ -55,6 +55,7 @@
         registerOptimizedAssumptionPlugins(plugins);
         registerExactMathPlugins(plugins);
         registerCompilerDirectivesPlugins(plugins);
+        registerCompilerAssertsPlugins(plugins);
         registerOptimizedCallTargetPlugins(metaAccess, plugins);
         registerUnsafeAccessImplPlugins(plugins);
 
@@ -68,21 +69,34 @@
 
     public static void registerOptimizedAssumptionPlugins(InvocationPlugins plugins) {
         Registration r = new Registration(plugins, OptimizedAssumption.class);
-        r.register1("isValid", Receiver.class, new InvocationPlugin() {
+        InvocationPlugin plugin = new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
                 if (receiver.isConstant()) {
                     Constant constant = receiver.get().asConstant();
                     OptimizedAssumption assumption = b.getSnippetReflection().asObject(OptimizedAssumption.class, (JavaConstant) constant);
-                    b.push(Kind.Boolean.getStackKind(), b.append(ConstantNode.forBoolean(assumption.isValid())));
                     if (assumption.isValid()) {
+                        if (targetMethod.getName().equals("isValid")) {
+                            b.addPush(ConstantNode.forBoolean(true));
+                        } else {
+                            assert targetMethod.getName().equals("check") : targetMethod;
+                        }
                         b.getAssumptions().record(new AssumptionValidAssumption(assumption));
+                    } else {
+                        if (targetMethod.getName().equals("isValid")) {
+                            b.addPush(ConstantNode.forBoolean(false));
+                        } else {
+                            assert targetMethod.getName().equals("check") : targetMethod;
+                            b.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.None));
+                        }
                     }
                 } else {
                     throw b.bailout("assumption could not be reduced to a constant");
                 }
                 return true;
             }
-        });
+        };
+        r.register1("isValid", Receiver.class, plugin);
+        r.register1("check", Receiver.class, plugin);
     }
 
     public static void registerExactMathPlugins(InvocationPlugins plugins) {
@@ -91,31 +105,31 @@
             Class<?> type = kind.toJavaClass();
             r.register2("addExact", type, type, new InvocationPlugin() {
                 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) {
-                    b.push(kind.getStackKind(), b.append(new IntegerAddExactNode(x, y)));
+                    b.addPush(kind.getStackKind(), new IntegerAddExactNode(x, y));
                     return true;
                 }
             });
             r.register2("subtractExact", type, type, new InvocationPlugin() {
                 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) {
-                    b.push(kind.getStackKind(), b.append(new IntegerSubExactNode(x, y)));
+                    b.addPush(kind.getStackKind(), new IntegerSubExactNode(x, y));
                     return true;
                 }
             });
             r.register2("multiplyExact", type, type, new InvocationPlugin() {
                 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) {
-                    b.push(kind.getStackKind(), b.append(new IntegerMulExactNode(x, y)));
+                    b.addPush(kind.getStackKind(), new IntegerMulExactNode(x, y));
                     return true;
                 }
             });
             r.register2("multiplyHigh", type, type, new InvocationPlugin() {
                 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) {
-                    b.push(kind.getStackKind(), b.append(new IntegerMulHighNode(x, y)));
+                    b.addPush(kind.getStackKind(), new IntegerMulHighNode(x, y));
                     return true;
                 }
             });
             r.register2("multiplyHighUnsigned", type, type, new InvocationPlugin() {
                 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) {
-                    b.push(kind.getStackKind(), b.append(new UnsignedMulHighNode(x, y)));
+                    b.addPush(kind.getStackKind(), new UnsignedMulHighNode(x, y));
                     return true;
                 }
             });
@@ -126,25 +140,25 @@
         Registration r = new Registration(plugins, CompilerDirectives.class);
         r.register0("inInterpreter", new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
-                b.push(Kind.Boolean.getStackKind(), b.append(ConstantNode.forBoolean(false)));
+                b.addPush(Kind.Boolean.getStackKind(), ConstantNode.forBoolean(false));
                 return true;
             }
         });
         r.register0("inCompiledCode", new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
-                b.push(Kind.Boolean.getStackKind(), b.append(ConstantNode.forBoolean(true)));
+                b.addPush(Kind.Boolean.getStackKind(), ConstantNode.forBoolean(true));
                 return true;
             }
         });
         r.register0("transferToInterpreter", new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
-                b.append(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.TransferToInterpreter));
+                b.add(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.TransferToInterpreter));
                 return true;
             }
         });
         r.register0("transferToInterpreterAndInvalidate", new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
-                b.append(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter));
+                b.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter));
                 return true;
             }
         });
@@ -160,7 +174,7 @@
         });
         r.register2("injectBranchProbability", double.class, boolean.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode probability, ValueNode condition) {
-                b.push(Kind.Boolean.getStackKind(), b.append(new BranchProbabilityNode(probability, condition)));
+                b.addPush(Kind.Boolean.getStackKind(), new BranchProbabilityNode(probability, condition));
                 return true;
             }
         });
@@ -175,21 +189,23 @@
         r.register1("isCompilationConstant", Object.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
                 if ((value instanceof BoxNode ? ((BoxNode) value).getValue() : value).isConstant()) {
-                    b.push(Kind.Boolean.getStackKind(), b.append(ConstantNode.forBoolean(true)));
+                    b.addPush(Kind.Boolean.getStackKind(), ConstantNode.forBoolean(true));
                 } else {
-                    b.push(Kind.Boolean.getStackKind(), b.append(new IsCompilationConstantNode(value)));
+                    b.addPush(Kind.Boolean.getStackKind(), new IsCompilationConstantNode(value));
                 }
                 return true;
             }
         });
         r.register1("materialize", Object.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
-                b.append(new ForceMaterializeNode(value));
+                b.add(new ForceMaterializeNode(value));
                 return true;
             }
         });
+    }
 
-        r = new Registration(plugins, CompilerAsserts.class);
+    public static void registerCompilerAssertsPlugins(InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, CompilerAsserts.class);
         r.register1("partialEvaluationConstant", Object.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
                 ValueNode curValue = value;
@@ -219,7 +235,7 @@
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode message) {
                 if (message.isConstant()) {
                     String messageString = message.asConstant().toValueString();
-                    b.append(new NeverPartOfCompilationNode(messageString));
+                    b.add(new NeverPartOfCompilationNode(messageString));
                     return true;
                 }
                 throw b.bailout("message for never part of compilation is non-constant");
@@ -232,13 +248,13 @@
         r.register2("createFrame", FrameDescriptor.class, Object[].class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode descriptor, ValueNode args) {
                 Class<?> frameClass = TruffleCompilerOptions.TruffleUseFrameWithoutBoxing.getValue() ? FrameWithoutBoxing.class : FrameWithBoxing.class;
-                b.push(Kind.Object, b.append(new NewFrameNode(StampFactory.exactNonNull(metaAccess.lookupJavaType(frameClass)), descriptor, args)));
+                b.addPush(Kind.Object, new NewFrameNode(StampFactory.exactNonNull(metaAccess.lookupJavaType(frameClass)), descriptor, args));
                 return true;
             }
         });
         r.register2("castArrayFixedLength", Object[].class, int.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode args, ValueNode length) {
-                b.push(Kind.Object, b.append(new PiArrayNode(args, length, args.stamp())));
+                b.addPush(Kind.Object, new PiArrayNode(args, length, args.stamp()));
                 return true;
             }
         });
@@ -266,7 +282,7 @@
     private static void registerMaterialize(Registration r) {
         r.register1("materialize", Receiver.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver frame) {
-                b.push(Kind.Object, b.append(new MaterializeFrameNode(frame.get())));
+                b.addPush(Kind.Object, new MaterializeFrameNode(frame.get()));
                 return true;
             }
         });
@@ -301,10 +317,9 @@
                         }
                         ConditionAnchorNode valueAnchorNode = null;
                         if (!skipAnchor) {
-                            valueAnchorNode = b.append(new ConditionAnchorNode(compareNode));
+                            valueAnchorNode = b.add(new ConditionAnchorNode(compareNode));
                         }
-                        PiNode piCast = b.append(new PiNode(object, piStamp, valueAnchorNode));
-                        b.push(Kind.Object, piCast);
+                        b.addPush(Kind.Object, new PiNode(object, piStamp, valueAnchorNode));
                     }
                     return true;
                 }
@@ -340,8 +355,8 @@
                 } else {
                     locationIdentity = ObjectLocationIdentity.create(location.asJavaConstant());
                 }
-                LogicNode compare = b.append(CompareNode.createCompareNode(Condition.EQ, condition, ConstantNode.forBoolean(true, object.graph()), b.getConstantReflection()));
-                b.push(returnKind.getStackKind(), b.append(new UnsafeLoadNode(object, offset, returnKind, locationIdentity, compare)));
+                LogicNode compare = b.add(CompareNode.createCompareNode(Condition.EQ, condition, ConstantNode.forBoolean(true, object.graph()), b.getConstantReflection()));
+                b.addPush(returnKind.getStackKind(), b.add(new UnsafeLoadNode(object, offset, returnKind, locationIdentity, compare)));
                 return true;
             }
             // TODO: should we throw GraalInternalError.shouldNotReachHere() here?
@@ -367,9 +382,7 @@
                     locationIdentity = ObjectLocationIdentity.create(locationArgument.asJavaConstant());
                 }
 
-                UnsafeStoreNode unsafeStore = new UnsafeStoreNode(object, offset, value, kind, locationIdentity, null);
-                b.append(unsafeStore);
-                unsafeStore.setStateAfter(b.createStateAfter());
+                b.add(new UnsafeStoreNode(object, offset, value, kind, locationIdentity, null));
                 return true;
             }
             // TODO: should we throw GraalInternalError.shouldNotReachHere() here?
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsPhase.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsPhase.java	Fri Mar 27 17:02:53 2015 +0100
@@ -83,33 +83,36 @@
                     schedule.apply(graph, false);
                     cfg = schedule.getCFG();
                 }
-
-                Closure<?> closure = createEffectsClosure(context, schedule, cfg);
-                ReentrantBlockIterator.apply(closure, cfg.getStartBlock());
+                try (Scope scheduleScope = Debug.scope("EffectsPhaseWithSchedule", schedule)) {
+                    Closure<?> closure = createEffectsClosure(context, schedule, cfg);
+                    ReentrantBlockIterator.apply(closure, cfg.getStartBlock());
 
-                if (!closure.hasChanged()) {
-                    break;
-                }
+                    if (!closure.hasChanged()) {
+                        break;
+                    }
 
-                // apply the effects collected during this iteration
-                HashSetNodeEventListener listener = new HashSetNodeEventListener();
-                try (NodeEventScope nes = graph.trackNodeEvents(listener)) {
-                    closure.applyEffects();
-                }
+                    // apply the effects collected during this iteration
+                    HashSetNodeEventListener listener = new HashSetNodeEventListener();
+                    try (NodeEventScope nes = graph.trackNodeEvents(listener)) {
+                        closure.applyEffects();
+                    }
 
-                if (Debug.isDumpEnabled()) {
-                    Debug.dump(graph, "after " + getName() + " iteration");
-                }
+                    if (Debug.isDumpEnabled()) {
+                        Debug.dump(graph, "after " + getName() + " iteration");
+                    }
 
-                new DeadCodeEliminationPhase(Required).apply(graph);
+                    new DeadCodeEliminationPhase(Required).apply(graph);
 
-                Set<Node> changedNodes = listener.getNodes();
-                for (Node node : graph.getNodes()) {
-                    if (node instanceof Simplifiable) {
-                        changedNodes.add(node);
+                    Set<Node> changedNodes = listener.getNodes();
+                    for (Node node : graph.getNodes()) {
+                        if (node instanceof Simplifiable) {
+                            changedNodes.add(node);
+                        }
                     }
+                    postIteration(graph, context, changedNodes);
+                } catch (Throwable t) {
+                    throw Debug.handle(t);
                 }
-                postIteration(graph, context, changedNodes);
             }
             changed = true;
         }
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/WordTypes.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/WordTypes.java	Fri Mar 27 17:02:53 2015 +0100
@@ -91,6 +91,7 @@
             assert wordImplType.isLinked();
             wordMethod = wordImplType.resolveConcreteMethod(targetMethod, callingContextType);
         }
+        assert wordMethod != null : targetMethod;
         assert wordMethod.getAnnotation(Operation.class) != null : wordMethod;
         return wordMethod;
     }
--- a/graal/com.oracle.truffle.api/.checkstyle_checks.xml	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.truffle.api/.checkstyle_checks.xml	Fri Mar 27 17:02:53 2015 +0100
@@ -5,7 +5,7 @@
     This configuration file was written by the eclipse-cs plugin configuration editor
 -->
 <!--
-    Checkstyle-Configuration: Maxine Checks
+    Checkstyle-Configuration: Checks
     Description: none
 -->
 <module name="Checker">
@@ -122,8 +122,12 @@
       <property name="format" value=" ,"/>
       <property name="message" value="illegal space before a comma"/>
       <property name="ignoreComments" value="true"/>
+      <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Checks for whitespace before a comma."/>
       <metadata name="com.atlassw.tools.eclipse.checkstyle.customMessage" value="Illegal whitespace before a comma."/>
-      <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Checks for whitespace before a comma."/>
+    </module>
+    <module name="RegexpSinglelineJava">
+      <property name="format" value="new (Hashtable|Vector|Stack|StringBuffer)[^\w]"/>
+      <property name="message" value="Don't use old synchronized collection classes"/>
     </module>
   </module>
   <module name="RegexpHeader">
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultVirtualFrame.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultVirtualFrame.java	Fri Mar 27 17:02:53 2015 +0100
@@ -150,32 +150,27 @@
 
     @Override
     public Object getValue(FrameSlot slot) {
+        int slotIndex = getSlotIndexChecked(slot);
+        return locals[slotIndex];
+    }
+
+    private int getSlotIndexChecked(FrameSlot slot) {
         int slotIndex = slot.getIndex();
         if (slotIndex >= tags.length) {
             if (!resize()) {
                 throw new IllegalArgumentException(String.format("The frame slot '%s' is not known by the frame descriptor.", slot));
             }
         }
-        return locals[slotIndex];
+        return slotIndex;
     }
 
     private void verifySet(FrameSlot slot, FrameSlotKind accessKind) {
-        int slotIndex = slot.getIndex();
-        if (slotIndex >= tags.length) {
-            if (!resize()) {
-                throw new IllegalArgumentException(String.format("The frame slot '%s' is not known by the frame descriptor.", slot));
-            }
-        }
+        int slotIndex = getSlotIndexChecked(slot);
         tags[slotIndex] = (byte) accessKind.ordinal();
     }
 
     private void verifyGet(FrameSlot slot, FrameSlotKind accessKind) throws FrameSlotTypeException {
-        int slotIndex = slot.getIndex();
-        if (slotIndex >= tags.length) {
-            if (!resize()) {
-                throw new IllegalArgumentException(String.format("The frame slot '%s' is not known by the frame descriptor.", slot));
-            }
-        }
+        int slotIndex = getSlotIndexChecked(slot);
         byte tag = tags[slotIndex];
         if (accessKind == FrameSlotKind.Object ? tag != 0 : tag != accessKind.ordinal()) {
             throw new FrameSlotTypeException();
@@ -195,12 +190,7 @@
     }
 
     private byte getTag(FrameSlot slot) {
-        int slotIndex = slot.getIndex();
-        if (slotIndex >= tags.length) {
-            if (!resize()) {
-                throw new IllegalArgumentException(String.format("The frame slot '%s' is not known by the frame descriptor.", slot));
-            }
-        }
+        int slotIndex = getSlotIndexChecked(slot);
         return tags[slotIndex];
     }
 
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/Source.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/Source.java	Fri Mar 27 17:02:53 2015 +0100
@@ -81,10 +81,10 @@
     /**
      * All Sources that have been created.
      */
-    private static final List<WeakReference<Source>> allSources = new ArrayList<>();
+    private static final List<WeakReference<Source>> allSources = Collections.synchronizedList(new ArrayList<WeakReference<Source>>());
 
     // Files and pseudo files are indexed.
-    private static final Map<String, WeakReference<Source>> filePathToSource = new Hashtable<>();
+    private static final Map<String, WeakReference<Source>> filePathToSource = new HashMap<>();
 
     private static boolean fileCacheEnabled = true;
 
@@ -273,11 +273,13 @@
      */
     public static Collection<Source> findSourcesTaggedAs(SourceTag tag) {
         final List<Source> taggedSources = new ArrayList<>();
-        for (WeakReference<Source> ref : allSources) {
-            Source source = ref.get();
-            if (source != null) {
-                if (tag == null || source.isTaggedAs(tag)) {
-                    taggedSources.add(ref.get());
+        synchronized (allSources) {
+            for (WeakReference<Source> ref : allSources) {
+                Source source = ref.get();
+                if (source != null) {
+                    if (tag == null || source.isTaggedAs(tag)) {
+                        taggedSources.add(ref.get());
+                    }
                 }
             }
         }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java	Fri Mar 27 17:02:53 2015 +0100
@@ -2118,7 +2118,7 @@
         boolean elseIf = false;
         for (ExecutableTypeData executableType : executableTypes) {
             elseIf = builder.startIf(elseIf);
-            builder.string(implicitClassFieldName).string(" == ").typeLiteral(executableType.getType().getBoxedType());
+            builder.string(implicitClassFieldName).string(" == ").typeLiteral(executableType.getType().getPrimitiveType());
             builder.end();
             builder.startBlock();
             builder.startStatement().tree(assignment);
--- a/mx/mx_graal.py	Fri Mar 27 15:43:31 2015 +0100
+++ b/mx/mx_graal.py	Fri Mar 27 17:02:53 2015 +0100
@@ -1425,18 +1425,29 @@
     mx.log('TOTAL TIME:   ' + '[' + str(allDuration) + ']')
 
 class Task:
+    # None or a list of strings. If not None, only tasks whose title
+    # matches at least one of the substrings in this list will return
+    # a non-None value from __enter__. The body of a 'with Task(...) as t'
+    # statement should check 't' and exit immediately if it is None.
+    filters = None
+
     def __init__(self, title, tasks=None):
-        self.start = time.time()
+        self.tasks = tasks
         self.title = title
-        self.end = None
-        self.duration = None
-        self.tasks = tasks
-        mx.log(time.strftime('gate: %d %b %Y %H:%M:%S: BEGIN: ') + title)
+        self.skipped = tasks is not None and Task.filters is not None and not any([f in title for f in Task.filters])
+        if not self.skipped:
+            self.start = time.time()
+            self.end = None
+            self.duration = None
+            mx.log(time.strftime('gate: %d %b %Y %H:%M:%S: BEGIN: ') + title)
     def __enter__(self):
         assert self.tasks is not None, "using Task with 'with' statement requires to pass the tasks list in the constructor"
+        if self.skipped:
+            return None
         return self
     def __exit__(self, exc_type, exc_value, traceback):
-        self.tasks.append(self.stop())
+        if not self.skipped:
+            self.tasks.append(self.stop())
     def stop(self):
         self.end = time.time()
         self.duration = datetime.timedelta(seconds=self.end - self.start)
@@ -1477,67 +1488,78 @@
         vmargs += ['-G:CompileTheWorldClasspath=' + jar]
     else:
         vmargs += ['-Xbootclasspath/p:' + jar]
+
+    # suppress menubar and dock when running on Mac
+    vmargs = ['-Djava.awt.headless=true'] + vmargs
+
     vm(vmargs)
 
 def _basic_gate_body(args, tasks):
     # Build server-hosted-graal now so we can run the unit tests
-    with Task('BuildHotSpotGraalHosted: product', tasks):
-        buildvms(['--vms', 'server', '--builds', 'product'])
+    with Task('BuildHotSpotGraalHosted: product', tasks) as t:
+        if t: buildvms(['--vms', 'server', '--builds', 'product'])
 
     # Run unit tests on server-hosted-graal
     with VM('server', 'product'):
-        with Task('UnitTests:hosted-product', tasks):
-            unittest(['--enable-timing', '--verbose', '--fail-fast'])
+        with Task('UnitTests:hosted-product', tasks) as t:
+            if t: unittest(['--enable-timing', '--verbose', '--fail-fast'])
+
+    # Run ctw against rt.jar on server-hosted-graal
+    with VM('server', 'product'):
+        with Task('CTW:hosted-product', tasks) as t:
+            if t: ctw(['--ctwopts', '-Inline +ExitVMOnException', '-esa', '-G:+CompileTheWorldMultiThreaded', '-G:-CompileTheWorldVerbose'])
 
     # Build the other VM flavors
-    with Task('BuildHotSpotGraalOthers: fastdebug,product', tasks):
-        buildvms(['--vms', 'graal,server', '--builds', 'fastdebug,product'])
+    with Task('BuildHotSpotGraalOthers: fastdebug,product', tasks) as t:
+        if t: buildvms(['--vms', 'graal,server', '--builds', 'fastdebug,product'])
 
     with VM('graal', 'fastdebug'):
-        with Task('BootstrapWithSystemAssertions:fastdebug', tasks):
-            vm(['-esa', '-XX:-TieredCompilation', '-version'])
+        with Task('BootstrapWithSystemAssertions:fastdebug', tasks) as t:
+            if t: vm(['-esa', '-XX:-TieredCompilation', '-version'])
 
     with VM('graal', 'fastdebug'):
-        with Task('BootstrapEconomyWithSystemAssertions:fastdebug', tasks):
-            vm(['-esa', '-XX:-TieredCompilation', '-G:CompilerConfiguration=economy', '-version'])
+        with Task('BootstrapEconomyWithSystemAssertions:fastdebug', tasks) as t:
+            if t: vm(['-esa', '-XX:-TieredCompilation', '-G:CompilerConfiguration=economy', '-version'])
 
     with VM('graal', 'fastdebug'):
-        with Task('BootstrapWithSystemAssertionsNoCoop:fastdebug', tasks):
-            vm(['-esa', '-XX:-TieredCompilation', '-XX:-UseCompressedOops', '-version'])
+        with Task('BootstrapWithSystemAssertionsNoCoop:fastdebug', tasks) as t:
+            if t: vm(['-esa', '-XX:-TieredCompilation', '-XX:-UseCompressedOops', '-version'])
 
     with VM('graal', 'product'):
-        with Task('BootstrapWithGCVerification:product', tasks):
-            out = mx.DuplicateSuppressingStream(['VerifyAfterGC:', 'VerifyBeforeGC:']).write
-            vm(['-XX:-TieredCompilation', '-XX:+UnlockDiagnosticVMOptions', '-XX:+VerifyBeforeGC', '-XX:+VerifyAfterGC', '-version'], out=out)
+        with Task('BootstrapWithGCVerification:product', tasks) as t:
+            if t:
+                out = mx.DuplicateSuppressingStream(['VerifyAfterGC:', 'VerifyBeforeGC:']).write
+                vm(['-XX:-TieredCompilation', '-XX:+UnlockDiagnosticVMOptions', '-XX:+VerifyBeforeGC', '-XX:+VerifyAfterGC', '-version'], out=out)
 
     with VM('graal', 'product'):
-        with Task('BootstrapWithG1GCVerification:product', tasks):
-            out = mx.DuplicateSuppressingStream(['VerifyAfterGC:', 'VerifyBeforeGC:']).write
-            vm(['-XX:-TieredCompilation', '-XX:+UnlockDiagnosticVMOptions', '-XX:-UseSerialGC', '-XX:+UseG1GC', '-XX:+VerifyBeforeGC', '-XX:+VerifyAfterGC', '-version'], out=out)
+        with Task('BootstrapWithG1GCVerification:product', tasks) as t:
+            if t:
+                out = mx.DuplicateSuppressingStream(['VerifyAfterGC:', 'VerifyBeforeGC:']).write
+                vm(['-XX:-TieredCompilation', '-XX:+UnlockDiagnosticVMOptions', '-XX:-UseSerialGC', '-XX:+UseG1GC', '-XX:+VerifyBeforeGC', '-XX:+VerifyAfterGC', '-version'], out=out)
 
     with VM('graal', 'product'):
-        with Task('BootstrapWithRegisterPressure:product', tasks):
-            vm(['-XX:-TieredCompilation', '-G:RegisterPressure=rbx,r11,r10,r14,xmm3,xmm11,xmm14', '-esa', '-version'])
+        with Task('BootstrapWithRegisterPressure:product', tasks) as t:
+            if t: vm(['-XX:-TieredCompilation', '-G:RegisterPressure=rbx,r11,r10,r14,xmm3,xmm11,xmm14', '-esa', '-version'])
 
     with VM('graal', 'product'):
-        with Task('BootstrapWithImmutableCode:product', tasks):
-            vm(['-XX:-TieredCompilation', '-G:+ImmutableCode', '-G:+VerifyPhases', '-esa', '-version'])
+        with Task('BootstrapWithImmutableCode:product', tasks) as t:
+            if t: vm(['-XX:-TieredCompilation', '-G:+ImmutableCode', '-G:+VerifyPhases', '-esa', '-version'])
 
     for vmbuild in ['fastdebug', 'product']:
         for test in sanitycheck.getDacapos(level=sanitycheck.SanityCheckLevel.Gate, gateBuildLevel=vmbuild) + sanitycheck.getScalaDacapos(level=sanitycheck.SanityCheckLevel.Gate, gateBuildLevel=vmbuild):
             with Task(str(test) + ':' + vmbuild, tasks) as t:
-                if not test.test('graal'):
+                if t and not test.test('graal'):
                     t.abort(test.name + ' Failed')
 
     # ensure -Xbatch still works
     with VM('graal', 'product'):
-        with Task('DaCapo_pmd:BatchMode:product', tasks):
-            dacapo(['-Xbatch', 'pmd'])
+        with Task('DaCapo_pmd:BatchMode:product', tasks) as t:
+            if t: dacapo(['-Xbatch', 'pmd'])
 
     # ensure -Xcomp still works
     with VM('graal', 'product'):
-        with Task('XCompMode:product', tasks):
-            vm(['-Xcomp', '-version'])
+        with Task('XCompMode:product', tasks) as t:
+            if t: vm(['-Xcomp', '-version'])
 
     if args.jacocout is not None:
         jacocoreport([args.jacocout])
@@ -1545,17 +1567,19 @@
     global _jacoco
     _jacoco = 'off'
 
-    with Task('CleanAndBuildIdealGraphVisualizer', tasks):
-        env = _igvFallbackJDK(os.environ)
-        buildxml = mx._cygpathU2W(join(_graal_home, 'src', 'share', 'tools', 'IdealGraphVisualizer', 'build.xml'))
-        mx.run(['ant', '-f', buildxml, '-q', 'clean', 'build'], env=env)
+    with Task('CleanAndBuildIdealGraphVisualizer', tasks) as t:
+        if t:
+            env = _igvFallbackJDK(os.environ)
+            buildxml = mx._cygpathU2W(join(_graal_home, 'src', 'share', 'tools', 'IdealGraphVisualizer', 'build.xml'))
+            mx.run(['ant', '-f', buildxml, '-q', 'clean', 'build'], env=env)
 
     # Prevent Graal modifications from breaking the standard builds
     if args.buildNonGraal:
-        with Task('BuildHotSpotVarieties', tasks):
-            buildvms(['--vms', 'client,server', '--builds', 'fastdebug,product'])
-            if mx.get_os() not in ['windows', 'cygwin']:
-                buildvms(['--vms', 'server-nograal', '--builds', 'product,optimized'])
+        with Task('BuildHotSpotVarieties', tasks) as t:
+            if t:
+                buildvms(['--vms', 'client,server', '--builds', 'fastdebug,product'])
+                if mx.get_os() not in ['windows', 'cygwin']:
+                    buildvms(['--vms', 'server-nograal', '--builds', 'product,optimized'])
 
         for vmbuild in ['product', 'fastdebug']:
             for theVm in ['client', 'server']:
@@ -1563,11 +1587,11 @@
                     mx.log('The' + theVm + ' VM is not supported on this platform')
                     continue
                 with VM(theVm, vmbuild):
-                    with Task('DaCapo_pmd:' + theVm + ':' + vmbuild, tasks):
-                        dacapo(['pmd'])
-
-                    with Task('UnitTests:' + theVm + ':' + vmbuild, tasks):
-                        unittest(['-XX:CompileCommand=exclude,*::run*', 'graal.api'])
+                    with Task('DaCapo_pmd:' + theVm + ':' + vmbuild, tasks) as t:
+                        if t: dacapo(['pmd'])
+
+                    with Task('UnitTests:' + theVm + ':' + vmbuild, tasks) as t:
+                        if t: unittest(['-XX:CompileCommand=exclude,*::run*', 'graal.api'])
 
 
 def gate(args, gate_body=_basic_gate_body):
@@ -1580,61 +1604,67 @@
     parser.add_argument('-j', '--omit-java-clean', action='store_false', dest='cleanJava', help='omit cleaning Java native code')
     parser.add_argument('-n', '--omit-native-clean', action='store_false', dest='cleanNative', help='omit cleaning and building native code')
     parser.add_argument('-g', '--only-build-graalvm', action='store_false', dest='buildNonGraal', help='only build the Graal VM')
+    parser.add_argument('-t', '--task-filter', help='comma separated list of substrings to select subset of tasks to be run')
     parser.add_argument('--jacocout', help='specify the output directory for jacoco report')
 
     args = parser.parse_args(args)
 
     global _jacoco
+    if args.task_filter:
+        Task.filters = args.task_filter.split(',')
 
     tasks = []
     total = Task('Gate')
     try:
-        with Task('Pylint', tasks):
-            mx.pylint([])
+        with Task('Pylint', tasks) as t:
+            if t: mx.pylint([])
 
         def _clean(name='Clean'):
-            with Task(name, tasks):
-                cleanArgs = []
-                if not args.cleanNative:
-                    cleanArgs.append('--no-native')
-                if not args.cleanJava:
-                    cleanArgs.append('--no-java')
-                clean(cleanArgs)
+            with Task(name, tasks) as t:
+                if t:
+                    cleanArgs = []
+                    if not args.cleanNative:
+                        cleanArgs.append('--no-native')
+                    if not args.cleanJava:
+                        cleanArgs.append('--no-java')
+                    clean(cleanArgs)
         _clean()
 
         with Task('IDEConfigCheck', tasks):
-            mx.ideclean([])
-            mx.ideinit([])
+            if t:
+                mx.ideclean([])
+                mx.ideinit([])
 
         eclipse_exe = mx.get_env('ECLIPSE_EXE')
         if eclipse_exe is not None:
             with Task('CodeFormatCheck', tasks) as t:
-                if mx.eclipseformat(['-e', eclipse_exe]) != 0:
+                if t and mx.eclipseformat(['-e', eclipse_exe]) != 0:
                     t.abort('Formatter modified files - run "mx eclipseformat", check in changes and repush')
 
         with Task('Canonicalization Check', tasks) as t:
-            mx.log(time.strftime('%d %b %Y %H:%M:%S - Ensuring mx/projects files are canonicalized...'))
-            if mx.canonicalizeprojects([]) != 0:
-                t.abort('Rerun "mx canonicalizeprojects" and check-in the modified mx/projects files.')
+            if t:
+                mx.log(time.strftime('%d %b %Y %H:%M:%S - Ensuring mx/projects files are canonicalized...'))
+                if mx.canonicalizeprojects([]) != 0:
+                    t.abort('Rerun "mx canonicalizeprojects" and check-in the modified mx/projects files.')
 
         if mx.get_env('JDT'):
             with Task('BuildJavaWithEcj', tasks):
-                build(['-p', '--no-native', '--jdt-warning-as-error'])
+                if t: build(['-p', '--no-native', '--jdt-warning-as-error'])
             _clean('CleanAfterEcjBuild')
 
         with Task('BuildJavaWithJavac', tasks):
-            build(['-p', '--no-native', '--force-javac'])
+            if t: build(['-p', '--no-native', '--force-javac'])
 
         with Task('Checkstyle', tasks) as t:
-            if mx.checkstyle([]) != 0:
+            if t and mx.checkstyle([]) != 0:
                 t.abort('Checkstyle warnings were found')
 
         with Task('Checkheaders', tasks) as t:
-            if checkheaders([]) != 0:
+            if t and checkheaders([]) != 0:
                 t.abort('Checkheaders warnings were found')
 
         with Task('FindBugs', tasks) as t:
-            if findbugs([]) != 0:
+            if t and findbugs([]) != 0:
                 t.abort('FindBugs warnings were found')
 
         if exists('jacoco.exec'):
@@ -1663,6 +1693,9 @@
     mx.log('  =======')
     mx.log('  ' + str(total.duration))
 
+    if args.task_filter:
+        Task.filters = None
+
 def deoptalot(args):
     """bootstrap a fastdebug Graal VM with DeoptimizeALot and VerifyOops on
 
--- a/mx/suite.py	Fri Mar 27 15:43:31 2015 +0100
+++ b/mx/suite.py	Fri Mar 27 17:02:53 2015 +0100
@@ -139,21 +139,6 @@
       ],
     },
 
-    "ASM" : {
-      "path" : "lib/asm-5.0.3.jar",
-      "urls" : [
-        "http://lafo.ssw.uni-linz.ac.at/graal-external-deps/asm-5.0.3.jar",
-        "https://search.maven.org/remotecontent?filepath=org/ow2/asm/asm/5.0.3/asm-5.0.3.jar",
-      ],
-      "sha1" : "dcc2193db20e19e1feca8b1240dbbc4e190824fa",
-      "sourcePath" : "lib/asm-5.0.3-sources.jar",
-      "sourceSha1" : "f0f24f6666c1a15c7e202e91610476bd4ce59368",
-      "sourceUrls" : [
-        "http://lafo.ssw.uni-linz.ac.at/graal-external-deps/asm-5.0.3-sources.jar",
-        "https://search.maven.org/remotecontent?filepath=org/ow2/asm/asm/5.0.3/asm-5.0.3-sources.jar",
-      ],
-    },
-
     "JAVA_ALLOCATION_INSTRUMENTER" : {
       "path" : "lib/java-allocation-instrumenter.jar",
       "sourcePath" : "lib/java-allocation-instrumenter.jar",
@@ -880,7 +865,6 @@
       "sourceDirs" : ["src"],
       "dependencies" : [
         "com.oracle.graal.compiler.test",
-        "ASM",
       ],
       "checkstyle" : "com.oracle.graal.graph",
       "javaCompliance" : "1.8",
@@ -1079,6 +1063,7 @@
       "sourceDirs" : ["src"],
       "dependencies" : [
         "com.oracle.graal.truffle",
+        "com.oracle.graal.graph.test",
         "com.oracle.graal.compiler.test",
         "com.oracle.truffle.sl.test",
       ],
--- a/src/share/tools/IdealGraphVisualizer/Bytecodes/nbproject/project.xml	Fri Mar 27 15:43:31 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/Bytecodes/nbproject/project.xml	Fri Mar 27 17:02:53 2015 +0100
@@ -40,6 +40,14 @@
                     </run-dependency>
                 </dependency>
                 <dependency>
+                    <code-name-base>org.openide.awt</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>7.39.1</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
                     <code-name-base>org.openide.explorer</code-name-base>
                     <build-prerequisite/>
                     <compile-dependency/>
--- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputBlock.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputBlock.java	Fri Mar 27 17:02:53 2015 +0100
@@ -88,12 +88,10 @@
     }
 
     public void addNode(int id) {
-        InputNode n = graph.getNode(id);
-        assert n != null;
-        graph.setBlock(n, this);
-        final InputNode node = graph.getNode(id);
+        InputNode node = graph.getNode(id);
         assert node != null;
         assert !nodes.contains(node) : "duplicate : " + node;
+        graph.setBlock(node, this);
         nodes.add(node);
     }
 
--- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/BinaryParser.java	Fri Mar 27 15:43:31 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/BinaryParser.java	Fri Mar 27 17:02:53 2015 +0100
@@ -687,8 +687,17 @@
             int nodeCount = readInt();
             for (int j = 0; j < nodeCount; j++) {
                 int nodeId = readInt();
-                block.addNode(nodeId);
-                graph.getNode(nodeId).getProperties().setProperty("block", name);
+                if (nodeId < 0) {
+                    continue;
+                }
+                final Properties properties = graph.getNode(nodeId).getProperties();
+                final String oldBlock = properties.get("block");
+                if(oldBlock != null) {
+                    properties.setProperty("block", oldBlock + ", " + name);
+                } else {
+                    block.addNode(nodeId);
+                    properties.setProperty("block", name);
+                }
             }
             int edgeCount = readInt();
             for (int j = 0; j < edgeCount; j++) {
--- a/src/share/tools/IdealGraphVisualizer/FilterWindow/nbproject/genfiles.properties	Fri Mar 27 15:43:31 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/FilterWindow/nbproject/genfiles.properties	Fri Mar 27 17:02:53 2015 +0100
@@ -1,5 +1,5 @@
 # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
 # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
-nbproject/build-impl.xml.data.CRC32=09ba2a87
+nbproject/build-impl.xml.data.CRC32=5b8e8a60
 nbproject/build-impl.xml.script.CRC32=e4293f0e
 nbproject/build-impl.xml.stylesheet.CRC32=238281d1@2.67.1
--- a/src/share/tools/IdealGraphVisualizer/FilterWindow/nbproject/project.xml	Fri Mar 27 15:43:31 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/FilterWindow/nbproject/project.xml	Fri Mar 27 17:02:53 2015 +0100
@@ -47,6 +47,14 @@
                     </run-dependency>
                 </dependency>
                 <dependency>
+                    <code-name-base>org.openide.awt</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>7.39.1</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
                     <code-name-base>org.openide.dialogs</code-name-base>
                     <build-prerequisite/>
                     <compile-dependency/>
--- a/src/share/tools/IdealGraphVisualizer/Graal/nbproject/genfiles.properties	Fri Mar 27 15:43:31 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/Graal/nbproject/genfiles.properties	Fri Mar 27 17:02:53 2015 +0100
@@ -1,8 +1,8 @@
-build.xml.data.CRC32=79002a09
+build.xml.data.CRC32=92ea213f
 build.xml.script.CRC32=3534d355
-build.xml.stylesheet.CRC32=a56c6a5b@2.62.1
+build.xml.stylesheet.CRC32=a56c6a5b@2.67.1
 # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
 # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
-nbproject/build-impl.xml.data.CRC32=79002a09
+nbproject/build-impl.xml.data.CRC32=92ea213f
 nbproject/build-impl.xml.script.CRC32=2867f2d5
 nbproject/build-impl.xml.stylesheet.CRC32=238281d1@2.67.1
--- a/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/color.filter	Fri Mar 27 15:43:31 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/color.filter	Fri Mar 27 17:02:53 2015 +0100
@@ -1,15 +1,11 @@
 colorize("name", ".*", white);
 colorize("name", "Begin|KillingBegin|EndNode|LoopBegin|LoopEnd|LoopExit|Return", orange);
-colorize("name", "Phi.*|ValueProxy", magenta);
-colorize("name", "FrameState@.*", new java.awt.Color(0.5, 0.8, 1.0));
-colorize("name", "If|Merge", pink);
-colorize("name", "const.*", new java.awt.Color(0.7, 0.7, 0.7));
-colorize("name", "Param", new java.awt.Color(0.85, 0.85, 0.85));
+colorize("class", "FrameState", new java.awt.Color(0.5, 0.8, 1.0));
+colorize("name", "If|Merge|(Integer|Type)Switch", pink);
 colorize("name", "\\+|-|\\*|/|&|\\||<<|>>|>>>", cyan);
-colorize("name", "Comp .*", yellow);
 colorize("name", "Virtual.*", green);
-
-colorize("name", "ValuePhi.*|ValueProxy", magenta);
-colorize("name", "Const.*", new java.awt.Color(0.7, 0.7, 0.7));
-colorize("name", "Param.*", new java.awt.Color(0.85, 0.85, 0.85));
-colorize("stamp", "Condition", yellow);
+colorize("name", "(Φ|Proxy)\(.*\)", magenta);
+colorize("name", "(Φ|Proxy)\(.*\) Identity\(.*\)", green);
+colorize("name", "C\(.*\)", new java.awt.Color(0.7, 0.7, 0.7));
+colorize("name", "P\(.*\)", new java.awt.Color(0.85, 0.85, 0.85));
+colorize("name", "==|<|InstanceOf", yellow);
--- a/src/share/tools/IdealGraphVisualizer/Util/nbproject/project.xml	Fri Mar 27 15:43:31 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/Util/nbproject/project.xml	Fri Mar 27 17:02:53 2015 +0100
@@ -23,6 +23,14 @@
                     </run-dependency>
                 </dependency>
                 <dependency>
+                    <code-name-base>org.openide.awt</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>7.39.1</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
                     <code-name-base>org.openide.nodes</code-name-base>
                     <build-prerequisite/>
                     <compile-dependency/>
--- a/src/share/vm/code/scopeDesc.cpp	Fri Mar 27 15:43:31 2015 +0100
+++ b/src/share/vm/code/scopeDesc.cpp	Fri Mar 27 17:02:53 2015 +0100
@@ -232,6 +232,7 @@
     for (int i = 0; i < _objects->length(); i++) {
       ObjectValue* sv = _objects->at(i)->as_ObjectValue();
       tty->print(" - %d: ", sv->id());
+      tty->print("%s ", java_lang_Class::as_Klass(sv->klass()->as_ConstantOopReadValue()->value()())->external_name());
       sv->print_fields_on(tty);
       tty->cr();
     }
--- a/src/share/vm/graal/graalCodeInstaller.cpp	Fri Mar 27 15:43:31 2015 +0100
+++ b/src/share/vm/graal/graalCodeInstaller.cpp	Fri Mar 27 17:02:53 2015 +0100
@@ -203,7 +203,7 @@
   record_metadata_reference(HotSpotMetaspaceConstantImpl::metaspaceObject(constant), HotSpotMetaspaceConstantImpl::primitive(constant), HotSpotMetaspaceConstantImpl::compressed(constant), oop_recorder);
 }
 
-ScopeValue* CodeInstaller::get_scope_value(oop value, int total_frame_size, GrowableArray<ScopeValue*>* objects, ScopeValue* &second, OopRecorder* oop_recorder) {
+ScopeValue* CodeInstaller::get_scope_value(oop value, GrowableArray<ScopeValue*>* objects, ScopeValue* &second) {
   second = NULL;
   if (value == AbstractValue::ILLEGAL()) {
     return _illegal_value;
@@ -282,7 +282,7 @@
     }
 #endif
     if (StackSlot::addFrameSize(value)) {
-      offset += total_frame_size;
+      offset += _total_frame_size;
     }
     ScopeValue* value = new LocationValue(Location::new_stk_loc(locationType, offset));
     if (type == T_DOUBLE || (type == T_LONG && !reference)) {
@@ -290,7 +290,7 @@
     }
     return value;
   } else if (value->is_a(JavaConstant::klass())){
-    record_metadata_in_constant(value, oop_recorder);
+    record_metadata_in_constant(value, _oop_recorder);
     if (value->is_a(PrimitiveConstant::klass())) {
       assert(!reference, "unexpected primitive constant type");
       if(value->is_a(RawConstant::klass())) {
@@ -323,40 +323,10 @@
       }
     }
   } else if (value->is_a(VirtualObject::klass())) {
-    oop type = VirtualObject::type(value);
     int id = VirtualObject::id(value);
-    oop javaMirror = HotSpotResolvedObjectTypeImpl::javaClass(type);
-    Klass* klass = java_lang_Class::as_Klass(javaMirror);
-    bool isLongArray = klass == Universe::longArrayKlassObj();
-
-    for (jint i = 0; i < objects->length(); i++) {
-      ObjectValue* obj = (ObjectValue*) objects->at(i);
-      if (obj->id() == id) {
-        return obj;
-      }
-    }
-
-    ObjectValue* sv = new ObjectValue(id, new ConstantOopWriteValue(JNIHandles::make_local(Thread::current(), javaMirror)));
-    objects->append(sv);
-
-    objArrayOop values = VirtualObject::values(value);
-    for (jint i = 0; i < values->length(); i++) {
-      ScopeValue* cur_second = NULL;
-      oop object = values->obj_at(i);
-      ScopeValue* value = get_scope_value(object, total_frame_size, objects, cur_second, oop_recorder);
-
-      if (isLongArray && cur_second == NULL) {
-        // we're trying to put ints into a long array... this isn't really valid, but it's used for some optimizations.
-        // add an int 0 constant
-        cur_second = _int_0_scope_value;
-      }
-
-      if (cur_second != NULL) {
-        sv->field_values()->append(cur_second);
-      }
-      sv->field_values()->append(value);
-    }
-    return sv;
+    ScopeValue* object = objects->at(id);
+    assert(object != NULL, "missing value");
+    return object;
   } else {
     value->klass()->print();
     value->print();
@@ -365,14 +335,41 @@
   return NULL;
 }
 
-MonitorValue* CodeInstaller::get_monitor_value(oop value, int total_frame_size, GrowableArray<ScopeValue*>* objects, OopRecorder* oop_recorder) {
+void CodeInstaller::record_object_value(ObjectValue* sv, oop value, GrowableArray<ScopeValue*>* objects) {
+  oop type = VirtualObject::type(value);
+  int id = VirtualObject::id(value);
+  oop javaMirror = HotSpotResolvedObjectTypeImpl::javaClass(type);
+  Klass* klass = java_lang_Class::as_Klass(javaMirror);
+  bool isLongArray = klass == Universe::longArrayKlassObj();
+
+  objArrayOop values = VirtualObject::values(value);
+  for (jint i = 0; i < values->length(); i++) {
+    ScopeValue* cur_second = NULL;
+    oop object = values->obj_at(i);
+    ScopeValue* value = get_scope_value(object, objects, cur_second);
+
+    if (isLongArray && cur_second == NULL) {
+      // we're trying to put ints into a long array... this isn't really valid, but it's used for some optimizations.
+      // add an int 0 constant
+      cur_second = _int_0_scope_value;
+    }
+
+    if (cur_second != NULL) {
+      sv->field_values()->append(cur_second);
+    }
+    assert(value != NULL, "missing value");
+    sv->field_values()->append(value);
+  }
+}
+
+MonitorValue* CodeInstaller::get_monitor_value(oop value, GrowableArray<ScopeValue*>* objects) {
   guarantee(value->is_a(StackLockValue::klass()), "Monitors must be of type MonitorValue");
 
   ScopeValue* second = NULL;
-  ScopeValue* owner_value = get_scope_value(StackLockValue::owner(value), total_frame_size, objects, second, oop_recorder);
+  ScopeValue* owner_value = get_scope_value(StackLockValue::owner(value), objects, second);
   assert(second == NULL, "monitor cannot occupy two stack slots");
 
-  ScopeValue* lock_data_value = get_scope_value(StackLockValue::slot(value), total_frame_size, objects, second, oop_recorder);
+  ScopeValue* lock_data_value = get_scope_value(StackLockValue::slot(value), objects, second);
   assert(second == lock_data_value, "monitor is LONG value that occupies two stack slots");
   assert(lock_data_value->is_location(), "invalid monitor location");
   Location lock_data_loc = ((LocationValue*)lock_data_value)->location();
@@ -727,6 +724,44 @@
   return true;
 }
 
+GrowableArray<ScopeValue*>* CodeInstaller::record_virtual_objects(oop debug_info) {
+  objArrayOop virtualObjects = DebugInfo::virtualObjectMapping(debug_info);
+  if (virtualObjects == NULL) {
+    return NULL;
+  }
+  GrowableArray<ScopeValue*>* objects = new GrowableArray<ScopeValue*>(virtualObjects->length(), virtualObjects->length(), NULL);
+  // Create the unique ObjectValues
+  for (int i = 0; i < virtualObjects->length(); i++) {
+    oop value = virtualObjects->obj_at(i);
+    int id = VirtualObject::id(value);
+    oop type = VirtualObject::type(value);
+    oop javaMirror = HotSpotResolvedObjectTypeImpl::javaClass(type);
+    ObjectValue* sv = new ObjectValue(id, new ConstantOopWriteValue(JNIHandles::make_local(Thread::current(), javaMirror)));
+    assert(objects->at(id) == NULL, "once");
+    objects->at_put(id, sv);
+  }
+  // All the values which could be referenced by the VirtualObjects
+  // exist, so now describe all the VirtualObjects themselves.
+  for (int i = 0; i < virtualObjects->length(); i++) {
+    oop value = virtualObjects->obj_at(i);
+    int id = VirtualObject::id(value);
+    record_object_value(objects->at(id)->as_ObjectValue(), value, objects);
+  }
+  _debug_recorder->dump_object_pool(objects);
+  return objects;
+}
+
+void CodeInstaller::record_scope(jint pc_offset, oop debug_info) {
+  oop position = DebugInfo::bytecodePosition(debug_info);
+  if (position == NULL) {
+    // Stubs do not record scope info, just oop maps
+    return;
+  }
+  
+  GrowableArray<ScopeValue*>* objectMapping = record_virtual_objects(debug_info);
+  record_scope(pc_offset, position, objectMapping);
+}
+
 void CodeInstaller::record_scope(jint pc_offset, oop position, GrowableArray<ScopeValue*>* objects) {
   oop frame = NULL;
   if (position->is_a(BytecodeFrame::klass())) {
@@ -785,21 +820,21 @@
 
     for (jint i = 0; i < values->length(); i++) {
       ScopeValue* second = NULL;
-      oop value= values->obj_at(i);
+      oop value = values->obj_at(i);
       if (i < local_count) {
-        ScopeValue* first = get_scope_value(value, _total_frame_size, objects, second, _oop_recorder);
+        ScopeValue* first = get_scope_value(value, objects, second);
         if (second != NULL) {
           locals->append(second);
         }
         locals->append(first);
       } else if (i < local_count + expression_count) {
-        ScopeValue* first = get_scope_value(value, _total_frame_size, objects, second, _oop_recorder);
+        ScopeValue* first = get_scope_value(value, objects, second);
         if (second != NULL) {
           expressions->append(second);
         }
         expressions->append(first);
       } else {
-        monitors->append(get_monitor_value(value, _total_frame_size, objects, _oop_recorder));
+        monitors->append(get_monitor_value(value, objects));
       }
       if (second != NULL) {
         i++;
@@ -808,8 +843,6 @@
       }
     }
 
-    _debug_recorder->dump_object_pool(objects);
-
     locals_token = _debug_recorder->create_scope_values(locals);
     expressions_token = _debug_recorder->create_scope_values(expressions);
     monitors_token = _debug_recorder->create_monitor_values(monitors);
@@ -817,7 +850,8 @@
     throw_exception = BytecodeFrame::rethrowException(frame) == JNI_TRUE;
   }
 
-  _debug_recorder->describe_scope(pc_offset, method, NULL, bci, reexecute, throw_exception, false, false, locals_token, expressions_token, monitors_token);
+  _debug_recorder->describe_scope(pc_offset, method, NULL, bci, reexecute, throw_exception, false, false,
+                                  locals_token, expressions_token, monitors_token);
 }
 
 void CodeInstaller::site_Safepoint(CodeBuffer& buffer, jint pc_offset, oop site) {
@@ -827,14 +861,7 @@
   // address instruction = _instructions->start() + pc_offset;
   // jint next_pc_offset = Assembler::locate_next_instruction(instruction) - _instructions->start();
   _debug_recorder->add_safepoint(pc_offset, create_oop_map(_total_frame_size, _parameter_count, debug_info));
-
-  oop frame = DebugInfo::bytecodePosition(debug_info);
-  if (frame != NULL) {
-    record_scope(pc_offset, frame, new GrowableArray<ScopeValue*>());
-  } else {
-    // Stubs do not record scope info, just oop maps
-  }
-
+  record_scope(pc_offset, debug_info);
   _debug_recorder->end_safepoint(pc_offset);
 }
 
@@ -843,12 +870,7 @@
   assert(debug_info != NULL, "debug info expected");
 
   _debug_recorder->add_non_safepoint(pc_offset);
-
-  oop position = DebugInfo::bytecodePosition(debug_info);
-  if (position != NULL) {
-    record_scope(pc_offset, position, NULL);
-  }
-
+  record_scope(pc_offset, debug_info);
   _debug_recorder->end_non_safepoint(pc_offset);
 }
 
@@ -873,13 +895,8 @@
   jint next_pc_offset = CodeInstaller::pd_next_offset(inst, pc_offset, hotspot_method);
 
   if (debug_info != NULL) {
-    oop frame = DebugInfo::bytecodePosition(debug_info);
     _debug_recorder->add_safepoint(next_pc_offset, create_oop_map(_total_frame_size, _parameter_count, debug_info));
-    if (frame != NULL) {
-      record_scope(next_pc_offset, frame, new GrowableArray<ScopeValue*>());
-    } else {
-      // Stubs do not record scope info, just oop maps
-    }
+    record_scope(next_pc_offset, debug_info);
   }
 
   if (foreign_call != NULL) {
--- a/src/share/vm/graal/graalCodeInstaller.hpp	Fri Mar 27 15:43:31 2015 +0100
+++ b/src/share/vm/graal/graalCodeInstaller.hpp	Fri Mar 27 17:02:53 2015 +0100
@@ -114,12 +114,10 @@
   static VMReg get_hotspot_reg(jint graalRegisterNumber);
   static bool is_general_purpose_reg(VMReg hotspotRegister);
 
-protected:
+private:
+  ScopeValue* get_scope_value(oop value, GrowableArray<ScopeValue*>* objects, ScopeValue* &second);
+  MonitorValue* get_monitor_value(oop value, GrowableArray<ScopeValue*>* objects);
 
-  virtual ScopeValue* get_scope_value(oop value, int total_frame_size, GrowableArray<ScopeValue*>* objects, ScopeValue* &second, OopRecorder* oop_recorder);
-  virtual MonitorValue* get_monitor_value(oop value, int total_frame_size, GrowableArray<ScopeValue*>* objects, OopRecorder* oop_recorder);
-
-private:
   // extract the fields of the CompilationResult
   void initialize_fields(oop target_method);
   void initialize_dependencies(oop target_method);
@@ -141,7 +139,11 @@
   void site_DataPatch(CodeBuffer& buffer, jint pc_offset, oop site);
   void site_Mark(CodeBuffer& buffer, jint pc_offset, oop site);
 
+  void record_scope(jint pc_offset, oop debug_info);
   void record_scope(jint pc_offset, oop code_pos, GrowableArray<ScopeValue*>* objects);
+  void record_object_value(ObjectValue* sv, oop value, GrowableArray<ScopeValue*>* objects);
+
+  GrowableArray<ScopeValue*>* record_virtual_objects(oop debug_info);
 
   void process_exception_handlers();
   int estimateStubSpace(int static_call_stubs);
--- a/src/share/vm/graal/graalCompiler.cpp	Fri Mar 27 15:43:31 2015 +0100
+++ b/src/share/vm/graal/graalCompiler.cpp	Fri Mar 27 17:02:53 2015 +0100
@@ -155,7 +155,6 @@
   tty->print_cr("       Graal code install time:        %6.3f s",    _codeInstallTimer.seconds());
 }
 
-#ifndef PRODUCT
 void GraalCompiler::compile_the_world() {
   HandleMark hm;
   JavaThread* THREAD = JavaThread::current();
@@ -167,4 +166,3 @@
   args.push_oop(GraalRuntime::get_HotSpotGraalRuntime());
   JavaCalls::call_special(&result, klass, compileTheWorld, vmSymbols::void_method_signature(), &args, CHECK_ABORT);
 }
-#endif
--- a/src/share/vm/graal/graalCompiler.hpp	Fri Mar 27 15:43:31 2015 +0100
+++ b/src/share/vm/graal/graalCompiler.hpp	Fri Mar 27 17:02:53 2015 +0100
@@ -87,9 +87,7 @@
 
   static elapsedTimer* codeInstallTimer() { return &_codeInstallTimer; }
 
-#ifndef PRODUCT
   void compile_the_world();
-#endif
 };
 
 #endif // SHARE_VM_GRAAL_GRAAL_COMPILER_HPP
--- a/src/share/vm/graal/graalJavaAccess.hpp	Fri Mar 27 15:43:31 2015 +0100
+++ b/src/share/vm/graal/graalJavaAccess.hpp	Fri Mar 27 17:02:53 2015 +0100
@@ -159,6 +159,7 @@
     oop_field(DebugInfo, bytecodePosition, "Lcom/oracle/graal/api/code/BytecodePosition;")                                                                     \
     oop_field(DebugInfo, referenceMap, "Lcom/oracle/graal/api/code/ReferenceMap;")                                                                             \
     oop_field(DebugInfo, calleeSaveInfo, "Lcom/oracle/graal/api/code/RegisterSaveLayout;")                                                                     \
+    objArrayOop_field(DebugInfo, virtualObjectMapping, "[Lcom/oracle/graal/api/meta/Value;")                                                                   \
   end_class                                                                                                                                                    \
   start_class(HotSpotReferenceMap)                                                                                                                             \
     oop_field(HotSpotReferenceMap, registerRefMap, "Ljava/util/BitSet;")                                                                                       \
--- a/src/share/vm/prims/jni.cpp	Fri Mar 27 15:43:31 2015 +0100
+++ b/src/share/vm/prims/jni.cpp	Fri Mar 27 17:02:53 2015 +0100
@@ -5199,7 +5199,7 @@
     *vm = (JavaVM *)(&main_vm);
     *(JNIEnv**)penv = thread->jni_environment();
 
-#if defined(GRAAL) && !defined(PRODUCT)
+#if defined(GRAAL)
     // We turn off CompileTheWorld so that compilation requests are not ignored during bootstrap or that Graal can be compiled by C1/C2.
     bool doCTW = CompileTheWorld;
     CompileTheWorld = false;
@@ -5210,14 +5210,14 @@
     if (FLAG_IS_DEFAULT(BootstrapGraal) ? !TieredCompilation : BootstrapGraal) {
       GraalCompiler::instance()->bootstrap();
     }
-#elif defined(GRAAL) && !defined(PRODUCT)
+#elif defined(GRAAL)
     if (doCTW) {
       // required for hosted CTW.
       CompilationPolicy::completed_vm_startup();
     }
 #endif
 
-#if defined(GRAAL) && !defined(PRODUCT)
+#if defined(GRAAL)
     if (doCTW) {
       GraalCompiler::instance()->compile_the_world();
     }
--- a/src/share/vm/runtime/globals.hpp	Fri Mar 27 15:43:31 2015 +0100
+++ b/src/share/vm/runtime/globals.hpp	Fri Mar 27 17:02:53 2015 +0100
@@ -2678,9 +2678,13 @@
           "Delay invoking the compiler until main application class is "    \
           "loaded")                                                         \
                                                                             \
-  develop(bool, CompileTheWorld, false,                                     \
+  NOT_GRAAL(develop(bool, CompileTheWorld, false,                           \
           "Compile all methods in all classes in bootstrap class path "     \
-          "(stress test)")                                                  \
+            "(stress test)"))                                               \
+                                                                            \
+  GRAAL_ONLY(product(bool, CompileTheWorld, false,                          \
+          "Compile all methods in all classes in bootstrap class path "     \
+                     "(stress test)"))                                      \
                                                                             \
   develop(bool, CompileTheWorldPreloadClasses, true,                        \
           "Preload all classes used by a class before start loading")       \