changeset 9472:e4e2686f30df

Merge.
author Doug Simon <doug.simon@oracle.com>
date Wed, 01 May 2013 18:04:28 +0200
parents 5fa54bf57f8c (diff) 225fc5463430 (current diff)
children d9fd6af5d200
files
diffstat 19 files changed, 487 insertions(+), 172 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCRuntimeCallEpilogueOp.java	Wed May 01 17:28:04 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCRuntimeCallEpilogueOp.java	Wed May 01 18:04:28 2013 +0200
@@ -22,11 +22,9 @@
  */
 package com.oracle.graal.hotspot.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.meta.*;
+import com.oracle.graal.api.code.*;
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.lir.LIRInstruction.Opcode;
@@ -36,17 +34,13 @@
 @Opcode("CRUNTIME_CALL_EPILOGUE")
 final class AMD64HotSpotCRuntimeCallEpilogueOp extends AMD64LIRInstruction {
 
-    @Use({REG, ILLEGAL}) protected Value thread;
-
-    AMD64HotSpotCRuntimeCallEpilogueOp(Value thread) {
-        this.thread = thread;
-    }
-
     @Override
     public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
         // reset last Java frame:
         HotSpotVMConfig config = graalRuntime().getConfig();
-        masm.movslq(new AMD64Address(asRegister(thread), config.threadLastJavaSpOffset), 0);
-        masm.movslq(new AMD64Address(asRegister(thread), config.threadLastJavaFpOffset), 0);
+        Register thread = graalRuntime().getRuntime().threadRegister();
+
+        masm.movslq(new AMD64Address(thread, config.threadLastJavaSpOffset), 0);
+        masm.movslq(new AMD64Address(thread, config.threadLastJavaFpOffset), 0);
     }
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCRuntimeCallPrologueOp.java	Wed May 01 17:28:04 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCRuntimeCallPrologueOp.java	Wed May 01 18:04:28 2013 +0200
@@ -23,11 +23,9 @@
 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.meta.*;
+import com.oracle.graal.api.code.*;
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.lir.LIRInstruction.Opcode;
 import com.oracle.graal.lir.amd64.*;
@@ -36,16 +34,11 @@
 @Opcode("CRUNTIME_CALL_PROLOGUE")
 final class AMD64HotSpotCRuntimeCallPrologueOp extends AMD64LIRInstruction {
 
-    @Use({REG, ILLEGAL}) protected Value thread;
-
-    AMD64HotSpotCRuntimeCallPrologueOp(Value thread) {
-        this.thread = thread;
-    }
-
     @Override
     public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
 
         // save last Java frame
-        masm.movq(new AMD64Address(asRegister(thread), graalRuntime().getConfig().threadLastJavaSpOffset), rsp);
+        Register thread = graalRuntime().getRuntime().threadRegister();
+        masm.movq(new AMD64Address(thread, graalRuntime().getConfig().threadLastJavaSpOffset), rsp);
     }
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Wed May 01 17:28:04 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Wed May 01 18:04:28 2013 +0200
@@ -213,23 +213,17 @@
             save = new AMD64SaveRegistersOp(savingMoves, restoringMoves, savedRegisterLocations);
             append(save);
 
-            Value thread = args[0];
-            AMD64HotSpotCRuntimeCallPrologueOp op = new AMD64HotSpotCRuntimeCallPrologueOp(thread);
-            append(op);
+            append(new AMD64HotSpotCRuntimeCallPrologueOp());
         }
 
         Variable result = super.emitCall(callTarget, cc, info, args);
 
         if (needsCalleeSave) {
-
-            Value thread = args[0];
-            AMD64HotSpotCRuntimeCallEpilogueOp op = new AMD64HotSpotCRuntimeCallEpilogueOp(thread);
-            append(op);
+            assert !calleeSaveInfo.containsKey(currentRuntimeCallInfo);
+            calleeSaveInfo.put(currentRuntimeCallInfo, save);
 
-            AMD64RestoreRegistersOp restore = new AMD64RestoreRegistersOp(savedRegisterLocations.clone(), save);
-            AMD64SaveRegistersOp oldValue = calleeSaveInfo.put(currentRuntimeCallInfo, save);
-            assert oldValue == null;
-            append(restore);
+            append(new AMD64HotSpotCRuntimeCallEpilogueOp());
+            append(new AMD64RestoreRegistersOp(savedRegisterLocations.clone(), save));
         }
 
         return result;
@@ -334,6 +328,13 @@
     }
 
     @Override
+    public void emitPatchReturnAddress(ValueNode address) {
+        load(operand(address));
+        AMD64HotSpotPatchReturnAddressOp op = new AMD64HotSpotPatchReturnAddressOp(load(operand(address)));
+        append(op);
+    }
+
+    @Override
     public void beforeRegisterAllocation() {
         boolean hasDebugInfo = lir.hasDebugInfo();
         AllocatableValue savedRbp = saveRbp.finalize(hasDebugInfo);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotPatchReturnAddressOp.java	Wed May 01 18:04:28 2013 +0200
@@ -0,0 +1,52 @@
+/*
+ * 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.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.lir.LIRInstruction.Opcode;
+import com.oracle.graal.lir.amd64.*;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Patch the return address of the current frame.
+ */
+@Opcode("PATCH_RETURN")
+final class AMD64HotSpotPatchReturnAddressOp extends AMD64LIRInstruction {
+
+    @Use(REG) AllocatableValue address;
+
+    AMD64HotSpotPatchReturnAddressOp(AllocatableValue address) {
+        this.address = address;
+    }
+
+    @Override
+    public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
+        int frameSize = tasm.frameMap.frameSize();
+        masm.movq(new AMD64Address(rsp, frameSize), asRegister(address));
+    }
+}
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRuntime.java	Wed May 01 17:28:04 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRuntime.java	Wed May 01 18:04:28 2013 +0200
@@ -24,6 +24,7 @@
 
 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.*;
@@ -54,6 +55,11 @@
         Kind word = graalRuntime.getTarget().wordKind;
 
         // @formatter:off
+        addStubCall(EXCEPTION_HANDLER,
+               /*             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),
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java	Wed May 01 17:28:04 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java	Wed May 01 18:04:28 2013 +0200
@@ -22,10 +22,13 @@
  */
 package com.oracle.graal.hotspot;
 
+import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 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.*;
 
 /**
  * HotSpot specific backend.
@@ -38,9 +41,10 @@
     public static final Descriptor UNCOMMON_TRAP = new Descriptor("deoptimize", true, void.class);
 
     /**
-     * Descriptor for GraalRuntime::handle_exception_nofpu_id.
+     * Descriptor for {@link ExceptionHandlerStub}. This stub is called by the
+     * {@linkplain Marks#MARK_EXCEPTION_HANDLER_ENTRY exception handler} in a compiled method.
      */
-    public static final Descriptor EXCEPTION_HANDLER = new Descriptor("exceptionHandler", true, void.class);
+    public static final Descriptor EXCEPTION_HANDLER = new Descriptor("exceptionHandler", true, void.class, Object.class, Word.class);
 
     /**
      * Descriptor for SharedRuntime::deopt_blob()->unpack().
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRGenerator.java	Wed May 01 17:28:04 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRGenerator.java	Wed May 01 18:04:28 2013 +0200
@@ -26,6 +26,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 
 /**
@@ -44,6 +45,8 @@
 
     void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason);
 
+    void emitPatchReturnAddress(ValueNode address);
+
     void visitDirectCompareAndSwap(DirectCompareAndSwapNode x);
 
     /**
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Wed May 01 17:28:04 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Wed May 01 18:04:28 2013 +0200
@@ -344,7 +344,6 @@
 
     // runtime stubs
     public long inlineCacheMissStub;
-    public long handleExceptionStub;
     public long handleDeoptStub;
     public long monitorEnterStub;
     public long monitorExitStub;
@@ -379,8 +378,9 @@
     public long newMultiArrayAddress;
     public long registerFinalizerAddress;
     public long threadIsInterruptedAddress;
-    public long stubPrintfAddress;
+    public long vmMessageAddress;
     public long identityHashCodeAddress;
+    public long handleExceptionForPcAddress;
 
     public int deoptReasonNullCheck;
     public int deoptReasonRangeCheck;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Wed May 01 17:28:04 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Wed May 01 18:04:28 2013 +0200
@@ -37,6 +37,7 @@
 import static com.oracle.graal.hotspot.nodes.ThreadIsInterruptedStubCall.*;
 import static com.oracle.graal.hotspot.replacements.SystemSubstitutions.*;
 import static com.oracle.graal.hotspot.stubs.IdentityHashCodeStub.*;
+import static com.oracle.graal.hotspot.stubs.ExceptionHandlerStub.*;
 import static com.oracle.graal.hotspot.stubs.NewArrayStub.*;
 import static com.oracle.graal.hotspot.stubs.NewInstanceStub.*;
 import static com.oracle.graal.hotspot.stubs.NewMultiArrayStub.*;
@@ -222,6 +223,10 @@
                         /*           temps */ null,
                         /*             ret */ ret(Kind.Void));
 
+        addCRuntimeCall(EXCEPTION_HANDLER_FOR_PC, config.handleExceptionForPcAddress,
+                        /*             ret */ ret(word),
+                        /* arg0:    thread */ nativeCallingConvention(word));
+
         addStubCall(REGISTER_FINALIZER,
                         /*             ret */ ret(Kind.Void),
                         /* arg0:    object */ javaCallingConvention(Kind.Object));
@@ -311,12 +316,13 @@
                         /* arg2:     value */                       Kind.Long,
                         /* arg3:     value */                       Kind.Long));
 
-        addCRuntimeCall(STUB_PRINTF_C, config.stubPrintfAddress,
+        addCRuntimeCall(STUB_PRINTF_C, config.vmMessageAddress,
                         /*             ret */ ret(Kind.Void),
-                        /* arg0:    format */ nativeCallingConvention(Kind.Long,
-                        /* arg1:     value */                         Kind.Long,
+                        /* arg0:   vmError */ nativeCallingConvention(Kind.Boolean,
+                        /* arg1:    format */                         word,
                         /* arg2:     value */                         Kind.Long,
-                        /* arg3:     value */                         Kind.Long));
+                        /* arg3:     value */                         Kind.Long,
+                        /* arg4:     value */                         Kind.Long));
 
         addRuntimeCall(LOG_OBJECT, config.logObjectStub,
                         /*           temps */ null,
@@ -335,10 +341,6 @@
                    /* arg1: receiverThread */                         Kind.Object,
               /* arg1: clearInterrupted */                            Kind.Boolean));
 
-        addRuntimeCall(EXCEPTION_HANDLER, config.handleExceptionStub,
-                        /*           temps */ null,
-                        /*             ret */ ret(Kind.Void));
-
         addRuntimeCall(DEOPT_HANDLER, config.handleDeoptStub,
                         /*           temps */ null,
                         /*             ret */ ret(Kind.Void));
@@ -454,6 +456,7 @@
         registerStub(new RegisterFinalizerStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(REGISTER_FINALIZER)));
         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)));
     }
 
     private void registerStub(Stub stub) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/PatchReturnAddressNode.java	Wed May 01 18:04:28 2013 +0200
@@ -0,0 +1,50 @@
+/*
+ * 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.*;
+
+/**
+ * Modifies the return address of the current frame.
+ */
+public class PatchReturnAddressNode extends FixedWithNextNode implements LIRLowerable {
+
+    @Input private ValueNode address;
+
+    public PatchReturnAddressNode(ValueNode address) {
+        super(StampFactory.forVoid());
+        this.address = address;
+    }
+
+    @Override
+    public void generate(LIRGeneratorTool gen) {
+        ((HotSpotLIRGenerator) gen).emitPatchReturnAddress(address);
+    }
+
+    @NodeIntrinsic
+    public static native void patchReturnAddress(Word address);
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSnippetUtils.java	Wed May 01 17:28:04 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSnippetUtils.java	Wed May 01 18:04:28 2013 +0200
@@ -115,6 +115,10 @@
         return thread.readObject(threadExceptionOopOffset(), EXCEPTION_OOP_LOCATION);
     }
 
+    public static Word readExceptionPc(Word thread) {
+        return thread.readWord(threadExceptionOopOffset(), EXCEPTION_PC_LOCATION);
+    }
+
     public static void writeExceptionOop(Word thread, Object value) {
         thread.writeObject(threadExceptionOopOffset(), value, EXCEPTION_OOP_LOCATION);
     }
@@ -146,7 +150,7 @@
     }
 
     /**
-     * Clears the pending exception if for the given thread.
+     * Clears the pending exception for the given thread.
      * 
      * @return {@code true} if there was a pending exception
      */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ExceptionHandlerStub.java	Wed May 01 18:04:28 2013 +0200
@@ -0,0 +1,107 @@
+/*
+ * 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.nodes.PatchReturnAddressNode.*;
+import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*;
+
+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.bridge.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.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 the {@linkplain Marks#MARK_EXCEPTION_HANDLER_ENTRY exception handler entry point}
+ * in a compiled method. This entry point is used 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.
+ * <p>
+ * The descriptor for a call to this stub is {@link HotSpotBackend#EXCEPTION_HANDLER}.
+ */
+public class ExceptionHandlerStub extends CRuntimeStub {
+
+    public ExceptionHandlerStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) {
+        super(runtime, replacements, target, linkage);
+    }
+
+    @Snippet
+    private static void exceptionHandler(Object exception, Word exceptionPc) {
+        checkNoExceptionInThread();
+        writeExceptionOop(thread(), exception);
+        writeExceptionPc(thread(), exceptionPc);
+        if (logging()) {
+            printf("handling exception %p at %p\n", Word.fromObject(exception).rawValue(), exceptionPc.rawValue());
+        }
+
+        // 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()) {
+            printf("handler for exception %p at %p is at %p\n", Word.fromObject(exception).rawValue(), exceptionPc.rawValue(), handlerPc.rawValue());
+        }
+
+        // patch the return address so that this stub returns to the exception handler
+        patchReturnAddress(handlerPc);
+    }
+
+    private static void checkNoExceptionInThread() {
+        if (assertionsEnabled()) {
+            if (readExceptionOop(thread()) != null) {
+                fatal("exception oop must be null, not %p", Word.fromObject(readExceptionOop(thread())).rawValue());
+            }
+            if (readExceptionPc(thread()).notEqual(Word.zero())) {
+                fatal("exception pc must be zero, not %p", readExceptionPc(thread()).rawValue());
+            }
+        }
+    }
+
+    @Fold
+    private static boolean logging() {
+        return Boolean.getBoolean("graal.logExceptionHandlerStub");
+    }
+
+    @Fold
+    @SuppressWarnings("all")
+    private static boolean assertionsEnabled() {
+        boolean enabled = false;
+        assert enabled = true;
+        return enabled;
+    }
+
+    public static final Descriptor EXCEPTION_HANDLER_FOR_PC = descriptorFor(ExceptionHandlerStub.class, "exceptionHandlerForPc", false);
+
+    @NodeIntrinsic(value = CRuntimeCall.class, setStampFromReturnType = true)
+    public static native Word exceptionHandlerForPc(@ConstantNodeParameter Descriptor exceptionHandlerForPc, Word thread);
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java	Wed May 01 17:28:04 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java	Wed May 01 18:04:28 2013 +0200
@@ -140,7 +140,7 @@
     private boolean checkStubInvariants(CompilationResult compResult) {
         for (DataPatch data : compResult.getDataReferences()) {
             Constant constant = data.constant;
-            assert constant.getKind() != Kind.Object : format("%h.%n(%p): ", getMethod()) + "cannot have embedded oop: " + constant;
+            assert constant.getKind() != Kind.Object : format("%h.%n(%p): ", getMethod()) + "cannot have embedded object constant: " + constant;
             assert constant.getPrimitiveAnnotation() == null : format("%h.%n(%p): ", getMethod()) + "cannot have embedded metadata: " + constant;
         }
         for (Infopoint infopoint : compResult.getInfopoints()) {
@@ -220,6 +220,12 @@
         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);
@@ -256,26 +262,113 @@
     public static final Descriptor STUB_PRINTF_C = descriptorFor(Stub.class, "printfC", false);
 
     @NodeIntrinsic(CRuntimeCall.class)
-    private static native void printfC(@ConstantNodeParameter Descriptor stubPrintf, Word format, long v1, long v2, long v3);
+    private static native void printfC(@ConstantNodeParameter Descriptor stubPrintfC, boolean vmError, Word format, long v1, long v2, long v3);
 
     /**
-     * Prints a formatted string to the log stream. This differs from {@link Log#LOG_PRINTF} in that
-     * the format string is a C string in the C heap which avoids having an embedded oop in a
-     * RuntimeStub.
+     * Prints a message to the log stream.
+     * <p>
+     * <b>Stubs must use this instead of {@link Log#printf(String, long)} to avoid an object
+     * constant in a RuntimeStub.</b>
      * 
-     * @param format a C style printf format value that can contain at most one conversion specifier
-     *            (i.e., a sequence of characters starting with '%').
-     * @param value the value associated with the conversion specifier
+     * @param message a message string
+     */
+    public static void printf(String message) {
+        printfC(STUB_PRINTF_C, false, cstring(message), 0L, 0L, 0L);
+    }
+
+    /**
+     * Prints a message to the log stream.
+     * <p>
+     * <b>Stubs must use this instead of {@link Log#printf(String, long)} to avoid an object
+     * constant in a RuntimeStub.</b>
+     * 
+     * @param format a C style printf format value
+     * @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, cstring(format), value, 0L, 0L);
+        printfC(STUB_PRINTF_C, false, cstring(format), value, 0L, 0L);
+    }
+
+    /**
+     * Prints a message to the log stream.
+     * <p>
+     * <b>Stubs must use this instead of {@link Log#printf(String, long, long)} to avoid an object
+     * constant in a RuntimeStub.</b>
+     * 
+     * @param format a C style printf format value
+     * @param v1 the value associated with the first conversion specifier in {@code format}
+     * @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);
+    }
+
+    /**
+     * Prints a message to the log stream.
+     * <p>
+     * <b>Stubs must use this instead of {@link Log#printf(String, long, long, long)} to avoid an
+     * object constant in a RuntimeStub.</b>
+     * 
+     * @param format a C style printf format value
+     * @param v1 the value associated with the first conversion specifier in {@code format}
+     * @param v2 the value associated with the second conversion specifier in {@code format}
+     * @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);
     }
 
-    public static void printf(String format, long v1, long v2) {
-        printfC(STUB_PRINTF_C, cstring(format), v1, v2, 0L);
+    /**
+     * Exits the VM with a given error message.
+     * <p>
+     * <b>Stubs must use this instead of {@link VMErrorNode#vmError(String, long)} to avoid an
+     * object constant in a RuntimeStub.</b>
+     * 
+     * @param message an error message
+     */
+    public static void fatal(String message) {
+        printfC(STUB_PRINTF_C, true, cstring(message), 0L, 0L, 0L);
+    }
+
+    /**
+     * Exits the VM with a given error message.
+     * <p>
+     * <b>Stubs must use this instead of {@link Log#printf(String, long, long, long)} to avoid an
+     * object constant in a RuntimeStub.</b>
+     * 
+     * @param format a C style printf format value
+     * @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);
     }
 
-    public static void printf(String format, long v1, long v2, long v3) {
-        printfC(STUB_PRINTF_C, cstring(format), v1, v2, v3);
+    /**
+     * Exits the VM with a given error message.
+     * <p>
+     * <b>Stubs must use this instead of {@link Log#printf(String, long, long, long)} to avoid an
+     * object constant in a RuntimeStub.</b>
+     * 
+     * @param format a C style printf format value
+     * @param v1 the value associated with the first conversion specifier in {@code format}
+     * @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);
+    }
+
+    /**
+     * Exits the VM with a given error message.
+     * <p>
+     * <b>Stubs must use this instead of {@link Log#printf(String, long, long, long)} to avoid an
+     * object constant in a RuntimeStub.</b>
+     * 
+     * @param format a C style printf format value
+     * @param v1 the value associated with the first conversion specifier in {@code format}
+     * @param v2 the value associated with the second conversion specifier in {@code format}
+     * @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);
     }
 }
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/CompiledExceptionHandlerTest.java	Wed May 01 17:28:04 2013 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/CompiledExceptionHandlerTest.java	Wed May 01 18:04:28 2013 +0200
@@ -64,6 +64,7 @@
         }
 
         test("test1Snippet", "a string");
+        test("test1Snippet", (String) null);
     }
 
     public static String test1Snippet(String message) {
@@ -76,4 +77,51 @@
         }
         return null;
     }
+
+    private static void raiseException(String m1, String m2, String m3, String m4, String m5) {
+        throw new RuntimeException(m1 + m2 + m3 + m4 + m5);
+    }
+
+    @Test
+    public void test2() {
+        // Ensure the profile shows a hot exception
+        for (int i = 0; i < 10000; i++) {
+            test2Snippet("m1", "m2", "m3", "m4", "m5");
+            test2Snippet(null, "m2", "m3", "m4", "m5");
+        }
+
+        test("test2Snippet", "m1", "m2", "m3", "m4", "m5");
+        test("test2Snippet", null, "m2", "m3", "m4", "m5");
+    }
+
+    public static String test2Snippet(String m1, String m2, String m3, String m4, String m5) {
+        if (m1 != null) {
+            try {
+                raiseException(m1, m2, m3, m4, m5);
+            } catch (Exception e) {
+                return m5 + m4 + m3 + m2 + m1;
+            }
+        }
+        return m4 + m3;
+    }
+
+    @Test
+    public void test3() {
+        // Ensure the profile shows a hot exception
+        for (int i = 0; i < 10000; i++) {
+            test3Snippet("object1", "object2");
+            test3Snippet(null, "object2");
+        }
+
+        test("test3Snippet", (Object) null, "object2");
+        test("test3Snippet", "object1", "object2");
+    }
+
+    public static String test3Snippet(Object o, Object o2) {
+        try {
+            return o.toString();
+        } catch (NullPointerException e) {
+            return String.valueOf(o2);
+        }
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/DeoptimizeOnExceptionTest.java	Wed May 01 18:04:28 2013 +0200
@@ -0,0 +1,59 @@
+/*
+ * 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.api.meta.*;
+import com.oracle.graal.compiler.test.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.common.*;
+
+/**
+ * Tests that deoptimization upon exception handling works.
+ */
+public class DeoptimizeOnExceptionTest extends GraalCompilerTest {
+
+    @Override
+    protected void editPhasePlan(ResolvedJavaMethod method, StructuredGraph graph, PhasePlan phasePlan) {
+        phasePlan.disablePhase(InliningPhase.class);
+    }
+
+    private static void raiseException(String m1, String m2, String m3, String m4, String m5) {
+        throw new RuntimeException(m1 + m2 + m3 + m4 + m5);
+    }
+
+    @Test
+    public void test1() {
+        test("test1Snippet", "m1", "m2", "m3", "m4", "m5");
+    }
+
+    // no local exception handler - will deopt
+    public static String test1Snippet(String m1, String m2, String m3, String m4, String m5) {
+        if (m1 != null) {
+            raiseException(m1, m2, m3, m4, m5);
+        }
+        return m1 + m2 + m3 + m4 + m5;
+    }
+}
--- a/src/cpu/x86/vm/graalRuntime_x86.cpp	Wed May 01 17:28:04 2013 +0200
+++ b/src/cpu/x86/vm/graalRuntime_x86.cpp	Wed May 01 18:04:28 2013 +0200
@@ -612,103 +612,6 @@
 #endif // _LP64
 }
 
-OopMapSet* GraalRuntime::generate_handle_exception(StubID id, GraalStubAssembler *sasm) {
-  __ block_comment("generate_handle_exception");
-
-  // incoming parameters
-  const Register exception_oop = rax;
-  const Register exception_pc  = rdx;
-  // other registers used in this stub
-  const Register thread = NOT_LP64(rdi) LP64_ONLY(r15_thread);
-
-  // Save registers, if required.
-  OopMapSet* oop_maps = new OopMapSet();
-  OopMap* oop_map = NULL;
-  switch (id) {
-    case handle_exception_nofpu_id:
-      // At this point all registers MAY be live.
-      oop_map = save_live_registers(sasm, 1 /*thread*/, id == handle_exception_nofpu_id);
-      break;
-    default:  ShouldNotReachHere();
-  }
-
-#ifdef TIERED
-  // C2 can leave the fpu stack dirty
-  if (UseSSE < 2) {
-    __ empty_FPU_stack();
-  }
-#endif // TIERED
-
-  // verify that only rax, and rdx is valid at this time
-#ifdef ASSERT
-  __ movptr(rbx, 0xDEAD);
-  __ movptr(rcx, 0xDEAD);
-  __ movptr(rsi, 0xDEAD);
-  __ movptr(rdi, 0xDEAD);
-#endif
-
-  // verify that rax, contains a valid exception
-  __ verify_not_null_oop(exception_oop);
-
-  // load address of JavaThread object for thread-local data
-  NOT_LP64(__ get_thread(thread);)
-
-#ifdef ASSERT
-  // check that fields in JavaThread for exception oop and issuing pc are
-  // empty before writing to them
-  Label oop_empty;
-  __ cmpptr(Address(thread, JavaThread::exception_oop_offset()), (int32_t) NULL_WORD);
-  __ jcc(Assembler::equal, oop_empty);
-  __ stop("exception oop already set");
-  __ bind(oop_empty);
-
-  Label pc_empty;
-  __ cmpptr(Address(thread, JavaThread::exception_pc_offset()), 0);
-  __ jcc(Assembler::equal, pc_empty);
-  __ stop("exception pc already set");
-  __ bind(pc_empty);
-#endif
-
-  // save exception oop and issuing pc into JavaThread
-  // (exception handler will load it from here)
-  __ movptr(Address(thread, JavaThread::exception_oop_offset()), exception_oop);
-  __ movptr(Address(thread, JavaThread::exception_pc_offset()),  exception_pc);
-
-  // patch throwing pc into return address (has bci & oop map)
-  __ movptr(Address(rbp, 1*BytesPerWord), exception_pc);
-
-  // compute the exception handler.
-  // the exception oop and the throwing pc are read from the fields in JavaThread
-  int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, exception_handler_for_pc));
-  oop_maps->add_gc_map(call_offset, oop_map);
-
-  // rax: handler address
-  //      will be the deopt blob if nmethod was deoptimized while we looked up
-  //      handler regardless of whether handler existed in the nmethod.
-
-  // only rax, is valid at this time, all other registers have been destroyed by the runtime call
-#ifdef ASSERT
-  __ movptr(rbx, 0xDEAD);
-  __ movptr(rcx, 0xDEAD);
-  __ movptr(rdx, 0xDEAD);
-  __ movptr(rsi, 0xDEAD);
-  __ movptr(rdi, 0xDEAD);
-#endif
-
-  // patch the return address, this stub will directly return to the exception handler
-  __ movptr(Address(rbp, 1*BytesPerWord), rax);
-
-  switch (id) {
-    case handle_exception_nofpu_id:
-      // Restore the registers that were saved at the beginning.
-      restore_live_registers(sasm, id == handle_exception_nofpu_id);
-      break;
-    default:  ShouldNotReachHere();
-  }
-
-  return oop_maps;
-}
-
 void GraalRuntime::generate_unwind_exception(GraalStubAssembler *sasm) {
   // incoming parameters
   const Register exception_oop = rax;
@@ -811,12 +714,6 @@
   OopMapSet* oop_maps = NULL;
   switch (id) {
 
-    case handle_exception_nofpu_id:
-      { GraalStubFrame f(sasm, "handle_exception", dont_gc_arguments);
-        oop_maps = generate_handle_exception(id, sasm);
-      }
-      break;
-
     case unwind_exception_call_id: {
       // remove the frame from the stack
       __ movptr(rsp, rbp);
--- a/src/share/vm/graal/graalCompilerToVM.cpp	Wed May 01 17:28:04 2013 +0200
+++ b/src/share/vm/graal/graalCompilerToVM.cpp	Wed May 01 18:04:28 2013 +0200
@@ -755,7 +755,6 @@
   set_address("wbPostCallStub", GraalRuntime::entry_for(GraalRuntime::wb_post_call_id));
 
   set_address("inlineCacheMissStub", SharedRuntime::get_ic_miss_stub());
-  set_address("handleExceptionStub", GraalRuntime::entry_for(GraalRuntime::handle_exception_nofpu_id));
   set_address("handleDeoptStub", SharedRuntime::deopt_blob()->unpack());
   set_address("monitorEnterStub", GraalRuntime::entry_for(GraalRuntime::monitorenter_id));
   set_address("monitorExitStub", GraalRuntime::entry_for(GraalRuntime::monitorexit_id));
@@ -786,8 +785,9 @@
   set_address("registerFinalizerAddress", SharedRuntime::register_finalizer);
   set_address("threadIsInterruptedAddress", GraalRuntime::thread_is_interrupted);
   set_address("uncommonTrapStub", SharedRuntime::deopt_blob()->uncommon_trap());
-  set_address("stubPrintfAddress", GraalRuntime::stub_printf);
+  set_address("vmMessageAddress", GraalRuntime::vm_message);
   set_address("identityHashCodeAddress", GraalRuntime::identity_hash_code);
+  set_address("handleExceptionForPcAddress", GraalRuntime::exception_handler_for_pc);
 
   set_int("deoptReasonNone", Deoptimization::Reason_none);
   set_int("deoptReasonNullCheck", Deoptimization::Reason_null_check);
--- a/src/share/vm/graal/graalRuntime.cpp	Wed May 01 17:28:04 2013 +0200
+++ b/src/share/vm/graal/graalRuntime.cpp	Wed May 01 18:04:28 2013 +0200
@@ -402,7 +402,6 @@
     }
   }
 
-  thread->set_vm_result(exception());
   // Set flag if return address is a method handle call site.
   thread->set_is_method_handle_return(nm->is_method_handle_return(pc));
 
@@ -570,10 +569,14 @@
   tty->print(buf, v1, v2, v3);
 JRT_END
 
-JRT_LEAF(void, GraalRuntime::stub_printf(jlong format, jlong v1, jlong v2, jlong v3))
+JRT_LEAF(void, GraalRuntime::vm_message(jboolean vmError, jlong format, jlong v1, jlong v2, jlong v3))
   ResourceMark rm;
   char *buf = (char*) (address) format;
-  tty->print(buf, v1, v2, v3);
+  if (vmError) {
+    fatal(err_msg(buf, v1, v2, v3));
+  } else {
+    tty->print(buf, v1, v2, v3);
+  }
 JRT_END
 
 JRT_ENTRY(void, GraalRuntime::log_primitive(JavaThread* thread, jchar typeChar, jlong value, jboolean newline))
--- a/src/share/vm/graal/graalRuntime.hpp	Wed May 01 17:28:04 2013 +0200
+++ b/src/share/vm/graal/graalRuntime.hpp	Wed May 01 18:04:28 2013 +0200
@@ -81,7 +81,6 @@
 // runtime routines needed by code code generated
 // by Graal.
 #define GRAAL_STUBS(stub, last_entry) \
-  stub(handle_exception_nofpu) /* optimized version that does not preserve fpu registers */ \
   stub(unwind_exception_call)   \
   stub(OSR_migration_end)       \
   stub(arithmetic_frem)         \
@@ -119,7 +118,6 @@
   // stub generation
   static void       generate_blob_for(BufferBlob* blob, StubID id);
   static OopMapSet* generate_code_for(StubID id, GraalStubAssembler* sasm);
-  static OopMapSet* generate_handle_exception(StubID id, GraalStubAssembler* sasm);
   static void       generate_unwind_exception(GraalStubAssembler *sasm);
 
   static OopMapSet* generate_stub_call(GraalStubAssembler* sasm, Register result, address entry,
@@ -128,8 +126,6 @@
   // runtime entry points
   static void unimplemented_entry(JavaThread* thread, StubID id);
 
-  static address exception_handler_for_pc(JavaThread* thread);
-
   static void create_null_exception(JavaThread* thread);
   static void create_out_of_bounds_exception(JavaThread* thread, jint index);
   static void monitorenter(JavaThread* thread, oopDesc* obj, BasicLock* lock);
@@ -154,8 +150,10 @@
   static void new_array(JavaThread* thread, Klass* klass, jint length);
   static void new_multi_array(JavaThread* thread, Klass* klass, int rank, jint* dims);
   static jboolean thread_is_interrupted(JavaThread* thread, oopDesc* obj, jboolean clear_interrupte);
-  static void stub_printf(jlong format, jlong v1, jlong v2, jlong v3);
+  static void vm_message(jboolean vmError, jlong format, jlong v1, jlong v2, jlong v3);
   static jint identity_hash_code(JavaThread* thread, oopDesc* objd);
+  static address exception_handler_for_pc(JavaThread* thread);
+
   // initialization
   static void initialize(BufferBlob* blob);