changeset 22731:a3268580f915

support for optimization aware accurate bytecode based profiling http://dag.inf.usi.ch/paper/oopsla15-zhengy.pdf
author zhengy <yudi.zheng@usi.ch>
date Wed, 30 Sep 2015 11:38:20 +0200
parents 7566297ba145
children 677b1d02cb0d
files graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LowTier.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/MidTier.java graal/com.oracle.graal.debug/src/com/oracle/graal/debug/query/DelimitationAPI.java graal/com.oracle.graal.debug/src/com/oracle/graal/debug/query/GraalQueryAPI.java graal/com.oracle.graal.debug/src/com/oracle/graal/debug/query/SpecialIntrinsicGuard.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalCompiler.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/DelimitationAPISubstitutions.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/GraalQueryAPISubstitutions.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/query/GetRootNameNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/query/GetRuntimePathNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/query/IsMethodInlinedNode.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/MultiTypeGuardInlineInfo.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableGraph.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/GreedyInliningPolicy.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/InlineEverythingPolicy.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/ComputeInliningRelevance.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/query/ExtractICGPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/query/HighTierReconcileICGPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/query/InlineICGPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/query/MidTierReconcileICGPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/query/nodes/GraalQueryNode.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/query/nodes/InstrumentationBeginNode.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/query/nodes/InstrumentationEndNode.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/query/nodes/InstrumentationNode.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/query/nodes/MonitorProxyNode.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java
diffstat 32 files changed, 1484 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java	Tue Sep 29 22:19:45 2015 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java	Wed Sep 30 11:38:20 2015 +0200
@@ -311,4 +311,8 @@
             return enabled;
         }
     };
+
+    @Option(help = "Enable compiler decision queries")
+    public static final OptionValue<Boolean> UseGraalQueries = new OptionValue<>(false);
+
 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Tue Sep 29 22:19:45 2015 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Wed Sep 30 11:38:20 2015 +0200
@@ -24,6 +24,7 @@
 
 import static com.oracle.graal.compiler.GraalCompilerOptions.EmitLIRRepeatCount;
 import static com.oracle.graal.compiler.common.GraalOptions.RegisterPressure;
+import static com.oracle.graal.compiler.common.GraalOptions.UseGraalQueries;
 import static com.oracle.graal.compiler.common.alloc.RegisterAllocationConfig.ALL_REGISTERS;
 import static com.oracle.graal.phases.common.DeadCodeEliminationPhase.Optionality.Optional;
 
@@ -75,6 +76,7 @@
 import com.oracle.graal.phases.OptimisticOptimizations;
 import com.oracle.graal.phases.PhaseSuite;
 import com.oracle.graal.phases.common.DeadCodeEliminationPhase;
+import com.oracle.graal.phases.common.query.ExtractICGPhase;
 import com.oracle.graal.phases.schedule.SchedulePhase;
 import com.oracle.graal.phases.tiers.HighTierContext;
 import com.oracle.graal.phases.tiers.LowTierContext;
@@ -201,6 +203,9 @@
             HighTierContext highTierContext = new HighTierContext(providers, graphBuilderSuite, optimisticOpts);
             if (graph.start().next() == null) {
                 graphBuilderSuite.apply(graph, highTierContext);
+                if (UseGraalQueries.getValue()) {
+                    new ExtractICGPhase().apply(graph, highTierContext);
+                }
                 new DeadCodeEliminationPhase(Optional).apply(graph);
             } else {
                 Debug.dump(graph, "initial state");
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java	Tue Sep 29 22:19:45 2015 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java	Wed Sep 30 11:38:20 2015 +0200
@@ -31,6 +31,7 @@
 import static com.oracle.graal.compiler.common.GraalOptions.OptConvertDeoptsToGuards;
 import static com.oracle.graal.compiler.common.GraalOptions.OptLoopTransform;
 import static com.oracle.graal.compiler.common.GraalOptions.PartialEscapeAnalysis;
+import static com.oracle.graal.compiler.common.GraalOptions.UseGraalQueries;
 import static com.oracle.graal.compiler.phases.HighTier.Options.Inline;
 import static com.oracle.graal.phases.common.DeadCodeEliminationPhase.Optionality.Optional;
 import jdk.internal.jvmci.options.Option;
@@ -49,6 +50,7 @@
 import com.oracle.graal.phases.common.LoweringPhase;
 import com.oracle.graal.phases.common.RemoveValueProxyPhase;
 import com.oracle.graal.phases.common.inlining.InliningPhase;
+import com.oracle.graal.phases.common.query.HighTierReconcileICGPhase;
 import com.oracle.graal.phases.tiers.HighTierContext;
 import com.oracle.graal.virtual.phases.ea.PartialEscapePhase;
 
@@ -109,5 +111,8 @@
         appendPhase(new RemoveValueProxyPhase());
 
         appendPhase(new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER));
+        if (UseGraalQueries.getValue()) {
+            appendPhase(new HighTierReconcileICGPhase());
+        }
     }
 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LowTier.java	Tue Sep 29 22:19:45 2015 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LowTier.java	Wed Sep 30 11:38:20 2015 +0200
@@ -25,6 +25,7 @@
 import static com.oracle.graal.compiler.common.GraalOptions.ConditionalElimination;
 import static com.oracle.graal.compiler.common.GraalOptions.ImmutableCode;
 import static com.oracle.graal.compiler.common.GraalOptions.OptCanonicalizer;
+import static com.oracle.graal.compiler.common.GraalOptions.UseGraalQueries;
 import static com.oracle.graal.phases.common.DeadCodeEliminationPhase.Optionality.Required;
 import jdk.internal.jvmci.options.Option;
 import jdk.internal.jvmci.options.OptionType;
@@ -40,6 +41,7 @@
 import com.oracle.graal.phases.common.ProfileCompiledMethodsPhase;
 import com.oracle.graal.phases.common.RemoveValueProxyPhase;
 import com.oracle.graal.phases.common.UseTrappingNullChecksPhase;
+import com.oracle.graal.phases.common.query.InlineICGPhase;
 import com.oracle.graal.phases.tiers.LowTierContext;
 
 public class LowTier extends PhaseSuite<LowTierContext> {
@@ -64,6 +66,9 @@
         }
 
         appendPhase(new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.LOW_TIER));
+        if (UseGraalQueries.getValue()) {
+            appendPhase(new InlineICGPhase());
+        }
 
         appendPhase(new RemoveValueProxyPhase());
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/MidTier.java	Tue Sep 29 22:19:45 2015 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/MidTier.java	Wed Sep 30 11:38:20 2015 +0200
@@ -31,6 +31,7 @@
 import static com.oracle.graal.compiler.common.GraalOptions.OptPushThroughPi;
 import static com.oracle.graal.compiler.common.GraalOptions.OptReadElimination;
 import static com.oracle.graal.compiler.common.GraalOptions.ReassociateInvariants;
+import static com.oracle.graal.compiler.common.GraalOptions.UseGraalQueries;
 import static com.oracle.graal.compiler.common.GraalOptions.VerifyHeapAtReturn;
 
 import com.oracle.graal.loop.phases.LoopSafepointEliminationPhase;
@@ -52,6 +53,7 @@
 import com.oracle.graal.phases.common.RemoveValueProxyPhase;
 import com.oracle.graal.phases.common.ValueAnchorCleanupPhase;
 import com.oracle.graal.phases.common.VerifyHeapAtReturnPhase;
+import com.oracle.graal.phases.common.query.MidTierReconcileICGPhase;
 import com.oracle.graal.phases.tiers.MidTierContext;
 import com.oracle.graal.virtual.phases.ea.EarlyReadEliminationPhase;
 
@@ -113,6 +115,9 @@
         }
 
         appendPhase(new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.MID_TIER));
+        if (UseGraalQueries.getValue()) {
+            appendPhase(new MidTierReconcileICGPhase());
+        }
 
         appendPhase(new FrameStateAssignmentPhase());
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/query/DelimitationAPI.java	Wed Sep 30 11:38:20 2015 +0200
@@ -0,0 +1,44 @@
+/*
+ * 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.debug.query;
+
+public class DelimitationAPI {
+
+    /**
+     * Marks the beginning of the instrumentation boundary. - The target parameter indicates whether
+     * to associate the instrumentation with the preceding or the following base program IR node.
+     * Supported values are -1 (predecessor), 1 (successor)}.
+     */
+    public static void instrumentationBegin(@SuppressWarnings("unused") int offset) {
+    }
+
+    public static void instrumentationBegin(@SuppressWarnings("unused") int offset, @SuppressWarnings("unused") int type) {
+    }
+
+    /**
+     * Marks the end of the instrumentation boundary.
+     */
+    public static void instrumentationEnd() {
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/query/GraalQueryAPI.java	Wed Sep 30 11:38:20 2015 +0200
@@ -0,0 +1,79 @@
+/*
+ * 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.debug.query;
+
+/**
+ * NOTE that these queries return fixed constants in the interpreter mode. The Graal option
+ * RemoveNeverExecutedCode is switched off to prevent de-optimization.
+ */
+public final class GraalQueryAPI {
+
+    // Static query intrinsics
+
+    /**
+     * @return true if the enclosing method has been compiled by the dynamic compiler.
+     */
+    public static boolean isMethodCompiled() {
+        return false;
+    }
+
+    /**
+     * @return true if the enclosing method is inlined.
+     */
+    public static boolean isMethodInlined() {
+        return false;
+    }
+
+    /**
+     * @return the name of the root method for the current compilation task. If the enclosing method
+     *         is inlined, this query returns the name of the method into which it is inlined.
+     */
+    public static String getRootName() {
+        return "unknown";
+    }
+
+    // Dynamic query intrinsics
+
+    public static final int ERROR = -1;
+
+    /**
+     * @return the kind of heap allocation for a directly preceding allocation site. The possible
+     *         return values are {ERROR(-1), TLAB(0), HEAP(1)}. While ERROR denotes either the
+     *         utility is not supported, e.g. in interpreter, or if the allocation site was
+     *         eliminated, the other two represent a TLAB allocation (fast path) or a direct heap
+     *         allocation (slow path).
+     */
+    public static int getAllocationType() {
+        return ERROR;
+    }
+
+    /**
+     * @return the runtime lock type for a directly preceding lock site. The possible return values
+     *         are {ERROR(-1), bias:existing(0), bias:acquired(1), bias:transfer(2),
+     *         stub:revoke_or_stub:epoch-expired(3), stub:failed-cas(4), recursive(5), cas(6)}.
+     */
+    public static int getLockType() {
+        return ERROR;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/query/SpecialIntrinsicGuard.java	Wed Sep 30 11:38:20 2015 +0200
@@ -0,0 +1,37 @@
+/*
+ * 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.debug.query;
+
+import jdk.internal.jvmci.meta.ResolvedJavaMethod;
+
+public class SpecialIntrinsicGuard {
+
+    public static final String CN_DELIMITATIONAPI = DelimitationAPI.class.getName();
+    public static final String CN_GRAALQUERYAPI = GraalQueryAPI.class.getName();
+
+    public static boolean isQueryIntrinsic(ResolvedJavaMethod method) {
+        String klass = method.getDeclaringClass().toJavaName();
+        return CN_DELIMITATIONAPI.equals(klass) || CN_GRAALQUERYAPI.equals(klass);
+    }
+
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalCompiler.java	Tue Sep 29 22:19:45 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalCompiler.java	Wed Sep 30 11:38:20 2015 +0200
@@ -46,6 +46,7 @@
 import com.oracle.graal.debug.TTY;
 import com.oracle.graal.debug.TopLevelDebugConfig;
 import com.oracle.graal.debug.internal.DebugScope;
+import com.oracle.graal.debug.query.SpecialIntrinsicGuard;
 import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration;
 import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.graphbuilderconf.IntrinsicContext;
@@ -108,8 +109,10 @@
         HotSpotBackend backend = graalRuntime.getHostBackend();
         HotSpotProviders providers = backend.getProviders();
         final boolean isOSR = entryBCI != Compiler.INVOCATION_ENTRY_BCI;
+        // avoid compiling the intrinsic graphs for GraalQueryAPI methods
+        boolean bypassIntrinsic = method.isNative() || isOSR || SpecialIntrinsicGuard.isQueryIntrinsic(method);
+        StructuredGraph graph = bypassIntrinsic ? null : getIntrinsicGraph(method, providers);
 
-        StructuredGraph graph = method.isNative() || isOSR ? null : getIntrinsicGraph(method, providers);
         if (graph == null) {
             SpeculationLog speculationLog = method.getSpeculationLog();
             if (speculationLog != null) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/DelimitationAPISubstitutions.java	Wed Sep 30 11:38:20 2015 +0200
@@ -0,0 +1,49 @@
+/*
+ * 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.replacements;
+
+import com.oracle.graal.api.replacements.ClassSubstitution;
+import com.oracle.graal.api.replacements.MethodSubstitution;
+import com.oracle.graal.debug.query.DelimitationAPI;
+import com.oracle.graal.phases.common.query.nodes.InstrumentationBeginNode;
+import com.oracle.graal.phases.common.query.nodes.InstrumentationEndNode;
+
+@ClassSubstitution(DelimitationAPI.class)
+public class DelimitationAPISubstitutions {
+
+    @MethodSubstitution(isStatic = true)
+    public static void instrumentationBegin(int target) {
+        InstrumentationBeginNode.instantiate(target, 0);
+    }
+
+    @MethodSubstitution(isStatic = true)
+    public static void instrumentationBegin(int target, int type) {
+        InstrumentationBeginNode.instantiate(target, type);
+    }
+
+    @MethodSubstitution(isStatic = true)
+    public static void instrumentationEnd() {
+        InstrumentationEndNode.instantiate();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/GraalQueryAPISubstitutions.java	Wed Sep 30 11:38:20 2015 +0200
@@ -0,0 +1,60 @@
+/*
+ * 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.replacements;
+
+import com.oracle.graal.api.replacements.ClassSubstitution;
+import com.oracle.graal.api.replacements.MethodSubstitution;
+import com.oracle.graal.debug.query.GraalQueryAPI;
+import com.oracle.graal.hotspot.replacements.query.GetRootNameNode;
+import com.oracle.graal.hotspot.replacements.query.GetRuntimePathNode;
+import com.oracle.graal.hotspot.replacements.query.IsMethodInlinedNode;
+
+@ClassSubstitution(GraalQueryAPI.class)
+public class GraalQueryAPISubstitutions {
+
+    @MethodSubstitution(isStatic = true)
+    public static boolean isMethodCompiled() {
+        return true;
+    }
+
+    @MethodSubstitution(isStatic = true)
+    public static boolean isMethodInlined() {
+        return IsMethodInlinedNode.instantiate();
+    }
+
+    @MethodSubstitution(isStatic = true)
+    public static String getRootName() {
+        return GetRootNameNode.instantiate();
+    }
+
+    @MethodSubstitution(isStatic = true)
+    public static int getAllocationType() {
+        return GetRuntimePathNode.instantiate();
+    }
+
+    @MethodSubstitution(isStatic = true)
+    public static int getLockType() {
+        return GetRuntimePathNode.instantiate();
+    }
+
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java	Tue Sep 29 22:19:45 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java	Wed Sep 30 11:38:20 2015 +0200
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
+import static com.oracle.graal.compiler.common.GraalOptions.UseGraalQueries;
 import jdk.internal.jvmci.code.TargetDescription;
 import jdk.internal.jvmci.meta.MetaAccessProvider;
 import jdk.internal.jvmci.service.ServiceProvider;
@@ -29,6 +30,8 @@
 import sun.reflect.Reflection;
 
 import com.oracle.graal.api.replacements.SnippetReflectionProvider;
+import com.oracle.graal.debug.query.DelimitationAPI;
+import com.oracle.graal.debug.query.GraalQueryAPI;
 import com.oracle.graal.nodes.spi.LoweringProvider;
 import com.oracle.graal.nodes.spi.Replacements;
 import com.oracle.graal.nodes.spi.ReplacementsProvider;
@@ -42,5 +45,9 @@
         replacements.registerSubstitutions(Thread.class, ThreadSubstitutions.class);
         replacements.registerSubstitutions(Reflection.class, ReflectionSubstitutions.class);
         replacements.registerSubstitutions(ConstantPool.class, ConstantPoolSubstitutions.class);
+        if (UseGraalQueries.getValue()) {
+            replacements.registerSubstitutions(GraalQueryAPI.class, GraalQueryAPISubstitutions.class);
+            replacements.registerSubstitutions(DelimitationAPI.class, DelimitationAPISubstitutions.class);
+        }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/query/GetRootNameNode.java	Wed Sep 30 11:38:20 2015 +0200
@@ -0,0 +1,60 @@
+/*
+ * 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.replacements.query;
+
+import jdk.internal.jvmci.hotspot.HotSpotObjectConstantImpl;
+import jdk.internal.jvmci.hotspot.HotSpotResolvedObjectType;
+import jdk.internal.jvmci.meta.Constant;
+import jdk.internal.jvmci.meta.JavaKind;
+import jdk.internal.jvmci.meta.ResolvedJavaMethod;
+
+import com.oracle.graal.compiler.common.type.StampFactory;
+import com.oracle.graal.graph.NodeClass;
+import com.oracle.graal.nodeinfo.NodeInfo;
+import com.oracle.graal.nodes.ConstantNode;
+import com.oracle.graal.nodes.FixedNode;
+import com.oracle.graal.phases.common.query.nodes.GraalQueryNode;
+import com.oracle.graal.phases.common.query.nodes.InstrumentationNode;
+
+@NodeInfo
+public final class GetRootNameNode extends GraalQueryNode {
+
+    public static final NodeClass<GetRootNameNode> TYPE = NodeClass.create(GetRootNameNode.class);
+
+    public GetRootNameNode() {
+        super(TYPE, StampFactory.exactNonNull(HotSpotResolvedObjectType.fromObjectClass(String.class)));
+    }
+
+    @Override
+    public void onInlineICG(InstrumentationNode instrumentation, FixedNode position) {
+        ResolvedJavaMethod method = graph().method();
+        String root = method.getDeclaringClass().toJavaName() + "." + method.getName() + method.getSignature().toMethodDescriptor();
+        Constant constant = HotSpotObjectConstantImpl.forBoxedValue(JavaKind.Object, root);
+        ConstantNode constantNode = graph().unique(new ConstantNode(constant, stamp()));
+        graph().replaceFixedWithFloating(this, constantNode);
+    }
+
+    @NodeIntrinsic
+    public static native String instantiate();
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/query/GetRuntimePathNode.java	Wed Sep 30 11:38:20 2015 +0200
@@ -0,0 +1,85 @@
+/*
+ * 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.replacements.query;
+
+import jdk.internal.jvmci.meta.JavaKind;
+
+import com.oracle.graal.compiler.common.type.StampFactory;
+import com.oracle.graal.graph.Node;
+import com.oracle.graal.graph.NodeClass;
+import com.oracle.graal.graph.NodeFlood;
+import com.oracle.graal.nodeinfo.NodeInfo;
+import com.oracle.graal.nodes.AbstractEndNode;
+import com.oracle.graal.nodes.AbstractMergeNode;
+import com.oracle.graal.nodes.ConstantNode;
+import com.oracle.graal.nodes.FixedNode;
+import com.oracle.graal.nodes.LoopEndNode;
+import com.oracle.graal.nodes.ValuePhiNode;
+import com.oracle.graal.phases.common.query.nodes.GraalQueryNode;
+import com.oracle.graal.phases.common.query.nodes.InstrumentationNode;
+
+@NodeInfo
+public final class GetRuntimePathNode extends GraalQueryNode {
+
+    public static final NodeClass<GetRuntimePathNode> TYPE = NodeClass.create(GetRuntimePathNode.class);
+
+    public GetRuntimePathNode() {
+        super(TYPE, StampFactory.forKind(JavaKind.Int));
+    }
+
+    private static boolean isCFGAccessible(FixedNode from, FixedNode to) {
+        NodeFlood flood = from.graph().createNodeFlood();
+        flood.add(from);
+        for (Node current : flood) {
+            if (current instanceof LoopEndNode) {
+                continue;
+            } else if (current instanceof AbstractEndNode) {
+                flood.add(((AbstractEndNode) current).merge());
+            } else {
+                flood.addAll(current.successors());
+            }
+        }
+        return flood.isMarked(to);
+    }
+
+    @Override
+    public void onInlineICG(InstrumentationNode instrumentation, FixedNode position) {
+        if (instrumentation.target() instanceof AbstractMergeNode) {
+            AbstractMergeNode merge = (AbstractMergeNode) instrumentation.target();
+
+            if (isCFGAccessible(merge, position)) {
+                ValuePhiNode phi = graph().addWithoutUnique(new ValuePhiNode(StampFactory.intValue(), merge));
+                for (int i = 0; i < merge.cfgPredecessors().count(); i++) {
+                    phi.addInput(ConstantNode.forInt(i, merge.graph()));
+                }
+                graph().replaceFixedWithFloating(this, phi);
+                return;
+            }
+        }
+        graph().replaceFixedWithFloating(this, ConstantNode.forInt(-1, graph()));
+    }
+
+    @NodeIntrinsic
+    public static native int instantiate();
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/query/IsMethodInlinedNode.java	Wed Sep 30 11:38:20 2015 +0200
@@ -0,0 +1,59 @@
+/*
+ * 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.replacements.query;
+
+import jdk.internal.jvmci.meta.JavaKind;
+
+import com.oracle.graal.compiler.common.type.StampFactory;
+import com.oracle.graal.graph.NodeClass;
+import com.oracle.graal.nodeinfo.NodeInfo;
+import com.oracle.graal.nodes.ConstantNode;
+import com.oracle.graal.nodes.FixedNode;
+import com.oracle.graal.phases.common.query.nodes.GraalQueryNode;
+import com.oracle.graal.phases.common.query.nodes.InstrumentationNode;
+
+@NodeInfo
+public final class IsMethodInlinedNode extends GraalQueryNode {
+
+    public static final NodeClass<IsMethodInlinedNode> TYPE = NodeClass.create(IsMethodInlinedNode.class);
+
+    protected int original;
+
+    public IsMethodInlinedNode() {
+        super(TYPE, StampFactory.forKind(JavaKind.Boolean));
+    }
+
+    @Override
+    public void onExtractICG(InstrumentationNode instrumentation) {
+        original = System.identityHashCode(instrumentation.graph());
+    }
+
+    @Override
+    public void onInlineICG(InstrumentationNode instrumentation, FixedNode position) {
+        graph().replaceFixedWithFloating(this, ConstantNode.forBoolean(original != System.identityHashCode(instrumentation.graph()), graph()));
+    }
+
+    @NodeIntrinsic
+    public static native boolean instantiate();
+
+}
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Tue Sep 29 22:19:45 2015 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Wed Sep 30 11:38:20 2015 +0200
@@ -23,6 +23,7 @@
 package com.oracle.graal.phases.common.inlining;
 
 import static com.oracle.graal.compiler.common.GraalOptions.HotSpotPrintInlining;
+import static com.oracle.graal.compiler.common.GraalOptions.UseGraalQueries;
 import static jdk.internal.jvmci.meta.DeoptimizationAction.InvalidateReprofile;
 import static jdk.internal.jvmci.meta.DeoptimizationReason.NullCheckException;
 
@@ -94,6 +95,7 @@
 import com.oracle.graal.nodes.type.StampTool;
 import com.oracle.graal.nodes.util.GraphUtil;
 import com.oracle.graal.phases.common.inlining.info.InlineInfo;
+import com.oracle.graal.phases.common.query.nodes.InstrumentationNode;
 
 public class InliningUtil {
 
@@ -363,6 +365,9 @@
             unwindNode = (UnwindNode) duplicates.get(unwindNode);
         }
 
+        if (UseGraalQueries.getValue()) {
+            removeAttachedInstrumentation(invoke);
+        }
         finishInlining(invoke, graph, firstCFGNode, returnNodes, unwindNode, inlineGraph.getAssumptions(), inlineGraph, canonicalizedNodes);
 
         GraphUtil.killCFG(invokeNode);
@@ -753,4 +758,24 @@
             throw new GraalGraphJVMCIError(e).addContext(invoke.asNode()).addContext("macroSubstitution", macroNodeClass);
         }
     }
+
+    // exclude InstrumentationNode for inlining heuristics
+    public static int getNodeCount(StructuredGraph graph) {
+        if (UseGraalQueries.getValue()) {
+            return graph.getNodeCount() - graph.getNodes().filter(InstrumentationNode.class).count();
+        } else {
+            return graph.getNodeCount();
+        }
+    }
+
+    public static void removeAttachedInstrumentation(Invoke invoke) {
+        FixedNode invokeNode = invoke.asNode();
+        for (InstrumentationNode instrumentation : invokeNode.usages().filter(InstrumentationNode.class)) {
+            if (instrumentation.target() == invoke) {
+                GraphUtil.unlinkFixedNode(instrumentation);
+                instrumentation.safeDelete();
+            }
+        }
+    }
+
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/MultiTypeGuardInlineInfo.java	Tue Sep 29 22:19:45 2015 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/MultiTypeGuardInlineInfo.java	Wed Sep 30 11:38:20 2015 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.phases.common.inlining.info;
 
+import static com.oracle.graal.compiler.common.GraalOptions.UseGraalQueries;
+
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashSet;
@@ -241,6 +243,9 @@
         assert invoke.next() == continuation;
         invoke.setNext(null);
         returnMerge.setNext(continuation);
+        if (UseGraalQueries.getValue()) {
+            InliningUtil.removeAttachedInstrumentation(invoke);
+        }
         if (returnValuePhi != null) {
             invoke.asNode().replaceAtUsages(returnValuePhi);
         }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableGraph.java	Tue Sep 29 22:19:45 2015 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableGraph.java	Wed Sep 30 11:38:20 2015 +0200
@@ -23,6 +23,7 @@
 package com.oracle.graal.phases.common.inlining.info.elem;
 
 import static com.oracle.graal.compiler.common.GraalOptions.OptCanonicalizer;
+import static com.oracle.graal.compiler.common.GraalOptions.UseGraalQueries;
 import static com.oracle.graal.phases.common.DeadCodeEliminationPhase.Optionality.Optional;
 
 import java.util.ArrayList;
@@ -44,6 +45,7 @@
 import com.oracle.graal.phases.common.CanonicalizerPhase;
 import com.oracle.graal.phases.common.DeadCodeEliminationPhase;
 import com.oracle.graal.phases.common.inlining.InliningUtil;
+import com.oracle.graal.phases.common.query.ExtractICGPhase;
 import com.oracle.graal.phases.graph.FixedNodeProbabilityCache;
 import com.oracle.graal.phases.tiers.HighTierContext;
 
@@ -209,6 +211,9 @@
             }
             assert newGraph.start().next() != null : "graph needs to be populated by the GraphBuilderSuite " + method + ", " + method.canBeInlined();
 
+            if (UseGraalQueries.getValue()) {
+                new ExtractICGPhase().apply(newGraph, context);
+            }
             new DeadCodeEliminationPhase(Optional).apply(newGraph);
 
             if (OptCanonicalizer.getValue()) {
@@ -223,7 +228,7 @@
 
     @Override
     public int getNodeCount() {
-        return graph.getNodeCount();
+        return InliningUtil.getNodeCount(graph);
     }
 
     @Override
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/GreedyInliningPolicy.java	Tue Sep 29 22:19:45 2015 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/GreedyInliningPolicy.java	Wed Sep 30 11:38:20 2015 +0200
@@ -49,7 +49,7 @@
     }
 
     public boolean continueInlining(StructuredGraph currentGraph) {
-        if (currentGraph.getNodeCount() >= MaximumDesiredSize.getValue()) {
+        if (InliningUtil.getNodeCount(currentGraph) >= MaximumDesiredSize.getValue()) {
             InliningUtil.logInliningDecision("inlining is cut off by MaximumDesiredSize");
             metricInliningStoppedByMaxDesiredSize.increment();
             return false;
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/InlineEverythingPolicy.java	Tue Sep 29 22:19:45 2015 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/InlineEverythingPolicy.java	Wed Sep 30 11:38:20 2015 +0200
@@ -27,12 +27,13 @@
 
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.spi.Replacements;
+import com.oracle.graal.phases.common.inlining.InliningUtil;
 import com.oracle.graal.phases.common.inlining.walker.MethodInvocation;
 
 public class InlineEverythingPolicy implements InliningPolicy {
 
     public boolean continueInlining(StructuredGraph graph) {
-        if (graph.getNodeCount() >= MaximumDesiredSize.getValue()) {
+        if (InliningUtil.getNodeCount(graph) >= MaximumDesiredSize.getValue()) {
             throw new BailoutException("Inline all calls failed. The resulting graph is too large.");
         }
         return true;
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/ComputeInliningRelevance.java	Tue Sep 29 22:19:45 2015 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/ComputeInliningRelevance.java	Wed Sep 30 11:38:20 2015 +0200
@@ -43,6 +43,7 @@
 import com.oracle.graal.nodes.MergeNode;
 import com.oracle.graal.nodes.StartNode;
 import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.phases.common.inlining.InliningUtil;
 
 public class ComputeInliningRelevance {
 
@@ -83,7 +84,7 @@
             rootScope = new Scope(graph.start(), null);
         } else {
             if (nodeRelevances == null) {
-                nodeRelevances = Node.newIdentityMap(EXPECTED_MIN_INVOKE_COUNT + graph.getNodeCount() / EXPECTED_INVOKE_RATIO);
+                nodeRelevances = Node.newIdentityMap(EXPECTED_MIN_INVOKE_COUNT + InliningUtil.getNodeCount(graph) / EXPECTED_INVOKE_RATIO);
             }
             NodeWorkList workList = graph.createNodeWorkList();
             Map<LoopBeginNode, Scope> loops = Node.newIdentityMap(EXPECTED_LOOP_COUNT);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/query/ExtractICGPhase.java	Wed Sep 30 11:38:20 2015 +0200
@@ -0,0 +1,217 @@
+/*
+ * 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.phases.common.query;
+
+import java.util.Map;
+
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.graph.Node;
+import com.oracle.graal.graph.NodeBitMap;
+import com.oracle.graal.graph.NodeFlood;
+import com.oracle.graal.graph.NodePosIterator;
+import com.oracle.graal.graph.Position;
+import com.oracle.graal.nodeinfo.InputType;
+import com.oracle.graal.nodes.AbstractEndNode;
+import com.oracle.graal.nodes.AbstractLocalNode;
+import com.oracle.graal.nodes.CallTargetNode;
+import com.oracle.graal.nodes.FixedNode;
+import com.oracle.graal.nodes.FixedWithNextNode;
+import com.oracle.graal.nodes.FrameState;
+import com.oracle.graal.nodes.LoopEndNode;
+import com.oracle.graal.nodes.ParameterNode;
+import com.oracle.graal.nodes.ReturnNode;
+import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.calc.FloatingNode;
+import com.oracle.graal.nodes.java.MonitorEnterNode;
+import com.oracle.graal.nodes.java.MonitorIdNode;
+import com.oracle.graal.nodes.util.GraphUtil;
+import com.oracle.graal.phases.BasePhase;
+import com.oracle.graal.phases.common.DeadCodeEliminationPhase;
+import com.oracle.graal.phases.common.query.nodes.GraalQueryNode;
+import com.oracle.graal.phases.common.query.nodes.InstrumentationBeginNode;
+import com.oracle.graal.phases.common.query.nodes.InstrumentationEndNode;
+import com.oracle.graal.phases.common.query.nodes.InstrumentationNode;
+import com.oracle.graal.phases.common.query.nodes.MonitorProxyNode;
+import com.oracle.graal.phases.tiers.HighTierContext;
+
+public class ExtractICGPhase extends BasePhase<HighTierContext> {
+
+    @Override
+    protected void run(StructuredGraph graph, HighTierContext context) {
+        for (InstrumentationBeginNode icgBegin : graph.getNodes().filter(InstrumentationBeginNode.class)) {
+            Instrumentation instrumentation = new Instrumentation(icgBegin);
+            InstrumentationNode instrumentationNode = instrumentation.createInstrumentationNode();
+
+            graph.addBeforeFixed(icgBegin, instrumentationNode);
+            Debug.dump(instrumentationNode.icg(), "After extracted ICG at " + instrumentation);
+
+            instrumentation.unlink();
+        }
+
+        for (InstrumentationNode instrumentationNode : graph.getNodes().filter(InstrumentationNode.class)) {
+            for (GraalQueryNode query : instrumentationNode.icg().getNodes().filter(GraalQueryNode.class)) {
+                query.onExtractICG(instrumentationNode);
+            }
+        }
+    }
+
+    static class Instrumentation {
+
+        protected InstrumentationBeginNode icgBegin;
+        protected InstrumentationEndNode icgEnd;
+        protected ValueNode target;
+        protected NodeBitMap icgNodes;
+
+        public Instrumentation(InstrumentationBeginNode icgBegin) {
+            this.icgBegin = icgBegin;
+
+            resolveICGNodes();
+            resolveTarget();
+        }
+
+        private static boolean shouldIncludeInput(Node node, NodeBitMap cfgNodes) {
+            if (node instanceof FloatingNode && !(node instanceof AbstractLocalNode)) {
+                NodePosIterator iterator = node.inputs().iterator();
+                while (iterator.hasNext()) {
+                    Position pos = iterator.nextPosition();
+                    if (pos.getInputType() == InputType.Value) {
+                        continue;
+                    }
+                    if (!cfgNodes.isMarked(pos.get(node))) {
+                        return false;
+                    }
+                }
+                return true;
+            }
+            if (node instanceof CallTargetNode || node instanceof MonitorIdNode || node instanceof FrameState) {
+                return true;
+            }
+            return false;
+        }
+
+        private void resolveICGNodes() {
+            NodeFlood icgCFG = icgBegin.graph().createNodeFlood();
+            icgCFG.add(icgBegin.next());
+            for (Node current : icgCFG) {
+                if (current instanceof InstrumentationEndNode) {
+                    icgEnd = (InstrumentationEndNode) current;
+                } else if (current instanceof LoopEndNode) {
+                    // do nothing
+                } else if (current instanceof AbstractEndNode) {
+                    icgCFG.add(((AbstractEndNode) current).merge());
+                } else {
+                    icgCFG.addAll(current.successors());
+                }
+            }
+
+            NodeBitMap cfgNodes = icgCFG.getVisited();
+            NodeFlood icgDFG = icgBegin.graph().createNodeFlood();
+            icgDFG.addAll(cfgNodes);
+            for (Node current : icgDFG) {
+                if (current instanceof FrameState) {
+                    continue;
+                }
+                for (Node input : current.inputs()) {
+                    if (shouldIncludeInput(input, cfgNodes)) {
+                        icgDFG.add(input);
+                    }
+                }
+            }
+            icgNodes = icgDFG.getVisited();
+        }
+
+        private void resolveTarget() {
+            int offset = icgBegin.getOffset();
+            if (offset < 0) {
+                Node pred = icgBegin;
+                while (offset < 0) {
+                    pred = pred.predecessor();
+                    if (pred == null || !(pred instanceof FixedNode)) {
+                        target = null;
+                        return;
+                    }
+                    offset++;
+                }
+                target = (FixedNode) pred;
+            } else if (offset > 0) {
+                FixedNode next = icgEnd;
+                while (offset > 0) {
+                    next = ((FixedWithNextNode) next).next();
+                    if (next == null || !(next instanceof FixedWithNextNode)) {
+                        target = null;
+                        return;
+                    }
+                    offset--;
+                }
+                target = next;
+            }
+        }
+
+        public InstrumentationNode createInstrumentationNode() {
+            ValueNode newTarget = target;
+            // MonitorEnterNode may be deleted during PEA
+            if (newTarget instanceof MonitorEnterNode) {
+                newTarget = new MonitorProxyNode(newTarget, ((MonitorEnterNode) newTarget).getMonitorId());
+                icgBegin.graph().addWithoutUnique(newTarget);
+            }
+            InstrumentationNode instrumentationNode = new InstrumentationNode(newTarget, icgBegin.getOffset(), icgBegin.getType());
+            icgBegin.graph().addWithoutUnique(instrumentationNode);
+            // copy icg nodes to the InstrumentationNode instance
+            StructuredGraph icg = instrumentationNode.icg();
+            Map<Node, Node> replacements = Node.newMap();
+            int index = 0;
+            for (Node current : icgNodes) {
+                if (current instanceof FrameState) {
+                    continue;
+                }
+                for (Node input : current.inputs()) {
+                    if (!(input instanceof ValueNode)) {
+                        continue;
+                    }
+                    if (!icgNodes.isMarked(input) && !replacements.containsKey(input)) {
+                        ParameterNode parameter = new ParameterNode(index++, ((ValueNode) input).stamp());
+                        icg.addWithoutUnique(parameter);
+                        replacements.put(input, parameter);
+                        instrumentationNode.addInput(input);
+                    }
+                }
+            }
+            replacements = icg.addDuplicates(icgNodes, icgBegin.graph(), icgNodes.count(), replacements);
+            icg.start().setNext((FixedNode) replacements.get(icgBegin.next()));
+            replacements.get(icgEnd).replaceAtPredecessor(icg.addWithoutUnique(new ReturnNode(null)));
+
+            new DeadCodeEliminationPhase().apply(icg, false);
+            return instrumentationNode;
+        }
+
+        public void unlink() {
+            FixedNode next = icgEnd.next();
+            icgEnd.setNext(null);
+            icgBegin.replaceAtPredecessor(next);
+            GraphUtil.killCFG(icgBegin);
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/query/HighTierReconcileICGPhase.java	Wed Sep 30 11:38:20 2015 +0200
@@ -0,0 +1,164 @@
+/*
+ * 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.phases.common.query;
+
+import java.util.HashMap;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+
+import com.oracle.graal.graph.Node;
+import com.oracle.graal.graph.NodeFlood;
+import com.oracle.graal.nodes.AbstractEndNode;
+import com.oracle.graal.nodes.FixedWithNextNode;
+import com.oracle.graal.nodes.LoopEndNode;
+import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.java.AccessMonitorNode;
+import com.oracle.graal.nodes.java.MonitorIdNode;
+import com.oracle.graal.nodes.util.GraphUtil;
+import com.oracle.graal.nodes.virtual.AllocatedObjectNode;
+import com.oracle.graal.nodes.virtual.CommitAllocationNode;
+import com.oracle.graal.nodes.virtual.VirtualObjectNode;
+import com.oracle.graal.phases.Phase;
+import com.oracle.graal.phases.common.query.nodes.InstrumentationNode;
+import com.oracle.graal.phases.common.query.nodes.MonitorProxyNode;
+
+public class HighTierReconcileICGPhase extends Phase {
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        for (CommitAllocationNode commit : graph.getNodes().filter(CommitAllocationNode.class)) {
+            InstrumentationAggregation aggregation = new InstrumentationAggregation(commit);
+
+            for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
+                VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex);
+                aggregation.duplicateInstrumentationIfMatch(i -> i.target() == virtual, () -> getAllocatedObject(commit, virtual));
+            }
+
+            for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
+                VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex);
+                for (MonitorIdNode monitorId : commit.getLocks(objIndex)) {
+                    aggregation.duplicateInstrumentationIfMatch(i -> i.target() instanceof MonitorProxyNode && ((MonitorProxyNode) i.target()).getMonitorId() == monitorId, () -> new MonitorProxyNode(
+                                    getAllocatedObject(commit, virtual), monitorId));
+                }
+            }
+        }
+
+        for (InstrumentationNode instrumentationNode : graph.getNodes().filter(InstrumentationNode.class)) {
+            ValueNode target = instrumentationNode.target();
+            if (target instanceof VirtualObjectNode) {
+                // at this point, we can remove InstrumentationNode whose target is still virtual.
+                GraphUtil.unlinkFixedNode(instrumentationNode);
+                instrumentationNode.safeDelete();
+            } else if (target instanceof MonitorProxyNode) {
+                MonitorProxyNode proxy = (MonitorProxyNode) target;
+                if (proxy.target() == null || proxy.target().isDeleted()) {
+                    GraphUtil.unlinkFixedNode(instrumentationNode);
+                    instrumentationNode.safeDelete();
+                } else if (proxy.target() instanceof AccessMonitorNode) {
+                    // unproxify the target of the InstrumentationNode.
+                    instrumentationNode.replaceFirstInput(proxy, proxy.target());
+                }
+            }
+        }
+    }
+
+    class InstrumentationAggregation {
+
+        protected CommitAllocationNode commit;
+        protected FixedWithNextNode insertingLocation;
+
+        public InstrumentationAggregation(CommitAllocationNode commit) {
+            this.commit = commit;
+            this.insertingLocation = commit;
+        }
+
+        public void insert(InstrumentationNode instrumentationNode) {
+            commit.graph().addAfterFixed(insertingLocation, instrumentationNode);
+            insertingLocation = instrumentationNode;
+        }
+
+        public void duplicateInstrumentationIfMatch(Predicate<InstrumentationNode> guard, Supplier<ValueNode> newTargetSupplier) {
+            StructuredGraph graph = commit.graph();
+            for (InstrumentationNode instrumentationNode : graph.getNodes().filter(InstrumentationNode.class)) {
+                // insert ICG only if the CommitAllocationNode is accessible from the
+                // instrumentation node
+                if (!(isCFGAccessible(instrumentationNode, commit) && guard.test(instrumentationNode))) {
+                    continue;
+                }
+                InstrumentationNode clone = (InstrumentationNode) instrumentationNode.copyWithInputs();
+                ValueNode newTarget = newTargetSupplier.get();
+                if (!newTarget.isAlive()) {
+                    graph.addWithoutUnique(newTarget);
+                }
+                clone.replaceFirstInput(clone.target(), newTarget);
+                updateVirtualInputs(clone);
+                insert(clone);
+            }
+        }
+
+        private void updateVirtualInputs(InstrumentationNode clone) {
+            for (ValueNode input : clone.getWeakDependencies()) {
+                if ((input instanceof VirtualObjectNode) && (commit.getVirtualObjects().contains(input))) {
+                    clone.replaceFirstInput(input, getAllocatedObject(commit, (VirtualObjectNode) input));
+                }
+            }
+        }
+
+    }
+
+    private final HashMap<InstrumentationNode, NodeFlood> cachedNodeFloods = new HashMap<>();
+
+    private boolean isCFGAccessible(InstrumentationNode from, CommitAllocationNode to) {
+        // we only insert InstrumentationNode during this phase, so it is fine to reuse cached
+        // NodeFlood.
+        NodeFlood flood = cachedNodeFloods.get(from);
+        if (flood == null) {
+            flood = from.graph().createNodeFlood();
+            flood.add(from);
+            for (Node current : flood) {
+                if (current instanceof LoopEndNode) {
+                    continue;
+                } else if (current instanceof AbstractEndNode) {
+                    flood.add(((AbstractEndNode) current).merge());
+                } else {
+                    flood.addAll(current.successors());
+                }
+            }
+            cachedNodeFloods.put(from, flood);
+        }
+        return flood.isMarked(to);
+    }
+
+    private static AllocatedObjectNode getAllocatedObject(CommitAllocationNode commit, VirtualObjectNode virtual) {
+        for (AllocatedObjectNode object : commit.graph().getNodes().filter(AllocatedObjectNode.class)) {
+            if (object.getCommit() == commit && object.getVirtualObject() == virtual) {
+                return object;
+            }
+        }
+        AllocatedObjectNode object = commit.graph().addWithoutUnique(new AllocatedObjectNode(virtual));
+        object.setCommit(commit);
+        return object;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/query/InlineICGPhase.java	Wed Sep 30 11:38:20 2015 +0200
@@ -0,0 +1,82 @@
+/*
+ * 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.phases.common.query;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import com.oracle.graal.nodeinfo.InputType;
+import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.memory.MemoryAnchorNode;
+import com.oracle.graal.nodes.spi.LoweringTool;
+import com.oracle.graal.nodes.util.GraphUtil;
+import com.oracle.graal.phases.BasePhase;
+import com.oracle.graal.phases.common.CanonicalizerPhase;
+import com.oracle.graal.phases.common.FloatingReadPhase;
+import com.oracle.graal.phases.common.FrameStateAssignmentPhase;
+import com.oracle.graal.phases.common.GuardLoweringPhase;
+import com.oracle.graal.phases.common.LoweringPhase;
+import com.oracle.graal.phases.common.query.nodes.GraalQueryNode;
+import com.oracle.graal.phases.common.query.nodes.InstrumentationNode;
+import com.oracle.graal.phases.tiers.LowTierContext;
+
+public class InlineICGPhase extends BasePhase<LowTierContext> {
+
+    @Override
+    protected void run(StructuredGraph graph, LowTierContext context) {
+        // ICG may be shared amongst multiple InstrumentationNode
+        Set<StructuredGraph> icgs = new HashSet<>();
+        for (InstrumentationNode instrumentationNode : graph.getNodes().filter(InstrumentationNode.class)) {
+            icgs.add(instrumentationNode.icg());
+        }
+        for (StructuredGraph icg : icgs) {
+            new GuardLoweringPhase().apply(icg, null);
+            new FrameStateAssignmentPhase().apply(icg, false);
+            new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.LOW_TIER).apply(icg, context);
+            new FloatingReadPhase(true, true).apply(icg, false);
+
+            MemoryAnchorNode anchor = icg.add(new MemoryAnchorNode());
+            icg.start().replaceAtUsages(InputType.Memory, anchor);
+            if (anchor.hasNoUsages()) {
+                anchor.safeDelete();
+            } else {
+                icg.addAfterFixed(icg.start(), anchor);
+            }
+        }
+
+        for (InstrumentationNode instrumentationNode : graph.getNodes().filter(InstrumentationNode.class)) {
+            instrumentationNode.inlineAt(instrumentationNode);
+
+            for (GraalQueryNode query : graph.getNodes().filter(GraalQueryNode.class)) {
+                query.onInlineICG(instrumentationNode, instrumentationNode);
+            }
+
+            GraphUtil.unlinkFixedNode(instrumentationNode);
+            instrumentationNode.clearInputs();
+            GraphUtil.killCFG(instrumentationNode);
+        }
+
+        new CanonicalizerPhase().apply(graph, context);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/query/MidTierReconcileICGPhase.java	Wed Sep 30 11:38:20 2015 +0200
@@ -0,0 +1,56 @@
+/*
+ * 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.phases.common.query;
+
+import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.extended.FixedValueAnchorNode;
+import com.oracle.graal.nodes.java.AccessMonitorNode;
+import com.oracle.graal.nodes.util.GraphUtil;
+import com.oracle.graal.phases.Phase;
+import com.oracle.graal.phases.common.query.nodes.InstrumentationNode;
+import com.oracle.graal.phases.common.query.nodes.MonitorProxyNode;
+
+public class MidTierReconcileICGPhase extends Phase {
+
+    private static AccessMonitorNode unproxify(MonitorProxyNode proxy) {
+        for (AccessMonitorNode monitorEnter : proxy.getMonitorId().usages().filter(AccessMonitorNode.class)) {
+            if (monitorEnter.object() == proxy.target()) {
+                return monitorEnter;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        for (InstrumentationNode instrumentationNode : graph.getNodes().filter(InstrumentationNode.class)) {
+            ValueNode target = instrumentationNode.target();
+            if (target instanceof MonitorProxyNode) {
+                instrumentationNode.replaceFirstInput(target, unproxify((MonitorProxyNode) target));
+            } else if (target instanceof FixedValueAnchorNode) {
+                instrumentationNode.replaceFirstInput(target, GraphUtil.unproxify(target));
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/query/nodes/GraalQueryNode.java	Wed Sep 30 11:38:20 2015 +0200
@@ -0,0 +1,46 @@
+/*
+ * 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.phases.common.query.nodes;
+
+import com.oracle.graal.compiler.common.type.Stamp;
+import com.oracle.graal.graph.NodeClass;
+import com.oracle.graal.nodeinfo.NodeInfo;
+import com.oracle.graal.nodes.FixedNode;
+import com.oracle.graal.nodes.FixedWithNextNode;
+
+@NodeInfo
+public abstract class GraalQueryNode extends FixedWithNextNode {
+
+    public static final NodeClass<GraalQueryNode> TYPE = NodeClass.create(GraalQueryNode.class);
+
+    public GraalQueryNode(NodeClass<? extends FixedWithNextNode> c, Stamp stamp) {
+        super(c, stamp);
+    }
+
+    public void onExtractICG(@SuppressWarnings("unused") InstrumentationNode instrumentation) {
+    }
+
+    public void onInlineICG(@SuppressWarnings("unused") InstrumentationNode instrumentation, @SuppressWarnings("unused") FixedNode position) {
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/query/nodes/InstrumentationBeginNode.java	Wed Sep 30 11:38:20 2015 +0200
@@ -0,0 +1,55 @@
+/*
+ * 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.phases.common.query.nodes;
+
+import com.oracle.graal.compiler.common.type.StampFactory;
+import com.oracle.graal.graph.NodeClass;
+import com.oracle.graal.nodeinfo.NodeInfo;
+import com.oracle.graal.nodes.FixedWithNextNode;
+
+@NodeInfo
+public final class InstrumentationBeginNode extends FixedWithNextNode {
+
+    public static final NodeClass<InstrumentationBeginNode> TYPE = NodeClass.create(InstrumentationBeginNode.class);
+
+    protected final int offset;
+    protected final int type;
+
+    public InstrumentationBeginNode(int offset, int type) {
+        super(TYPE, StampFactory.forVoid());
+        this.offset = offset;
+        this.type = type;
+    }
+
+    public int getOffset() {
+        return offset;
+    }
+
+    public int getType() {
+        return type;
+    }
+
+    @NodeIntrinsic
+    public static native void instantiate(@ConstantNodeParameter int offset, @ConstantNodeParameter int type);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/query/nodes/InstrumentationEndNode.java	Wed Sep 30 11:38:20 2015 +0200
@@ -0,0 +1,42 @@
+/*
+ * 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.phases.common.query.nodes;
+
+import com.oracle.graal.compiler.common.type.StampFactory;
+import com.oracle.graal.graph.NodeClass;
+import com.oracle.graal.nodeinfo.NodeInfo;
+import com.oracle.graal.nodes.FixedWithNextNode;
+
+@NodeInfo
+public final class InstrumentationEndNode extends FixedWithNextNode {
+
+    public static final NodeClass<InstrumentationEndNode> TYPE = NodeClass.create(InstrumentationEndNode.class);
+
+    public InstrumentationEndNode() {
+        super(TYPE, StampFactory.forVoid());
+    }
+
+    @NodeIntrinsic
+    public static native void instantiate();
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/query/nodes/InstrumentationNode.java	Wed Sep 30 11:38:20 2015 +0200
@@ -0,0 +1,195 @@
+/*
+ * 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.phases.common.query.nodes;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Map;
+
+import jdk.internal.jvmci.meta.JavaConstant;
+import jdk.internal.jvmci.meta.JavaKind;
+
+import com.oracle.graal.compiler.common.type.StampFactory;
+import com.oracle.graal.graph.Graph.DuplicationReplacement;
+import com.oracle.graal.graph.Node;
+import com.oracle.graal.graph.NodeClass;
+import com.oracle.graal.graph.NodeInputList;
+import com.oracle.graal.nodeinfo.InputType;
+import com.oracle.graal.nodeinfo.NodeInfo;
+import com.oracle.graal.nodes.AbstractBeginNode;
+import com.oracle.graal.nodes.AbstractMergeNode;
+import com.oracle.graal.nodes.ConstantNode;
+import com.oracle.graal.nodes.EndNode;
+import com.oracle.graal.nodes.FixedNode;
+import com.oracle.graal.nodes.FixedWithNextNode;
+import com.oracle.graal.nodes.FrameState;
+import com.oracle.graal.nodes.MergeNode;
+import com.oracle.graal.nodes.ParameterNode;
+import com.oracle.graal.nodes.ReturnNode;
+import com.oracle.graal.nodes.StartNode;
+import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
+import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.spi.Virtualizable;
+import com.oracle.graal.nodes.spi.VirtualizerTool;
+import com.oracle.graal.nodes.virtual.EscapeObjectState;
+import com.oracle.graal.nodes.virtual.VirtualObjectNode;
+
+@NodeInfo
+public class InstrumentationNode extends FixedWithNextNode implements Virtualizable {
+
+    public static final NodeClass<InstrumentationNode> TYPE = NodeClass.create(InstrumentationNode.class);
+
+    @OptionalInput(value = InputType.Association) protected ValueNode target;
+    @OptionalInput protected NodeInputList<ValueNode> weakDependencies;
+
+    protected StructuredGraph icg;
+    protected final int offset;
+    protected final int type;
+
+    public InstrumentationNode(ValueNode target, int offset, int type) {
+        super(TYPE, StampFactory.forVoid());
+
+        this.target = target;
+        this.icg = new StructuredGraph(AllowAssumptions.YES);
+        this.offset = offset;
+        this.type = type;
+
+        this.weakDependencies = new NodeInputList<>(this);
+    }
+
+    public boolean addInput(Node node) {
+        return weakDependencies.add(node);
+    }
+
+    public ValueNode target() {
+        return target;
+    }
+
+    public StructuredGraph icg() {
+        return icg;
+    }
+
+    public int offset() {
+        return offset;
+    }
+
+    public int type() {
+        return type;
+    }
+
+    public NodeInputList<ValueNode> getWeakDependencies() {
+        return weakDependencies;
+    }
+
+    public void virtualize(VirtualizerTool tool) {
+        // InstrumentationNode allows non-materialized inputs. During the inlining of the
+        // InstrumentationNode, non-materialized inputs will be replaced by null.
+        if (target != null) {
+            ValueNode alias = tool.getAlias(target);
+            if (alias instanceof VirtualObjectNode) {
+                tool.replaceFirstInput(target, alias);
+            }
+        }
+        for (ValueNode input : weakDependencies) {
+            ValueNode alias = tool.getAlias(input);
+            if (alias instanceof VirtualObjectNode) {
+                tool.replaceFirstInput(input, alias);
+            }
+        }
+    }
+
+    public void inlineAt(FixedNode position) {
+        ArrayList<Node> nodes = new ArrayList<>(icg.getNodes().count());
+        final StartNode entryPointNode = icg.start();
+        FixedNode firstCFGNode = entryPointNode.next();
+        ArrayList<ReturnNode> returnNodes = new ArrayList<>(4);
+
+        for (Node icgnode : icg.getNodes()) {
+            if (icgnode == entryPointNode || icgnode == entryPointNode.stateAfter() || icgnode instanceof ParameterNode) {
+                // Do nothing.
+            } else {
+                nodes.add(icgnode);
+                if (icgnode instanceof ReturnNode) {
+                    returnNodes.add((ReturnNode) icgnode);
+                }
+            }
+        }
+
+        final AbstractBeginNode prevBegin = AbstractBeginNode.prevBegin(position);
+        DuplicationReplacement localReplacement = new DuplicationReplacement() {
+
+            public Node replacement(Node replacement) {
+                if (replacement instanceof ParameterNode) {
+                    ValueNode value = getWeakDependencies().get(((ParameterNode) replacement).index());
+                    if (value == null || value.isDeleted() || value instanceof VirtualObjectNode || value.stamp().getStackKind() != JavaKind.Object) {
+                        return graph().unique(new ConstantNode(JavaConstant.NULL_POINTER, ((ParameterNode) replacement).stamp()));
+                    } else {
+                        return value;
+                    }
+                } else if (replacement == entryPointNode) {
+                    return prevBegin;
+                }
+                return replacement;
+            }
+
+        };
+
+        Map<Node, Node> duplicates = graph().addDuplicates(nodes, icg, icg.getNodeCount(), localReplacement);
+        FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode);
+        position.replaceAtPredecessor(firstCFGNodeDuplicate);
+
+        if (!returnNodes.isEmpty()) {
+            if (returnNodes.size() == 1) {
+                ReturnNode returnNode = (ReturnNode) duplicates.get(returnNodes.get(0));
+                returnNode.replaceAndDelete(position);
+            } else {
+                ArrayList<ReturnNode> returnDuplicates = new ArrayList<>(returnNodes.size());
+                for (ReturnNode returnNode : returnNodes) {
+                    returnDuplicates.add((ReturnNode) duplicates.get(returnNode));
+                }
+                AbstractMergeNode merge = graph().add(new MergeNode());
+
+                for (ReturnNode returnNode : returnDuplicates) {
+                    EndNode endNode = graph().add(new EndNode());
+                    merge.addForwardEnd(endNode);
+                    returnNode.replaceAndDelete(endNode);
+                }
+
+                merge.setNext(position);
+            }
+        }
+
+        // since we may relocate InstrumentationNodes, the FrameState can be invalid
+        for (Node replacee : duplicates.values()) {
+            if (replacee instanceof FrameState) {
+                FrameState oldState = (FrameState) replacee;
+                FrameState newState = new FrameState(null, oldState.method(), oldState.bci, 0, 0, 0, oldState.rethrowException(), oldState.duringCall(), null,
+                                Collections.<EscapeObjectState> emptyList());
+                graph().addWithoutUnique(newState);
+                oldState.replaceAtUsages(newState);
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/query/nodes/MonitorProxyNode.java	Wed Sep 30 11:38:20 2015 +0200
@@ -0,0 +1,55 @@
+/*
+ * 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.phases.common.query.nodes;
+
+import com.oracle.graal.compiler.common.type.StampFactory;
+import com.oracle.graal.graph.NodeClass;
+import com.oracle.graal.nodeinfo.InputType;
+import com.oracle.graal.nodeinfo.NodeInfo;
+import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.java.MonitorIdNode;
+
+@NodeInfo
+public class MonitorProxyNode extends ValueNode {
+
+    public static final NodeClass<MonitorProxyNode> TYPE = NodeClass.create(MonitorProxyNode.class);
+
+    @OptionalInput(value = InputType.Association) protected ValueNode target;
+    @OptionalInput(value = InputType.Association) protected MonitorIdNode monitorId;
+
+    public MonitorProxyNode(ValueNode target, MonitorIdNode monitorId) {
+        super(TYPE, StampFactory.forVoid());
+
+        this.target = target;
+        this.monitorId = monitorId;
+    }
+
+    public ValueNode target() {
+        return target;
+    }
+
+    public MonitorIdNode getMonitorId() {
+        return monitorId;
+    }
+
+}
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Tue Sep 29 22:19:45 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Wed Sep 30 11:38:20 2015 +0200
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.replacements;
 
+import static com.oracle.graal.compiler.common.GraalOptions.UseGraalQueries;
 import static com.oracle.graal.debug.Debug.applyFormattingFlagsAndWidth;
 import static com.oracle.graal.phases.common.DeadCodeEliminationPhase.Optionality.Required;
 import static com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates.UseSnippetTemplateCache;
@@ -117,6 +118,7 @@
 import com.oracle.graal.phases.common.GuardLoweringPhase;
 import com.oracle.graal.phases.common.LoweringPhase;
 import com.oracle.graal.phases.common.inlining.InliningUtil;
+import com.oracle.graal.phases.common.query.nodes.InstrumentationNode;
 import com.oracle.graal.phases.tiers.PhaseContext;
 import com.oracle.graal.phases.util.Providers;
 import com.oracle.graal.replacements.Snippet.ConstantParameter;
@@ -1336,6 +1338,20 @@
 
             updateStamps(replacee, duplicates);
 
+            if (UseGraalQueries.getValue()) {
+                for (InstrumentationNode instrumentation : replaceeGraph.getNodes().filter(InstrumentationNode.class)) {
+                    if (instrumentation.target() == replacee) {
+                        if (instrumentation.offset() < 0) {
+                            ReturnNode returnDuplicate = (ReturnNode) duplicates.get(returnNode);
+                            FixedWithNextNode pred = (FixedWithNextNode) returnDuplicate.predecessor();
+                            instrumentation.replaceFirstInput(replacee, pred);
+                        } else {
+                            instrumentation.replaceFirstInput(replacee, firstCFGNodeDuplicate);
+                        }
+                    }
+                }
+            }
+
             rewireMemoryGraph(replacee, duplicates);
 
             // Replace all usages of the replacee with the value returned by the snippet
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Tue Sep 29 22:19:45 2015 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Wed Sep 30 11:38:20 2015 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.virtual.phases.ea;
 
+import static com.oracle.graal.compiler.common.GraalOptions.UseGraalQueries;
+
 import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -71,6 +73,7 @@
 import com.oracle.graal.nodes.spi.VirtualizableAllocation;
 import com.oracle.graal.nodes.spi.VirtualizerTool;
 import com.oracle.graal.nodes.virtual.VirtualObjectNode;
+import com.oracle.graal.phases.common.query.nodes.InstrumentationNode;
 import com.oracle.graal.phases.schedule.SchedulePhase;
 
 public abstract class PartialEscapeClosure<BlockT extends PartialEscapeBlockState<BlockT>> extends EffectsClosure<BlockT> {
@@ -187,6 +190,10 @@
                     return true;
                 }
             }
+            if (UseGraalQueries.getValue() && (node instanceof InstrumentationNode)) {
+                // ignore inputs for InstrumentationNode
+                return false;
+            }
             processNodeInputs((ValueNode) node, nextFixedNode, state, effects);
         }