changeset 19903:d15769a7e444

Merge.
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Tue, 17 Mar 2015 17:16:04 +0100
parents d66d53b6b73c (diff) 706252994ee6 (current diff)
children 15ef790fec92 842918052c50 bcfca701c935
files graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderConfiguration.java graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderContext.java graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java graal/com.oracle.graal.java/src/com/oracle/graal/java/InvocationPlugins.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java
diffstat 8 files changed, 353 insertions(+), 29 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java	Tue Mar 17 15:52:41 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java	Tue Mar 17 17:16:04 2015 +0100
@@ -282,9 +282,42 @@
     }
 
     /**
+     * Here the read should not float out of the loop.
+     */
+    public static int testLoop7Snippet(int a, int b, MemoryScheduleTest obj) {
+        int ret = 0;
+        int bb = b;
+        for (int i = 0; i < a; i++) {
+            ret = obj.hash;
+            if (a > 10) {
+                bb++;
+            } else {
+                bb--;
+                for (int k = 0; k < a; ++k) {
+                    if (k % 2 == 1) {
+                        for (int j = 0; j < b; ++j) {
+                            obj.hash = 3;
+                        }
+                    }
+                }
+            }
+            ret = ret / 10;
+        }
+        return ret + bb;
+    }
+
+    @Test
+    public void testLoop7() {
+        SchedulePhase schedule = getFinalSchedule("testLoop7Snippet", TestMode.WITHOUT_FRAMESTATES);
+        assertDeepEquals(18, schedule.getCFG().getBlocks().size());
+        assertReadWithinStartBlock(schedule, false);
+        assertReadWithinAllReturnBlocks(schedule, false);
+    }
+
+    /**
      * Here the read should not float to the end.
      */
-    public static int testLoop7Snippet(int a, int b) {
+    public static int testLoop8Snippet(int a, int b) {
         int result = container.a;
         for (int i = 0; i < a; i++) {
             if (b < 0) {
@@ -301,8 +334,8 @@
     }
 
     @Test
-    public void testLoop7() {
-        SchedulePhase schedule = getFinalSchedule("testLoop7Snippet", TestMode.WITHOUT_FRAMESTATES);
+    public void testLoop8() {
+        SchedulePhase schedule = getFinalSchedule("testLoop8Snippet", TestMode.WITHOUT_FRAMESTATES);
         assertDeepEquals(10, schedule.getCFG().getBlocks().size());
         assertReadWithinStartBlock(schedule, true);
         assertReadWithinAllReturnBlocks(schedule, false);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SchedulingTest2.java	Tue Mar 17 17:16:04 2015 +0100
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.test;
+
+import java.util.*;
+
+import org.junit.*;
+
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.DeoptimizingNode.DeoptDuring;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.cfg.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.schedule.*;
+import com.oracle.graal.phases.schedule.SchedulePhase.SchedulingStrategy;
+import com.oracle.graal.phases.tiers.*;
+
+public class SchedulingTest2 extends GraphScheduleTest {
+
+    public static int testSnippet() {
+        return test() + 2;
+    }
+
+    public static int test() {
+        return 40;
+    }
+
+    @Test
+    public void testValueProxyInputs() {
+        StructuredGraph graph = parseEager("testSnippet", AllowAssumptions.YES);
+        ReturnNode returnNode = graph.getNodes(ReturnNode.TYPE).first();
+        BeginNode beginNode = graph.add(new BeginNode());
+        returnNode.replaceAtPredecessor(beginNode);
+        beginNode.setNext(returnNode);
+        Debug.dump(graph, "Graph");
+        SchedulePhase schedule = new SchedulePhase(SchedulingStrategy.EARLIEST);
+        schedule.apply(graph);
+        BlockMap<List<Node>> blockToNodesMap = schedule.getBlockToNodesMap();
+        NodeMap<Block> nodeToBlock = schedule.getNodeToBlockMap();
+        assertDeepEquals(2, schedule.getCFG().getBlocks().size());
+        for (BinaryArithmeticNode<?> node : graph.getNodes().filter(BinaryArithmeticNode.class)) {
+            if (node instanceof AddNode) {
+                assertTrue(node.toString() + " expected: " + nodeToBlock.get(beginNode) + " but was: " + nodeToBlock.get(node), nodeToBlock.get(node) == nodeToBlock.get(beginNode));
+            }
+        }
+
+        for (FrameState fs : graph.getNodes(FrameState.TYPE)) {
+            Block block = nodeToBlock.get(fs);
+            assertTrue(fs.toString(), block == schedule.getCFG().getStartBlock());
+            for (Node usage : fs.usages()) {
+                if (usage instanceof StateSplit && ((StateSplit) usage).stateAfter() == fs) {
+                    assertTrue(usage.toString(), nodeToBlock.get(usage) == block);
+                    if (usage != block.getBeginNode()) {
+                        List<Node> map = blockToNodesMap.get(block);
+                        assertTrue(map.indexOf(fs) + " < " + map.indexOf(usage), map.indexOf(fs) < map.indexOf(usage));
+                    }
+                }
+            }
+        }
+
+        PhaseContext context = new PhaseContext(getProviders());
+        new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+        new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, context);
+        MidTierContext midContext = new MidTierContext(getProviders(), getCodeCache().getTarget(), OptimisticOptimizations.ALL, graph.method().getProfilingInfo(), null);
+
+        new GuardLoweringPhase().apply(graph, midContext);
+        FrameStateAssignmentPhase phase = new FrameStateAssignmentPhase();
+        phase.apply(graph);
+
+        schedule = new SchedulePhase(SchedulingStrategy.EARLIEST);
+        schedule.apply(graph);
+        blockToNodesMap = schedule.getBlockToNodesMap();
+        nodeToBlock = schedule.getNodeToBlockMap();
+        for (FrameState fs : graph.getNodes(FrameState.TYPE)) {
+            Block block = nodeToBlock.get(fs);
+            assertTrue(fs.toString(), block == schedule.getCFG().getStartBlock());
+            for (Node usage : fs.usages()) {
+                if ((usage instanceof StateSplit && ((StateSplit) usage).stateAfter() == fs) || (usage instanceof DeoptDuring && ((DeoptDuring) usage).stateDuring() == fs)) {
+                    assertTrue(usage.toString(), nodeToBlock.get(usage) == block);
+                    if (usage != block.getBeginNode()) {
+                        List<Node> map = blockToNodesMap.get(block);
+                        assertTrue(map.indexOf(fs) + " < " + map.indexOf(usage), map.indexOf(fs) < map.indexOf(usage));
+                    }
+                }
+            }
+        }
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java	Tue Mar 17 15:52:41 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java	Tue Mar 17 17:16:04 2015 +0100
@@ -237,15 +237,21 @@
         if (this.killLocationsBetweenThisAndDominator == null) {
             LocationSet dominatorResult = new LocationSet();
             Block stopBlock = getDominator();
-            for (Block b : this.getPredecessors()) {
-                if (b != stopBlock && (!this.isLoopHeader() || b.getLoopDepth() < this.getLoopDepth())) {
-                    dominatorResult.addAll(b.getKillLocations());
-                    if (dominatorResult.isAny()) {
-                        break;
-                    }
-                    b.calcKillLocationsBetweenThisAndTarget(dominatorResult, stopBlock);
-                    if (dominatorResult.isAny()) {
-                        break;
+            if (this.isLoopHeader()) {
+                assert stopBlock.getLoopDepth() < this.getLoopDepth();
+                dominatorResult.addAll(((HIRLoop) this.getLoop()).getKillLocations());
+            } else {
+                for (Block b : this.getPredecessors()) {
+                    assert !this.isLoopHeader();
+                    if (b != stopBlock) {
+                        dominatorResult.addAll(b.getKillLocations());
+                        if (dominatorResult.isAny()) {
+                            break;
+                        }
+                        b.calcKillLocationsBetweenThisAndTarget(dominatorResult, stopBlock);
+                        if (dominatorResult.isAny()) {
+                            break;
+                        }
                     }
                 }
             }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/HIRLoop.java	Tue Mar 17 15:52:41 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/HIRLoop.java	Tue Mar 17 17:16:04 2015 +0100
@@ -39,7 +39,7 @@
         return ((LoopBeginNode) getHeader().getBeginNode()).loopEnds().count();
     }
 
-    private LocationSet getKillLocations() {
+    public LocationSet getKillLocations() {
         if (killLocations == null) {
             killLocations = new LocationSet();
             for (Block b : this.getBlocks()) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/MemoryScheduleVerification.java	Tue Mar 17 17:16:04 2015 +0100
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.schedule;
+
+import java.util.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.graph.Node;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.cfg.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.phases.graph.*;
+import com.oracle.graal.phases.graph.ReentrantBlockIterator.BlockIteratorClosure;
+
+public final class MemoryScheduleVerification extends BlockIteratorClosure<Set<FloatingReadNode>> {
+
+    private final BlockMap<List<Node>> blockToNodesMap;
+
+    public static boolean check(Block startBlock, BlockMap<List<Node>> blockToNodesMap) {
+        ReentrantBlockIterator.apply(new MemoryScheduleVerification(blockToNodesMap), startBlock);
+        return true;
+    }
+
+    private MemoryScheduleVerification(BlockMap<List<Node>> blockToNodesMap) {
+        this.blockToNodesMap = blockToNodesMap;
+    }
+
+    @Override
+    protected Set<FloatingReadNode> getInitialState() {
+        return CollectionsFactory.newSet();
+    }
+
+    @Override
+    protected Set<FloatingReadNode> processBlock(Block block, Set<FloatingReadNode> currentState) {
+        for (Node n : blockToNodesMap.get(block)) {
+            if (n instanceof AbstractMergeNode) {
+                AbstractMergeNode abstractMergeNode = (AbstractMergeNode) n;
+                for (PhiNode phi : abstractMergeNode.phis()) {
+                    if (phi instanceof MemoryPhiNode) {
+                        MemoryPhiNode memoryPhiNode = (MemoryPhiNode) phi;
+                        addFloatingReadUsages(currentState, memoryPhiNode);
+                    }
+                }
+
+            }
+
+            if (n instanceof MemoryCheckpoint) {
+                if (n instanceof MemoryCheckpoint.Single) {
+                    MemoryCheckpoint.Single single = (MemoryCheckpoint.Single) n;
+                    processLocation(n, single.getLocationIdentity(), currentState);
+                } else if (n instanceof MemoryCheckpoint.Multi) {
+                    MemoryCheckpoint.Multi multi = (MemoryCheckpoint.Multi) n;
+                    for (LocationIdentity location : multi.getLocationIdentities()) {
+                        processLocation(n, location, currentState);
+                    }
+                }
+
+                addFloatingReadUsages(currentState, n);
+            } else if (n instanceof FloatingReadNode) {
+                FloatingReadNode floatingReadNode = (FloatingReadNode) n;
+                if (floatingReadNode.getLastLocationAccess() != null && floatingReadNode.getLocationIdentity().isMutable()) {
+                    if (currentState.contains(floatingReadNode)) {
+                        // Floating read was found in the state.
+                        currentState.remove(floatingReadNode);
+                    } else {
+                        throw new RuntimeException("Floating read node " + n + " was not found in the state, i.e., it was killed by a memory check point before its place in the schedule");
+                    }
+                }
+
+            }
+        }
+        return currentState;
+    }
+
+    private static void addFloatingReadUsages(Set<FloatingReadNode> currentState, Node n) {
+        for (FloatingReadNode read : n.usages().filter(FloatingReadNode.class)) {
+            if (read.getLastLocationAccess() == n && read.getLocationIdentity().isMutable()) {
+                currentState.add(read);
+            }
+        }
+    }
+
+    private void processLocation(Node n, LocationIdentity location, Set<FloatingReadNode> currentState) {
+        assert n != null;
+        if (location.isImmutable()) {
+            return;
+        }
+
+        for (FloatingReadNode r : cloneState(currentState)) {
+            if (r.getLocationIdentity().overlaps(location)) {
+                // This read is killed by this location.
+                currentState.remove(r);
+            }
+        }
+    }
+
+    @Override
+    protected Set<FloatingReadNode> merge(Block merge, List<Set<FloatingReadNode>> states) {
+        Set<FloatingReadNode> result = states.get(0);
+        for (int i = 1; i < states.size(); ++i) {
+            result.retainAll(states.get(i));
+        }
+        return result;
+    }
+
+    @Override
+    protected Set<FloatingReadNode> cloneState(Set<FloatingReadNode> oldState) {
+        Set<FloatingReadNode> result = CollectionsFactory.newSet();
+        result.addAll(oldState);
+        return result;
+    }
+
+    @Override
+    protected List<Set<FloatingReadNode>> processLoop(Loop<Block> loop, Set<FloatingReadNode> initialState) {
+        HIRLoop l = (HIRLoop) loop;
+        for (MemoryPhiNode memoryPhi : ((LoopBeginNode) l.getHeader().getBeginNode()).phis().filter(MemoryPhiNode.class)) {
+            for (FloatingReadNode r : cloneState(initialState)) {
+                if (r.getLocationIdentity().overlaps(memoryPhi.getLocationIdentity())) {
+                    initialState.remove(r);
+                }
+            }
+        }
+        return ReentrantBlockIterator.processLoop(this, loop, initialState).exitStates;
+    }
+}
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Tue Mar 17 15:52:41 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Tue Mar 17 17:16:04 2015 +0100
@@ -94,6 +94,7 @@
         cfg = ControlFlowGraph.compute(graph, true, true, true, false);
 
         if (selectedStrategy == SchedulingStrategy.EARLIEST) {
+            // Assign early so we are getting a context in case of an exception.
             this.nodeToBlockMap = graph.createNodeMap();
             this.blockToNodesMap = new BlockMap<>(cfg);
             NodeBitMap visited = graph.createNodeBitMap();
@@ -105,6 +106,11 @@
                 NodeMap<Block> currentNodeMap = graph.createNodeMap();
                 BlockMap<List<Node>> earliestBlockToNodesMap = new BlockMap<>(cfg);
                 NodeBitMap visited = graph.createNodeBitMap();
+
+                // Assign early so we are getting a context in case of an exception.
+                this.blockToNodesMap = earliestBlockToNodesMap;
+                this.nodeToBlockMap = currentNodeMap;
+
                 scheduleEarliestIterative(cfg, earliestBlockToNodesMap, currentNodeMap, visited, graph);
                 BlockMap<List<Node>> latestBlockToNodesMap = new BlockMap<>(cfg);
 
@@ -115,10 +121,12 @@
                 BlockMap<ArrayList<FloatingReadNode>> watchListMap = calcLatestBlocks(isOutOfLoops, currentNodeMap, earliestBlockToNodesMap, visited, latestBlockToNodesMap);
                 sortNodesLatestWithinBlock(cfg, earliestBlockToNodesMap, latestBlockToNodesMap, currentNodeMap, watchListMap, visited);
 
+                assert verifySchedule(cfg, latestBlockToNodesMap, currentNodeMap);
+                assert MemoryScheduleVerification.check(cfg.getStartBlock(), latestBlockToNodesMap);
+
                 this.blockToNodesMap = latestBlockToNodesMap;
                 this.nodeToBlockMap = currentNodeMap;
 
-                assert verifySchedule(cfg, latestBlockToNodesMap, currentNodeMap);
                 cfg.setNodeToBlock(currentNodeMap);
             }
         }
@@ -165,7 +173,7 @@
                                     // We are not constraint within currentBlock. Check if
                                     // we are contraint while walking down the dominator
                                     // line.
-                                    Block newLatestBlock = adjustLatestForRead(currentBlock, latestBlock, location);
+                                    Block newLatestBlock = adjustLatestForRead(floatingReadNode, currentBlock, latestBlock, location);
                                     assert dominates(newLatestBlock, latestBlock);
                                     assert dominates(currentBlock, newLatestBlock);
                                     latestBlock = newLatestBlock;
@@ -203,7 +211,7 @@
         return true;
     }
 
-    private static Block adjustLatestForRead(Block earliestBlock, Block latestBlock, LocationIdentity location) {
+    private static Block adjustLatestForRead(FloatingReadNode floatingReadNode, Block earliestBlock, Block latestBlock, LocationIdentity location) {
         assert strictlyDominates(earliestBlock, latestBlock);
         Block current = latestBlock.getDominator();
 
@@ -218,6 +226,7 @@
             }
             dominatorChain.add(current);
             current = current.getDominator();
+            assert current != null : floatingReadNode;
         }
 
         // The first element of dominatorChain now contains the latest possible block.
@@ -537,6 +546,8 @@
                 }
             }
         }
+
+        assert MemoryScheduleVerification.check(cfg.getStartBlock(), blockToNodes);
     }
 
     private static void resortEarliestWithinBlock(Block b, BlockMap<List<Node>> blockToNodes, NodeMap<Block> nodeToBlock, NodeBitMap unprocessed) {
@@ -550,7 +561,7 @@
                 MemoryNode lastLocationAccess = floatingReadNode.getLastLocationAccess();
                 if (locationIdentity.isMutable() && lastLocationAccess != null) {
                     ValueNode lastAccessLocation = lastLocationAccess.asNode();
-                    if (nodeToBlock.get(lastAccessLocation) == b && lastAccessLocation != beginNode) {
+                    if (nodeToBlock.get(lastAccessLocation) == b && lastAccessLocation != beginNode && !(lastAccessLocation instanceof MemoryPhiNode)) {
                         // This node's last access location is within this block. Add to watch list
                         // when processing the last access location.
                     } else {
@@ -650,16 +661,22 @@
                         assert current.predecessor() == null && !(current instanceof FixedNode) : "The assignment of blocks to fixed nodes is already done when constructing the cfg.";
                         Block earliest = startBlock;
                         for (Node input : current.inputs()) {
-                            Block inputEarliest;
-                            if (input instanceof ControlSplitNode) {
-                                inputEarliest = nodeToBlock.get(((ControlSplitNode) input).getPrimarySuccessor());
-                            } else {
-                                inputEarliest = nodeToBlock.get(input);
-                            }
+                            Block inputEarliest = nodeToBlock.get(input);
                             if (inputEarliest == null) {
                                 assert current instanceof FrameState && input instanceof StateSplit && ((StateSplit) input).stateAfter() == current;
                             } else {
                                 assert inputEarliest != null;
+                                if (inputEarliest.getEndNode() == input) {
+                                    // This is the last node of the block.
+                                    if (current instanceof FrameState && input instanceof StateSplit && ((StateSplit) input).stateAfter() == current) {
+                                        // Keep regular inputEarliest.
+                                    } else if (input instanceof ControlSplitNode) {
+                                        inputEarliest = nodeToBlock.get(((ControlSplitNode) input).getPrimarySuccessor());
+                                    } else {
+                                        assert inputEarliest.getSuccessorCount() == 1;
+                                        inputEarliest = inputEarliest.getSuccessors().get(0);
+                                    }
+                                }
                                 if (earliest.getDominatorDepth() < inputEarliest.getDominatorDepth()) {
                                     earliest = inputEarliest;
                                 }
--- a/src/share/vm/compiler/compileBroker.cpp	Tue Mar 17 15:52:41 2015 +0100
+++ b/src/share/vm/compiler/compileBroker.cpp	Tue Mar 17 17:16:04 2015 +0100
@@ -801,12 +801,6 @@
   GraalCompiler* graal = new GraalCompiler();
 #endif
 
-#ifdef COMPILER1
-  if (c1_count > 0) {
-    _compilers[0] = new Compiler();
-  }
-#endif // COMPILER1
-
 #if defined(COMPILERGRAAL)
   _compilers[1] = graal;
   if (FLAG_IS_DEFAULT(GraalThreads)) {
@@ -817,8 +811,18 @@
   } else {
     c2_count = GraalThreads;
   }
+  if (FLAG_IS_DEFAULT(GraalHostThreads)) {
+  } else {
+    c1_count = GraalHostThreads;
+  }
 #endif // COMPILERGRAAL
 
+#ifdef COMPILER1
+  if (c1_count > 0) {
+    _compilers[0] = new Compiler();
+  }
+#endif // COMPILER1
+
 #ifdef COMPILER2
   if (c2_count > 0) {
     _compilers[1] = new C2Compiler();
--- a/src/share/vm/graal/graalGlobals.hpp	Tue Mar 17 15:52:41 2015 +0100
+++ b/src/share/vm/graal/graalGlobals.hpp	Tue Mar 17 17:16:04 2015 +0100
@@ -61,6 +61,9 @@
   COMPILERGRAAL_PRESENT(product(intx, GraalThreads, 1,                      \
           "Force number of Graal compiler threads to use"))                 \
                                                                             \
+  COMPILERGRAAL_PRESENT(product(intx, GraalHostThreads, 1,                  \
+          "Force number of compiler threads for Graal host compiler"))      \
+                                                                            \
   GRAAL_ONLY(product(bool, CodeInstallSafepointChecks, true,                \
           "Perform explicit safepoint checks while installing code"))       \
                                                                             \