changeset 9731:f7bd4594cbbf

added support for declaring a foreign function call to be a leaf
author Doug Simon <doug.simon@oracle.com>
date Wed, 15 May 2013 21:37:25 +0200
parents d58ebf85443e
children 1a5fbe41b8d4
files 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/AMD64HotSpotRuntime.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotRuntimeCallTarget.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/RuntimeCallStub.java
diffstat 6 files changed, 73 insertions(+), 51 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Wed May 15 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Wed May 15 21:37:25 2013 +0200
@@ -211,37 +211,46 @@
     @Override
     public Variable emitCall(RuntimeCallTarget callTarget, CallingConvention callCc, 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;
+        HotSpotRuntimeCallTarget hsCallTarget = (HotSpotRuntimeCallTarget) callTarget;
+        boolean destroysRegisters = hsCallTarget.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 (!hsCallTarget.isLeaf()) {
             append(new AMD64HotSpotCRuntimeCallPrologueOp());
         }
 
         Variable result = super.emitCall(callTarget, callCc, info, args);
 
-        if (destroysRegisters) {
+        if (!hsCallTarget.isLeaf()) {
             append(new AMD64HotSpotCRuntimeCallEpilogueOp());
-            if (stub.preservesRegisters()) {
-                assert !calleeSaveInfo.containsKey(currentRuntimeCallInfo);
-                calleeSaveInfo.put(currentRuntimeCallInfo, save);
+        }
 
-                emitRestoreRegisters(save);
-            } else {
-                assert zapRegisters();
+        if (destroysRegisters) {
+            if (stub != null) {
+                if (stub.preservesRegisters()) {
+                    assert !calleeSaveInfo.containsKey(currentRuntimeCallInfo);
+                    calleeSaveInfo.put(currentRuntimeCallInfo, save);
+
+                    emitRestoreRegisters(save);
+                } else {
+                    assert zapRegisters();
+                }
             }
         }
 
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRuntime.java	Wed May 15 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRuntime.java	Wed May 15 21:37:25 2013 +0200
@@ -27,6 +27,7 @@
 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.HotSpotRuntimeCallTarget.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.*;
@@ -60,8 +61,8 @@
         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()));
+        register(new HotSpotRuntimeCallTarget(EXCEPTION_HANDLER, 0L, PRESERVES_REGISTERS, LEAF, exceptionCc));
+        register(new HotSpotRuntimeCallTarget(EXCEPTION_HANDLER_IN_CALLER, JUMP_ADDRESS, PRESERVES_REGISTERS, LEAF, exceptionCc));
 
         // The crypto stubs do callee saving
         registerLeafCall(ENCRYPT_BLOCK, config.aescryptEncryptBlockStub, NativeCall, PRESERVES_REGISTERS);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotRuntimeCallTarget.java	Wed May 15 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotRuntimeCallTarget.java	Wed May 15 21:37:25 2013 +0200
@@ -31,7 +31,6 @@
 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.*;
@@ -51,6 +50,15 @@
     }
 
     /**
+     * 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;
@@ -75,9 +83,9 @@
      */
     private CallingConvention cc;
 
-    private final CompilerToVM vm;
+    private final RegisterEffect effect;
 
-    private final RegisterEffect effect;
+    private final Transition transition;
 
     /**
      * Creates a {@link HotSpotRuntimeCallTarget}.
@@ -87,18 +95,18 @@
      * @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
+     * @param transition specifies if this is a {@linkplain #isLeaf() leaf} call
      */
-    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 static HotSpotRuntimeCallTarget create(Descriptor descriptor, long address, RegisterEffect effect, Type ccType, Transition transition) {
+        CallingConvention targetCc = createCallingConvention(descriptor, ccType);
+        return new HotSpotRuntimeCallTarget(descriptor, address, effect, transition, targetCc);
     }
 
     /**
      * Gets a calling convention for a given descriptor and call type.
      */
-    public static CallingConvention createCallingConvention(Descriptor descriptor, Type ccType, RegisterConfig ccProvider, HotSpotRuntime runtime) {
+    public static CallingConvention createCallingConvention(Descriptor 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) {
@@ -106,7 +114,7 @@
         }
         TargetDescription target = graalRuntime().getTarget();
         JavaType returnType = asJavaType(descriptor.getResultType(), runtime);
-        return ccProvider.getCallingConvention(ccType, returnType, parameterTypes, target, false);
+        return runtime.lookupRegisterConfig().getCallingConvention(ccType, returnType, parameterTypes, target, false);
     }
 
     private static JavaType asJavaType(Class type, HotSpotRuntime runtime) {
@@ -117,12 +125,12 @@
         }
     }
 
-    public HotSpotRuntimeCallTarget(Descriptor descriptor, long address, RegisterEffect effect, CallingConvention cc, CompilerToVM vm) {
+    public HotSpotRuntimeCallTarget(Descriptor descriptor, long address, RegisterEffect effect, Transition transition, CallingConvention cc) {
         this.address = address;
         this.effect = effect;
+        this.transition = transition;
         this.descriptor = descriptor;
         this.cc = cc;
-        this.vm = vm;
     }
 
     @Override
@@ -135,7 +143,7 @@
     }
 
     public long getMaxCallTargetOffset() {
-        return vm.getMaxCallTargetOffset(address);
+        return graalRuntime().getCompilerToVM().getMaxCallTargetOffset(address);
     }
 
     public Descriptor getDescriptor() {
@@ -180,4 +188,12 @@
     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/meta/HotSpotRuntime.java	Wed May 15 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Wed May 15 21:37:25 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.HotSpotGraalRuntime.*;
 import static com.oracle.graal.hotspot.HotSpotRuntimeCallTarget.RegisterEffect.*;
+import static com.oracle.graal.hotspot.HotSpotRuntimeCallTarget.Transition.*;
 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 +41,6 @@
 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.*;
@@ -74,7 +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.HotSpotRuntimeCallTarget.RegisterEffect;
 import com.oracle.graal.hotspot.bridge.*;
 import com.oracle.graal.hotspot.bridge.CompilerToVM.CodeInstallResult;
 import com.oracle.graal.hotspot.nodes.*;
@@ -101,6 +101,7 @@
 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 Descriptor IDENTITY_HASHCODE = new Descriptor("identity_hashcode", false, int.class, Object.class);
 
     public final HotSpotVMConfig config;
 
@@ -193,7 +194,7 @@
      * Registers the details for linking a call to a {@link Stub}.
      */
     protected RuntimeCallTarget registerStubCall(Descriptor descriptor) {
-        return register(HotSpotRuntimeCallTarget.create(descriptor, 0L, PRESERVES_REGISTERS, JavaCallee, regConfig, this, graalRuntime.getCompilerToVM()));
+        return register(HotSpotRuntimeCallTarget.create(descriptor, 0L, PRESERVES_REGISTERS, JavaCallee, NOT_LEAF));
     }
 
     /**
@@ -202,14 +203,14 @@
     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()));
+        return register(HotSpotRuntimeCallTarget.create(descriptor, address, DESTROYS_REGISTERS, NativeCall, NOT_LEAF));
     }
 
     /**
      * 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, regConfig, this, graalRuntime.getCompilerToVM()));
+        return register(HotSpotRuntimeCallTarget.create(descriptor, address, PRESERVES_REGISTERS, ccType, NOT_LEAF));
     }
 
     /**
@@ -218,7 +219,7 @@
      * another thread.
      */
     protected RuntimeCallTarget registerLeafCall(Descriptor descriptor, long address, CallingConvention.Type ccType, RegisterEffect effect) {
-        return register(HotSpotRuntimeCallTarget.create(descriptor, address, effect, ccType, regConfig, this, graalRuntime.getCompilerToVM()));
+        return register(HotSpotRuntimeCallTarget.create(descriptor, address, effect, ccType, LEAF));
     }
 
     protected abstract RegisterConfig createRegisterConfig();
@@ -320,7 +321,7 @@
     }
 
     private void linkRuntimeCall(Descriptor descriptor, long address, Replacements replacements) {
-        RuntimeCallStub stub = new RuntimeCallStub(address, descriptor, true, this, replacements, regConfig, graalRuntime.getCompilerToVM());
+        RuntimeCallStub stub = new RuntimeCallStub(address, descriptor, true, this, replacements);
         HotSpotRuntimeCallTarget linkage = stub.getLinkage();
         HotSpotRuntimeCallTarget targetLinkage = stub.getTargetLinkage();
         linkage.setCompiledStub(stub);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java	Wed May 15 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java	Wed May 15 21:37:25 2013 +0200
@@ -23,6 +23,7 @@
 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.*;
 
@@ -672,8 +673,6 @@
         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) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/RuntimeCallStub.java	Wed May 15 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/RuntimeCallStub.java	Wed May 15 21:37:25 2013 +0200
@@ -26,6 +26,7 @@
 import static com.oracle.graal.api.meta.MetaUtil.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 import static com.oracle.graal.hotspot.HotSpotRuntimeCallTarget.RegisterEffect.*;
+import static com.oracle.graal.hotspot.HotSpotRuntimeCallTarget.Transition.*;
 
 import java.lang.reflect.*;
 
@@ -34,7 +35,6 @@
 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.*;
@@ -74,17 +74,13 @@
      * @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));
+    public RuntimeCallStub(long address, Descriptor sig, boolean prependThread, HotSpotRuntime runtime, Replacements replacements) {
+        super(runtime, replacements, HotSpotRuntimeCallTarget.create(sig, 0L, PRESERVES_REGISTERS, JavaCallee, NOT_LEAF));
         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);
+        target = HotSpotRuntimeCallTarget.create(targetSig, address, DESTROYS_REGISTERS, NativeCall, NOT_LEAF);
     }
 
     /**