changeset 9693:d04944441454

cleaned up and simplified runtime call mechanisms
author Doug Simon <doug.simon@oracle.com>
date Tue, 14 May 2013 21:33:37 +0200
parents fb2cf3033ebb
children b2ba1c6f9bf8
files graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CallingConvention.java graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRegisterConfig.java graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRuntime.java graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotRuntime.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledRuntimeStub.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotRuntimeCallTarget.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorEnterStubCall.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/RuntimeCallStub.java src/share/vm/graal/graalCompilerToVM.cpp
diffstat 12 files changed, 227 insertions(+), 432 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CallingConvention.java	Mon May 13 23:15:53 2013 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CallingConvention.java	Tue May 14 21:33:37 2013 +0200
@@ -48,12 +48,6 @@
         JavaCallee(false),
 
         /**
-         * A request for the outgoing argument locations at a call site to the runtime (which may be
-         * Java or native code).
-         */
-        RuntimeCall(true),
-
-        /**
          * A request for the outgoing argument locations at a call site to external native code that
          * complies with the platform ABI.
          */
@@ -152,6 +146,16 @@
     }
 
     /**
+     * Gets the locations required for the arguments.
+     */
+    public AllocatableValue[] getArguments() {
+        if (argumentLocations.length == 0) {
+            return argumentLocations;
+        }
+        return argumentLocations.clone();
+    }
+
+    /**
      * Gets the locations used (and killed) by the call apart from the
      * {@linkplain #getArgument(int) arguments}.
      */
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Mon May 13 23:15:53 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Tue May 14 21:33:37 2013 +0200
@@ -211,12 +211,12 @@
     @Override
     public Variable emitCall(RuntimeCallTarget callTarget, CallingConvention callCc, DeoptimizingNode info, Value... args) {
         Stub stub = getStub();
-        boolean isCRuntimeCall = ((HotSpotRuntimeCallTarget) callTarget).isCRuntimeCall();
-        assert !isCRuntimeCall || stub != null : "direct call to C runtime can only be made from compiled stubs, not from " + graph;
+        boolean destroysRegisters = ((HotSpotRuntimeCallTarget) callTarget).destroysRegisters();
+        assert !destroysRegisters || stub != null : "foreign call that destroys registers can only be made from compiled stub, not from " + graph;
 
         AMD64SaveRegistersOp save = null;
         StackSlot[] savedRegisterLocations = null;
-        if (isCRuntimeCall) {
+        if (destroysRegisters) {
             if (stub.preservesRegisters()) {
                 Register[] savedRegisters = frameMap.registerConfig.getAllocatableRegisters();
                 savedRegisterLocations = new StackSlot[savedRegisters.length];
@@ -233,7 +233,7 @@
 
         Variable result = super.emitCall(callTarget, callCc, info, args);
 
-        if (isCRuntimeCall) {
+        if (destroysRegisters) {
             append(new AMD64HotSpotCRuntimeCallEpilogueOp());
             if (stub.preservesRegisters()) {
                 assert !calleeSaveInfo.containsKey(currentRuntimeCallInfo);
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRegisterConfig.java	Mon May 13 23:15:53 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRegisterConfig.java	Tue May 14 21:33:37 2013 +0200
@@ -106,7 +106,7 @@
         return allocatable;
     }
 
-    public AMD64HotSpotRegisterConfig(Architecture architecture, HotSpotVMConfig config, boolean globalStubConfig) {
+    public AMD64HotSpotRegisterConfig(Architecture architecture, HotSpotVMConfig config, boolean isNative) {
         this.architecture = architecture;
 
         if (config.windowsOs) {
@@ -117,7 +117,7 @@
             nativeGeneralParameterRegisters = new Register[] {rdi, rsi, rdx, rcx, r8, r9};
         }
 
-        if (globalStubConfig) {
+        if (isNative) {
             Register[] regs = {
                 rax,  rcx,  rdx,   rbx,   rsp,   rbp,   rsi,   rdi,
                 r8,   r9,   r10,   r11,   r12,   r13,   r14,   r15,
@@ -147,6 +147,7 @@
         if (type == Type.NativeCall) {
             return callingConvention(nativeGeneralParameterRegisters, returnType, parameterTypes, type, target, stackOnly);
         }
+        // On x64, parameter locations are the same whether viewed from the caller or callee perspective   
         return callingConvention(javaGeneralParameterRegisters, returnType, parameterTypes, type, target, stackOnly);
     }
 
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRuntime.java	Mon May 13 23:15:53 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRuntime.java	Tue May 14 21:33:37 2013 +0200
@@ -23,7 +23,10 @@
 package com.oracle.graal.hotspot.amd64;
 
 import static com.oracle.graal.amd64.AMD64.*;
+import static com.oracle.graal.api.code.CallingConvention.Type.*;
 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.replacements.AESCryptSubstitutions.DecryptBlockStubCall.*;
 import static com.oracle.graal.hotspot.replacements.AESCryptSubstitutions.EncryptBlockStubCall.*;
 import static com.oracle.graal.hotspot.replacements.CipherBlockChainingSubstitutions.DecryptAESCryptStubCall.*;
@@ -43,61 +46,29 @@
     public AMD64HotSpotRuntime(HotSpotVMConfig config, HotSpotGraalRuntime graalRuntime) {
         super(config, graalRuntime);
 
-        Kind word = graalRuntime.getTarget().wordKind;
-
-        // @formatter:off
-
-        // The calling convention for the exception handler stub is (only?) defined in
-        // TemplateInterpreterGenerator::generate_throw_exception()
-        // in templateInterpreter_x86_64.cpp around line 1923 
-        addStubCall(EXCEPTION_HANDLER,
-                /*            ret */ ret(Kind.Void),
-               /* arg0: exception */ rax.asValue(Kind.Object),
-             /* arg1: exceptionPc */ rdx.asValue(word));
-
-        addJump(EXCEPTION_HANDLER_IN_CALLER,
-                /* arg0: exception */ rax.asValue(Kind.Object),
-               /* arg1: exceptionPc */ rdx.asValue(word));
-
-        addRuntimeCall(ENCRYPT_BLOCK, config.aescryptEncryptBlockStub,
-                /*        temps */ null,
-                /*          ret */ ret(Kind.Void),
-                /* arg0:     in */ nativeCallingConvention(word,
-                /* arg1:    out */                         word,
-                /* arg2:    key */                         word));
-
-        addRuntimeCall(DECRYPT_BLOCK, config.aescryptDecryptBlockStub,
-                /*        temps */ null,
-                /*          ret */ ret(Kind.Void),
-                /* arg0:     in */ nativeCallingConvention(word,
-                /* arg1:    out */                         word,
-                /* arg2:    key */                         word));
-
-        addRuntimeCall(ENCRYPT, config.cipherBlockChainingEncryptAESCryptStub,
-                /*        temps */ null,
-                /*          ret */ ret(Kind.Void),
-                /* arg0:     in */ nativeCallingConvention(word,
-                /* arg1:    out */                         word,
-                /* arg2:    key */                         word,
-                /* arg3:      r */                         word,
-              /* arg4: inLength */                         Kind.Int));
-
-        addRuntimeCall(DECRYPT, config.cipherBlockChainingDecryptAESCryptStub,
-                /*        temps */ null,
-                /*          ret */ ret(Kind.Void),
-                /* arg0:     in */ nativeCallingConvention(word,
-                /* arg1:    out */                         word,
-                /* arg2:    key */                         word,
-                /* arg3:      r */                         word,
-              /* arg4: inLength */                         Kind.Int));
-        // @formatter:on
-
     }
 
     private AMD64ConvertSnippets.Templates convertSnippets;
 
     @Override
     public void registerReplacements(Replacements replacements) {
+        Kind word = graalRuntime.getTarget().wordKind;
+
+        // The calling convention for the exception handler stub is (only?) defined in
+        // TemplateInterpreterGenerator::generate_throw_exception()
+        // 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()));
+
+        // 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);
+
         convertSnippets = new AMD64ConvertSnippets.Templates(this, replacements, graalRuntime.getTarget());
         super.registerReplacements(replacements);
     }
@@ -122,7 +93,7 @@
     }
 
     @Override
-    protected RegisterConfig createRegisterConfig(boolean globalStubConfig) {
-        return new AMD64HotSpotRegisterConfig(graalRuntime.getTarget().arch, config, globalStubConfig);
+    protected RegisterConfig createRegisterConfig(boolean isNative) {
+        return new AMD64HotSpotRegisterConfig(graalRuntime.getTarget().arch, config, isNative);
     }
 }
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotRuntime.java	Mon May 13 23:15:53 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotRuntime.java	Tue May 14 21:33:37 2013 +0200
@@ -46,7 +46,7 @@
     }
 
     @Override
-    protected RegisterConfig createRegisterConfig(boolean globalStubConfig) {
+    protected RegisterConfig createRegisterConfig(boolean isNative) {
         // SPARC: Create register configuration.
         return null;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledRuntimeStub.java	Mon May 13 23:15:53 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledRuntimeStub.java	Tue May 14 21:33:37 2013 +0200
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.hotspot;
 
-import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
-
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.code.CompilationResult.Call;
 import com.oracle.graal.api.code.CompilationResult.DataPatch;
@@ -61,7 +59,7 @@
             Call call = (Call) infopoint;
             assert call.target instanceof HotSpotRuntimeCallTarget : this + " cannot have non runtime call: " + call.target;
             HotSpotRuntimeCallTarget callTarget = (HotSpotRuntimeCallTarget) call.target;
-            assert callTarget.getAddress() == graalRuntime().getConfig().uncommonTrapStub || callTarget.isCRuntimeCall() : this + "must only call C runtime or deoptimization stub, not " + call.target;
+            assert !callTarget.isCompiledStub() : this + " cannot call compiled stub " + callTarget;
         }
         return true;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotRuntimeCallTarget.java	Mon May 13 23:15:53 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotRuntimeCallTarget.java	Tue May 14 21:33:37 2013 +0200
@@ -22,13 +22,19 @@
  */
 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.
@@ -36,17 +42,26 @@
 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 stub. This is for informational purposes only.
+     * The descriptor of the call.
      */
-    public final Descriptor descriptor;
+    private final Descriptor descriptor;
 
     /**
-     * The entry point address of the stub.
+     * The entry point address of this call's target.
      */
     private long address;
 
@@ -56,17 +71,55 @@
     private Stub stub;
 
     /**
-     * Where the stub gets its arguments and where it places its result.
+     * The calling convention for this call.
      */
     private CallingConvention cc;
 
     private final CompilerToVM vm;
 
-    private final boolean isCRuntimeCall;
+    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);
+    }
 
-    public HotSpotRuntimeCallTarget(Descriptor descriptor, long address, boolean isCRuntimeCall, CallingConvention cc, CompilerToVM 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.isCRuntimeCall = isCRuntimeCall;
+        this.effect = effect;
         this.descriptor = descriptor;
         this.cc = cc;
         this.vm = vm;
@@ -89,21 +142,23 @@
         return descriptor;
     }
 
-    public void setStub(Stub stub) {
+    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);
 
-            AllocatableValue[] argumentLocations = new AllocatableValue[cc.getArgumentCount()];
-            for (int i = 0; i < argumentLocations.length; i++) {
-                argumentLocations[i] = cc.getArgument(i);
-            }
-
             Set<Register> destroyedRegisters = stub.getDestroyedRegisters();
             AllocatableValue[] temporaryLocations = new AllocatableValue[destroyedRegisters.size()];
             int i = 0;
@@ -111,7 +166,7 @@
                 temporaryLocations[i++] = reg.asValue();
             }
             // Update calling convention with temporaries
-            cc = new CallingConvention(temporaryLocations, cc.getStackSize(), cc.getReturn(), argumentLocations);
+            cc = new CallingConvention(temporaryLocations, cc.getStackSize(), cc.getReturn(), cc.getArguments());
             address = code.getStart();
         }
     }
@@ -123,23 +178,6 @@
 
     @Override
     public boolean destroysRegisters() {
-        if (isCRuntimeCall) {
-            // Even though most native ABIs define some callee saved registers,
-            // for simplicity we force the register allocator to save all live
-            // registers across a C runtime call as such calls are only made from
-            // compiled stubs which a) are slow path and b) will typically only
-            // have very few live registers across a C runtime call
-            return true;
-        }
-        // This is a call to a compiled (or assembler) stub which saves
-        // all registers (apart from its temporaries)
-        return false;
-    }
-
-    /**
-     * Determines if this is a link to a C/C++ function in the HotSpot runtime.
-     */
-    public boolean isCRuntimeCall() {
-        return isCRuntimeCall;
+        return effect == DESTROYS_REGISTERS;
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Mon May 13 23:15:53 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Tue May 14 21:33:37 2013 +0200
@@ -366,18 +366,10 @@
     public int bciProfileWidth;
     public int typeProfileWidth;
 
-    // runtime stubs
     public long inlineCacheMissStub;
     public long handleDeoptStub;
+    public long uncommonTrapStub;
 
-    public long uncommonTrapStub;
-    public long unwindExceptionStub;
-    public long javaTimeMillisStub;
-    public long javaTimeNanosStub;
-    public long arithmeticSinStub;
-    public long arithmeticCosStub;
-    public long arithmeticTanStub;
-    public int deoptReasonNone;
     public long aescryptEncryptBlockStub;
     public long aescryptDecryptBlockStub;
     public long cipherBlockChainingEncryptAESCryptStub;
@@ -403,7 +395,13 @@
     public long vmErrorAddress;
     public long writeBarrierPreAddress;
     public long writeBarrierPostAddress;
+    public long javaTimeMillisAddress;
+    public long javaTimeNanosAddress;
+    public long arithmeticSinAddress;
+    public long arithmeticCosAddress;
+    public long arithmeticTanAddress;
 
+    public int deoptReasonNone;
     public int deoptReasonNullCheck;
     public int deoptReasonRangeCheck;
     public int deoptReasonClassCheck;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Mon May 13 23:15:53 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Tue May 14 21:33:37 2013 +0200
@@ -26,10 +26,10 @@
 import static com.oracle.graal.api.code.DeoptimizationAction.*;
 import static com.oracle.graal.api.code.MemoryBarriers.*;
 import static com.oracle.graal.api.meta.DeoptimizationReason.*;
-import static com.oracle.graal.api.meta.Value.*;
 import static com.oracle.graal.graph.UnsafeAccess.*;
 import static com.oracle.graal.hotspot.HotSpotBackend.*;
-import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.wordKind;
+import static com.oracle.graal.hotspot.HotSpotRuntimeCallTarget.RegisterEffect.*;
 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,7 +40,7 @@
 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.IDENTITY_HASHCODE;
+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.*;
@@ -74,6 +74,7 @@
 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.bridge.*;
 import com.oracle.graal.hotspot.bridge.CompilerToVM.CodeInstallResult;
 import com.oracle.graal.hotspot.nodes.*;
@@ -103,8 +104,8 @@
 
     public final HotSpotVMConfig config;
 
-    protected final RegisterConfig regConfig;
-    protected final RegisterConfig globalStubRegConfig;
+    protected final RegisterConfig javaABI;
+    protected final RegisterConfig nativeABI;
     protected final HotSpotGraalRuntime graalRuntime;
 
     private CheckCastSnippets.Templates checkcastSnippets;
@@ -177,292 +178,90 @@
         }
     }
 
-    protected AllocatableValue ret(Kind kind) {
-        if (kind == Kind.Void) {
-            return ILLEGAL;
-        }
-        return globalStubRegConfig.getReturnRegister(kind).asValue(kind);
-    }
-
-    protected AllocatableValue[] javaCallingConvention(Kind... arguments) {
-        return callingConvention(arguments, RuntimeCall);
-    }
-
-    protected AllocatableValue[] nativeCallingConvention(Kind... arguments) {
-        return callingConvention(arguments, NativeCall);
-    }
-
-    private AllocatableValue[] callingConvention(Kind[] arguments, CallingConvention.Type type) {
-        AllocatableValue[] result = new AllocatableValue[arguments.length];
-
-        TargetDescription target = graalRuntime.getTarget();
-        int currentStackOffset = 0;
-        for (int i = 0; i < arguments.length; i++) {
-            Kind kind = arguments[i];
-            Register[] ccRegs = globalStubRegConfig.getCallingConventionRegisters(type, kind);
-            if (i < ccRegs.length) {
-                result[i] = ccRegs[i].asValue(kind);
-            } else {
-                result[i] = StackSlot.get(kind.getStackKind(), currentStackOffset, false);
-                currentStackOffset += Math.max(target.arch.getSizeInBytes(kind), target.wordSize);
-            }
-        }
-        return result;
+    public HotSpotRuntime(HotSpotVMConfig c, HotSpotGraalRuntime graalRuntime) {
+        this.config = c;
+        this.graalRuntime = graalRuntime;
+        javaABI = createRegisterConfig(false);
+        nativeABI = createRegisterConfig(true);
     }
 
-    public HotSpotRuntime(HotSpotVMConfig config, HotSpotGraalRuntime graalRuntime) {
-        this.config = config;
-        this.graalRuntime = graalRuntime;
-        regConfig = createRegisterConfig(false);
-        globalStubRegConfig = createRegisterConfig(true);
-        Kind word = graalRuntime.getTarget().wordKind;
-
-        // @formatter:off
-
-        addStubCall(VERIFY_OOP,
-                        /*             ret */ ret(Kind.Object),
-                        /* arg0:    object */ javaCallingConvention(Kind.Object));
-
-        addStubCall(OSR_MIGRATION_END,
-                        /*             ret */ ret(Kind.Void),
-                        /* arg0:    buffer */ javaCallingConvention(word));
-
-        addCRuntimeCall(OSR_MIGRATION_END_C, config.osrMigrationEndAddress,
-                        /*             ret */ ret(Kind.Void),
-                        /* arg0:    buffer */ nativeCallingConvention(word));
-
-        addRuntimeCall(UNCOMMON_TRAP, config.uncommonTrapStub,
-                        /*           temps */ null,
-                        /*             ret */ ret(Kind.Void));
-
-        addCRuntimeCall(EXCEPTION_HANDLER_FOR_PC, config.exceptionHandlerForPcAddress,
-                        /*             ret */ ret(word),
-                        /* arg0:    thread */ nativeCallingConvention(word));
-
-        addStubCall(UNWIND_EXCEPTION_TO_CALLER,
-                        /*             ret */ ret(Kind.Void),
-                        /* arg0: exception */ javaCallingConvention(Kind.Object,
-                    /* arg1: returnAddress */                       word));
-
-        addCRuntimeCall(EXCEPTION_HANDLER_FOR_RETURN_ADDRESS, config.exceptionHandlerForReturnAddressAddress,
-                        /*             ret */ ret(word),
-                        /* arg0:    thread */ nativeCallingConvention(word,
-                    /* arg1: returnAddress */                         word));
-
-        addStubCall(NEW_ARRAY,
-                        /*             ret */ ret(Kind.Object),
-                        /* arg0:       hub */ javaCallingConvention(word,
-                        /* arg1:    length */ Kind.Int));
-
-        addCRuntimeCall(NEW_ARRAY_C, config.newArrayAddress,
-                        /*             ret */ ret(Kind.Void),
-                        /* arg0:    thread */ nativeCallingConvention(word,
-                        /* arg1:       hub */                         word,
-                        /* arg2:    length */                         Kind.Int));
-
-        addStubCall(NEW_INSTANCE,
-                        /*             ret */ ret(Kind.Object),
-                        /* arg0:       hub */ javaCallingConvention(word));
-
-        addCRuntimeCall(NEW_INSTANCE_C, config.newInstanceAddress,
-                        /*             ret */ ret(Kind.Void),
-                        /* arg0:    thread */ nativeCallingConvention(word,
-                        /* arg1:       hub */                         word));
-
-        addStubCall(NEW_MULTI_ARRAY,
-                        /*             ret */ ret(Kind.Object),
-                        /* arg0:       hub */ javaCallingConvention(word,
-                        /* arg1:      rank */                       Kind.Int,
-                        /* arg2:      dims */                       word));
-
-        addCRuntimeCall(NEW_MULTI_ARRAY_C, config.newMultiArrayAddress,
-                        /*             ret */ ret(Kind.Void),
-                        /* arg0:    thread */ nativeCallingConvention(word,
-                        /* arg1:       hub */                         word,
-                        /* arg2:      rank */                         Kind.Int,
-                        /* arg3:      dims */                         word));
-
-        addRuntimeCall(JAVA_TIME_MILLIS, config.javaTimeMillisStub,
-                        /*           temps */ this.regConfig.getCallerSaveRegisters(),
-                        /*             ret */ ret(Kind.Long));
-
-        addRuntimeCall(JAVA_TIME_NANOS, config.javaTimeNanosStub,
-                        /*           temps */ this.regConfig.getCallerSaveRegisters(),
-                        /*             ret */ ret(Kind.Long));
-
-        addRuntimeCall(ARITHMETIC_SIN, config.arithmeticSinStub,
-                        /*           temps */ this.regConfig.getCallerSaveRegisters(),
-                        /*             ret */ ret(Kind.Double),
-                        /* arg0:     index */ javaCallingConvention(Kind.Double));
-
-        addRuntimeCall(ARITHMETIC_COS, config.arithmeticCosStub,
-                        /*           temps */ this.regConfig.getCallerSaveRegisters(),
-                        /*             ret */ ret(Kind.Double),
-                        /* arg0:     index */ javaCallingConvention(Kind.Double));
-
-        addRuntimeCall(ARITHMETIC_TAN, config.arithmeticTanStub,
-                        /*           temps */ this.regConfig.getCallerSaveRegisters(),
-                        /*             ret */ ret(Kind.Double),
-                        /* arg0:     index */ javaCallingConvention(Kind.Double));
-
-        addStubCall(LOG_PRIMITIVE,
-                        /*             ret */ ret(Kind.Void),
-                        /* arg0:  typeChar */ javaCallingConvention(Kind.Int,
-                        /* arg1:     value */                       Kind.Long,
-                        /* arg2:   newline */                       Kind.Boolean));
-
-        addCRuntimeCall(LOG_PRIMITIVE_C, config.logPrimitiveAddress,
-                        /*             ret */ ret(Kind.Void),
-                        /* arg0:    thread */ nativeCallingConvention(word,
-                        /* arg1:  typeChar */                         Kind.Char,
-                        /* arg2:     value */                         Kind.Long,
-                        /* arg3:   newline */                         Kind.Boolean));
-
-        addStubCall(LOG_PRINTF,
-                        /*             ret */ ret(Kind.Void),
-                        /* arg0:    format */ javaCallingConvention(Kind.Object,
-                        /* arg1:     value */                       Kind.Long,
-                        /* arg2:     value */                       Kind.Long,
-                        /* arg3:     value */                       Kind.Long));
-
-        addCRuntimeCall(LOG_PRINTF_C, config.logObjectAddress,
-                        /*             ret */ ret(Kind.Void),
-                        /* arg0:    thread */ nativeCallingConvention(word,
-                        /* arg1:    format */                         Kind.Object,
-                        /* arg2:        v1 */                         Kind.Long,
-                        /* arg3:        v2 */                         Kind.Long,
-                        /* arg4:        v3 */                         Kind.Long));
-
-        addCRuntimeCall(VM_MESSAGE_C, config.vmMessageAddress,
-                        /*             ret */ ret(Kind.Void),
-                        /* arg0:   vmError */ nativeCallingConvention(Kind.Boolean,
-                        /* arg1:    format */                         word,
-                        /* arg2:     value */                         Kind.Long,
-                        /* arg3:     value */                         Kind.Long,
-                        /* arg4:     value */                         Kind.Long));
-
-        addStubCall(LOG_OBJECT,
-                        /*             ret */ ret(Kind.Void),
-                        /* arg0:    object */ javaCallingConvention(Kind.Object,
-                        /* arg1:     flags */                       Kind.Int));
-
-        addCRuntimeCall(LOG_OBJECT_C, config.logObjectAddress,
-                        /*             ret */ ret(Kind.Void),
-                        /* arg0:    thread */ nativeCallingConvention(word,
-                        /* arg1:    object */                         Kind.Object,
-                        /* arg2:     flags */                         Kind.Int));
-
-        addStubCall(THREAD_IS_INTERRUPTED,
-                        /*             ret */ ret(Kind.Boolean),
-                        /* arg0:    thread */ javaCallingConvention(Kind.Object,
-                 /* arg1: clearInterrupted */                       Kind.Boolean));
-
-        addCRuntimeCall(THREAD_IS_INTERRUPTED_C, config.threadIsInterruptedAddress,
-                        /*             ret */ ret(Kind.Boolean),
-                        /* arg0:    thread */ nativeCallingConvention(word,
-                   /* arg1: receiverThread */                         Kind.Object,
-              /* arg1: clearInterrupted */                            Kind.Boolean));
-
-        addRuntimeCall(DEOPT_HANDLER, config.handleDeoptStub,
-                        /*           temps */ null,
-                        /*             ret */ ret(Kind.Void));
-
-        addRuntimeCall(IC_MISS_HANDLER, config.inlineCacheMissStub,
-                        /*           temps */ null,
-                        /*             ret */ ret(Kind.Void));
-
-        addStubCall(VM_ERROR,
-                        /*          ret */ ret(Kind.Void),
-                        /* arg0:  where */ javaCallingConvention(Kind.Object,
-                        /* arg1: format */                       Kind.Object,
-                        /* arg2:  value */                       Kind.Long));
-
-        addCRuntimeCall(VM_ERROR_C, config.vmErrorAddress,
-                        /*          ret */ ret(Kind.Void),
-                        /* arg0: thread */ nativeCallingConvention(word,
-                        /* arg0:  where */                         Kind.Object,
-                        /* arg1: format */                         Kind.Object,
-                        /* arg2:  value */                         Kind.Long));
-        // @formatter:on
+    protected HotSpotRuntimeCallTarget register(HotSpotRuntimeCallTarget call) {
+        HotSpotRuntimeCallTarget oldValue = runtimeCalls.put(call.getDescriptor(), call);
+        assert oldValue == null;
+        return call;
     }
 
     /**
-     * Registers the details for linking a call to a compiled {@link Stub}.
-     * 
-     * @param descriptor name and signature of the call
-     * @param ret where the call returns its result
-     * @param args where arguments are passed to the call
+     * Registers the details for linking a call to a {@link Stub}.
      */
-    protected RuntimeCallTarget addStubCall(Descriptor descriptor, AllocatableValue ret, AllocatableValue... args) {
-        return addRuntimeCall(descriptor, 0L, null, ret, args);
-    }
-
-    /**
-     * Registers the details for a jump to a target that has a signature (i.e. expects arguments in
-     * specified locations).
-     * 
-     * @param descriptor name and signature of the jump target
-     * @param args where arguments are passed to the call
-     */
-    protected RuntimeCallTarget addJump(Descriptor descriptor, AllocatableValue... args) {
-        return addRuntimeCall(descriptor, HotSpotRuntimeCallTarget.JUMP_ADDRESS, null, ret(Kind.Void), args);
+    protected RuntimeCallTarget registerStubCall(Descriptor descriptor) {
+        return register(HotSpotRuntimeCallTarget.create(descriptor, 0L, PRESERVES_REGISTERS, JavaCallee, javaABI, this, graalRuntime.getCompilerToVM()));
     }
 
     /**
      * Registers the details for a call to a runtime C/C++ function.
-     * 
-     * @param descriptor name and signature of the call
-     * @param args where arguments are passed to the call
      */
-    protected RuntimeCallTarget addCRuntimeCall(Descriptor descriptor, long address, AllocatableValue ret, AllocatableValue... args) {
-        assert descriptor.getResultType().isPrimitive() || Word.class.isAssignableFrom(descriptor.getResultType()) : "C runtime call cannot have Object return type - objects must be returned via thread local storage: " +
-                        descriptor;
-        return addRuntimeCall(descriptor, address, true, null, ret, args);
+    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, nativeABI, this, graalRuntime.getCompilerToVM()));
     }
 
-    protected RuntimeCallTarget addRuntimeCall(Descriptor descriptor, long address, Register[] tempRegs, AllocatableValue ret, AllocatableValue... args) {
-        return addRuntimeCall(descriptor, address, false, tempRegs, ret, args);
+    /**
+     * Registers the details for a call to a stub that never returns.
+     */
+    protected RuntimeCallTarget registerNoReturnStub(Descriptor descriptor, long address, CallingConvention.Type ccType) {
+        return register(HotSpotRuntimeCallTarget.create(descriptor, address, PRESERVES_REGISTERS, ccType, javaABI, this, graalRuntime.getCompilerToVM()));
     }
 
     /**
-     * Registers the details for linking a runtime call.
-     * 
-     * @param descriptor name and signature of the call
-     * @param address target address of the call
-     * @param tempRegs temporary registers used (and killed) by the call (null if none)
-     * @param ret where the call returns its result
-     * @param args where arguments are passed to the call
+     * 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.
      */
-    protected RuntimeCallTarget addRuntimeCall(Descriptor descriptor, long address, boolean isCRuntimeCall, Register[] tempRegs, AllocatableValue ret, AllocatableValue... args) {
-        AllocatableValue[] temps = tempRegs == null || tempRegs.length == 0 ? AllocatableValue.NONE : new AllocatableValue[tempRegs.length];
-        for (int i = 0; i < temps.length; i++) {
-            temps[i] = tempRegs[i].asValue();
-        }
-        assert checkAssignable(descriptor.getResultType(), ret) : descriptor + " incompatible with result location " + ret;
-        Class[] argTypes = descriptor.getArgumentTypes();
-        assert argTypes.length == args.length : descriptor + " incompatible with number of argument locations: " + args.length;
-        for (int i = 0; i < argTypes.length; i++) {
-            assert checkAssignable(argTypes[i], args[i]) : descriptor + " incompatible with argument location " + i + ": " + args[i];
-        }
-        HotSpotRuntimeCallTarget runtimeCall = new HotSpotRuntimeCallTarget(descriptor, address, isCRuntimeCall, new CallingConvention(temps, 0, ret, args), graalRuntime.getCompilerToVM());
-        runtimeCalls.put(descriptor, runtimeCall);
-        return runtimeCall;
+    protected RuntimeCallTarget registerLeafCall(Descriptor descriptor, long address, CallingConvention.Type ccType, RegisterEffect effect) {
+        return register(HotSpotRuntimeCallTarget.create(descriptor, address, effect, ccType, javaABI, this, graalRuntime.getCompilerToVM()));
     }
 
-    private boolean checkAssignable(Class spec, Value value) {
-        Kind kind = value.getKind();
-        if (kind == Kind.Illegal) {
-            kind = Kind.Void;
-        }
-        if (WordBase.class.isAssignableFrom(spec)) {
-            return kind == graalRuntime.getTarget().wordKind;
-        }
-        return kind == Kind.fromJavaClass(spec);
-    }
-
-    protected abstract RegisterConfig createRegisterConfig(boolean globalStubConfig);
+    protected abstract RegisterConfig createRegisterConfig(boolean isNative);
 
     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;
+        registerNoReturnStub(UNCOMMON_TRAP, c.uncommonTrapStub, NativeCall);
+        registerNoReturnStub(DEOPT_HANDLER, c.handleDeoptStub, NativeCall);
+        registerNoReturnStub(IC_MISS_HANDLER, c.inlineCacheMissStub, NativeCall);
+
+        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);
+
+        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);
+
         if (GraalOptions.IntrinsifyObjectMethods) {
             replacements.registerSubstitutions(ObjectSubstitutions.class);
         }
@@ -486,26 +285,27 @@
             replacements.registerSubstitutions(ReflectionSubstitutions.class);
         }
 
-        checkcastSnippets = new CheckCastSnippets.Templates(this, replacements, graalRuntime.getTarget());
-        instanceofSnippets = new InstanceOfSnippets.Templates(this, replacements, graalRuntime.getTarget());
-        newObjectSnippets = new NewObjectSnippets.Templates(this, replacements, graalRuntime.getTarget(), config.useTLAB);
-        monitorSnippets = new MonitorSnippets.Templates(this, replacements, graalRuntime.getTarget(), config.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 = graalRuntime.getTarget();
+        checkcastSnippets = new CheckCastSnippets.Templates(this, replacements, target);
+        instanceofSnippets = new InstanceOfSnippets.Templates(this, replacements, target);
+        newObjectSnippets = new NewObjectSnippets.Templates(this, replacements, target, config.useTLAB);
+        monitorSnippets = new MonitorSnippets.Templates(this, replacements, target, config.useFastLocking);
+        writeBarrierSnippets = new WriteBarrierSnippets.Templates(this, replacements, target);
+        boxingSnippets = new BoxingSnippets.Templates(this, replacements, target);
+        exceptionObjectSnippets = new LoadExceptionObjectSnippets.Templates(this, replacements, target);
 
-        link(new NewInstanceStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(NEW_INSTANCE)));
-        link(new NewArrayStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(NEW_ARRAY)));
-        link(new NewMultiArrayStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(NEW_MULTI_ARRAY)));
-        link(new ThreadIsInterruptedStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(THREAD_IS_INTERRUPTED)));
-        link(new ExceptionHandlerStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(EXCEPTION_HANDLER)));
-        link(new UnwindExceptionToCallerStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(UNWIND_EXCEPTION_TO_CALLER)));
-        link(new VerifyOopStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(VERIFY_OOP)));
-        link(new OSRMigrationEndStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(OSR_MIGRATION_END)));
-        link(new LogPrimitiveStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(LOG_PRIMITIVE)));
-        link(new LogObjectStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(LOG_OBJECT)));
-        link(new LogPrintfStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(LOG_PRINTF)));
-        link(new VMErrorStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(VM_ERROR)));
+        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);
@@ -518,14 +318,14 @@
     }
 
     private static void link(Stub stub) {
-        stub.getLinkage().setStub(stub);
+        stub.getLinkage().setCompiledStub(stub);
     }
 
     private void linkRuntimeCall(Descriptor descriptor, long address, Replacements replacements) {
-        RuntimeCallStub stub = new RuntimeCallStub(address, descriptor, true, this, replacements, globalStubRegConfig, graalRuntime.getCompilerToVM());
+        RuntimeCallStub stub = new RuntimeCallStub(address, descriptor, true, this, replacements, nativeABI, graalRuntime.getCompilerToVM());
         HotSpotRuntimeCallTarget linkage = stub.getLinkage();
         HotSpotRuntimeCallTarget targetLinkage = stub.getTargetLinkage();
-        linkage.setStub(stub);
+        linkage.setCompiledStub(stub);
         runtimeCalls.put(linkage.getDescriptor(), linkage);
         runtimeCalls.put(targetLinkage.getDescriptor(), targetLinkage);
     }
@@ -553,7 +353,7 @@
         if (compResult != null) {
             HexCodeFile.addAnnotations(hcf, compResult.getAnnotations());
             addExceptionHandlersComment(compResult, hcf);
-            Register fp = regConfig.getFrameRegister();
+            Register fp = javaABI.getFrameRegister();
             RefMapFormatter slotFormatter = new RefMapFormatter(target.arch, target.wordSize, fp, 0);
             for (Infopoint infopoint : compResult.getInfopoints()) {
                 if (infopoint instanceof Call) {
@@ -657,7 +457,7 @@
 
     @Override
     public RegisterConfig lookupRegisterConfig() {
-        return regConfig;
+        return javaABI;
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorEnterStubCall.java	Mon May 13 23:15:53 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorEnterStubCall.java	Tue May 14 21:33:37 2013 +0200
@@ -47,7 +47,7 @@
 
     @Override
     public void generate(LIRGenerator gen) {
-        RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(MonitorEnterStubCall.MONITORENTER);
+        RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(MONITORENTER);
         gen.emitCall(stub, stub.getCallingConvention(), this, gen.operand(object), gen.operand(lock));
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/RuntimeCallStub.java	Mon May 13 23:15:53 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/RuntimeCallStub.java	Tue May 14 21:33:37 2013 +0200
@@ -22,13 +22,14 @@
  */
 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.CallingConvention.Type;
 import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.debug.*;
@@ -79,12 +80,11 @@
      * @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, new HotSpotRuntimeCallTarget(sig, 0L, false, createCallingConvention(runtime, regConfig, sig), 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);
-        CallingConvention targetCc = createCallingConvention(runtime, regConfig, targetSig);
-        target = new HotSpotRuntimeCallTarget(targetSig, address, true, targetCc, vm);
+        target = HotSpotRuntimeCallTarget.create(targetSig, address, DESTROYS_REGISTERS, NativeCall, regConfig, runtime, vm);
     }
 
     /**
@@ -94,21 +94,6 @@
         return target;
     }
 
-    private static CallingConvention createCallingConvention(HotSpotRuntime runtime, RegisterConfig regConfig, Descriptor d) {
-        Class<?>[] argumentTypes = d.getArgumentTypes();
-        JavaType[] parameterTypes = new JavaType[argumentTypes.length];
-        for (int i = 0; i < parameterTypes.length; ++i) {
-            if (WordBase.class.isAssignableFrom(argumentTypes[i])) {
-                parameterTypes[i] = runtime.lookupJavaType(wordKind().toJavaClass());
-            } else {
-                parameterTypes[i] = runtime.lookupJavaType(argumentTypes[i]);
-            }
-        }
-        TargetDescription target = graalRuntime().getTarget();
-        JavaType returnType = runtime.lookupJavaType(d.getResultType());
-        return regConfig.getCallingConvention(Type.NativeCall, returnType, parameterTypes, target, false);
-    }
-
     private Class[] createTargetParameters(Descriptor sig) {
         Class[] parameters = sig.getArgumentTypes();
         if (prependThread) {
@@ -130,7 +115,7 @@
         return new JavaMethod() {
 
             public Signature getSignature() {
-                Descriptor d = linkage.descriptor;
+                Descriptor d = linkage.getDescriptor();
                 Class<?>[] arguments = d.getArgumentTypes();
                 JavaType[] parameters = new JavaType[arguments.length];
                 for (int i = 0; i < arguments.length; i++) {
@@ -140,7 +125,7 @@
             }
 
             public String getName() {
-                return linkage.descriptor.getName();
+                return linkage.getDescriptor().getName();
             }
 
             public JavaType getDeclaringClass() {
@@ -199,7 +184,7 @@
             InvokeNode object = createInvoke(builder, HotSpotReplacementsUtil.class, "getAndClearObjectResult", thread);
             result = createInvoke(builder, StubUtil.class, "verifyObject", object);
         }
-        builder.add(new ReturnNode(linkage.descriptor.getResultType() == void.class ? null : result));
+        builder.add(new ReturnNode(linkage.getDescriptor().getResultType() == void.class ? null : result));
 
         if (Debug.isDumpEnabled()) {
             Debug.dump(builder.graph, "Initial stub graph");
@@ -255,9 +240,9 @@
             ValueNode[] targetArguments = new ValueNode[1 + locals.length];
             targetArguments[0] = thread;
             System.arraycopy(locals, 0, targetArguments, 1, locals.length);
-            return builder.add(new CRuntimeCall(target.descriptor, targetArguments));
+            return builder.add(new CRuntimeCall(target.getDescriptor(), targetArguments));
         } else {
-            return builder.add(new CRuntimeCall(target.descriptor, locals));
+            return builder.add(new CRuntimeCall(target.getDescriptor(), locals));
         }
     }
 
--- a/src/share/vm/graal/graalCompilerToVM.cpp	Mon May 13 23:15:53 2013 +0200
+++ b/src/share/vm/graal/graalCompilerToVM.cpp	Tue May 14 21:33:37 2013 +0200
@@ -768,11 +768,6 @@
 
   set_address("inlineCacheMissStub", SharedRuntime::get_ic_miss_stub());
   set_address("handleDeoptStub", SharedRuntime::deopt_blob()->unpack());
-  set_address("javaTimeMillisStub", CAST_FROM_FN_PTR(address, os::javaTimeMillis));
-  set_address("javaTimeNanosStub", CAST_FROM_FN_PTR(address, os::javaTimeNanos));
-  set_address("arithmeticSinStub", CAST_FROM_FN_PTR(address, SharedRuntime::dsin));
-  set_address("arithmeticCosStub", CAST_FROM_FN_PTR(address, SharedRuntime::dcos));
-  set_address("arithmeticTanStub", CAST_FROM_FN_PTR(address, SharedRuntime::dtan));
   set_address("aescryptEncryptBlockStub", StubRoutines::aescrypt_encryptBlock());
   set_address("aescryptDecryptBlockStub", StubRoutines::aescrypt_decryptBlock());
   set_address("cipherBlockChainingEncryptAESCryptStub", StubRoutines::cipherBlockChaining_encryptAESCrypt());
@@ -799,6 +794,11 @@
   set_address("vmErrorAddress", GraalRuntime::vm_error);
   set_address("writeBarrierPreAddress", GraalRuntime::write_barrier_pre);
   set_address("writeBarrierPostAddress", GraalRuntime::write_barrier_post);
+  set_address("javaTimeMillisAddress", CAST_FROM_FN_PTR(address, os::javaTimeMillis));
+  set_address("javaTimeNanosAddress", CAST_FROM_FN_PTR(address, os::javaTimeNanos));
+  set_address("arithmeticSinAddress", CAST_FROM_FN_PTR(address, SharedRuntime::dsin));
+  set_address("arithmeticCosAddress", CAST_FROM_FN_PTR(address, SharedRuntime::dcos));
+  set_address("arithmeticTanAddress", CAST_FROM_FN_PTR(address, SharedRuntime::dtan));
 
   set_int("deoptReasonNone", Deoptimization::Reason_none);
   set_int("deoptReasonNullCheck", Deoptimization::Reason_null_check);