# HG changeset patch # User Doug Simon # Date 1368646645 -7200 # Node ID f7bd4594cbbf03736cd00a83eb4a0d497ad490ce # Parent d58ebf85443e8f20fb7a57bdd4e5bb86f199e7ff added support for declaring a foreign function call to be a leaf diff -r d58ebf85443e -r f7bd4594cbbf graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java --- 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(); + } } } diff -r d58ebf85443e -r f7bd4594cbbf graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRuntime.java --- 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); diff -r d58ebf85443e -r f7bd4594cbbf graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotRuntimeCallTarget.java --- 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; + } } diff -r d58ebf85443e -r f7bd4594cbbf graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java --- 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); diff -r d58ebf85443e -r f7bd4594cbbf graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java --- 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) { diff -r d58ebf85443e -r f7bd4594cbbf graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/RuntimeCallStub.java --- 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); } /**