changeset 9761:b1e4aebbd19e

Merge.
author Christian Haeubl <haeubl@ssw.jku.at>
date Fri, 17 May 2013 15:40:06 +0200
parents c76b43ed5089 (current diff) 43a94291d239 (diff)
children 57e5211846f9
files graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RuntimeCallTarget.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotRuntimeCallTarget.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CRuntimeCall.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/CRuntimeStub.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/LogObjectStub.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/LogPrimitiveStub.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/LogPrintfStub.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewMultiArrayStub.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/OSRMigrationEndStub.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/RuntimeCallStub.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ThreadIsInterruptedStub.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/VMErrorStub.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/RuntimeCallNode.java
diffstat 90 files changed, 1745 insertions(+), 2252 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Architecture.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Architecture.java	Fri May 17 15:40:06 2013 +0200
@@ -161,8 +161,25 @@
     /**
      * Determine the maximum vector length supported for vector operations on values of a given
      * {@link Kind}.
+     * 
+     * @param kind the kind of the individual vector elements
+     * @return the maximum supported vector size
      */
-    public int getMaxVectorLength(@SuppressWarnings("unused") Kind kind) {
+    public int getMaxVectorLength(Kind kind) {
+        return 1;
+    }
+
+    /**
+     * Get a natively supported vector length for breaking down some vector operation on a constant
+     * length vector.
+     * 
+     * @param kind the kind of the individual vector elements
+     * @param maxLength the maximum length that should be returned
+     * @param arithmetic whether the vector length needs to support arithmetic operations or just
+     *            load and store
+     * @return a supported vector size, but at most {@code maxLength}
+     */
+    public int getSupportedVectorLength(Kind kind, int maxLength, boolean arithmetic) {
         return 1;
     }
 
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CallingConvention.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CallingConvention.java	Fri May 17 15:40:06 2013 +0200
@@ -27,9 +27,8 @@
 import com.oracle.graal.api.meta.*;
 
 /**
- * A calling convention describes the locations in which the arguments for a call are placed, the
- * location in which the return value is placed if the call is not void and any
- * {@linkplain #getTemporaries() extra} locations used (and killed) by the call.
+ * A calling convention describes the locations in which the arguments for a call are placed and the
+ * location in which the return value is placed if the call is not void.
  */
 public class CallingConvention {
 
@@ -78,11 +77,6 @@
     private final AllocatableValue[] argumentLocations;
 
     /**
-     * The locations used (and killed) by the call in addition to the arguments.
-     */
-    private final AllocatableValue[] temporaryLocations;
-
-    /**
      * Creates a description of the registers and stack locations used by a call.
      * 
      * @param stackSize amount of stack space (in bytes) required for the stack-based arguments of
@@ -92,28 +86,11 @@
      * @param argumentLocations the ordered locations in which the arguments are placed
      */
     public CallingConvention(int stackSize, AllocatableValue returnLocation, AllocatableValue... argumentLocations) {
-        this(AllocatableValue.NONE, stackSize, returnLocation, argumentLocations);
-    }
-
-    /**
-     * Creates a description of the registers and stack locations used by a call.
-     * 
-     * @param temporaryLocations the locations used (and killed) by the call in addition to
-     *            {@code arguments}
-     * @param stackSize amount of stack space (in bytes) required for the stack-based arguments of
-     *            the call
-     * @param returnLocation the location for the return value or {@link Value#ILLEGAL} if a void
-     *            call
-     * @param argumentLocations the ordered locations in which the arguments are placed
-     */
-    public CallingConvention(AllocatableValue[] temporaryLocations, int stackSize, AllocatableValue returnLocation, AllocatableValue... argumentLocations) {
         assert argumentLocations != null;
-        assert temporaryLocations != null;
         assert returnLocation != null;
         this.argumentLocations = argumentLocations;
         this.stackSize = stackSize;
         this.returnLocation = returnLocation;
-        this.temporaryLocations = temporaryLocations;
         assert verify();
     }
 
@@ -155,17 +132,6 @@
         return argumentLocations.clone();
     }
 
-    /**
-     * Gets the locations used (and killed) by the call apart from the
-     * {@linkplain #getArgument(int) arguments}.
-     */
-    public AllocatableValue[] getTemporaries() {
-        if (temporaryLocations.length == 0) {
-            return temporaryLocations;
-        }
-        return temporaryLocations.clone();
-    }
-
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
@@ -178,14 +144,6 @@
         if (!returnLocation.equals(Value.ILLEGAL)) {
             sb.append(" -> ").append(returnLocation);
         }
-        if (temporaryLocations.length != 0) {
-            sb.append("; temps=");
-            sep = "";
-            for (Value op : temporaryLocations) {
-                sb.append(sep).append(op);
-                sep = ", ";
-            }
-        }
         sb.append("]");
         return sb.toString();
     }
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeCacheProvider.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeCacheProvider.java	Fri May 17 15:40:06 2013 +0200
@@ -23,7 +23,6 @@
 package com.oracle.graal.api.code;
 
 import com.oracle.graal.api.code.CompilationResult.DataPatch;
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.api.meta.*;
 
 /**
@@ -68,9 +67,9 @@
     int getMinimumOutgoingSize();
 
     /**
-     * Gets the signature and linkage information for a runtime call.
+     * Gets the linkage for a foreign call.
      */
-    RuntimeCallTarget lookupRuntimeCall(Descriptor descriptor);
+    ForeignCallLinkage lookupForeignCall(ForeignCallDescriptor descriptor);
 
     /**
      * Encodes a deoptimization action and a deoptimization reason in an integer value.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ForeignCallLinkage.java	Fri May 17 15:40:06 2013 +0200
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.api.code;
+
+import com.oracle.graal.api.meta.*;
+
+/**
+ * The runtime specific details of a {@linkplain ForeignCallDescriptor foreign} call.
+ */
+public interface ForeignCallLinkage extends InvokeTarget {
+
+    /**
+     * Gets the details of where parameters are passed and value(s) are returned.
+     */
+    CallingConvention getCallingConvention();
+
+    /**
+     * Returns the maximum absolute offset of PC relative call to this stub from any position in the
+     * code cache or -1 when not applicable. Intended for determining the required size of
+     * address/offset fields.
+     */
+    long getMaxCallTargetOffset();
+
+    ForeignCallDescriptor getDescriptor();
+
+    /**
+     * Gets the values used/killed by this foreign call.
+     */
+    Value[] getTemporaries();
+
+    /**
+     * Determines if the foreign call target destroys all registers.
+     * 
+     * @return {@code true} if the register allocator must save all live registers around a call to
+     *         this target
+     */
+    boolean destroysRegisters();
+}
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RuntimeCallTarget.java	Fri May 17 15:38:22 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,125 +0,0 @@
-/*
- * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.api.code;
-
-import java.util.*;
-
-import com.oracle.graal.api.meta.*;
-
-/**
- * The name, signature and calling convention of a call from compiled code to the runtime. The
- * target of such a call may be a leaf stub or a call into the runtime code proper.
- */
-public interface RuntimeCallTarget extends InvokeTarget {
-
-    /**
-     * The name and signature of a runtime call.
-     */
-    public static class Descriptor {
-
-        private final String name;
-        private final boolean hasSideEffect;
-        private final Class resultType;
-        private final Class[] argumentTypes;
-
-        public Descriptor(String name, boolean hasSideEffect, Class resultType, Class... argumentTypes) {
-            this.name = name;
-            this.hasSideEffect = hasSideEffect;
-            this.resultType = resultType;
-            this.argumentTypes = argumentTypes;
-        }
-
-        /**
-         * Gets the name of this runtime call.
-         */
-        public String getName() {
-            return name;
-        }
-
-        /**
-         * Determines if this call changes state visible to other threads. Such calls denote
-         * boundaries across which deoptimization points cannot be moved.
-         */
-        public boolean hasSideEffect() {
-            return hasSideEffect;
-        }
-
-        /**
-         * Gets the return kind of this runtime call.
-         */
-        public Class<?> getResultType() {
-            return resultType;
-        }
-
-        /**
-         * Gets the argument kinds of this runtime call.
-         */
-        public Class<?>[] getArgumentTypes() {
-            return argumentTypes.clone();
-        }
-
-        @Override
-        public int hashCode() {
-            return name.hashCode();
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (obj instanceof Descriptor) {
-                Descriptor nas = (Descriptor) obj;
-                return nas.name.equals(name) && nas.resultType.equals(resultType) && Arrays.equals(nas.argumentTypes, argumentTypes);
-            }
-            return false;
-        }
-
-        @Override
-        public String toString() {
-            StringBuilder sb = new StringBuilder(name).append('(');
-            String sep = "";
-            for (Class arg : argumentTypes) {
-                sb.append(sep).append(arg.getSimpleName());
-                sep = ",";
-            }
-            return sb.append(')').append(resultType.getSimpleName()).toString();
-        }
-    }
-
-    CallingConvention getCallingConvention();
-
-    /**
-     * Returns the maximum absolute offset of PC relative call to this stub from any position in the
-     * code cache or -1 when not applicable. Intended for determining the required size of
-     * address/offset fields.
-     */
-    long getMaxCallTargetOffset();
-
-    Descriptor getDescriptor();
-
-    /**
-     * Determines if the target routine destroys all registers.
-     * 
-     * @return {@code true} if the register allocator must save all live registers around a call to
-     *         this target
-     */
-    boolean destroysRegisters();
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ForeignCallDescriptor.java	Fri May 17 15:40:06 2013 +0200
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.api.meta;
+
+import java.util.*;
+
+/**
+ * The name and signature of a foreign call. A foreign call differs from a normal compiled Java call
+ * in at least one of these aspects:
+ * <ul>
+ * <li>The call is to C/C++/assembler code.</li>
+ * <li>The call uses different conventions for passing parameters or returning values.</li>
+ * <li>The callee has different register saving semantics. For example, the callee may save all
+ * registers (apart from some specified temporaries) in which case the register allocator doesn't
+ * not need to spill all live registers around the call site.</li>
+ * </ul>
+ */
+public class ForeignCallDescriptor {
+
+    private final String name;
+    private final Class resultType;
+    private final Class[] argumentTypes;
+
+    public ForeignCallDescriptor(String name, Class resultType, Class... argumentTypes) {
+        this.name = name;
+        this.resultType = resultType;
+        this.argumentTypes = argumentTypes;
+    }
+
+    /**
+     * Gets the name of this foreign call.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Gets the return type of this foreign call.
+     */
+    public Class<?> getResultType() {
+        return resultType;
+    }
+
+    /**
+     * Gets the argument types of this foreign call.
+     */
+    public Class<?>[] getArgumentTypes() {
+        return argumentTypes.clone();
+    }
+
+    @Override
+    public int hashCode() {
+        return name.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof ForeignCallDescriptor) {
+            ForeignCallDescriptor other = (ForeignCallDescriptor) obj;
+            return other.name.equals(name) && other.resultType.equals(resultType) && Arrays.equals(other.argumentTypes, argumentTypes);
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder(name).append('(');
+        String sep = "";
+        for (Class arg : argumentTypes) {
+            sb.append(sep).append(arg.getSimpleName());
+            sep = ",";
+        }
+        return sb.append(')').append(resultType.getSimpleName()).toString();
+    }
+}
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaAccessProvider.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaAccessProvider.java	Fri May 17 15:40:06 2013 +0200
@@ -94,4 +94,10 @@
      *         value cannot be read.
      */
     Constant readUnsafeConstant(Kind kind, Object base, long displacement);
+
+    /**
+     * Determines if a given foreign call has a side-effect. Deoptimization cannot return execution
+     * to a point before a foreign call that has a side effect.
+     */
+    boolean hasSideEffect(ForeignCallDescriptor descriptor);
 }
--- a/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64MacroAssembler.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64MacroAssembler.java	Fri May 17 15:40:06 2013 +0200
@@ -26,6 +26,7 @@
 
 import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
 
 /**
  * This class implements commonly used X86 code patterns.
@@ -255,7 +256,7 @@
     private AMD64Address trigPrologue(Register value) {
         assert value.getRegisterCategory() == AMD64.XMM;
         AMD64Address tmp = new AMD64Address(AMD64.rsp);
-        subq(AMD64.rsp, 8);
+        subq(AMD64.rsp, target.arch.getSizeInBytes(Kind.Double));
         movsd(tmp, value);
         fld_d(tmp);
         return tmp;
@@ -265,7 +266,7 @@
         assert dest.getRegisterCategory() == AMD64.XMM;
         fstp_d(tmp);
         movsd(dest, tmp);
-        addq(AMD64.rsp, 8);
+        addq(AMD64.rsp, target.arch.getSizeInBytes(Kind.Double));
     }
 
     /**
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Fri May 17 15:40:06 2013 +0200
@@ -135,7 +135,7 @@
 
     @Override
     public Variable emitMove(Value input) {
-        Variable result = newVariable(input.getKind());
+        Variable result = newVariable(input.getPlatformKind());
         emitMove(result, input);
         return result;
     }
@@ -784,13 +784,12 @@
     }
 
     @Override
-    protected void emitCall(RuntimeCallTarget callTarget, Value result, Value[] arguments, Value[] temps, LIRFrameState info) {
-
-        long maxOffset = callTarget.getMaxCallTargetOffset();
+    protected void emitForeignCall(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info) {
+        long maxOffset = linkage.getMaxCallTargetOffset();
         if (maxOffset != (int) maxOffset) {
-            append(new AMD64Call.DirectFarRuntimeCallOp(this, callTarget, result, arguments, temps, info));
+            append(new AMD64Call.DirectFarForeignCallOp(this, linkage, result, arguments, temps, info));
         } else {
-            append(new AMD64Call.DirectNearRuntimeCallOp(callTarget, result, arguments, temps, info));
+            append(new AMD64Call.DirectNearForeignCallOp(linkage, result, arguments, temps, info));
         }
     }
 
--- a/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java	Fri May 17 15:40:06 2013 +0200
@@ -29,7 +29,6 @@
 import static com.oracle.graal.lir.ptx.PTXCompare.*;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.NumUtil;
 import com.oracle.graal.compiler.gen.LIRGenerator;
@@ -70,8 +69,8 @@
  */
 public class PTXLIRGenerator extends LIRGenerator {
 
-    public static final Descriptor ARITHMETIC_FREM = new Descriptor("arithmeticFrem", false, float.class, float.class, float.class);
-    public static final Descriptor ARITHMETIC_DREM = new Descriptor("arithmeticDrem", false, double.class, double.class, double.class);
+    public static final ForeignCallDescriptor ARITHMETIC_FREM = new ForeignCallDescriptor("arithmeticFrem", float.class, float.class, float.class);
+    public static final ForeignCallDescriptor ARITHMETIC_DREM = new ForeignCallDescriptor("arithmeticDrem", double.class, double.class, double.class);
 
     public static class PTXSpillMoveFactory implements LIR.SpillMoveFactory {
 
@@ -643,7 +642,7 @@
     }
 
     @Override
-    protected void emitCall(RuntimeCallTarget callTarget, Value result, Value[] arguments, Value[] temps, LIRFrameState info) {
+    protected void emitForeignCall(ForeignCallLinkage callTarget, Value result, Value[] arguments, Value[] temps, LIRFrameState info) {
         throw new InternalError("NYI");
     }
 
--- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Fri May 17 15:40:06 2013 +0200
@@ -112,7 +112,7 @@
     }
 
     @Override
-    protected void emitCall(RuntimeCallTarget callTarget, Value result, Value[] arguments, Value[] temps, LIRFrameState info) {
+    protected void emitForeignCall(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info) {
         // SPARC: Auto-generated method stub
 
     }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Fri May 17 15:40:06 2013 +0200
@@ -608,9 +608,9 @@
 
         Value result = invokeCc.getReturn();
         if (callTarget instanceof DirectCallTargetNode) {
-            emitDirectCall((DirectCallTargetNode) callTarget, result, parameters, invokeCc.getTemporaries(), callState);
+            emitDirectCall((DirectCallTargetNode) callTarget, result, parameters, AllocatableValue.NONE, callState);
         } else if (callTarget instanceof IndirectCallTargetNode) {
-            emitIndirectCall((IndirectCallTargetNode) callTarget, result, parameters, invokeCc.getTemporaries(), callState);
+            emitIndirectCall((IndirectCallTargetNode) callTarget, result, parameters, AllocatableValue.NONE, callState);
         } else {
             throw GraalInternalError.shouldNotReachHere();
         }
@@ -624,7 +624,7 @@
 
     protected abstract void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState);
 
-    protected abstract void emitCall(RuntimeCallTarget callTarget, Value result, Value[] arguments, Value[] temps, LIRFrameState info);
+    protected abstract void emitForeignCall(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info);
 
     protected static AllocatableValue toStackKind(AllocatableValue value) {
         if (value.getKind().getStackKind() != value.getKind()) {
@@ -659,43 +659,29 @@
     }
 
     @Override
-    public Variable emitCall(RuntimeCallTarget callTarget, CallingConvention callCc, DeoptimizingNode info, Value... args) {
+    public Variable emitForeignCall(ForeignCallLinkage linkage, DeoptimizingNode info, Value... args) {
         LIRFrameState state = info != null ? state(info) : null;
 
         // move the arguments into the correct location
-        frameMap.callsMethod(callCc);
-        assert callCc.getArgumentCount() == args.length : "argument count mismatch";
+        CallingConvention linkageCc = linkage.getCallingConvention();
+        frameMap.callsMethod(linkageCc);
+        assert linkageCc.getArgumentCount() == args.length : "argument count mismatch";
         Value[] argLocations = new Value[args.length];
         for (int i = 0; i < args.length; i++) {
             Value arg = args[i];
-            AllocatableValue loc = callCc.getArgument(i);
+            AllocatableValue loc = linkageCc.getArgument(i);
             emitMove(loc, arg);
             argLocations[i] = loc;
         }
-        emitCall(callTarget, callCc.getReturn(), argLocations, callCc.getTemporaries(), state);
+        emitForeignCall(linkage, linkageCc.getReturn(), argLocations, linkage.getTemporaries(), state);
 
-        if (isLegal(callCc.getReturn())) {
-            return emitMove(callCc.getReturn());
+        if (isLegal(linkageCc.getReturn())) {
+            return emitMove(linkageCc.getReturn());
         } else {
             return null;
         }
     }
 
-    @Override
-    public void visitRuntimeCall(RuntimeCallNode x) {
-        RuntimeCallTarget call = runtime.lookupRuntimeCall(x.getDescriptor());
-        CallingConvention callCc = call.getCallingConvention();
-        frameMap.callsMethod(callCc);
-        Value resultOperand = callCc.getReturn();
-        Value[] args = visitInvokeArguments(callCc, x.arguments());
-
-        emitCall(call, resultOperand, args, callCc.getTemporaries(), state(x));
-
-        if (isLegal(resultOperand)) {
-            setResult(x, emitMove(resultOperand));
-        }
-    }
-
     /**
      * This method tries to create a switch implementation that is optimal for the given switch. It
      * will either generate a sequential if/then/else cascade, a set of range tests or a table
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizeOp.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizeOp.java	Fri May 17 15:40:06 2013 +0200
@@ -52,6 +52,6 @@
         HotSpotGraalRuntime runtime = graalRuntime();
         Register thread = runtime.getRuntime().threadRegister();
         masm.movl(new AMD64Address(thread, runtime.getConfig().pendingDeoptimizationOffset), tasm.runtime.encodeDeoptActionAndReason(action, reason));
-        AMD64Call.directCall(tasm, masm, tasm.runtime.lookupRuntimeCall(UNCOMMON_TRAP), null, false, info);
+        AMD64Call.directCall(tasm, masm, tasm.runtime.lookupForeignCall(UNCOMMON_TRAP), null, false, info);
     }
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Fri May 17 15:40:06 2013 +0200
@@ -250,9 +250,9 @@
         HotSpotFrameContext frameContext = (HotSpotFrameContext) tasm.frameContext;
         if (frameContext != null && !frameContext.isStub) {
             tasm.recordMark(Marks.MARK_EXCEPTION_HANDLER_ENTRY);
-            AMD64Call.directCall(tasm, asm, runtime().lookupRuntimeCall(EXCEPTION_HANDLER), null, false, null);
+            AMD64Call.directCall(tasm, asm, runtime().lookupForeignCall(EXCEPTION_HANDLER), null, false, null);
             tasm.recordMark(Marks.MARK_DEOPT_HANDLER_ENTRY);
-            AMD64Call.directCall(tasm, asm, runtime().lookupRuntimeCall(DEOPT_HANDLER), null, false, null);
+            AMD64Call.directCall(tasm, asm, runtime().lookupForeignCall(DEOPT_HANDLER), null, false, null);
         } else {
             // No need to emit the stubs for entries back into the method since
             // it has no calls that can cause such "return" entries
@@ -261,7 +261,7 @@
 
         if (unverifiedStub != null) {
             asm.bind(unverifiedStub);
-            AMD64Call.directJmp(tasm, asm, runtime().lookupRuntimeCall(IC_MISS_HANDLER));
+            AMD64Call.directJmp(tasm, asm, runtime().lookupForeignCall(IC_MISS_HANDLER));
         }
     }
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotDeoptimizeCallerOp.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotDeoptimizeCallerOp.java	Fri May 17 15:40:06 2013 +0200
@@ -54,6 +54,6 @@
         HotSpotGraalRuntime runtime = graalRuntime();
         Register thread = runtime.getRuntime().threadRegister();
         masm.movl(new AMD64Address(thread, runtime.getConfig().pendingDeoptimizationOffset), tasm.runtime.encodeDeoptActionAndReason(action, reason));
-        AMD64Call.directJmp(tasm, masm, tasm.runtime.lookupRuntimeCall(UNCOMMON_TRAP));
+        AMD64Call.directJmp(tasm, masm, tasm.runtime.lookupForeignCall(UNCOMMON_TRAP));
     }
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Fri May 17 15:40:06 2013 +0200
@@ -186,9 +186,9 @@
     private LIRFrameState currentRuntimeCallInfo;
 
     @Override
-    protected void emitCall(RuntimeCallTarget callTarget, Value result, Value[] arguments, Value[] temps, LIRFrameState info) {
+    protected void emitForeignCall(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info) {
         currentRuntimeCallInfo = info;
-        super.emitCall(callTarget, result, arguments, temps, info);
+        super.emitForeignCall(linkage, result, arguments, temps, info);
     }
 
     protected AMD64SaveRegistersOp emitSaveRegisters(Register[] savedRegisters, StackSlot[] savedRegisterLocations) {
@@ -209,39 +209,48 @@
     }
 
     @Override
-    public Variable emitCall(RuntimeCallTarget callTarget, CallingConvention callCc, DeoptimizingNode info, Value... args) {
+    public Variable emitForeignCall(ForeignCallLinkage linkage, DeoptimizingNode info, Value... args) {
         Stub stub = getStub();
-        boolean destroysRegisters = ((HotSpotRuntimeCallTarget) callTarget).destroysRegisters();
-        assert !destroysRegisters || stub != null : "foreign call that destroys registers can only be made from compiled stub, not from " + graph;
+        HotSpotForeignCallLinkage hsLinkage = (HotSpotForeignCallLinkage) linkage;
+        boolean destroysRegisters = hsLinkage.destroysRegisters();
 
         AMD64SaveRegistersOp save = null;
         StackSlot[] savedRegisterLocations = null;
         if (destroysRegisters) {
-            if (stub.preservesRegisters()) {
-                Register[] savedRegisters = frameMap.registerConfig.getAllocatableRegisters();
-                savedRegisterLocations = new StackSlot[savedRegisters.length];
-                for (int i = 0; i < savedRegisters.length; i++) {
-                    PlatformKind kind = target.arch.getLargestStorableKind(savedRegisters[i].getRegisterCategory());
-                    assert kind != Kind.Illegal;
-                    StackSlot spillSlot = frameMap.allocateSpillSlot(kind);
-                    savedRegisterLocations[i] = spillSlot;
+            if (stub != null) {
+                if (stub.preservesRegisters()) {
+                    Register[] savedRegisters = frameMap.registerConfig.getAllocatableRegisters();
+                    savedRegisterLocations = new StackSlot[savedRegisters.length];
+                    for (int i = 0; i < savedRegisters.length; i++) {
+                        PlatformKind kind = target.arch.getLargestStorableKind(savedRegisters[i].getRegisterCategory());
+                        assert kind != Kind.Illegal;
+                        StackSlot spillSlot = frameMap.allocateSpillSlot(kind);
+                        savedRegisterLocations[i] = spillSlot;
+                    }
+                    save = emitSaveRegisters(savedRegisters, savedRegisterLocations);
                 }
-                save = emitSaveRegisters(savedRegisters, savedRegisterLocations);
             }
+        }
+        if (!hsLinkage.isLeaf()) {
             append(new AMD64HotSpotCRuntimeCallPrologueOp());
         }
 
-        Variable result = super.emitCall(callTarget, callCc, info, args);
+        Variable result = super.emitForeignCall(linkage, info, args);
+
+        if (!hsLinkage.isLeaf()) {
+            append(new AMD64HotSpotCRuntimeCallEpilogueOp());
+        }
 
         if (destroysRegisters) {
-            append(new AMD64HotSpotCRuntimeCallEpilogueOp());
-            if (stub.preservesRegisters()) {
-                assert !calleeSaveInfo.containsKey(currentRuntimeCallInfo);
-                calleeSaveInfo.put(currentRuntimeCallInfo, save);
+            if (stub != null) {
+                if (stub.preservesRegisters()) {
+                    assert !calleeSaveInfo.containsKey(currentRuntimeCallInfo);
+                    calleeSaveInfo.put(currentRuntimeCallInfo, save);
 
-                emitRestoreRegisters(save);
-            } else {
-                assert zapRegisters();
+                    emitRestoreRegisters(save);
+                } else {
+                    assert zapRegisters();
+                }
             }
         }
 
@@ -331,10 +340,10 @@
 
     @Override
     public void emitUnwind(Value exception) {
-        RuntimeCallTarget stub = getRuntime().lookupRuntimeCall(HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER);
-        CallingConvention stubCc = stub.getCallingConvention();
-        assert stubCc.getArgumentCount() == 2;
-        RegisterValue exceptionParameter = (RegisterValue) stubCc.getArgument(0);
+        ForeignCallLinkage linkage = getRuntime().lookupForeignCall(HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER);
+        CallingConvention linkageCc = linkage.getCallingConvention();
+        assert linkageCc.getArgumentCount() == 2;
+        RegisterValue exceptionParameter = (RegisterValue) linkageCc.getArgument(0);
         emitMove(exceptionParameter, exception);
         append(new AMD64HotSpotUnwindOp(exceptionParameter));
     }
@@ -357,11 +366,11 @@
     @Override
     public void emitJumpToExceptionHandlerInCaller(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc) {
         Variable handler = load(operand(handlerInCallerPc));
-        RuntimeCallTarget stub = getRuntime().lookupRuntimeCall(EXCEPTION_HANDLER_IN_CALLER);
-        CallingConvention stubCc = stub.getCallingConvention();
-        assert stubCc.getArgumentCount() == 2;
-        RegisterValue exceptionFixed = (RegisterValue) stubCc.getArgument(0);
-        RegisterValue exceptionPcFixed = (RegisterValue) stubCc.getArgument(1);
+        ForeignCallLinkage linkage = getRuntime().lookupForeignCall(EXCEPTION_HANDLER_IN_CALLER);
+        CallingConvention linkageCc = linkage.getCallingConvention();
+        assert linkageCc.getArgumentCount() == 2;
+        RegisterValue exceptionFixed = (RegisterValue) linkageCc.getArgument(0);
+        RegisterValue exceptionPcFixed = (RegisterValue) linkageCc.getArgument(1);
         emitMove(exceptionFixed, operand(exception));
         emitMove(exceptionPcFixed, operand(exceptionPc));
         AMD64HotSpotJumpToExceptionHandlerInCallerOp op = new AMD64HotSpotJumpToExceptionHandlerInCallerOp(handler, exceptionFixed, exceptionPcFixed);
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRuntime.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRuntime.java	Fri May 17 15:40:06 2013 +0200
@@ -24,9 +24,11 @@
 
 import static com.oracle.graal.amd64.AMD64.*;
 import static com.oracle.graal.api.code.CallingConvention.Type.*;
+import static com.oracle.graal.api.meta.Value.*;
 import static com.oracle.graal.hotspot.HotSpotBackend.*;
-import static com.oracle.graal.hotspot.HotSpotRuntimeCallTarget.*;
-import static com.oracle.graal.hotspot.HotSpotRuntimeCallTarget.RegisterEffect.*;
+import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.*;
+import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.RegisterEffect.*;
+import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.Transition.*;
 import static com.oracle.graal.hotspot.replacements.AESCryptSubstitutions.DecryptBlockStubCall.*;
 import static com.oracle.graal.hotspot.replacements.AESCryptSubstitutions.EncryptBlockStubCall.*;
 import static com.oracle.graal.hotspot.replacements.CipherBlockChainingSubstitutions.DecryptAESCryptStubCall.*;
@@ -59,15 +61,15 @@
         // in templateInterpreter_x86_64.cpp around line 1923
         RegisterValue exception = rax.asValue(Kind.Object);
         RegisterValue exceptionPc = rdx.asValue(word);
-        CallingConvention exceptionCc = new CallingConvention(0, Value.ILLEGAL, exception, exceptionPc);
-        register(new HotSpotRuntimeCallTarget(EXCEPTION_HANDLER, 0L, PRESERVES_REGISTERS, exceptionCc, graalRuntime.getCompilerToVM()));
-        register(new HotSpotRuntimeCallTarget(EXCEPTION_HANDLER_IN_CALLER, JUMP_ADDRESS, PRESERVES_REGISTERS, exceptionCc, graalRuntime.getCompilerToVM()));
+        CallingConvention exceptionCc = new CallingConvention(0, ILLEGAL, exception, exceptionPc);
+        register(new HotSpotForeignCallLinkage(EXCEPTION_HANDLER, 0L, PRESERVES_REGISTERS, LEAF, exceptionCc));
+        register(new HotSpotForeignCallLinkage(EXCEPTION_HANDLER_IN_CALLER, JUMP_ADDRESS, PRESERVES_REGISTERS, LEAF, exceptionCc));
 
-        // The crypto stubs do callee saving
-        registerLeafCall(ENCRYPT_BLOCK, config.aescryptEncryptBlockStub, NativeCall, PRESERVES_REGISTERS);
-        registerLeafCall(DECRYPT_BLOCK, config.aescryptDecryptBlockStub, NativeCall, PRESERVES_REGISTERS);
-        registerLeafCall(ENCRYPT, config.cipherBlockChainingEncryptAESCryptStub, NativeCall, PRESERVES_REGISTERS);
-        registerLeafCall(DECRYPT, config.cipherBlockChainingDecryptAESCryptStub, NativeCall, PRESERVES_REGISTERS);
+        // The x86 crypto stubs do callee saving
+        registerForeignCall(ENCRYPT_BLOCK, config.aescryptEncryptBlockStub, NativeCall, PRESERVES_REGISTERS, LEAF);
+        registerForeignCall(DECRYPT_BLOCK, config.aescryptDecryptBlockStub, NativeCall, PRESERVES_REGISTERS, LEAF);
+        registerForeignCall(ENCRYPT, config.cipherBlockChainingEncryptAESCryptStub, NativeCall, PRESERVES_REGISTERS, LEAF);
+        registerForeignCall(DECRYPT, config.cipherBlockChainingDecryptAESCryptStub, NativeCall, PRESERVES_REGISTERS, LEAF);
 
         convertSnippets = new AMD64ConvertSnippets.Templates(this, replacements, graalRuntime.getTarget());
         super.registerReplacements(replacements);
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotUnwindOp.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotUnwindOp.java	Fri May 17 15:40:06 2013 +0200
@@ -51,8 +51,8 @@
     public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
         leaveFrameAndRestoreRbp(tasm, masm);
 
-        RuntimeCallTarget stub = tasm.runtime.lookupRuntimeCall(UNWIND_EXCEPTION_TO_CALLER);
-        CallingConvention cc = stub.getCallingConvention();
+        ForeignCallLinkage linkage = tasm.runtime.lookupForeignCall(UNWIND_EXCEPTION_TO_CALLER);
+        CallingConvention cc = linkage.getCallingConvention();
         assert cc.getArgumentCount() == 2;
         assert exception.equals(cc.getArgument(0));
 
@@ -60,6 +60,6 @@
         Register returnAddress = asRegister(cc.getArgument(1));
         masm.movq(returnAddress, new AMD64Address(rsp, 0));
 
-        AMD64Call.directJmp(tasm, masm, tasm.runtime.lookupRuntimeCall(HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER));
+        AMD64Call.directJmp(tasm, masm, tasm.runtime.lookupForeignCall(HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER));
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java	Fri May 17 15:40:06 2013 +0200
@@ -22,8 +22,8 @@
  */
 package com.oracle.graal.hotspot;
 
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.hotspot.bridge.*;
 import com.oracle.graal.hotspot.meta.*;
@@ -39,34 +39,34 @@
     /**
      * Descriptor for SharedRuntime::deopt_blob()->uncommon_trap().
      */
-    public static final Descriptor UNCOMMON_TRAP = new Descriptor("deoptimize", true, void.class);
+    public static final ForeignCallDescriptor UNCOMMON_TRAP = new ForeignCallDescriptor("deoptimize", void.class);
 
     /**
      * Descriptor for {@link ExceptionHandlerStub}. This stub is called by the
      * {@linkplain Marks#MARK_EXCEPTION_HANDLER_ENTRY exception handler} in a compiled method.
      */
-    public static final Descriptor EXCEPTION_HANDLER = new Descriptor("exceptionHandler", true, void.class, Object.class, Word.class);
+    public static final ForeignCallDescriptor EXCEPTION_HANDLER = new ForeignCallDescriptor("exceptionHandler", void.class, Object.class, Word.class);
 
     /**
      * Descriptor for SharedRuntime::deopt_blob()->unpack().
      */
-    public static final Descriptor DEOPT_HANDLER = new Descriptor("deoptHandler", true, void.class);
+    public static final ForeignCallDescriptor DEOPT_HANDLER = new ForeignCallDescriptor("deoptHandler", void.class);
 
     /**
      * Descriptor for SharedRuntime::get_ic_miss_stub().
      */
-    public static final Descriptor IC_MISS_HANDLER = new Descriptor("icMissHandler", true, void.class);
+    public static final ForeignCallDescriptor IC_MISS_HANDLER = new ForeignCallDescriptor("icMissHandler", void.class);
 
     /**
      * Descriptor for {@link UnwindExceptionToCallerStub}. This stub is called by code generated
      * from {@link UnwindNode}.
      */
-    public static final Descriptor UNWIND_EXCEPTION_TO_CALLER = new Descriptor("unwindExceptionToCaller", true, void.class, Object.class, Word.class);
+    public static final ForeignCallDescriptor UNWIND_EXCEPTION_TO_CALLER = new ForeignCallDescriptor("unwindExceptionToCaller", void.class, Object.class, Word.class);
 
     /**
      * Descriptor for the arguments when unwinding to an exception handler in a caller.
      */
-    public static final Descriptor EXCEPTION_HANDLER_IN_CALLER = new Descriptor("exceptionHandlerInCaller", false, void.class, Object.class, Word.class);
+    public static final ForeignCallDescriptor EXCEPTION_HANDLER_IN_CALLER = new ForeignCallDescriptor("exceptionHandlerInCaller", void.class, Object.class, Word.class);
 
     public HotSpotBackend(HotSpotRuntime runtime, TargetDescription target) {
         super(runtime, target);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledRuntimeStub.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledRuntimeStub.java	Fri May 17 15:40:06 2013 +0200
@@ -57,9 +57,9 @@
         for (Infopoint infopoint : compResult.getInfopoints()) {
             assert infopoint instanceof Call : this + " cannot have non-call infopoint: " + infopoint;
             Call call = (Call) infopoint;
-            assert call.target instanceof HotSpotRuntimeCallTarget : this + " cannot have non runtime call: " + call.target;
-            HotSpotRuntimeCallTarget callTarget = (HotSpotRuntimeCallTarget) call.target;
-            assert !callTarget.isCompiledStub() : this + " cannot call compiled stub " + callTarget;
+            assert call.target instanceof HotSpotForeignCallLinkage : this + " cannot have non runtime call: " + call.target;
+            HotSpotForeignCallLinkage linkage = (HotSpotForeignCallLinkage) call.target;
+            assert !linkage.isCompiledStub() : this + " cannot call compiled stub " + linkage;
         }
         return true;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotForeignCallLinkage.java	Fri May 17 15:40:06 2013 +0200
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot;
+
+import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.RegisterEffect.*;
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.code.CallingConvention.Type;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.target.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.stubs.*;
+import com.oracle.graal.word.*;
+
+/**
+ * The details required to link a HotSpot runtime or stub call.
+ */
+public class HotSpotForeignCallLinkage implements ForeignCallLinkage, InvokeTarget {
+
+    /**
+     * Constants for specifying whether a foreign call destroys or preserves registers. A foreign
+     * call will always destroy {@link HotSpotForeignCallLinkage#getCallingConvention() its}
+     * {@linkplain ForeignCallLinkage#getTemporaries() temporary} registers.
+     */
+    public enum RegisterEffect {
+        DESTROYS_REGISTERS, PRESERVES_REGISTERS
+    }
+
+    /**
+     * Constants for specifying whether a call is a leaf or not. A leaf function does not lock, GC
+     * or throw exceptions. That is, the thread's execution state during the call is never inspected
+     * by another thread.
+     */
+    public enum Transition {
+        LEAF, NOT_LEAF;
+    }
+
+    /**
+     * Sentinel marker for a computed jump address.
+     */
+    public static final long JUMP_ADDRESS = 0xDEADDEADBEEFBEEFL;
+
+    /**
+     * The descriptor of the call.
+     */
+    private final ForeignCallDescriptor descriptor;
+
+    /**
+     * The entry point address of this call's target.
+     */
+    private long address;
+
+    /**
+     * Non-null (eventually) iff this is a call to a compiled {@linkplain Stub stub}.
+     */
+    private Stub stub;
+
+    /**
+     * The calling convention for this call.
+     */
+    private final CallingConvention cc;
+
+    private final RegisterEffect effect;
+
+    private final Transition transition;
+
+    /**
+     * The locations defined/killed by the call.
+     */
+    private Value[] temporaries = AllocatableValue.NONE;
+
+    /**
+     * Creates a {@link HotSpotForeignCallLinkage}.
+     * 
+     * @param descriptor the descriptor of the call
+     * @param address the address of the code to call
+     * @param effect specifies if the call destroys or preserves all registers (apart from
+     *            temporaries which are always destroyed)
+     * @param ccType calling convention type
+     * @param transition specifies if this is a {@linkplain #isLeaf() leaf} call
+     */
+    public static HotSpotForeignCallLinkage create(ForeignCallDescriptor descriptor, long address, RegisterEffect effect, Type ccType, Transition transition) {
+        CallingConvention targetCc = createCallingConvention(descriptor, ccType);
+        return new HotSpotForeignCallLinkage(descriptor, address, effect, transition, targetCc);
+    }
+
+    /**
+     * Gets a calling convention for a given descriptor and call type.
+     */
+    public static CallingConvention createCallingConvention(ForeignCallDescriptor descriptor, Type ccType) {
+        HotSpotRuntime runtime = graalRuntime().getRuntime();
+        Class<?>[] argumentTypes = descriptor.getArgumentTypes();
+        JavaType[] parameterTypes = new JavaType[argumentTypes.length];
+        for (int i = 0; i < parameterTypes.length; ++i) {
+            parameterTypes[i] = asJavaType(argumentTypes[i], runtime);
+        }
+        TargetDescription target = graalRuntime().getTarget();
+        JavaType returnType = asJavaType(descriptor.getResultType(), runtime);
+        return runtime.lookupRegisterConfig().getCallingConvention(ccType, returnType, parameterTypes, target, false);
+    }
+
+    private static JavaType asJavaType(Class type, HotSpotRuntime runtime) {
+        if (WordBase.class.isAssignableFrom(type)) {
+            return runtime.lookupJavaType(wordKind().toJavaClass());
+        } else {
+            return runtime.lookupJavaType(type);
+        }
+    }
+
+    public HotSpotForeignCallLinkage(ForeignCallDescriptor descriptor, long address, RegisterEffect effect, Transition transition, CallingConvention cc) {
+        this.address = address;
+        this.effect = effect;
+        this.transition = transition;
+        this.descriptor = descriptor;
+        this.cc = cc;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder(stub == null ? descriptor.toString() : stub.toString());
+        sb.append("@0x").append(Long.toHexString(address)).append(':').append(cc);
+        if (temporaries != null && temporaries.length != 0) {
+            sb.append("; temps=");
+            String sep = "";
+            for (Value op : temporaries) {
+                sb.append(sep).append(op);
+                sep = ",";
+            }
+        }
+        return sb.toString();
+    }
+
+    public CallingConvention getCallingConvention() {
+        return cc;
+    }
+
+    public Value[] getTemporaries() {
+        if (temporaries.length == 0) {
+            return temporaries;
+        }
+        return temporaries.clone();
+    }
+
+    public long getMaxCallTargetOffset() {
+        return graalRuntime().getCompilerToVM().getMaxCallTargetOffset(address);
+    }
+
+    public ForeignCallDescriptor getDescriptor() {
+        return descriptor;
+    }
+
+    public void setCompiledStub(Stub stub) {
+        assert address == 0L : "cannot set stub for linkage that already has an address: " + this;
+        this.stub = stub;
+    }
+
+    /**
+     * Determines if this is a call to a compiled {@linkplain Stub stub}.
+     */
+    public boolean isCompiledStub() {
+        return address == 0L || stub != null;
+    }
+
+    public void finalizeAddress(Backend backend) {
+        if (address == 0) {
+            assert stub != null : "linkage without an address must be a stub - forgot to register a Stub associated with " + descriptor + "?";
+            InstalledCode code = stub.getCode(backend);
+
+            Set<Register> destroyedRegisters = stub.getDestroyedRegisters();
+            if (!destroyedRegisters.isEmpty()) {
+                AllocatableValue[] temporaryLocations = new AllocatableValue[destroyedRegisters.size()];
+                int i = 0;
+                for (Register reg : destroyedRegisters) {
+                    temporaryLocations[i++] = reg.asValue();
+                }
+                temporaries = temporaryLocations;
+            }
+            address = code.getStart();
+        }
+    }
+
+    public long getAddress() {
+        assert address != 0L : "address not yet finalized: " + this;
+        return address;
+    }
+
+    @Override
+    public boolean destroysRegisters() {
+        return effect == DESTROYS_REGISTERS;
+    }
+
+    /**
+     * Determines if this is call to a function that does not lock, GC or throw exceptions. That is,
+     * the thread's execution state during the call is never inspected by another thread.
+     */
+    public boolean isLeaf() {
+        return transition == Transition.LEAF;
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotRuntimeCallTarget.java	Fri May 17 15:38:22 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,183 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot;
-
-import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
-import static com.oracle.graal.hotspot.HotSpotRuntimeCallTarget.RegisterEffect.*;
-
-import java.util.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.CallingConvention.Type;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.target.*;
-import com.oracle.graal.hotspot.bridge.*;
-import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.hotspot.stubs.*;
-import com.oracle.graal.word.*;
-
-/**
- * The details required to link a HotSpot runtime or stub call.
- */
-public class HotSpotRuntimeCallTarget implements RuntimeCallTarget, InvokeTarget {
-
-    /**
-     * Constants for specifying whether a call destroys or preserves registers. A call will always
-     * destroy {@link HotSpotRuntimeCallTarget#getCallingConvention() its}
-     * {@linkplain CallingConvention#getTemporaries() temporary} registers.
-     */
-    public enum RegisterEffect {
-        DESTROYS_REGISTERS, PRESERVES_REGISTERS
-    }
-
-    /**
-     * Sentinel marker for a computed jump address.
-     */
-    public static final long JUMP_ADDRESS = 0xDEADDEADBEEFBEEFL;
-
-    /**
-     * The descriptor of the call.
-     */
-    private final Descriptor descriptor;
-
-    /**
-     * The entry point address of this call's target.
-     */
-    private long address;
-
-    /**
-     * Non-null (eventually) iff this is a call to a compiled {@linkplain Stub stub}.
-     */
-    private Stub stub;
-
-    /**
-     * The calling convention for this call.
-     */
-    private CallingConvention cc;
-
-    private final CompilerToVM vm;
-
-    private final RegisterEffect effect;
-
-    /**
-     * Creates a {@link HotSpotRuntimeCallTarget}.
-     * 
-     * @param descriptor the descriptor of the call
-     * @param address the address of the code to call
-     * @param effect specifies if the call destroys or preserves all registers (apart from
-     *            temporaries which are always destroyed)
-     * @param ccType calling convention type
-     * @param ccProvider calling convention provider
-     * @param vm the Java to HotSpot C/C++ runtime interface
-     */
-    public static HotSpotRuntimeCallTarget create(Descriptor descriptor, long address, RegisterEffect effect, Type ccType, RegisterConfig ccProvider, HotSpotRuntime runtime, CompilerToVM vm) {
-        CallingConvention targetCc = createCallingConvention(descriptor, ccType, ccProvider, runtime);
-        return new HotSpotRuntimeCallTarget(descriptor, address, effect, targetCc, vm);
-    }
-
-    /**
-     * Gets a calling convention for a given descriptor and call type.
-     */
-    public static CallingConvention createCallingConvention(Descriptor descriptor, Type ccType, RegisterConfig ccProvider, HotSpotRuntime runtime) {
-        Class<?>[] argumentTypes = descriptor.getArgumentTypes();
-        JavaType[] parameterTypes = new JavaType[argumentTypes.length];
-        for (int i = 0; i < parameterTypes.length; ++i) {
-            parameterTypes[i] = asJavaType(argumentTypes[i], runtime);
-        }
-        TargetDescription target = graalRuntime().getTarget();
-        JavaType returnType = asJavaType(descriptor.getResultType(), runtime);
-        return ccProvider.getCallingConvention(ccType, returnType, parameterTypes, target, false);
-    }
-
-    private static JavaType asJavaType(Class type, HotSpotRuntime runtime) {
-        if (WordBase.class.isAssignableFrom(type)) {
-            return runtime.lookupJavaType(wordKind().toJavaClass());
-        } else {
-            return runtime.lookupJavaType(type);
-        }
-    }
-
-    public HotSpotRuntimeCallTarget(Descriptor descriptor, long address, RegisterEffect effect, CallingConvention cc, CompilerToVM vm) {
-        this.address = address;
-        this.effect = effect;
-        this.descriptor = descriptor;
-        this.cc = cc;
-        this.vm = vm;
-    }
-
-    @Override
-    public String toString() {
-        return (stub == null ? descriptor.toString() : stub) + "@0x" + Long.toHexString(address) + ":" + cc;
-    }
-
-    public CallingConvention getCallingConvention() {
-        return cc;
-    }
-
-    public long getMaxCallTargetOffset() {
-        return vm.getMaxCallTargetOffset(address);
-    }
-
-    public Descriptor getDescriptor() {
-        return descriptor;
-    }
-
-    public void setCompiledStub(Stub stub) {
-        assert address == 0L : "cannot set stub for linkage that already has an address: " + this;
-        this.stub = stub;
-    }
-
-    /**
-     * Determines if this is a call to a compiled {@linkplain Stub stub}.
-     */
-    public boolean isCompiledStub() {
-        return address == 0L || stub != null;
-    }
-
-    public void finalizeAddress(Backend backend) {
-        if (address == 0) {
-            assert stub != null : "linkage without an address must be a stub - forgot to register a Stub associated with " + descriptor + "?";
-            InstalledCode code = stub.getCode(backend);
-
-            Set<Register> destroyedRegisters = stub.getDestroyedRegisters();
-            AllocatableValue[] temporaryLocations = new AllocatableValue[destroyedRegisters.size()];
-            int i = 0;
-            for (Register reg : destroyedRegisters) {
-                temporaryLocations[i++] = reg.asValue();
-            }
-            // Update calling convention with temporaries
-            cc = new CallingConvention(temporaryLocations, cc.getStackSize(), cc.getReturn(), cc.getArguments());
-            address = code.getStart();
-        }
-    }
-
-    public long getAddress() {
-        assert address != 0L : "address not yet finalized: " + this;
-        return address;
-    }
-
-    @Override
-    public boolean destroysRegisters() {
-        return effect == DESTROYS_REGISTERS;
-    }
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompiler.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompiler.java	Fri May 17 15:40:06 2013 +0200
@@ -53,7 +53,7 @@
 
     void shutdownCompiler() throws Throwable;
 
-    void startCompiler() throws Throwable;
+    void startCompiler(boolean bootstrapEnabled) throws Throwable;
 
     void bootstrap() throws Throwable;
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Fri May 17 15:40:06 2013 +0200
@@ -101,7 +101,9 @@
         assert unsafe.getObject(mirror, offset) == type;
     }
 
-    public void startCompiler() throws Throwable {
+    public void startCompiler(boolean bootstrapEnabled) throws Throwable {
+
+        bootstrapRunning = bootstrapEnabled;
 
         HotSpotVMConfig config = graalRuntime.getConfig();
         long offset = config.graalMirrorInClassOffset;
@@ -339,7 +341,6 @@
         TTY.flush();
         long startTime = System.currentTimeMillis();
 
-        bootstrapRunning = true;
         boolean firstRun = true;
         do {
             // Initialize compile queue with a selected set of methods.
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Fri May 17 15:40:06 2013 +0200
@@ -28,8 +28,9 @@
 import static com.oracle.graal.api.meta.DeoptimizationReason.*;
 import static com.oracle.graal.graph.UnsafeAccess.*;
 import static com.oracle.graal.hotspot.HotSpotBackend.*;
-import static com.oracle.graal.hotspot.HotSpotGraalRuntime.wordKind;
-import static com.oracle.graal.hotspot.HotSpotRuntimeCallTarget.RegisterEffect.*;
+import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.RegisterEffect.*;
+import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.Transition.*;
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 import static com.oracle.graal.hotspot.nodes.MonitorEnterStubCall.*;
 import static com.oracle.graal.hotspot.nodes.MonitorExitStubCall.*;
 import static com.oracle.graal.hotspot.nodes.NewArrayStubCall.*;
@@ -40,20 +41,12 @@
 import static com.oracle.graal.hotspot.nodes.VerifyOopStubCall.*;
 import static com.oracle.graal.hotspot.nodes.WriteBarrierPostStubCall.*;
 import static com.oracle.graal.hotspot.nodes.WriteBarrierPreStubCall.*;
-import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 import static com.oracle.graal.hotspot.replacements.SystemSubstitutions.*;
 import static com.oracle.graal.hotspot.stubs.ExceptionHandlerStub.*;
-import static com.oracle.graal.hotspot.stubs.LogObjectStub.*;
-import static com.oracle.graal.hotspot.stubs.LogPrimitiveStub.*;
-import static com.oracle.graal.hotspot.stubs.LogPrintfStub.*;
 import static com.oracle.graal.hotspot.stubs.NewArrayStub.*;
 import static com.oracle.graal.hotspot.stubs.NewInstanceStub.*;
-import static com.oracle.graal.hotspot.stubs.NewMultiArrayStub.*;
-import static com.oracle.graal.hotspot.stubs.OSRMigrationEndStub.*;
 import static com.oracle.graal.hotspot.stubs.StubUtil.*;
-import static com.oracle.graal.hotspot.stubs.ThreadIsInterruptedStub.*;
 import static com.oracle.graal.hotspot.stubs.UnwindExceptionToCallerStub.*;
-import static com.oracle.graal.hotspot.stubs.VMErrorStub.*;
 import static com.oracle.graal.java.GraphBuilderPhase.RuntimeCalls.*;
 import static com.oracle.graal.nodes.java.RegisterFinalizerNode.*;
 import static com.oracle.graal.replacements.Log.*;
@@ -70,11 +63,11 @@
 import com.oracle.graal.api.code.CompilationResult.DataPatch;
 import com.oracle.graal.api.code.CompilationResult.Infopoint;
 import com.oracle.graal.api.code.CompilationResult.Mark;
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
-import com.oracle.graal.hotspot.HotSpotRuntimeCallTarget.*;
+import com.oracle.graal.hotspot.HotSpotForeignCallLinkage.RegisterEffect;
+import com.oracle.graal.hotspot.HotSpotForeignCallLinkage.Transition;
 import com.oracle.graal.hotspot.bridge.*;
 import com.oracle.graal.hotspot.bridge.CompilerToVM.CodeInstallResult;
 import com.oracle.graal.hotspot.nodes.*;
@@ -100,7 +93,8 @@
  */
 public abstract class HotSpotRuntime implements GraalCodeCacheProvider, DisassemblerProvider, BytecodeDisassemblerProvider {
 
-    public static final Descriptor OSR_MIGRATION_END = new Descriptor("OSR_migration_end", true, void.class, long.class);
+    public static final ForeignCallDescriptor OSR_MIGRATION_END = new ForeignCallDescriptor("OSR_migration_end", void.class, long.class);
+    public static final ForeignCallDescriptor IDENTITY_HASHCODE = new ForeignCallDescriptor("identity_hashcode", int.class, Object.class);
 
     public final HotSpotVMConfig config;
 
@@ -115,7 +109,7 @@
     private BoxingSnippets.Templates boxingSnippets;
     private LoadExceptionObjectSnippets.Templates exceptionObjectSnippets;
 
-    private final Map<Descriptor, HotSpotRuntimeCallTarget> runtimeCalls = new HashMap<>();
+    private final Map<ForeignCallDescriptor, HotSpotForeignCallLinkage> foreignCalls = new HashMap<>();
 
     /**
      * The offset from the origin of an array to the first element.
@@ -183,82 +177,95 @@
         regConfig = createRegisterConfig();
     }
 
-    protected HotSpotRuntimeCallTarget register(HotSpotRuntimeCallTarget call) {
-        HotSpotRuntimeCallTarget oldValue = runtimeCalls.put(call.getDescriptor(), call);
-        assert oldValue == null;
-        return call;
-    }
+    protected abstract RegisterConfig createRegisterConfig();
 
     /**
-     * Registers the details for linking a call to a {@link Stub}.
+     * Registers the linkage for a foreign call.
      */
-    protected RuntimeCallTarget registerStubCall(Descriptor descriptor) {
-        return register(HotSpotRuntimeCallTarget.create(descriptor, 0L, PRESERVES_REGISTERS, JavaCallee, regConfig, this, graalRuntime.getCompilerToVM()));
+    protected HotSpotForeignCallLinkage register(HotSpotForeignCallLinkage linkage) {
+        assert !foreignCalls.containsKey(linkage.getDescriptor()) : "already registered linkage for " + linkage.getDescriptor();
+        foreignCalls.put(linkage.getDescriptor(), linkage);
+        return linkage;
     }
 
     /**
-     * Registers the details for a call to a runtime C/C++ function.
+     * Creates and registers the details for linking a foreign call to a {@link Stub}.
      */
-    protected RuntimeCallTarget registerCRuntimeCall(Descriptor descriptor, long address) {
-        Class<?> resultType = descriptor.getResultType();
-        assert resultType.isPrimitive() || Word.class.isAssignableFrom(resultType) : "C runtime call must return object thread local storage: " + descriptor;
-        return register(HotSpotRuntimeCallTarget.create(descriptor, address, DESTROYS_REGISTERS, NativeCall, regConfig, this, graalRuntime.getCompilerToVM()));
+    protected HotSpotForeignCallLinkage registerStubCall(ForeignCallDescriptor descriptor) {
+        return register(HotSpotForeignCallLinkage.create(descriptor, 0L, PRESERVES_REGISTERS, JavaCallee, NOT_LEAF));
     }
 
     /**
-     * Registers the details for a call to a stub that never returns.
+     * Creates and registers the linkage for a foreign call.
      */
-    protected RuntimeCallTarget registerNoReturnStub(Descriptor descriptor, long address, CallingConvention.Type ccType) {
-        return register(HotSpotRuntimeCallTarget.create(descriptor, address, PRESERVES_REGISTERS, ccType, regConfig, this, graalRuntime.getCompilerToVM()));
+    protected HotSpotForeignCallLinkage registerForeignCall(ForeignCallDescriptor descriptor, long address, CallingConvention.Type ccType, RegisterEffect effect, Transition transition) {
+        Class<?> resultType = descriptor.getResultType();
+        assert resultType.isPrimitive() || Word.class.isAssignableFrom(resultType) : "foreign calls must return objects in thread local storage: " + descriptor;
+        return register(HotSpotForeignCallLinkage.create(descriptor, address, effect, ccType, transition));
+    }
+
+    private static void link(Stub stub) {
+        stub.getLinkage().setCompiledStub(stub);
     }
 
     /**
-     * Registers the details for a call to a leaf function. A leaf function does not lock, GC or
-     * throw exceptions. That is, the thread's execution state during the call is never inspected by
-     * another thread.
+     * Creates a {@linkplain ForeignCallStub stub} for a non-leaf foreign call.
+     * 
+     * @param descriptor the signature of the call to this stub
+     * @param address the address of the code to call
+     * @param prependThread true if the JavaThread value for the current thread is to be prepended
+     *            to the arguments for the call to {@code address}
      */
-    protected RuntimeCallTarget registerLeafCall(Descriptor descriptor, long address, CallingConvention.Type ccType, RegisterEffect effect) {
-        return register(HotSpotRuntimeCallTarget.create(descriptor, address, effect, ccType, regConfig, this, graalRuntime.getCompilerToVM()));
+    private void linkForeignCall(ForeignCallDescriptor descriptor, long address, boolean prependThread, Replacements replacements) {
+        ForeignCallStub stub = new ForeignCallStub(address, descriptor, prependThread, this, replacements);
+        HotSpotForeignCallLinkage linkage = stub.getLinkage();
+        HotSpotForeignCallLinkage targetLinkage = stub.getTargetLinkage();
+        linkage.setCompiledStub(stub);
+        register(linkage);
+        register(targetLinkage);
     }
 
-    protected abstract RegisterConfig createRegisterConfig();
-
     public void registerReplacements(Replacements replacements) {
-        registerStubCall(VERIFY_OOP);
-        registerStubCall(OSR_MIGRATION_END);
-        registerStubCall(NEW_ARRAY);
-        registerStubCall(UNWIND_EXCEPTION_TO_CALLER);
-        registerStubCall(NEW_INSTANCE);
-        registerStubCall(NEW_MULTI_ARRAY);
-        registerStubCall(LOG_PRIMITIVE);
-        registerStubCall(LOG_PRINTF);
-        registerStubCall(LOG_OBJECT);
-        registerStubCall(THREAD_IS_INTERRUPTED);
-        registerStubCall(VM_ERROR);
+        HotSpotVMConfig c = config;
+        TargetDescription target = getTarget();
+
+        registerForeignCall(UNCOMMON_TRAP, c.uncommonTrapStub, NativeCall, PRESERVES_REGISTERS, LEAF);
+        registerForeignCall(DEOPT_HANDLER, c.handleDeoptStub, NativeCall, PRESERVES_REGISTERS, LEAF);
+        registerForeignCall(IC_MISS_HANDLER, c.inlineCacheMissStub, NativeCall, PRESERVES_REGISTERS, LEAF);
 
-        HotSpotVMConfig c = config;
-        registerNoReturnStub(UNCOMMON_TRAP, c.uncommonTrapStub, NativeCall);
-        registerNoReturnStub(DEOPT_HANDLER, c.handleDeoptStub, NativeCall);
-        registerNoReturnStub(IC_MISS_HANDLER, c.inlineCacheMissStub, NativeCall);
+        registerForeignCall(JAVA_TIME_MILLIS, c.javaTimeMillisAddress, NativeCall, DESTROYS_REGISTERS, LEAF);
+        registerForeignCall(JAVA_TIME_NANOS, c.javaTimeNanosAddress, NativeCall, DESTROYS_REGISTERS, LEAF);
+        registerForeignCall(ARITHMETIC_SIN, c.arithmeticSinAddress, NativeCall, DESTROYS_REGISTERS, LEAF);
+        registerForeignCall(ARITHMETIC_COS, c.arithmeticCosAddress, NativeCall, DESTROYS_REGISTERS, LEAF);
+        registerForeignCall(ARITHMETIC_TAN, c.arithmeticTanAddress, NativeCall, DESTROYS_REGISTERS, LEAF);
+
+        registerForeignCall(EXCEPTION_HANDLER_FOR_PC, c.exceptionHandlerForPcAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF);
+        registerForeignCall(EXCEPTION_HANDLER_FOR_RETURN_ADDRESS, c.exceptionHandlerForReturnAddressAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF);
+        registerForeignCall(NEW_ARRAY_C, c.newArrayAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF);
+        registerForeignCall(NEW_INSTANCE_C, c.newInstanceAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF);
+        registerForeignCall(VM_MESSAGE_C, c.vmMessageAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF);
 
-        registerLeafCall(JAVA_TIME_MILLIS, c.javaTimeMillisAddress, NativeCall, DESTROYS_REGISTERS);
-        registerLeafCall(JAVA_TIME_NANOS, c.javaTimeNanosAddress, NativeCall, DESTROYS_REGISTERS);
-        registerLeafCall(ARITHMETIC_SIN, c.arithmeticSinAddress, NativeCall, DESTROYS_REGISTERS);
-        registerLeafCall(ARITHMETIC_COS, c.arithmeticCosAddress, NativeCall, DESTROYS_REGISTERS);
-        registerLeafCall(ARITHMETIC_TAN, c.arithmeticTanAddress, NativeCall, DESTROYS_REGISTERS);
+        link(new NewInstanceStub(this, replacements, target, registerStubCall(NEW_INSTANCE)));
+        link(new NewArrayStub(this, replacements, target, registerStubCall(NEW_ARRAY)));
+        link(new ExceptionHandlerStub(this, replacements, target, foreignCalls.get(EXCEPTION_HANDLER)));
+        link(new UnwindExceptionToCallerStub(this, replacements, target, registerStubCall(UNWIND_EXCEPTION_TO_CALLER)));
+        link(new VerifyOopStub(this, replacements, target, registerStubCall(VERIFY_OOP)));
 
-        registerCRuntimeCall(OSR_MIGRATION_END_C, c.osrMigrationEndAddress);
-        registerCRuntimeCall(EXCEPTION_HANDLER_FOR_PC, c.exceptionHandlerForPcAddress);
-        registerCRuntimeCall(EXCEPTION_HANDLER_FOR_RETURN_ADDRESS, c.exceptionHandlerForReturnAddressAddress);
-        registerCRuntimeCall(NEW_ARRAY_C, c.newArrayAddress);
-        registerCRuntimeCall(NEW_INSTANCE_C, c.newInstanceAddress);
-        registerCRuntimeCall(NEW_MULTI_ARRAY_C, c.newMultiArrayAddress);
-        registerCRuntimeCall(LOG_PRIMITIVE_C, c.logPrimitiveAddress);
-        registerCRuntimeCall(LOG_PRINTF_C, c.logObjectAddress);
-        registerCRuntimeCall(VM_MESSAGE_C, c.vmMessageAddress);
-        registerCRuntimeCall(LOG_OBJECT_C, c.logObjectAddress);
-        registerCRuntimeCall(THREAD_IS_INTERRUPTED_C, c.threadIsInterruptedAddress);
-        registerCRuntimeCall(VM_ERROR_C, c.vmErrorAddress);
+        linkForeignCall(IDENTITY_HASHCODE, c.identityHashCodeAddress, true, replacements);
+        linkForeignCall(REGISTER_FINALIZER, c.registerFinalizerAddress, true, replacements);
+        linkForeignCall(CREATE_NULL_POINTER_EXCEPTION, c.createNullPointerExceptionAddress, true, replacements);
+        linkForeignCall(CREATE_OUT_OF_BOUNDS_EXCEPTION, c.createOutOfBoundsExceptionAddress, true, replacements);
+        linkForeignCall(MONITORENTER, c.monitorenterAddress, true, replacements);
+        linkForeignCall(MONITOREXIT, c.monitorexitAddress, true, replacements);
+        linkForeignCall(WRITE_BARRIER_PRE, c.writeBarrierPreAddress, true, replacements);
+        linkForeignCall(WRITE_BARRIER_POST, c.writeBarrierPostAddress, true, replacements);
+        linkForeignCall(NEW_MULTI_ARRAY, c.newMultiArrayAddress, true, replacements);
+        linkForeignCall(LOG_PRINTF, c.logPrintfAddress, true, replacements);
+        linkForeignCall(LOG_OBJECT, c.logObjectAddress, true, replacements);
+        linkForeignCall(LOG_PRIMITIVE, c.logPrimitiveAddress, true, replacements);
+        linkForeignCall(THREAD_IS_INTERRUPTED, c.threadIsInterruptedAddress, true, replacements);
+        linkForeignCall(VM_ERROR, c.vmErrorAddress, true, replacements);
+        linkForeignCall(OSR_MIGRATION_END, c.osrMigrationEndAddress, false, replacements);
 
         if (GraalOptions.IntrinsifyObjectMethods) {
             replacements.registerSubstitutions(ObjectSubstitutions.class);
@@ -286,46 +293,10 @@
         checkcastSnippets = new CheckCastSnippets.Templates(this, replacements, graalRuntime.getTarget());
         instanceofSnippets = new InstanceOfSnippets.Templates(this, replacements, graalRuntime.getTarget());
         newObjectSnippets = new NewObjectSnippets.Templates(this, replacements, graalRuntime.getTarget());
-        monitorSnippets = new MonitorSnippets.Templates(this, replacements, graalRuntime.getTarget(), config.useFastLocking);
+        monitorSnippets = new MonitorSnippets.Templates(this, replacements, graalRuntime.getTarget(), c.useFastLocking);
         writeBarrierSnippets = new WriteBarrierSnippets.Templates(this, replacements, graalRuntime.getTarget());
         boxingSnippets = new BoxingSnippets.Templates(this, replacements, graalRuntime.getTarget());
         exceptionObjectSnippets = new LoadExceptionObjectSnippets.Templates(this, replacements, graalRuntime.getTarget());
-
-        TargetDescription target = getTarget();
-        link(new NewInstanceStub(this, replacements, target, runtimeCalls.get(NEW_INSTANCE)));
-        link(new NewArrayStub(this, replacements, target, runtimeCalls.get(NEW_ARRAY)));
-        link(new NewMultiArrayStub(this, replacements, target, runtimeCalls.get(NEW_MULTI_ARRAY)));
-        link(new ThreadIsInterruptedStub(this, replacements, target, runtimeCalls.get(THREAD_IS_INTERRUPTED)));
-        link(new ExceptionHandlerStub(this, replacements, target, runtimeCalls.get(EXCEPTION_HANDLER)));
-        link(new UnwindExceptionToCallerStub(this, replacements, target, runtimeCalls.get(UNWIND_EXCEPTION_TO_CALLER)));
-        link(new VerifyOopStub(this, replacements, target, runtimeCalls.get(VERIFY_OOP)));
-        link(new OSRMigrationEndStub(this, replacements, target, runtimeCalls.get(OSR_MIGRATION_END)));
-        link(new LogPrimitiveStub(this, replacements, target, runtimeCalls.get(LOG_PRIMITIVE)));
-        link(new LogObjectStub(this, replacements, target, runtimeCalls.get(LOG_OBJECT)));
-        link(new LogPrintfStub(this, replacements, target, runtimeCalls.get(LOG_PRINTF)));
-        link(new VMErrorStub(this, replacements, target, runtimeCalls.get(VM_ERROR)));
-
-        linkRuntimeCall(IDENTITY_HASHCODE, config.identityHashCodeAddress, replacements);
-        linkRuntimeCall(REGISTER_FINALIZER, config.registerFinalizerAddress, replacements);
-        linkRuntimeCall(CREATE_NULL_POINTER_EXCEPTION, config.createNullPointerExceptionAddress, replacements);
-        linkRuntimeCall(CREATE_OUT_OF_BOUNDS_EXCEPTION, config.createOutOfBoundsExceptionAddress, replacements);
-        linkRuntimeCall(MONITORENTER, config.monitorenterAddress, replacements);
-        linkRuntimeCall(MONITOREXIT, config.monitorexitAddress, replacements);
-        linkRuntimeCall(WRITE_BARRIER_PRE, config.writeBarrierPreAddress, replacements);
-        linkRuntimeCall(WRITE_BARRIER_POST, config.writeBarrierPostAddress, replacements);
-    }
-
-    private static void link(Stub stub) {
-        stub.getLinkage().setCompiledStub(stub);
-    }
-
-    private void linkRuntimeCall(Descriptor descriptor, long address, Replacements replacements) {
-        RuntimeCallStub stub = new RuntimeCallStub(address, descriptor, true, this, replacements, regConfig, graalRuntime.getCompilerToVM());
-        HotSpotRuntimeCallTarget linkage = stub.getLinkage();
-        HotSpotRuntimeCallTarget targetLinkage = stub.getTargetLinkage();
-        linkage.setCompiledStub(stub);
-        runtimeCalls.put(linkage.getDescriptor(), linkage);
-        runtimeCalls.put(targetLinkage.getDescriptor(), targetLinkage);
     }
 
     public HotSpotGraalRuntime getGraalRuntime() {
@@ -712,8 +683,8 @@
             OSRStartNode osrStart = (OSRStartNode) n;
             StartNode newStart = graph.add(new StartNode());
             LocalNode buffer = graph.unique(new LocalNode(0, StampFactory.forKind(wordKind())));
-            RuntimeCallNode migrationEnd = graph.add(new RuntimeCallNode(OSR_MIGRATION_END, buffer));
-            migrationEnd.setStateAfter(osrStart.stateAfter());
+            ForeignCallNode migrationEnd = graph.add(new ForeignCallNode(OSR_MIGRATION_END, buffer));
+            newStart.setStateAfter(osrStart.stateAfter());
 
             newStart.setNext(migrationEnd);
             FixedNode next = osrStart.next();
@@ -854,9 +825,9 @@
         return HotSpotResolvedObjectType.fromClass(clazz);
     }
 
-    public HotSpotRuntimeCallTarget lookupRuntimeCall(Descriptor descriptor) {
-        HotSpotRuntimeCallTarget callTarget = runtimeCalls.get(descriptor);
-        assert runtimeCalls != null : descriptor;
+    public HotSpotForeignCallLinkage lookupForeignCall(ForeignCallDescriptor descriptor) {
+        HotSpotForeignCallLinkage callTarget = foreignCalls.get(descriptor);
+        assert foreignCalls != null : descriptor;
         callTarget.finalizeAddress(graalRuntime.getBackend());
         return callTarget;
     }
@@ -996,6 +967,15 @@
     }
 
     @Override
+    public boolean hasSideEffect(ForeignCallDescriptor descriptor) {
+        // Only these two foreign calls are expected to be made with
+        // a node that implements StateSplit. They need to be a state
+        // split so that the stack trace they produce is accurate.
+        assert descriptor == CREATE_NULL_POINTER_EXCEPTION || descriptor == CREATE_OUT_OF_BOUNDS_EXCEPTION : descriptor;
+        return false;
+    }
+
+    @Override
     public TargetDescription getTarget() {
         return graalRuntime.getTarget();
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CRuntimeCall.java	Fri May 17 15:38:22 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,72 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.nodes;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.type.*;
-
-/**
- * Implements a direct call to a C/C++ HotSpot function.
- */
-public class CRuntimeCall extends DeoptimizingFixedWithNextNode implements LIRGenLowerable {
-
-    @Input private final NodeInputList<ValueNode> arguments;
-
-    private final Descriptor descriptor;
-
-    public CRuntimeCall(Descriptor descriptor, ValueNode... arguments) {
-        super(StampFactory.forKind(Kind.fromJavaClass(descriptor.getResultType())));
-        this.arguments = new NodeInputList<>(this, arguments);
-        this.descriptor = descriptor;
-    }
-
-    @Override
-    public void generate(LIRGenerator gen) {
-        RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(descriptor);
-        Value[] args = new Value[arguments.size()];
-        for (int i = 0; i < args.length; i++) {
-            args[i] = gen.operand(arguments.get(i));
-        }
-        Variable result = gen.emitCall(stub, stub.getCallingConvention(), this, args);
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-    }
-
-    @Override
-    public boolean canDeoptimize() {
-        return true;
-    }
-
-    @Override
-    public DeoptimizationReason getDeoptimizationReason() {
-        return null;
-    }
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorEnterStubCall.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorEnterStubCall.java	Fri May 17 15:40:06 2013 +0200
@@ -23,7 +23,7 @@
 package com.oracle.graal.hotspot.nodes;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.nodes.*;
@@ -37,7 +37,7 @@
 
     @Input private ValueNode object;
     @Input private ValueNode lock;
-    public static final Descriptor MONITORENTER = new Descriptor("monitorenter", true, void.class, Object.class, Word.class);
+    public static final ForeignCallDescriptor MONITORENTER = new ForeignCallDescriptor("monitorenter", void.class, Object.class, Word.class);
 
     public MonitorEnterStubCall(ValueNode object, ValueNode lock) {
         super(StampFactory.forVoid());
@@ -47,8 +47,8 @@
 
     @Override
     public void generate(LIRGenerator gen) {
-        RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(MONITORENTER);
-        gen.emitCall(stub, stub.getCallingConvention(), this, gen.operand(object), gen.operand(lock));
+        ForeignCallLinkage linkage = gen.getRuntime().lookupForeignCall(MONITORENTER);
+        gen.emitForeignCall(linkage, this, gen.operand(object), gen.operand(lock));
     }
 
     @NodeIntrinsic
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorExitStubCall.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorExitStubCall.java	Fri May 17 15:40:06 2013 +0200
@@ -23,7 +23,7 @@
 package com.oracle.graal.hotspot.nodes;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.hotspot.*;
@@ -38,7 +38,7 @@
 
     @Input private ValueNode object;
     private int lockDepth;
-    public static final Descriptor MONITOREXIT = new Descriptor("monitorexit", true, void.class, Object.class, Word.class);
+    public static final ForeignCallDescriptor MONITOREXIT = new ForeignCallDescriptor("monitorexit", void.class, Object.class, Word.class);
 
     public MonitorExitStubCall(ValueNode object, int lockDepth) {
         super(StampFactory.forVoid());
@@ -51,8 +51,8 @@
         assert lockDepth != -1;
         HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen;
         StackSlot slot = hsGen.getLockSlot(lockDepth);
-        RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(MonitorExitStubCall.MONITOREXIT);
-        gen.emitCall(stub, stub.getCallingConvention(), this, gen.operand(object), gen.emitAddress(slot));
+        ForeignCallLinkage linkage = gen.getRuntime().lookupForeignCall(MonitorExitStubCall.MONITOREXIT);
+        gen.emitForeignCall(linkage, this, gen.operand(object), gen.emitAddress(slot));
     }
 
     @NodeIntrinsic
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArrayStubCall.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArrayStubCall.java	Fri May 17 15:40:06 2013 +0200
@@ -23,7 +23,7 @@
 package com.oracle.graal.hotspot.nodes;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.hotspot.meta.*;
@@ -43,7 +43,7 @@
     @Input private ValueNode hub;
     @Input private ValueNode length;
 
-    public static final Descriptor NEW_ARRAY = new Descriptor("new_array", false, Object.class, Word.class, int.class);
+    public static final ForeignCallDescriptor NEW_ARRAY = new ForeignCallDescriptor("new_array", Object.class, Word.class, int.class);
 
     public NewArrayStubCall(ValueNode hub, ValueNode length) {
         super(defaultStamp);
@@ -62,8 +62,8 @@
 
     @Override
     public void generate(LIRGenerator gen) {
-        RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(NEW_ARRAY);
-        Variable result = gen.emitCall(stub, stub.getCallingConvention(), this, gen.operand(hub), gen.operand(length));
+        ForeignCallLinkage linkage = gen.getRuntime().lookupForeignCall(NEW_ARRAY);
+        Variable result = gen.emitForeignCall(linkage, this, gen.operand(hub), gen.operand(length));
         gen.setResult(this, result);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceStubCall.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceStubCall.java	Fri May 17 15:40:06 2013 +0200
@@ -23,7 +23,7 @@
 package com.oracle.graal.hotspot.nodes;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.hotspot.meta.*;
@@ -42,7 +42,7 @@
 
     @Input private ValueNode hub;
 
-    public static final Descriptor NEW_INSTANCE = new Descriptor("new_instance", false, Object.class, Word.class);
+    public static final ForeignCallDescriptor NEW_INSTANCE = new ForeignCallDescriptor("new_instance", Object.class, Word.class);
 
     public NewInstanceStubCall(ValueNode hub) {
         super(defaultStamp);
@@ -60,8 +60,8 @@
 
     @Override
     public void generate(LIRGenerator gen) {
-        RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(NEW_INSTANCE);
-        Variable result = gen.emitCall(stub, stub.getCallingConvention(), this, gen.operand(hub));
+        ForeignCallLinkage linkage = gen.getRuntime().lookupForeignCall(NEW_INSTANCE);
+        Variable result = gen.emitForeignCall(linkage, this, gen.operand(hub));
         gen.setResult(this, result);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewMultiArrayStubCall.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewMultiArrayStubCall.java	Fri May 17 15:40:06 2013 +0200
@@ -22,22 +22,18 @@
  */
 package com.oracle.graal.hotspot.nodes;
 
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.hotspot.stubs.*;
-import com.oracle.graal.lir.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.word.*;
 
 /**
- * Node implementing a call to {@link NewMultiArrayStub}.
+ * Node implementing a call to {@code GraalRuntime::new_multi_array}.
  */
-public class NewMultiArrayStubCall extends DeoptimizingStubCall implements LIRGenLowerable {
+public class NewMultiArrayStubCall extends ForeignCallNode {
 
     private static final Stamp defaultStamp = StampFactory.objectNonNull();
 
@@ -45,10 +41,10 @@
     @Input private ValueNode dims;
     private final int rank;
 
-    public static final Descriptor NEW_MULTI_ARRAY = new Descriptor("new_multi_array", false, Object.class, Word.class, int.class, Word.class);
+    public static final ForeignCallDescriptor NEW_MULTI_ARRAY = new ForeignCallDescriptor("new_multi_array", Object.class, Word.class, int.class, Word.class);
 
     public NewMultiArrayStubCall(ValueNode hub, int rank, ValueNode dims) {
-        super(defaultStamp);
+        super(NEW_MULTI_ARRAY, defaultStamp);
         this.hub = hub;
         this.rank = rank;
         this.dims = dims;
@@ -64,10 +60,8 @@
     }
 
     @Override
-    public void generate(LIRGenerator gen) {
-        RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(NewMultiArrayStubCall.NEW_MULTI_ARRAY);
-        Variable result = gen.emitCall(stub, stub.getCallingConvention(), this, gen.operand(hub), Constant.forInt(rank), gen.operand(dims));
-        gen.setResult(this, result);
+    protected Value[] operands(LIRGeneratorTool gen) {
+        return new Value[]{gen.operand(hub), Constant.forInt(rank), gen.operand(dims)};
     }
 
     @NodeIntrinsic
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ThreadIsInterruptedStubCall.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ThreadIsInterruptedStubCall.java	Fri May 17 15:40:06 2013 +0200
@@ -25,24 +25,22 @@
 import java.lang.reflect.*;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.graph.*;
-import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.type.*;
 
 /**
- * Node implementing a call to {@link ThreadIsInterruptedStub}.
+ * Node implementing a call to {@code GraalRuntime::thread_is_interrupted}.
  */
 public class ThreadIsInterruptedStubCall extends DeoptimizingStubCall implements LIRGenLowerable {
 
     @Input private ValueNode thread;
     @Input private ValueNode clearIsInterrupted;
-    public static final Descriptor THREAD_IS_INTERRUPTED = new Descriptor("thread_is_interrupted", false, boolean.class, Object.class, boolean.class);
+    public static final ForeignCallDescriptor THREAD_IS_INTERRUPTED = new ForeignCallDescriptor("thread_is_interrupted", boolean.class, Object.class, boolean.class);
 
     public ThreadIsInterruptedStubCall(ValueNode thread, ValueNode clearIsInterrupted) {
         super(StampFactory.forInteger(Kind.Int, 0, 1));
@@ -52,8 +50,8 @@
 
     @Override
     public void generate(LIRGenerator gen) {
-        RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(ThreadIsInterruptedStubCall.THREAD_IS_INTERRUPTED);
-        Variable result = gen.emitCall(stub, stub.getCallingConvention(), this, gen.operand(thread), gen.operand(clearIsInterrupted));
+        ForeignCallLinkage linkage = gen.getRuntime().lookupForeignCall(ThreadIsInterruptedStubCall.THREAD_IS_INTERRUPTED);
+        Variable result = gen.emitForeignCall(linkage, this, gen.operand(thread), gen.operand(clearIsInterrupted));
         gen.setResult(this, result);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VMErrorNode.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VMErrorNode.java	Fri May 17 15:40:06 2013 +0200
@@ -23,7 +23,6 @@
 package com.oracle.graal.hotspot.nodes;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.target.*;
@@ -39,7 +38,7 @@
 
     private final String format;
     @Input private ValueNode value;
-    public static final Descriptor VM_ERROR = new Descriptor("vm_error", false, void.class, Object.class, Object.class, long.class);
+    public static final ForeignCallDescriptor VM_ERROR = new ForeignCallDescriptor("vm_error", void.class, Object.class, Object.class, long.class);
 
     private VMErrorNode(String format, ValueNode value) {
         super(StampFactory.forVoid());
@@ -58,8 +57,8 @@
         Constant whereArg = Constant.forObject(whereString.intern());
         Constant formatArg = Constant.forObject(format.intern());
 
-        RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(VMErrorNode.VM_ERROR);
-        gen.emitCall(stub, stub.getCallingConvention(), null, whereArg, formatArg, gen.operand(value));
+        ForeignCallLinkage linkage = gen.getRuntime().lookupForeignCall(VMErrorNode.VM_ERROR);
+        gen.emitForeignCall(linkage, null, whereArg, formatArg, gen.operand(value));
     }
 
     @NodeIntrinsic
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VerifyOopStubCall.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VerifyOopStubCall.java	Fri May 17 15:40:06 2013 +0200
@@ -23,7 +23,7 @@
 package com.oracle.graal.hotspot.nodes;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.hotspot.stubs.*;
@@ -36,7 +36,7 @@
 public class VerifyOopStubCall extends DeoptimizingStubCall implements LIRGenLowerable {
 
     @Input private ValueNode object;
-    public static final Descriptor VERIFY_OOP = new Descriptor("verify_oop", false, Object.class, Object.class);
+    public static final ForeignCallDescriptor VERIFY_OOP = new ForeignCallDescriptor("verify_oop", Object.class, Object.class);
 
     public VerifyOopStubCall(ValueNode object) {
         super(StampFactory.objectNonNull());
@@ -45,8 +45,8 @@
 
     @Override
     public void generate(LIRGenerator gen) {
-        RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(VerifyOopStubCall.VERIFY_OOP);
-        gen.emitCall(stub, stub.getCallingConvention(), this, gen.operand(object));
+        ForeignCallLinkage linkage = gen.getRuntime().lookupForeignCall(VerifyOopStubCall.VERIFY_OOP);
+        gen.emitForeignCall(linkage, this, gen.operand(object));
     }
 
     @NodeIntrinsic
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrierPostStubCall.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrierPostStubCall.java	Fri May 17 15:40:06 2013 +0200
@@ -23,7 +23,7 @@
 package com.oracle.graal.hotspot.nodes;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.nodes.*;
@@ -37,7 +37,7 @@
 
     @Input private ValueNode object;
     @Input private ValueNode card;
-    public static final Descriptor WRITE_BARRIER_POST = new Descriptor("writeBarrierPost", true, void.class, Object.class, Word.class);
+    public static final ForeignCallDescriptor WRITE_BARRIER_POST = new ForeignCallDescriptor("writeBarrierPost", void.class, Object.class, Word.class);
 
     public WriteBarrierPostStubCall(ValueNode object, ValueNode card) {
         super(StampFactory.forVoid());
@@ -47,8 +47,8 @@
 
     @Override
     public void generate(LIRGenerator gen) {
-        RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(WriteBarrierPostStubCall.WRITE_BARRIER_POST);
-        gen.emitCall(stub, stub.getCallingConvention(), null, gen.operand(object), gen.operand(card));
+        ForeignCallLinkage linkage = gen.getRuntime().lookupForeignCall(WriteBarrierPostStubCall.WRITE_BARRIER_POST);
+        gen.emitForeignCall(linkage, null, gen.operand(object), gen.operand(card));
     }
 
     @NodeIntrinsic
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrierPreStubCall.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrierPreStubCall.java	Fri May 17 15:40:06 2013 +0200
@@ -23,7 +23,7 @@
 package com.oracle.graal.hotspot.nodes;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.nodes.*;
@@ -35,7 +35,7 @@
 public class WriteBarrierPreStubCall extends FixedWithNextNode implements LIRGenLowerable {
 
     @Input private ValueNode object;
-    public static final Descriptor WRITE_BARRIER_PRE = new Descriptor("writeBarrierPre", true, void.class, Object.class);
+    public static final ForeignCallDescriptor WRITE_BARRIER_PRE = new ForeignCallDescriptor("writeBarrierPre", void.class, Object.class);
 
     public WriteBarrierPreStubCall(ValueNode object) {
         super(StampFactory.forVoid());
@@ -44,8 +44,8 @@
 
     @Override
     public void generate(LIRGenerator gen) {
-        RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(WriteBarrierPreStubCall.WRITE_BARRIER_PRE);
-        gen.emitCall(stub, stub.getCallingConvention(), null, gen.operand(object));
+        ForeignCallLinkage linkage = gen.getRuntime().lookupForeignCall(WriteBarrierPreStubCall.WRITE_BARRIER_PRE);
+        gen.emitForeignCall(linkage, null, gen.operand(object));
     }
 
     @NodeIntrinsic
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AESCryptSubstitutions.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AESCryptSubstitutions.java	Fri May 17 15:40:06 2013 +0200
@@ -26,7 +26,6 @@
 import sun.misc.*;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.compiler.gen.*;
@@ -85,9 +84,9 @@
         @Input private ValueNode out;
         @Input private ValueNode key;
 
-        private final Descriptor descriptor;
+        private final ForeignCallDescriptor descriptor;
 
-        public CryptBlockStubCall(ValueNode in, ValueNode out, ValueNode key, Descriptor descriptor) {
+        public CryptBlockStubCall(ValueNode in, ValueNode out, ValueNode key, ForeignCallDescriptor descriptor) {
             super(StampFactory.forVoid());
             this.in = in;
             this.out = out;
@@ -97,14 +96,14 @@
 
         @Override
         public void generate(LIRGenerator gen) {
-            RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(descriptor);
-            gen.emitCall(stub, stub.getCallingConvention(), null, gen.operand(in), gen.operand(out), gen.operand(key));
+            ForeignCallLinkage linkage = gen.getRuntime().lookupForeignCall(descriptor);
+            gen.emitForeignCall(linkage, null, gen.operand(in), gen.operand(out), gen.operand(key));
         }
     }
 
     public static class EncryptBlockStubCall extends CryptBlockStubCall {
 
-        public static final Descriptor ENCRYPT_BLOCK = new Descriptor("encrypt_block", false, void.class, Word.class, Word.class, Word.class);
+        public static final ForeignCallDescriptor ENCRYPT_BLOCK = new ForeignCallDescriptor("encrypt_block", void.class, Word.class, Word.class, Word.class);
 
         public EncryptBlockStubCall(ValueNode in, ValueNode out, ValueNode key) {
             super(in, out, key, ENCRYPT_BLOCK);
@@ -116,7 +115,7 @@
 
     public static class DecryptBlockStubCall extends CryptBlockStubCall {
 
-        public static final Descriptor DECRYPT_BLOCK = new Descriptor("decrypt_block", false, void.class, Word.class, Word.class, Word.class);
+        public static final ForeignCallDescriptor DECRYPT_BLOCK = new ForeignCallDescriptor("decrypt_block", void.class, Word.class, Word.class, Word.class);
 
         public DecryptBlockStubCall(ValueNode in, ValueNode out, ValueNode key) {
             super(in, out, key, DECRYPT_BLOCK);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java	Fri May 17 15:40:06 2013 +0200
@@ -26,7 +26,6 @@
 import sun.misc.*;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.compiler.gen.*;
@@ -104,9 +103,9 @@
         @Input private ValueNode r;
         @Input private ValueNode inLength;
 
-        private final Descriptor descriptor;
+        private final ForeignCallDescriptor descriptor;
 
-        public AESCryptStubCall(ValueNode in, ValueNode out, ValueNode key, ValueNode r, ValueNode inLength, Descriptor descriptor) {
+        public AESCryptStubCall(ValueNode in, ValueNode out, ValueNode key, ValueNode r, ValueNode inLength, ForeignCallDescriptor descriptor) {
             super(StampFactory.forVoid());
             this.in = in;
             this.out = out;
@@ -118,14 +117,14 @@
 
         @Override
         public void generate(LIRGenerator gen) {
-            RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(descriptor);
-            gen.emitCall(stub, stub.getCallingConvention(), null, gen.operand(in), gen.operand(out), gen.operand(key), gen.operand(r), gen.operand(inLength));
+            ForeignCallLinkage linkage = gen.getRuntime().lookupForeignCall(descriptor);
+            gen.emitForeignCall(linkage, null, gen.operand(in), gen.operand(out), gen.operand(key), gen.operand(r), gen.operand(inLength));
         }
     }
 
     public static class EncryptAESCryptStubCall extends AESCryptStubCall {
 
-        public static final Descriptor ENCRYPT = new Descriptor("encrypt", false, void.class, Word.class, Word.class, Word.class, Word.class, int.class);
+        public static final ForeignCallDescriptor ENCRYPT = new ForeignCallDescriptor("encrypt", void.class, Word.class, Word.class, Word.class, Word.class, int.class);
 
         public EncryptAESCryptStubCall(ValueNode in, ValueNode out, ValueNode key, ValueNode r, ValueNode inLength) {
             super(in, out, key, r, inLength, ENCRYPT);
@@ -137,7 +136,7 @@
 
     public static class DecryptAESCryptStubCall extends AESCryptStubCall {
 
-        public static final Descriptor DECRYPT = new Descriptor("decrypt", false, void.class, Word.class, Word.class, Word.class, Word.class, int.class);
+        public static final ForeignCallDescriptor DECRYPT = new ForeignCallDescriptor("decrypt", void.class, Word.class, Word.class, Word.class, Word.class, int.class);
 
         public DecryptAESCryptStubCall(ValueNode in, ValueNode out, ValueNode key, ValueNode r, ValueNode inLength) {
             super(in, out, key, r, inLength, DECRYPT);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java	Fri May 17 15:40:06 2013 +0200
@@ -23,11 +23,11 @@
 package com.oracle.graal.hotspot.replacements;
 
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+import static com.oracle.graal.hotspot.meta.HotSpotRuntime.*;
 import static com.oracle.graal.replacements.nodes.BranchProbabilityNode.*;
 import sun.misc.*;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.Node.ConstantNodeParameter;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
@@ -672,11 +672,9 @@
         return identityHashCode(IDENTITY_HASHCODE, x);
     }
 
-    public static final Descriptor IDENTITY_HASHCODE = new Descriptor("identity_hashcode", false, int.class, Object.class);
-
     @SuppressWarnings("unused")
-    @NodeIntrinsic(RuntimeCallNode.class)
-    public static int identityHashCode(@ConstantNodeParameter Descriptor descriptor, Object object) {
+    @NodeIntrinsic(ForeignCallNode.class)
+    public static int identityHashCode(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object object) {
         return System.identityHashCode(object);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/SystemSubstitutions.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/SystemSubstitutions.java	Fri May 17 15:40:06 2013 +0200
@@ -25,7 +25,7 @@
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 import static com.oracle.graal.replacements.nodes.BranchProbabilityNode.*;
 
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.graph.Node.ConstantNodeParameter;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
@@ -38,8 +38,8 @@
 @ClassSubstitution(java.lang.System.class)
 public class SystemSubstitutions {
 
-    public static final Descriptor JAVA_TIME_MILLIS = new Descriptor("javaTimeMillis", false, long.class);
-    public static final Descriptor JAVA_TIME_NANOS = new Descriptor("javaTimeNanos", false, long.class);
+    public static final ForeignCallDescriptor JAVA_TIME_MILLIS = new ForeignCallDescriptor("javaTimeMillis", long.class);
+    public static final ForeignCallDescriptor JAVA_TIME_NANOS = new ForeignCallDescriptor("javaTimeNanos", long.class);
 
     @MacroSubstitution(macro = ArrayCopyNode.class)
     public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
@@ -63,8 +63,8 @@
         return computeHashCode(x);
     }
 
-    @NodeIntrinsic(value = RuntimeCallNode.class, setStampFromReturnType = true)
-    public static long callLong(@ConstantNodeParameter Descriptor descriptor) {
+    @NodeIntrinsic(value = ForeignCallNode.class, setStampFromReturnType = true)
+    public static long callLong(@ConstantNodeParameter ForeignCallDescriptor descriptor) {
         if (descriptor == JAVA_TIME_MILLIS) {
             return System.currentTimeMillis();
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/CRuntimeStub.java	Fri May 17 15:38:22 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.stubs;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.hotspot.*;
-import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.replacements.SnippetTemplate.Arguments;
-import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo;
-
-/**
- * Base class for a stub that saves registers around a C runtime call.
- */
-public abstract class CRuntimeStub extends SnippetStub {
-
-    public CRuntimeStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) {
-        super(runtime, replacements, target, linkage);
-    }
-
-    @Override
-    protected Arguments makeArguments(SnippetInfo stub) {
-        Arguments args = new Arguments(stub);
-        for (int i = 0; i < stub.getParameterCount(); i++) {
-            args.add(stub.getParameterName(i), null);
-        }
-        return args;
-    }
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ExceptionHandlerStub.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ExceptionHandlerStub.java	Fri May 17 15:40:06 2013 +0200
@@ -27,14 +27,14 @@
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 import static com.oracle.graal.hotspot.stubs.StubUtil.*;
 
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.Node.ConstantNodeParameter;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.bridge.*;
 import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.Snippet.Fold;
@@ -48,9 +48,9 @@
  * <p>
  * The descriptor for a call to this stub is {@link HotSpotBackend#EXCEPTION_HANDLER}.
  */
-public class ExceptionHandlerStub extends CRuntimeStub {
+public class ExceptionHandlerStub extends SnippetStub {
 
-    public ExceptionHandlerStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) {
+    public ExceptionHandlerStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotForeignCallLinkage linkage) {
         super(runtime, replacements, target, linkage);
     }
 
@@ -125,8 +125,8 @@
         return enabled || graalRuntime().getConfig().cAssertions;
     }
 
-    public static final Descriptor EXCEPTION_HANDLER_FOR_PC = descriptorFor(ExceptionHandlerStub.class, "exceptionHandlerForPc", false);
+    public static final ForeignCallDescriptor EXCEPTION_HANDLER_FOR_PC = descriptorFor(ExceptionHandlerStub.class, "exceptionHandlerForPc");
 
-    @NodeIntrinsic(value = CRuntimeCall.class, setStampFromReturnType = true)
-    public static native Word exceptionHandlerForPc(@ConstantNodeParameter Descriptor exceptionHandlerForPc, Word thread);
+    @NodeIntrinsic(value = ForeignCallNode.class, setStampFromReturnType = true)
+    public static native Word exceptionHandlerForPc(@ConstantNodeParameter ForeignCallDescriptor exceptionHandlerForPc, Word thread);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java	Fri May 17 15:40:06 2013 +0200
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.stubs;
+
+import static com.oracle.graal.api.code.CallingConvention.Type.*;
+import static com.oracle.graal.api.meta.MetaUtil.*;
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.RegisterEffect.*;
+import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.Transition.*;
+
+import java.lang.reflect.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.HotSpotForeignCallLinkage.Transition;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.hotspot.replacements.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.replacements.*;
+import com.oracle.graal.replacements.nodes.*;
+import com.oracle.graal.word.*;
+import com.oracle.graal.word.phases.*;
+
+/**
+ * A {@linkplain #getGraph() generated} stub for a {@link Transition non-leaf} foreign call from
+ * compiled code. A stub is required for such calls as the caller may be scheduled for
+ * deoptimization while the call is in progress. And since these are foreign/runtime calls on slow
+ * paths, we don't want to force the register allocator to spill around the call. As such, this stub
+ * saves and restores all allocatable registers. It also
+ * {@linkplain StubUtil#handlePendingException(boolean) handles} any exceptions raised during the
+ * foreign call.
+ */
+public class ForeignCallStub extends Stub {
+
+    /**
+     * The target of the call.
+     */
+    private final HotSpotForeignCallLinkage target;
+
+    /**
+     * Specifies if the JavaThread value for the current thread is to be prepended to the arguments
+     * for the call to {@link #target}.
+     */
+    protected final boolean prependThread;
+
+    /**
+     * Creates a stub for a call to code at a given address.
+     * 
+     * @param address the address of the code to call
+     * @param descriptor the signature of the call to this stub
+     * @param prependThread true if the JavaThread value for the current thread is to be prepended
+     *            to the arguments for the call to {@code address}
+     */
+    public ForeignCallStub(long address, ForeignCallDescriptor descriptor, boolean prependThread, HotSpotRuntime runtime, Replacements replacements) {
+        super(runtime, replacements, HotSpotForeignCallLinkage.create(descriptor, 0L, PRESERVES_REGISTERS, JavaCallee, NOT_LEAF));
+        this.prependThread = prependThread;
+        Class[] targetParameterTypes = createTargetParameters(descriptor);
+        ForeignCallDescriptor targetSig = new ForeignCallDescriptor(descriptor.getName() + ":C", descriptor.getResultType(), targetParameterTypes);
+        target = HotSpotForeignCallLinkage.create(targetSig, address, DESTROYS_REGISTERS, NativeCall, NOT_LEAF);
+    }
+
+    /**
+     * Gets the linkage information for the call from this stub.
+     */
+    public HotSpotForeignCallLinkage getTargetLinkage() {
+        return target;
+    }
+
+    private Class[] createTargetParameters(ForeignCallDescriptor descriptor) {
+        Class[] parameters = descriptor.getArgumentTypes();
+        if (prependThread) {
+            Class[] newParameters = new Class[parameters.length + 1];
+            System.arraycopy(parameters, 0, newParameters, 1, parameters.length);
+            newParameters[0] = Word.class;
+            return newParameters;
+        }
+        return parameters;
+    }
+
+    @Override
+    protected ResolvedJavaMethod getInstalledCodeOwner() {
+        return null;
+    }
+
+    @Override
+    protected Object debugScopeContext() {
+        return new JavaMethod() {
+
+            public Signature getSignature() {
+                ForeignCallDescriptor d = linkage.getDescriptor();
+                Class<?>[] arguments = d.getArgumentTypes();
+                JavaType[] parameters = new JavaType[arguments.length];
+                for (int i = 0; i < arguments.length; i++) {
+                    parameters[i] = runtime.lookupJavaType(arguments[i]);
+                }
+                return new HotSpotSignature(runtime.lookupJavaType(d.getResultType()), parameters);
+            }
+
+            public String getName() {
+                return linkage.getDescriptor().getName();
+            }
+
+            public JavaType getDeclaringClass() {
+                return runtime.lookupJavaType(ForeignCallStub.class);
+            }
+
+            @Override
+            public String toString() {
+                return format("ForeignCallStub<%n(%p)>", this);
+            }
+        };
+    }
+
+    static class GraphBuilder {
+
+        public GraphBuilder(Stub stub) {
+            this.graph = new StructuredGraph(stub.toString(), null);
+            graph.replaceFixed(graph.start(), graph.add(new StubStartNode(stub)));
+            this.lastFixedNode = graph.start();
+        }
+
+        final StructuredGraph graph;
+        private FixedWithNextNode lastFixedNode;
+
+        <T extends FloatingNode> T add(T node) {
+            return graph.unique(node);
+        }
+
+        <T extends FixedNode> T append(T node) {
+            T result = graph.add(node);
+            assert lastFixedNode != null;
+            assert result.predecessor() == null;
+            graph.addAfterFixed(lastFixedNode, result);
+            if (result instanceof FixedWithNextNode) {
+                lastFixedNode = (FixedWithNextNode) result;
+            } else {
+                lastFixedNode = null;
+            }
+            return result;
+        }
+    }
+
+    /**
+     * Creates a graph for this stub.
+     * <p>
+     * If the stub returns an object, the graph created corresponds to this pseudo code:
+     * 
+     * <pre>
+     *     Object foreignFunctionStub(args...) {
+     *         foreignFunction(currentThread,  args);
+     *         if (clearPendingException(thread())) {
+     *             getAndClearObjectResult(thread());
+     *             DeoptimizeCallerNode.deopt(InvalidateReprofile, RuntimeConstraint);
+     *         }
+     *         return verifyObject(getAndClearObjectResult(thread()));
+     *     }
+     * </pre>
+     * 
+     * If the stub returns a primitive or word, the graph created corresponds to this pseudo code
+     * (using {@code int} as the primitive return type):
+     * 
+     * <pre>
+     *     int foreignFunctionStub(args...) {
+     *         int result = foreignFunction(currentThread,  args);
+     *         if (clearPendingException(thread())) {
+     *             DeoptimizeCallerNode.deopt(InvalidateReprofile, RuntimeConstraint);
+     *         }
+     *         return result;
+     *     }
+     * </pre>
+     * 
+     * If the stub is void, the graph created corresponds to this pseudo code:
+     * 
+     * <pre>
+     *     void foreignFunctionStub(args...) {
+     *         foreignFunction(currentThread,  args);
+     *         if (clearPendingException(thread())) {
+     *             DeoptimizeCallerNode.deopt(InvalidateReprofile, RuntimeConstraint);
+     *         }
+     *     }
+     * </pre>
+     * 
+     * In each example above, the {@code currentThread} argument is the C++ JavaThread value (i.e.,
+     * %r15 on AMD64) and is only prepended if {@link #prependThread} is true.
+     */
+    @Override
+    protected StructuredGraph getGraph() {
+        Class<?>[] args = linkage.getDescriptor().getArgumentTypes();
+        boolean isObjectResult = linkage.getCallingConvention().getReturn().getKind() == Kind.Object;
+        GraphBuilder builder = new GraphBuilder(this);
+        LocalNode[] locals = createLocals(builder, args);
+
+        ReadRegisterNode thread = prependThread || isObjectResult ? builder.append(new ReadRegisterNode(runtime.threadRegister(), true, false)) : null;
+        ValueNode result = createTargetCall(builder, locals, thread);
+        createInvoke(builder, StubUtil.class, "handlePendingException", ConstantNode.forBoolean(isObjectResult, builder.graph));
+        if (isObjectResult) {
+            InvokeNode object = createInvoke(builder, HotSpotReplacementsUtil.class, "getAndClearObjectResult", thread);
+            result = createInvoke(builder, StubUtil.class, "verifyObject", object);
+        }
+        builder.append(new ReturnNode(linkage.getDescriptor().getResultType() == void.class ? null : result));
+
+        if (Debug.isDumpEnabled()) {
+            Debug.dump(builder.graph, "Initial stub graph");
+        }
+
+        for (InvokeNode invoke : builder.graph.getNodes(InvokeNode.class).snapshot()) {
+            inline(invoke);
+        }
+        assert builder.graph.getNodes(InvokeNode.class).isEmpty();
+
+        if (Debug.isDumpEnabled()) {
+            Debug.dump(builder.graph, "Stub graph before compilation");
+        }
+
+        return builder.graph;
+    }
+
+    private LocalNode[] createLocals(GraphBuilder builder, Class<?>[] args) {
+        LocalNode[] locals = new LocalNode[args.length];
+        ResolvedJavaType accessingClass = runtime.lookupJavaType(getClass());
+        for (int i = 0; i < args.length; i++) {
+            ResolvedJavaType type = runtime.lookupJavaType(args[i]).resolve(accessingClass);
+            Kind kind = type.getKind().getStackKind();
+            Stamp stamp;
+            if (kind == Kind.Object) {
+                stamp = StampFactory.declared(type);
+            } else {
+                stamp = StampFactory.forKind(kind);
+            }
+            LocalNode local = builder.add(new LocalNode(i, stamp));
+            locals[i] = local;
+        }
+        return locals;
+    }
+
+    private InvokeNode createInvoke(GraphBuilder builder, Class<?> declaringClass, String name, ValueNode... hpeArgs) {
+        ResolvedJavaMethod method = null;
+        for (Method m : declaringClass.getDeclaredMethods()) {
+            if (Modifier.isStatic(m.getModifiers()) && m.getName().equals(name)) {
+                assert method == null : "found more than one method in " + declaringClass + " named " + name;
+                method = runtime.lookupJavaMethod(m);
+            }
+        }
+        assert method != null : "did not find method in " + declaringClass + " named " + name;
+        JavaType returnType = method.getSignature().getReturnType(null);
+        MethodCallTargetNode callTarget = builder.graph.add(new MethodCallTargetNode(InvokeKind.Static, method, hpeArgs, returnType));
+        InvokeNode invoke = builder.append(new InvokeNode(callTarget, FrameState.UNKNOWN_BCI));
+        return invoke;
+    }
+
+    private ForeignCallNode createTargetCall(GraphBuilder builder, LocalNode[] locals, ReadRegisterNode thread) {
+        if (prependThread) {
+            ValueNode[] targetArguments = new ValueNode[1 + locals.length];
+            targetArguments[0] = thread;
+            System.arraycopy(locals, 0, targetArguments, 1, locals.length);
+            return builder.append(new ForeignCallNode(target.getDescriptor(), targetArguments));
+        } else {
+            return builder.append(new ForeignCallNode(target.getDescriptor(), locals));
+        }
+    }
+
+    private void inline(InvokeNode invoke) {
+        StructuredGraph graph = invoke.graph();
+        ResolvedJavaMethod method = ((MethodCallTargetNode) invoke.callTarget()).targetMethod();
+        ReplacementsImpl repl = new ReplacementsImpl(runtime, new Assumptions(false), runtime.getTarget());
+        StructuredGraph calleeGraph = repl.makeGraph(method, null, null);
+        InliningUtil.inline(invoke, calleeGraph, false);
+        new NodeIntrinsificationPhase(runtime).apply(graph);
+        new WordTypeRewriterPhase(runtime, wordKind()).apply(graph);
+        new DeadCodeEliminationPhase().apply(graph);
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/LogObjectStub.java	Fri May 17 15:38:22 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.stubs;
-
-import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
-import static com.oracle.graal.hotspot.stubs.StubUtil.*;
-
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.graph.Node.ConstantNodeParameter;
-import com.oracle.graal.graph.Node.NodeIntrinsic;
-import com.oracle.graal.hotspot.*;
-import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.hotspot.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.replacements.*;
-import com.oracle.graal.word.*;
-
-/**
- * Stub called from {@link Log}.
- */
-public class LogObjectStub extends CRuntimeStub {
-
-    public LogObjectStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) {
-        super(runtime, replacements, target, linkage);
-    }
-
-    @Snippet
-    private static void logObject(Object object, int flags) {
-        logObjectC(LOG_OBJECT_C, thread(), object, flags);
-    }
-
-    public static final Descriptor LOG_OBJECT_C = descriptorFor(LogObjectStub.class, "logObjectC", false);
-
-    @NodeIntrinsic(CRuntimeCall.class)
-    public static native void logObjectC(@ConstantNodeParameter Descriptor logObjectC, Word thread, Object object, int flags);
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/LogPrimitiveStub.java	Fri May 17 15:38:22 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.stubs;
-
-import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
-import static com.oracle.graal.hotspot.stubs.StubUtil.*;
-
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.graph.Node.ConstantNodeParameter;
-import com.oracle.graal.graph.Node.NodeIntrinsic;
-import com.oracle.graal.hotspot.*;
-import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.hotspot.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.replacements.*;
-import com.oracle.graal.word.*;
-
-/**
- * Stub called from {@link Log}.
- */
-public class LogPrimitiveStub extends CRuntimeStub {
-
-    public LogPrimitiveStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) {
-        super(runtime, replacements, target, linkage);
-    }
-
-    @Snippet
-    private static void logPrimitive(char typeChar, long value, boolean newline) {
-        logPrimitivefC(LOG_PRIMITIVE_C, thread(), typeChar, value, newline);
-    }
-
-    public static final Descriptor LOG_PRIMITIVE_C = descriptorFor(LogPrimitiveStub.class, "logPrimitivefC", false);
-
-    @NodeIntrinsic(CRuntimeCall.class)
-    public static native void logPrimitivefC(@ConstantNodeParameter Descriptor logPrimitivefC, Word thread, char typeChar, long value, boolean newline);
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/LogPrintfStub.java	Fri May 17 15:38:22 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.stubs;
-
-import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
-import static com.oracle.graal.hotspot.stubs.StubUtil.*;
-
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.graph.Node.ConstantNodeParameter;
-import com.oracle.graal.graph.Node.NodeIntrinsic;
-import com.oracle.graal.hotspot.*;
-import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.hotspot.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.replacements.*;
-import com.oracle.graal.word.*;
-
-/**
- * Stub called from {@link Log}.
- */
-public class LogPrintfStub extends CRuntimeStub {
-
-    public LogPrintfStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) {
-        super(runtime, replacements, target, linkage);
-    }
-
-    @Snippet
-    private static void logPrintf(String format, long v1, long v2, long v3) {
-        logPrintfC(LOG_PRINTF_C, thread(), format, v1, v2, v3);
-    }
-
-    public static final Descriptor LOG_PRINTF_C = descriptorFor(LogPrintfStub.class, "logPrintfC", false);
-
-    @NodeIntrinsic(CRuntimeCall.class)
-    public static native void logPrintfC(@ConstantNodeParameter Descriptor logPrintfC, Word thread, String format, long v1, long v2, long v3);
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java	Fri May 17 15:40:06 2013 +0200
@@ -28,7 +28,6 @@
 import static com.oracle.graal.hotspot.stubs.NewInstanceStub.*;
 import static com.oracle.graal.hotspot.stubs.StubUtil.*;
 
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.Node.ConstantNodeParameter;
@@ -37,6 +36,7 @@
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.hotspot.replacements.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.Snippet.ConstantParameter;
@@ -53,7 +53,7 @@
  */
 public class NewArrayStub extends SnippetStub {
 
-    public NewArrayStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) {
+    public NewArrayStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotForeignCallLinkage linkage) {
         super(runtime, replacements, target, linkage);
     }
 
@@ -120,8 +120,8 @@
         return verifyObject(getAndClearObjectResult(thread()));
     }
 
-    public static final Descriptor NEW_ARRAY_C = descriptorFor(NewArrayStub.class, "newArrayC", false);
+    public static final ForeignCallDescriptor NEW_ARRAY_C = descriptorFor(NewArrayStub.class, "newArrayC");
 
-    @NodeIntrinsic(CRuntimeCall.class)
-    public static native void newArrayC(@ConstantNodeParameter Descriptor newArrayC, Word thread, Word hub, int length);
+    @NodeIntrinsic(ForeignCallNode.class)
+    public static native void newArrayC(@ConstantNodeParameter ForeignCallDescriptor newArrayC, Word thread, Word hub, int length);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java	Fri May 17 15:40:06 2013 +0200
@@ -28,7 +28,6 @@
 import static com.oracle.graal.hotspot.replacements.NewObjectSnippets.*;
 import static com.oracle.graal.hotspot.stubs.StubUtil.*;
 
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.Node.ConstantNodeParameter;
@@ -37,6 +36,7 @@
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.hotspot.replacements.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.Snippet.ConstantParameter;
@@ -53,7 +53,7 @@
  */
 public class NewInstanceStub extends SnippetStub {
 
-    public NewInstanceStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) {
+    public NewInstanceStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotForeignCallLinkage linkage) {
         super(runtime, replacements, target, linkage);
     }
 
@@ -239,8 +239,8 @@
         return Boolean.getBoolean("graal.newInstanceStub.forceSlowPath");
     }
 
-    public static final Descriptor NEW_INSTANCE_C = descriptorFor(NewInstanceStub.class, "newInstanceC", false);
+    public static final ForeignCallDescriptor NEW_INSTANCE_C = descriptorFor(NewInstanceStub.class, "newInstanceC");
 
-    @NodeIntrinsic(CRuntimeCall.class)
-    public static native void newInstanceC(@ConstantNodeParameter Descriptor newInstanceC, Word thread, Word hub);
+    @NodeIntrinsic(ForeignCallNode.class)
+    public static native void newInstanceC(@ConstantNodeParameter ForeignCallDescriptor newInstanceC, Word thread, Word hub);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewMultiArrayStub.java	Fri May 17 15:38:22 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.stubs;
-
-import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
-import static com.oracle.graal.hotspot.stubs.StubUtil.*;
-
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.graph.Node.ConstantNodeParameter;
-import com.oracle.graal.graph.Node.NodeIntrinsic;
-import com.oracle.graal.hotspot.*;
-import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.hotspot.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.replacements.*;
-import com.oracle.graal.word.*;
-
-/**
- * Stub called from {@link NewMultiArrayStubCall}.
- */
-public class NewMultiArrayStub extends CRuntimeStub {
-
-    public NewMultiArrayStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) {
-        super(runtime, replacements, target, linkage);
-    }
-
-    @Snippet
-    private static Object newMultiArray(Word hub, int rank, Word dims) {
-        newMultiArrayC(NEW_MULTI_ARRAY_C, thread(), hub, rank, dims);
-        handlePendingException(true);
-        return verifyObject(getAndClearObjectResult(thread()));
-    }
-
-    public static final Descriptor NEW_MULTI_ARRAY_C = descriptorFor(NewMultiArrayStub.class, "newMultiArrayC", false);
-
-    @NodeIntrinsic(CRuntimeCall.class)
-    public static native void newMultiArrayC(@ConstantNodeParameter Descriptor newArrayC, Word thread, Word hub, int rank, Word dims);
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/OSRMigrationEndStub.java	Fri May 17 15:38:22 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.stubs;
-
-import static com.oracle.graal.hotspot.stubs.StubUtil.*;
-
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.graph.Node.ConstantNodeParameter;
-import com.oracle.graal.graph.Node.NodeIntrinsic;
-import com.oracle.graal.hotspot.*;
-import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.hotspot.nodes.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.replacements.*;
-import com.oracle.graal.word.*;
-
-/**
- * Stub called from {@link OSRStartNode}.
- */
-public class OSRMigrationEndStub extends CRuntimeStub {
-
-    public OSRMigrationEndStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) {
-        super(runtime, replacements, target, linkage);
-    }
-
-    @Snippet
-    private static void osrMigrationEnd(Word buffer) {
-        osrMigrationEndC(OSR_MIGRATION_END_C, buffer);
-    }
-
-    public static final Descriptor OSR_MIGRATION_END_C = descriptorFor(OSRMigrationEndStub.class, "osrMigrationEndC", false);
-
-    @NodeIntrinsic(CRuntimeCall.class)
-    public static native void osrMigrationEndC(@ConstantNodeParameter Descriptor osrMigrationEndC, Word buffer);
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/RuntimeCallStub.java	Fri May 17 15:38:22 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,257 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.stubs;
-
-import static com.oracle.graal.api.code.CallingConvention.Type.*;
-import static com.oracle.graal.api.meta.MetaUtil.*;
-import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
-import static com.oracle.graal.hotspot.HotSpotRuntimeCallTarget.RegisterEffect.*;
-
-import java.lang.reflect.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.debug.*;
-import com.oracle.graal.hotspot.*;
-import com.oracle.graal.hotspot.bridge.*;
-import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.hotspot.nodes.*;
-import com.oracle.graal.hotspot.replacements.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.phases.common.*;
-import com.oracle.graal.replacements.*;
-import com.oracle.graal.replacements.nodes.*;
-import com.oracle.graal.word.*;
-import com.oracle.graal.word.phases.*;
-
-/**
- * A stub that calls into a HotSpot C/C++ runtime function using the native
- * {@link CallingConvention}.
- */
-public class RuntimeCallStub extends Stub {
-
-    /**
-     * The target of the call.
-     */
-    private final HotSpotRuntimeCallTarget target;
-
-    /**
-     * Specifies if the JavaThread value for the current thread is to be prepended to the arguments
-     * for the call to {@link #target}.
-     */
-    protected final boolean prependThread;
-
-    /**
-     * Creates a stub for a call to code at a given address.
-     * 
-     * @param address the address of the code to call
-     * @param sig the signature of the call to this stub
-     * @param prependThread true if the JavaThread value for the current thread is to be prepended
-     *            to the arguments for the call to {@code address}
-     * @param regConfig used to get the calling convention for the call to this stub from Graal
-     *            compiled Java code as well as the calling convention for the call to
-     *            {@code address}
-     * @param vm the Java to HotSpot C/C++ runtime interface
-     */
-    public RuntimeCallStub(long address, Descriptor sig, boolean prependThread, HotSpotRuntime runtime, Replacements replacements, RegisterConfig regConfig, CompilerToVM vm) {
-        super(runtime, replacements, HotSpotRuntimeCallTarget.create(sig, 0L, PRESERVES_REGISTERS, JavaCallee, regConfig, runtime, vm));
-        this.prependThread = prependThread;
-        Class[] targetParameterTypes = createTargetParameters(sig);
-        Descriptor targetSig = new Descriptor(sig.getName() + ":C", sig.hasSideEffect(), sig.getResultType(), targetParameterTypes);
-        target = HotSpotRuntimeCallTarget.create(targetSig, address, DESTROYS_REGISTERS, NativeCall, regConfig, runtime, vm);
-    }
-
-    /**
-     * Gets the linkage information for the runtime call.
-     */
-    public HotSpotRuntimeCallTarget getTargetLinkage() {
-        return target;
-    }
-
-    private Class[] createTargetParameters(Descriptor sig) {
-        Class[] parameters = sig.getArgumentTypes();
-        if (prependThread) {
-            Class[] newParameters = new Class[parameters.length + 1];
-            System.arraycopy(parameters, 0, newParameters, 1, parameters.length);
-            newParameters[0] = Word.class;
-            return newParameters;
-        }
-        return parameters;
-    }
-
-    @Override
-    protected ResolvedJavaMethod getInstalledCodeOwner() {
-        return null;
-    }
-
-    @Override
-    protected Object debugScopeContext() {
-        return new JavaMethod() {
-
-            public Signature getSignature() {
-                Descriptor d = linkage.getDescriptor();
-                Class<?>[] arguments = d.getArgumentTypes();
-                JavaType[] parameters = new JavaType[arguments.length];
-                for (int i = 0; i < arguments.length; i++) {
-                    parameters[i] = runtime.lookupJavaType(arguments[i]);
-                }
-                return new HotSpotSignature(runtime.lookupJavaType(d.getResultType()), parameters);
-            }
-
-            public String getName() {
-                return linkage.getDescriptor().getName();
-            }
-
-            public JavaType getDeclaringClass() {
-                return runtime.lookupJavaType(RuntimeCallStub.class);
-            }
-
-            @Override
-            public String toString() {
-                return format("HotSpotStub<%n(%p)>", this);
-            }
-        };
-    }
-
-    static class GraphBuilder {
-
-        public GraphBuilder(Stub stub) {
-            this.graph = new StructuredGraph(stub.toString(), null);
-            graph.replaceFixed(graph.start(), graph.add(new StubStartNode(stub)));
-            this.lastFixedNode = graph.start();
-        }
-
-        final StructuredGraph graph;
-        private FixedWithNextNode lastFixedNode;
-
-        <T extends FloatingNode> T add(T node) {
-            return graph.unique(node);
-        }
-
-        <T extends FixedNode> T append(T node) {
-            T result = graph.add(node);
-            assert lastFixedNode != null;
-            assert result.predecessor() == null;
-            graph.addAfterFixed(lastFixedNode, result);
-            if (result instanceof FixedWithNextNode) {
-                lastFixedNode = (FixedWithNextNode) result;
-            } else {
-                lastFixedNode = null;
-            }
-            return result;
-        }
-    }
-
-    @Override
-    protected StructuredGraph getGraph() {
-        Class<?>[] args = linkage.getDescriptor().getArgumentTypes();
-        boolean isObjectResult = linkage.getCallingConvention().getReturn().getKind() == Kind.Object;
-        GraphBuilder builder = new GraphBuilder(this);
-        LocalNode[] locals = createLocals(builder, args);
-
-        ReadRegisterNode thread = prependThread || isObjectResult ? builder.append(new ReadRegisterNode(runtime.threadRegister(), true, false)) : null;
-        ValueNode result = createTargetCall(builder, locals, thread);
-        createInvoke(builder, StubUtil.class, "handlePendingException", ConstantNode.forBoolean(isObjectResult, builder.graph));
-        if (isObjectResult) {
-            InvokeNode object = createInvoke(builder, HotSpotReplacementsUtil.class, "getAndClearObjectResult", thread);
-            result = createInvoke(builder, StubUtil.class, "verifyObject", object);
-        }
-        builder.append(new ReturnNode(linkage.getDescriptor().getResultType() == void.class ? null : result));
-
-        if (Debug.isDumpEnabled()) {
-            Debug.dump(builder.graph, "Initial stub graph");
-        }
-
-        for (InvokeNode invoke : builder.graph.getNodes(InvokeNode.class).snapshot()) {
-            inline(invoke);
-        }
-        assert builder.graph.getNodes(InvokeNode.class).isEmpty();
-
-        if (Debug.isDumpEnabled()) {
-            Debug.dump(builder.graph, "Stub graph before compilation");
-        }
-
-        return builder.graph;
-    }
-
-    private LocalNode[] createLocals(GraphBuilder builder, Class<?>[] args) {
-        LocalNode[] locals = new LocalNode[args.length];
-        ResolvedJavaType accessingClass = runtime.lookupJavaType(getClass());
-        for (int i = 0; i < args.length; i++) {
-            ResolvedJavaType type = runtime.lookupJavaType(args[i]).resolve(accessingClass);
-            Kind kind = type.getKind().getStackKind();
-            Stamp stamp;
-            if (kind == Kind.Object) {
-                stamp = StampFactory.declared(type);
-            } else {
-                stamp = StampFactory.forKind(kind);
-            }
-            LocalNode local = builder.add(new LocalNode(i, stamp));
-            locals[i] = local;
-        }
-        return locals;
-    }
-
-    private InvokeNode createInvoke(GraphBuilder builder, Class<?> declaringClass, String name, ValueNode... hpeArgs) {
-        ResolvedJavaMethod method = null;
-        for (Method m : declaringClass.getDeclaredMethods()) {
-            if (Modifier.isStatic(m.getModifiers()) && m.getName().equals(name)) {
-                assert method == null : "found more than one method in " + declaringClass + " named " + name;
-                method = runtime.lookupJavaMethod(m);
-            }
-        }
-        assert method != null : "did not find method in " + declaringClass + " named " + name;
-        JavaType returnType = method.getSignature().getReturnType(null);
-        MethodCallTargetNode callTarget = builder.graph.add(new MethodCallTargetNode(InvokeKind.Static, method, hpeArgs, returnType));
-        InvokeNode invoke = builder.append(new InvokeNode(callTarget, FrameState.UNKNOWN_BCI));
-        return invoke;
-    }
-
-    private CRuntimeCall createTargetCall(GraphBuilder builder, LocalNode[] locals, ReadRegisterNode thread) {
-        if (prependThread) {
-            ValueNode[] targetArguments = new ValueNode[1 + locals.length];
-            targetArguments[0] = thread;
-            System.arraycopy(locals, 0, targetArguments, 1, locals.length);
-            return builder.append(new CRuntimeCall(target.getDescriptor(), targetArguments));
-        } else {
-            return builder.append(new CRuntimeCall(target.getDescriptor(), locals));
-        }
-    }
-
-    private void inline(InvokeNode invoke) {
-        StructuredGraph graph = invoke.graph();
-        ResolvedJavaMethod method = ((MethodCallTargetNode) invoke.callTarget()).targetMethod();
-        ReplacementsImpl repl = new ReplacementsImpl(runtime, new Assumptions(false), runtime.getTarget());
-        StructuredGraph calleeGraph = repl.makeGraph(method, null, null);
-        InliningUtil.inline(invoke, calleeGraph, false);
-        new NodeIntrinsificationPhase(runtime).apply(graph);
-        new WordTypeRewriterPhase(runtime, wordKind()).apply(graph);
-        new DeadCodeEliminationPhase().apply(graph);
-    }
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java	Fri May 17 15:40:06 2013 +0200
@@ -30,7 +30,6 @@
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.replacements.Snippet.ConstantParameter;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates;
 import com.oracle.graal.replacements.SnippetTemplate.Arguments;
@@ -66,7 +65,7 @@
      * 
      * @param linkage linkage details for a call to the stub
      */
-    public SnippetStub(HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) {
+    public SnippetStub(HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotForeignCallLinkage linkage) {
         super(runtime, replacements, linkage);
         this.snippet = new Template(runtime, replacements, target, getClass());
     }
@@ -77,9 +76,15 @@
     }
 
     /**
-     * Adds the {@linkplain ConstantParameter constant} arguments of this stub.
+     * Adds the arguments to this snippet stub.
      */
-    protected abstract Arguments makeArguments(SnippetInfo stub);
+    protected Arguments makeArguments(SnippetInfo stub) {
+        Arguments args = new Arguments(stub);
+        for (int i = 0; i < stub.getParameterCount(); i++) {
+            args.add(stub.getParameterName(i), null);
+        }
+        return args;
+    }
 
     @Override
     protected Object debugScopeContext() {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java	Fri May 17 15:40:06 2013 +0200
@@ -56,7 +56,7 @@
     /**
      * The linkage information for a call to this stub from compiled code.
      */
-    protected final HotSpotRuntimeCallTarget linkage;
+    protected final HotSpotForeignCallLinkage linkage;
 
     /**
      * The code installed for the stub.
@@ -100,7 +100,7 @@
      * 
      * @param linkage linkage details for a call to the stub
      */
-    public Stub(HotSpotRuntime runtime, Replacements replacements, HotSpotRuntimeCallTarget linkage) {
+    public Stub(HotSpotRuntime runtime, Replacements replacements, HotSpotForeignCallLinkage linkage) {
         this.linkage = linkage;
         this.runtime = runtime;
         this.replacements = replacements;
@@ -109,7 +109,7 @@
     /**
      * Gets the linkage for a call to this stub from compiled code.
      */
-    public HotSpotRuntimeCallTarget getLinkage() {
+    public HotSpotForeignCallLinkage getLinkage() {
         return linkage;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/StubUtil.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/StubUtil.java	Fri May 17 15:40:06 2013 +0200
@@ -31,10 +31,11 @@
 import java.lang.reflect.*;
 import java.util.*;
 
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.Node.ConstantNodeParameter;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.Snippet.Fold;
 import com.oracle.graal.word.*;
@@ -46,28 +47,29 @@
  */
 public class StubUtil {
 
-    public static final Descriptor VM_MESSAGE_C = descriptorFor(StubUtil.class, "vmMessageC", false);
+    public static final ForeignCallDescriptor VM_MESSAGE_C = descriptorFor(StubUtil.class, "vmMessageC");
 
     /**
-     * Looks for a {@link CRuntimeCall} node intrinsic named {@code name} in {@code stubClass} and
-     * returns a {@link Descriptor} based on its signature and the value of {@code hasSideEffect}.
+     * Looks for a {@link ForeignCallNode} node intrinsic named {@code name} in {@code stubClass}
+     * and returns a {@link ForeignCallDescriptor} based on its signature and the value of
+     * {@code hasSideEffect}.
      */
-    public static Descriptor descriptorFor(Class<?> stubClass, String name, boolean hasSideEffect) {
+    public static ForeignCallDescriptor descriptorFor(Class<?> stubClass, String name) {
         Method found = null;
         for (Method method : stubClass.getDeclaredMethods()) {
             if (Modifier.isStatic(method.getModifiers()) && method.getAnnotation(NodeIntrinsic.class) != null && method.getName().equals(name)) {
-                if (method.getAnnotation(NodeIntrinsic.class).value() == CRuntimeCall.class) {
-                    assert found == null : "found more than one C runtime call named " + name + " in " + stubClass;
-                    assert method.getParameterTypes().length != 0 && method.getParameterTypes()[0] == Descriptor.class : "first parameter of C runtime call '" + name + "' in " + stubClass +
-                                    " must be of type " + Descriptor.class.getSimpleName();
+                if (method.getAnnotation(NodeIntrinsic.class).value() == ForeignCallNode.class) {
+                    assert found == null : "found more than one foreign call named " + name + " in " + stubClass;
+                    assert method.getParameterTypes().length != 0 && method.getParameterTypes()[0] == ForeignCallDescriptor.class : "first parameter of foreign call '" + name + "' in " + stubClass +
+                                    " must be of type " + ForeignCallDescriptor.class.getSimpleName();
                     found = method;
                 }
             }
         }
-        assert found != null : "could not find C runtime call named " + name + " in " + stubClass;
+        assert found != null : "could not find foreign call named " + name + " in " + stubClass;
         List<Class<?>> paramList = Arrays.asList(found.getParameterTypes());
         Class[] cCallTypes = paramList.subList(1, paramList.size()).toArray(new Class[paramList.size() - 1]);
-        return new Descriptor(name, hasSideEffect, found.getReturnType(), cCallTypes);
+        return new ForeignCallDescriptor(name, found.getReturnType(), cCallTypes);
     }
 
     public static void handlePendingException(boolean isObjectResult) {
@@ -79,8 +81,8 @@
         }
     }
 
-    @NodeIntrinsic(CRuntimeCall.class)
-    private static native void vmMessageC(@ConstantNodeParameter Descriptor stubPrintfC, boolean vmError, Word format, long v1, long v2, long v3);
+    @NodeIntrinsic(ForeignCallNode.class)
+    private static native void vmMessageC(@ConstantNodeParameter ForeignCallDescriptor stubPrintfC, boolean vmError, Word format, long v1, long v2, long v3);
 
     /**
      * Prints a message to the log stream.
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ThreadIsInterruptedStub.java	Fri May 17 15:38:22 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.stubs;
-
-import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
-import static com.oracle.graal.hotspot.stubs.StubUtil.*;
-
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.graph.Node.ConstantNodeParameter;
-import com.oracle.graal.graph.Node.NodeIntrinsic;
-import com.oracle.graal.hotspot.*;
-import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.hotspot.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.replacements.*;
-import com.oracle.graal.word.*;
-
-/**
- * Stub called from {@link ThreadIsInterruptedStubCall}.
- */
-public class ThreadIsInterruptedStub extends CRuntimeStub {
-
-    public ThreadIsInterruptedStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) {
-        super(runtime, replacements, target, linkage);
-    }
-
-    @Snippet
-    private static boolean threadIsInterrupted(Thread receiverThread, boolean clearIsInterrupted) {
-        boolean result = threadIsInterruptedC(THREAD_IS_INTERRUPTED_C, thread(), receiverThread, clearIsInterrupted);
-        handlePendingException(false);
-        return result;
-    }
-
-    public static final Descriptor THREAD_IS_INTERRUPTED_C = descriptorFor(ThreadIsInterruptedStub.class, "threadIsInterruptedC", false);
-
-    @NodeIntrinsic(CRuntimeCall.class)
-    public static native boolean threadIsInterruptedC(@ConstantNodeParameter Descriptor threadIsInterruptedC, Word thread, Thread receiverThread, boolean clearIsInterrupted);
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/UnwindExceptionToCallerStub.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/UnwindExceptionToCallerStub.java	Fri May 17 15:40:06 2013 +0200
@@ -28,14 +28,14 @@
 import static com.oracle.graal.hotspot.stubs.ExceptionHandlerStub.*;
 import static com.oracle.graal.hotspot.stubs.StubUtil.*;
 
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.Node.ConstantNodeParameter;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.Snippet.Fold;
@@ -45,9 +45,9 @@
  * Stub called by an {@link UnwindNode}. This stub executes in the frame of the method throwing an
  * exception and completes by jumping to the exception handler in the calling frame.
  */
-public class UnwindExceptionToCallerStub extends CRuntimeStub {
+public class UnwindExceptionToCallerStub extends SnippetStub {
 
-    public UnwindExceptionToCallerStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) {
+    public UnwindExceptionToCallerStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotForeignCallLinkage linkage) {
         super(runtime, replacements, target, linkage);
     }
 
@@ -97,8 +97,8 @@
         return enabled || graalRuntime().getConfig().cAssertions;
     }
 
-    public static final Descriptor EXCEPTION_HANDLER_FOR_RETURN_ADDRESS = descriptorFor(UnwindExceptionToCallerStub.class, "exceptionHandlerForReturnAddress", false);
+    public static final ForeignCallDescriptor EXCEPTION_HANDLER_FOR_RETURN_ADDRESS = descriptorFor(UnwindExceptionToCallerStub.class, "exceptionHandlerForReturnAddress");
 
-    @NodeIntrinsic(value = CRuntimeCall.class, setStampFromReturnType = true)
-    public static native Word exceptionHandlerForReturnAddress(@ConstantNodeParameter Descriptor exceptionHandlerForReturnAddress, Word thread, Word returnAddress);
+    @NodeIntrinsic(value = ForeignCallNode.class, setStampFromReturnType = true)
+    public static native Word exceptionHandlerForReturnAddress(@ConstantNodeParameter ForeignCallDescriptor exceptionHandlerForReturnAddress, Word thread, Word returnAddress);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/VMErrorStub.java	Fri May 17 15:38:22 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.stubs;
-
-import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
-import static com.oracle.graal.hotspot.stubs.StubUtil.*;
-
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.graph.Node.ConstantNodeParameter;
-import com.oracle.graal.graph.Node.NodeIntrinsic;
-import com.oracle.graal.hotspot.*;
-import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.hotspot.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.replacements.*;
-import com.oracle.graal.word.*;
-
-/**
- * Stub called from {@link VMErrorNode}.
- */
-public class VMErrorStub extends CRuntimeStub {
-
-    public VMErrorStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) {
-        super(runtime, replacements, target, linkage);
-    }
-
-    @Snippet
-    private static void vmError(String where, String format, long value) {
-        vmErrorC(VM_ERROR_C, thread(), where, format, value);
-    }
-
-    public static final Descriptor VM_ERROR_C = descriptorFor(VMErrorStub.class, "vmErrorC", false);
-
-    @NodeIntrinsic(CRuntimeCall.class)
-    public static native void vmErrorC(@ConstantNodeParameter Descriptor vmErrorC, Word thread, String where, String format, long value);
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/VerifyOopStub.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/VerifyOopStub.java	Fri May 17 15:40:06 2013 +0200
@@ -34,9 +34,9 @@
 /**
  * Stub called from {@link VerifyOopStubCall}.
  */
-public class VerifyOopStub extends CRuntimeStub {
+public class VerifyOopStub extends SnippetStub {
 
-    public VerifyOopStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) {
+    public VerifyOopStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotForeignCallLinkage linkage) {
         super(runtime, replacements, target, linkage);
     }
 
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java	Fri May 17 15:40:06 2013 +0200
@@ -358,6 +358,7 @@
      * @param object the object whose monitor will be locked.
      */
     public void pushLock(ValueNode object) {
+        assert object.isAlive() && object.kind() == Kind.Object : "unexpected value: " + object;
         locks = Arrays.copyOf(locks, locks.length + 1);
         locks[locks.length - 1] = object;
     }
@@ -406,7 +407,7 @@
      * @param x the instruction which produces the value for the local
      */
     public void storeLocal(int i, ValueNode x) {
-        assert x == null || x.kind() != Kind.Void && x.kind() != Kind.Illegal : "unexpected value: " + x;
+        assert x == null || x.isAlive() && x.kind() != Kind.Void && x.kind() != Kind.Illegal : "unexpected value: " + x;
         locals[i] = x;
         if (x != null && isTwoSlot(x.kind())) {
             // if this is a double word, then kill i+1
@@ -422,7 +423,7 @@
     }
 
     private void storeStack(int i, ValueNode x) {
-        assert x == null || stack[i] == null || x.kind() == stack[i].kind() : "Method does not handle changes from one-slot to two-slot values";
+        assert x == null || x.isAlive() && (stack[i] == null || x.kind() == stack[i].kind()) : "Method does not handle changes from one-slot to two-slot values or non-alive values";
         stack[i] = x;
     }
 
@@ -433,7 +434,7 @@
      * @param x the instruction to push onto the stack
      */
     public void push(Kind kind, ValueNode x) {
-        assert !x.isDeleted() && x.kind() != Kind.Void && x.kind() != Kind.Illegal;
+        assert x.isAlive() && x.kind() != Kind.Void && x.kind() != Kind.Illegal;
         xpush(assertKind(kind, x));
         if (isTwoSlot(kind)) {
             xpush(null);
@@ -446,7 +447,7 @@
      * @param x the instruction to push onto the stack
      */
     public void xpush(ValueNode x) {
-        assert x == null || (!x.isDeleted() && x.kind() != Kind.Void && x.kind() != Kind.Illegal);
+        assert x == null || (x.isAlive() && x.kind() != Kind.Void && x.kind() != Kind.Illegal);
         stack[stackSize++] = x;
     }
 
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Fri May 17 15:40:06 2013 +0200
@@ -33,7 +33,6 @@
 import java.util.*;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.meta.ProfilingInfo.TriState;
 import com.oracle.graal.api.meta.ResolvedJavaType.Representation;
@@ -59,8 +58,8 @@
 
     public static final class RuntimeCalls {
 
-        public static final Descriptor CREATE_NULL_POINTER_EXCEPTION = new Descriptor("createNullPointerException", true, Object.class);
-        public static final Descriptor CREATE_OUT_OF_BOUNDS_EXCEPTION = new Descriptor("createOutOfBoundsException", true, Object.class, int.class);
+        public static final ForeignCallDescriptor CREATE_NULL_POINTER_EXCEPTION = new ForeignCallDescriptor("createNullPointerException", Object.class);
+        public static final ForeignCallDescriptor CREATE_OUT_OF_BOUNDS_EXCEPTION = new ForeignCallDescriptor("createOutOfBoundsException", Object.class, int.class);
     }
 
     /**
@@ -305,8 +304,8 @@
      * @param type the unresolved type of the constant
      */
     protected void handleUnresolvedLoadConstant(JavaType type) {
-        append(currentGraph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved)));
-        frameState.push(Kind.Object, append(ConstantNode.forObject(null, runtime, currentGraph)));
+        append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+        frameState.push(Kind.Object, appendConstant(Constant.NULL_OBJECT));
     }
 
     /**
@@ -314,7 +313,7 @@
      * @param object the object value whose type is being checked against {@code type}
      */
     protected void handleUnresolvedCheckCast(JavaType type, ValueNode object) {
-        append(currentGraph.add(new FixedGuardNode(currentGraph.unique(new IsNullNode(object)), Unresolved, InvalidateRecompile)));
+        append(new FixedGuardNode(currentGraph.unique(new IsNullNode(object)), Unresolved, InvalidateRecompile));
         frameState.apush(appendConstant(Constant.NULL_OBJECT));
     }
 
@@ -325,8 +324,7 @@
     protected void handleUnresolvedInstanceOf(JavaType type, ValueNode object) {
         BlockPlaceholderNode successor = currentGraph.add(new BlockPlaceholderNode());
         DeoptimizeNode deopt = currentGraph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved));
-        IfNode ifNode = currentGraph.add(new IfNode(currentGraph.unique(new IsNullNode(object)), successor, deopt, 1));
-        append(ifNode);
+        append(new IfNode(currentGraph.unique(new IsNullNode(object)), successor, deopt, 1));
         lastInstr = successor;
         frameState.ipush(appendConstant(Constant.INT_0));
     }
@@ -335,7 +333,7 @@
      * @param type the type being instantiated
      */
     protected void handleUnresolvedNewInstance(JavaType type) {
-        append(currentGraph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved)));
+        append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
         frameState.apush(appendConstant(Constant.NULL_OBJECT));
     }
 
@@ -344,7 +342,7 @@
      * @param length the length of the array
      */
     protected void handleUnresolvedNewObjectArray(JavaType type, ValueNode length) {
-        append(currentGraph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved)));
+        append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
         frameState.apush(appendConstant(Constant.NULL_OBJECT));
     }
 
@@ -353,7 +351,7 @@
      * @param dims the dimensions for the multi-array
      */
     protected void handleUnresolvedNewMultiArray(JavaType type, ValueNode[] dims) {
-        append(currentGraph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved)));
+        append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
         frameState.apush(appendConstant(Constant.NULL_OBJECT));
     }
 
@@ -363,8 +361,8 @@
      */
     protected void handleUnresolvedLoadField(JavaField field, ValueNode receiver) {
         Kind kind = field.getKind();
-        append(currentGraph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved)));
-        frameState.push(kind.getStackKind(), append(ConstantNode.defaultForKind(kind, currentGraph)));
+        append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+        frameState.push(kind.getStackKind(), appendConstant(Constant.defaultForKind(kind)));
     }
 
     /**
@@ -373,7 +371,7 @@
      * @param receiver the object containing the field or {@code null} if {@code field} is static
      */
     protected void handleUnresolvedStoreField(JavaField field, ValueNode value, ValueNode receiver) {
-        append(currentGraph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved)));
+        append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
     }
 
     /**
@@ -381,16 +379,16 @@
      * @param type
      */
     protected void handleUnresolvedExceptionType(Representation representation, JavaType type) {
-        append(currentGraph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved)));
+        append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
     }
 
     protected void handleUnresolvedInvoke(JavaMethod javaMethod, InvokeKind invokeKind) {
         boolean withReceiver = invokeKind != InvokeKind.Static;
-        append(currentGraph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved)));
+        append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
         frameState.popArguments(javaMethod.getSignature().getParameterSlots(withReceiver), javaMethod.getSignature().getParameterCount(withReceiver));
         Kind kind = javaMethod.getSignature().getReturnKind();
         if (kind != Kind.Void) {
-            frameState.push(kind.getStackKind(), append(ConstantNode.defaultForKind(kind, currentGraph)));
+            frameState.push(kind.getStackKind(), appendConstant(Constant.defaultForKind(kind)));
         }
     }
 
@@ -433,7 +431,7 @@
             // this is a load of class constant which might be unresolved
             JavaType type = (JavaType) con;
             if (type instanceof ResolvedJavaType) {
-                frameState.push(Kind.Object, append(ConstantNode.forConstant(((ResolvedJavaType) type).getEncoding(Representation.JavaClass), runtime, currentGraph)));
+                frameState.push(Kind.Object, appendConstant(((ResolvedJavaType) type).getEncoding(Representation.JavaClass)));
             } else {
                 handleUnresolvedLoadConstant(type);
             }
@@ -450,8 +448,7 @@
 
         ValueNode index = frameState.ipop();
         ValueNode array = frameState.apop();
-        ValueNode v = append(currentGraph.add(new LoadIndexedNode(array, index, kind)));
-        frameState.push(kind.getStackKind(), v);
+        frameState.push(kind.getStackKind(), append(new LoadIndexedNode(array, index, kind)));
     }
 
     private void genStoreIndexed(Kind kind) {
@@ -460,8 +457,7 @@
         ValueNode value = frameState.pop(kind.getStackKind());
         ValueNode index = frameState.ipop();
         ValueNode array = frameState.apop();
-        StoreIndexedNode result = currentGraph.add(new StoreIndexedNode(array, index, kind, value));
-        append(result);
+        append(new StoreIndexedNode(array, index, kind, value));
     }
 
     private void stackOp(int opcode) {
@@ -586,8 +582,7 @@
             default:
                 throw new GraalInternalError("should not reach");
         }
-        ValueNode result1 = append(currentGraph.unique(v));
-        frameState.push(result, result1);
+        frameState.push(result, append(v));
     }
 
     private void genIntegerDivOp(Kind result, int opcode) {
@@ -606,12 +601,11 @@
             default:
                 throw new GraalInternalError("should not reach");
         }
-        ValueNode result1 = append(currentGraph.add(v));
-        frameState.push(result, result1);
+        frameState.push(result, append(v));
     }
 
     private void genNegateOp(Kind kind) {
-        frameState.push(kind, append(currentGraph.unique(new NegateNode(frameState.pop(kind)))));
+        frameState.push(kind, append(new NegateNode(frameState.pop(kind))));
     }
 
     private void genShiftOp(Kind kind, int opcode) {
@@ -634,7 +628,7 @@
             default:
                 throw new GraalInternalError("should not reach");
         }
-        frameState.push(kind, append(currentGraph.unique(v)));
+        frameState.push(kind, append(v));
     }
 
     private void genLogicOp(Kind kind, int opcode) {
@@ -657,26 +651,26 @@
             default:
                 throw new GraalInternalError("should not reach");
         }
-        frameState.push(kind, append(currentGraph.unique(v)));
+        frameState.push(kind, append(v));
     }
 
     private void genCompareOp(Kind kind, boolean isUnorderedLess) {
         ValueNode y = frameState.pop(kind);
         ValueNode x = frameState.pop(kind);
-        frameState.ipush(append(currentGraph.unique(new NormalizeCompareNode(x, y, isUnorderedLess))));
+        frameState.ipush(append(new NormalizeCompareNode(x, y, isUnorderedLess)));
     }
 
     private void genConvert(ConvertNode.Op opcode) {
         ValueNode input = frameState.pop(opcode.from.getStackKind());
-        frameState.push(opcode.to.getStackKind(), append(currentGraph.unique(new ConvertNode(opcode, input))));
+        frameState.push(opcode.to.getStackKind(), append(new ConvertNode(opcode, input)));
     }
 
     private void genIncrement() {
         int index = stream().readLocalIndex();
         int delta = stream().readIncrement();
         ValueNode x = frameState.loadLocal(index);
-        ValueNode y = append(ConstantNode.forInt(delta, currentGraph));
-        frameState.storeLocal(index, append(currentGraph.unique(new IntegerAddNode(Kind.Int, x, y))));
+        ValueNode y = appendConstant(Constant.forInt(delta));
+        frameState.storeLocal(index, append(new IntegerAddNode(Kind.Int, x, y)));
     }
 
     private void genGoto() {
@@ -726,7 +720,7 @@
         AbstractBeginNode falseSuccessor = createBlockTarget(1 - probability, falseBlock, frameState);
 
         IfNode ifNode = negate ? new IfNode(condition, falseSuccessor, trueSuccessor, 1 - probability) : new IfNode(condition, trueSuccessor, falseSuccessor, probability);
-        append(currentGraph.add(ifNode));
+        append(ifNode);
     }
 
     private void genIfZero(Condition cond) {
@@ -750,9 +744,8 @@
 
     private void genThrow() {
         ValueNode exception = frameState.apop();
-        FixedGuardNode node = currentGraph.add(new FixedGuardNode(currentGraph.unique(new IsNullNode(exception)), NullCheckException, InvalidateReprofile, true));
-        append(node);
-        append(handleException(exception, bci()));
+        append(new FixedGuardNode(currentGraph.unique(new IsNullNode(exception)), NullCheckException, InvalidateReprofile, true));
+        lastInstr.setNext(handleException(exception, bci()));
     }
 
     private JavaType lookupType(int cpi, int bytecode) {
@@ -804,9 +797,8 @@
         ValueNode object = frameState.apop();
         if (type instanceof ResolvedJavaType) {
             JavaTypeProfile profileForTypeCheck = getProfileForTypeCheck((ResolvedJavaType) type);
-            CheckCastNode checkCast = currentGraph.add(new CheckCastNode((ResolvedJavaType) type, object, profileForTypeCheck, false));
-            append(checkCast);
-            frameState.apush(checkCast);
+            CheckCastNode checkCastNode = append(new CheckCastNode((ResolvedJavaType) type, object, profileForTypeCheck, false));
+            frameState.apush(checkCastNode);
         } else {
             handleUnresolvedCheckCast(type, object);
         }
@@ -819,8 +811,7 @@
         if (type instanceof ResolvedJavaType) {
             ResolvedJavaType resolvedType = (ResolvedJavaType) type;
             InstanceOfNode instanceOfNode = new InstanceOfNode((ResolvedJavaType) type, object, getProfileForTypeCheck(resolvedType));
-            ConditionalNode conditional = currentGraph.unique(new ConditionalNode(currentGraph.unique(instanceOfNode), ConstantNode.forInt(1, currentGraph), ConstantNode.forInt(0, currentGraph)));
-            frameState.ipush(append(conditional));
+            frameState.ipush(append(new ConditionalNode(currentGraph.unique(instanceOfNode), ConstantNode.forInt(1, currentGraph), ConstantNode.forInt(0, currentGraph))));
         } else {
             handleUnresolvedInstanceOf(type, object);
         }
@@ -829,8 +820,7 @@
     void genNewInstance(int cpi) {
         JavaType type = lookupType(cpi, NEW);
         if (type instanceof ResolvedJavaType && ((ResolvedJavaType) type).isInitialized()) {
-            NewInstanceNode n = currentGraph.add(new NewInstanceNode((ResolvedJavaType) type, true));
-            frameState.apush(append(n));
+            frameState.apush(append(new NewInstanceNode((ResolvedJavaType) type, true)));
         } else {
             handleUnresolvedNewInstance(type);
         }
@@ -871,16 +861,14 @@
     private void genNewPrimitiveArray(int typeCode) {
         Class<?> clazz = arrayTypeCodeToClass(typeCode);
         ResolvedJavaType elementType = runtime.lookupJavaType(clazz);
-        NewArrayNode nta = currentGraph.add(new NewArrayNode(elementType, frameState.ipop(), true));
-        frameState.apush(append(nta));
+        frameState.apush(append(new NewArrayNode(elementType, frameState.ipop(), true)));
     }
 
     private void genNewObjectArray(int cpi) {
         JavaType type = lookupType(cpi, ANEWARRAY);
         ValueNode length = frameState.ipop();
         if (type instanceof ResolvedJavaType) {
-            NewArrayNode n = currentGraph.add(new NewArrayNode((ResolvedJavaType) type, length, true));
-            frameState.apush(append(n));
+            frameState.apush(append(new NewArrayNode((ResolvedJavaType) type, length, true)));
         } else {
             handleUnresolvedNewObjectArray(type, length);
         }
@@ -895,8 +883,7 @@
             dims[i] = frameState.ipop();
         }
         if (type instanceof ResolvedJavaType) {
-            FixedWithNextNode n = currentGraph.add(new NewMultiArrayNode((ResolvedJavaType) type, dims));
-            frameState.apush(append(n));
+            frameState.apush(append(new NewMultiArrayNode((ResolvedJavaType) type, dims)));
         } else {
             handleUnresolvedNewMultiArray(type, dims);
         }
@@ -908,8 +895,7 @@
         Kind kind = field.getKind();
         ValueNode receiver = frameState.apop();
         if ((field instanceof ResolvedJavaField) && ((ResolvedJavaField) field).getDeclaringClass().isInitialized()) {
-            LoadFieldNode load = currentGraph.add(new LoadFieldNode(receiver, (ResolvedJavaField) field));
-            appendOptimizedLoadField(kind, load);
+            appendOptimizedLoadField(kind, new LoadFieldNode(receiver, (ResolvedJavaField) field));
         } else {
             handleUnresolvedLoadField(field, receiver);
         }
@@ -932,16 +918,14 @@
         }
         BlockPlaceholderNode trueSucc = currentGraph.add(new BlockPlaceholderNode());
         BlockPlaceholderNode falseSucc = currentGraph.add(new BlockPlaceholderNode());
-        IfNode ifNode = currentGraph.add(new IfNode(currentGraph.unique(new IsNullNode(receiver)), trueSucc, falseSucc, 0.1));
-
-        append(ifNode);
+        append(new IfNode(currentGraph.unique(new IsNullNode(receiver)), trueSucc, falseSucc, 0.1));
         lastInstr = falseSucc;
 
         if (GraalOptions.OmitHotExceptionStacktrace) {
             ValueNode exception = ConstantNode.forObject(cachedNullPointerException, runtime, currentGraph);
             trueSucc.setNext(handleException(exception, bci()));
         } else {
-            RuntimeCallNode call = currentGraph.add(new RuntimeCallNode(CREATE_NULL_POINTER_EXCEPTION));
+            ForeignCallStateSplitNode call = currentGraph.add(new ForeignCallStateSplitNode(runtime, CREATE_NULL_POINTER_EXCEPTION));
             call.setStateAfter(frameState.create(bci()));
             trueSucc.setNext(call);
             call.setNext(handleException(call, bci()));
@@ -958,16 +942,14 @@
     private void emitBoundsCheck(ValueNode index, ValueNode length) {
         BlockPlaceholderNode trueSucc = currentGraph.add(new BlockPlaceholderNode());
         BlockPlaceholderNode falseSucc = currentGraph.add(new BlockPlaceholderNode());
-        IfNode ifNode = currentGraph.add(new IfNode(currentGraph.unique(new IntegerBelowThanNode(index, length)), trueSucc, falseSucc, 0.9));
-
-        append(ifNode);
+        append(new IfNode(currentGraph.unique(new IntegerBelowThanNode(index, length)), trueSucc, falseSucc, 0.9));
         lastInstr = trueSucc;
 
         if (GraalOptions.OmitHotExceptionStacktrace) {
             ValueNode exception = ConstantNode.forObject(cachedArrayIndexOutOfBoundsException, runtime, currentGraph);
             falseSucc.setNext(handleException(exception, bci()));
         } else {
-            RuntimeCallNode call = currentGraph.add(new RuntimeCallNode(CREATE_OUT_OF_BOUNDS_EXCEPTION, index));
+            ForeignCallStateSplitNode call = currentGraph.add(new ForeignCallStateSplitNode(runtime, CREATE_OUT_OF_BOUNDS_EXCEPTION, index));
             call.setStateAfter(frameState.create(bci()));
             falseSucc.setNext(call);
             call.setNext(handleException(call, bci()));
@@ -982,7 +964,7 @@
 
         emitNullCheck(receiver);
         if (outOfBoundsIndex != null) {
-            ValueNode length = append(currentGraph.add(new ArrayLengthNode(receiver)));
+            ValueNode length = append(new ArrayLengthNode(receiver));
             emitBoundsCheck(outOfBoundsIndex, length);
         }
         Debug.metric("ExplicitExceptions").increment();
@@ -994,8 +976,7 @@
         ValueNode value = frameState.pop(field.getKind().getStackKind());
         ValueNode receiver = frameState.apop();
         if (field instanceof ResolvedJavaField && ((ResolvedJavaField) field).getDeclaringClass().isInitialized()) {
-            StoreFieldNode store = currentGraph.add(new StoreFieldNode(receiver, (ResolvedJavaField) field, value));
-            appendOptimizedStoreField(store);
+            appendOptimizedStoreField(new StoreFieldNode(receiver, (ResolvedJavaField) field, value));
         } else {
             handleUnresolvedStoreField(field, value, receiver);
         }
@@ -1004,8 +985,7 @@
     private void genGetStatic(JavaField field) {
         Kind kind = field.getKind();
         if (field instanceof ResolvedJavaField && ((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) {
-            LoadFieldNode load = currentGraph.add(new LoadFieldNode(null, (ResolvedJavaField) field));
-            appendOptimizedLoadField(kind, load);
+            appendOptimizedLoadField(kind, new LoadFieldNode(null, (ResolvedJavaField) field));
         } else {
             handleUnresolvedLoadField(field, null);
         }
@@ -1014,8 +994,7 @@
     private void genPutStatic(JavaField field) {
         ValueNode value = frameState.pop(field.getKind().getStackKind());
         if (field instanceof ResolvedJavaField && ((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) {
-            StoreFieldNode store = currentGraph.add(new StoreFieldNode(null, (ResolvedJavaField) field, value));
-            appendOptimizedStoreField(store);
+            appendOptimizedStoreField(new StoreFieldNode(null, (ResolvedJavaField) field, value));
         } else {
             handleUnresolvedStoreField(field, value, null);
         }
@@ -1142,8 +1121,7 @@
     private void appendInvoke(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args) {
         Kind resultType = targetMethod.getSignature().getReturnKind();
         if (GraalOptions.DeoptALot) {
-            DeoptimizeNode deoptimize = currentGraph.add(new DeoptimizeNode(DeoptimizationAction.None, RuntimeConstraint));
-            append(deoptimize);
+            append(new DeoptimizeNode(DeoptimizationAction.None, RuntimeConstraint));
             frameState.pushReturn(resultType, ConstantNode.defaultForKind(resultType, currentGraph));
             return;
         }
@@ -1164,15 +1142,12 @@
         // be conservative if information was not recorded (could result in endless recompiles
         // otherwise)
         if (graphBuilderConfig.omitAllExceptionEdges() || (optimisticOpts.useExceptionProbability() && profilingInfo.getExceptionSeen(bci()) == TriState.FALSE)) {
-            InvokeNode invoke = new InvokeNode(callTarget, bci());
-            ValueNode result = appendWithBCI(currentGraph.add(invoke));
-            frameState.pushReturn(resultType, result);
-            return invoke;
+            frameState.pushReturn(resultType, append(new InvokeNode(callTarget, bci())));
+            return new InvokeNode(callTarget, bci());
         } else {
             DispatchBeginNode exceptionEdge = handleException(null, bci());
-            InvokeWithExceptionNode invoke = currentGraph.add(new InvokeWithExceptionNode(callTarget, exceptionEdge, bci()));
-            ValueNode result = append(invoke);
-            frameState.pushReturn(resultType, result);
+            InvokeWithExceptionNode invoke = append(new InvokeWithExceptionNode(callTarget, exceptionEdge, bci()));
+            frameState.pushReturn(resultType, invoke);
             Block nextBlock = currentBlock.successors.get(0);
 
             assert bci() == currentBlock.endBci;
@@ -1193,19 +1168,17 @@
     }
 
     private MonitorEnterNode genMonitorEnter(ValueNode x) {
-        MonitorEnterNode monitorEnter = currentGraph.add(new MonitorEnterNode(x, frameState.lockDepth()));
+        MonitorEnterNode monitorEnter = append(new MonitorEnterNode(x, frameState.lockDepth()));
         frameState.pushLock(x);
-        appendWithBCI(monitorEnter);
         return monitorEnter;
     }
 
     private MonitorExitNode genMonitorExit(ValueNode x) {
         ValueNode lockedObject = frameState.popLock();
-        MonitorExitNode monitorExit = currentGraph.add(new MonitorExitNode(x, frameState.lockDepth()));
         if (GraphUtil.originalValue(lockedObject) != GraphUtil.originalValue(x)) {
             throw new BailoutException("unbalanced monitors: mismatch at monitorexit, %s != %s", GraphUtil.originalValue(x), GraphUtil.originalValue(lockedObject));
         }
-        appendWithBCI(monitorExit);
+        MonitorExitNode monitorExit = append(new MonitorExitNode(x, frameState.lockDepth()));
         return monitorExit;
     }
 
@@ -1228,7 +1201,7 @@
         ValueNode local = frameState.loadLocal(localIndex);
         JsrScope scope = currentBlock.jsrScope;
         int retAddress = scope.nextReturnAddress();
-        append(currentGraph.add(new FixedGuardNode(currentGraph.unique(new IntegerEqualsNode(local, ConstantNode.forInt(retAddress, currentGraph))), JavaSubroutineMismatch, InvalidateReprofile)));
+        append(new FixedGuardNode(currentGraph.unique(new IntegerEqualsNode(local, ConstantNode.forInt(retAddress, currentGraph))), JavaSubroutineMismatch, InvalidateReprofile));
         if (!successor.jsrScope.equals(scope.pop())) {
             throw new JsrNotSupportedBailout("unstructured control flow (ret leaves more than one scope)");
         }
@@ -1315,12 +1288,11 @@
         }
 
         double[] successorProbabilities = successorProbabilites(actualSuccessors.size(), keySuccessors, keyProbabilities);
-        IntegerSwitchNode switchNode = currentGraph.add(new IntegerSwitchNode(value, actualSuccessors.size(), keys, keyProbabilities, keySuccessors));
+        IntegerSwitchNode switchNode = append(new IntegerSwitchNode(value, actualSuccessors.size(), keys, keyProbabilities, keySuccessors));
         for (int i = 0; i < actualSuccessors.size(); i++) {
             switchNode.setBlockSuccessor(i, createBlockTarget(successorProbabilities[i], actualSuccessors.get(i), frameState));
         }
 
-        append(switchNode);
     }
 
     private static class SuccessorInfo {
@@ -1339,26 +1311,37 @@
         return ConstantNode.forConstant(constant, runtime, currentGraph);
     }
 
-    private ValueNode append(FixedNode fixed) {
-        lastInstr.setNext(fixed);
+    private <T extends ControlSinkNode> T append(T fixed) {
+        assert !fixed.isAlive() && !fixed.isDeleted() : "instruction should not have been appended yet";
+        assert lastInstr.next() == null : "cannot append instruction to instruction which isn't end (" + lastInstr + "->" + lastInstr.next() + ")";
+        T added = currentGraph.add(fixed);
+        lastInstr.setNext(added);
         lastInstr = null;
-        return fixed;
-    }
-
-    protected ValueNode append(FixedWithNextNode x) {
-        return appendWithBCI(x);
+        return added;
     }
 
-    private static ValueNode append(ValueNode v) {
-        return v;
+    private <T extends ControlSplitNode> T append(T fixed) {
+        assert !fixed.isAlive() && !fixed.isDeleted() : "instruction should not have been appended yet";
+        assert lastInstr.next() == null : "cannot append instruction to instruction which isn't end (" + lastInstr + "->" + lastInstr.next() + ")";
+        T added = currentGraph.add(fixed);
+        lastInstr.setNext(added);
+        lastInstr = null;
+        return added;
     }
 
-    protected ValueNode appendWithBCI(FixedWithNextNode x) {
-        assert x.predecessor() == null : "instruction should not have been appended yet";
+    protected <T extends FixedWithNextNode> T append(T fixed) {
+        assert !fixed.isAlive() && !fixed.isDeleted() : "instruction should not have been appended yet";
         assert lastInstr.next() == null : "cannot append instruction to instruction which isn't end (" + lastInstr + "->" + lastInstr.next() + ")";
-        lastInstr.setNext(x);
-        lastInstr = x;
-        return x;
+        T added = currentGraph.add(fixed);
+        lastInstr.setNext(added);
+        lastInstr = added;
+        return added;
+    }
+
+    private <T extends FloatingNode> T append(T v) {
+        assert !(v instanceof ConstantNode);
+        T added = currentGraph.unique(v);
+        return added;
     }
 
     private static class Target {
@@ -1525,7 +1508,7 @@
 
     private ValueNode synchronizedObject(FrameStateBuilder state, ResolvedJavaMethod target) {
         if (isStatic(target.getModifiers())) {
-            return append(ConstantNode.forConstant(target.getDeclaringClass().getEncoding(Representation.JavaClass), runtime, currentGraph));
+            return appendConstant(target.getDeclaringClass().getEncoding(Representation.JavaClass));
         } else {
             return state.loadLocal(0);
         }
@@ -1590,11 +1573,9 @@
     private void createUnwind() {
         assert frameState.stackSize() == 1 : frameState;
         ValueNode exception = frameState.apop();
-        FixedGuardNode guard = currentGraph.add(new FixedGuardNode(currentGraph.unique(new IsNullNode(exception)), NullCheckException, InvalidateReprofile, true));
-        append(guard);
+        append(new FixedGuardNode(currentGraph.unique(new IsNullNode(exception)), NullCheckException, InvalidateReprofile, true));
         synchronizedEpilogue(FrameState.AFTER_EXCEPTION_BCI);
-        UnwindNode unwindNode = currentGraph.add(new UnwindNode(exception));
-        append(unwindNode);
+        append(new UnwindNode(exception));
     }
 
     private void createReturn() {
@@ -1603,7 +1584,7 @@
         assert frameState.stackSize() == 0;
 
         if (Modifier.isSynchronized(method.getModifiers())) {
-            append(currentGraph.add(new ValueAnchorNode(true, x)));
+            append(new ValueAnchorNode(true, x));
             assert !frameState.rethrowException();
         }
 
@@ -1611,15 +1592,13 @@
         if (frameState.lockDepth() != 0) {
             throw new BailoutException("unbalanced monitors");
         }
-        ReturnNode returnNode = currentGraph.add(new ReturnNode(x));
 
         if (graphBuilderConfig.eagerInfopointMode()) {
-            InfopointNode ipn = currentGraph.add(new InfopointNode(InfopointReason.METHOD_END));
+            InfopointNode ipn = append(new InfopointNode(InfopointReason.METHOD_END));
             ipn.setStateAfter(frameState.create(FrameState.AFTER_BCI));
-            append(ipn);
         }
 
-        append(returnNode);
+        append(new ReturnNode(x));
     }
 
     private void synchronizedEpilogue(int bci) {
@@ -1665,8 +1644,7 @@
             frameState.push(Kind.Object, exception);
             FixedNode nextDispatch = createTarget(nextBlock, frameState);
             checkCast.setNext(catchSuccessor);
-            IfNode ifNode = currentGraph.add(new IfNode(currentGraph.unique(new InstanceOfNode((ResolvedJavaType) catchType, exception, null)), checkCast, nextDispatch, 0.5));
-            append(ifNode);
+            append(new IfNode(currentGraph.unique(new InstanceOfNode((ResolvedJavaType) catchType, exception, null)), checkCast, nextDispatch, 0.5));
         }
     }
 
@@ -1732,9 +1710,8 @@
             if (graphBuilderConfig.eagerInfopointMode() && lnt != null) {
                 currentLineNumber = lnt.getLineNumber(bci);
                 if (currentLineNumber != previousLineNumber) {
-                    InfopointNode ipn = currentGraph.add(new InfopointNode(InfopointReason.LINE_NUMBER));
+                    InfopointNode ipn = append(new InfopointNode(InfopointReason.LINE_NUMBER));
                     ipn.setStateAfter(frameState.create(bci));
-                    append(ipn);
                     previousLineNumber = currentLineNumber;
                 }
             }
@@ -1747,8 +1724,7 @@
                 if (block.jsrScope != JsrScope.EMPTY_SCOPE) {
                     throw new BailoutException("OSR into a JSR scope is not supported");
                 }
-                EntryMarkerNode x = currentGraph.add(new EntryMarkerNode());
-                append(x);
+                EntryMarkerNode x = append(new EntryMarkerNode());
                 frameState.insertProxies(x);
                 x.setStateAfter(frameState.create(bci));
             }
@@ -2037,6 +2013,6 @@
     }
 
     private void genArrayLength() {
-        frameState.ipush(append(currentGraph.add(new ArrayLengthNode(frameState.apop()))));
+        frameState.ipush(append(new ArrayLengthNode(frameState.apop())));
     }
 }
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Call.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Call.java	Fri May 17 15:40:06 2013 +0200
@@ -102,11 +102,11 @@
         }
     }
 
-    public abstract static class RuntimeCallOp extends CallOp {
+    public abstract static class ForeignCallOp extends CallOp {
 
-        protected final RuntimeCallTarget callTarget;
+        protected final ForeignCallLinkage callTarget;
 
-        public RuntimeCallOp(RuntimeCallTarget callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
+        public ForeignCallOp(ForeignCallLinkage callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
             super(result, parameters, temps, state);
             this.callTarget = callTarget;
         }
@@ -117,11 +117,11 @@
         }
     }
 
-    @Opcode("CALL_NEAR_RUNTIME")
-    public static class DirectNearRuntimeCallOp extends RuntimeCallOp {
+    @Opcode("NEAR_FOREIGN_CALL")
+    public static class DirectNearForeignCallOp extends ForeignCallOp {
 
-        public DirectNearRuntimeCallOp(RuntimeCallTarget callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
-            super(callTarget, result, parameters, temps, state);
+        public DirectNearForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
+            super(linkage, result, parameters, temps, state);
         }
 
         @Override
@@ -130,12 +130,12 @@
         }
     }
 
-    @Opcode("CALL_FAR_RUNTIME")
-    public static class DirectFarRuntimeCallOp extends RuntimeCallOp {
+    @Opcode("FAR_FOREIGN_CALL")
+    public static class DirectFarForeignCallOp extends ForeignCallOp {
 
         @Temp({REG}) protected AllocatableValue callTemp;
 
-        public DirectFarRuntimeCallOp(LIRGeneratorTool gen, RuntimeCallTarget callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
+        public DirectFarForeignCallOp(LIRGeneratorTool gen, ForeignCallLinkage callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
             super(callTarget, result, parameters, temps, state);
             callTemp = gen.newVariable(Kind.Long);
         }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopSafepointEliminationPhase.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopSafepointEliminationPhase.java	Fri May 17 15:40:06 2013 +0200
@@ -52,7 +52,7 @@
                 blocks: while (b != loop.lirLoop().header) {
                     assert b != null;
                     for (FixedNode node : b.getNodes()) {
-                        if (node instanceof Invoke || node instanceof RuntimeCallNode) {
+                        if (node instanceof Invoke || node instanceof ForeignCallNode) {
                             loopEnd.disableSafepoint();
                             break blocks;
                         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Fri May 17 15:40:06 2013 +0200
@@ -218,7 +218,7 @@
     }
 
     /**
-     * Unlinks a node from all its control flow neighbours and then removes it from its graph. The
+     * Unlinks a node from all its control flow neighbors and then removes it from its graph. The
      * node must have no {@linkplain Node#usages() usages}.
      * 
      * @param node the node to be unlinked and removed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java	Fri May 17 15:40:06 2013 +0200
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes.extended;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+
+/**
+ * Node for a {@linkplain ForeignCallDescriptor foreign} call.
+ */
+@NodeInfo(nameTemplate = "ForeignCall#{p#descriptor/s}")
+public class ForeignCallNode extends DeoptimizingFixedWithNextNode implements LIRLowerable, DeoptimizingNode, MemoryCheckpoint {
+
+    @Input private final NodeInputList<ValueNode> arguments;
+
+    private final ForeignCallDescriptor descriptor;
+
+    public ForeignCallNode(ForeignCallDescriptor descriptor, ValueNode... arguments) {
+        super(StampFactory.forKind(Kind.fromJavaClass(descriptor.getResultType())));
+        this.arguments = new NodeInputList<>(this, arguments);
+        this.descriptor = descriptor;
+    }
+
+    protected ForeignCallNode(ForeignCallDescriptor descriptor, Stamp stamp) {
+        super(stamp);
+        this.arguments = new NodeInputList<>(this);
+        this.descriptor = descriptor;
+    }
+
+    public ForeignCallDescriptor getDescriptor() {
+        return descriptor;
+    }
+
+    @Override
+    public LocationIdentity[] getLocationIdentities() {
+        return new LocationIdentity[]{LocationNode.ANY_LOCATION};
+    }
+
+    protected Value[] operands(LIRGeneratorTool gen) {
+        Value[] operands = new Value[arguments.size()];
+        for (int i = 0; i < operands.length; i++) {
+            operands[i] = gen.operand(arguments.get(i));
+        }
+        return operands;
+    }
+
+    @Override
+    public void generate(LIRGeneratorTool gen) {
+        ForeignCallLinkage linkage = gen.getRuntime().lookupForeignCall(descriptor);
+        Value[] operands = operands(gen);
+        Value result = gen.emitForeignCall(linkage, this, operands);
+        if (result != null) {
+            gen.setResult(this, result);
+        }
+    }
+
+    @Override
+    public String toString(Verbosity verbosity) {
+        if (verbosity == Verbosity.Name) {
+            return super.toString(verbosity) + "#" + descriptor;
+        }
+        return super.toString(verbosity);
+    }
+
+    @Override
+    public boolean canDeoptimize() {
+        return true;
+    }
+
+    @Override
+    public DeoptimizationReason getDeoptimizationReason() {
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallStateSplitNode.java	Fri May 17 15:40:06 2013 +0200
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes.extended;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+
+/**
+ * A foreign call that is also a state split.
+ */
+@NodeInfo(nameTemplate = "ForeignCallStateSplit#{p#descriptor/s}")
+public class ForeignCallStateSplitNode extends ForeignCallNode implements LIRLowerable, StateSplit, DeoptimizingNode {
+
+    @Input(notDataflow = true) private FrameState stateAfter;
+    private MetaAccessProvider runtime;
+
+    public ForeignCallStateSplitNode(MetaAccessProvider runtime, ForeignCallDescriptor descriptor, ValueNode... arguments) {
+        super(descriptor, arguments);
+        this.runtime = runtime;
+    }
+
+    public FrameState stateAfter() {
+        return stateAfter;
+    }
+
+    public void setStateAfter(FrameState x) {
+        assert x == null || x.isAlive() : "frame state must be in a graph";
+        updateUsages(stateAfter, x);
+        stateAfter = x;
+    }
+
+    public boolean hasSideEffect() {
+        return runtime.hasSideEffect(getDescriptor());
+    }
+
+    @Override
+    public FrameState getDeoptimizationState() {
+        if (super.getDeoptimizationState() != null) {
+            return super.getDeoptimizationState();
+        } else if (stateAfter() != null) {
+            FrameState stateDuring = stateAfter();
+            if ((stateDuring.stackSize() > 0 && stateDuring.stackAt(stateDuring.stackSize() - 1) == this) || (stateDuring.stackSize() > 1 && stateDuring.stackAt(stateDuring.stackSize() - 2) == this)) {
+                stateDuring = stateDuring.duplicateModified(stateDuring.bci, stateDuring.rethrowException(), this.kind());
+            }
+            setDeoptimizationState(stateDuring);
+            return stateDuring;
+        }
+        return null;
+    }
+
+    @Override
+    public void setDeoptimizationState(FrameState f) {
+        if (super.getDeoptimizationState() != null) {
+            throw new IllegalStateException();
+        }
+        super.setDeoptimizationState(f);
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/RuntimeCallNode.java	Fri May 17 15:38:22 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,109 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes.extended;
-
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
-
-@NodeInfo(nameTemplate = "RuntimeCall#{p#descriptor/s}")
-public final class RuntimeCallNode extends AbstractCallNode implements LIRLowerable, DeoptimizingNode {
-
-    private final Descriptor descriptor;
-    @Input private FrameState deoptState;
-
-    public RuntimeCallNode(Descriptor descriptor, ValueNode... arguments) {
-        super(StampFactory.forKind(Kind.fromJavaClass(descriptor.getResultType())), arguments);
-        this.descriptor = descriptor;
-    }
-
-    public Descriptor getDescriptor() {
-        return descriptor;
-    }
-
-    @Override
-    public boolean hasSideEffect() {
-        return descriptor.hasSideEffect();
-    }
-
-    @Override
-    public LocationIdentity[] getLocationIdentities() {
-        return new LocationIdentity[]{LocationNode.ANY_LOCATION};
-    }
-
-    @Override
-    public void generate(LIRGeneratorTool gen) {
-        gen.visitRuntimeCall(this);
-    }
-
-    @Override
-    public String toString(Verbosity verbosity) {
-        if (verbosity == Verbosity.Name) {
-            return super.toString(verbosity) + "#" + descriptor;
-        }
-        return super.toString(verbosity);
-    }
-
-    @Override
-    public boolean canDeoptimize() {
-        return true;
-    }
-
-    @Override
-    public FrameState getDeoptimizationState() {
-        if (deoptState != null) {
-            return deoptState;
-        } else if (stateAfter() != null) {
-            FrameState stateDuring = stateAfter();
-            if ((stateDuring.stackSize() > 0 && stateDuring.stackAt(stateDuring.stackSize() - 1) == this) || (stateDuring.stackSize() > 1 && stateDuring.stackAt(stateDuring.stackSize() - 2) == this)) {
-                stateDuring = stateDuring.duplicateModified(stateDuring.bci, stateDuring.rethrowException(), this.kind());
-            }
-            updateUsages(deoptState, stateDuring);
-            return deoptState = stateDuring;
-        }
-        return null;
-    }
-
-    @Override
-    public void setDeoptimizationState(FrameState f) {
-        if (deoptState != null) {
-            throw new IllegalStateException();
-        }
-        updateUsages(deoptState, f);
-        deoptState = f;
-    }
-
-    @Override
-    public DeoptimizationReason getDeoptimizationReason() {
-        return null;
-    }
-
-    @Override
-    public boolean isCallSiteDeoptimization() {
-        return stateAfter() != null;
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java	Fri May 17 15:40:06 2013 +0200
@@ -33,7 +33,7 @@
  * The {@code LoadFieldNode} represents a read of a static or instance field.
  */
 @NodeInfo(nameTemplate = "LoadField#{p#field/s}")
-public final class LoadFieldNode extends AccessFieldNode implements Canonicalizable, Node.IterableNodeType, Virtualizable {
+public final class LoadFieldNode extends AccessFieldNode implements Canonicalizable, Node.IterableNodeType, VirtualizableRoot {
 
     /**
      * Creates a new LoadFieldNode instance.
@@ -79,6 +79,13 @@
             if (fieldIndex != -1) {
                 tool.replaceWith(state.getEntry(fieldIndex));
             }
+        } else {
+            ValueNode cachedValue = tool.getReadCache(object(), field());
+            if (cachedValue != null) {
+                tool.replaceWithValue(cachedValue);
+            } else {
+                tool.addReadCache(object(), field(), this);
+            }
         }
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java	Fri May 17 15:40:06 2013 +0200
@@ -23,7 +23,6 @@
 package com.oracle.graal.nodes.java;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
@@ -35,7 +34,7 @@
  */
 public final class RegisterFinalizerNode extends AbstractStateSplit implements StateSplit, Canonicalizable, LIRLowerable, Virtualizable, DeoptimizingNode {
 
-    public static final Descriptor REGISTER_FINALIZER = new Descriptor("registerFinalizer", true, void.class, Object.class);
+    public static final ForeignCallDescriptor REGISTER_FINALIZER = new ForeignCallDescriptor("registerFinalizer", void.class, Object.class);
 
     @Input private FrameState deoptState;
     @Input private ValueNode object;
@@ -51,8 +50,8 @@
 
     @Override
     public void generate(LIRGeneratorTool gen) {
-        RuntimeCallTarget call = gen.getRuntime().lookupRuntimeCall(REGISTER_FINALIZER);
-        gen.emitCall(call, call.getCallingConvention(), this, gen.operand(object()));
+        ForeignCallLinkage linkage = gen.getRuntime().lookupForeignCall(REGISTER_FINALIZER);
+        gen.emitForeignCall(linkage, this, gen.operand(object()));
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreFieldNode.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreFieldNode.java	Fri May 17 15:40:06 2013 +0200
@@ -33,7 +33,7 @@
  * The {@code StoreFieldNode} represents a write to a static or instance field.
  */
 @NodeInfo(nameTemplate = "StoreField#{p#field/s}")
-public final class StoreFieldNode extends AccessFieldNode implements StateSplit, Virtualizable {
+public final class StoreFieldNode extends AccessFieldNode implements StateSplit, VirtualizableRoot {
 
     @Input private ValueNode value;
     @Input(notDataflow = true) private FrameState stateAfter;
@@ -77,6 +77,12 @@
                 tool.setVirtualEntry(state, fieldIndex, value());
                 tool.delete();
             }
+        } else {
+            if (value() == tool.getReadCache(object(), field())) {
+                tool.delete();
+            }
+            tool.killReadCache(field());
+            tool.addReadCache(object(), field(), value());
         }
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java	Fri May 17 15:40:06 2013 +0200
@@ -101,7 +101,7 @@
 
     void emitNullCheck(ValueNode v, DeoptimizingNode deopting);
 
-    Value emitCall(RuntimeCallTarget callTarget, CallingConvention cc, DeoptimizingNode info, Value... args);
+    Value emitForeignCall(ForeignCallLinkage linkage, DeoptimizingNode info, Value... args);
 
     void emitIf(IfNode i);
 
@@ -111,8 +111,6 @@
 
     void emitInvoke(Invoke i);
 
-    void visitRuntimeCall(RuntimeCallNode i);
-
     // Handling of block-end nodes still needs to be unified in the LIRGenerator.
     void visitMerge(MergeNode i);
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizableAllocation.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizableAllocation.java	Fri May 17 15:40:06 2013 +0200
@@ -26,12 +26,9 @@
  * This interface allows a node to convey information about what its effect would be if some of its
  * inputs were virtualized.
  * 
- * The difference to {@link Virtualizable} is that the {@link #virtualize(VirtualizerTool)} method
- * will be called regardless of whether this node had any interaction with virtualized nodes. This
- * interface can therefore be used for object allocations, for which virtualization introduces new
- * virtualized objects.
- * 
+ * The difference to {@link VirtualizableRoot} is that removing {@link VirtualizableAllocation}
+ * nodes is not considered progress during the escape analysis iterations.
  */
-public interface VirtualizableAllocation extends Virtualizable {
+public interface VirtualizableAllocation extends VirtualizableRoot {
 
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizableRoot.java	Fri May 17 15:40:06 2013 +0200
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes.spi;
+
+/**
+ * This interface allows a node to convey information about what its effect would be if some of its
+ * inputs were virtualized.
+ * 
+ * The difference to {@link Virtualizable} is that the {@link #virtualize(VirtualizerTool)} method
+ * will be called regardless of whether this node had any interaction with virtualized nodes. This
+ * interface can therefore be used for object allocations, for which virtualization introduces new
+ * virtualized objects.
+ * 
+ */
+public interface VirtualizableRoot extends Virtualizable {
+
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java	Fri May 17 15:40:06 2013 +0200
@@ -152,4 +152,11 @@
      * @param value the replacement value
      */
     void replaceWith(ValueNode value);
+
+    void addReadCache(ValueNode object, ResolvedJavaField identity, ValueNode value);
+
+    ValueNode getReadCache(ValueNode object, ResolvedJavaField identity);
+
+    void killReadCache(ResolvedJavaField identity);
+
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FrameStateAssignmentPhase.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FrameStateAssignmentPhase.java	Fri May 17 15:40:06 2013 +0200
@@ -34,7 +34,7 @@
 
 public class FrameStateAssignmentPhase extends Phase {
 
-    private static class FrameStateAssignementClosure extends NodeIteratorClosure<FrameState> {
+    private static class FrameStateAssignmentClosure extends NodeIteratorClosure<FrameState> {
 
         @Override
         protected FrameState processNode(FixedNode node, FrameState currentState) {
@@ -79,7 +79,7 @@
     @Override
     protected void run(StructuredGraph graph) {
         assert checkFixedDeopts(graph);
-        ReentrantNodeIterator.apply(new FrameStateAssignementClosure(), graph.start(), null, null);
+        ReentrantNodeIterator.apply(new FrameStateAssignmentClosure(), graph.start(), null, null);
     }
 
     private static boolean checkFixedDeopts(StructuredGraph graph) {
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Fri May 17 15:40:06 2013 +0200
@@ -95,6 +95,7 @@
                             FixedNode fixed = (FixedNode) node;
                             if (identity == LocationNode.ANY_LOCATION || read.location().getLocationIdentity() == identity) {
                                 addPhantomReference(read, fixed);
+                                iter.remove();
                             }
                         }
                     }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Log.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Log.java	Fri May 17 15:40:06 2013 +0200
@@ -24,7 +24,6 @@
 
 import java.io.*;
 
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.Node.ConstantNodeParameter;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
@@ -33,28 +32,27 @@
 //JaCoCo Exclude
 
 /**
- * Provides {@link PrintStream}-like logging facility. This should only be used in
- * {@linkplain Snippet snippets}.
+ * Provides {@link PrintStream}-like logging facility.
  */
 public final class Log {
 
-    public static final Descriptor LOG_PRIMITIVE = new Descriptor("logPrimitive", false, void.class, int.class, long.class, boolean.class);
-    public static final Descriptor LOG_OBJECT = new Descriptor("logObject", false, void.class, Object.class, int.class);
-    public static final Descriptor LOG_PRINTF = new Descriptor("logPrintf", false, void.class, Object.class, long.class, long.class, long.class);
+    public static final ForeignCallDescriptor LOG_PRIMITIVE = new ForeignCallDescriptor("logPrimitive", void.class, int.class, long.class, boolean.class);
+    public static final ForeignCallDescriptor LOG_OBJECT = new ForeignCallDescriptor("logObject", void.class, Object.class, int.class);
+    public static final ForeignCallDescriptor LOG_PRINTF = new ForeignCallDescriptor("logPrintf", void.class, Object.class, long.class, long.class, long.class);
 
-    // Note: Must be kept in sync with constants in c1_Runtime1.hpp
+    // Note: Must be kept in sync with constants in graalRuntime.hpp
     private static final int LOG_OBJECT_NEWLINE = 0x01;
     private static final int LOG_OBJECT_STRING = 0x02;
     private static final int LOG_OBJECT_ADDRESS = 0x04;
 
-    @NodeIntrinsic(RuntimeCallNode.class)
-    private static native void log(@ConstantNodeParameter Descriptor logObject, Object object, int flags);
+    @NodeIntrinsic(ForeignCallNode.class)
+    private static native void log(@ConstantNodeParameter ForeignCallDescriptor logObject, Object object, int flags);
 
-    @NodeIntrinsic(RuntimeCallNode.class)
-    private static native void log(@ConstantNodeParameter Descriptor logPrimitive, int typeChar, long value, boolean newline);
+    @NodeIntrinsic(ForeignCallNode.class)
+    private static native void log(@ConstantNodeParameter ForeignCallDescriptor logPrimitive, int typeChar, long value, boolean newline);
 
-    @NodeIntrinsic(RuntimeCallNode.class)
-    private static native void printf(@ConstantNodeParameter Descriptor logPrintf, String format, long v1, long v2, long v3);
+    @NodeIntrinsic(ForeignCallNode.class)
+    private static native void printf(@ConstantNodeParameter ForeignCallDescriptor logPrintf, String format, long v1, long v2, long v3);
 
     public static void print(boolean value) {
         log(LOG_PRIMITIVE, Kind.Boolean.getTypeChar(), value ? 1L : 0L, false);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/MathSubstitutionsX86.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/MathSubstitutionsX86.java	Fri May 17 15:40:06 2013 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.replacements;
 
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.graph.Node.ConstantNodeParameter;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
@@ -91,12 +91,12 @@
         }
     }
 
-    public static final Descriptor ARITHMETIC_SIN = new Descriptor("arithmeticSin", false, double.class, double.class);
-    public static final Descriptor ARITHMETIC_COS = new Descriptor("arithmeticCos", false, double.class, double.class);
-    public static final Descriptor ARITHMETIC_TAN = new Descriptor("arithmeticTan", false, double.class, double.class);
+    public static final ForeignCallDescriptor ARITHMETIC_SIN = new ForeignCallDescriptor("arithmeticSin", double.class, double.class);
+    public static final ForeignCallDescriptor ARITHMETIC_COS = new ForeignCallDescriptor("arithmeticCos", double.class, double.class);
+    public static final ForeignCallDescriptor ARITHMETIC_TAN = new ForeignCallDescriptor("arithmeticTan", double.class, double.class);
 
-    @NodeIntrinsic(value = RuntimeCallNode.class, setStampFromReturnType = true)
-    public static double callDouble(@ConstantNodeParameter Descriptor descriptor, double value) {
+    @NodeIntrinsic(value = ForeignCallNode.class, setStampFromReturnType = true)
+    public static double callDouble(@ConstantNodeParameter ForeignCallDescriptor descriptor, double value) {
         if (descriptor == ARITHMETIC_SIN) {
             return Math.sin(value);
         }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/BlockState.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/BlockState.java	Fri May 17 15:40:06 2013 +0200
@@ -26,10 +26,9 @@
 
 import java.util.*;
 
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity;
 import com.oracle.graal.nodes.spi.Virtualizable.EscapeState;
 import com.oracle.graal.nodes.virtual.*;
 
@@ -42,10 +41,10 @@
 
     static class ReadCacheEntry {
 
-        public final LocationIdentity identity;
+        public final ResolvedJavaField identity;
         public final ValueNode object;
 
-        public ReadCacheEntry(LocationIdentity identity, ValueNode object) {
+        public ReadCacheEntry(ResolvedJavaField identity, ValueNode object) {
             this.identity = identity;
             this.object = object;
         }
@@ -83,7 +82,7 @@
         readCache = new HashMap<>(other.readCache);
     }
 
-    public void addReadCache(ValueNode object, LocationIdentity identity, ValueNode value) {
+    public void addReadCache(ValueNode object, ResolvedJavaField identity, ValueNode value) {
         ValueNode cacheObject;
         ObjectState obj = getObjectState(object);
         if (obj != null) {
@@ -95,7 +94,7 @@
         readCache.put(new ReadCacheEntry(identity, cacheObject), value);
     }
 
-    public ValueNode getReadCache(ValueNode object, LocationIdentity identity) {
+    public ValueNode getReadCache(ValueNode object, ResolvedJavaField identity) {
         ValueNode cacheObject;
         ObjectState obj = getObjectState(object);
         if (obj != null) {
@@ -115,16 +114,16 @@
         return cacheValue;
     }
 
-    public void killReadCache(LocationIdentity identity) {
-        if (identity == LocationNode.ANY_LOCATION) {
-            readCache.clear();
-        } else {
-            Iterator<Map.Entry<ReadCacheEntry, ValueNode>> iter = readCache.entrySet().iterator();
-            while (iter.hasNext()) {
-                Map.Entry<ReadCacheEntry, ValueNode> entry = iter.next();
-                if (entry.getKey().identity == identity) {
-                    iter.remove();
-                }
+    public void killReadCache() {
+        readCache.clear();
+    }
+
+    public void killReadCache(ResolvedJavaField identity) {
+        Iterator<Map.Entry<ReadCacheEntry, ValueNode>> iter = readCache.entrySet().iterator();
+        while (iter.hasNext()) {
+            Map.Entry<ReadCacheEntry, ValueNode> entry = iter.next();
+            if (entry.getKey().identity == identity) {
+                iter.remove();
             }
         }
     }
@@ -187,7 +186,7 @@
             if (virtual instanceof VirtualInstanceNode) {
                 VirtualInstanceNode instance = (VirtualInstanceNode) virtual;
                 for (int i = 0; i < entries.length; i++) {
-                    readCache.put(new ReadCacheEntry((LocationIdentity) instance.field(i), representation), values.get(pos + i));
+                    readCache.put(new ReadCacheEntry(instance.field(i), representation), values.get(pos + i));
                 }
             }
         } else {
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java	Fri May 17 15:40:06 2013 +0200
@@ -75,7 +75,7 @@
         if (!readElimination) {
             boolean analyzableNodes = false;
             for (Node node : graph.getNodes()) {
-                if (node instanceof VirtualizableAllocation) {
+                if (node instanceof VirtualizableRoot) {
                     analyzableNodes = true;
                     break;
                 }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Fri May 17 15:40:06 2013 +0200
@@ -59,9 +59,6 @@
     public static final DebugMetric METRIC_MATERIALIZATIONS_LOOP_END = Debug.metric("MaterializationsLoopEnd");
     public static final DebugMetric METRIC_ALLOCATION_REMOVED = Debug.metric("AllocationsRemoved");
 
-    public static final DebugMetric METRIC_STOREFIELD_RECORDED = Debug.metric("StoreFieldRecorded");
-    public static final DebugMetric METRIC_LOADFIELD_ELIMINATED = Debug.metric("LoadFieldEliminated");
-    public static final DebugMetric METRIC_LOADFIELD_NOT_ELIMINATED = Debug.metric("LoadFieldNotEliminated");
     public static final DebugMetric METRIC_MEMORYCHECKOINT = Debug.metric("MemoryCheckpoint");
 
     private final NodeBitMap usages;
@@ -148,44 +145,24 @@
         FixedWithNextNode lastFixedNode = null;
         for (Node node : nodeList) {
             boolean deleted;
-            if (usages.isMarked(node) || node instanceof VirtualizableAllocation) {
+            boolean isMarked = usages.isMarked(node);
+            if (isMarked || node instanceof VirtualizableRoot) {
                 trace("[[%s]] ", node);
-                deleted = processNode((ValueNode) node, lastFixedNode == null ? null : lastFixedNode.next(), state, effects);
+                FixedNode nextFixedNode = lastFixedNode == null ? null : lastFixedNode.next();
+                deleted = processNode((ValueNode) node, nextFixedNode, state, effects, isMarked);
             } else {
                 trace("%s ", node);
                 deleted = false;
             }
             if (GraalOptions.OptEarlyReadElimination) {
-                if (!deleted) {
-                    if (node instanceof StoreFieldNode) {
-                        METRIC_STOREFIELD_RECORDED.increment();
-                        StoreFieldNode store = (StoreFieldNode) node;
-                        ValueNode cachedValue = state.getReadCache(store.object(), (LocationIdentity) store.field());
-                        state.killReadCache((LocationIdentity) store.field());
-
-                        if (cachedValue == store.value()) {
-                            effects.deleteFixedNode(store);
-                            changed = true;
-                        } else {
-                            state.addReadCache(store.object(), (LocationIdentity) store.field(), store.value());
-                        }
-                    } else if (node instanceof LoadFieldNode) {
-                        LoadFieldNode load = (LoadFieldNode) node;
-                        ValueNode cachedValue = state.getReadCache(load.object(), (LocationIdentity) load.field());
-                        if (cachedValue != null) {
-                            METRIC_LOADFIELD_ELIMINATED.increment();
-                            effects.replaceAtUsages(load, cachedValue);
-                            state.addScalarAlias(load, cachedValue);
-                            changed = true;
-                        } else {
-                            METRIC_LOADFIELD_NOT_ELIMINATED.increment();
-                            state.addReadCache(load.object(), (LocationIdentity) load.field(), load);
-                        }
-                    } else if (node instanceof MemoryCheckpoint) {
-                        METRIC_MEMORYCHECKOINT.increment();
-                        MemoryCheckpoint checkpoint = (MemoryCheckpoint) node;
-                        for (LocationIdentity identity : checkpoint.getLocationIdentities()) {
-                            state.killReadCache(identity);
+                if (!deleted && node instanceof MemoryCheckpoint) {
+                    METRIC_MEMORYCHECKOINT.increment();
+                    MemoryCheckpoint checkpoint = (MemoryCheckpoint) node;
+                    for (LocationIdentity identity : checkpoint.getLocationIdentities()) {
+                        if (identity instanceof ResolvedJavaField) {
+                            state.killReadCache((ResolvedJavaField) identity);
+                        } else if (identity == LocationNode.ANY_LOCATION) {
+                            state.killReadCache();
                         }
                     }
                 }
@@ -198,7 +175,7 @@
         return state;
     }
 
-    private boolean processNode(final ValueNode node, FixedNode insertBefore, final BlockState state, final GraphEffectList effects) {
+    private boolean processNode(final ValueNode node, FixedNode insertBefore, final BlockState state, final GraphEffectList effects, boolean isMarked) {
         tool.reset(state, node, insertBefore);
         if (node instanceof Virtualizable) {
             ((Virtualizable) node).virtualize(tool);
@@ -209,89 +186,91 @@
             }
             return true;
         }
-        if (node instanceof StateSplit) {
-            StateSplit split = (StateSplit) node;
-            FrameState stateAfter = split.stateAfter();
-            if (stateAfter != null) {
-                if (stateAfter.usages().count() > 1) {
-                    stateAfter = (FrameState) stateAfter.copyWithInputs();
-                    split.setStateAfter(stateAfter);
-                }
-                final HashSet<ObjectState> virtual = new HashSet<>();
-                stateAfter.applyToNonVirtual(new NodeClosure<ValueNode>() {
+        if (isMarked) {
+            if (node instanceof StateSplit) {
+                StateSplit split = (StateSplit) node;
+                FrameState stateAfter = split.stateAfter();
+                if (stateAfter != null) {
+                    if (stateAfter.usages().count() > 1) {
+                        stateAfter = (FrameState) stateAfter.copyWithInputs();
+                        split.setStateAfter(stateAfter);
+                    }
+                    final HashSet<ObjectState> virtual = new HashSet<>();
+                    stateAfter.applyToNonVirtual(new NodeClosure<ValueNode>() {
 
-                    @Override
-                    public void apply(Node usage, ValueNode value) {
-                        ObjectState valueObj = state.getObjectState(value);
-                        if (valueObj != null) {
-                            virtual.add(valueObj);
-                            effects.replaceFirstInput(usage, value, valueObj.virtual);
-                        } else if (value instanceof VirtualObjectNode) {
-                            ObjectState virtualObj = null;
-                            for (ObjectState obj : state.getStates()) {
-                                if (value == obj.virtual) {
-                                    virtualObj = obj;
-                                    break;
+                        @Override
+                        public void apply(Node usage, ValueNode value) {
+                            ObjectState valueObj = state.getObjectState(value);
+                            if (valueObj != null) {
+                                virtual.add(valueObj);
+                                effects.replaceFirstInput(usage, value, valueObj.virtual);
+                            } else if (value instanceof VirtualObjectNode) {
+                                ObjectState virtualObj = null;
+                                for (ObjectState obj : state.getStates()) {
+                                    if (value == obj.virtual) {
+                                        virtualObj = obj;
+                                        break;
+                                    }
+                                }
+                                if (virtualObj != null) {
+                                    virtual.add(virtualObj);
                                 }
                             }
-                            if (virtualObj != null) {
-                                virtual.add(virtualObj);
-                            }
+                        }
+                    });
+                    for (ObjectState obj : state.getStates()) {
+                        if (obj.isVirtual() && obj.hasLocks()) {
+                            virtual.add(obj);
                         }
                     }
-                });
-                for (ObjectState obj : state.getStates()) {
-                    if (obj.isVirtual() && obj.hasLocks()) {
-                        virtual.add(obj);
-                    }
-                }
 
-                ArrayDeque<ObjectState> queue = new ArrayDeque<>(virtual);
-                while (!queue.isEmpty()) {
-                    ObjectState obj = queue.removeLast();
-                    if (obj.isVirtual()) {
-                        for (ValueNode field : obj.getEntries()) {
-                            ObjectState fieldObj = state.getObjectState(field);
-                            if (fieldObj != null) {
-                                if (fieldObj.isVirtual() && !virtual.contains(fieldObj)) {
-                                    virtual.add(fieldObj);
-                                    queue.addLast(fieldObj);
+                    ArrayDeque<ObjectState> queue = new ArrayDeque<>(virtual);
+                    while (!queue.isEmpty()) {
+                        ObjectState obj = queue.removeLast();
+                        if (obj.isVirtual()) {
+                            for (ValueNode field : obj.getEntries()) {
+                                ObjectState fieldObj = state.getObjectState(field);
+                                if (fieldObj != null) {
+                                    if (fieldObj.isVirtual() && !virtual.contains(fieldObj)) {
+                                        virtual.add(fieldObj);
+                                        queue.addLast(fieldObj);
+                                    }
                                 }
                             }
                         }
                     }
-                }
-                for (ObjectState obj : virtual) {
-                    EscapeObjectState v;
-                    if (obj.isVirtual()) {
-                        ValueNode[] fieldState = obj.getEntries().clone();
-                        for (int i = 0; i < fieldState.length; i++) {
-                            ObjectState valueObj = state.getObjectState(fieldState[i]);
-                            if (valueObj != null) {
-                                if (valueObj.isVirtual()) {
-                                    fieldState[i] = valueObj.virtual;
-                                } else {
-                                    fieldState[i] = valueObj.getMaterializedValue();
+                    for (ObjectState obj : virtual) {
+                        EscapeObjectState v;
+                        if (obj.isVirtual()) {
+                            ValueNode[] fieldState = obj.getEntries().clone();
+                            for (int i = 0; i < fieldState.length; i++) {
+                                ObjectState valueObj = state.getObjectState(fieldState[i]);
+                                if (valueObj != null) {
+                                    if (valueObj.isVirtual()) {
+                                        fieldState[i] = valueObj.virtual;
+                                    } else {
+                                        fieldState[i] = valueObj.getMaterializedValue();
+                                    }
                                 }
                             }
+                            v = new VirtualObjectState(obj.virtual, fieldState);
+                        } else {
+                            v = new MaterializedObjectState(obj.virtual, obj.getMaterializedValue());
                         }
-                        v = new VirtualObjectState(obj.virtual, fieldState);
-                    } else {
-                        v = new MaterializedObjectState(obj.virtual, obj.getMaterializedValue());
+                        effects.addVirtualMapping(stateAfter, v);
                     }
-                    effects.addVirtualMapping(stateAfter, v);
                 }
             }
-        }
-        for (ValueNode input : node.inputs().filter(ValueNode.class)) {
-            ObjectState obj = state.getObjectState(input);
-            if (obj != null) {
-                if (obj.isVirtual() && node instanceof MethodCallTargetNode) {
-                    Invoke invoke = ((MethodCallTargetNode) node).invoke();
-                    hints.put(invoke, 5d);
+            for (ValueNode input : node.inputs().filter(ValueNode.class)) {
+                ObjectState obj = state.getObjectState(input);
+                if (obj != null) {
+                    if (obj.isVirtual() && node instanceof MethodCallTargetNode) {
+                        Invoke invoke = ((MethodCallTargetNode) node).invoke();
+                        hints.put(invoke, 5d);
+                    }
+                    trace("replacing input %s at %s: %s", input, node, obj);
+                    replaceWithMaterialized(input, node, insertBefore, state, obj, effects, METRIC_MATERIALIZATIONS_UNHANDLED);
                 }
-                trace("replacing input %s at %s: %s", input, node, obj);
-                replaceWithMaterialized(input, node, insertBefore, state, obj, effects, METRIC_MATERIALIZATIONS_UNHANDLED);
             }
         }
         return false;
@@ -703,7 +682,7 @@
             }
         }
 
-        private void mergeReadCachePhi(PhiNode phi, LocationIdentity identity, List<BlockState> states) {
+        private void mergeReadCachePhi(PhiNode phi, ResolvedJavaField identity, List<BlockState> states) {
             ValueNode[] values = new ValueNode[phi.valueCount()];
             for (int i = 0; i < phi.valueCount(); i++) {
                 ValueNode value = states.get(i).getReadCache(phi.valueAt(i), identity);
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java	Fri May 17 15:40:06 2013 +0200
@@ -181,4 +181,26 @@
             }
         }
     }
+
+    @Override
+    public void addReadCache(ValueNode object, ResolvedJavaField identity, ValueNode value) {
+        if (GraalOptions.OptEarlyReadElimination) {
+            state.addReadCache(object, identity, value);
+        }
+    }
+
+    @Override
+    public ValueNode getReadCache(ValueNode object, ResolvedJavaField identity) {
+        if (GraalOptions.OptEarlyReadElimination) {
+            return state.getReadCache(object, identity);
+        }
+        return null;
+    }
+
+    @Override
+    public void killReadCache(ResolvedJavaField identity) {
+        if (GraalOptions.OptEarlyReadElimination) {
+            state.killReadCache(identity);
+        }
+    }
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/GraphPrintVisitor.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/GraphPrintVisitor.java	Fri May 17 15:40:06 2013 +0200
@@ -24,7 +24,6 @@
 
 import java.io.*;
 import java.lang.annotation.*;
-import java.lang.reflect.*;
 import java.net.*;
 import java.util.*;
 
@@ -35,6 +34,10 @@
 
 import org.w3c.dom.*;
 
+import com.oracle.truffle.api.nodes.NodeUtil.NodeClass;
+import com.oracle.truffle.api.nodes.NodeUtil.NodeField;
+import com.oracle.truffle.api.nodes.NodeUtil.NodeFieldKind;
+
 /**
  * Utility class for creating output for the ideal graph visualizer.
  */
@@ -212,7 +215,7 @@
             setNodeProperty(node, "nodeType", (Node.class.isAssignableFrom(node.getClass()) ? Node.class.getSimpleName() : "other"));
             setNodeProperty(node, "nodeClass", node.getClass().getSimpleName());
             copyDebugProperties(node); // TODO: may overwrite property "name"? (currently allowed)
-            readNodeProperties(node);
+            readNodeProperties((Node) node);
         }
     }
 
@@ -254,23 +257,14 @@
         }
     }
 
-    private void readNodeProperties(Object node) {
-        Field[] fields = NodeUtil.getAllFields(node.getClass());
-        for (Field field : fields) {
-            if (Modifier.isStatic(field.getModifiers())) {
-                continue;
-            }
-            if (Node.class.isAssignableFrom(field.getType()) || (field.getType().getComponentType() != null && Node.class.isAssignableFrom(field.getType()))) {
-                continue;
-            }
-            String key = field.getName();
-            if (field.getAnnotation(HiddenField.class) == null && getPropertyElement(node, key) == null) {
-                try {
-                    field.setAccessible(true);
-                    Object value = field.get(node);
+    private void readNodeProperties(Node node) {
+        NodeField[] fields = NodeClass.get(node.getClass()).getFields();
+        for (NodeField field : fields) {
+            if (field.getKind() == NodeFieldKind.DATA) {
+                String key = field.getName();
+                if (getPropertyElement(node, key) == null) {
+                    Object value = field.loadValue(node);
                     setNodeProperty(node, key, value);
-                } catch (IllegalArgumentException | IllegalAccessException e) {
-                    assert false : e;
                 }
             }
         }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java	Fri May 17 15:38:22 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java	Fri May 17 15:40:06 2013 +0200
@@ -37,104 +37,181 @@
  */
 public class NodeUtil {
 
-    public static final class NodeClass {
+    /**
+     * Interface that allows the customization of field offsets used for {@link Unsafe} field
+     * accesses.
+     */
+    public interface FieldOffsetProvider {
+
+        long objectFieldOffset(Field field);
+    }
+
+    private static final FieldOffsetProvider unsafeFieldOffsetProvider = new FieldOffsetProvider() {
+
+        @Override
+        public long objectFieldOffset(Field field) {
+            return unsafe.objectFieldOffset(field);
+        }
+    };
+
+    public static enum NodeFieldKind {
+        /** The single {@link Node#getParent() parent} field. */
+        PARENT,
+        /** A field annotated with {@link Child}. */
+        CHILD,
+        /** A field annotated with {@link Children}. */
+        CHILDREN,
+        /** A normal non-child data field of the node. */
+        DATA
+    }
+
+    /**
+     * Information about a field in a {@link Node} class.
+     */
+    public static final class NodeField {
+
+        private final NodeFieldKind kind;
+        private final Class<?> type;
+        private final String name;
+        private long offset;
+
+        protected NodeField(NodeFieldKind kind, Class<?> type, String name, long offset) {
+            this.kind = kind;
+            this.type = type;
+            this.name = name;
+            this.offset = offset;
+        }
 
-        private final Class parentClass;
-        private final long[] nodeFieldOffsets;
-        private final Class[] nodeFieldClasses;
-        private final long[] nodeArrayFieldOffsets;
-        private final Class[] nodeArrayFieldClasses;
-        private final long parentOffset;
-        private final long[] nodeDataFieldOffsets;
-        private final Class<?>[] nodeDataFieldClasses;
+        public NodeFieldKind getKind() {
+            return kind;
+        }
+
+        public Class<?> getType() {
+            return type;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public long getOffset() {
+            return offset;
+        }
+
+        public Object loadValue(Node node) {
+            if (type == boolean.class) {
+                return unsafe.getBoolean(node, offset);
+            } else if (type == byte.class) {
+                return unsafe.getByte(node, offset);
+            } else if (type == short.class) {
+                return unsafe.getShort(node, offset);
+            } else if (type == char.class) {
+                return unsafe.getChar(node, offset);
+            } else if (type == int.class) {
+                return unsafe.getInt(node, offset);
+            } else if (type == long.class) {
+                return unsafe.getLong(node, offset);
+            } else if (type == float.class) {
+                return unsafe.getFloat(node, offset);
+            } else if (type == double.class) {
+                return unsafe.getDouble(node, offset);
+            } else {
+                return unsafe.getObject(node, offset);
+            }
+        }
+    }
+
+    /**
+     * Information about a {@link Node} class. A single instance of this class is allocated for
+     * every subclass of {@link Node} that is used.
+     */
+    public static final class NodeClass {
 
         private static final Map<Class<?>, NodeClass> nodeClasses = new IdentityHashMap<>();
 
-        public static NodeClass get(Class<?> clazz) {
+        // The comprehensive list of all fields.
+        private final NodeField[] fields;
+        // Separate arrays for the frequently accessed field offsets.
+        private final long parentOffset;
+        private final long[] childOffsets;
+        private final long[] childrenOffsets;
+
+        public static NodeClass get(Class<? extends Node> clazz) {
             NodeClass nodeClass = nodeClasses.get(clazz);
             if (nodeClass == null) {
-                nodeClass = new NodeClass(clazz);
+                nodeClass = new NodeClass(clazz, unsafeFieldOffsetProvider);
                 nodeClasses.put(clazz, nodeClass);
             }
             return nodeClass;
         }
 
-        private NodeClass(Class<?> clazz) {
-            // scan object fields
-            Class<?> parentClassTmp = null;
-            List<Long> nodeFieldOffsetsList = new ArrayList<>();
-            List<Class<?>> nodeFieldClassesList = new ArrayList<>();
-            List<Long> nodeArrayFieldOffsetsList = new ArrayList<>();
-            List<Class<?>> nodeArrayFieldClassesList = new ArrayList<>();
-            List<Long> nodeDataFieldOffsetList = new ArrayList<>();
-            List<Class<?>> nodeDataFieldClassList = new ArrayList<>();
-            Field[] fields = getAllFields(clazz);
-            long parentOffsetTemp = -1;
-            for (Field field : fields) {
+        public NodeClass(Class<? extends Node> clazz, FieldOffsetProvider fieldOffsetProvider) {
+            List<NodeField> fieldsList = new ArrayList<>();
+            List<Long> parentOffsetsList = new ArrayList<>();
+            List<Long> childOffsetsList = new ArrayList<>();
+            List<Long> childrenOffsetsList = new ArrayList<>();
+
+            for (Field field : getAllFields(clazz)) {
                 if (Modifier.isStatic(field.getModifiers()) || field.isSynthetic()) {
                     continue;
                 }
 
-                // Node fields
-                if (Node.class.isAssignableFrom(field.getType()) && field.getName().equals("parent")) {
-                    parentOffsetTemp = unsafe.objectFieldOffset(field);
-                    parentClassTmp = field.getType();
+                NodeFieldKind kind;
+                if (Node.class.isAssignableFrom(field.getType()) && field.getName().equals("parent") && field.getDeclaringClass() == Node.class) {
+                    kind = NodeFieldKind.PARENT;
+                    parentOffsetsList.add(fieldOffsetProvider.objectFieldOffset(field));
                 } else if (Node.class.isAssignableFrom(field.getType()) && field.getAnnotation(Child.class) != null) {
-                    nodeFieldOffsetsList.add(unsafe.objectFieldOffset(field));
-                    nodeFieldClassesList.add(field.getType());
-                } else if (field.getType().getComponentType() != null && Node.class.isAssignableFrom(field.getType().getComponentType()) && field.getAnnotation(Children.class) != null) {
-                    nodeArrayFieldOffsetsList.add(unsafe.objectFieldOffset(field));
-                    nodeArrayFieldClassesList.add(field.getType());
+                    kind = NodeFieldKind.CHILD;
+                    childOffsetsList.add(fieldOffsetProvider.objectFieldOffset(field));
+                } else if (field.getType().isArray() && Node.class.isAssignableFrom(field.getType().getComponentType()) && field.getAnnotation(Children.class) != null) {
+                    kind = NodeFieldKind.CHILDREN;
+                    childrenOffsetsList.add(fieldOffsetProvider.objectFieldOffset(field));
                 } else {
-                    nodeDataFieldOffsetList.add(unsafe.objectFieldOffset(field));
-                    nodeDataFieldClassList.add(field.getType());
+                    kind = NodeFieldKind.DATA;
                 }
+                fieldsList.add(new NodeField(kind, field.getType(), field.getName(), fieldOffsetProvider.objectFieldOffset(field)));
             }
-            this.parentClass = parentClassTmp;
-            this.nodeFieldOffsets = toLongArray(nodeFieldOffsetsList);
-            this.nodeFieldClasses = nodeFieldClassesList.toArray(new Class[nodeFieldClassesList.size()]);
-            this.nodeArrayFieldOffsets = toLongArray(nodeArrayFieldOffsetsList);
-            this.nodeArrayFieldClasses = nodeArrayFieldClassesList.toArray(new Class[nodeArrayFieldClassesList.size()]);
-            this.nodeDataFieldOffsets = toLongArray(nodeDataFieldOffsetList);
-            this.nodeDataFieldClasses = nodeDataFieldClassList.toArray(new Class<?>[nodeDataFieldClassList.size()]);
+            this.fields = fieldsList.toArray(new NodeField[fieldsList.size()]);
+            assert parentOffsetsList.size() == 1 : "must have exactly one parent field";
+            this.parentOffset = parentOffsetsList.get(0);
+            this.childOffsets = toLongArray(childOffsetsList);
+            this.childrenOffsets = toLongArray(childrenOffsetsList);
+        }
 
-            this.parentOffset = parentOffsetTemp;
+        public NodeField[] getFields() {
+            return fields;
         }
 
         public long getParentOffset() {
             return parentOffset;
         }
 
-        public long[] getNodeFieldOffsets() {
-            return nodeFieldOffsets;
+        public long[] getChildOffsets() {
+            return childOffsets;
         }
 
-        public long[] getNodeArrayFieldOffsets() {
-            return nodeArrayFieldOffsets;
+        public long[] getChildrenOffsets() {
+            return childrenOffsets;
         }
     }
 
-    public static class NodeIterator implements Iterator<Node> {
+    static class NodeIterator implements Iterator<Node> {
 
         private final Node node;
         private final NodeClass nodeClass;
         private final int childrenCount;
         private int index;
 
-        public NodeIterator(Node node) {
-            this(node, 0);
-        }
-
-        public NodeIterator(Node node, int index) {
+        protected NodeIterator(Node node) {
             this.node = node;
-            this.index = index;
+            this.index = 0;
             this.nodeClass = NodeClass.get(node.getClass());
             this.childrenCount = childrenCount();
         }
 
         private int childrenCount() {
-            int nodeCount = nodeClass.nodeFieldOffsets.length;
-            for (long fieldOffset : nodeClass.nodeArrayFieldOffsets) {
+            int nodeCount = nodeClass.childOffsets.length;
+            for (long fieldOffset : nodeClass.childrenOffsets) {
                 Node[] children = ((Node[]) unsafe.getObject(node, fieldOffset));
                 if (children != null) {
                     nodeCount += children.length;
@@ -144,11 +221,11 @@
         }
 
         private Node nodeAt(int idx) {
-            int nodeCount = nodeClass.nodeFieldOffsets.length;
+            int nodeCount = nodeClass.childOffsets.length;
             if (idx < nodeCount) {
-                return (Node) unsafe.getObject(node, nodeClass.nodeFieldOffsets[idx]);
+                return (Node) unsafe.getObject(node, nodeClass.childOffsets[idx]);
             } else {
-                for (long fieldOffset : nodeClass.nodeArrayFieldOffsets) {
+                for (long fieldOffset : nodeClass.childrenOffsets) {
                     Node[] nodeArray = (Node[]) unsafe.getObject(node, fieldOffset);
                     if (idx < nodeCount + nodeArray.length) {
                         return nodeArray[idx - nodeCount];
@@ -220,7 +297,7 @@
 
         unsafe.putObject(clone, nodeClass.parentOffset, null);
 
-        for (long fieldOffset : nodeClass.nodeFieldOffsets) {
+        for (long fieldOffset : nodeClass.childOffsets) {
             Node child = (Node) unsafe.getObject(orig, fieldOffset);
             if (child != null) {
                 Node clonedChild = cloneNode(child);
@@ -232,7 +309,7 @@
                 unsafe.putObject(clone, fieldOffset, clonedChild);
             }
         }
-        for (long fieldOffset : nodeClass.nodeArrayFieldOffsets) {
+        for (long fieldOffset : nodeClass.childrenOffsets) {
             Node[] children = (Node[]) unsafe.getObject(orig, fieldOffset);
             if (children != null) {
                 Node[] clonedChildren = children.clone();
@@ -256,13 +333,13 @@
         List<Node> nodes = new ArrayList<>();
         NodeClass nodeClass = NodeClass.get(node.getClass());
 
-        for (long fieldOffset : nodeClass.nodeFieldOffsets) {
+        for (long fieldOffset : nodeClass.childOffsets) {
             Object child = unsafe.getObject(node, fieldOffset);
             if (child != null) {
                 nodes.add((Node) child);
             }
         }
-        for (long fieldOffset : nodeClass.nodeArrayFieldOffsets) {
+        for (long fieldOffset : nodeClass.childrenOffsets) {
             Node[] children = (Node[]) unsafe.getObject(node, fieldOffset);
             if (children != null) {
                 nodes.addAll(Arrays.asList(children));
@@ -275,12 +352,12 @@
     public static void replaceChild(Node parent, Node oldChild, Node newChild) {
         NodeClass nodeClass = NodeClass.get(parent.getClass());
 
-        for (long fieldOffset : nodeClass.nodeFieldOffsets) {
+        for (long fieldOffset : nodeClass.childOffsets) {
             if (unsafe.getObject(parent, fieldOffset) == oldChild) {
                 unsafe.putObject(parent, fieldOffset, newChild);
             }
         }
-        for (long fieldOffset : nodeClass.nodeArrayFieldOffsets) {
+        for (long fieldOffset : nodeClass.childrenOffsets) {
             Node[] array = (Node[]) unsafe.getObject(parent, fieldOffset);
             if (array != null) {
                 for (int i = 0; i < array.length; i++) {
@@ -293,49 +370,8 @@
         }
     }
 
-    public static long[] getNodeDataFieldOffsets(Class<?> nodeClass) {
-        NodeClass clazz = NodeClass.get(nodeClass);
-        return Arrays.copyOf(clazz.nodeDataFieldOffsets, clazz.nodeDataFieldClasses.length);
-    }
-
-    public static Class[] getNodeDataFieldClasses(Class<?> nodeClass) {
-        NodeClass clazz = NodeClass.get(nodeClass);
-        return Arrays.copyOf(clazz.nodeDataFieldClasses, clazz.nodeDataFieldClasses.length);
-    }
-
-    public static long getNodeParentOffset(Class<?> nodeClass) {
-        NodeClass clazz = NodeClass.get(nodeClass);
-        return clazz.parentOffset;
-    }
-
-    /** Returns the number of Node field declarations in the class hierarchy. */
-    public static long[] getNodeFieldOffsets(Class<?> nodeClass) {
-        NodeClass clazz = NodeClass.get(nodeClass);
-        return Arrays.copyOf(clazz.nodeFieldOffsets, clazz.nodeFieldOffsets.length);
-    }
-
-    /** Returns the number of Node[] declaration in the class hierarchy. */
-    public static long[] getNodeFieldArrayOffsets(Class<?> nodeClass) {
-        NodeClass clazz = NodeClass.get(nodeClass);
-        return Arrays.copyOf(clazz.nodeArrayFieldOffsets, clazz.nodeArrayFieldOffsets.length);
-    }
-
-    public static Class[] getNodeFieldArrayClasses(Class<?> nodeClass) {
-        NodeClass clazz = NodeClass.get(nodeClass);
-        return Arrays.copyOf(clazz.nodeArrayFieldClasses, clazz.nodeArrayFieldClasses.length);
-    }
-
-    public static Class getNodeParentClass(Class<?> nodeClass) {
-        return NodeClass.get(nodeClass).parentClass;
-    }
-
-    public static Class[] getNodeFieldClasses(Class<?> nodeClass) {
-        NodeClass clazz = NodeClass.get(nodeClass);
-        return Arrays.copyOf(clazz.nodeFieldClasses, clazz.nodeFieldClasses.length);
-    }
-
     /** Returns all declared fields in the class hierarchy. */
-    public static Field[] getAllFields(Class<? extends Object> clazz) {
+    private static Field[] getAllFields(Class<? extends Object> clazz) {
         Field[] declaredFields = clazz.getDeclaredFields();
         if (clazz.getSuperclass() != null) {
             return concat(getAllFields(clazz.getSuperclass()), declaredFields);
@@ -472,44 +508,17 @@
         return nodeList;
     }
 
-    public static String printTreeToString(Node node) {
-        return printTreeToString(node, false);
-    }
-
-    private static String printTreeToString(Node node, boolean compact) {
-        ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
-        if (compact) {
-            printCompactTree(new PrintStream(byteOut), node);
-        } else {
-            printTree(new PrintStream(byteOut), node);
-        }
-        try {
-            byteOut.flush();
-        } catch (IOException e) {
-        }
-        return new String(byteOut.toByteArray());
+    public static String printCompactTreeToString(Node node) {
+        StringWriter out = new StringWriter();
+        printCompactTree(new PrintWriter(out), null, node, 1);
+        return out.toString();
     }
 
-    /**
-     * Prints a human readable form of a {@link Node} AST to the given {@link PrintStream}. This
-     * print method does not check for cycles in the node structure.
-     * 
-     * @param p the {@link PrintStream} to print to.
-     * @param node the root node to write
-     */
-    public static void printTree(PrintStream p, Node node) {
-        printTree(p, node, new NodeTreeResolver());
+    public static void printCompactTree(OutputStream out, Node node) {
+        printCompactTree(new PrintWriter(out), null, node, 1);
     }
 
-    public static String printCompactTreeToString(Node node) {
-        return printTreeToString(node, true);
-    }
-
-    public static void printCompactTree(PrintStream p, Node node) {
-        printCompactTree(p, null, node, 1);
-    }
-
-    private static void printCompactTree(PrintStream p, Node parent, Node node, int level) {
+    private static void printCompactTree(PrintWriter p, Node parent, Node node, int level) {
         if (node == null) {
             return;
         }
@@ -519,32 +528,23 @@
         if (parent == null) {
             p.println(node.getClass().getSimpleName());
         } else {
-            String fieldName = null;
-            Field[] fields = NodeUtil.getAllFields(parent.getClass());
-            try {
-                for (Field field : fields) {
-                    field.setAccessible(true);
-                    Object value = field.get(parent);
-                    if (value == node) {
-                        fieldName = field.getName();
-                        break;
-                    } else if (value instanceof Node[]) {
-                        int index = 0;
-                        for (Node arrayNode : (Node[]) value) {
-                            if (arrayNode == node) {
-                                fieldName = field.getName() + "[" + index + "]";
-                                break;
-                            }
-                            index++;
+            String fieldName = "unknownField";
+            NodeField[] fields = NodeClass.get(parent.getClass()).fields;
+            for (NodeField field : fields) {
+                Object value = field.loadValue(parent);
+                if (value == node) {
+                    fieldName = field.getName();
+                    break;
+                } else if (value instanceof Node[]) {
+                    int index = 0;
+                    for (Node arrayNode : (Node[]) value) {
+                        if (arrayNode == node) {
+                            fieldName = field.getName() + "[" + index + "]";
+                            break;
                         }
+                        index++;
                     }
                 }
-            } catch (Exception e) {
-                e.printStackTrace();
-            }
-
-            if (fieldName == null) {
-                fieldName = "unknownField";
             }
             p.print(fieldName);
             p.print(" = ");
@@ -554,23 +554,33 @@
         for (Node child : node.getChildren()) {
             printCompactTree(p, node, child, level + 1);
         }
+        p.flush();
     }
 
     /**
-     * Prints a human readable form of a tree to the given {@link PrintStream}. The
-     * {@link TreeResolver} interface needs to be implemented to specify how the method can read the
-     * tree from plain a object.
+     * Prints a human readable form of a {@link Node} AST to the given {@link PrintStream}. This
+     * print method does not check for cycles in the node structure.
      * 
-     * @param p the {@link PrintStream} to print to.
-     * @param o the root object to be printed.
-     * @param resolver an implementation of a tree resolver
+     * @param out the stream to print to.
+     * @param node the root node to write
      */
-    public static void printTree(PrintStream p, Object o, TreeResolver resolver) {
-        printTree(p, o, resolver, 1);
-        p.println();
+    public static void printTree(OutputStream out, Node node) {
+        printTree(new PrintWriter(out), node);
     }
 
-    private static void printTree(PrintStream p, Object node, TreeResolver resolver, int level) {
+    public static String printTreeToString(Node node) {
+        StringWriter out = new StringWriter();
+        printTree(new PrintWriter(out), node);
+        return out.toString();
+    }
+
+    public static void printTree(PrintWriter p, Node node) {
+        printTree(p, node, 1);
+        p.println();
+        p.flush();
+    }
+
+    private static void printTree(PrintWriter p, Node node, int level) {
         if (node == null) {
             p.print("null");
             return;
@@ -578,204 +588,56 @@
 
         p.print(node.getClass().getSimpleName());
 
-        Field[] fields = NodeUtil.getAllFields(node.getClass());
+        ArrayList<NodeField> childFields = new ArrayList<>();
+        String sep = "";
         p.print("(");
-
-        ArrayList<Field> childFields = new ArrayList<>();
+        for (NodeField field : NodeClass.get(node.getClass()).fields) {
+            if (field.getKind() == NodeFieldKind.CHILD || field.getKind() == NodeFieldKind.CHILDREN) {
+                childFields.add(field);
+            } else if (field.getKind() == NodeFieldKind.DATA) {
+                p.print(sep);
+                sep = ", ";
 
-        boolean first = true;
-        for (int i = 0; i < fields.length; i++) {
-            Field field = fields[i];
-            if (Modifier.isStatic(field.getModifiers()) || resolver.isFiltered(field)) {
-                continue;
-            }
-            if (resolver.isChildObject(field) || resolver.isChildArrayObject(field)) {
-                childFields.add(field);
+                p.print(field.getName());
+                p.print(" = ");
+                p.print(field.loadValue(node));
             }
-            if (!resolver.isDataField(field)) {
-                continue;
-            }
-            if (!first) {
-                p.print(", ");
-            } else {
-                first = false;
-            }
-
-            Object value = getObjectValue(node, field.getType(), unsafe.objectFieldOffset(field));
-
-            p.print(field.getName());
-            p.print(" = ");
-            p.print(resolver.toString(value));
         }
         p.print(")");
 
         if (childFields.size() != 0) {
             p.print(" {");
-        }
-
-        // I refetch the fields to get declaration order.
-        for (int i = 0; i < childFields.size(); i++) {
-            Field field = childFields.get(i);
-            Class<?> fieldClass = field.getType();
-            String name = field.getName();
-
-            long offset = unsafe.objectFieldOffset(field);
-
-            Object value = getObjectValue(node, fieldClass, offset);
+            for (NodeField field : childFields) {
+                printNewLine(p, level);
+                p.print(field.getName());
 
-            printNewLine(p, level);
-            p.print(name);
-            if (value == null) {
-                p.print(" = null ");
-            } else if (resolver.isChildObject(field)) {
-                p.print(" = ");
-                printTree(p, value, resolver, level + 1);
-            } else if (resolver.isChildArrayObject(field)) {
-                Object[] objectArray = resolver.convertToArray(field, value);
-                if (objectArray.length == 0) {
-                    p.print(" = []");
-                } else {
+                Object value = field.loadValue(node);
+                if (value == null) {
+                    p.print(" = null ");
+                } else if (field.getKind() == NodeFieldKind.CHILD) {
+                    p.print(" = ");
+                    printTree(p, (Node) value, level + 1);
+                } else if (field.getKind() == NodeFieldKind.CHILDREN) {
+                    Node[] children = (Node[]) value;
                     p.print(" = [");
-                    for (int j = 0; j < objectArray.length; j++) {
-                        printTree(p, objectArray[j], resolver, level + 1);
-                        if (j < objectArray.length - 1) {
-                            p.print(", ");
-                        }
+                    sep = "";
+                    for (Node child : children) {
+                        p.print(sep);
+                        sep = ", ";
+                        printTree(p, child, level + 1);
                     }
                     p.print("]");
                 }
-            } else {
-                assert false;
             }
-        }
-
-        if (childFields.size() != 0) {
             printNewLine(p, level - 1);
             p.print("}");
         }
     }
 
-    private static Object getObjectValue(Object base, Class<?> fieldClass, long offset) {
-        if (fieldClass == boolean.class) {
-            return unsafe.getBoolean(base, offset);
-        } else if (fieldClass == byte.class) {
-            return unsafe.getByte(base, offset);
-        } else if (fieldClass == short.class) {
-            return unsafe.getShort(base, offset);
-        } else if (fieldClass == char.class) {
-            return unsafe.getChar(base, offset);
-        } else if (fieldClass == int.class) {
-            return unsafe.getInt(base, offset);
-        } else if (fieldClass == long.class) {
-            return unsafe.getLong(base, offset);
-        } else if (fieldClass == float.class) {
-            return unsafe.getFloat(base, offset);
-        } else if (fieldClass == double.class) {
-            return unsafe.getDouble(base, offset);
-        } else {
-            return unsafe.getObject(base, offset);
-        }
-    }
-
-    private static void printNewLine(PrintStream p, int level) {
+    private static void printNewLine(PrintWriter p, int level) {
         p.println();
         for (int i = 0; i < level; i++) {
             p.print("    ");
         }
     }
-
-    private static class NodeTreeResolver implements TreeResolver {
-
-        @Override
-        public boolean isFiltered(Field f) {
-            if (f.getName().equals("parent")) {
-                return true;
-            }
-            return f.isSynthetic();
-        }
-
-        @Override
-        public boolean isDataField(Field f) {
-            return !isChildArrayObject(f) && !isChildObject(f);
-        }
-
-        @Override
-        public boolean isChildObject(Field f) {
-            return Node.class.isAssignableFrom(f.getType()) && f.getAnnotation(Child.class) != null;
-        }
-
-        @Override
-        public boolean isChildArrayObject(Field f) {
-            return f.getType().getComponentType() != null && Node.class.isAssignableFrom(f.getType().getComponentType()) && f.getAnnotation(Children.class) != null;
-        }
-
-        @Override
-        public Object[] convertToArray(Field f, Object data) {
-            return (Object[]) data;
-        }
-
-        @Override
-        public String toString(Object o) {
-            return o == null ? "null" : o.toString();
-        }
-    }
-
-    /**
-     * Specifies how a tree can be built from plain objects.
-     */
-    public interface TreeResolver {
-
-        /**
-         * Returns true if a {@link Field} is filtered from the tree.
-         * 
-         * @param f the field to check
-         */
-        boolean isFiltered(Field f);
-
-        /**
-         * Returns true if a {@link Field} is a field that contains a data value which should not be
-         * traversed recursively.
-         * 
-         * @param f the field to check
-         * @return true if a the given field is a data field else false.
-         */
-        boolean isDataField(Field f);
-
-        /**
-         * Returns true if a {@link Field} is a field that contains an {@link Object} which should
-         * be recursively visited.
-         * 
-         * @param f the field to check
-         * @return true if a the given field is a child field else false.
-         */
-        boolean isChildObject(Field f);
-
-        /**
-         * Returns true if a {@link Field} is a field that contains any kind of list/array structure
-         * which itself holds values that should be recursively visited.
-         * 
-         * @param f the field to check
-         * @return true if a the given field is a child array/list field else false.
-         */
-        boolean isChildArrayObject(Field f);
-
-        /**
-         * Converts an given child array object to array which can be traversed. This is especially
-         * useful to convert any kind of list structure to a traversable array.
-         * 
-         * @param f the field for meta data needed to convert the data {@link Object}.
-         * @param value the actual value of the child array/list object.
-         * @return the converted {@link Object} array.
-         */
-        Object[] convertToArray(Field f, Object value);
-
-        /**
-         * Returns a human readable string for any data field object in the tree.
-         * 
-         * @param o the object to convert to string.
-         * @return the converted string
-         */
-        String toString(Object o);
-    }
-
 }
--- a/src/share/vm/classfile/systemDictionary.hpp	Fri May 17 15:38:22 2013 +0200
+++ b/src/share/vm/classfile/systemDictionary.hpp	Fri May 17 15:40:06 2013 +0200
@@ -188,7 +188,7 @@
   do_klass(HotSpotCompiledCode_klass,             com_oracle_graal_hotspot_HotSpotCompiledCode,                 Opt) \
   do_klass(HotSpotCompiledNmethod_klass,          com_oracle_graal_hotspot_HotSpotCompiledNmethod,              Opt) \
   do_klass(HotSpotCompiledRuntimeStub_klass,      com_oracle_graal_hotspot_HotSpotCompiledRuntimeStub,          Opt) \
-  do_klass(HotSpotRuntimeCallTarget_klass,        com_oracle_graal_hotspot_HotSpotRuntimeCallTarget,            Opt) \
+  do_klass(HotSpotForeignCallLinkage_klass,       com_oracle_graal_hotspot_HotSpotForeignCallLinkage,           Opt) \
   do_klass(HotSpotCodeInfo_klass,                 com_oracle_graal_hotspot_meta_HotSpotCodeInfo,                Opt) \
   do_klass(HotSpotInstalledCode_klass,            com_oracle_graal_hotspot_meta_HotSpotInstalledCode,           Opt) \
   do_klass(HotSpotNmethod_klass,                  com_oracle_graal_hotspot_meta_HotSpotNmethod,                 Opt) \
--- a/src/share/vm/classfile/vmSymbols.hpp	Fri May 17 15:38:22 2013 +0200
+++ b/src/share/vm/classfile/vmSymbols.hpp	Fri May 17 15:40:06 2013 +0200
@@ -299,7 +299,7 @@
   template(com_oracle_graal_hotspot_HotSpotCompiledCode,             "com/oracle/graal/hotspot/HotSpotCompiledCode")                  \
   template(com_oracle_graal_hotspot_HotSpotCompiledNmethod,          "com/oracle/graal/hotspot/HotSpotCompiledNmethod")               \
   template(com_oracle_graal_hotspot_HotSpotCompiledRuntimeStub,      "com/oracle/graal/hotspot/HotSpotCompiledRuntimeStub")           \
-  template(com_oracle_graal_hotspot_HotSpotRuntimeCallTarget,        "com/oracle/graal/hotspot/HotSpotRuntimeCallTarget")             \
+  template(com_oracle_graal_hotspot_HotSpotForeignCallLinkage,       "com/oracle/graal/hotspot/HotSpotForeignCallLinkage")            \
   template(com_oracle_graal_hotspot_bridge_VMToCompiler,             "com/oracle/graal/hotspot/bridge/VMToCompiler")                  \
   template(com_oracle_graal_hotspot_bridge_CompilerToVMImpl,         "com/oracle/graal/hotspot/bridge/CompilerToVMImpl")              \
   template(com_oracle_graal_hotspot_meta_HotSpotCodeInfo,            "com/oracle/graal/hotspot/meta/HotSpotCodeInfo")                 \
--- a/src/share/vm/graal/graalCodeInstaller.cpp	Fri May 17 15:38:22 2013 +0200
+++ b/src/share/vm/graal/graalCodeInstaller.cpp	Fri May 17 15:40:06 2013 +0200
@@ -647,17 +647,17 @@
   InstanceKlass* target_klass = InstanceKlass::cast(target->klass());
 
   oop hotspot_method = NULL; // JavaMethod
-  oop global_stub = NULL;
+  oop foreign_call = NULL;
 
-  if (target_klass->is_subclass_of(SystemDictionary::HotSpotRuntimeCallTarget_klass())) {
-    global_stub = target;
+  if (target_klass->is_subclass_of(SystemDictionary::HotSpotForeignCallLinkage_klass())) {
+    foreign_call = target;
   } else {
     hotspot_method = target;
   }
 
   oop debug_info = CompilationResult_Call::debugInfo(site);
 
-  assert((hotspot_method ? 1 : 0) + (global_stub ? 1 : 0) == 1, "Call site needs exactly one type");
+  assert((hotspot_method ? 1 : 0) + (foreign_call ? 1 : 0) == 1, "Call site needs exactly one type");
 
   NativeInstruction* inst = nativeInstruction_at(_instructions->start() + pc_offset);
   jint next_pc_offset = 0x0;
@@ -704,24 +704,24 @@
     }
   }
 
-  if (global_stub != NULL) {
-    jlong global_stub_destination = HotSpotRuntimeCallTarget::address(global_stub);
+  if (foreign_call != NULL) {
+    jlong foreign_call_destination = HotSpotForeignCallLinkage::address(foreign_call);
     if (inst->is_call()) {
       // NOTE: for call without a mov, the offset must fit a 32-bit immediate
       //       see also CompilerToVM.getMaxCallTargetOffset()
       NativeCall* call = nativeCall_at((address) (inst));
-      call->set_destination((address) global_stub_destination);
+      call->set_destination((address) foreign_call_destination);
       _instructions->relocate(call->instruction_address(), runtime_call_Relocation::spec(), Assembler::call32_operand);
     } else if (inst->is_mov_literal64()) {
       NativeMovConstReg* mov = nativeMovConstReg_at((address) (inst));
-      mov->set_data((intptr_t) global_stub_destination);
+      mov->set_data((intptr_t) foreign_call_destination);
       _instructions->relocate(mov->instruction_address(), runtime_call_Relocation::spec(), Assembler::imm_operand);
     } else {
       NativeJump* jump = nativeJump_at((address) (inst));
-      jump->set_jump_destination((address) global_stub_destination);
+      jump->set_jump_destination((address) foreign_call_destination);
       _instructions->relocate((address)inst, runtime_call_Relocation::spec(), Assembler::call32_operand);
     }
-    TRACE_graal_3("relocating (stub)  at %p", inst);
+    TRACE_graal_3("relocating (foreign call)  at %p", inst);
   } else { // method != NULL
     assert(hotspot_method != NULL, "unexpected JavaMethod");
 #ifdef ASSERT
--- a/src/share/vm/graal/graalCompiler.cpp	Fri May 17 15:38:22 2013 +0200
+++ b/src/share/vm/graal/graalCompiler.cpp	Fri May 17 15:40:06 2013 +0200
@@ -95,7 +95,7 @@
       }
     }
     if (UseCompiler) {
-      VMToCompiler::startCompiler();
+      VMToCompiler::startCompiler(BootstrapGraal);
       _initialized = true;
       if (BootstrapGraal) {
         // We turn off CompileTheWorld and complete the VM startup so that
--- a/src/share/vm/graal/graalJavaAccess.hpp	Fri May 17 15:38:22 2013 +0200
+++ b/src/share/vm/graal/graalJavaAccess.hpp	Fri May 17 15:40:06 2013 +0200
@@ -95,8 +95,8 @@
   start_class(HotSpotCompiledRuntimeStub)                                                                                                                      \
     oop_field(HotSpotCompiledRuntimeStub, stubName, "Ljava/lang/String;")                                                                                      \
   end_class                                                                                                                                                    \
-  start_class(HotSpotRuntimeCallTarget)                                                                                                                        \
-    long_field(HotSpotRuntimeCallTarget, address)                                                                                                              \
+  start_class(HotSpotForeignCallLinkage)                                                                                                                        \
+    long_field(HotSpotForeignCallLinkage, address)                                                                                                              \
   end_class                                                                                                                                                    \
   start_class(ExceptionHandler)                                                                                                                                \
     int_field(ExceptionHandler, startBCI)                                                                                                                      \
--- a/src/share/vm/graal/graalVMToCompiler.cpp	Fri May 17 15:38:22 2013 +0200
+++ b/src/share/vm/graal/graalVMToCompiler.cpp	Fri May 17 15:40:06 2013 +0200
@@ -123,12 +123,13 @@
   }
 }
 
-void VMToCompiler::startCompiler() {
+void VMToCompiler::startCompiler(jboolean bootstrap_enabled) {
   JavaThread* THREAD = JavaThread::current();
   JavaValue result(T_VOID);
   JavaCallArguments args;
   args.push_oop(instance());
-  JavaCalls::call_interface(&result, vmToCompilerKlass(), vmSymbols::startCompiler_name(), vmSymbols::void_method_signature(), &args, THREAD);
+  args.push_int(bootstrap_enabled);
+  JavaCalls::call_interface(&result, vmToCompilerKlass(), vmSymbols::startCompiler_name(), vmSymbols::bool_void_signature(), &args, THREAD);
   check_pending_exception("Error while calling startCompiler");
 }
 
--- a/src/share/vm/graal/graalVMToCompiler.hpp	Fri May 17 15:38:22 2013 +0200
+++ b/src/share/vm/graal/graalVMToCompiler.hpp	Fri May 17 15:40:06 2013 +0200
@@ -59,8 +59,8 @@
   // public abstract void shutdownCompiler();
   static void shutdownCompiler();
   
-  // public abstract void startCompiler();
-  static void startCompiler();
+  // public abstract void startCompiler(boolean bootstrapEnabled);
+  static void startCompiler(jboolean bootstrap_enabled);
   
   // public abstract void bootstrap();
   static void bootstrap();