changeset 18350:23a2faa68470

converted HotSpotForeignCallLinkage to an interface
author Doug Simon <doug.simon@oracle.com>
date Wed, 12 Nov 2014 14:43:58 +0100
parents 7aa6180a3486
children 1e7b53d7489d
files graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotForeignCallsProvider.java graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotForeignCallsProvider.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotForeignCallLinkage.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotForeignCallLinkageImpl.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotForeignCallsProviderImpl.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java src/share/vm/classfile/systemDictionary.hpp src/share/vm/classfile/vmSymbols.hpp src/share/vm/graal/graalCodeInstaller.cpp src/share/vm/graal/graalJavaAccess.hpp
diffstat 11 files changed, 289 insertions(+), 216 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java	Wed Nov 12 14:41:32 2014 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java	Wed Nov 12 14:43:58 2014 +0100
@@ -58,8 +58,8 @@
         RegisterValue exception = rax.asValue(LIRKind.reference(Kind.Object));
         RegisterValue exceptionPc = rdx.asValue(LIRKind.value(word));
         CallingConvention exceptionCc = new CallingConvention(0, ILLEGAL, exception, exceptionPc);
-        register(new HotSpotForeignCallLinkage(EXCEPTION_HANDLER, 0L, PRESERVES_REGISTERS, LEAF_NOFP, null, exceptionCc, NOT_REEXECUTABLE, ANY_LOCATION));
-        register(new HotSpotForeignCallLinkage(EXCEPTION_HANDLER_IN_CALLER, JUMP_ADDRESS, PRESERVES_REGISTERS, LEAF_NOFP, exceptionCc, null, NOT_REEXECUTABLE, ANY_LOCATION));
+        register(new HotSpotForeignCallLinkageImpl(EXCEPTION_HANDLER, 0L, PRESERVES_REGISTERS, LEAF_NOFP, null, exceptionCc, NOT_REEXECUTABLE, ANY_LOCATION));
+        register(new HotSpotForeignCallLinkageImpl(EXCEPTION_HANDLER_IN_CALLER, JUMP_ADDRESS, PRESERVES_REGISTERS, LEAF_NOFP, exceptionCc, null, NOT_REEXECUTABLE, ANY_LOCATION));
 
         link(new AMD64DeoptimizationStub(providers, target, registerStubCall(DEOPTIMIZATION_HANDLER, REEXECUTABLE, LEAF, NO_LOCATIONS)));
         link(new AMD64UncommonTrapStub(providers, target, registerStubCall(UNCOMMON_TRAP_HANDLER, REEXECUTABLE, LEAF, NO_LOCATIONS)));
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotForeignCallsProvider.java	Wed Nov 12 14:41:32 2014 +0100
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotForeignCallsProvider.java	Wed Nov 12 14:43:58 2014 +0100
@@ -38,7 +38,7 @@
         // we don't really support foreign calls yet, but we do want to generate dummy code for them
         // so we lazily create dummy linkages here.
         if (foreignCalls.get(descriptor) == null) {
-            return register(new HotSpotForeignCallLinkage(descriptor, 0x12345678, null, null, null, null, false, new LocationIdentity[0]));
+            return register(new HotSpotForeignCallLinkageImpl(descriptor, 0x12345678, null, null, null, null, false, new LocationIdentity[0]));
         } else {
             return super.lookupForeignCall(descriptor);
         }
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotForeignCallsProvider.java	Wed Nov 12 14:41:32 2014 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotForeignCallsProvider.java	Wed Nov 12 14:43:58 2014 +0100
@@ -58,8 +58,8 @@
         RegisterValue incomingExceptionPc = i1.asValue(LIRKind.value(word));
         CallingConvention outgoingExceptionCc = new CallingConvention(0, ILLEGAL, outgoingException, outgoingExceptionPc);
         CallingConvention incomingExceptionCc = new CallingConvention(0, ILLEGAL, incomingException, incomingExceptionPc);
-        register(new HotSpotForeignCallLinkage(EXCEPTION_HANDLER, 0L, PRESERVES_REGISTERS, LEAF_NOFP, outgoingExceptionCc, incomingExceptionCc, NOT_REEXECUTABLE, ANY_LOCATION));
-        register(new HotSpotForeignCallLinkage(EXCEPTION_HANDLER_IN_CALLER, JUMP_ADDRESS, PRESERVES_REGISTERS, LEAF_NOFP, outgoingExceptionCc, incomingExceptionCc, NOT_REEXECUTABLE, ANY_LOCATION));
+        register(new HotSpotForeignCallLinkageImpl(EXCEPTION_HANDLER, 0L, PRESERVES_REGISTERS, LEAF_NOFP, outgoingExceptionCc, incomingExceptionCc, NOT_REEXECUTABLE, ANY_LOCATION));
+        register(new HotSpotForeignCallLinkageImpl(EXCEPTION_HANDLER_IN_CALLER, JUMP_ADDRESS, PRESERVES_REGISTERS, LEAF_NOFP, outgoingExceptionCc, incomingExceptionCc, NOT_REEXECUTABLE, ANY_LOCATION));
 
         link(new SPARCDeoptimizationStub(providers, target, registerStubCall(DEOPTIMIZATION_HANDLER, REEXECUTABLE, LEAF, NO_LOCATIONS)));
         link(new SPARCUncommonTrapStub(providers, target, registerStubCall(UNCOMMON_TRAP_HANDLER, REEXECUTABLE, LEAF, NO_LOCATIONS)));
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotForeignCallLinkage.java	Wed Nov 12 14:41:32 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotForeignCallLinkage.java	Wed Nov 12 14:43:58 2014 +0100
@@ -22,23 +22,15 @@
  */
 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 {
+public interface HotSpotForeignCallLinkage extends ForeignCallLinkage, InvokeTarget, Remote {
 
     /**
      * Constants for specifying whether a foreign call destroys or preserves registers. A foreign
@@ -65,216 +57,44 @@
     /**
      * 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;
+    long JUMP_ADDRESS = 0xDEADDEADBEEFBEEFL;
 
-    /**
-     * 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 outgoingCallingConvention;
-
-    /**
-     * The calling convention for incoming arguments to the stub, iff this call uses a compiled
-     * {@linkplain Stub stub}.
-     */
-    private final CallingConvention incomingCallingConvention;
-
-    private final RegisterEffect effect;
-
-    private final Transition transition;
+    boolean isReexecutable();
 
-    /**
-     * The registers and stack slots defined/killed by the call.
-     */
-    private Value[] temporaries = AllocatableValue.NONE;
-
-    /**
-     * The memory locations killed by the call.
-     */
-    private final LocationIdentity[] killedLocations;
-
-    private final boolean reexecutable;
+    LocationIdentity[] getKilledLocations();
 
-    /**
-     * 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 outgoingCcType outgoing (caller) calling convention type
-     * @param incomingCcType incoming (callee) calling convention type (can be null)
-     * @param transition specifies if this is a {@linkplain #canDeoptimize() leaf} call
-     * @param reexecutable specifies if the call can be re-executed without (meaningful) side
-     *            effects. Deoptimization will not return to a point before a call that cannot be
-     *            re-executed.
-     * @param killedLocations the memory locations killed by the call
-     */
-    public static HotSpotForeignCallLinkage create(MetaAccessProvider metaAccess, CodeCacheProvider codeCache, HotSpotForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor,
-                    long address, RegisterEffect effect, Type outgoingCcType, Type incomingCcType, Transition transition, boolean reexecutable, LocationIdentity... killedLocations) {
-        CallingConvention outgoingCc = createCallingConvention(metaAccess, codeCache, descriptor, outgoingCcType);
-        CallingConvention incomingCc = incomingCcType == null ? null : createCallingConvention(metaAccess, codeCache, descriptor, incomingCcType);
-        HotSpotForeignCallLinkage linkage = new HotSpotForeignCallLinkage(descriptor, address, effect, transition, outgoingCc, incomingCc, reexecutable, killedLocations);
-        if (outgoingCcType == Type.NativeCall) {
-            linkage.temporaries = foreignCalls.getNativeABICallerSaveRegisters();
-        }
-        return linkage;
-    }
+    CallingConvention getOutgoingCallingConvention();
 
-    /**
-     * Gets a calling convention for a given descriptor and call type.
-     */
-    public static CallingConvention createCallingConvention(MetaAccessProvider metaAccess, CodeCacheProvider codeCache, ForeignCallDescriptor descriptor, Type ccType) {
-        assert ccType != null;
-        Class<?>[] argumentTypes = descriptor.getArgumentTypes();
-        JavaType[] parameterTypes = new JavaType[argumentTypes.length];
-        for (int i = 0; i < parameterTypes.length; ++i) {
-            parameterTypes[i] = asJavaType(argumentTypes[i], metaAccess, codeCache);
-        }
-        TargetDescription target = codeCache.getTarget();
-        JavaType returnType = asJavaType(descriptor.getResultType(), metaAccess, codeCache);
-        RegisterConfig regConfig = codeCache.getRegisterConfig();
-        return regConfig.getCallingConvention(ccType, returnType, parameterTypes, target, false);
-    }
+    CallingConvention getIncomingCallingConvention();
 
-    private static JavaType asJavaType(Class<?> type, MetaAccessProvider metaAccess, CodeCacheProvider codeCache) {
-        if (WordBase.class.isAssignableFrom(type)) {
-            return metaAccess.lookupJavaType(codeCache.getTarget().wordKind.toJavaClass());
-        } else {
-            return metaAccess.lookupJavaType(type);
-        }
-    }
-
-    public HotSpotForeignCallLinkage(ForeignCallDescriptor descriptor, long address, RegisterEffect effect, Transition transition, CallingConvention outgoingCallingConvention,
-                    CallingConvention incomingCallingConvention, boolean reexecutable, LocationIdentity... killedLocations) {
-        this.address = address;
-        this.effect = effect;
-        this.transition = transition;
-        this.descriptor = descriptor;
-        this.outgoingCallingConvention = outgoingCallingConvention;
-        this.incomingCallingConvention = incomingCallingConvention;
-        this.reexecutable = reexecutable;
-        this.killedLocations = killedLocations;
-    }
+    Value[] getTemporaries();
 
-    @Override
-    public String toString() {
-        StringBuilder sb = new StringBuilder(stub == null ? descriptor.toString() : stub.toString());
-        sb.append("@0x").append(Long.toHexString(address)).append(':').append(outgoingCallingConvention).append(":").append(incomingCallingConvention);
-        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 boolean isReexecutable() {
-        return reexecutable;
-    }
-
-    public LocationIdentity[] getKilledLocations() {
-        return killedLocations;
-    }
+    long getMaxCallTargetOffset();
 
-    public CallingConvention getOutgoingCallingConvention() {
-        return outgoingCallingConvention;
-    }
-
-    public CallingConvention getIncomingCallingConvention() {
-        return incomingCallingConvention;
-    }
+    ForeignCallDescriptor getDescriptor();
 
-    public Value[] getTemporaries() {
-        if (temporaries.length == 0) {
-            return temporaries;
-        }
-        return temporaries.clone();
-    }
-
-    public long getMaxCallTargetOffset() {
-        return runtime().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;
-    }
+    void setCompiledStub(Stub stub);
 
     /**
      * Determines if this is a call to a compiled {@linkplain Stub stub}.
      */
-    public boolean isCompiledStub() {
-        return address == 0L || stub != null;
-    }
+    boolean isCompiledStub();
 
-    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);
+    void finalizeAddress(Backend 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();
-        }
-    }
+    long getAddress();
 
-    public long getAddress() {
-        assert address != 0L : "address not yet finalized: " + this;
-        return address;
-    }
+    @Override
+    boolean destroysRegisters();
 
     @Override
-    public boolean destroysRegisters() {
-        return effect == DESTROYS_REGISTERS;
-    }
+    boolean canDeoptimize();
 
-    @Override
-    public boolean canDeoptimize() {
-        return transition == Transition.NOT_LEAF;
-    }
-
-    public boolean mayContainFP() {
-        return transition != Transition.LEAF_NOFP;
-    }
+    boolean mayContainFP();
 
-    public boolean needsJavaFrameAnchor() {
-        return canDeoptimize() || transition == Transition.LEAF_SP;
-    }
+    boolean needsJavaFrameAnchor();
 
-    public CompilationResult getStubCompilationResult(final Backend backend) {
-        return stub.getCompilationResult(backend);
-    }
+    CompilationResult getStubCompilationResult(final Backend backend);
 
-    public Stub getStub() {
-        return stub;
-    }
+    Stub getStub();
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotForeignCallLinkageImpl.java	Wed Nov 12 14:43:58 2014 +0100
@@ -0,0 +1,253 @@
+/*
+ * 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 HotSpotForeignCallLinkageImpl implements HotSpotForeignCallLinkage {
+
+    /**
+     * 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 outgoingCallingConvention;
+
+    /**
+     * The calling convention for incoming arguments to the stub, iff this call uses a compiled
+     * {@linkplain Stub stub}.
+     */
+    private final CallingConvention incomingCallingConvention;
+
+    private final RegisterEffect effect;
+
+    private final Transition transition;
+
+    /**
+     * The registers and stack slots defined/killed by the call.
+     */
+    private Value[] temporaries = AllocatableValue.NONE;
+
+    /**
+     * The memory locations killed by the call.
+     */
+    private final LocationIdentity[] killedLocations;
+
+    private final boolean reexecutable;
+
+    /**
+     * 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 outgoingCcType outgoing (caller) calling convention type
+     * @param incomingCcType incoming (callee) calling convention type (can be null)
+     * @param transition specifies if this is a {@linkplain #canDeoptimize() leaf} call
+     * @param reexecutable specifies if the call can be re-executed without (meaningful) side
+     *            effects. Deoptimization will not return to a point before a call that cannot be
+     *            re-executed.
+     * @param killedLocations the memory locations killed by the call
+     */
+    public static HotSpotForeignCallLinkage create(MetaAccessProvider metaAccess, CodeCacheProvider codeCache, HotSpotForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor,
+                    long address, RegisterEffect effect, Type outgoingCcType, Type incomingCcType, Transition transition, boolean reexecutable, LocationIdentity... killedLocations) {
+        CallingConvention outgoingCc = createCallingConvention(metaAccess, codeCache, descriptor, outgoingCcType);
+        CallingConvention incomingCc = incomingCcType == null ? null : createCallingConvention(metaAccess, codeCache, descriptor, incomingCcType);
+        HotSpotForeignCallLinkageImpl linkage = new HotSpotForeignCallLinkageImpl(descriptor, address, effect, transition, outgoingCc, incomingCc, reexecutable, killedLocations);
+        if (outgoingCcType == Type.NativeCall) {
+            linkage.temporaries = foreignCalls.getNativeABICallerSaveRegisters();
+        }
+        return linkage;
+    }
+
+    /**
+     * Gets a calling convention for a given descriptor and call type.
+     */
+    public static CallingConvention createCallingConvention(MetaAccessProvider metaAccess, CodeCacheProvider codeCache, ForeignCallDescriptor descriptor, Type ccType) {
+        assert ccType != null;
+        Class<?>[] argumentTypes = descriptor.getArgumentTypes();
+        JavaType[] parameterTypes = new JavaType[argumentTypes.length];
+        for (int i = 0; i < parameterTypes.length; ++i) {
+            parameterTypes[i] = asJavaType(argumentTypes[i], metaAccess, codeCache);
+        }
+        TargetDescription target = codeCache.getTarget();
+        JavaType returnType = asJavaType(descriptor.getResultType(), metaAccess, codeCache);
+        RegisterConfig regConfig = codeCache.getRegisterConfig();
+        return regConfig.getCallingConvention(ccType, returnType, parameterTypes, target, false);
+    }
+
+    private static JavaType asJavaType(Class<?> type, MetaAccessProvider metaAccess, CodeCacheProvider codeCache) {
+        if (WordBase.class.isAssignableFrom(type)) {
+            return metaAccess.lookupJavaType(codeCache.getTarget().wordKind.toJavaClass());
+        } else {
+            return metaAccess.lookupJavaType(type);
+        }
+    }
+
+    public HotSpotForeignCallLinkageImpl(ForeignCallDescriptor descriptor, long address, RegisterEffect effect, Transition transition, CallingConvention outgoingCallingConvention,
+                    CallingConvention incomingCallingConvention, boolean reexecutable, LocationIdentity... killedLocations) {
+        this.address = address;
+        this.effect = effect;
+        this.transition = transition;
+        this.descriptor = descriptor;
+        this.outgoingCallingConvention = outgoingCallingConvention;
+        this.incomingCallingConvention = incomingCallingConvention;
+        this.reexecutable = reexecutable;
+        this.killedLocations = killedLocations;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder(stub == null ? descriptor.toString() : stub.toString());
+        sb.append("@0x").append(Long.toHexString(address)).append(':').append(outgoingCallingConvention).append(":").append(incomingCallingConvention);
+        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 boolean isReexecutable() {
+        return reexecutable;
+    }
+
+    public LocationIdentity[] getKilledLocations() {
+        return killedLocations;
+    }
+
+    public CallingConvention getOutgoingCallingConvention() {
+        return outgoingCallingConvention;
+    }
+
+    public CallingConvention getIncomingCallingConvention() {
+        return incomingCallingConvention;
+    }
+
+    public Value[] getTemporaries() {
+        if (temporaries.length == 0) {
+            return temporaries;
+        }
+        return temporaries.clone();
+    }
+
+    public long getMaxCallTargetOffset() {
+        return runtime().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;
+    }
+
+    @Override
+    public boolean canDeoptimize() {
+        return transition == Transition.NOT_LEAF;
+    }
+
+    public boolean mayContainFP() {
+        return transition != Transition.LEAF_NOFP;
+    }
+
+    public boolean needsJavaFrameAnchor() {
+        return canDeoptimize() || transition == Transition.LEAF_SP;
+    }
+
+    public CompilationResult getStubCompilationResult(final Backend backend) {
+        return stub.getCompilationResult(backend);
+    }
+
+    public Stub getStub() {
+        return stub;
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotForeignCallsProviderImpl.java	Wed Nov 12 14:41:32 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotForeignCallsProviderImpl.java	Wed Nov 12 14:43:58 2014 +0100
@@ -80,7 +80,7 @@
      * @param killedLocations the memory locations killed by the stub call
      */
     public HotSpotForeignCallLinkage registerStubCall(ForeignCallDescriptor descriptor, boolean reexecutable, Transition transition, LocationIdentity... killedLocations) {
-        return register(HotSpotForeignCallLinkage.create(metaAccess, codeCache, this, descriptor, 0L, PRESERVES_REGISTERS, JavaCall, JavaCallee, transition, reexecutable, killedLocations));
+        return register(HotSpotForeignCallLinkageImpl.create(metaAccess, codeCache, this, descriptor, 0L, PRESERVES_REGISTERS, JavaCall, JavaCallee, transition, reexecutable, killedLocations));
     }
 
     /**
@@ -102,7 +102,7 @@
         Class<?> resultType = descriptor.getResultType();
         assert address != 0;
         assert transition != NOT_LEAF || resultType.isPrimitive() || Word.class.isAssignableFrom(resultType) : "non-leaf foreign calls must return objects in thread local storage: " + descriptor;
-        return register(HotSpotForeignCallLinkage.create(metaAccess, codeCache, this, descriptor, address, effect, outgoingCcType, null, transition, reexecutable, killedLocations));
+        return register(HotSpotForeignCallLinkageImpl.create(metaAccess, codeCache, this, descriptor, address, effect, outgoingCcType, null, transition, reexecutable, killedLocations));
     }
 
     /**
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java	Wed Nov 12 14:41:32 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java	Wed Nov 12 14:43:58 2014 +0100
@@ -74,12 +74,12 @@
      */
     public ForeignCallStub(HotSpotProviders providers, long address, ForeignCallDescriptor descriptor, boolean prependThread, Transition transition, boolean reexecutable,
                     LocationIdentity... killedLocations) {
-        super(providers, HotSpotForeignCallLinkage.create(providers.getMetaAccess(), providers.getCodeCache(), providers.getForeignCalls(), descriptor, 0L, PRESERVES_REGISTERS, JavaCall, JavaCallee,
-                        transition, reexecutable, killedLocations));
+        super(providers, HotSpotForeignCallLinkageImpl.create(providers.getMetaAccess(), providers.getCodeCache(), providers.getForeignCalls(), descriptor, 0L, PRESERVES_REGISTERS, JavaCall,
+                        JavaCallee, transition, reexecutable, killedLocations));
         this.prependThread = prependThread;
         Class<?>[] targetParameterTypes = createTargetParameters(descriptor);
         ForeignCallDescriptor targetSig = new ForeignCallDescriptor(descriptor.getName() + ":C", descriptor.getResultType(), targetParameterTypes);
-        target = HotSpotForeignCallLinkage.create(providers.getMetaAccess(), providers.getCodeCache(), providers.getForeignCalls(), targetSig, address, DESTROYS_REGISTERS, NativeCall, NativeCall,
+        target = HotSpotForeignCallLinkageImpl.create(providers.getMetaAccess(), providers.getCodeCache(), providers.getForeignCalls(), targetSig, address, DESTROYS_REGISTERS, NativeCall, NativeCall,
                         transition, reexecutable, killedLocations);
     }
 
--- a/src/share/vm/classfile/systemDictionary.hpp	Wed Nov 12 14:41:32 2014 +0100
+++ b/src/share/vm/classfile/systemDictionary.hpp	Wed Nov 12 14:43:58 2014 +0100
@@ -193,7 +193,7 @@
   GRAAL_ONLY(do_klass(HotSpotCompiledCode_Comment_klass,     com_oracle_graal_hotspot_HotSpotCompiledCode_Comment,         Graal)) \
   GRAAL_ONLY(do_klass(HotSpotCompiledNmethod_klass,          com_oracle_graal_hotspot_HotSpotCompiledNmethod,              Graal)) \
   GRAAL_ONLY(do_klass(HotSpotCompiledRuntimeStub_klass,      com_oracle_graal_hotspot_HotSpotCompiledRuntimeStub,          Graal)) \
-  GRAAL_ONLY(do_klass(HotSpotForeignCallLinkage_klass,       com_oracle_graal_hotspot_HotSpotForeignCallLinkage,           Graal)) \
+  GRAAL_ONLY(do_klass(HotSpotForeignCallLinkageImpl_klass,   com_oracle_graal_hotspot_HotSpotForeignCallLinkageImpl,       Graal)) \
   GRAAL_ONLY(do_klass(HotSpotReferenceMap_klass,             com_oracle_graal_hotspot_HotSpotReferenceMap,                 Graal)) \
   GRAAL_ONLY(do_klass(HotSpotInstalledCode_klass,            com_oracle_graal_hotspot_meta_HotSpotInstalledCode,           Graal)) \
   GRAAL_ONLY(do_klass(HotSpotNmethod_klass,                  com_oracle_graal_hotspot_meta_HotSpotNmethod,                 Graal)) \
--- a/src/share/vm/classfile/vmSymbols.hpp	Wed Nov 12 14:41:32 2014 +0100
+++ b/src/share/vm/classfile/vmSymbols.hpp	Wed Nov 12 14:43:58 2014 +0100
@@ -299,7 +299,7 @@
   GRAAL_ONLY(template(com_oracle_graal_hotspot_HotSpotCompiledCode_Comment,     "com/oracle/graal/hotspot/HotSpotCompiledCode$Comment"))          \
   GRAAL_ONLY(template(com_oracle_graal_hotspot_HotSpotCompiledNmethod,          "com/oracle/graal/hotspot/HotSpotCompiledNmethod"))               \
   GRAAL_ONLY(template(com_oracle_graal_hotspot_HotSpotCompiledRuntimeStub,      "com/oracle/graal/hotspot/HotSpotCompiledRuntimeStub"))           \
-  GRAAL_ONLY(template(com_oracle_graal_hotspot_HotSpotForeignCallLinkage,       "com/oracle/graal/hotspot/HotSpotForeignCallLinkage"))            \
+  GRAAL_ONLY(template(com_oracle_graal_hotspot_HotSpotForeignCallLinkageImpl,   "com/oracle/graal/hotspot/HotSpotForeignCallLinkageImpl"))        \
   GRAAL_ONLY(template(com_oracle_graal_hotspot_HotSpotReferenceMap,             "com/oracle/graal/hotspot/HotSpotReferenceMap"))                  \
   GRAAL_ONLY(template(com_oracle_graal_hotspot_bridge_CompilerToVMImpl,         "com/oracle/graal/hotspot/bridge/CompilerToVMImpl"))              \
   GRAAL_ONLY(template(com_oracle_graal_hotspot_meta_HotSpotInstalledCode,       "com/oracle/graal/hotspot/meta/HotSpotInstalledCode"))            \
--- a/src/share/vm/graal/graalCodeInstaller.cpp	Wed Nov 12 14:41:32 2014 +0100
+++ b/src/share/vm/graal/graalCodeInstaller.cpp	Wed Nov 12 14:43:58 2014 +0100
@@ -858,7 +858,7 @@
   oop hotspot_method = NULL; // JavaMethod
   oop foreign_call = NULL;
 
-  if (target_klass->is_subclass_of(SystemDictionary::HotSpotForeignCallLinkage_klass())) {
+  if (target_klass->is_subclass_of(SystemDictionary::HotSpotForeignCallLinkageImpl_klass())) {
     foreign_call = target;
   } else {
     hotspot_method = target;
@@ -882,7 +882,7 @@
   }
 
   if (foreign_call != NULL) {
-    jlong foreign_call_destination = HotSpotForeignCallLinkage::address(foreign_call);
+    jlong foreign_call_destination = HotSpotForeignCallLinkageImpl::address(foreign_call);
     CodeInstaller::pd_relocate_ForeignCall(inst, foreign_call_destination);
   } else { // method != NULL
     assert(hotspot_method != NULL, "unexpected JavaMethod");
--- a/src/share/vm/graal/graalJavaAccess.hpp	Wed Nov 12 14:41:32 2014 +0100
+++ b/src/share/vm/graal/graalJavaAccess.hpp	Wed Nov 12 14:43:58 2014 +0100
@@ -90,8 +90,8 @@
   start_class(HotSpotCompiledRuntimeStub)                                                                                                                      \
     oop_field(HotSpotCompiledRuntimeStub, stubName, "Ljava/lang/String;")                                                                                      \
   end_class                                                                                                                                                    \
-  start_class(HotSpotForeignCallLinkage)                                                                                                                       \
-    long_field(HotSpotForeignCallLinkage, address)                                                                                                             \
+  start_class(HotSpotForeignCallLinkageImpl)                                                                                                                   \
+    long_field(HotSpotForeignCallLinkageImpl, address)                                                                                                         \
   end_class                                                                                                                                                    \
   start_class(ExternalCompilationResult)                                                                                                                       \
     long_field(ExternalCompilationResult, entryPoint)                                                                                                          \