# HG changeset patch # User Gilles Duboscq # Date 1367846733 -7200 # Node ID d6bf345d58c137e6b7ffe2ce44fca79a13322d53 # Parent f0ef8f58a1d909796c131317466ab172c785749c# Parent f64a3fec4e428a289a91e84d122cd153ac78d0fc Merge diff -r f0ef8f58a1d9 -r d6bf345d58c1 graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java --- a/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java Mon May 06 15:25:18 2013 +0200 +++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java Mon May 06 15:25:33 2013 +0200 @@ -513,6 +513,13 @@ emitOperandHelper(dst, src); } + public final void cmpl(AMD64Address dst, int imm32) { + prefix(dst); + emitByte(0x81); + emitOperandHelper(7, dst); + emitInt(imm32); + } + // The 32-bit cmpxchg compares the value at adr with the contents of X86.rax, // and stores reg into adr if so; otherwise, the value at adr is loaded into X86.rax,. // The ZF is set if the compared values were equal, and cleared otherwise. diff -r f0ef8f58a1d9 -r d6bf345d58c1 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotDeoptimizeCallerOp.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotDeoptimizeCallerOp.java Mon May 06 15:25:18 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotDeoptimizeCallerOp.java Mon May 06 15:25:33 2013 +0200 @@ -22,8 +22,6 @@ */ package com.oracle.graal.hotspot.amd64; -import static com.oracle.graal.amd64.AMD64.*; -import static com.oracle.graal.api.code.ValueUtil.*; import static com.oracle.graal.hotspot.HotSpotBackend.*; import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; @@ -51,18 +49,8 @@ @Override public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - if (isStackSlot(savedRbp)) { - // Restoring RBP from the stack must be done before the frame is removed - masm.movq(rbp, (AMD64Address) tasm.asAddress(savedRbp)); - } else { - Register framePointer = asRegister(savedRbp); - if (framePointer != rbp) { - masm.movq(rbp, framePointer); - } - } - if (tasm.frameContext != null) { - tasm.frameContext.leave(tasm); - } + leaveFrameAndRestoreRbp(tasm, masm); + HotSpotGraalRuntime runtime = graalRuntime(); Register thread = runtime.getRuntime().threadRegister(); masm.movl(new AMD64Address(thread, runtime.getConfig().pendingDeoptimizationOffset), tasm.runtime.encodeDeoptActionAndReason(action, reason)); diff -r f0ef8f58a1d9 -r d6bf345d58c1 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotEpilogueOp.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotEpilogueOp.java Mon May 06 15:25:18 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotEpilogueOp.java Mon May 06 15:25:33 2013 +0200 @@ -22,11 +22,16 @@ */ package com.oracle.graal.hotspot.amd64; +import static com.oracle.graal.amd64.AMD64.*; +import static com.oracle.graal.api.code.ValueUtil.*; import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; +import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.amd64.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.amd64.*; +import com.oracle.graal.lir.asm.*; /** * Superclass for operations that use the value of RBP saved in a method's prologue. @@ -41,4 +46,19 @@ private static final Variable PLACEHOLDER = new Variable(Kind.Long, Integer.MAX_VALUE); @Use({REG, STACK}) protected AllocatableValue savedRbp = PLACEHOLDER; + + protected void leaveFrameAndRestoreRbp(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + if (isStackSlot(savedRbp)) { + // Restoring RBP from the stack must be done before the frame is removed + masm.movq(rbp, (AMD64Address) tasm.asAddress(savedRbp)); + } else { + Register framePointer = asRegister(savedRbp); + if (framePointer != rbp) { + masm.movq(rbp, framePointer); + } + } + if (tasm.frameContext != null) { + tasm.frameContext.leave(tasm); + } + } } diff -r f0ef8f58a1d9 -r d6bf345d58c1 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotJumpToExceptionHandlerInCallerOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotJumpToExceptionHandlerInCallerOp.java Mon May 06 15:25:33 2013 +0200 @@ -0,0 +1,70 @@ +/* + * 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.amd64; + +import static com.oracle.graal.amd64.AMD64.*; +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.asm.amd64.AMD64Assembler.ConditionFlag; +import com.oracle.graal.lir.LIRInstruction.Opcode; +import com.oracle.graal.lir.asm.*; + +/** + * Sets up the arguments for an exception handler in the callers frame, removes the current frame + * and jumps to the handler. + */ +@Opcode("JUMP_TO_EXCEPTION_HANDLER_IN_CALLER") +final class AMD64HotSpotJumpToExceptionHandlerInCallerOp extends AMD64HotSpotEpilogueOp { + + @Use(REG) AllocatableValue handlerInCallerPc; + @Use(REG) AllocatableValue exception; + @Use(REG) AllocatableValue exceptionPc; + + AMD64HotSpotJumpToExceptionHandlerInCallerOp(AllocatableValue handlerInCallerPc, AllocatableValue exception, AllocatableValue exceptionPc) { + this.handlerInCallerPc = handlerInCallerPc; + this.exception = exception; + this.exceptionPc = exceptionPc; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + leaveFrameAndRestoreRbp(tasm, masm); + + // Discard the return address, thus completing restoration of caller frame + masm.incrementq(rsp, 8); + + // Restore rsp from rbp if the exception PC is a method handle call site. + Register thread = graalRuntime().getRuntime().threadRegister(); + int isMethodHandleReturnOffset = graalRuntime().getConfig().threadIsMethodHandleReturnOffset; + AMD64Address dst = new AMD64Address(thread, isMethodHandleReturnOffset); + masm.cmpl(dst, 0); + masm.cmovq(ConditionFlag.NotEqual, rsp, rbp); + + masm.jmp(asRegister(handlerInCallerPc)); + } +} diff -r f0ef8f58a1d9 -r d6bf345d58c1 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 Mon May 06 15:25:18 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java Mon May 06 15:25:33 2013 +0200 @@ -25,7 +25,7 @@ import static com.oracle.graal.amd64.AMD64.*; import static com.oracle.graal.api.code.CallingConvention.Type.*; import static com.oracle.graal.api.code.ValueUtil.*; -import static com.oracle.graal.hotspot.amd64.AMD64HotSpotUnwindOp.*; +import static com.oracle.graal.hotspot.HotSpotBackend.*; import java.lang.reflect.*; import java.util.*; @@ -115,6 +115,14 @@ */ List epilogueOps = new ArrayList<>(2); + @Override + public void append(LIRInstruction op) { + super.append(op); + if (op instanceof AMD64HotSpotEpilogueOp) { + epilogueOps.add((AMD64HotSpotEpilogueOp) op); + } + } + @SuppressWarnings("hiding") @Override protected DebugInfoBuilder createDebugInfoBuilder(NodeMap nodeOperands) { @@ -161,9 +169,7 @@ @Override protected void emitReturn(Value input) { - AMD64HotSpotReturnOp op = new AMD64HotSpotReturnOp(input); - epilogueOps.add(op); - append(op); + append(new AMD64HotSpotReturnOp(input)); } @Override @@ -333,11 +339,12 @@ @Override public void emitUnwind(Value exception) { - RegisterValue exceptionParameter = EXCEPTION.asValue(); + RuntimeCallTarget stub = getRuntime().lookupRuntimeCall(HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER); + CallingConvention cc = stub.getCallingConvention(); + assert cc.getArgumentCount() == 2; + RegisterValue exceptionParameter = (RegisterValue) cc.getArgument(0); emitMove(exceptionParameter, exception); - AMD64HotSpotUnwindOp op = new AMD64HotSpotUnwindOp(exceptionParameter); - epilogueOps.add(op); - append(op); + append(new AMD64HotSpotUnwindOp(exceptionParameter)); } @Override @@ -347,15 +354,25 @@ @Override public void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason) { - AMD64HotSpotDeoptimizeCallerOp op = new AMD64HotSpotDeoptimizeCallerOp(action, reason); - epilogueOps.add(op); - append(op); + append(new AMD64HotSpotDeoptimizeCallerOp(action, reason)); } @Override public void emitPatchReturnAddress(ValueNode address) { - load(operand(address)); - AMD64HotSpotPatchReturnAddressOp op = new AMD64HotSpotPatchReturnAddressOp(load(operand(address))); + append(new AMD64HotSpotPatchReturnAddressOp(load(operand(address)))); + } + + @Override + public void emitJumpToExceptionHandlerInCaller(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc) { + Variable handler = load(operand(handlerInCallerPc)); + RuntimeCallTarget stub = getRuntime().lookupRuntimeCall(EXCEPTION_HANDLER_IN_CALLER); + CallingConvention cc = stub.getCallingConvention(); + assert cc.getArgumentCount() == 2; + RegisterValue exceptionFixed = (RegisterValue) cc.getArgument(0); + RegisterValue exceptionPcFixed = (RegisterValue) cc.getArgument(1); + emitMove(exceptionFixed, operand(exception)); + emitMove(exceptionPcFixed, operand(exceptionPc)); + AMD64HotSpotJumpToExceptionHandlerInCallerOp op = new AMD64HotSpotJumpToExceptionHandlerInCallerOp(handler, exceptionFixed, exceptionPcFixed); append(op); } diff -r f0ef8f58a1d9 -r d6bf345d58c1 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotReturnOp.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotReturnOp.java Mon May 06 15:25:18 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotReturnOp.java Mon May 06 15:25:33 2013 +0200 @@ -22,11 +22,8 @@ */ package com.oracle.graal.hotspot.amd64; -import static com.oracle.graal.amd64.AMD64.*; -import static com.oracle.graal.api.code.ValueUtil.*; import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; -import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.amd64.*; import com.oracle.graal.lir.LIRInstruction.Opcode; @@ -46,18 +43,7 @@ @Override public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - if (isStackSlot(savedRbp)) { - // Restoring RBP from the stack must be done before the frame is removed - masm.movq(rbp, (AMD64Address) tasm.asAddress(savedRbp)); - } else { - Register framePointer = asRegister(savedRbp); - if (framePointer != rbp) { - masm.movq(rbp, framePointer); - } - } - if (tasm.frameContext != null) { - tasm.frameContext.leave(tasm); - } + leaveFrameAndRestoreRbp(tasm, masm); masm.ret(0); } } diff -r f0ef8f58a1d9 -r d6bf345d58c1 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 Mon May 06 15:25:18 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRuntime.java Mon May 06 15:25:33 2013 +0200 @@ -25,7 +25,6 @@ import static com.oracle.graal.amd64.AMD64.*; import static com.oracle.graal.compiler.amd64.AMD64LIRGenerator.*; import static com.oracle.graal.hotspot.HotSpotBackend.*; -import static com.oracle.graal.hotspot.amd64.AMD64HotSpotUnwindOp.*; import static com.oracle.graal.hotspot.nodes.MonitorEnterStubCall.*; import static com.oracle.graal.hotspot.nodes.MonitorExitStubCall.*; import static com.oracle.graal.hotspot.nodes.VMErrorNode.*; @@ -55,15 +54,18 @@ Kind word = graalRuntime.getTarget().wordKind; // @formatter:off + + // The calling convention for the exception handler stub is (only?) defined in + // TemplateInterpreterGenerator::generate_throw_exception() + // in templateInterpreter_x86_64.cpp around line 1923 addStubCall(EXCEPTION_HANDLER, - /* ret */ ret(Kind.Void), + /* ret */ ret(Kind.Void), /* arg0: exception */ rax.asValue(Kind.Object), /* arg1: exceptionPc */ rdx.asValue(word)); - addRuntimeCall(UNWIND_EXCEPTION, config.unwindExceptionStub, - /* temps */ null, - /* ret */ ret(Kind.Void), - /* arg0: exception */ rax.asValue(Kind.Object)); + addJump(EXCEPTION_HANDLER_IN_CALLER, + /* arg0: exception */ rax.asValue(Kind.Object), + /* arg1: exceptionPc */ rdx.asValue(word)); addRuntimeCall(ARITHMETIC_FREM, config.arithmeticFremStub, /* temps */ new Register[]{AMD64.rax}, diff -r f0ef8f58a1d9 -r d6bf345d58c1 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotUnwindOp.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotUnwindOp.java Mon May 06 15:25:18 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotUnwindOp.java Mon May 06 15:25:33 2013 +0200 @@ -24,53 +24,42 @@ import static com.oracle.graal.amd64.AMD64.*; import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.hotspot.HotSpotBackend.*; import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; -import com.oracle.graal.amd64.*; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; -import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.stubs.*; import com.oracle.graal.lir.LIRInstruction.Opcode; import com.oracle.graal.lir.amd64.*; import com.oracle.graal.lir.asm.*; /** - * Performs an unwind to throw an exception. + * Removes the current frame and jumps to the {@link UnwindExceptionToCallerStub}. */ @Opcode("UNWIND") final class AMD64HotSpotUnwindOp extends AMD64HotSpotEpilogueOp { - public static final Descriptor UNWIND_EXCEPTION = new Descriptor("unwindException", true, void.class, Object.class); + @Use({REG}) protected RegisterValue exception; - /** - * Unwind stub expects the exception in RAX. - */ - public static final Register EXCEPTION = AMD64.rax; - - @Use({REG}) protected AllocatableValue exception; - - AMD64HotSpotUnwindOp(AllocatableValue exception) { + AMD64HotSpotUnwindOp(RegisterValue exception) { this.exception = exception; - assert asRegister(exception) == EXCEPTION; } @Override public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - // Copy the saved RBP value into the slot just below the return address - // so that the stub can pick it up from there. - AMD64Address rbpSlot; - int rbpSlotOffset = tasm.frameMap.frameSize() - 8; - if (isStackSlot(savedRbp)) { - rbpSlot = (AMD64Address) tasm.asAddress(savedRbp); - assert rbpSlot.getDisplacement() == rbpSlotOffset; - } else { - rbpSlot = new AMD64Address(rsp, rbpSlotOffset); - masm.movq(rbpSlot, asRegister(savedRbp)); - } + leaveFrameAndRestoreRbp(tasm, masm); - // Pass the address of the RBP slot in RBP itself - masm.leaq(rbp, rbpSlot); - AMD64Call.directCall(tasm, masm, tasm.runtime.lookupRuntimeCall(UNWIND_EXCEPTION), AMD64.r10, false, null); + RuntimeCallTarget stub = tasm.runtime.lookupRuntimeCall(UNWIND_EXCEPTION_TO_CALLER); + CallingConvention cc = stub.getCallingConvention(); + assert cc.getArgumentCount() == 2; + assert exception == cc.getArgument(0); + + // Get return address (is on top of stack after leave). + Register returnAddress = asRegister(cc.getArgument(1)); + masm.movq(returnAddress, new AMD64Address(rsp, 0)); + + AMD64Call.directJmp(tasm, masm, tasm.runtime.lookupRuntimeCall(HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER)); } } diff -r f0ef8f58a1d9 -r d6bf345d58c1 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java Mon May 06 15:25:18 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java Mon May 06 15:25:33 2013 +0200 @@ -28,6 +28,7 @@ import com.oracle.graal.hotspot.bridge.*; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.stubs.*; +import com.oracle.graal.nodes.*; import com.oracle.graal.word.*; /** @@ -56,6 +57,17 @@ */ public static final Descriptor IC_MISS_HANDLER = new Descriptor("icMissHandler", true, void.class); + /** + * Descriptor for {@link UnwindExceptionToCallerStub}. This stub is called by code generated + * from {@link UnwindNode}. + */ + public static final Descriptor UNWIND_EXCEPTION_TO_CALLER = new Descriptor("unwindExceptionToCaller", true, void.class, Object.class, Word.class); + + /** + * Descriptor for the arguments when unwinding to an exception handler in a caller. + */ + public static final Descriptor EXCEPTION_HANDLER_IN_CALLER = new Descriptor("exceptionHandlerInCaller", false, void.class, Object.class, Word.class); + public HotSpotBackend(HotSpotRuntime runtime, TargetDescription target) { super(runtime, target); } diff -r f0ef8f58a1d9 -r d6bf345d58c1 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRGenerator.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRGenerator.java Mon May 06 15:25:18 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRGenerator.java Mon May 06 15:25:33 2013 +0200 @@ -47,6 +47,8 @@ void emitPatchReturnAddress(ValueNode address); + void emitJumpToExceptionHandlerInCaller(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc); + void visitDirectCompareAndSwap(DirectCompareAndSwapNode x); /** diff -r f0ef8f58a1d9 -r d6bf345d58c1 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 Mon May 06 15:25:18 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotRuntimeCallTarget.java Mon May 06 15:25:33 2013 +0200 @@ -36,6 +36,11 @@ public class HotSpotRuntimeCallTarget implements RuntimeCallTarget, InvokeTarget { /** + * Sentinel marker for a computed jump address. + */ + public static final long JUMP_ADDRESS = 0xDEADDEADBEEFBEEFL; + + /** * The descriptor of the stub. This is for informational purposes only. */ public final Descriptor descriptor; diff -r f0ef8f58a1d9 -r d6bf345d58c1 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Mon May 06 15:25:18 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Mon May 06 15:25:33 2013 +0200 @@ -137,6 +137,9 @@ */ public int threadTlabEndOffset; + /** + * The value of JavaThread::threadObj_offset(). + */ public int threadObjectOffset; /** @@ -233,6 +236,11 @@ public int klassHasFinalizerFlag; /** + * The value of JavaThread::is_method_handle_return_offset(). + */ + public int threadIsMethodHandleReturnOffset; + + /** * Offset of the _exception_oop field in Thread (defined in thread.hpp). This field is used to * pass exception objects into and out of the runtime system during exception handling for * compiled code. @@ -392,7 +400,8 @@ public long threadIsInterruptedAddress; public long vmMessageAddress; public long identityHashCodeAddress; - public long handleExceptionForPcAddress; + public long exceptionHandlerForPcAddress; + public long exceptionHandlerForReturnAddressAddress; public int deoptReasonNullCheck; public int deoptReasonRangeCheck; diff -r f0ef8f58a1d9 -r d6bf345d58c1 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 Mon May 06 15:25:18 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Mon May 06 15:25:33 2013 +0200 @@ -43,6 +43,7 @@ import static com.oracle.graal.hotspot.stubs.NewMultiArrayStub.*; import static com.oracle.graal.hotspot.stubs.RegisterFinalizerStub.*; import static com.oracle.graal.hotspot.stubs.ThreadIsInterruptedStub.*; +import static com.oracle.graal.hotspot.stubs.UnwindExceptionToCallerStub.*; import static com.oracle.graal.java.GraphBuilderPhase.RuntimeCalls.*; import static com.oracle.graal.nodes.java.RegisterFinalizerNode.*; import static com.oracle.graal.replacements.Log.*; @@ -225,10 +226,19 @@ /* temps */ null, /* ret */ ret(Kind.Void)); - addCRuntimeCall(EXCEPTION_HANDLER_FOR_PC, config.handleExceptionForPcAddress, + addCRuntimeCall(EXCEPTION_HANDLER_FOR_PC, config.exceptionHandlerForPcAddress, /* ret */ ret(word), /* arg0: thread */ nativeCallingConvention(word)); + addStubCall(UNWIND_EXCEPTION_TO_CALLER, + /* ret */ ret(Kind.Void), + /* arg0: exception */ javaCallingConvention(Kind.Object, + /* arg1: returnAddress */ word)); + + addCRuntimeCall(EXCEPTION_HANDLER_FOR_RETURN_ADDRESS, config.exceptionHandlerForReturnAddressAddress, + /* ret */ ret(word), + /* arg0: thread */ nativeCallingConvention(word, + /* arg1: returnAddress */ word)); addStubCall(REGISTER_FINALIZER, /* ret */ ret(Kind.Void), /* arg0: object */ javaCallingConvention(Kind.Object)); @@ -374,6 +384,23 @@ return addRuntimeCall(descriptor, 0L, null, ret, args); } + /** + * Registers the details for a jump to a target that has a signature (i.e. expects arguments in + * specified locations). + * + * @param descriptor name and signature of the jump target + * @param args where arguments are passed to the call + */ + protected RuntimeCallTarget addJump(Descriptor descriptor, AllocatableValue... args) { + return addRuntimeCall(descriptor, HotSpotRuntimeCallTarget.JUMP_ADDRESS, null, ret(Kind.Void), args); + } + + /** + * Registers the details for a call to a runtime C/C++ function. + * + * @param descriptor name and signature of the call + * @param args where arguments are passed to the call + */ protected RuntimeCallTarget addCRuntimeCall(Descriptor descriptor, long address, AllocatableValue ret, AllocatableValue... args) { return addRuntimeCall(descriptor, address, true, null, ret, args); } @@ -459,6 +486,7 @@ registerStub(new ThreadIsInterruptedStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(THREAD_IS_INTERRUPTED))); registerStub(new IdentityHashCodeStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(IDENTITY_HASHCODE))); registerStub(new ExceptionHandlerStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(EXCEPTION_HANDLER))); + registerStub(new UnwindExceptionToCallerStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(UNWIND_EXCEPTION_TO_CALLER))); } private void registerStub(Stub stub) { diff -r f0ef8f58a1d9 -r d6bf345d58c1 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/JumpToExceptionHandlerInCallerNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/JumpToExceptionHandlerInCallerNode.java Mon May 06 15:25:33 2013 +0200 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2009, 2011, 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.nodes; + +import com.oracle.graal.hotspot.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.word.*; + +/** + * Sets up the {@linkplain HotSpotBackend#EXCEPTION_HANDLER_IN_CALLER arguments} expected by an + * exception handler in the caller's frame, removes the current frame and jumps to said handler. + */ +public class JumpToExceptionHandlerInCallerNode extends ControlSinkNode implements LIRLowerable { + + @Input private ValueNode handlerInCallerPc; + @Input private ValueNode exception; + @Input private ValueNode exceptionPc; + + public JumpToExceptionHandlerInCallerNode(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc) { + super(StampFactory.forVoid()); + this.handlerInCallerPc = handlerInCallerPc; + this.exception = exception; + this.exceptionPc = exceptionPc; + } + + @Override + public void generate(LIRGeneratorTool gen) { + ((HotSpotLIRGenerator) gen).emitJumpToExceptionHandlerInCaller(handlerInCallerPc, exception, exceptionPc); + } + + @NodeIntrinsic + public static native void jumpToExceptionHandlerInCaller(Word handlerInCallerPc, Object exception, Word exceptionPc); +} diff -r f0ef8f58a1d9 -r d6bf345d58c1 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 Mon May 06 15:25:18 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java Mon May 06 15:25:33 2013 +0200 @@ -458,14 +458,14 @@ * Gets the value of the stack pointer register as a Word. */ public static Word stackPointer() { - return HotSpotReplacementsUtil.registerAsWord(stackPointerRegister(), true, false); + return registerAsWord(stackPointerRegister(), true, false); } /** * Gets the value of the thread register as a Word. */ public static Word thread() { - return HotSpotReplacementsUtil.registerAsWord(threadRegister(), true, false); + return registerAsWord(threadRegister(), true, false); } public static Word loadWordFromObject(Object object, int offset) { diff -r f0ef8f58a1d9 -r d6bf345d58c1 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 Mon May 06 15:25:18 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ExceptionHandlerStub.java Mon May 06 15:25:33 2013 +0200 @@ -65,7 +65,8 @@ @Snippet private static void exceptionHandler(Object exception, Word exceptionPc) { - checkNoExceptionInThread(exception, exceptionPc); + checkNoExceptionInThread(assertionsEnabled()); + checkExceptionNotNull(assertionsEnabled(), exception); writeExceptionOop(thread(), exception); writeExceptionPc(thread(), exceptionPc); if (logging()) { @@ -85,19 +86,25 @@ patchReturnAddress(handlerPc); } - private static void checkNoExceptionInThread(Object exception, Word exceptionPc) { - if (assertionsEnabled()) { + static void checkNoExceptionInThread(boolean enabled) { + if (enabled) { Object currentException = readExceptionOop(thread()); - if (currentException != null && currentException != exception) { - fatal("exception oop must be null or %p, not %p", Word.fromObject(exception).rawValue(), Word.fromObject(currentException).rawValue()); + if (currentException != null) { + fatal("exception object in thread must be null, not %p", Word.fromObject(currentException).rawValue()); } Word currentExceptionPc = readExceptionPc(thread()); - if (currentExceptionPc.notEqual(Word.zero()) && currentExceptionPc.notEqual(exceptionPc)) { - fatal("exception pc must be zero or %p, not %p", exceptionPc.rawValue(), currentExceptionPc.rawValue()); + if (currentExceptionPc.notEqual(Word.zero())) { + fatal("exception PC in thread must be zero, not %p", currentExceptionPc.rawValue()); } } } + static void checkExceptionNotNull(boolean enabled, Object exception) { + if (enabled && exception == null) { + fatal("exception must not be null"); + } + } + @Fold private static boolean logging() { return Boolean.getBoolean("graal.logExceptionHandlerStub"); diff -r f0ef8f58a1d9 -r d6bf345d58c1 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java Mon May 06 15:25:18 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java Mon May 06 15:25:33 2013 +0200 @@ -39,7 +39,7 @@ import com.oracle.graal.hotspot.replacements.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.replacements.*; -import com.oracle.graal.replacements.Snippet.ConstantParameter; +import com.oracle.graal.replacements.Snippet.*; import com.oracle.graal.replacements.SnippetTemplate.Arguments; import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo; import com.oracle.graal.word.*; @@ -70,10 +70,14 @@ args.add("hub", null); args.add("length", null); args.addConst("intArrayHub", intArrayHub); - args.addConst("log", Boolean.getBoolean("graal.logNewArrayStub")); return args; } + @Fold + private static boolean logging() { + return Boolean.getBoolean("graal.logNewArrayStub"); + } + /** * Re-attempts allocation after an initial TLAB allocation failed or was skipped (e.g., due to * -XX:-UseTLAB). @@ -81,35 +85,42 @@ * @param hub the hub of the object to be allocated * @param length the length of the array * @param intArrayHub the hub for {@code int[].class} - * @param log specifies if logging is enabled */ @Snippet - private static Object newArray(Word hub, int length, @ConstantParameter Word intArrayHub, @ConstantParameter boolean log) { + private static Object newArray(Word hub, int length, @ConstantParameter Word intArrayHub) { int layoutHelper = hub.readInt(layoutHelperOffset(), FINAL_LOCATION); int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask(); int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift()) & layoutHelperHeaderSizeMask(); int elementKind = (layoutHelper >> layoutHelperElementTypeShift()) & layoutHelperElementTypeMask(); int sizeInBytes = computeArrayAllocationSize(length, wordSize(), headerSize, log2ElementSize); - log(log, "newArray: element kind %d\n", elementKind); - log(log, "newArray: array length %d\n", length); - log(log, "newArray: array size %d\n", sizeInBytes); - log(log, "newArray: hub=%p\n", hub); + if (logging()) { + printf("newArray: element kind %d\n", elementKind); + printf("newArray: array length %d\n", length); + printf("newArray: array size %d\n", sizeInBytes); + printf("newArray: hub=%p\n", hub.rawValue()); + } // check that array length is small enough for fast path. if (length <= MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH) { - Word memory = refillAllocate(intArrayHub, sizeInBytes, log); + Word memory = refillAllocate(intArrayHub, sizeInBytes, logging()); if (memory.notEqual(0)) { - log(log, "newArray: allocated new array at %p\n", memory); + if (logging()) { + printf("newArray: allocated new array at %p\n", memory.rawValue()); + } formatArray(hub, sizeInBytes, length, headerSize, memory, Word.unsigned(arrayPrototypeMarkWord()), true); return memory.toObject(); } } - log(log, "newArray: calling new_array_c\n", 0L); + if (logging()) { + printf("newArray: calling new_array_c\n"); + } newArrayC(NEW_ARRAY_C, thread(), hub, length); if (clearPendingException(thread())) { - log(log, "newArray: deoptimizing to caller\n", 0L); + if (logging()) { + printf("newArray: deoptimizing to caller\n"); + } getAndClearObjectResult(thread()); DeoptimizeCallerNode.deopt(InvalidateReprofile, RuntimeConstraint); } diff -r f0ef8f58a1d9 -r d6bf345d58c1 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java Mon May 06 15:25:18 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java Mon May 06 15:25:33 2013 +0200 @@ -71,10 +71,14 @@ Arguments args = new Arguments(stub); args.add("hub", null); args.addConst("intArrayHub", intArrayHub); - args.addConst("log", Boolean.getBoolean("graal.logNewInstanceStub")); return args; } + @Fold + private static boolean logging() { + return Boolean.getBoolean("graal.logNewInstanceStub"); + } + /** * Re-attempts allocation after an initial TLAB allocation failed or was skipped (e.g., due to * -XX:-UseTLAB). @@ -83,11 +87,11 @@ * @param intArrayHub the hub for {@code int[].class} */ @Snippet - private static Object newInstance(Word hub, @ConstantParameter Word intArrayHub, @ConstantParameter boolean log) { + private static Object newInstance(Word hub, @ConstantParameter Word intArrayHub) { int sizeInBytes = hub.readInt(klassInstanceSizeOffset(), FINAL_LOCATION); if (!forceSlowPath() && inlineContiguousAllocationSupported()) { if (hub.readInt(klassStateOffset(), CLASS_STATE_LOCATION) == klassStateFullyInitialized()) { - Word memory = refillAllocate(intArrayHub, sizeInBytes, log); + Word memory = refillAllocate(intArrayHub, sizeInBytes, logging()); if (memory.notEqual(0)) { Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION); initializeObjectHeader(memory, prototypeMarkWord, hub); @@ -99,12 +103,16 @@ } } - log(log, "newInstance: calling new_instance_c\n", 0L); + if (logging()) { + printf("newInstance: calling new_instance_c\n"); + } newInstanceC(NEW_INSTANCE_C, thread(), hub); if (clearPendingException(thread())) { - log(log, "newInstance: deoptimizing to caller\n", 0L); + if (logging()) { + printf("newInstance: deoptimizing to caller\n"); + } getAndClearObjectResult(thread()); DeoptimizeCallerNode.deopt(InvalidateReprofile, RuntimeConstraint); } @@ -134,10 +142,12 @@ // calculate amount of free space Word tlabFreeSpaceInBytes = end.subtract(top); - log(log, "refillTLAB: thread=%p\n", thread); - log(log, "refillTLAB: top=%p\n", top); - log(log, "refillTLAB: end=%p\n", end); - log(log, "refillTLAB: tlabFreeSpaceInBytes=%d\n", tlabFreeSpaceInBytes); + if (log) { + printf("refillTLAB: thread=%p\n", thread.rawValue()); + printf("refillTLAB: top=%p\n", top.rawValue()); + printf("refillTLAB: end=%p\n", end.rawValue()); + printf("refillTLAB: tlabFreeSpaceInBytes=%d\n", tlabFreeSpaceInBytes.rawValue()); + } Word tlabFreeSpaceInWords = tlabFreeSpaceInBytes.unsignedShiftRight(log2WordSize()); @@ -148,10 +158,14 @@ if (tlabStats()) { // increment number of refills thread.writeInt(tlabNumberOfRefillsOffset(), thread.readInt(tlabNumberOfRefillsOffset(), TLAB_NOF_REFILLS_LOCATION) + 1, TLAB_NOF_REFILLS_LOCATION); - log(log, "thread: %p -- number_of_refills %d\n", thread, thread.readInt(tlabNumberOfRefillsOffset(), TLAB_NOF_REFILLS_LOCATION)); + if (log) { + printf("thread: %p -- number_of_refills %d\n", thread.rawValue(), thread.readInt(tlabNumberOfRefillsOffset(), TLAB_NOF_REFILLS_LOCATION)); + } // accumulate wastage Word wastage = thread.readWord(tlabFastRefillWasteOffset(), TLAB_FAST_REFILL_WASTE_LOCATION).add(tlabFreeSpaceInWords); - log(log, "thread: %p -- accumulated wastage %d\n", thread, wastage); + if (log) { + printf("thread: %p -- accumulated wastage %d\n", thread.rawValue(), wastage.rawValue()); + } thread.writeWord(tlabFastRefillWasteOffset(), wastage, TLAB_FAST_REFILL_WASTE_LOCATION); } @@ -187,7 +201,9 @@ // Retain TLAB Word newRefillWasteLimit = refillWasteLimit.add(tlabRefillWasteIncrement()); thread.writeWord(tlabRefillWasteLimitOffset(), newRefillWasteLimit, TLAB_REFILL_WASTE_LIMIT_LOCATION); - log(log, "refillTLAB: retaining TLAB - newRefillWasteLimit=%p\n", newRefillWasteLimit); + if (log) { + printf("refillTLAB: retaining TLAB - newRefillWasteLimit=%p\n", newRefillWasteLimit.rawValue()); + } if (tlabStats()) { thread.writeInt(tlabSlowAllocationsOffset(), thread.readInt(tlabSlowAllocationsOffset(), TLAB_SLOW_ALLOCATIONS_LOCATION) + 1, TLAB_SLOW_ALLOCATIONS_LOCATION); diff -r f0ef8f58a1d9 -r d6bf345d58c1 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 Mon May 06 15:25:18 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java Mon May 06 15:25:33 2013 +0200 @@ -232,36 +232,6 @@ return code; } - static void log(boolean enabled, String message) { - if (enabled) { - printf(message); - } - } - - static void log(boolean enabled, String format, long value) { - if (enabled) { - printf(format, value); - } - } - - static void log(boolean enabled, String format, WordBase value) { - if (enabled) { - printf(format, value.rawValue()); - } - } - - static void log(boolean enabled, String format, Word v1, long v2) { - if (enabled) { - printf(format, v1.rawValue(), v2); - } - } - - static void log(boolean enabled, String format, Word v1, Word v2) { - if (enabled) { - printf(format, v1.rawValue(), v2.rawValue()); - } - } - static void handlePendingException(boolean isObjectResult) { if (clearPendingException(thread())) { if (isObjectResult) { diff -r f0ef8f58a1d9 -r d6bf345d58c1 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/UnwindExceptionToCallerStub.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/UnwindExceptionToCallerStub.java Mon May 06 15:25:33 2013 +0200 @@ -0,0 +1,96 @@ +/* + * 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.stubs; + +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; +import static com.oracle.graal.hotspot.nodes.JumpToExceptionHandlerInCallerNode.*; +import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; +import static com.oracle.graal.hotspot.stubs.ExceptionHandlerStub.*; + +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; +import com.oracle.graal.api.code.*; +import com.oracle.graal.graph.Node.ConstantNodeParameter; +import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.replacements.Snippet.Fold; +import com.oracle.graal.word.*; + +/** + * Stub called by an {@link UnwindNode}. This stub executes in the frame of the method throwing an + * exception and completes by jumping to the exception handler in the calling frame. + */ +public class UnwindExceptionToCallerStub extends CRuntimeStub { + + public UnwindExceptionToCallerStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) { + super(runtime, replacements, target, linkage); + } + + /** + * The current frame is unwound by this stub. 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 unwindExceptionToCaller(Object exception, Word returnAddress) { + checkNoExceptionInThread(assertionsEnabled()); + checkExceptionNotNull(assertionsEnabled(), exception); + if (logging()) { + printf("unwinding exception %p at return address %p\n", Word.fromObject(exception).rawValue(), returnAddress.rawValue()); + } + + Word handlerInCallerPc = exceptionHandlerForReturnAddress(EXCEPTION_HANDLER_FOR_RETURN_ADDRESS, thread(), returnAddress); + + if (logging()) { + printf("handler for exception %p at return address %p is at %p\n", Word.fromObject(exception).rawValue(), returnAddress.rawValue(), handlerInCallerPc.rawValue()); + } + + jumpToExceptionHandlerInCaller(handlerInCallerPc, exception, returnAddress); + } + + @Fold + private static boolean logging() { + return Boolean.getBoolean("graal.logUnwindExceptionToCallerStub"); + } + + @Fold + @SuppressWarnings("all") + private static boolean assertionsEnabled() { + boolean enabled = false; + assert enabled = true; + return enabled || graalRuntime().getConfig().cAssertions; + } + + public static final Descriptor EXCEPTION_HANDLER_FOR_RETURN_ADDRESS = descriptorFor(UnwindExceptionToCallerStub.class, "exceptionHandlerForReturnAddress", false); + + @NodeIntrinsic(value = CRuntimeCall.class, setStampFromReturnType = true) + public static native Word exceptionHandlerForReturnAddress(@ConstantNodeParameter Descriptor exceptionHandlerForReturnAddress, Word thread, Word returnAddress); +} diff -r f0ef8f58a1d9 -r d6bf345d58c1 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ControlSinkNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ControlSinkNode.java Mon May 06 15:25:18 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ControlSinkNode.java Mon May 06 15:25:33 2013 +0200 @@ -22,9 +22,10 @@ */ package com.oracle.graal.nodes; +import com.oracle.graal.graph.*; import com.oracle.graal.nodes.type.*; -public abstract class ControlSinkNode extends FixedNode { +public abstract class ControlSinkNode extends FixedNode implements Node.IterableNodeType { public ControlSinkNode(Stamp stamp) { super(stamp); diff -r f0ef8f58a1d9 -r d6bf345d58c1 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/UnwindNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/UnwindNode.java Mon May 06 15:25:18 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/UnwindNode.java Mon May 06 15:25:33 2013 +0200 @@ -28,8 +28,7 @@ import com.oracle.graal.nodes.type.*; /** - * Unwind takes an exception object, destroys the current stack frame and passes the exception - * object to the system's exception dispatch code. + * Unwinds the current frame to an exception handler in the caller frame. */ public final class UnwindNode extends ControlSinkNode implements Lowerable, LIRLowerable, Node.IterableNodeType { diff -r f0ef8f58a1d9 -r d6bf345d58c1 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java Mon May 06 15:25:18 2013 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java Mon May 06 15:25:33 2013 +0200 @@ -39,13 +39,7 @@ NodeBitMap visited = graph.createNodeBitMap(); - for (ReturnNode node : graph.getNodes(ReturnNode.class)) { - result.visitForward(visited, node); - } - for (UnwindNode node : graph.getNodes(UnwindNode.class)) { - result.visitForward(visited, node); - } - for (DeoptimizeNode node : graph.getNodes(DeoptimizeNode.class)) { + for (ControlSinkNode node : graph.getNodes(ControlSinkNode.class)) { result.visitForward(visited, node); } return result; diff -r f0ef8f58a1d9 -r d6bf345d58c1 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/UnwindExceptionToCallerTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/UnwindExceptionToCallerTest.java Mon May 06 15:25:33 2013 +0200 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2011, 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.replacements.test; + +import org.junit.*; + +import com.oracle.graal.compiler.test.*; + +/** + * Tests exception throwing from Graal compiled code. + */ +public class UnwindExceptionToCallerTest extends GraalCompilerTest { + + @Test + public void test1() { + NullPointerException npe = new NullPointerException(); + test("test1Snippet", "a string", npe); + test("test1Snippet", (String) null, npe); + } + + public static String test1Snippet(String message, NullPointerException npe) { + if (message == null) { + throw npe; + } + return message; + } +} diff -r f0ef8f58a1d9 -r d6bf345d58c1 src/cpu/x86/vm/graalRuntime_x86.cpp --- a/src/cpu/x86/vm/graalRuntime_x86.cpp Mon May 06 15:25:18 2013 +0200 +++ b/src/cpu/x86/vm/graalRuntime_x86.cpp Mon May 06 15:25:33 2013 +0200 @@ -612,95 +612,6 @@ #endif // _LP64 } -void GraalRuntime::generate_unwind_exception(GraalStubAssembler *sasm) { - // incoming parameters - const Register exception_oop = rax; - // callee-saved copy of exception_oop during runtime call - const Register exception_oop_callee_saved = NOT_LP64(rsi) LP64_ONLY(r14); - // other registers used in this stub - const Register exception_pc = rdx; - const Register handler_addr = rbx; - const Register thread = NOT_LP64(rdi) LP64_ONLY(r15_thread); - - // verify that only rax is valid at this time -#ifdef ASSERT - __ movptr(rbx, 0xDEAD); - __ movptr(rcx, 0xDEAD); - __ movptr(rdx, 0xDEAD); - __ movptr(rsi, 0xDEAD); - __ movptr(rdi, 0xDEAD); -#endif - -#ifdef ASSERT - // check that fields in JavaThread for exception oop and issuing pc are empty - NOT_LP64(__ get_thread(thread);) - Label oop_empty; - __ cmpptr(Address(thread, JavaThread::exception_oop_offset()), 0); - __ jcc(Assembler::equal, oop_empty); - __ stop("exception oop must be empty"); - __ bind(oop_empty); - - Label pc_empty; - __ cmpptr(Address(thread, JavaThread::exception_pc_offset()), 0); - __ jcc(Assembler::equal, pc_empty); - __ stop("exception pc must be empty"); - __ bind(pc_empty); -#endif - - // clear the FPU stack in case any FPU results are left behind - __ empty_FPU_stack(); - - // save exception_oop in callee-saved register to preserve it during runtime calls - __ verify_not_null_oop(exception_oop); - __ movptr(exception_oop_callee_saved, exception_oop); - - NOT_LP64(__ get_thread(thread);) - // Get return address (is on top of stack after leave). - __ movptr(exception_pc, Address(rsp, 0)); - - // search the exception handler address of the caller (using the return address) - __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), thread, exception_pc); - // rax: exception handler address of the caller - - // Only RAX and RSI are valid at this time, all other registers have been destroyed by the call. -#ifdef ASSERT - __ movptr(rbx, 0xDEAD); - __ movptr(rcx, 0xDEAD); - __ movptr(rdx, 0xDEAD); - __ movptr(rdi, 0xDEAD); -#endif - - // move result of call into correct register - __ movptr(handler_addr, rax); - - // Restore exception oop to RAX (required convention of exception handler). - __ movptr(exception_oop, exception_oop_callee_saved); - - // verify that there is really a valid exception in rax - __ verify_not_null_oop(exception_oop); - - // get throwing pc (= return address). - // rdx has been destroyed by the call, so it must be set again - // the pop is also necessary to simulate the effect of a ret(0) - __ pop(exception_pc); - - // Restore SP from BP if the exception PC is a method handle call site. - NOT_LP64(__ get_thread(thread);) - __ cmpl(Address(thread, JavaThread::is_method_handle_return_offset()), 0); - __ cmovptr(Assembler::notEqual, rsp, rbp_mh_SP_save); - - // continue at exception handler (return address removed) - // note: do *not* remove arguments when unwinding the - // activation since the caller assumes having - // all arguments on the stack when entering the - // runtime to determine the exception handler - // (GC happens at call site with arguments!) - // rax: exception oop - // rdx: throwing pc - // rbx: exception handler - __ jmp(handler_addr); -} - OopMapSet* GraalRuntime::generate_code_for(StubID id, GraalStubAssembler* sasm) { // for better readability @@ -714,19 +625,6 @@ OopMapSet* oop_maps = NULL; switch (id) { - case unwind_exception_call_id: { - // remove the frame from the stack - __ movptr(rsp, rbp); - __ pop(rbp); - - __ set_info("unwind_exception", dont_gc_arguments); - // note: no stubframe since we are about to leave the current - // activation and we are calling a leaf VM function only. - generate_unwind_exception(sasm); - __ should_not_reach_here(); - break; - } - case OSR_migration_end_id: { __ enter(); save_live_registers(sasm, 0); diff -r f0ef8f58a1d9 -r d6bf345d58c1 src/share/vm/graal/graalCompilerToVM.cpp --- a/src/share/vm/graal/graalCompilerToVM.cpp Mon May 06 15:25:18 2013 +0200 +++ b/src/share/vm/graal/graalCompilerToVM.cpp Mon May 06 15:25:33 2013 +0200 @@ -666,6 +666,7 @@ set_int("threadTlabTopOffset", in_bytes(JavaThread::tlab_top_offset())); set_int("threadTlabEndOffset", in_bytes(JavaThread::tlab_end_offset())); set_int("threadObjectOffset", in_bytes(JavaThread::threadObj_offset())); + set_int("threadIsMethodHandleReturnOffset", in_bytes(JavaThread::is_method_handle_return_offset())); set_int("osThreadOffset", in_bytes(JavaThread::osthread_offset())); set_int("osThreadInterruptedOffset", in_bytes(OSThread::interrupted_offset())); set_int("unlockedMask", (int) markOopDesc::unlocked_value); @@ -761,7 +762,6 @@ set_address("monitorExitStub", GraalRuntime::entry_for(GraalRuntime::monitorexit_id)); set_address("verifyOopStub", GraalRuntime::entry_for(GraalRuntime::verify_oop_id)); set_address("vmErrorStub", GraalRuntime::entry_for(GraalRuntime::vm_error_id)); - set_address("unwindExceptionStub", GraalRuntime::entry_for(GraalRuntime::unwind_exception_call_id)); set_address("osrMigrationEndStub", GraalRuntime::entry_for(GraalRuntime::OSR_migration_end_id)); set_address("createNullPointerExceptionStub", GraalRuntime::entry_for(GraalRuntime::create_null_pointer_exception_id)); set_address("createOutOfBoundsExceptionStub", GraalRuntime::entry_for(GraalRuntime::create_out_of_bounds_exception_id)); @@ -788,7 +788,8 @@ set_address("uncommonTrapStub", SharedRuntime::deopt_blob()->uncommon_trap()); set_address("vmMessageAddress", GraalRuntime::vm_message); set_address("identityHashCodeAddress", GraalRuntime::identity_hash_code); - set_address("handleExceptionForPcAddress", GraalRuntime::exception_handler_for_pc); + set_address("exceptionHandlerForPcAddress", GraalRuntime::exception_handler_for_pc); + set_address("exceptionHandlerForReturnAddressAddress", SharedRuntime::exception_handler_for_return_address); set_int("deoptReasonNone", Deoptimization::Reason_none); set_int("deoptReasonNullCheck", Deoptimization::Reason_null_check); diff -r f0ef8f58a1d9 -r d6bf345d58c1 src/share/vm/graal/graalRuntime.cpp --- a/src/share/vm/graal/graalRuntime.cpp Mon May 06 15:25:18 2013 +0200 +++ b/src/share/vm/graal/graalRuntime.cpp Mon May 06 15:25:33 2013 +0200 @@ -131,7 +131,6 @@ case handle_exception_nofpu_id: // Unused on sparc #endif case verify_oop_id: - case unwind_exception_call_id: case OSR_migration_end_id: case arithmetic_frem_id: case arithmetic_drem_id: diff -r f0ef8f58a1d9 -r d6bf345d58c1 src/share/vm/graal/graalRuntime.hpp --- a/src/share/vm/graal/graalRuntime.hpp Mon May 06 15:25:18 2013 +0200 +++ b/src/share/vm/graal/graalRuntime.hpp Mon May 06 15:25:33 2013 +0200 @@ -81,7 +81,6 @@ // runtime routines needed by code code generated // by Graal. #define GRAAL_STUBS(stub, last_entry) \ - stub(unwind_exception_call) \ stub(OSR_migration_end) \ stub(arithmetic_frem) \ stub(arithmetic_drem) \ diff -r f0ef8f58a1d9 -r d6bf345d58c1 src/share/vm/runtime/sharedRuntime.cpp --- a/src/share/vm/runtime/sharedRuntime.cpp Mon May 06 15:25:18 2013 +0200 +++ b/src/share/vm/runtime/sharedRuntime.cpp Mon May 06 15:25:33 2013 +0200 @@ -484,6 +484,12 @@ // Reset method handle flag. thread->set_is_method_handle_return(false); +#ifdef GRAAL + // Graal's ExceptionHandlerStub expects the thread local exception PC to be clear + // and other exception handler continuations do not read it + thread->set_exception_pc(NULL); +#endif + // The fastest case first CodeBlob* blob = CodeCache::find_blob(return_address); nmethod* nm = (blob != NULL) ? blob->as_nmethod_or_null() : NULL; @@ -493,10 +499,6 @@ // native nmethods don't have exception handlers assert(!nm->is_native_method(), "no exception handler"); assert(nm->header_begin() != nm->exception_begin(), "no exception handler"); -#ifdef GRAAL - // Graal's ExceptionHandlerStub expects the exception PC stored in the thread to be 0 - thread->set_exception_pc(NULL); -#endif if (nm->is_deopt_pc(return_address)) { return SharedRuntime::deopt_blob()->unpack_with_exception(); } else {