changeset 21567:f41409c6ff26

Do not rely on single/double slot information from the Kind of the value in a local variable or expression stack entry. With word type rewriting during parsing, long values can be single slot values when they are rewritten from Object values.
author Christian Wimmer <christian.wimmer@oracle.com>
date Thu, 28 May 2015 17:00:59 -0700
parents 1de4d7e69f85
children a880844225e4
files graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/ForeignCallPlugin.java graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderContext.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotWordOperationPlugin.java graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java graal/com.oracle.graal.lir.jtt/src/com/oracle/graal/lir/jtt/LIRTest.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.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.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64GraphBuilderPlugins.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultGenericInvocationPlugin.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/MethodHandleInvocationPlugin.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/PEGraphDecoder.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/WordOperationPlugin.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java graal/com.oracle.jvmci.meta/src/com/oracle/jvmci/meta/Signature.java
diffstat 18 files changed, 397 insertions(+), 669 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/ForeignCallPlugin.java	Fri May 29 01:11:41 2015 +0200
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/ForeignCallPlugin.java	Thu May 28 17:00:59 2015 -0700
@@ -43,7 +43,7 @@
     public boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode[] args) {
         ForeignCallNode foreignCall = new ForeignCallNode(foreignCalls, descriptor, args);
         foreignCall.setBci(b.bci());
-        b.addPush(foreignCall);
+        b.addPush(targetMethod.getSignature().getReturnKind(), foreignCall);
         return true;
     }
 }
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderContext.java	Fri May 29 01:11:41 2015 +0200
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderContext.java	Thu May 28 17:00:59 2015 -0700
@@ -48,8 +48,8 @@
 public interface GraphBuilderContext {
 
     /**
-     * Raw operation for adding a node to the graph when neither {@link #add},
-     * {@link #addPush(ValueNode)} nor {@link #addPush(Kind, ValueNode)} can be used.
+     * Raw operation for adding a node to the graph when neither {@link #add} nor
+     * {@link #addPush(Kind, ValueNode)} can be used.
      *
      * @return either the node added or an equivalent node
      */
@@ -102,26 +102,13 @@
      * is a {@link StateSplit} with a null {@linkplain StateSplit#stateAfter() frame state}, the
      * frame state is initialized.
      *
-     * @param value the value to add to the graph and push to the stack. The {@code value.getKind()}
-     *            kind is used when type checking this operation.
-     * @return a node equivalent to {@code value} in the graph
-     */
-    default <T extends ValueNode> T addPush(T value) {
-        return addPush(value.getKind().getStackKind(), value);
-    }
-
-    /**
-     * Adds a node with a non-void kind to the graph, pushes it to the stack. If the returned node
-     * is a {@link StateSplit} with a null {@linkplain StateSplit#stateAfter() frame state}, the
-     * frame state is initialized.
-     *
      * @param kind the kind to use when type checking this operation
      * @param value the value to add to the graph and push to the stack
      * @return a node equivalent to {@code value} in the graph
      */
     default <T extends ValueNode> T addPush(Kind kind, T value) {
         T equivalentValue = value.graph() != null ? value : append(value);
-        push(kind.getStackKind(), equivalentValue);
+        push(kind, equivalentValue);
         if (equivalentValue instanceof StateSplit) {
             StateSplit stateSplit = (StateSplit) equivalentValue;
             if (stateSplit.stateAfter() == null && stateSplit.hasSideEffect()) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java	Fri May 29 01:11:41 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java	Thu May 28 17:00:59 2015 -0700
@@ -168,7 +168,7 @@
         Registration r = new Registration(plugins, Reflection.class);
         r.register0("getCallerClass", new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
-                b.addPush(new ReflectionGetCallerClassNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnType()));
+                b.addPush(Kind.Object, new ReflectionGetCallerClassNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnType()));
                 return true;
             }
 
@@ -184,7 +184,7 @@
         r.register0("nanoTime", new ForeignCallPlugin(foreignCalls, JAVA_TIME_NANOS));
         r.register1("identityHashCode", Object.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) {
-                b.addPush(new IdentityHashCodeNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnType(), object));
+                b.addPush(Kind.Int, new IdentityHashCodeNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnType(), object));
                 return true;
             }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotWordOperationPlugin.java	Fri May 29 01:11:41 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotWordOperationPlugin.java	Thu May 28 17:00:59 2015 -0700
@@ -69,7 +69,6 @@
 
     public void processHotSpotWordOperation(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, HotSpotOperation operation) {
         Kind returnKind = method.getSignature().getReturnKind();
-        Kind returnStackKind = returnKind.getStackKind();
         switch (operation.opcode()) {
             case POINTER_EQ:
             case POINTER_NE:
@@ -84,7 +83,7 @@
                 PointerEqualsNode comparison = b.add(new PointerEqualsNode(left, right));
                 ValueNode eqValue = b.add(forBoolean(opcode == POINTER_EQ));
                 ValueNode neValue = b.add(forBoolean(opcode == POINTER_NE));
-                b.addPush(returnStackKind, new ConditionalNode(comparison, eqValue, neValue));
+                b.addPush(returnKind, new ConditionalNode(comparison, eqValue, neValue));
                 break;
 
             case IS_NULL:
@@ -93,22 +92,22 @@
                 assert pointer.stamp() instanceof MetaspacePointerStamp;
 
                 IsNullNode isNull = b.add(new IsNullNode(pointer));
-                b.addPush(returnStackKind, new ConditionalNode(isNull, b.add(forBoolean(true)), b.add(forBoolean(false))));
+                b.addPush(returnKind, new ConditionalNode(isNull, b.add(forBoolean(true)), b.add(forBoolean(false))));
                 break;
 
             case FROM_POINTER:
                 assert args.length == 1;
-                b.addPush(returnStackKind, new PointerCastNode(StampFactory.forKind(wordKind), args[0]));
+                b.addPush(returnKind, new PointerCastNode(StampFactory.forKind(wordKind), args[0]));
                 break;
 
             case TO_KLASS_POINTER:
                 assert args.length == 1;
-                b.addPush(returnStackKind, new PointerCastNode(KlassPointerStamp.klass(), args[0]));
+                b.addPush(returnKind, new PointerCastNode(KlassPointerStamp.klass(), args[0]));
                 break;
 
             case TO_METHOD_POINTER:
                 assert args.length == 1;
-                b.addPush(returnStackKind, new PointerCastNode(MethodPointerStamp.method(), args[0]));
+                b.addPush(returnKind, new PointerCastNode(MethodPointerStamp.method(), args[0]));
                 break;
 
             case READ_KLASS_POINTER:
@@ -126,7 +125,7 @@
                  * explicit zero check on its base address.
                  */
                 read.setGuard(AbstractBeginNode.prevBegin(read));
-                b.push(returnStackKind, read);
+                b.push(returnKind, read);
                 break;
 
             default:
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java	Fri May 29 01:11:41 2015 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java	Thu May 28 17:00:59 2015 -0700
@@ -22,16 +22,10 @@
  */
 package com.oracle.graal.java;
 
-import com.oracle.jvmci.code.BailoutException;
-import com.oracle.jvmci.code.BytecodeFrame;
-import com.oracle.jvmci.code.BytecodePosition;
-import com.oracle.jvmci.meta.ResolvedJavaType;
-import com.oracle.jvmci.meta.Signature;
-import com.oracle.jvmci.meta.ResolvedJavaMethod;
-import com.oracle.jvmci.meta.Kind;
-import com.oracle.jvmci.meta.JavaType;
+import static com.oracle.graal.bytecode.Bytecodes.*;
 import static com.oracle.graal.graph.iterators.NodePredicates.*;
 import static com.oracle.graal.java.GraphBuilderPhase.Options.*;
+import static com.oracle.jvmci.common.JVMCIError.*;
 
 import java.util.*;
 
@@ -45,25 +39,26 @@
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.util.*;
-import com.oracle.jvmci.common.*;
+import com.oracle.jvmci.code.*;
 import com.oracle.jvmci.debug.*;
+import com.oracle.jvmci.meta.*;
 
 public final class FrameStateBuilder implements SideEffectsState {
 
-    static final ValueNode[] EMPTY_ARRAY = new ValueNode[0];
-    static final MonitorIdNode[] EMPTY_MONITOR_ARRAY = new MonitorIdNode[0];
+    private static final ValueNode[] EMPTY_ARRAY = new ValueNode[0];
+    private static final MonitorIdNode[] EMPTY_MONITOR_ARRAY = new MonitorIdNode[0];
 
-    protected final BytecodeParser parser;
-    protected final ResolvedJavaMethod method;
-    protected int stackSize;
+    private final BytecodeParser parser;
+    private final ResolvedJavaMethod method;
+    private int stackSize;
     protected final ValueNode[] locals;
     protected final ValueNode[] stack;
-    protected ValueNode[] lockedObjects;
+    private ValueNode[] lockedObjects;
 
     /**
      * @see BytecodeFrame#rethrowException
      */
-    protected boolean rethrowException;
+    private boolean rethrowException;
 
     private MonitorIdNode[] monitorIds;
     private final StructuredGraph graph;
@@ -73,7 +68,7 @@
      * The closest {@link StateSplit#hasSideEffect() side-effect} predecessors. There will be more
      * than one when the current block contains no side-effects but merging predecessor blocks do.
      */
-    protected List<StateSplit> sideEffects;
+    private List<StateSplit> sideEffects;
 
     /**
      * Creates a new frame state builder for the given method and the given target graph.
@@ -185,6 +180,10 @@
         return length == 0 ? EMPTY_ARRAY : new ValueNode[length];
     }
 
+    public ResolvedJavaMethod getMethod() {
+        return method;
+    }
+
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
@@ -214,29 +213,30 @@
         }
 
         // Skip intrinsic frames
-        return create(bci, parser.getNonIntrinsicAncestor(), false, (ValueNode[]) null);
+        return create(bci, parser.getNonIntrinsicAncestor(), false, null, null);
     }
 
     /**
      * @param pushedValues if non-null, values to {@link #push(Kind, ValueNode)} to the stack before
      *            creating the {@link FrameState}
      */
-    public FrameState create(int bci, BytecodeParser parent, boolean duringCall, ValueNode... pushedValues) {
+    public FrameState create(int bci, BytecodeParser parent, boolean duringCall, Kind[] pushedSlotKinds, ValueNode[] pushedValues) {
         if (outerFrameState == null && parent != null) {
             outerFrameState = parent.getFrameStateBuilder().create(parent.bci(), null);
         }
         if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI && parent != null) {
-            FrameState newFrameState = outerFrameState.duplicateModified(outerFrameState.bci, true, Kind.Void, this.peek(0));
+            FrameState newFrameState = outerFrameState.duplicateModified(outerFrameState.bci, true, Kind.Void, new Kind[]{Kind.Object}, new ValueNode[]{stack[0]});
             return newFrameState;
         }
         if (bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) {
-            throw JVMCIError.shouldNotReachHere();
+            throw shouldNotReachHere();
         }
 
         if (pushedValues != null) {
+            assert pushedSlotKinds.length == pushedValues.length;
             int stackSizeToRestore = stackSize;
-            for (ValueNode arg : pushedValues) {
-                push(arg.getKind(), arg);
+            for (int i = 0; i < pushedValues.length; i++) {
+                push(pushedSlotKinds[i], pushedValues[i]);
             }
             FrameState res = graph.add(new FrameState(outerFrameState, method, bci, locals, stack, stackSize, lockedObjects, Arrays.asList(monitorIds), rethrowException, duringCall));
             stackSize = stackSizeToRestore;
@@ -268,7 +268,7 @@
             return FrameState.toBytecodePosition(outerFrameState);
         }
         if (bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) {
-            throw JVMCIError.shouldNotReachHere();
+            throw shouldNotReachHere();
         }
         return new BytecodePosition(outer, method, bci);
     }
@@ -285,8 +285,8 @@
             return false;
         }
         for (int i = 0; i < stackSize(); i++) {
-            ValueNode x = stackAt(i);
-            ValueNode y = other.stackAt(i);
+            ValueNode x = stack[i];
+            ValueNode y = other.stack[i];
             if (x != y && (x == null || x.isDeleted() || y == null || y.isDeleted() || x.getKind() != y.getKind())) {
                 return false;
             }
@@ -306,18 +306,10 @@
         assert isCompatibleWith(other);
 
         for (int i = 0; i < localsSize(); i++) {
-            ValueNode curLocal = localAt(i);
-            ValueNode mergedLocal = merge(curLocal, other.localAt(i), block);
-            if (curLocal != mergedLocal) {
-                storeLocal(i, mergedLocal);
-            }
+            locals[i] = merge(locals[i], other.locals[i], block);
         }
         for (int i = 0; i < stackSize(); i++) {
-            ValueNode curStack = stackAt(i);
-            ValueNode mergedStack = merge(curStack, other.stackAt(i), block);
-            if (curStack != mergedStack) {
-                storeStack(i, mergedStack);
-            }
+            stack[i] = merge(stack[i], other.stack[i], block);
         }
         for (int i = 0; i < lockedObjects.length; i++) {
             lockedObjects[i] = merge(lockedObjects[i], other.lockedObjects[i], block);
@@ -387,11 +379,11 @@
         for (int i = 0; i < localsSize(); i++) {
             boolean changedInLoop = liveness.localIsChangedInLoop(loopId, i);
             if (changedInLoop || forcePhis) {
-                storeLocal(i, createLoopPhi(loopBegin, localAt(i), !changedInLoop));
+                locals[i] = createLoopPhi(loopBegin, locals[i], !changedInLoop);
             }
         }
         for (int i = 0; i < stackSize(); i++) {
-            storeStack(i, createLoopPhi(loopBegin, stackAt(i), false));
+            stack[i] = createLoopPhi(loopBegin, stack[i], false);
         }
         for (int i = 0; i < lockedObjects.length; i++) {
             lockedObjects[i] = createLoopPhi(loopBegin, lockedObjects[i], false);
@@ -400,17 +392,17 @@
 
     public void insertLoopProxies(LoopExitNode loopExit, FrameStateBuilder loopEntryState) {
         for (int i = 0; i < localsSize(); i++) {
-            ValueNode value = localAt(i);
+            ValueNode value = locals[i];
             if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) {
                 Debug.log(" inserting proxy for %s", value);
-                storeLocal(i, ProxyNode.forValue(value, loopExit, graph));
+                locals[i] = ProxyNode.forValue(value, loopExit, graph);
             }
         }
         for (int i = 0; i < stackSize(); i++) {
-            ValueNode value = stackAt(i);
+            ValueNode value = stack[i];
             if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) {
                 Debug.log(" inserting proxy for %s", value);
-                storeStack(i, ProxyNode.forValue(value, loopExit, graph));
+                stack[i] = ProxyNode.forValue(value, loopExit, graph);
             }
         }
         for (int i = 0; i < lockedObjects.length; i++) {
@@ -424,17 +416,17 @@
 
     public void insertProxies(AbstractBeginNode begin) {
         for (int i = 0; i < localsSize(); i++) {
-            ValueNode value = localAt(i);
+            ValueNode value = locals[i];
             if (value != null) {
                 Debug.log(" inserting proxy for %s", value);
-                storeLocal(i, ProxyNode.forValue(value, begin, graph));
+                locals[i] = ProxyNode.forValue(value, begin, graph);
             }
         }
         for (int i = 0; i < stackSize(); i++) {
-            ValueNode value = stackAt(i);
+            ValueNode value = stack[i];
             if (value != null) {
                 Debug.log(" inserting proxy for %s", value);
-                storeStack(i, ProxyNode.forValue(value, begin, graph));
+                stack[i] = ProxyNode.forValue(value, begin, graph);
             }
         }
         for (int i = 0; i < lockedObjects.length; i++) {
@@ -500,12 +492,12 @@
 
     public boolean contains(ValueNode value) {
         for (int i = 0; i < localsSize(); i++) {
-            if (localAt(i) == value) {
+            if (locals[i] == value) {
                 return true;
             }
         }
         for (int i = 0; i < stackSize(); i++) {
-            if (stackAt(i) == value) {
+            if (stack[i] == value) {
                 return true;
             }
         }
@@ -574,61 +566,20 @@
     }
 
     /**
-     * Gets the value in the local variables at the specified index, without any sanity checking.
-     *
-     * @param i the index into the locals
-     * @return the instruction that produced the value for the specified local
-     */
-    public ValueNode localAt(int i) {
-        return locals[i];
-    }
-
-    /**
-     * Get the value on the stack at the specified stack index.
-     *
-     * @param i the index into the stack, with {@code 0} being the bottom of the stack
-     * @return the instruction at the specified position in the stack
-     */
-    public ValueNode stackAt(int i) {
-        return stack[i];
-    }
-
-    /**
-     * Gets the value in the lock at the specified index, without any sanity checking.
-     *
-     * @param i the index into the lock
-     * @return the instruction that produced the value for the specified lock
-     */
-    public ValueNode lockAt(int i) {
-        return lockedObjects[i];
-    }
-
-    public void storeLock(int i, ValueNode lock) {
-        lockedObjects[i] = lock;
-    }
-
-    /**
      * Loads the local variable at the specified index, checking that the returned value is non-null
      * and that two-stack values are properly handled.
      *
      * @param i the index of the local variable to load
+     * @param slotKind the kind of the local variable from the point of view of the bytecodes
      * @return the instruction that produced the specified local
      */
-    public ValueNode loadLocal(int i) {
+    public ValueNode loadLocal(int i, Kind slotKind) {
+        assert slotKind.getSlotCount() > 0;
+        assert slotKind.getSlotCount() == 1 || locals[i + 1] == null;
+
         ValueNode x = locals[i];
-        assert assertLoadLocal(i, x);
-        return x;
-    }
-
-    private boolean assertLoadLocal(int i, ValueNode x) {
         assert x != null : i;
-        assert parser.parsingIntrinsic() || (x.getKind().getSlotCount() == 1 || locals[i + 1] == null);
-        assert parser.parsingIntrinsic() || (i == 0 || locals[i - 1] == null || locals[i - 1].getKind().getSlotCount() == 1);
-        return true;
-    }
-
-    public void storeLocal(int i, ValueNode x) {
-        storeLocal(i, x, x == null ? null : x.getKind());
+        return x;
     }
 
     /**
@@ -636,223 +587,69 @@
      * the next local variable index is also overwritten.
      *
      * @param i the index at which to store
+     * @param slotKind the kind of the local variable from the point of view of the bytecodes
      * @param x the instruction which produces the value for the local
      */
-    public void storeLocal(int i, ValueNode x, Kind kind) {
-        assert assertStoreLocal(x);
+    public void storeLocal(int i, Kind slotKind, ValueNode x) {
+        assert slotKind.getSlotCount() > 0;
+
         locals[i] = x;
-        if (x != null) {
-            if (kind.needsTwoSlots() && !parser.parsingIntrinsic()) {
-                // if this is a double word, then kill i+1
-                locals[i + 1] = null;
-            }
-            if (i > 0 && !parser.parsingIntrinsic()) {
-                ValueNode p = locals[i - 1];
-                if (p != null && p.getKind().needsTwoSlots()) {
-                    // if there was a double word at i - 1, then kill it
-                    locals[i - 1] = null;
-                }
-            }
+        if (slotKind.needsTwoSlots()) {
+            locals[i + 1] = null;
         }
     }
 
-    private boolean assertStoreLocal(ValueNode x) {
-        assert x == null || parser.parsingIntrinsic() || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal) : "unexpected value: " + x;
-        return true;
-    }
-
-    public void storeStack(int i, ValueNode x) {
-        assert assertStoreStack(i, x);
-        stack[i] = x;
-    }
-
-    private boolean assertStoreStack(int i, ValueNode x) {
-        assert x == null || (stack[i] == null || x.getKind() == stack[i].getKind()) : "Method does not handle changes from one-slot to two-slot values or non-alive values";
-        return true;
-    }
-
     /**
      * Pushes an instruction onto the stack with the expected type.
      *
-     * @param kind the type expected for this instruction
+     * @param slotKind the kind of the stack element from the point of view of the bytecodes
      * @param x the instruction to push onto the stack
      */
-    public void push(Kind kind, ValueNode x) {
-        assert assertPush(kind, x);
+    public void push(Kind slotKind, ValueNode x) {
+        assert x != null;
+        assert slotKind.getSlotCount() > 0;
         xpush(x);
-        if (kind.needsTwoSlots()) {
+        if (slotKind.needsTwoSlots()) {
             xpush(null);
         }
     }
 
-    private boolean assertPush(Kind kind, ValueNode x) {
-        assert parser.parsingIntrinsic() || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal);
-        assert x != null && (parser.parsingIntrinsic() || x.getKind() == kind);
-        return true;
-    }
-
-    /**
-     * Pushes a value onto the stack without checking the type.
-     *
-     * @param x the instruction to push onto the stack
-     */
-    public void xpush(ValueNode x) {
-        assert assertXpush(x);
-        stack[stackSize++] = x;
-    }
-
-    private boolean assertXpush(ValueNode x) {
-        assert parser.parsingIntrinsic() || (x == null || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal));
-        return true;
-    }
-
-    /**
-     * Pushes a value onto the stack and checks that it is an int.
-     *
-     * @param x the instruction to push onto the stack
-     */
-    public void ipush(ValueNode x) {
-        assert assertInt(x);
-        xpush(x);
-    }
-
-    /**
-     * Pushes a value onto the stack and checks that it is a float.
-     *
-     * @param x the instruction to push onto the stack
-     */
-    public void fpush(ValueNode x) {
-        assert assertFloat(x);
-        xpush(x);
-    }
-
-    /**
-     * Pushes a value onto the stack and checks that it is an object.
-     *
-     * @param x the instruction to push onto the stack
-     */
-    public void apush(ValueNode x) {
-        assert assertObject(x);
-        xpush(x);
-    }
-
-    /**
-     * Pushes a value onto the stack and checks that it is a long.
-     *
-     * @param x the instruction to push onto the stack
-     */
-    public void lpush(ValueNode x) {
-        assert assertLong(x);
-        xpush(x);
-        xpush(null);
-    }
-
-    /**
-     * Pushes a value onto the stack and checks that it is a double.
-     *
-     * @param x the instruction to push onto the stack
-     */
-    public void dpush(ValueNode x) {
-        assert assertDouble(x);
-        xpush(x);
-        xpush(null);
-    }
-
-    public void pushReturn(Kind kind, ValueNode x) {
-        if (kind != Kind.Void) {
-            push(kind.getStackKind(), x);
+    public void pushReturn(Kind slotKind, ValueNode x) {
+        if (slotKind != Kind.Void) {
+            push(slotKind, x);
         }
     }
 
     /**
      * Pops an instruction off the stack with the expected type.
      *
-     * @param kind the expected type
+     * @param slotKind the kind of the stack element from the point of view of the bytecodes
      * @return the instruction on the top of the stack
      */
-    public ValueNode pop(Kind kind) {
-        if (kind.needsTwoSlots()) {
-            xpop();
+    public ValueNode pop(Kind slotKind) {
+        assert slotKind.getSlotCount() > 0;
+        if (slotKind.needsTwoSlots()) {
+            ValueNode s = xpop();
+            assert s == null;
         }
-        assert assertPop(kind);
-        return xpop();
+        ValueNode x = xpop();
+        assert x != null;
+        return x;
     }
 
-    private boolean assertPop(Kind kind) {
-        assert kind != Kind.Void;
-        ValueNode x = xpeek();
-        assert x != null && (parser.parsingIntrinsic() || x.getKind() == kind);
-        return true;
+    private void xpush(ValueNode x) {
+        stack[stackSize++] = x;
     }
 
-    /**
-     * Pops a value off of the stack without checking the type.
-     *
-     * @return x the instruction popped off the stack
-     */
-    public ValueNode xpop() {
+    private ValueNode xpop() {
         return stack[--stackSize];
     }
 
-    public ValueNode xpeek() {
+    private ValueNode xpeek() {
         return stack[stackSize - 1];
     }
 
     /**
-     * Pops a value off of the stack and checks that it is an int.
-     *
-     * @return x the instruction popped off the stack
-     */
-    public ValueNode ipop() {
-        assert assertIntPeek();
-        return xpop();
-    }
-
-    /**
-     * Pops a value off of the stack and checks that it is a float.
-     *
-     * @return x the instruction popped off the stack
-     */
-    public ValueNode fpop() {
-        assert assertFloatPeek();
-        return xpop();
-    }
-
-    /**
-     * Pops a value off of the stack and checks that it is an object.
-     *
-     * @return x the instruction popped off the stack
-     */
-    public ValueNode apop() {
-        assert assertObjectPeek();
-        return xpop();
-    }
-
-    /**
-     * Pops a value off of the stack and checks that it is a long.
-     *
-     * @return x the instruction popped off the stack
-     */
-    public ValueNode lpop() {
-        assert assertHighPeek();
-        xpop();
-        assert assertLongPeek();
-        return xpop();
-    }
-
-    /**
-     * Pops a value off of the stack and checks that it is a double.
-     *
-     * @return x the instruction popped off the stack
-     */
-    public ValueNode dpop() {
-        assert assertHighPeek();
-        xpop();
-        assert assertDoublePeek();
-        return xpop();
-    }
-
-    /**
      * Pop the specified number of slots off of this stack and return them as an array of
      * instructions.
      *
@@ -866,9 +663,6 @@
             if (stack[newStackSize] == null) {
                 /* Two-slot value. */
                 newStackSize--;
-                assert stack[newStackSize].getKind().needsTwoSlots();
-            } else {
-                assert parser.parsingIntrinsic() || (stack[newStackSize].getKind().getSlotCount() == 1);
             }
             result[i] = stack[newStackSize];
         }
@@ -877,80 +671,93 @@
     }
 
     /**
-     * Peeks an element from the operand stack.
-     *
-     * @param argumentNumber The number of the argument, relative from the top of the stack (0 =
-     *            top). Long and double arguments only count as one argument, i.e., null-slots are
-     *            ignored.
-     * @return The peeked argument.
-     */
-    public ValueNode peek(int argumentNumber) {
-        int idx = stackSize() - 1;
-        for (int i = 0; i < argumentNumber; i++) {
-            if (stackAt(idx) == null) {
-                idx--;
-                assert stackAt(idx).getKind().needsTwoSlots();
-            }
-            idx--;
-        }
-        return stackAt(idx);
-    }
-
-    /**
      * Clears all values on this stack.
      */
     public void clearStack() {
         stackSize = 0;
     }
 
-    private boolean assertLongPeek() {
-        return assertLong(xpeek());
-    }
-
-    private static boolean assertLong(ValueNode x) {
-        assert x != null && (x.getKind() == Kind.Long);
-        return true;
-    }
-
-    private boolean assertIntPeek() {
-        return assertInt(xpeek());
-    }
-
-    private static boolean assertInt(ValueNode x) {
-        assert x != null && (x.getKind() == Kind.Int);
-        return true;
-    }
-
-    private boolean assertFloatPeek() {
-        return assertFloat(xpeek());
-    }
-
-    private static boolean assertFloat(ValueNode x) {
-        assert x != null && (x.getKind() == Kind.Float);
-        return true;
-    }
-
-    private boolean assertObjectPeek() {
-        return assertObject(xpeek());
-    }
-
-    private boolean assertObject(ValueNode x) {
-        assert x != null && (parser.parsingIntrinsic() || (x.getKind() == Kind.Object));
-        return true;
-    }
-
-    private boolean assertDoublePeek() {
-        return assertDouble(xpeek());
-    }
-
-    private static boolean assertDouble(ValueNode x) {
-        assert x != null && (x.getKind() == Kind.Double);
-        return true;
-    }
-
-    private boolean assertHighPeek() {
-        assert xpeek() == null;
-        return true;
+    /**
+     * Performs a raw stack operation as defined in the Java bytecode specification.
+     *
+     * @param opcode The Java bytecode.
+     */
+    public void stackOp(int opcode) {
+        switch (opcode) {
+            case POP: {
+                xpop();
+                break;
+            }
+            case POP2: {
+                xpop();
+                xpop();
+                break;
+            }
+            case DUP: {
+                xpush(xpeek());
+                break;
+            }
+            case DUP_X1: {
+                ValueNode w1 = xpop();
+                ValueNode w2 = xpop();
+                xpush(w1);
+                xpush(w2);
+                xpush(w1);
+                break;
+            }
+            case DUP_X2: {
+                ValueNode w1 = xpop();
+                ValueNode w2 = xpop();
+                ValueNode w3 = xpop();
+                xpush(w1);
+                xpush(w3);
+                xpush(w2);
+                xpush(w1);
+                break;
+            }
+            case DUP2: {
+                ValueNode w1 = xpop();
+                ValueNode w2 = xpop();
+                xpush(w2);
+                xpush(w1);
+                xpush(w2);
+                xpush(w1);
+                break;
+            }
+            case DUP2_X1: {
+                ValueNode w1 = xpop();
+                ValueNode w2 = xpop();
+                ValueNode w3 = xpop();
+                xpush(w2);
+                xpush(w1);
+                xpush(w3);
+                xpush(w2);
+                xpush(w1);
+                break;
+            }
+            case DUP2_X2: {
+                ValueNode w1 = xpop();
+                ValueNode w2 = xpop();
+                ValueNode w3 = xpop();
+                ValueNode w4 = xpop();
+                xpush(w2);
+                xpush(w1);
+                xpush(w4);
+                xpush(w3);
+                xpush(w2);
+                xpush(w1);
+                break;
+            }
+            case SWAP: {
+                ValueNode w1 = xpop();
+                ValueNode w2 = xpop();
+                xpush(w1);
+                xpush(w2);
+                break;
+            }
+            default:
+                throw shouldNotReachHere();
+        }
     }
 
     @Override
@@ -1007,19 +814,6 @@
         return false;
     }
 
-    public void replace(ValueNode oldValue, ValueNode newValue) {
-        for (int i = 0; i < locals.length; i++) {
-            if (locals[i] == oldValue) {
-                locals[i] = newValue;
-            }
-        }
-        for (int i = 0; i < stackSize; i++) {
-            if (stack[i] == oldValue) {
-                stack[i] = newValue;
-            }
-        }
-    }
-
     @Override
     public boolean isAfterSideEffect() {
         return sideEffects != null;
@@ -1039,4 +833,16 @@
         }
         sideEffects.add(sideEffect);
     }
+
+    public void traceState() {
+        Debug.log(String.format("|   state [nr locals = %d, stack depth = %d, method = %s]", localsSize(), stackSize(), method));
+        for (int i = 0; i < localsSize(); ++i) {
+            ValueNode value = locals[i];
+            Debug.log(String.format("|   local[%d] = %-8s : %s", i, value == null ? "bogus" : value.getKind().getJavaName(), value));
+        }
+        for (int i = 0; i < stackSize(); ++i) {
+            ValueNode value = stack[i];
+            Debug.log(String.format("|   stack[%d] = %-8s : %s", i, value == null ? "bogus" : value.getKind().getJavaName(), value));
+        }
+    }
 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Fri May 29 01:11:41 2015 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Thu May 28 17:00:59 2015 -0700
@@ -235,11 +235,11 @@
          * @param parser the parsing context of the (non-intrinsic) method calling the intrinsic
          * @param args the arguments to the call
          */
-        public IntrinsicScope(BytecodeParser parser, ValueNode[] args) {
+        public IntrinsicScope(BytecodeParser parser, Kind[] argSlotKinds, ValueNode[] args) {
             assert !parser.parsingIntrinsic();
             this.parser = parser;
             mark = parser.getGraph().getMark();
-            stateBefore = parser.frameState.create(parser.bci(), parser.getNonIntrinsicAncestor(), false, args);
+            stateBefore = parser.frameState.create(parser.bci(), parser.getNonIntrinsicAncestor(), false, argSlotKinds, args);
         }
 
         public void close() {
@@ -273,11 +273,13 @@
                                  * Swap the top-of-stack value with the side-effect return value
                                  * using the frame state.
                                  */
-                                ValueNode tos = frameStateBuilder.pop(returnVal.getKind());
+                                Kind returnKind = parser.currentInvokeReturnType.getKind();
+                                ValueNode tos = frameStateBuilder.pop(returnKind);
                                 assert tos.getKind() == returnVal.getKind();
-                                FrameState newFrameState = frameStateBuilder.create(parser.stream.nextBCI(), parser.getNonIntrinsicAncestor(), false, returnVal);
+                                FrameState newFrameState = frameStateBuilder.create(parser.stream.nextBCI(), parser.getNonIntrinsicAncestor(), false, new Kind[]{returnKind},
+                                                new ValueNode[]{returnVal});
                                 frameState.replaceAndDelete(newFrameState);
-                                frameStateBuilder.push(tos.getKind(), tos);
+                                frameStateBuilder.push(returnKind, tos);
                             } else {
                                 if (stateAfterReturn == null) {
                                     if (intrinsic != null) {
@@ -625,9 +627,9 @@
              */
             private FrameState createStateAfterStartOfReplacementGraph() {
                 assert parent == null;
-                assert frameState.method.equals(intrinsicContext.getIntrinsicMethod());
+                assert frameState.getMethod().equals(intrinsicContext.getIntrinsicMethod());
                 assert bci() == 0;
-                assert frameState.stackSize == 0;
+                assert frameState.stackSize() == 0;
                 FrameState stateAfterStart;
                 if (intrinsicContext.isPostParseInlined()) {
                     stateAfterStart = graph.add(new FrameState(BytecodeFrame.BEFORE_BCI));
@@ -899,7 +901,7 @@
             protected void handleUnresolvedCheckCast(JavaType type, ValueNode object) {
                 assert !graphBuilderConfig.eagerResolving();
                 append(new FixedGuardNode(graph.unique(new IsNullNode(object)), Unresolved, InvalidateRecompile));
-                frameState.apush(appendConstant(JavaConstant.NULL_POINTER));
+                frameState.push(Kind.Object, appendConstant(JavaConstant.NULL_POINTER));
             }
 
             /**
@@ -912,7 +914,7 @@
                 DeoptimizeNode deopt = graph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved));
                 append(new IfNode(graph.unique(new IsNullNode(object)), successor, deopt, 1));
                 lastInstr = successor;
-                frameState.ipush(appendConstant(JavaConstant.INT_0));
+                frameState.push(Kind.Int, appendConstant(JavaConstant.INT_0));
             }
 
             /**
@@ -999,12 +1001,12 @@
                 DispatchBeginNode dispatchBegin;
                 if (exceptionObject == null) {
                     dispatchBegin = graph.add(new ExceptionObjectNode(metaAccess));
-                    dispatchState.apush(dispatchBegin);
+                    dispatchState.push(Kind.Object, dispatchBegin);
                     dispatchState.setRethrowException(true);
                     dispatchBegin.setStateAfter(dispatchState.create(bci, dispatchBegin));
                 } else {
                     dispatchBegin = graph.add(new DispatchBeginNode());
-                    dispatchState.apush(exceptionObject);
+                    dispatchState.push(Kind.Object, exceptionObject);
                     dispatchBegin.setStateAfter(dispatchState.create(bci, dispatchBegin));
                     dispatchState.setRethrowException(true);
                 }
@@ -1137,7 +1139,7 @@
             }
 
             protected void genThrow() {
-                ValueNode exception = frameState.apop();
+                ValueNode exception = frameState.pop(Kind.Object);
                 append(new FixedGuardNode(graph.unique(new IsNullNode(exception)), NullCheckException, InvalidateReprofile, true));
                 lastInstr.setNext(handleException(exception, bci()));
             }
@@ -1250,7 +1252,7 @@
                 if (target instanceof ResolvedJavaMethod) {
                     JavaConstant appendix = constantPool.lookupAppendix(stream.readCPI4(), Bytecodes.INVOKEDYNAMIC);
                     if (appendix != null) {
-                        frameState.apush(ConstantNode.forConstant(appendix, metaAccess, graph));
+                        frameState.push(Kind.Object, ConstantNode.forConstant(appendix, metaAccess, graph));
                     }
                     ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(false));
                     appendInvoke(InvokeKind.Static, (ResolvedJavaMethod) target, args);
@@ -1271,7 +1273,7 @@
                     boolean hasReceiver = !((ResolvedJavaMethod) target).isStatic();
                     JavaConstant appendix = constantPool.lookupAppendix(stream.readCPI(), Bytecodes.INVOKEVIRTUAL);
                     if (appendix != null) {
-                        frameState.apush(ConstantNode.forConstant(appendix, metaAccess, graph));
+                        frameState.push(Kind.Object, ConstantNode.forConstant(appendix, metaAccess, graph));
                     }
                     ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(hasReceiver));
                     if (hasReceiver) {
@@ -1325,7 +1327,7 @@
                 ResolvedJavaMethod targetMethod = initialTargetMethod;
                 InvokeKind invokeKind = initialInvokeKind;
                 if (initialInvokeKind.isIndirect()) {
-                    ResolvedJavaType contextType = this.frameState.method.getDeclaringClass();
+                    ResolvedJavaType contextType = this.frameState.getMethod().getDeclaringClass();
                     ResolvedJavaMethod specialCallTarget = MethodCallTargetNode.findSpecialCallTarget(initialInvokeKind, args[0], initialTargetMethod, contextType);
                     if (specialCallTarget != null) {
                         invokeKind = InvokeKind.Special;
@@ -1428,7 +1430,7 @@
                     this.targetMethod = targetMethod;
                     this.args = args;
                     this.resultType = resultType;
-                    this.beforeStackSize = frameState.stackSize;
+                    this.beforeStackSize = frameState.stackSize();
                     this.needsNullCheck = !targetMethod.isStatic() && args[0].getKind() == Kind.Object && !StampTool.isPointerNonNull(args[0].stamp());
                     this.nodeCount = graph.getNodeCount();
                     this.mark = graph.getMark();
@@ -1441,7 +1443,7 @@
                 boolean check(boolean pluginResult) {
                     if (pluginResult == true) {
                         int expectedStackSize = beforeStackSize + resultType.getSlotCount();
-                        assert expectedStackSize == frameState.stackSize : error("plugin manipulated the stack incorrectly: expected=%d, actual=%d", expectedStackSize, frameState.stackSize);
+                        assert expectedStackSize == frameState.stackSize() : error("plugin manipulated the stack incorrectly: expected=%d, actual=%d", expectedStackSize, frameState.stackSize());
                         NodeIterable<Node> newNodes = graph.getNewNodes(mark);
                         assert !needsNullCheck || isPointerNonNull(args[0].stamp()) : error("plugin needs to null check the receiver of %s: receiver=%s", targetMethod.format("%H.%n(%p)"), args[0]);
                         for (Node n : newNodes) {
@@ -1458,7 +1460,7 @@
                         }
                     } else {
                         assert nodeCount == graph.getNodeCount() : error("plugin that returns false must not create new nodes");
-                        assert beforeStackSize == frameState.stackSize : error("plugin that returns false must modify the stack");
+                        assert beforeStackSize == frameState.stackSize() : error("plugin that returns false must not modify the stack");
                     }
                     return true;
                 }
@@ -1586,7 +1588,8 @@
             }
 
             private void parseAndInlineCallee(ResolvedJavaMethod targetMethod, ValueNode[] args, IntrinsicContext calleeIntrinsicContext) {
-                try (IntrinsicScope s = calleeIntrinsicContext != null && !parsingIntrinsic() ? new IntrinsicScope(this, args) : null) {
+                try (IntrinsicScope s = calleeIntrinsicContext != null && !parsingIntrinsic() ? new IntrinsicScope(this, targetMethod.getSignature().toParameterKinds(!targetMethod.isStatic()), args)
+                                : null) {
 
                     BytecodeParser parser = new BytecodeParser(this, metaAccess, targetMethod, graphBuilderConfig, optimisticOpts, INVOCATION_ENTRY_BCI, calleeIntrinsicContext);
                     FrameStateBuilder startFrameState = new FrameStateBuilder(parser, targetMethod, graph);
@@ -1695,7 +1698,7 @@
 
             private void beforeReturn(ValueNode x, Kind kind) {
                 if (graph.method() != null && graph.method().isJavaLangObjectInit()) {
-                    append(new RegisterFinalizerNode(frameState.localAt(0)));
+                    append(new RegisterFinalizerNode(frameState.loadLocal(0, Kind.Object)));
                 }
                 if (graphBuilderConfig.insertNonSafepointDebugInfo() && !parsingIntrinsic()) {
                     append(createInfoPointNode(InfopointReason.METHOD_END));
@@ -1736,13 +1739,13 @@
                     throw new JsrNotSupportedBailout("unstructured control flow (internal limitation)");
                 }
                 ConstantNode nextBciNode = getJsrConstant(nextBci);
-                frameState.push(Kind.Int, nextBciNode);
+                frameState.push(Kind.Object, nextBciNode);
                 appendGoto(successor);
             }
 
             protected void genRet(int localIndex) {
                 BciBlock successor = currentBlock.getRetSuccessor();
-                ValueNode local = frameState.loadLocal(localIndex);
+                ValueNode local = frameState.loadLocal(localIndex, Kind.Object);
                 JsrScope scope = currentBlock.getJsrScope();
                 int retAddress = scope.nextReturnAddress();
                 ConstantNode returnBciNode = getJsrConstant(retAddress);
@@ -2150,7 +2153,7 @@
                 if (target.isStatic()) {
                     return appendConstant(target.getDeclaringClass().getJavaClass());
                 } else {
-                    return state.loadLocal(0);
+                    return state.loadLocal(0, Kind.Object);
                 }
             }
 
@@ -2191,7 +2194,7 @@
                     frameState.setRethrowException(false);
                     createUnwind();
                 } else {
-                    ValueNode exception = frameState.apop();
+                    ValueNode exception = frameState.pop(Kind.Object);
                     this.unwindValue = exception;
                     this.beforeUnwindNode = this.lastInstr;
                 }
@@ -2219,7 +2222,7 @@
 
             private void createUnwind() {
                 assert frameState.stackSize() == 1 : frameState;
-                ValueNode exception = frameState.apop();
+                ValueNode exception = frameState.pop(Kind.Object);
                 synchronizedEpilogue(BytecodeFrame.AFTER_EXCEPTION_BCI, null, null);
                 append(new UnwindNode(exception));
             }
@@ -2252,7 +2255,7 @@
                     for (ResolvedJavaType skippedType : graphBuilderConfig.getSkippedExceptionTypes()) {
                         if (skippedType.isAssignableFrom(resolvedCatchType)) {
                             BciBlock nextBlock = block.getSuccessorCount() == 1 ? blockMap.getUnwindBlock() : block.getSuccessor(1);
-                            ValueNode exception = frameState.stackAt(0);
+                            ValueNode exception = frameState.stack[0];
                             FixedNode trueSuccessor = graph.add(new DeoptimizeNode(InvalidateReprofile, UnreachedCode));
                             FixedNode nextDispatch = createTarget(nextBlock, frameState);
                             append(new IfNode(graph.unique(new InstanceOfNode((ResolvedJavaType) catchType, exception, null)), trueSuccessor, nextDispatch, 0));
@@ -2263,12 +2266,12 @@
 
                 if (initialized) {
                     BciBlock nextBlock = block.getSuccessorCount() == 1 ? blockMap.getUnwindBlock() : block.getSuccessor(1);
-                    ValueNode exception = frameState.stackAt(0);
+                    ValueNode exception = frameState.stack[0];
                     CheckCastNode checkCast = graph.add(new CheckCastNode((ResolvedJavaType) catchType, exception, null, false));
-                    frameState.apop();
+                    frameState.pop(Kind.Object);
                     frameState.push(Kind.Object, checkCast);
                     FixedNode catchSuccessor = createTarget(block.getSuccessor(0), frameState);
-                    frameState.apop();
+                    frameState.pop(Kind.Object);
                     frameState.push(Kind.Object, exception);
                     FixedNode nextDispatch = createTarget(nextBlock, frameState);
                     checkCast.setNext(catchSuccessor);
@@ -2435,24 +2438,13 @@
 
             private boolean traceState() {
                 if (Debug.isEnabled() && Options.TraceBytecodeParserLevel.getValue() >= TRACELEVEL_STATE && Debug.isLogEnabled()) {
-                    traceStateHelper();
+                    frameState.traceState();
                 }
                 return true;
             }
 
-            private void traceStateHelper() {
-                Debug.log(String.format("|   state [nr locals = %d, stack depth = %d, method = %s]", frameState.localsSize(), frameState.stackSize(), method));
-                for (int i = 0; i < frameState.localsSize(); ++i) {
-                    ValueNode value = frameState.localAt(i);
-                    Debug.log(String.format("|   local[%d] = %-8s : %s", i, value == null ? "bogus" : value.getKind().getJavaName(), value));
-                }
-                for (int i = 0; i < frameState.stackSize(); ++i) {
-                    ValueNode value = frameState.stackAt(i);
-                    Debug.log(String.format("|   stack[%d] = %-8s : %s", i, value == null ? "bogus" : value.getKind().getJavaName(), value));
-                }
-            }
-
             protected void genIf(ValueNode x, Condition cond, ValueNode y) {
+                assert x.getKind().getStackKind() == y.getKind().getStackKind();
                 assert currentBlock.getSuccessorCount() == 2;
                 BciBlock trueBlock = currentBlock.getSuccessor(0);
                 BciBlock falseBlock = currentBlock.getSuccessor(1);
@@ -2628,10 +2620,9 @@
                 return metaAccess;
             }
 
-            public void push(Kind kind, ValueNode value) {
+            public void push(Kind slotKind, ValueNode value) {
                 assert value.isAlive();
-                assert kind == kind.getStackKind();
-                frameState.push(kind, value);
+                frameState.push(slotKind, value);
             }
 
             private int getCurrentDimension() {
@@ -2715,19 +2706,13 @@
             }
 
             public void loadLocal(int index, Kind kind) {
-                frameState.push(kind, frameState.loadLocal(index));
+                ValueNode value = frameState.loadLocal(index, kind);
+                frameState.push(kind, value);
             }
 
             public void storeLocal(Kind kind, int index) {
-                ValueNode value;
-                if (kind == Kind.Object) {
-                    value = frameState.xpop();
-                    // astore and astore_<n> may be used to store a returnAddress (jsr)
-                    assert parsingIntrinsic() || (value.getKind() == Kind.Object || value.getKind() == Kind.Int) : value + ":" + value.getKind();
-                } else {
-                    value = frameState.pop(kind);
-                }
-                frameState.storeLocal(index, value, kind);
+                ValueNode value = frameState.pop(kind);
+                frameState.storeLocal(index, kind, value);
             }
 
             private void genLoadConstant(int cpi, int opcode) {
@@ -2743,17 +2728,17 @@
                     }
                 } else if (con instanceof JavaConstant) {
                     JavaConstant constant = (JavaConstant) con;
-                    frameState.push(constant.getKind().getStackKind(), appendConstant(constant));
+                    frameState.push(constant.getKind(), appendConstant(constant));
                 } else {
                     throw new Error("lookupConstant returned an object of incorrect type");
                 }
             }
 
             private void genLoadIndexed(Kind kind) {
-                ValueNode index = frameState.ipop();
-                ValueNode array = emitExplicitExceptions(frameState.apop(), index);
+                ValueNode index = frameState.pop(Kind.Int);
+                ValueNode array = emitExplicitExceptions(frameState.pop(Kind.Object), index);
                 if (!tryLoadIndexedPlugin(kind, index, array)) {
-                    frameState.push(kind.getStackKind(), append(genLoadIndexed(array, index, kind)));
+                    frameState.push(kind, append(genLoadIndexed(array, index, kind)));
                 }
             }
 
@@ -2770,80 +2755,15 @@
             }
 
             private void genStoreIndexed(Kind kind) {
-                ValueNode value = frameState.pop(kind.getStackKind());
-                ValueNode index = frameState.ipop();
-                ValueNode array = emitExplicitExceptions(frameState.apop(), index);
+                ValueNode value = frameState.pop(kind);
+                ValueNode index = frameState.pop(Kind.Int);
+                ValueNode array = emitExplicitExceptions(frameState.pop(Kind.Object), index);
                 genStoreIndexed(array, index, kind, value);
             }
 
-            private void stackOp(int opcode) {
-                switch (opcode) {
-                    case DUP_X1: {
-                        ValueNode w1 = frameState.xpop();
-                        ValueNode w2 = frameState.xpop();
-                        frameState.xpush(w1);
-                        frameState.xpush(w2);
-                        frameState.xpush(w1);
-                        break;
-                    }
-                    case DUP_X2: {
-                        ValueNode w1 = frameState.xpop();
-                        ValueNode w2 = frameState.xpop();
-                        ValueNode w3 = frameState.xpop();
-                        frameState.xpush(w1);
-                        frameState.xpush(w3);
-                        frameState.xpush(w2);
-                        frameState.xpush(w1);
-                        break;
-                    }
-                    case DUP2: {
-                        ValueNode w1 = frameState.xpop();
-                        ValueNode w2 = frameState.xpop();
-                        frameState.xpush(w2);
-                        frameState.xpush(w1);
-                        frameState.xpush(w2);
-                        frameState.xpush(w1);
-                        break;
-                    }
-                    case DUP2_X1: {
-                        ValueNode w1 = frameState.xpop();
-                        ValueNode w2 = frameState.xpop();
-                        ValueNode w3 = frameState.xpop();
-                        frameState.xpush(w2);
-                        frameState.xpush(w1);
-                        frameState.xpush(w3);
-                        frameState.xpush(w2);
-                        frameState.xpush(w1);
-                        break;
-                    }
-                    case DUP2_X2: {
-                        ValueNode w1 = frameState.xpop();
-                        ValueNode w2 = frameState.xpop();
-                        ValueNode w3 = frameState.xpop();
-                        ValueNode w4 = frameState.xpop();
-                        frameState.xpush(w2);
-                        frameState.xpush(w1);
-                        frameState.xpush(w4);
-                        frameState.xpush(w3);
-                        frameState.xpush(w2);
-                        frameState.xpush(w1);
-                        break;
-                    }
-                    case SWAP: {
-                        ValueNode w1 = frameState.xpop();
-                        ValueNode w2 = frameState.xpop();
-                        frameState.xpush(w1);
-                        frameState.xpush(w2);
-                        break;
-                    }
-                    default:
-                        throw JVMCIError.shouldNotReachHere();
-                }
-            }
-
-            private void genArithmeticOp(Kind result, int opcode) {
-                ValueNode y = frameState.pop(result);
-                ValueNode x = frameState.pop(result);
+            private void genArithmeticOp(Kind kind, int opcode) {
+                ValueNode y = frameState.pop(kind);
+                ValueNode x = frameState.pop(kind);
                 ValueNode v;
                 switch (opcode) {
                     case IADD:
@@ -2879,14 +2799,14 @@
                         v = genFloatRem(x, y);
                         break;
                     default:
-                        throw new JVMCIError("should not reach");
+                        throw shouldNotReachHere();
                 }
-                frameState.push(result, append(v));
+                frameState.push(kind, append(v));
             }
 
-            private void genIntegerDivOp(Kind result, int opcode) {
-                ValueNode y = frameState.pop(result);
-                ValueNode x = frameState.pop(result);
+            private void genIntegerDivOp(Kind kind, int opcode) {
+                ValueNode y = frameState.pop(kind);
+                ValueNode x = frameState.pop(kind);
                 ValueNode v;
                 switch (opcode) {
                     case IDIV:
@@ -2898,17 +2818,18 @@
                         v = genIntegerRem(x, y);
                         break;
                     default:
-                        throw new JVMCIError("should not reach");
+                        throw shouldNotReachHere();
                 }
-                frameState.push(result, append(v));
+                frameState.push(kind, append(v));
             }
 
             private void genNegateOp(Kind kind) {
-                frameState.push(kind, append(genNegateOp(frameState.pop(kind))));
+                ValueNode x = frameState.pop(kind);
+                frameState.push(kind, append(genNegateOp(x)));
             }
 
             private void genShiftOp(Kind kind, int opcode) {
-                ValueNode s = frameState.ipop();
+                ValueNode s = frameState.pop(Kind.Int);
                 ValueNode x = frameState.pop(kind);
                 ValueNode v;
                 switch (opcode) {
@@ -2925,7 +2846,7 @@
                         v = genUnsignedRightShift(x, s);
                         break;
                     default:
-                        throw new JVMCIError("should not reach");
+                        throw shouldNotReachHere();
                 }
                 frameState.push(kind, append(v));
             }
@@ -2948,7 +2869,7 @@
                         v = genXor(x, y);
                         break;
                     default:
-                        throw new JVMCIError("should not reach");
+                        throw shouldNotReachHere();
                 }
                 frameState.push(kind, append(v));
             }
@@ -2956,52 +2877,52 @@
             private void genCompareOp(Kind kind, boolean isUnorderedLess) {
                 ValueNode y = frameState.pop(kind);
                 ValueNode x = frameState.pop(kind);
-                frameState.ipush(append(genNormalizeCompare(x, y, isUnorderedLess)));
+                frameState.push(Kind.Int, append(genNormalizeCompare(x, y, isUnorderedLess)));
             }
 
             private void genFloatConvert(FloatConvert op, Kind from, Kind to) {
-                ValueNode input = frameState.pop(from.getStackKind());
-                frameState.push(to.getStackKind(), append(genFloatConvert(op, input)));
+                ValueNode input = frameState.pop(from);
+                frameState.push(to, append(genFloatConvert(op, input)));
             }
 
             private void genSignExtend(Kind from, Kind to) {
-                ValueNode input = frameState.pop(from.getStackKind());
+                ValueNode input = frameState.pop(from);
                 if (from != from.getStackKind()) {
                     input = append(genNarrow(input, from.getBitCount()));
                 }
-                frameState.push(to.getStackKind(), append(genSignExtend(input, to.getBitCount())));
+                frameState.push(to, append(genSignExtend(input, to.getBitCount())));
             }
 
             private void genZeroExtend(Kind from, Kind to) {
-                ValueNode input = frameState.pop(from.getStackKind());
+                ValueNode input = frameState.pop(from);
                 if (from != from.getStackKind()) {
                     input = append(genNarrow(input, from.getBitCount()));
                 }
-                frameState.push(to.getStackKind(), append(genZeroExtend(input, to.getBitCount())));
+                frameState.push(to, append(genZeroExtend(input, to.getBitCount())));
             }
 
             private void genNarrow(Kind from, Kind to) {
-                ValueNode input = frameState.pop(from.getStackKind());
-                frameState.push(to.getStackKind(), append(genNarrow(input, to.getBitCount())));
+                ValueNode input = frameState.pop(from);
+                frameState.push(to, append(genNarrow(input, to.getBitCount())));
             }
 
             private void genIncrement() {
                 int index = getStream().readLocalIndex();
                 int delta = getStream().readIncrement();
-                ValueNode x = frameState.loadLocal(index);
+                ValueNode x = frameState.loadLocal(index, Kind.Int);
                 ValueNode y = appendConstant(JavaConstant.forInt(delta));
-                frameState.storeLocal(index, append(genIntegerAdd(x, y)));
+                frameState.storeLocal(index, Kind.Int, append(genIntegerAdd(x, y)));
             }
 
             private void genIfZero(Condition cond) {
                 ValueNode y = appendConstant(JavaConstant.INT_0);
-                ValueNode x = frameState.ipop();
+                ValueNode x = frameState.pop(Kind.Int);
                 genIf(x, cond, y);
             }
 
             private void genIfNull(Condition cond) {
                 ValueNode y = appendConstant(JavaConstant.NULL_POINTER);
-                ValueNode x = frameState.apop();
+                ValueNode x = frameState.pop(Kind.Object);
                 genIf(x, cond, y);
             }
 
@@ -3063,7 +2984,7 @@
             private void genCheckCast() {
                 int cpi = getStream().readCPI();
                 JavaType type = lookupType(cpi, CHECKCAST);
-                ValueNode object = frameState.apop();
+                ValueNode object = frameState.pop(Kind.Object);
                 if (type instanceof ResolvedJavaType) {
                     ResolvedJavaType resolvedType = (ResolvedJavaType) type;
                     JavaTypeProfile profile = getProfileForTypeCheck(resolvedType);
@@ -3089,7 +3010,7 @@
                         if (checkCastNode == null) {
                             checkCastNode = append(createCheckCast(resolvedType, object, profile, false));
                         }
-                        frameState.apush(checkCastNode);
+                        frameState.push(Kind.Object, checkCastNode);
                     }
                 } else {
                     handleUnresolvedCheckCast(type, object);
@@ -3099,7 +3020,7 @@
             private void genInstanceOf() {
                 int cpi = getStream().readCPI();
                 JavaType type = lookupType(cpi, INSTANCEOF);
-                ValueNode object = frameState.apop();
+                ValueNode object = frameState.pop(Kind.Object);
                 if (type instanceof ResolvedJavaType) {
                     ResolvedJavaType resolvedType = (ResolvedJavaType) type;
                     JavaTypeProfile profile = getProfileForTypeCheck(resolvedType);
@@ -3120,7 +3041,7 @@
                         if (instanceOfNode == null) {
                             instanceOfNode = createInstanceOf(resolvedType, object, profile);
                         }
-                        frameState.ipush(append(genConditional(genUnique(instanceOfNode))));
+                        frameState.push(Kind.Int, append(genConditional(genUnique(instanceOfNode))));
                     }
                 } else {
                     handleUnresolvedInstanceOf(type, object);
@@ -3139,23 +3060,23 @@
                             }
                         }
                     }
-                    frameState.apush(append(createNewInstance((ResolvedJavaType) type, true)));
+                    frameState.push(Kind.Object, append(createNewInstance((ResolvedJavaType) type, true)));
                 } else {
                     handleUnresolvedNewInstance(type);
                 }
             }
 
             private void genNewPrimitiveArray(int typeCode) {
-                Class<?> clazz = arrayTypeCodeToClass(typeCode);
-                ResolvedJavaType elementType = metaAccess.lookupJavaType(clazz);
-                frameState.apush(append(createNewArray(elementType, frameState.ipop(), true)));
+                ResolvedJavaType elementType = metaAccess.lookupJavaType(arrayTypeCodeToClass(typeCode));
+                ValueNode length = frameState.pop(Kind.Int);
+                frameState.push(Kind.Object, append(createNewArray(elementType, length, true)));
             }
 
             private void genNewObjectArray(int cpi) {
                 JavaType type = lookupType(cpi, ANEWARRAY);
-                ValueNode length = frameState.ipop();
+                ValueNode length = frameState.pop(Kind.Int);
                 if (type instanceof ResolvedJavaType) {
-                    frameState.apush(append(createNewArray((ResolvedJavaType) type, length, true)));
+                    frameState.push(Kind.Object, append(createNewArray((ResolvedJavaType) type, length, true)));
                 } else {
                     handleUnresolvedNewObjectArray(type, length);
                 }
@@ -3167,22 +3088,23 @@
                 int rank = getStream().readUByte(bci() + 3);
                 List<ValueNode> dims = new ArrayList<>(Collections.nCopies(rank, null));
                 for (int i = rank - 1; i >= 0; i--) {
-                    dims.set(i, frameState.ipop());
+                    dims.set(i, frameState.pop(Kind.Int));
                 }
                 if (type instanceof ResolvedJavaType) {
-                    frameState.apush(append(createNewMultiArray((ResolvedJavaType) type, dims)));
+                    frameState.push(Kind.Object, append(createNewMultiArray((ResolvedJavaType) type, dims)));
                 } else {
                     handleUnresolvedNewMultiArray(type, dims);
                 }
             }
 
             private void genGetField(JavaField field) {
-                Kind kind = field.getKind();
-                ValueNode receiver = emitExplicitExceptions(frameState.apop(), null);
+                ValueNode receiver = emitExplicitExceptions(frameState.pop(Kind.Object), null);
                 if ((field instanceof ResolvedJavaField) && ((ResolvedJavaField) field).getDeclaringClass().isInitialized()) {
+                    ResolvedJavaField resolvedField = (ResolvedJavaField) field;
+
                     LoadFieldPlugin loadFieldPlugin = this.graphBuilderConfig.getPlugins().getLoadFieldPlugin();
-                    if (loadFieldPlugin == null || !loadFieldPlugin.apply((GraphBuilderContext) this, receiver, (ResolvedJavaField) field)) {
-                        appendOptimizedLoadField(kind, genLoadField(receiver, (ResolvedJavaField) field));
+                    if (loadFieldPlugin == null || !loadFieldPlugin.apply(this, receiver, resolvedField)) {
+                        frameState.push(field.getKind(), append(genLoadField(receiver, resolvedField)));
                     }
                 } else {
                     handleUnresolvedLoadField(field, receiver);
@@ -3213,8 +3135,8 @@
             }
 
             private void genPutField(JavaField field) {
-                ValueNode value = frameState.pop(field.getKind().getStackKind());
-                ValueNode receiver = emitExplicitExceptions(frameState.apop(), null);
+                ValueNode value = frameState.pop(field.getKind());
+                ValueNode receiver = emitExplicitExceptions(frameState.pop(Kind.Object), null);
                 if (field instanceof ResolvedJavaField && ((ResolvedJavaField) field).getDeclaringClass().isInitialized()) {
                     genStoreField(receiver, (ResolvedJavaField) field, value);
                 } else {
@@ -3223,44 +3145,35 @@
             }
 
             private void genGetStatic(JavaField field) {
-                Kind kind = field.getKind();
                 if (field instanceof ResolvedJavaField && ((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) {
                     ResolvedJavaField resolvedField = (ResolvedJavaField) field;
+
                     // Javac does not allow use of "$assertionsDisabled" for a field name but
                     // Eclipse does in which case a suffix is added to the generated field.
                     if ((parsingIntrinsic() || graphBuilderConfig.omitAssertions()) && resolvedField.isSynthetic() && resolvedField.getName().startsWith("$assertionsDisabled")) {
-                        appendOptimizedLoadField(kind, ConstantNode.forBoolean(true));
+                        frameState.push(field.getKind(), ConstantNode.forBoolean(true, graph));
                         return;
                     }
 
                     LoadFieldPlugin loadFieldPlugin = this.graphBuilderConfig.getPlugins().getLoadFieldPlugin();
                     if (loadFieldPlugin == null || !loadFieldPlugin.apply(this, resolvedField)) {
-                        appendOptimizedLoadField(kind, genLoadField(null, resolvedField));
+                        frameState.push(field.getKind(), append(genLoadField(null, resolvedField)));
                     }
                 } else {
                     handleUnresolvedLoadField(field, null);
                 }
             }
 
-            public boolean tryLoadFieldPlugin(JavaField field, LoadFieldPlugin loadFieldPlugin) {
-                return loadFieldPlugin.apply((GraphBuilderContext) this, (ResolvedJavaField) field);
-            }
-
             private void genPutStatic(JavaField field) {
-                ValueNode value = frameState.pop(field.getKind().getStackKind());
+                ValueNode value = frameState.pop(field.getKind());
                 if (field instanceof ResolvedJavaField && ((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) {
-                    genStoreField(null, (ResolvedJavaField) field, value);
+                    ResolvedJavaField resolvedField = (ResolvedJavaField) field;
+                    genStoreField(null, resolvedField, value);
                 } else {
                     handleUnresolvedStoreField(field, value, null);
                 }
             }
 
-            protected void appendOptimizedLoadField(Kind kind, ValueNode load) {
-                // append the load to the instruction
-                ValueNode optimized = append(load);
-                frameState.push(kind.getStackKind(), optimized);
-            }
-
             private double[] switchProbability(int numberOfCases, int bci) {
                 double[] prob = (profilingInfo == null ? null : profilingInfo.getSwitchProbabilities(bci));
                 if (prob != null) {
@@ -3278,7 +3191,7 @@
 
             private void genSwitch(BytecodeSwitch bs) {
                 int bci = bci();
-                ValueNode value = frameState.ipop();
+                ValueNode value = frameState.pop(Kind.Int);
 
                 int nofCases = bs.numberOfCases();
                 double[] keyProbabilities = switchProbability(nofCases + 1, bci);
@@ -3381,23 +3294,23 @@
                 // @formatter:off
                 switch (opcode) {
                     case NOP            : /* nothing to do */ break;
-                    case ACONST_NULL    : frameState.apush(appendConstant(JavaConstant.NULL_POINTER)); break;
+                    case ACONST_NULL    : frameState.push(Kind.Object, appendConstant(JavaConstant.NULL_POINTER)); break;
                     case ICONST_M1      : // fall through
                     case ICONST_0       : // fall through
                     case ICONST_1       : // fall through
                     case ICONST_2       : // fall through
                     case ICONST_3       : // fall through
                     case ICONST_4       : // fall through
-                    case ICONST_5       : frameState.ipush(appendConstant(JavaConstant.forInt(opcode - ICONST_0))); break;
+                    case ICONST_5       : frameState.push(Kind.Int, appendConstant(JavaConstant.forInt(opcode - ICONST_0))); break;
                     case LCONST_0       : // fall through
-                    case LCONST_1       : frameState.lpush(appendConstant(JavaConstant.forLong(opcode - LCONST_0))); break;
+                    case LCONST_1       : frameState.push(Kind.Long, appendConstant(JavaConstant.forLong(opcode - LCONST_0))); break;
                     case FCONST_0       : // fall through
                     case FCONST_1       : // fall through
-                    case FCONST_2       : frameState.fpush(appendConstant(JavaConstant.forFloat(opcode - FCONST_0))); break;
+                    case FCONST_2       : frameState.push(Kind.Float, appendConstant(JavaConstant.forFloat(opcode - FCONST_0))); break;
                     case DCONST_0       : // fall through
-                    case DCONST_1       : frameState.dpush(appendConstant(JavaConstant.forDouble(opcode - DCONST_0))); break;
-                    case BIPUSH         : frameState.ipush(appendConstant(JavaConstant.forInt(stream.readByte()))); break;
-                    case SIPUSH         : frameState.ipush(appendConstant(JavaConstant.forInt(stream.readShort()))); break;
+                    case DCONST_1       : frameState.push(Kind.Double, appendConstant(JavaConstant.forDouble(opcode - DCONST_0))); break;
+                    case BIPUSH         : frameState.push(Kind.Int, appendConstant(JavaConstant.forInt(stream.readByte()))); break;
+                    case SIPUSH         : frameState.push(Kind.Int, appendConstant(JavaConstant.forInt(stream.readShort()))); break;
                     case LDC            : // fall through
                     case LDC_W          : // fall through
                     case LDC2_W         : genLoadConstant(stream.readCPI(), opcode); break;
@@ -3467,15 +3380,15 @@
                     case BASTORE        : genStoreIndexed(Kind.Byte  ); break;
                     case CASTORE        : genStoreIndexed(Kind.Char  ); break;
                     case SASTORE        : genStoreIndexed(Kind.Short ); break;
-                    case POP            : frameState.xpop(); break;
-                    case POP2           : frameState.xpop(); frameState.xpop(); break;
-                    case DUP            : frameState.xpush(frameState.xpeek()); break;
+                    case POP            : // fall through
+                    case POP2           : // fall through
+                    case DUP            : // fall through
                     case DUP_X1         : // fall through
                     case DUP_X2         : // fall through
                     case DUP2           : // fall through
                     case DUP2_X1        : // fall through
                     case DUP2_X2        : // fall through
-                    case SWAP           : stackOp(opcode); break;
+                    case SWAP           : frameState.stackOp(opcode); break;
                     case IADD           : // fall through
                     case ISUB           : // fall through
                     case IMUL           : genArithmeticOp(Kind.Int, opcode); break;
@@ -3552,11 +3465,11 @@
                     case RET            : genRet(stream.readLocalIndex()); break;
                     case TABLESWITCH    : genSwitch(new BytecodeTableSwitch(getStream(), bci())); break;
                     case LOOKUPSWITCH   : genSwitch(new BytecodeLookupSwitch(getStream(), bci())); break;
-                    case IRETURN        : genReturn(frameState.ipop(), Kind.Int); break;
-                    case LRETURN        : genReturn(frameState.lpop(), Kind.Long); break;
-                    case FRETURN        : genReturn(frameState.fpop(), Kind.Float); break;
-                    case DRETURN        : genReturn(frameState.dpop(), Kind.Double); break;
-                    case ARETURN        : genReturn(frameState.apop(), Kind.Object); break;
+                    case IRETURN        : genReturn(frameState.pop(Kind.Int), Kind.Int); break;
+                    case LRETURN        : genReturn(frameState.pop(Kind.Long), Kind.Long); break;
+                    case FRETURN        : genReturn(frameState.pop(Kind.Float), Kind.Float); break;
+                    case DRETURN        : genReturn(frameState.pop(Kind.Double), Kind.Double); break;
+                    case ARETURN        : genReturn(frameState.pop(Kind.Object), Kind.Object); break;
                     case RETURN         : genReturn(null, Kind.Void); break;
                     case GETSTATIC      : cpi = stream.readCPI(); genGetStatic(lookupField(cpi, opcode)); break;
                     case PUTSTATIC      : cpi = stream.readCPI(); genPutStatic(lookupField(cpi, opcode)); break;
@@ -3574,8 +3487,8 @@
                     case ATHROW         : genThrow(); break;
                     case CHECKCAST      : genCheckCast(); break;
                     case INSTANCEOF     : genInstanceOf(); break;
-                    case MONITORENTER   : genMonitorEnter(frameState.apop(), stream.nextBCI()); break;
-                    case MONITOREXIT    : genMonitorExit(frameState.apop(), null, stream.nextBCI()); break;
+                    case MONITORENTER   : genMonitorEnter(frameState.pop(Kind.Object), stream.nextBCI()); break;
+                    case MONITOREXIT    : genMonitorExit(frameState.pop(Kind.Object), null, stream.nextBCI()); break;
                     case MULTIANEWARRAY : genNewMultiArray(stream.readCPI()); break;
                     case IFNULL         : genIfNull(Condition.EQ); break;
                     case IFNONNULL      : genIfNull(Condition.NE); break;
@@ -3591,7 +3504,7 @@
             }
 
             private void genArrayLength() {
-                frameState.ipush(append(genArrayLength(frameState.apop())));
+                frameState.push(Kind.Int, append(genArrayLength(frameState.pop(Kind.Object))));
             }
 
             public ResolvedJavaMethod getMethod() {
--- a/graal/com.oracle.graal.lir.jtt/src/com/oracle/graal/lir/jtt/LIRTest.java	Fri May 29 01:11:41 2015 +0200
+++ b/graal/com.oracle.graal.lir.jtt/src/com/oracle/graal/lir/jtt/LIRTest.java	Thu May 28 17:00:59 2015 -0700
@@ -215,27 +215,32 @@
 
     private InvocationPlugin floatingLIRNodePlugin = new InvocationPlugin() {
         public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode spec) {
-            b.addPush(new FloatingLIRTestNode(getSnippetReflection(), targetMethod.getSignature().getReturnKind(), spec, new ValueNode[]{}));
+            Kind returnKind = targetMethod.getSignature().getReturnKind();
+            b.addPush(returnKind, new FloatingLIRTestNode(getSnippetReflection(), returnKind, spec, new ValueNode[]{}));
             return true;
         }
 
         public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode spec, ValueNode arg0) {
-            b.addPush(new FloatingLIRTestNode(getSnippetReflection(), targetMethod.getSignature().getReturnKind(), spec, new ValueNode[]{arg0}));
+            Kind returnKind = targetMethod.getSignature().getReturnKind();
+            b.addPush(returnKind, new FloatingLIRTestNode(getSnippetReflection(), returnKind, spec, new ValueNode[]{arg0}));
             return true;
         }
 
         public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode spec, ValueNode arg0, ValueNode arg1) {
-            b.addPush(new FloatingLIRTestNode(getSnippetReflection(), targetMethod.getSignature().getReturnKind(), spec, new ValueNode[]{arg0, arg1}));
+            Kind returnKind = targetMethod.getSignature().getReturnKind();
+            b.addPush(returnKind, new FloatingLIRTestNode(getSnippetReflection(), returnKind, spec, new ValueNode[]{arg0, arg1}));
             return true;
         }
 
         public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode spec, ValueNode arg0, ValueNode arg1, ValueNode arg2) {
-            b.addPush(new FloatingLIRTestNode(getSnippetReflection(), targetMethod.getSignature().getReturnKind(), spec, new ValueNode[]{arg0, arg1, arg2}));
+            Kind returnKind = targetMethod.getSignature().getReturnKind();
+            b.addPush(returnKind, new FloatingLIRTestNode(getSnippetReflection(), returnKind, spec, new ValueNode[]{arg0, arg1, arg2}));
             return true;
         }
 
         public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode spec, ValueNode arg0, ValueNode arg1, ValueNode arg2, ValueNode arg3) {
-            b.addPush(new FloatingLIRTestNode(getSnippetReflection(), targetMethod.getSignature().getReturnKind(), spec, new ValueNode[]{arg0, arg1, arg2, arg3}));
+            Kind returnKind = targetMethod.getSignature().getReturnKind();
+            b.addPush(returnKind, new FloatingLIRTestNode(getSnippetReflection(), returnKind, spec, new ValueNode[]{arg0, arg1, arg2, arg3}));
             return true;
         }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Fri May 29 01:11:41 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Thu May 28 17:00:59 2015 -0700
@@ -253,11 +253,11 @@
      * the stack.
      */
     public FrameState duplicateModifiedDuringCall(int newBci, Kind popKind) {
-        return duplicateModified(graph(), newBci, rethrowException, true, popKind);
+        return duplicateModified(graph(), newBci, rethrowException, true, popKind, null, null);
     }
 
-    public FrameState duplicateModifiedBeforeCall(int newBci, Kind popKind, ValueNode... pushedValues) {
-        return duplicateModified(graph(), newBci, rethrowException, false, popKind, pushedValues);
+    public FrameState duplicateModifiedBeforeCall(int newBci, Kind popKind, Kind[] pushedSlotKinds, ValueNode[] pushedValues) {
+        return duplicateModified(graph(), newBci, rethrowException, false, popKind, pushedSlotKinds, pushedValues);
     }
 
     /**
@@ -266,17 +266,17 @@
      * {@code pushedValues} will be formatted correctly in slot encoding: a long or double will be
      * followed by a null slot.
      */
-    public FrameState duplicateModified(int newBci, boolean newRethrowException, Kind popKind, ValueNode... pushedValues) {
-        return duplicateModified(graph(), newBci, newRethrowException, duringCall, popKind, pushedValues);
+    public FrameState duplicateModified(int newBci, boolean newRethrowException, Kind popKind, Kind[] pushedSlotKinds, ValueNode[] pushedValues) {
+        return duplicateModified(graph(), newBci, newRethrowException, duringCall, popKind, pushedSlotKinds, pushedValues);
     }
 
     /**
      * Creates a copy of this frame state with the top of stack replaced with with
      * {@code pushedValue} which must be of type {@code popKind}.
      */
-    public FrameState duplicateModified(Kind popKind, ValueNode pushedValue) {
+    public FrameState duplicateModified(Kind popKind, Kind pushedSlotKind, ValueNode pushedValue) {
         assert pushedValue != null && pushedValue.getKind() == popKind;
-        return duplicateModified(graph(), bci, rethrowException, duringCall, popKind, pushedValue);
+        return duplicateModified(graph(), bci, rethrowException, duringCall, popKind, new Kind[]{pushedSlotKind}, new ValueNode[]{pushedValue});
     }
 
     /**
@@ -285,7 +285,7 @@
      * correctly in slot encoding: a long or double will be followed by a null slot. The bci will be
      * changed to newBci.
      */
-    public FrameState duplicateModified(StructuredGraph graph, int newBci, boolean newRethrowException, boolean newDuringCall, Kind popKind, ValueNode... pushedValues) {
+    public FrameState duplicateModified(StructuredGraph graph, int newBci, boolean newRethrowException, boolean newDuringCall, Kind popKind, Kind[] pushedSlotKinds, ValueNode[] pushedValues) {
         ArrayList<ValueNode> copy;
         if (newRethrowException && !rethrowException && popKind == Kind.Void) {
             assert popKind == Kind.Void;
@@ -301,10 +301,13 @@
                 copy.remove(copy.size() - 1);
             }
         }
-        for (ValueNode node : pushedValues) {
-            copy.add(node);
-            if (node.getKind().needsTwoSlots()) {
-                copy.add(null);
+        if (pushedValues != null) {
+            assert pushedSlotKinds.length == pushedValues.length;
+            for (int i = 0; i < pushedValues.length; i++) {
+                copy.add(pushedValues[i]);
+                if (pushedSlotKinds[i].needsTwoSlots()) {
+                    copy.add(null);
+                }
             }
         }
         int newStackSize = copy.size() - localsSize;
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Fri May 29 01:11:41 2015 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Thu May 28 17:00:59 2015 -0700
@@ -485,7 +485,7 @@
              * value (top of stack)
              */
             if (frameState.stackSize() > 0 && (alwaysDuplicateStateAfter || stateAfterReturn.stackAt(0) != frameState.stackAt(0))) {
-                stateAfterReturn = stateAtReturn.duplicateModified(invokeReturnKind, frameState.stackAt(0));
+                stateAfterReturn = stateAtReturn.duplicateModified(invokeReturnKind, invokeReturnKind, frameState.stackAt(0));
             }
 
             frameState.replaceAndDelete(stateAfterReturn);
@@ -497,7 +497,7 @@
              */
             FrameState stateAfterException = stateAtExceptionEdge;
             if (frameState.stackSize() > 0 && stateAtExceptionEdge.stackAt(0) != frameState.stackAt(0)) {
-                stateAfterException = stateAtExceptionEdge.duplicateModified(Kind.Object, frameState.stackAt(0));
+                stateAfterException = stateAtExceptionEdge.duplicateModified(Kind.Object, Kind.Object, frameState.stackAt(0));
             }
             frameState.replaceAndDelete(stateAfterException);
             return stateAfterException;
@@ -509,7 +509,8 @@
             assert frameState.outerFrameState() == null;
             NodeInputList<ValueNode> invokeArgsList = invoke.callTarget().arguments();
             ValueNode[] invokeArgs = invokeArgsList.isEmpty() ? NO_ARGS : invokeArgsList.toArray(new ValueNode[invokeArgsList.size()]);
-            FrameState stateBeforeCall = stateAtReturn.duplicateModifiedBeforeCall(invoke.bci(), invokeReturnKind, invokeArgs);
+            ResolvedJavaMethod targetMethod = invoke.callTarget().targetMethod();
+            FrameState stateBeforeCall = stateAtReturn.duplicateModifiedBeforeCall(invoke.bci(), invokeReturnKind, targetMethod.getSignature().toParameterKinds(!targetMethod.isStatic()), invokeArgs);
             frameState.replaceAndDelete(stateBeforeCall);
             return stateBeforeCall;
         } else {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/MultiTypeGuardInlineInfo.java	Fri May 29 01:11:41 2015 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/MultiTypeGuardInlineInfo.java	Thu May 28 17:00:59 2015 -0700
@@ -190,7 +190,7 @@
             FixedNode exceptionSux = exceptionEdge.next();
             graph.addBeforeFixed(exceptionSux, exceptionMerge);
             exceptionObjectPhi = graph.addWithoutUnique(new ValuePhiNode(StampFactory.forKind(Kind.Object), exceptionMerge));
-            exceptionMerge.setStateAfter(exceptionEdge.stateAfter().duplicateModified(invoke.stateAfter().bci, true, Kind.Object, exceptionObjectPhi));
+            exceptionMerge.setStateAfter(exceptionEdge.stateAfter().duplicateModified(invoke.stateAfter().bci, true, Kind.Object, new Kind[]{Kind.Object}, new ValueNode[]{exceptionObjectPhi}));
         }
 
         // create one separate block for each invoked method
@@ -472,7 +472,7 @@
 
             ExceptionObjectNode newExceptionEdge = (ExceptionObjectNode) exceptionEdge.copyWithInputs();
             // set new state (pop old exception object, push new one)
-            newExceptionEdge.setStateAfter(stateAfterException.duplicateModified(Kind.Object, newExceptionEdge));
+            newExceptionEdge.setStateAfter(stateAfterException.duplicateModified(Kind.Object, Kind.Object, newExceptionEdge));
 
             EndNode endNode = graph.add(new EndNode());
             newExceptionEdge.setNext(endNode);
--- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64GraphBuilderPlugins.java	Fri May 29 01:11:41 2015 +0200
+++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64GraphBuilderPlugins.java	Thu May 28 17:00:59 2015 -0700
@@ -58,9 +58,9 @@
                 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
                     ValueNode folded = AMD64CountLeadingZerosNode.tryFold(value);
                     if (folded != null) {
-                        b.addPush(folded);
+                        b.addPush(Kind.Int, folded);
                     } else {
-                        b.addPush(new AMD64CountLeadingZerosNode(value));
+                        b.addPush(Kind.Int, new AMD64CountLeadingZerosNode(value));
                     }
                     return true;
                 }
@@ -73,9 +73,9 @@
                 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
                     ValueNode folded = AMD64CountTrailingZerosNode.tryFold(value);
                     if (folded != null) {
-                        b.addPush(folded);
+                        b.addPush(Kind.Int, folded);
                     } else {
-                        b.addPush(new AMD64CountTrailingZerosNode(value));
+                        b.addPush(Kind.Int, new AMD64CountTrailingZerosNode(value));
                     }
                     return true;
                 }
@@ -116,7 +116,7 @@
                 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset, ValueNode value) {
                     // Emits a null-check for the otherwise unused receiver
                     unsafe.get();
-                    b.addPush(kind.getStackKind(), new AtomicReadAndWriteNode(object, offset, value, kind, LocationIdentity.any()));
+                    b.addPush(kind, new AtomicReadAndWriteNode(object, offset, value, kind, LocationIdentity.any()));
                     return true;
                 }
             });
@@ -125,7 +125,7 @@
                     public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset, ValueNode delta) {
                         // Emits a null-check for the otherwise unused receiver
                         unsafe.get();
-                        b.addPush(kind.getStackKind(), new AtomicReadAndAddNode(object, offset, delta, LocationIdentity.any()));
+                        b.addPush(kind, new AtomicReadAndAddNode(object, offset, delta, LocationIdentity.any()));
                         return true;
                     }
                 });
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultGenericInvocationPlugin.java	Fri May 29 01:11:41 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultGenericInvocationPlugin.java	Thu May 28 17:00:59 2015 -0700
@@ -101,8 +101,7 @@
                 if (!COULD_NOT_FOLD.equals(constant)) {
                     if (constant != null) {
                         // Replace the invoke with the result of the call
-                        ConstantNode res = b.add(ConstantNode.forConstant(constant, b.getMetaAccess()));
-                        b.addPush(res.getKind().getStackKind(), res);
+                        b.push(method.getSignature().getReturnKind(), ConstantNode.forConstant(constant, b.getMetaAccess(), b.getGraph()));
                     } else {
                         // This must be a void invoke
                         assert method.getSignature().getReturnKind() == Kind.Void;
@@ -168,7 +167,7 @@
 
         if (returnKind != Kind.Void) {
             assert nonValueType || res.getKind().getStackKind() != Kind.Void;
-            res = b.addPush(returnKind.getStackKind(), res);
+            res = b.addPush(returnKind, res);
         } else {
             assert res.getKind().getStackKind() == Kind.Void;
             res = b.add(res);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/MethodHandleInvocationPlugin.java	Fri May 29 01:11:41 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/MethodHandleInvocationPlugin.java	Thu May 28 17:00:59 2015 -0700
@@ -54,7 +54,7 @@
                 if (invokeReturnType.getKind() == Kind.Void) {
                     b.add(methodHandleNode);
                 } else {
-                    b.addPush(methodHandleNode);
+                    b.addPush(invokeReturnType.getKind(), methodHandleNode);
                 }
             } else {
                 CallTargetNode callTarget = invoke.callTarget();
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/PEGraphDecoder.java	Fri May 29 01:11:41 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/PEGraphDecoder.java	Thu May 28 17:00:59 2015 -0700
@@ -575,7 +575,7 @@
             }
 
             Kind invokeReturnKind = methodScope.invokeData.invoke.asNode().getKind();
-            FrameState outerState = stateAtReturn.duplicateModified(methodScope.graph, methodScope.invokeData.invoke.bci(), stateAtReturn.rethrowException(), true, invokeReturnKind);
+            FrameState outerState = stateAtReturn.duplicateModified(methodScope.graph, methodScope.invokeData.invoke.bci(), stateAtReturn.rethrowException(), true, invokeReturnKind, null, null);
 
             /*
              * When the encoded graph has methods inlining, we can already have a proper caller
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java	Fri May 29 01:11:41 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java	Thu May 28 17:00:59 2015 -0700
@@ -104,7 +104,7 @@
         r.register1("getValue", String.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
                 ResolvedJavaField field = b.getMetaAccess().lookupJavaField(STRING_VALUE_FIELD);
-                b.addPush(new LoadFieldNode(value, field));
+                b.addPush(Kind.Object, new LoadFieldNode(value, field));
                 return true;
             }
         });
@@ -209,7 +209,7 @@
                 ReverseBytesNode reverse = b.add(new ReverseBytesNode(value));
                 RightShiftNode rightShift = b.add(new RightShiftNode(reverse, b.add(ConstantNode.forInt(16))));
                 ZeroExtendNode charCast = b.add(new ZeroExtendNode(b.add(new NarrowNode(rightShift, 16)), 32));
-                b.push(Kind.Char.getStackKind(), b.recursiveAppend(charCast.canonical(null, value)));
+                b.push(Kind.Char, b.recursiveAppend(charCast.canonical(null, value)));
                 return true;
             }
         });
@@ -223,7 +223,7 @@
                 ReverseBytesNode reverse = b.add(new ReverseBytesNode(value));
                 RightShiftNode rightShift = b.add(new RightShiftNode(reverse, b.add(ConstantNode.forInt(16))));
                 SignExtendNode charCast = b.add(new SignExtendNode(b.add(new NarrowNode(rightShift, 16)), 32));
-                b.push(Kind.Short.getStackKind(), b.recursiveAppend(charCast.canonical(null, value)));
+                b.push(Kind.Short, b.recursiveAppend(charCast.canonical(null, value)));
                 return true;
             }
         });
@@ -267,19 +267,19 @@
             Class<?> type = kind.toJavaClass();
             r.register2("addExact", type, type, new InvocationPlugin() {
                 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) {
-                    b.addPush(kind.getStackKind(), new IntegerAddExactNode(x, y));
+                    b.addPush(kind, new IntegerAddExactNode(x, y));
                     return true;
                 }
             });
             r.register2("subtractExact", type, type, new InvocationPlugin() {
                 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) {
-                    b.addPush(kind.getStackKind(), new IntegerSubExactNode(x, y));
+                    b.addPush(kind, new IntegerSubExactNode(x, y));
                     return true;
                 }
             });
             r.register2("multiplyExact", type, type, new InvocationPlugin() {
                 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) {
-                    b.addPush(kind.getStackKind(), new IntegerMulExactNode(x, y));
+                    b.addPush(kind, new IntegerMulExactNode(x, y));
                     return true;
                 }
             });
@@ -329,7 +329,7 @@
             }
 
             LogicNode compare = CompareNode.createCompareNode(graph, cond, lhs, rhs, b.getConstantReflection());
-            b.addPush(Kind.Boolean.getStackKind(), new ConditionalNode(compare, trueValue, falseValue));
+            b.addPush(Kind.Boolean, new ConditionalNode(compare, trueValue, falseValue));
             return true;
         }
     }
@@ -410,14 +410,14 @@
         r.register2("isInstance", Receiver.class, Object.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver type, ValueNode object) {
                 LogicNode condition = b.add(InstanceOfDynamicNode.create(b.getConstantReflection(), type.get(), object));
-                b.push(Kind.Boolean.getStackKind(), b.recursiveAppend(new ConditionalNode(condition).canonical(null)));
+                b.push(Kind.Boolean, b.recursiveAppend(new ConditionalNode(condition).canonical(null)));
                 return true;
             }
         });
         r.register2("isAssignableFrom", Receiver.class, Class.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver type, ValueNode otherType) {
                 ClassIsAssignableFromNode condition = b.recursiveAppend(new ClassIsAssignableFromNode(type.get(), otherType));
-                b.push(Kind.Boolean.getStackKind(), b.recursiveAppend(new ConditionalNode(condition).canonical(null)));
+                b.push(Kind.Boolean, b.recursiveAppend(new ConditionalNode(condition).canonical(null)));
                 return true;
             }
         });
@@ -496,7 +496,7 @@
                 }
             }
             ValueNode valueNode = UnboxNode.create(b.getMetaAccess(), b.getConstantReflection(), receiver.get(), kind);
-            b.addPush(kind.getStackKind(), valueNode);
+            b.addPush(kind, valueNode);
             return true;
         }
 
@@ -519,7 +519,7 @@
         public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode address) {
             // Emits a null-check for the otherwise unused receiver
             unsafe.get();
-            b.addPush(returnKind.getStackKind(), new DirectReadNode(address, returnKind));
+            b.addPush(returnKind, new DirectReadNode(address, returnKind));
             return true;
         }
 
@@ -529,7 +529,7 @@
             if (isVolatile) {
                 b.add(new MembarNode(JMM_PRE_VOLATILE_READ));
             }
-            b.addPush(returnKind.getStackKind(), new UnsafeLoadNode(object, offset, returnKind, LocationIdentity.any()));
+            b.addPush(returnKind, new UnsafeLoadNode(object, offset, returnKind, LocationIdentity.any()));
             if (isVolatile) {
                 b.add(new MembarNode(JMM_POST_VOLATILE_READ));
             }
@@ -586,7 +586,7 @@
 
         r.register0("inCompiledCode", new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
-                b.addPush(Kind.Int, ConstantNode.forInt(1));
+                b.addPush(Kind.Boolean, ConstantNode.forBoolean(true));
                 return true;
             }
         });
@@ -600,7 +600,7 @@
 
         r.register2("injectBranchProbability", double.class, boolean.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode probability, ValueNode condition) {
-                b.addPush(Kind.Int, new BranchProbabilityNode(probability, condition));
+                b.addPush(Kind.Boolean, new BranchProbabilityNode(probability, condition));
                 return true;
             }
         });
@@ -617,10 +617,9 @@
                 Class<?> javaClass = kind == Kind.Object ? Object.class : kind.toJavaClass();
                 r.register1("blackhole", javaClass, blackholePlugin);
 
-                final Kind stackKind = kind.getStackKind();
                 r.register1("opaque", javaClass, new InvocationPlugin() {
                     public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
-                        b.addPush(stackKind, new OpaqueNode(value));
+                        b.addPush(kind, new OpaqueNode(value));
                         return true;
                     }
                 });
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/WordOperationPlugin.java	Fri May 29 01:11:41 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/WordOperationPlugin.java	Thu May 28 17:00:59 2015 -0700
@@ -101,24 +101,23 @@
     protected void processWordOperation(GraphBuilderContext b, ValueNode[] args, ResolvedJavaMethod wordMethod) throws JVMCIError {
         Operation operation = wordMethod.getAnnotation(Word.Operation.class);
         Kind returnKind = wordMethod.getSignature().getReturnKind();
-        Kind returnStackKind = returnKind.getStackKind();
         switch (operation.opcode()) {
             case NODE_CLASS:
                 assert args.length == 2;
                 ValueNode left = args[0];
                 ValueNode right = operation.rightOperandIsInt() ? toUnsigned(b, args[1], Kind.Int) : fromSigned(b, args[1]);
 
-                b.addPush(returnStackKind, createBinaryNodeInstance(operation.node(), left, right));
+                b.addPush(returnKind, createBinaryNodeInstance(operation.node(), left, right));
                 break;
 
             case COMPARISON:
                 assert args.length == 2;
-                b.push(returnStackKind, comparisonOp(b, operation.condition(), args[0], fromSigned(b, args[1])));
+                b.push(returnKind, comparisonOp(b, operation.condition(), args[0], fromSigned(b, args[1])));
                 break;
 
             case NOT:
                 assert args.length == 1;
-                b.addPush(returnStackKind, new XorNode(args[0], b.add(forIntegerKind(wordKind, -1))));
+                b.addPush(returnKind, new XorNode(args[0], b.add(forIntegerKind(wordKind, -1))));
                 break;
 
             case READ_POINTER:
@@ -132,7 +131,7 @@
                 } else {
                     location = makeLocation(b, args[1], args[2]);
                 }
-                b.push(returnStackKind, readOp(b, readKind, args[0], location, operation.opcode()));
+                b.push(returnKind, readOp(b, readKind, args[0], location, operation.opcode()));
                 break;
             }
             case READ_HEAP: {
@@ -140,7 +139,7 @@
                 Kind readKind = wordTypes.asKind(wordMethod.getSignature().getReturnType(wordMethod.getDeclaringClass()));
                 LocationNode location = makeLocation(b, args[1], any());
                 BarrierType barrierType = snippetReflection.asObject(BarrierType.class, args[2].asJavaConstant());
-                b.push(returnStackKind, readOp(b, readKind, args[0], location, barrierType, true));
+                b.push(returnKind, readOp(b, readKind, args[0], location, barrierType, true));
                 break;
             }
             case WRITE_POINTER:
@@ -160,44 +159,44 @@
             }
             case ZERO:
                 assert args.length == 0;
-                b.addPush(returnStackKind, forIntegerKind(wordKind, 0L));
+                b.addPush(returnKind, forIntegerKind(wordKind, 0L));
                 break;
 
             case FROM_UNSIGNED:
                 assert args.length == 1;
-                b.push(returnStackKind, fromUnsigned(b, args[0]));
+                b.push(returnKind, fromUnsigned(b, args[0]));
                 break;
 
             case FROM_SIGNED:
                 assert args.length == 1;
-                b.push(returnStackKind, fromSigned(b, args[0]));
+                b.push(returnKind, fromSigned(b, args[0]));
                 break;
 
             case TO_RAW_VALUE:
                 assert args.length == 1;
-                b.push(returnStackKind, toUnsigned(b, args[0], Kind.Long));
+                b.push(returnKind, toUnsigned(b, args[0], Kind.Long));
                 break;
 
             case FROM_WORDBASE:
                 assert args.length == 1;
-                b.push(returnStackKind, args[0]);
+                b.push(returnKind, args[0]);
                 break;
 
             case FROM_OBJECT:
                 assert args.length == 1;
                 WordCastNode objectToWord = b.add(WordCastNode.objectToWord(args[0], wordKind));
-                b.push(returnStackKind, objectToWord);
+                b.push(returnKind, objectToWord);
                 break;
 
             case FROM_ARRAY:
                 assert args.length == 2;
-                b.addPush(returnStackKind, new ComputeAddressNode(args[0], args[1], StampFactory.forKind(wordKind)));
+                b.addPush(returnKind, new ComputeAddressNode(args[0], args[1], StampFactory.forKind(wordKind)));
                 break;
 
             case TO_OBJECT:
                 assert args.length == 1;
                 WordCastNode wordToObject = b.add(WordCastNode.wordToObject(args[0], wordKind));
-                b.push(returnStackKind, wordToObject);
+                b.push(returnKind, wordToObject);
                 break;
 
             default:
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java	Fri May 29 01:11:41 2015 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java	Thu May 28 17:00:59 2015 -0700
@@ -85,14 +85,14 @@
                     OptimizedAssumption assumption = snippetReflection.asObject(OptimizedAssumption.class, (JavaConstant) constant);
                     if (assumption.isValid()) {
                         if (targetMethod.getName().equals("isValid")) {
-                            b.addPush(ConstantNode.forBoolean(true));
+                            b.addPush(Kind.Boolean, ConstantNode.forBoolean(true));
                         } else {
                             assert targetMethod.getName().equals("check") : targetMethod;
                         }
                         b.getAssumptions().record(new AssumptionValidAssumption(assumption));
                     } else {
                         if (targetMethod.getName().equals("isValid")) {
-                            b.addPush(ConstantNode.forBoolean(false));
+                            b.addPush(Kind.Boolean, ConstantNode.forBoolean(false));
                         } else {
                             assert targetMethod.getName().equals("check") : targetMethod;
                             b.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.None));
@@ -116,31 +116,31 @@
             Class<?> type = kind.toJavaClass();
             r.register2("addExact", type, type, new InvocationPlugin() {
                 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) {
-                    b.addPush(kind.getStackKind(), new IntegerAddExactNode(x, y));
+                    b.addPush(kind, new IntegerAddExactNode(x, y));
                     return true;
                 }
             });
             r.register2("subtractExact", type, type, new InvocationPlugin() {
                 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) {
-                    b.addPush(kind.getStackKind(), new IntegerSubExactNode(x, y));
+                    b.addPush(kind, new IntegerSubExactNode(x, y));
                     return true;
                 }
             });
             r.register2("multiplyExact", type, type, new InvocationPlugin() {
                 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) {
-                    b.addPush(kind.getStackKind(), new IntegerMulExactNode(x, y));
+                    b.addPush(kind, new IntegerMulExactNode(x, y));
                     return true;
                 }
             });
             r.register2("multiplyHigh", type, type, new InvocationPlugin() {
                 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) {
-                    b.addPush(kind.getStackKind(), new IntegerMulHighNode(x, y));
+                    b.addPush(kind, new IntegerMulHighNode(x, y));
                     return true;
                 }
             });
             r.register2("multiplyHighUnsigned", type, type, new InvocationPlugin() {
                 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) {
-                    b.addPush(kind.getStackKind(), new UnsignedMulHighNode(x, y));
+                    b.addPush(kind, new UnsignedMulHighNode(x, y));
                     return true;
                 }
             });
@@ -151,13 +151,13 @@
         Registration r = new Registration(plugins, CompilerDirectives.class);
         r.register0("inInterpreter", new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
-                b.addPush(Kind.Boolean.getStackKind(), ConstantNode.forBoolean(false));
+                b.addPush(Kind.Boolean, ConstantNode.forBoolean(false));
                 return true;
             }
         });
         r.register0("inCompiledCode", new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
-                b.addPush(Kind.Boolean.getStackKind(), ConstantNode.forBoolean(true));
+                b.addPush(Kind.Boolean, ConstantNode.forBoolean(true));
                 return true;
             }
         });
@@ -185,7 +185,7 @@
         });
         r.register2("injectBranchProbability", double.class, boolean.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode probability, ValueNode condition) {
-                b.addPush(Kind.Boolean.getStackKind(), new BranchProbabilityNode(probability, condition));
+                b.addPush(Kind.Boolean, new BranchProbabilityNode(probability, condition));
                 return true;
             }
         });
@@ -200,9 +200,9 @@
         r.register1("isCompilationConstant", Object.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
                 if ((value instanceof BoxNode ? ((BoxNode) value).getValue() : value).isConstant()) {
-                    b.addPush(Kind.Boolean.getStackKind(), ConstantNode.forBoolean(true));
+                    b.addPush(Kind.Boolean, ConstantNode.forBoolean(true));
                 } else {
-                    b.addPush(Kind.Boolean.getStackKind(), new IsCompilationConstantNode(value));
+                    b.addPush(Kind.Boolean, new IsCompilationConstantNode(value));
                 }
                 return true;
             }
@@ -375,7 +375,7 @@
                     locationIdentity = ObjectLocationIdentity.create(location.asJavaConstant());
                 }
                 LogicNode compare = b.add(CompareNode.createCompareNode(Condition.EQ, condition, ConstantNode.forBoolean(true, object.graph()), b.getConstantReflection()));
-                b.addPush(returnKind.getStackKind(), b.add(new UnsafeLoadNode(object, offset, returnKind, locationIdentity, compare)));
+                b.addPush(returnKind, b.add(new UnsafeLoadNode(object, offset, returnKind, locationIdentity, compare)));
                 return true;
             }
             // TODO: should we throw b.bailout() here?
--- a/graal/com.oracle.jvmci.meta/src/com/oracle/jvmci/meta/Signature.java	Fri May 29 01:11:41 2015 +0200
+++ b/graal/com.oracle.jvmci.meta/src/com/oracle/jvmci/meta/Signature.java	Thu May 28 17:00:59 2015 -0700
@@ -119,4 +119,21 @@
         }
         return result;
     }
+
+    default Kind[] toParameterKinds(boolean receiver) {
+        int args = getParameterCount(false);
+        Kind[] result;
+        int i = 0;
+        if (receiver) {
+            result = new Kind[args + 1];
+            result[0] = Kind.Object;
+            i = 1;
+        } else {
+            result = new Kind[args];
+        }
+        for (int j = 0; j < args; j++) {
+            result[i + j] = getParameterKind(j);
+        }
+        return result;
+    }
 }