# HG changeset patch # User Lukas Stadler # Date 1352296332 -3600 # Node ID 3dddb311395f25fe8ddf70e6a1ba9b6e9a263961 # Parent 090868cbcda667abab4f7b5a53255fbc58cf10f9 hotspot infrastructure for OnStackReplacement diff -r 090868cbcda6 -r 3dddb311395f graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java --- 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 withinCompilation = new ThreadLocal() { + @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"); } diff -r 090868cbcda6 -r 3dddb311395f graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompiler.java --- 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); } diff -r 090868cbcda6 -r 3dddb311395f graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java --- 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); } diff -r 090868cbcda6 -r 3dddb311395f graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java --- 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), diff -r 090868cbcda6 -r 3dddb311395f graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java --- /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 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); + } +}