# HG changeset patch # User Doug Simon # Date 1367467682 -7200 # Node ID 789cfd153265a3d928e6c7846a05ff800ec86671 # Parent 3822ce079ec4e7f876ef68ebf2a409760f939c65 a compiled stub can now specify whether it needs to preserve registers. If a stub does not preserve registers and assertions are enabled, then all non-temporary registers are zapped after a C runtime call from the stub. the ExceptionHandler stub no longer preserves registers diff -r 3822ce079ec4 -r 789cfd153265 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Wed May 01 18:08:07 2013 -0700 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Thu May 02 06:08:02 2013 +0200 @@ -825,6 +825,35 @@ public void beforeRegisterAllocation() { } + /** + * Gets an garbage vale for a given kind. + */ + protected Constant zapValueForKind(PlatformKind kind) { + long dead = 0xDEADDEADDEADDEADL; + switch ((Kind) kind) { + case Boolean: + return Constant.FALSE; + case Byte: + return Constant.forByte((byte) dead); + case Char: + return Constant.forChar((char) dead); + case Short: + return Constant.forShort((short) dead); + case Int: + return Constant.forInt((int) dead); + case Double: + return Constant.forDouble(Double.longBitsToDouble(dead)); + case Float: + return Constant.forFloat(Float.intBitsToFloat((int) dead)); + case Long: + return Constant.forLong(dead); + case Object: + return Constant.NULL_OBJECT; + default: + throw new IllegalArgumentException(kind.toString()); + } + } + public abstract void emitBitCount(Variable result, Value operand); public abstract void emitBitScanForward(Variable result, Value operand); diff -r 3822ce079ec4 -r 789cfd153265 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java Wed May 01 18:08:07 2013 -0700 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java Thu May 02 06:08:02 2013 +0200 @@ -173,13 +173,13 @@ if (stub != null) { final Set definedRegisters = gatherDefinedRegisters(lir); - stub.initDefinedRegisters(definedRegisters); + stub.initDestroyedRegisters(definedRegisters); // Eliminate unnecessary register preservation and // record where preserved registers are saved - for (Map.Entry e : gen.calleeSaveInfo.entrySet()) { - AMD64SaveRegistersOp save = e.getValue(); - save.updateAndDescribePreservation(definedRegisters, e.getKey().debugInfo(), frameMap); + for (Map.Entry e : gen.calleeSaveInfo.entrySet()) { + AMD64RegistersPreservationOp save = e.getValue(); + save.update(definedRegisters, e.getKey().debugInfo(), frameMap); } } diff -r 3822ce079ec4 -r 789cfd153265 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 01 18:08:07 2013 -0700 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java Thu May 02 06:08:02 2013 +0200 @@ -176,59 +176,79 @@ * Map from debug infos that need to be updated with callee save information to the operations * that provide the information. */ - Map calleeSaveInfo = new HashMap<>(); + Map calleeSaveInfo = new HashMap<>(); private LIRFrameState currentRuntimeCallInfo; @Override protected void emitCall(RuntimeCallTarget callTarget, Value result, Value[] arguments, Value[] temps, LIRFrameState info) { - boolean needsCalleeSave = ((HotSpotRuntimeCallTarget) callTarget).isCRuntimeCall(); - if (needsCalleeSave) { - currentRuntimeCallInfo = info; - } + currentRuntimeCallInfo = info; super.emitCall(callTarget, result, arguments, temps, info); } @Override public Variable emitCall(RuntimeCallTarget callTarget, CallingConvention cc, DeoptimizingNode info, Value... args) { - boolean needsCalleeSave = ((HotSpotRuntimeCallTarget) callTarget).isCRuntimeCall(); + Stub stub = runtime().asStub(method); + boolean isCRuntimeCall = ((HotSpotRuntimeCallTarget) callTarget).isCRuntimeCall(); + assert !isCRuntimeCall || stub != null : "direct call to C runtime can only be made from compiled stubs, not from " + method; AMD64SaveRegistersOp save = null; StackSlot[] savedRegisterLocations = null; - if (needsCalleeSave) { - Register[] savedRegisters = frameMap.registerConfig.getAllocatableRegisters(); - savedRegisterLocations = new StackSlot[savedRegisters.length]; - AMD64LIRInstruction[] savingMoves = new AMD64LIRInstruction[savedRegisters.length]; - AMD64LIRInstruction[] restoringMoves = new AMD64LIRInstruction[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 (isCRuntimeCall) { + if (stub.preservesRegisters()) { + Register[] savedRegisters = frameMap.registerConfig.getAllocatableRegisters(); + savedRegisterLocations = new StackSlot[savedRegisters.length]; + AMD64LIRInstruction[] savingMoves = new AMD64LIRInstruction[savedRegisters.length]; + AMD64LIRInstruction[] restoringMoves = new AMD64LIRInstruction[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; - RegisterValue register = savedRegisters[i].asValue(kind); - savingMoves[i] = createMove(spillSlot, register); - restoringMoves[i] = createMove(register, spillSlot); + RegisterValue register = savedRegisters[i].asValue(kind); + savingMoves[i] = createMove(spillSlot, register); + restoringMoves[i] = createMove(register, spillSlot); + } + save = new AMD64SaveRegistersOp(savingMoves, restoringMoves, savedRegisterLocations); + append(save); } - save = new AMD64SaveRegistersOp(savingMoves, restoringMoves, savedRegisterLocations); - append(save); - append(new AMD64HotSpotCRuntimeCallPrologueOp()); } Variable result = super.emitCall(callTarget, cc, info, args); - if (needsCalleeSave) { - assert !calleeSaveInfo.containsKey(currentRuntimeCallInfo); - calleeSaveInfo.put(currentRuntimeCallInfo, save); + if (isCRuntimeCall) { + append(new AMD64HotSpotCRuntimeCallEpilogueOp()); + if (stub.preservesRegisters()) { + assert !calleeSaveInfo.containsKey(currentRuntimeCallInfo); + calleeSaveInfo.put(currentRuntimeCallInfo, save); - append(new AMD64HotSpotCRuntimeCallEpilogueOp()); - append(new AMD64RestoreRegistersOp(savedRegisterLocations.clone(), save)); + append(new AMD64RestoreRegistersOp(savedRegisterLocations.clone(), save)); + } else { + assert zapRegisters(); + } } return result; } + protected boolean zapRegisters() { + Register[] zappedRegisters = frameMap.registerConfig.getAllocatableRegisters(); + AMD64LIRInstruction[] zappingMoves = new AMD64LIRInstruction[zappedRegisters.length]; + for (int i = 0; i < zappedRegisters.length; i++) { + PlatformKind kind = target.arch.getLargestStorableKind(zappedRegisters[i].getRegisterCategory()); + assert kind != Kind.Illegal; + + RegisterValue register = zappedRegisters[i].asValue(kind); + zappingMoves[i] = createMove(register, zapValueForKind(kind)); + } + AMD64ZapRegistersOp zap = new AMD64ZapRegistersOp(zappingMoves); + append(zap); + calleeSaveInfo.put(currentRuntimeCallInfo, zap); + return true; + } + @Override protected CallingConvention createCallingConvention() { Stub stub = runtime().asStub(method); diff -r 3822ce079ec4 -r 789cfd153265 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 01 18:08:07 2013 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotRuntimeCallTarget.java Thu May 02 06:08:02 2013 +0200 @@ -99,10 +99,10 @@ argumentLocations[i] = cc.getArgument(i); } - Set definedRegisters = stub.getDefinedRegisters(); - AllocatableValue[] temporaryLocations = new AllocatableValue[definedRegisters.size()]; + Set destroyedRegisters = stub.getDestroyedRegisters(); + AllocatableValue[] temporaryLocations = new AllocatableValue[destroyedRegisters.size()]; int i = 0; - for (Register reg : definedRegisters) { + for (Register reg : destroyedRegisters) { temporaryLocations[i++] = reg.asValue(); } // Update calling convention with temporaries diff -r 3822ce079ec4 -r 789cfd153265 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 01 18:08:07 2013 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Thu May 02 06:08:02 2013 +0200 @@ -316,7 +316,7 @@ /* arg2: value */ Kind.Long, /* arg3: value */ Kind.Long)); - addCRuntimeCall(STUB_PRINTF_C, config.vmMessageAddress, + addCRuntimeCall(VM_MESSAGE_C, config.vmMessageAddress, /* ret */ ret(Kind.Void), /* arg0: vmError */ nativeCallingConvention(Kind.Boolean, /* arg1: format */ word, diff -r 3822ce079ec4 -r 789cfd153265 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ExceptionHandlerStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ExceptionHandlerStub.java Wed May 01 18:08:07 2013 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ExceptionHandlerStub.java Thu May 02 06:08:02 2013 +0200 @@ -52,6 +52,16 @@ super(runtime, replacements, target, linkage); } + /** + * This stub is called when returning to a method to handle an exception thrown by a callee. It + * is not used for routing implicit exceptions. Therefore, it does not need to save any + * registers as HotSpot uses a caller save convention. + */ + @Override + public boolean preservesRegisters() { + return false; + } + @Snippet private static void exceptionHandler(Object exception, Word exceptionPc) { checkNoExceptionInThread(); @@ -64,8 +74,6 @@ // patch throwing pc into return address so that deoptimization finds the right debug info patchReturnAddress(exceptionPc); - // TODO (ds) add support for non-register-preserving C runtime calls and - // use it for this call as no registers need saving by this stub Word handlerPc = exceptionHandlerForPc(EXCEPTION_HANDLER_FOR_PC, thread()); if (logging()) { diff -r 3822ce079ec4 -r 789cfd153265 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java Wed May 01 18:08:07 2013 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java Thu May 02 06:08:02 2013 +0200 @@ -88,19 +88,31 @@ protected InstalledCode code; /** - * The registers/temporaries defined by this stub. + * The registers destroyed by this stub. */ - private Set definedRegisters; + private Set destroyedRegisters; - public void initDefinedRegisters(Set registers) { + public void initDestroyedRegisters(Set registers) { assert registers != null; - assert definedRegisters == null || registers.equals(definedRegisters) : "cannot redefine"; - definedRegisters = registers; + assert destroyedRegisters == null || registers.equals(destroyedRegisters) : "cannot redefine"; + destroyedRegisters = registers; } - public Set getDefinedRegisters() { - assert definedRegisters != null : "not yet initialized"; - return definedRegisters; + /** + * Gets the registers defined by this stub. These are the temporaries of this stub and must thus + * be caller saved by a callers of this stub. + */ + public Set getDestroyedRegisters() { + assert destroyedRegisters != null : "not yet initialized"; + return destroyedRegisters; + } + + /** + * Determines if this stub preserves all registers apart from those it + * {@linkplain #getDestroyedRegisters() destroys}. + */ + public boolean preservesRegisters() { + return true; } /** @@ -198,7 +210,7 @@ assert checkStubInvariants(compResult); - assert definedRegisters != null; + assert destroyedRegisters != null; code = Debug.scope("CodeInstall", new Callable() { @Override @@ -259,10 +271,10 @@ } } - public static final Descriptor STUB_PRINTF_C = descriptorFor(Stub.class, "printfC", false); + public static final Descriptor VM_MESSAGE_C = descriptorFor(Stub.class, "vmMessageC", false); @NodeIntrinsic(CRuntimeCall.class) - private static native void printfC(@ConstantNodeParameter Descriptor stubPrintfC, boolean vmError, Word format, long v1, long v2, long v3); + private static native void vmMessageC(@ConstantNodeParameter Descriptor stubPrintfC, boolean vmError, Word format, long v1, long v2, long v3); /** * Prints a message to the log stream. @@ -273,7 +285,7 @@ * @param message a message string */ public static void printf(String message) { - printfC(STUB_PRINTF_C, false, cstring(message), 0L, 0L, 0L); + vmMessageC(VM_MESSAGE_C, false, cstring(message), 0L, 0L, 0L); } /** @@ -286,7 +298,7 @@ * @param value the value associated with the first conversion specifier in {@code format} */ public static void printf(String format, long value) { - printfC(STUB_PRINTF_C, false, cstring(format), value, 0L, 0L); + vmMessageC(VM_MESSAGE_C, false, cstring(format), value, 0L, 0L); } /** @@ -300,7 +312,7 @@ * @param v2 the value associated with the second conversion specifier in {@code format} */ public static void printf(String format, long v1, long v2) { - printfC(STUB_PRINTF_C, false, cstring(format), v1, v2, 0L); + vmMessageC(VM_MESSAGE_C, false, cstring(format), v1, v2, 0L); } /** @@ -315,7 +327,7 @@ * @param v3 the value associated with the third conversion specifier in {@code format} */ public static void printf(String format, long v1, long v2, long v3) { - printfC(STUB_PRINTF_C, false, cstring(format), v1, v2, v3); + vmMessageC(VM_MESSAGE_C, false, cstring(format), v1, v2, v3); } /** @@ -327,7 +339,7 @@ * @param message an error message */ public static void fatal(String message) { - printfC(STUB_PRINTF_C, true, cstring(message), 0L, 0L, 0L); + vmMessageC(VM_MESSAGE_C, true, cstring(message), 0L, 0L, 0L); } /** @@ -340,7 +352,7 @@ * @param value the value associated with the first conversion specifier in {@code format} */ public static void fatal(String format, long value) { - printfC(STUB_PRINTF_C, true, cstring(format), value, 0L, 0L); + vmMessageC(VM_MESSAGE_C, true, cstring(format), value, 0L, 0L); } /** @@ -354,7 +366,7 @@ * @param v2 the value associated with the second conversion specifier in {@code format} */ public static void fatal(String format, long v1, long v2) { - printfC(STUB_PRINTF_C, true, cstring(format), v1, v2, 0L); + vmMessageC(VM_MESSAGE_C, true, cstring(format), v1, v2, 0L); } /** @@ -369,6 +381,6 @@ * @param v3 the value associated with the third conversion specifier in {@code format} */ public static void fatal(String format, long v1, long v2, long v3) { - printfC(STUB_PRINTF_C, true, cstring(format), v1, v2, v3); + vmMessageC(VM_MESSAGE_C, true, cstring(format), v1, v2, v3); } } diff -r 3822ce079ec4 -r 789cfd153265 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64RegistersPreservationOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64RegistersPreservationOp.java Thu May 02 06:08:02 2013 +0200 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.lir.amd64; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.lir.*; + +/** + * Base class for operations that preserve a set of registers. + */ +public abstract class AMD64RegistersPreservationOp extends AMD64LIRInstruction { + + /** + * Prunes the set of registers preserved by this operation to exclude those in {@code ignored} + * and updates {@code debugInfo} with a {@linkplain DebugInfo#getCalleeSaveInfo() description} + * of where each preserved register is saved. + */ + public abstract void update(Set ignored, DebugInfo debugInfo, FrameMap frameMap); +} diff -r 3822ce079ec4 -r 789cfd153265 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64SaveRegistersOp.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64SaveRegistersOp.java Wed May 01 18:08:07 2013 -0700 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64SaveRegistersOp.java Thu May 02 06:08:02 2013 +0200 @@ -37,7 +37,7 @@ * Saves registers to stack slots. */ @Opcode("SAVE_REGISTER") -public final class AMD64SaveRegistersOp extends AMD64LIRInstruction { +public final class AMD64SaveRegistersOp extends AMD64RegistersPreservationOp { /** * The move instructions for saving the registers. @@ -70,16 +70,17 @@ } /** - * Prunes the set of registers saved by this operation to exclude those in {@code notSaved} and + * Prunes the set of registers saved by this operation to exclude those in {@code ignored} and * updates {@code debugInfo} with a {@linkplain DebugInfo#getCalleeSaveInfo() description} of * where each preserved register is saved. */ - public void updateAndDescribePreservation(Set notSaved, DebugInfo debugInfo, FrameMap frameMap) { + @Override + public void update(Set ignored, DebugInfo debugInfo, FrameMap frameMap) { int preserved = 0; for (int i = 0; i < savingMoves.length; i++) { if (savingMoves[i] != null) { Register register = ValueUtil.asRegister(((MoveOp) savingMoves[i]).getInput()); - if (notSaved.contains(register)) { + if (ignored.contains(register)) { savingMoves[i] = null; restoringMoves[i] = null; } else { diff -r 3822ce079ec4 -r 789cfd153265 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ZapRegistersOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ZapRegistersOp.java Thu May 02 06:08:02 2013 +0200 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.lir.amd64; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.LIRInstruction.Opcode; +import com.oracle.graal.lir.StandardOp.MoveOp; +import com.oracle.graal.lir.asm.*; + +/** + * Writes well known garbage values to registers. + */ +@Opcode("ZAP_REGISTER") +public final class AMD64ZapRegistersOp extends AMD64RegistersPreservationOp { + + /** + * The move instructions for zapping the registers. + */ + protected final AMD64LIRInstruction[] zappingMoves; + + public AMD64ZapRegistersOp(AMD64LIRInstruction[] zappingMoves) { + this.zappingMoves = zappingMoves; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + for (AMD64LIRInstruction zappingMove : zappingMoves) { + if (zappingMove != null) { + zappingMove.emitCode(tasm, masm); + } + } + } + + /** + * Prunes the set of registers zapped by this operation to exclude those in {@code ignored}. + */ + @Override + public void update(Set ignored, DebugInfo debugInfo, FrameMap frameMap) { + for (int i = 0; i < zappingMoves.length; i++) { + if (zappingMoves[i] != null) { + Register register = ValueUtil.asRegister(((MoveOp) zappingMoves[i]).getResult()); + if (ignored.contains(register)) { + zappingMoves[i] = null; + } + } + } + } +}