changeset 11724:c8d0d5ff846e

Merged
author Christian Wirth <christian.wirth@oracle.com>
date Thu, 19 Sep 2013 10:51:30 +0200
parents 9b8e3b2986c5 5a6d1d2a6522
children 45570e4fe8a9 271ffa2d36b3
files graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InsertStateAfterPlaceholderPhase.java
diffstat 13 files changed, 119 insertions(+), 148 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaMethod.java	Thu Sep 19 10:38:00 2013 +0200
+++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaMethod.java	Thu Sep 19 10:51:30 2013 +0200
@@ -265,7 +265,9 @@
         ResolvedJavaMethod method2 = runtime.lookupJavaMethod(getClass().getDeclaredMethod("nullPointerExceptionOnFirstLine", Object.class, String.class));
         assertEquals(0, method1.getMaxStackSize());
         // some versions of javac produce bytecode with a stacksize of 2 for this method
-        assertTrue(3 == method2.getMaxStackSize() || 2 == method2.getMaxStackSize());
+        // JSR 292 also sometimes need one more stack slot
+        int method2StackSize = method2.getMaxStackSize();
+        assertTrue(2 <= method2StackSize && method2StackSize <= 4);
     }
 
     private Method findTestMethod(Method apiMethod) {
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java	Thu Sep 19 10:38:00 2013 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java	Thu Sep 19 10:51:30 2013 +0200
@@ -175,12 +175,14 @@
     boolean canBeInlined();
 
     /**
-     * Returns the LineNumberTable of this method.
+     * Returns the LineNumberTable of this method or null if this method does not have a line
+     * numbers table.
      */
     LineNumberTable getLineNumberTable();
 
     /**
-     * Returns the localvariable table of this method.
+     * Returns the local variable table of this method or null if this method does not have a local
+     * variable table.
      */
     LocalVariableTable getLocalVariableTable();
 
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticDoubleSpillTest.java	Thu Sep 19 10:38:00 2013 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticDoubleSpillTest.java	Thu Sep 19 10:51:30 2013 +0200
@@ -25,7 +25,8 @@
 import java.util.*;
 
 import com.oracle.graal.compiler.hsail.test.infra.GraalKernelTester;
-import org.junit.Test;
+
+import org.junit.*;
 
 /**
  * Tests the spilling of double variables into memory.
@@ -118,6 +119,7 @@
     }
 
     // Marked to only run on hardware until simulator spill bug is fixed.
+    @Ignore
     @Test
     public void test() {
         testGeneratedHsail();
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticIntSpillTest.java	Thu Sep 19 10:38:00 2013 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticIntSpillTest.java	Thu Sep 19 10:51:30 2013 +0200
@@ -25,7 +25,8 @@
 import java.util.*;
 
 import com.oracle.graal.compiler.hsail.test.infra.GraalKernelTester;
-import org.junit.Test;
+
+import org.junit.*;
 
 /**
  * Tests the spilling of integers into memory.
@@ -87,6 +88,7 @@
     }
 
     // Marked to only run on hardware until simulator spill bug is fixed.
+    @Ignore
     @Test
     public void test() {
         testGeneratedHsail();
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java	Thu Sep 19 10:38:00 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java	Thu Sep 19 10:51:30 2013 +0200
@@ -218,6 +218,10 @@
 
     @Override
     public int getMaxLocals() {
+        int modifiers = getModifiers();
+        if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) {
+            return 0;
+        }
         HotSpotVMConfig config = graalRuntime().getConfig();
         long metaspaceConstMethod = unsafe.getLong(metaspaceMethod + config.methodConstMethodOffset);
         return unsafe.getShort(metaspaceConstMethod + config.methodMaxLocalsOffset) & 0xFFFF;
@@ -225,6 +229,10 @@
 
     @Override
     public int getMaxStackSize() {
+        int modifiers = getModifiers();
+        if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) {
+            return 0;
+        }
         HotSpotVMConfig config = graalRuntime().getConfig();
         long metaspaceConstMethod = unsafe.getLong(metaspaceMethod + config.methodConstMethodOffset);
         return config.extraStackEntries + (unsafe.getShort(metaspaceConstMethod + config.constMethodMaxStackOffset) & 0xFFFF);
@@ -407,6 +415,9 @@
     @Override
     public LineNumberTable getLineNumberTable() {
         long[] values = graalRuntime().getCompilerToVM().getLineNumberTable(this);
+        if (values == null) {
+            return null;
+        }
         assert values.length % 2 == 0;
         int[] bci = new int[values.length / 2];
         int[] line = new int[values.length / 2];
@@ -422,6 +433,9 @@
     @Override
     public LocalVariableTable getLocalVariableTable() {
         Local[] locals = graalRuntime().getCompilerToVM().getLocalVariableTable(this);
+        if (locals == null) {
+            return null;
+        }
         return new LocalVariableTableImpl(locals);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopyNode.java	Thu Sep 19 10:38:00 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopyNode.java	Thu Sep 19 10:51:30 2013 +0200
@@ -24,6 +24,8 @@
 
 import static com.oracle.graal.compiler.GraalCompiler.*;
 
+import java.util.concurrent.*;
+
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.loop.phases.*;
@@ -62,7 +64,7 @@
         return arguments.get(4);
     }
 
-    private StructuredGraph selectSnippet(LoweringTool tool, Replacements replacements) {
+    private StructuredGraph selectSnippet(LoweringTool tool, final Replacements replacements) {
         ResolvedJavaType srcType = ObjectStamp.typeOrNull(getSource().stamp());
         ResolvedJavaType destType = ObjectStamp.typeOrNull(getDestination().stamp());
 
@@ -73,8 +75,15 @@
             return null;
         }
         Kind componentKind = srcType.getComponentType().getKind();
-        ResolvedJavaMethod snippetMethod = tool.getRuntime().lookupJavaMethod(ArrayCopySnippets.getSnippetForKind(componentKind));
-        return replacements.getSnippet(snippetMethod);
+        final ResolvedJavaMethod snippetMethod = tool.getRuntime().lookupJavaMethod(ArrayCopySnippets.getSnippetForKind(componentKind));
+        return Debug.scope("ArrayCopySnippet", snippetMethod, new Callable<StructuredGraph>() {
+
+            @Override
+            public StructuredGraph call() throws Exception {
+                return replacements.getSnippet(snippetMethod);
+            }
+        });
+
     }
 
     private static void unrollFixedLengthLoop(StructuredGraph snippetGraph, int length, LoweringTool tool) {
@@ -91,23 +100,37 @@
     }
 
     @Override
-    protected StructuredGraph getSnippetGraph(LoweringTool tool) {
+    protected StructuredGraph getSnippetGraph(final LoweringTool tool) {
         if (!shouldIntrinsify(getTargetMethod())) {
             return null;
         }
 
-        Replacements replacements = tool.getReplacements();
+        final Replacements replacements = tool.getReplacements();
         StructuredGraph snippetGraph = selectSnippet(tool, replacements);
         if (snippetGraph == null) {
-            ResolvedJavaMethod snippetMethod = tool.getRuntime().lookupJavaMethod(ArrayCopySnippets.genericArraycopySnippet);
-            snippetGraph = replacements.getSnippet(snippetMethod).copy();
+            final ResolvedJavaMethod snippetMethod = tool.getRuntime().lookupJavaMethod(ArrayCopySnippets.genericArraycopySnippet);
+            snippetGraph = Debug.scope("ArrayCopySnippet", snippetMethod, new Callable<StructuredGraph>() {
+
+                @Override
+                public StructuredGraph call() throws Exception {
+                    return replacements.getSnippet(snippetMethod).copy();
+                }
+            });
             replaceSnippetInvokes(snippetGraph);
         } else {
             assert snippetGraph != null : "ArrayCopySnippets should be installed";
 
             if (getLength().isConstant() && getLength().asConstant().asInt() <= GraalOptions.MaximumEscapeAnalysisArrayLength.getValue()) {
-                snippetGraph = snippetGraph.copy();
-                unrollFixedLengthLoop(snippetGraph, getLength().asConstant().asInt(), tool);
+                final StructuredGraph copy = snippetGraph.copy();
+                snippetGraph = copy;
+                Debug.scope("ArrayCopySnippetSpecialization", snippetGraph.method(), new Runnable() {
+
+                    @Override
+                    public void run() {
+                        unrollFixedLengthLoop(copy, getLength().asConstant().asInt(), tool);
+                    }
+                });
+
             }
         }
         return snippetGraph;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java	Thu Sep 19 10:38:00 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java	Thu Sep 19 10:51:30 2013 +0200
@@ -25,9 +25,11 @@
 import static com.oracle.graal.compiler.GraalCompiler.*;
 
 import java.lang.reflect.*;
+import java.util.concurrent.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.debug.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
@@ -69,9 +71,15 @@
         } else {
             method = ObjectCloneSnippets.instanceCloneMethod;
         }
-        ResolvedJavaMethod snippetMethod = tool.getRuntime().lookupJavaMethod(method);
-        Replacements replacements = tool.getReplacements();
-        StructuredGraph snippetGraph = replacements.getSnippet(snippetMethod);
+        final ResolvedJavaMethod snippetMethod = tool.getRuntime().lookupJavaMethod(method);
+        final Replacements replacements = tool.getReplacements();
+        StructuredGraph snippetGraph = Debug.scope("ArrayCopySnippet", snippetMethod, new Callable<StructuredGraph>() {
+
+            @Override
+            public StructuredGraph call() throws Exception {
+                return replacements.getSnippet(snippetMethod);
+            }
+        });
 
         assert snippetGraph != null : "ObjectCloneSnippets should be installed";
         return snippetGraph;
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java	Thu Sep 19 10:38:00 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java	Thu Sep 19 10:51:30 2013 +0200
@@ -37,6 +37,7 @@
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.graph.*;
 import com.oracle.graal.phases.schedule.*;
+import com.oracle.graal.phases.schedule.SchedulePhase.SchedulingStrategy;
 import com.oracle.graal.phases.tiers.*;
 
 /**
@@ -182,7 +183,7 @@
 
     @Override
     protected void run(StructuredGraph graph, MidTierContext context) {
-        SchedulePhase schedule = new SchedulePhase();
+        SchedulePhase schedule = new SchedulePhase(SchedulingStrategy.EARLIEST);
         schedule.apply(graph);
 
         for (Block block : schedule.getCFG().getBlocks()) {
@@ -193,10 +194,9 @@
     }
 
     private static void processBlock(Block block, SchedulePhase schedule, int implicitNullCheckLimit) {
-        List<ScheduledNode> nodes = schedule.nodesFor(block);
         if (OptImplicitNullChecks.getValue() && implicitNullCheckLimit > 0) {
-            new UseImplicitNullChecks(implicitNullCheckLimit).processNodes(nodes, block.getBeginNode());
+            new UseImplicitNullChecks(implicitNullCheckLimit).processNodes(block, schedule);
         }
-        new LowerGuards(block).processNodes(nodes, block.getBeginNode());
+        new LowerGuards(block).processNodes(block, schedule);
     }
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InsertStateAfterPlaceholderPhase.java	Thu Sep 19 10:38:00 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,83 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.phases.common;
-
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.phases.*;
-
-public class InsertStateAfterPlaceholderPhase extends Phase {
-
-    private static class PlaceholderNode extends AbstractStateSplit implements StateSplit, IterableNodeType, LIRLowerable, Canonicalizable {
-
-        public PlaceholderNode() {
-            super(StampFactory.forVoid());
-        }
-
-        @Override
-        public void generate(LIRGeneratorTool gen) {
-            // nothing to do
-        }
-
-        @Override
-        public boolean hasSideEffect() {
-            return false;
-        }
-
-        @Override
-        public ValueNode canonical(CanonicalizerTool tool) {
-            if (!usages().isEmpty()) {
-                return this;
-            }
-            if (stateAfter() == null) {
-                return null;
-            }
-            FixedNode next = next();
-            if (next instanceof PlaceholderNode && ((PlaceholderNode) next).stateAfter() != null) {
-                return null;
-            }
-            return this;
-        }
-    }
-
-    @Override
-    protected void run(StructuredGraph graph) {
-        boolean needsPlaceHolder = false;
-        for (Node node : graph.getNodes().filterInterface(StateSplit.class)) {
-            StateSplit stateSplit = (StateSplit) node;
-            if (stateSplit.hasSideEffect() && stateSplit.stateAfter() != null) {
-                needsPlaceHolder = true;
-            }
-        }
-        if (needsPlaceHolder) {
-            for (ReturnNode ret : graph.getNodes().filter(ReturnNode.class)) {
-                PlaceholderNode p = graph.add(new PlaceholderNode());
-                p.setStateAfter(graph.add(new FrameState(FrameState.AFTER_BCI)));
-                graph.addBeforeFixed(ret, p);
-            }
-        }
-    }
-
-}
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ScheduledNodeIterator.java	Thu Sep 19 10:38:00 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ScheduledNodeIterator.java	Thu Sep 19 10:51:30 2013 +0200
@@ -26,6 +26,7 @@
 
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.phases.schedule.*;
 
 /**
@@ -41,11 +42,12 @@
     private FixedWithNextNode reconnect;
     private ListIterator<ScheduledNode> iterator;
 
-    public void processNodes(List<ScheduledNode> nodes, FixedWithNextNode begin) {
-        assert begin != null;
-        lastFixed = begin;
+    public void processNodes(Block block, SchedulePhase shedule) {
+        lastFixed = block.getBeginNode();
+        assert lastFixed != null;
         reconnect = null;
-        iterator = nodes.listIterator();
+        iterator = shedule.nodesFor(block).listIterator();
+
         while (iterator.hasNext()) {
             Node node = iterator.next();
             if (!node.isAlive()) {
@@ -60,7 +62,10 @@
             }
             processNode(node);
         }
-        assert reconnect == null;
+        if (reconnect != null) {
+            assert block.getSuccessorCount() == 1;
+            reconnect.setNext(block.getFirstSuccessor().getBeginNode());
+        }
     }
 
     protected void insert(FixedNode start, FixedWithNextNode end) {
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java	Thu Sep 19 10:38:00 2013 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java	Thu Sep 19 10:51:30 2013 +0200
@@ -131,7 +131,7 @@
         WriteNode write = (WriteNode) graph.start().next();
         Assert.assertEquals(graph.getLocal(2), write.value());
         Assert.assertEquals(Kind.Void, write.kind());
-        Assert.assertEquals(FrameState.INVALID_FRAMESTATE_BCI, write.stateAfter().bci);
+        Assert.assertEquals(FrameState.AFTER_BCI, write.stateAfter().bci);
 
         UnsafeCastNode cast = (UnsafeCastNode) write.object();
         Assert.assertEquals(graph.getLocal(0), cast.object());
@@ -150,10 +150,7 @@
             Assert.assertEquals(graph.getLocal(1), location.getIndex());
         }
 
-        AbstractStateSplit stateSplit = (AbstractStateSplit) write.next();
-        Assert.assertEquals(FrameState.AFTER_BCI, stateSplit.stateAfter().bci);
-
-        ReturnNode ret = (ReturnNode) stateSplit.next();
+        ReturnNode ret = (ReturnNode) write.next();
         Assert.assertEquals(null, ret.result());
     }
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Thu Sep 19 10:38:00 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Thu Sep 19 10:51:30 2013 +0200
@@ -292,11 +292,8 @@
 
             if (original == null) {
                 new SnippetFrameStateCleanupPhase().apply(graph);
-                new DeadCodeEliminationPhase().apply(graph);
-                new InsertStateAfterPlaceholderPhase().apply(graph);
-            } else {
-                new DeadCodeEliminationPhase().apply(graph);
             }
+            new DeadCodeEliminationPhase().apply(graph);
         }
 
         private StructuredGraph parseGraph(final ResolvedJavaMethod methodToParse, final SnippetInliningPolicy policy) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetFrameStateCleanupPhase.java	Thu Sep 19 10:38:00 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetFrameStateCleanupPhase.java	Thu Sep 19 10:51:30 2013 +0200
@@ -45,24 +45,23 @@
 
     @Override
     protected void run(StructuredGraph graph) {
-        ReentrantNodeIterator.apply(new SnippetFrameStateCleanupClosure(), graph.start(), false, null);
+        ReentrantNodeIterator.apply(new SnippetFrameStateCleanupClosure(), graph.start(), null, null);
     }
 
-    /**
-     * A proper (loop-aware) iteration over the graph is used to detect loops that contain invalid
-     * frame states, so that they can be marked with an invalid frame state.
-     */
-    private static class SnippetFrameStateCleanupClosure extends NodeIteratorClosure<Boolean> {
+    private static class SnippetFrameStateCleanupClosure extends NodeIteratorClosure<StateSplit> {
 
         @Override
-        protected Boolean processNode(FixedNode node, Boolean currentState) {
+        protected StateSplit processNode(FixedNode node, StateSplit currentState) {
+            StateSplit state = currentState;
             if (node instanceof StateSplit) {
                 StateSplit stateSplit = (StateSplit) node;
                 FrameState frameState = stateSplit.stateAfter();
                 if (frameState != null) {
                     if (stateSplit.hasSideEffect()) {
-                        stateSplit.setStateAfter(node.graph().add(new FrameState(FrameState.INVALID_FRAMESTATE_BCI)));
-                        return true;
+                        stateSplit.setStateAfter(createInvalidFrameState(node));
+                        state = stateSplit;
+                    } else if (hasInvalidState(state)) {
+                        stateSplit.setStateAfter(createInvalidFrameState(node));
                     } else {
                         stateSplit.setStateAfter(null);
                     }
@@ -71,41 +70,44 @@
                     }
                 }
             }
-            return currentState;
+            if (node instanceof ControlSinkNode && state != null) {
+                state.setStateAfter(node.graph().add(new FrameState(FrameState.AFTER_BCI)));
+            }
+            return state;
         }
 
         @Override
-        protected Boolean merge(MergeNode merge, List<Boolean> states) {
-            for (boolean state : states) {
-                if (state) {
-                    return true;
-                }
-            }
-            return false;
+        protected StateSplit merge(MergeNode merge, List<StateSplit> states) {
+            return merge;
         }
 
         @Override
-        protected Boolean afterSplit(AbstractBeginNode node, Boolean oldState) {
+        protected StateSplit afterSplit(AbstractBeginNode node, StateSplit oldState) {
             return oldState;
         }
 
         @Override
-        protected Map<LoopExitNode, Boolean> processLoop(LoopBeginNode loop, Boolean initialState) {
-            LoopInfo<Boolean> info = ReentrantNodeIterator.processLoop(this, loop, false);
-            boolean containsFrameState = false;
-            for (Boolean state : info.endStates.values()) {
-                containsFrameState |= state;
-            }
-            if (containsFrameState) {
-                loop.setStateAfter(loop.graph().add(new FrameState(FrameState.INVALID_FRAMESTATE_BCI)));
-            }
-            if (containsFrameState || initialState) {
-                for (Map.Entry<?, Boolean> entry : info.exitStates.entrySet()) {
-                    entry.setValue(true);
+        protected Map<LoopExitNode, StateSplit> processLoop(LoopBeginNode loop, StateSplit initialState) {
+            LoopInfo<StateSplit> info = ReentrantNodeIterator.processLoop(this, loop, initialState);
+            if (!hasInvalidState(initialState)) {
+                boolean isNowInvalid = false;
+                for (StateSplit endState : info.endStates.values()) {
+                    isNowInvalid |= hasInvalidState(endState);
+                }
+                if (isNowInvalid) {
+                    loop.setStateAfter(createInvalidFrameState(loop));
+                    info = ReentrantNodeIterator.processLoop(this, loop, loop);
                 }
             }
             return info.exitStates;
         }
 
+        private static boolean hasInvalidState(StateSplit state) {
+            return state != null && state.stateAfter() != null && state.stateAfter().bci == FrameState.INVALID_FRAMESTATE_BCI;
+        }
+
+        private static FrameState createInvalidFrameState(FixedNode node) {
+            return node.graph().add(new FrameState(FrameState.INVALID_FRAMESTATE_BCI));
+        }
     }
 }