changeset 6677:3dddb311395f

hotspot infrastructure for OnStackReplacement
author Lukas Stadler <lukas.stadler@jku.at>
date Wed, 07 Nov 2012 14:52:12 +0100
parents 090868cbcda6
children e75c3dd32c5b
files graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompiler.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java
diffstat 5 files changed, 178 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Wed Nov 07 14:14:35 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Wed Nov 07 14:52:12 2012 +0100
@@ -42,27 +42,38 @@
         }
     };
 
+    public static final ThreadLocal<Long> withinCompilation = new ThreadLocal<Long>() {
+        @Override
+        protected Long initialValue() {
+            return 0L;
+        }
+    };
+
 
     private volatile boolean cancelled;
 
     private final HotSpotGraalRuntime graalRuntime;
     private final PhasePlan plan;
+    private final OptimisticOptimizations optimisticOpts;
     private final HotSpotResolvedJavaMethod method;
-    private final OptimisticOptimizations optimisticOpts;
+    private final int entryBCI;
     private final int id;
     private final int priority;
+    private final Runnable callback;
 
-    public static CompilationTask create(HotSpotGraalRuntime graalRuntime, PhasePlan plan, OptimisticOptimizations optimisticOpts, HotSpotResolvedJavaMethod method, int id, int priority) {
-        return new CompilationTask(graalRuntime, plan, optimisticOpts, method, id, priority);
+    public static CompilationTask create(HotSpotGraalRuntime graalRuntime, PhasePlan plan, OptimisticOptimizations optimisticOpts, HotSpotResolvedJavaMethod method, int entryBCI, int id, int priority, Runnable callback) {
+        return new CompilationTask(graalRuntime, plan, optimisticOpts, method, entryBCI, id, priority, callback);
     }
 
-    private CompilationTask(HotSpotGraalRuntime graalRuntime, PhasePlan plan, OptimisticOptimizations optimisticOpts, HotSpotResolvedJavaMethod method, int id, int priority) {
+    private CompilationTask(HotSpotGraalRuntime graalRuntime, PhasePlan plan, OptimisticOptimizations optimisticOpts, HotSpotResolvedJavaMethod method, int entryBCI, int id, int priority, Runnable callback) {
         this.graalRuntime = graalRuntime;
         this.plan = plan;
         this.method = method;
         this.optimisticOpts = optimisticOpts;
+        this.entryBCI = entryBCI;
         this.id = id;
         this.priority = priority;
+        this.callback = callback;
     }
 
     public ResolvedJavaMethod method() {
@@ -90,7 +101,7 @@
                 }
             }
             runCompilation();
-            if (method.currentTask() == this) {
+            if (method.currentTask() == this && entryBCI == StructuredGraph.INVOCATION_ENTRY_BCI) {
                 method.setCurrentTask(null);
             }
         } finally {
@@ -99,6 +110,7 @@
     }
 
     public void runCompilation() {
+        withinCompilation.set(withinCompilation.get() + 1);
         CompilationStatistics stats = CompilationStatistics.create(method);
         try {
             final boolean printCompilation = GraalOptions.PrintCompilation && !TTY.isSuppressed();
@@ -143,6 +155,10 @@
             }
         }
         stats.finish(method);
+        if (callback != null) {
+            callback.run();
+        }
+        withinCompilation.set(withinCompilation.get() - 1);
     }
 
     private void installMethod(final CompilationResult tm) {
@@ -150,7 +166,7 @@
             @Override
             public void run() {
                 final CodeInfo[] info = Debug.isDumpEnabled() ? new CodeInfo[1] : null;
-                graalRuntime.getRuntime().installMethod(method, -1, tm, info);
+                graalRuntime.getRuntime().installMethod(method, entryBCI, tm, info);
                 if (info != null) {
                     Debug.dump(new Object[] {tm, info[0]}, "After code installation");
                 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompiler.java	Wed Nov 07 14:14:35 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompiler.java	Wed Nov 07 14:52:12 2012 +0100
@@ -27,7 +27,6 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.phases.*;
 
 /**
  * Calls from HotSpot into Java.
@@ -61,6 +60,4 @@
     Constant createConstantDouble(double value);
 
     Constant createConstantObject(Object object);
-
-    PhasePlan createPhasePlan(OptimisticOptimizations optimisticOpts);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Wed Nov 07 14:14:35 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Wed Nov 07 14:52:12 2012 +0100
@@ -35,10 +35,12 @@
 import com.oracle.graal.debug.internal.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.phases.*;
 import com.oracle.graal.hotspot.snippets.*;
 import com.oracle.graal.java.*;
+import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.PhasePlan.*;
+import com.oracle.graal.phases.PhasePlan.PhasePosition;
 import com.oracle.graal.snippets.*;
 
 /**
@@ -223,7 +225,7 @@
     private void enqueue(Method m) throws Throwable {
         JavaMethod javaMethod = graalRuntime.getRuntime().lookupJavaMethod(m);
         assert !Modifier.isAbstract(((HotSpotResolvedJavaMethod) javaMethod).getModifiers()) && !Modifier.isNative(((HotSpotResolvedJavaMethod) javaMethod).getModifiers()) : javaMethod;
-        compileMethod((HotSpotResolvedJavaMethod) javaMethod, 0, false, 10);
+        compileMethod((HotSpotResolvedJavaMethod) javaMethod, StructuredGraph.INVOCATION_ENTRY_BCI, false, 10);
     }
 
     private static void shutdownCompileQueue(ThreadPoolExecutor queue) throws InterruptedException {
@@ -370,7 +372,7 @@
 
             final OptimisticOptimizations optimisticOpts = new OptimisticOptimizations(method);
             int id = compileTaskIds.incrementAndGet();
-            CompilationTask task = CompilationTask.create(graalRuntime, createPhasePlan(optimisticOpts), optimisticOpts, method, id, priority);
+            CompilationTask task = CompilationTask.create(graalRuntime, createPhasePlan(optimisticOpts, false), optimisticOpts, method, StructuredGraph.INVOCATION_ENTRY_BCI, id, priority, null);
             if (blocking) {
                 task.runCompilation();
             } else {
@@ -386,6 +388,22 @@
                     return false;
                 }
             }
+            if (entryBCI != StructuredGraph.INVOCATION_ENTRY_BCI && CompilationTask.withinCompilation.get() == 0) {
+                assert !blocking;
+                final OptimisticOptimizations osrOptimisticOpts = new OptimisticOptimizations(method);
+                int osrId = compileTaskIds.incrementAndGet();
+                Debug.log("OSR compilation %s@%d", method, entryBCI);
+                final CountDownLatch latch = new CountDownLatch(1);
+                Runnable callback = new Runnable() {
+                    @Override
+                    public void run() {
+                        latch.countDown();
+                    }
+                };
+                CompilationTask osrTask = CompilationTask.create(graalRuntime, createPhasePlan(osrOptimisticOpts, true), osrOptimisticOpts, method, entryBCI, osrId, Integer.MAX_VALUE, callback);
+                compileQueue.execute(osrTask);
+                latch.await();
+            }
             return true;
         } finally {
             CompilationTask.withinEnqueue.set(Boolean.FALSE);
@@ -476,11 +494,12 @@
         return Constant.forObject(object);
     }
 
-
-    public PhasePlan createPhasePlan(OptimisticOptimizations optimisticOpts) {
+    public PhasePlan createPhasePlan(OptimisticOptimizations optimisticOpts, boolean onStackReplacement) {
         PhasePlan phasePlan = new PhasePlan();
-        GraphBuilderPhase graphBuilderPhase = new GraphBuilderPhase(graalRuntime.getRuntime(), GraphBuilderConfiguration.getDefault(), optimisticOpts);
-        phasePlan.addPhase(PhasePosition.AFTER_PARSING, graphBuilderPhase);
+        phasePlan.addPhase(PhasePosition.AFTER_PARSING, new GraphBuilderPhase(graalRuntime.getRuntime(), GraphBuilderConfiguration.getDefault(), optimisticOpts));
+        if (onStackReplacement) {
+            phasePlan.addPhase(PhasePosition.AFTER_PARSING, new OnStackReplacementPhase());
+        }
         if (GraalOptions.Intrinsify) {
             phasePlan.addPhase(PhasePosition.HIGH_LEVEL, intrinsifyArrayCopy);
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Wed Nov 07 14:14:35 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Wed Nov 07 14:52:12 2012 +0100
@@ -47,6 +47,7 @@
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.bridge.*;
 import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.hotspot.phases.*;
 import com.oracle.graal.hotspot.snippets.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
@@ -104,6 +105,11 @@
                         /*             ret */ ret(Kind.Void),
                         /* arg0: exception */ arg(0, Kind.Object));
 
+        addRuntimeCall(OnStackReplacementPhase.OSR_MIGRATION_END, config.osrMigrationEndStub,
+                        /*           temps */ null,
+                        /*             ret */ ret(Kind.Void),
+                        /* arg0:      long */ arg(0, Kind.Long));
+
         addRuntimeCall(REGISTER_FINALIZER, config.registerFinalizerStub,
                         /*           temps */ null,
                         /*             ret */ ret(Kind.Void),
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java	Wed Nov 07 14:52:12 2012 +0100
@@ -0,0 +1,124 @@
+/*
+ * 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.hotspot.phases;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.code.RuntimeCall.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.iterators.*;
+import com.oracle.graal.loop.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.util.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.common.*;
+
+public class OnStackReplacementPhase extends Phase {
+
+    public static final Descriptor OSR_MIGRATION_END = new Descriptor("OSR_migration_end", true, Kind.Void, Kind.Long);
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        Debug.dump(graph, "OnStackReplacement initial");
+        EntryMarkerNode osr;
+        do {
+            NodeIterable<EntryMarkerNode> osrNodes = graph.getNodes(EntryMarkerNode.class);
+            osr = osrNodes.first();
+            if (osr == null) {
+                System.out.println("no OnStackReplacementNode generated");
+                throw new BailoutException("no OnStackReplacementNode generated");
+            }
+            if (osrNodes.count() > 1) {
+                throw new GraalInternalError("multiple OnStackReplacementNodes generated");
+            }
+            if (osr.stateAfter().locksSize() != 0) {
+                System.out.println("osr with locks not supported");
+                throw new BailoutException("osr with locks not supported");
+            }
+            if (osr.stateAfter().stackSize() != 0) {
+                throw new GraalInternalError("osr with stack entries not supported");
+            }
+            LoopEx osrLoop = null;
+            LoopsData loops = new LoopsData(graph);
+            for (LoopEx loop : loops.loops()) {
+                if (loop.inside().contains(osr)) {
+                    osrLoop = loop;
+                    break;
+                }
+            }
+            if (osrLoop == null) {
+                break;
+            }
+
+            LoopTransformations.peel(osrLoop);
+            for (Node usage : osr.usages().snapshot()) {
+                ValueProxyNode proxy = (ValueProxyNode) usage;
+                proxy.replaceAndDelete(proxy.value());
+            }
+            FixedNode next = osr.next();
+            osr.setNext(null);
+            ((FixedWithNextNode) osr.predecessor()).setNext(next);
+            GraphUtil.killWithUnusedFloatingInputs(osr);
+            Debug.dump(graph, "OnStackReplacement loop peeling result");
+        } while (true);
+
+
+        LocalNode buffer = graph.unique(new LocalNode(0, StampFactory.forKind(Kind.Long)));
+        RuntimeCallNode migrationEnd = graph.add(new RuntimeCallNode(OSR_MIGRATION_END, buffer));
+        FrameState osrState = osr.stateAfter();
+        migrationEnd.setStateAfter(osrState);
+        osr.setStateAfter(null);
+
+        StartNode start = graph.start();
+        FixedNode rest = start.next();
+        start.setNext(migrationEnd);
+        FixedNode next = osr.next();
+        osr.setNext(null);
+        migrationEnd.setNext(next);
+
+        FrameState oldStartState = start.stateAfter();
+        start.setStateAfter(null);
+        GraphUtil.killWithUnusedFloatingInputs(oldStartState);
+
+        int localsOffset = (graph.method().getMaxLocals() - 1) * 8;
+        for (int i = 0; i < osrState.localsSize(); i++) {
+            ValueNode value = osrState.localAt(i);
+            if (value != null) {
+                ValueProxyNode proxy = (ValueProxyNode) value;
+                int size = (value.kind() == Kind.Long || value.kind() == Kind.Double) ? 2 : 1;
+                int offset = localsOffset - (i + size - 1) * 8;
+                UnsafeLoadNode load = graph.add(new UnsafeLoadNode(buffer, offset, ConstantNode.forInt(0, graph), value.kind()));
+                proxy.replaceAndDelete(load);
+                graph.addBeforeFixed(migrationEnd, load);
+            }
+        }
+
+        GraphUtil.killCFG(rest);
+
+        Debug.dump(graph, "OnStackReplacement result");
+        new DeadCodeEliminationPhase().apply(graph);
+    }
+}