changeset 15104:ed29f7ff71eb

add DeoptimizationStub
author twisti
date Mon, 14 Apr 2014 17:21:49 -1000
parents 9dc7efd43c44
children 4833806209f2 083e9e4df58a
files graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizationStub.java graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizeOp.java graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotDeoptimizeCallerOp.java graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotEnterUnpackFramesStackFrameOp.java graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotEpilogueOp.java graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotJumpToExceptionHandlerInCallerOp.java graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLeaveCurrentStackFrameOp.java graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLeaveDeoptimizedStackFrameOp.java graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLeaveUnpackFramesStackFrameOp.java graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotPushInterpreterFrameOp.java graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotReturnOp.java graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotUnwindOp.java graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerator.java graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotLIRGenerator.java graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCDeoptimizationStub.java graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCDeoptimizeOp.java graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotDeoptimizeCallerOp.java graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotForeignCallsProvider.java graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledRuntimeStub.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRGenerator.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EnterUnpackFramesStackFrameNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/LeaveCurrentStackFrameNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/LeaveDeoptimizedStackFrameNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/LeaveUnpackFramesStackFrameNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/PushInterpreterFrameNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SaveAllRegistersNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/StubForeignCallNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/UncommonTrapCallNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/DeoptimizationStub.java src/cpu/x86/vm/sharedRuntime_x86_64.cpp src/cpu/x86/vm/vmStructs_x86.hpp src/share/vm/code/codeBlob.hpp src/share/vm/graal/graalCompilerToVM.cpp src/share/vm/runtime/deoptimization.cpp
diffstat 41 files changed, 1442 insertions(+), 58 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizationStub.java	Mon Apr 14 17:21:49 2014 -1000
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2014, 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 com.oracle.graal.api.code.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.stubs.*;
+
+final class AMD64DeoptimizationStub extends DeoptimizationStub {
+
+    private RegisterConfig registerConfig;
+
+    public AMD64DeoptimizationStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
+        super(providers, target, linkage);
+        registerConfig = new AMD64HotSpotRegisterConfig(target.arch, HotSpotGraalRuntime.runtime().getConfig(), new Register[]{rax, rbx, rcx, rdx, rsi, rdi, r8, r9, r10, r11, r13, r14});
+    }
+
+    @Override
+    public RegisterConfig getRegisterConfig() {
+        return registerConfig;
+    }
+}
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizeOp.java	Mon Apr 14 15:36:27 2014 -1000
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizeOp.java	Mon Apr 14 17:21:49 2014 -1000
@@ -41,6 +41,6 @@
 
     @Override
     public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-        AMD64Call.directCall(crb, masm, crb.foreignCalls.lookupForeignCall(UNCOMMON_TRAP), null, false, info);
+        AMD64Call.directCall(crb, masm, crb.foreignCalls.lookupForeignCall(UNCOMMON_TRAP_HANDLER), null, false, info);
     }
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotDeoptimizeCallerOp.java	Mon Apr 14 15:36:27 2014 -1000
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotDeoptimizeCallerOp.java	Mon Apr 14 17:21:49 2014 -1000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -26,6 +26,7 @@
 
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.*;
 import com.oracle.graal.lir.amd64.*;
 import com.oracle.graal.lir.asm.*;
 
@@ -33,11 +34,11 @@
  * Removes the current frame and tail calls the uncommon trap routine.
  */
 @Opcode("DEOPT_CALLER")
-final class AMD64HotSpotDeoptimizeCallerOp extends AMD64HotSpotEpilogueOp {
+final class AMD64HotSpotDeoptimizeCallerOp extends AMD64HotSpotEpilogueOp implements BlockEndOp {
 
     @Override
     public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
         leaveFrameAndRestoreRbp(crb, masm);
-        AMD64Call.directJmp(crb, masm, crb.foreignCalls.lookupForeignCall(UNCOMMON_TRAP));
+        AMD64Call.directJmp(crb, masm, crb.foreignCalls.lookupForeignCall(UNCOMMON_TRAP_HANDLER));
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotEnterUnpackFramesStackFrameOp.java	Mon Apr 14 17:21:49 2014 -1000
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2013, 2014, 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.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.hotspot.stubs.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.amd64.*;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Emits code that enters a stack frame which is tailored to call the C++ method
+ * {@link DeoptimizationStub#UNPACK_FRAMES Deoptimization::unpack_frames}.
+ */
+@Opcode("ENTER_UNPACK_FRAMES_STACK_FRAME")
+final class AMD64HotSpotEnterUnpackFramesStackFrameOp extends AMD64LIRInstruction {
+
+    private final Register thread;
+    private final int threadLastJavaSpOffset;
+    private final int threadLastJavaPcOffset;
+    private final int threadLastJavaFpOffset;
+    @Alive(REG) AllocatableValue framePc;
+    @Alive(REG) AllocatableValue senderSp;
+    @Alive(REG) AllocatableValue senderFp;
+
+    AMD64HotSpotEnterUnpackFramesStackFrameOp(Register thread, int threadLastJavaSpOffset, int threadLastJavaPcOffset, int threadLastJavaFpOffset, AllocatableValue framePc, AllocatableValue senderSp,
+                    AllocatableValue senderFp) {
+        this.thread = thread;
+        this.threadLastJavaSpOffset = threadLastJavaSpOffset;
+        this.threadLastJavaPcOffset = threadLastJavaPcOffset;
+        this.threadLastJavaFpOffset = threadLastJavaFpOffset;
+        this.framePc = framePc;
+        this.senderSp = senderSp;
+        this.senderFp = senderFp;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        final int totalFrameSize = crb.frameMap.totalFrameSize();
+        masm.push(asRegister(framePc));
+        masm.push(asRegister(senderFp));
+        masm.movq(rbp, rsp);
+
+        /*
+         * Allocate a full sized frame. Since return address and base pointer are already in place
+         * (see above) we allocate two words less.
+         */
+        masm.decrementq(rsp, totalFrameSize - 2 * crb.target.wordSize);
+
+        // Set up last Java values.
+        masm.movq(new AMD64Address(thread, threadLastJavaSpOffset), rsp);
+
+        /*
+         * Save the PC since it cannot easily be retrieved using the last Java SP after we aligned
+         * SP. Don't need the precise return PC here, just precise enough to point into this code
+         * blob.
+         */
+        masm.leaq(rax, new AMD64Address(rip, 0));
+        masm.movq(new AMD64Address(thread, threadLastJavaPcOffset), rax);
+
+        // Use BP because the frames look interpreted now.
+        masm.movq(new AMD64Address(thread, threadLastJavaFpOffset), rbp);
+
+        // Align the stack for the following unpackFrames call.
+        masm.andq(rsp, -(crb.target.stackAlignment));
+    }
+}
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotEpilogueOp.java	Mon Apr 14 15:36:27 2014 -1000
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotEpilogueOp.java	Mon Apr 14 17:21:49 2014 -1000
@@ -29,7 +29,6 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.amd64.*;
-import com.oracle.graal.lir.StandardOp.BlockEndOp;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.amd64.*;
 import com.oracle.graal.lir.asm.*;
@@ -37,7 +36,7 @@
 /**
  * Superclass for operations that use the value of RBP saved in a method's prologue.
  */
-abstract class AMD64HotSpotEpilogueOp extends AMD64LIRInstruction implements BlockEndOp {
+abstract class AMD64HotSpotEpilogueOp extends AMD64LIRInstruction {
 
     /**
      * The type of location (i.e., stack or register) in which RBP is saved is not known until
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java	Mon Apr 14 15:36:27 2014 -1000
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java	Mon Apr 14 17:21:49 2014 -1000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, 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
@@ -51,7 +51,8 @@
 
     @Override
     public void initialize(HotSpotProviders providers, HotSpotVMConfig config) {
-        Kind word = providers.getCodeCache().getTarget().wordKind;
+        TargetDescription target = providers.getCodeCache().getTarget();
+        Kind word = target.wordKind;
 
         // The calling convention for the exception handler stub is (only?) defined in
         // TemplateInterpreterGenerator::generate_throw_exception()
@@ -62,6 +63,8 @@
         register(new HotSpotForeignCallLinkage(EXCEPTION_HANDLER, 0L, PRESERVES_REGISTERS, LEAF_NOFP, null, exceptionCc, NOT_REEXECUTABLE, ANY_LOCATION));
         register(new HotSpotForeignCallLinkage(EXCEPTION_HANDLER_IN_CALLER, JUMP_ADDRESS, PRESERVES_REGISTERS, LEAF_NOFP, exceptionCc, null, NOT_REEXECUTABLE, ANY_LOCATION));
 
+        link(new AMD64DeoptimizationStub(providers, target, registerStubCall(UNCOMMON_TRAP_HANDLER, REEXECUTABLE, LEAF, NO_LOCATIONS)));
+
         // When the java.ext.dirs property is modified then the crypto classes might not be found.
         // If that's the case we ignore the ClassNotFoundException and continue since we cannot
         // replace a non-existing method anyway.
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotJumpToExceptionHandlerInCallerOp.java	Mon Apr 14 15:36:27 2014 -1000
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotJumpToExceptionHandlerInCallerOp.java	Mon Apr 14 17:21:49 2014 -1000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -31,6 +31,7 @@
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.asm.amd64.AMD64Assembler.ConditionFlag;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.*;
 import com.oracle.graal.lir.asm.*;
 
 /**
@@ -38,7 +39,7 @@
  * and jumps to the handler.
  */
 @Opcode("JUMP_TO_EXCEPTION_HANDLER_IN_CALLER")
-final class AMD64HotSpotJumpToExceptionHandlerInCallerOp extends AMD64HotSpotEpilogueOp {
+final class AMD64HotSpotJumpToExceptionHandlerInCallerOp extends AMD64HotSpotEpilogueOp implements BlockEndOp {
 
     @Use(REG) AllocatableValue handlerInCallerPc;
     @Use(REG) AllocatableValue exception;
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Mon Apr 14 15:36:27 2014 -1000
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Mon Apr 14 17:21:49 2014 -1000
@@ -25,6 +25,7 @@
 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.hotspot.nodes.UncommonTrapCallNode.*;
 
 import java.util.*;
 
@@ -43,7 +44,8 @@
 import com.oracle.graal.hotspot.nodes.type.*;
 import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.StandardOp.NoOp;
+import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
+import com.oracle.graal.lir.StandardOp.*;
 import com.oracle.graal.lir.amd64.*;
 import com.oracle.graal.lir.amd64.AMD64ControlFlow.CondMoveOp;
 import com.oracle.graal.lir.amd64.AMD64Move.CompareAndSwapOp;
@@ -176,12 +178,65 @@
         super.emitForeignCall(linkage, result, arguments, temps, info);
     }
 
-    protected AMD64SaveRegistersOp emitSaveRegisters(Register[] savedRegisters, StackSlot[] savedRegisterLocations) {
-        AMD64SaveRegistersOp save = new AMD64SaveRegistersOp(savedRegisters, savedRegisterLocations, true);
+    public void emitLeaveCurrentStackFrame() {
+        append(new AMD64HotSpotLeaveCurrentStackFrameOp());
+    }
+
+    public void emitLeaveDeoptimizedStackFrame(Value frameSize, Value initialInfo) {
+        Variable frameSizeVariable = load(frameSize);
+        Variable initialInfoVariable = load(initialInfo);
+        append(new AMD64HotSpotLeaveDeoptimizedStackFrameOp(frameSizeVariable, initialInfoVariable));
+    }
+
+    public void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp) {
+        Register thread = getProviders().getRegisters().getThreadRegister();
+        Variable framePcVariable = load(framePc);
+        Variable senderSpVariable = load(senderSp);
+        Variable senderFpVariable = load(senderFp);
+        append(new AMD64HotSpotEnterUnpackFramesStackFrameOp(thread, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadLastJavaFpOffset(), framePcVariable,
+                        senderSpVariable, senderFpVariable));
+    }
+
+    public void emitLeaveUnpackFramesStackFrame() {
+        Register thread = getProviders().getRegisters().getThreadRegister();
+        append(new AMD64HotSpotLeaveUnpackFramesStackFrameOp(thread, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadLastJavaFpOffset()));
+    }
+
+    /**
+     * @param savedRegisters the registers saved by this operation which may be subject to pruning
+     * @param savedRegisterLocations the slots to which the registers are saved
+     * @param supportsRemove determines if registers can be pruned
+     */
+    protected AMD64SaveRegistersOp emitSaveRegisters(Register[] savedRegisters, StackSlot[] savedRegisterLocations, boolean supportsRemove) {
+        AMD64SaveRegistersOp save = new AMD64SaveRegistersOp(savedRegisters, savedRegisterLocations, supportsRemove);
         append(save);
         return save;
     }
 
+    /**
+     * Adds a node to the graph that saves all allocatable registers to the stack.
+     *
+     * @param supportsRemove determines if registers can be pruned
+     * @return the register save node
+     */
+    private AMD64SaveRegistersOp emitSaveAllRegisters(Register[] savedRegisters, boolean supportsRemove) {
+        StackSlot[] savedRegisterLocations = new StackSlot[savedRegisters.length];
+        for (int i = 0; i < savedRegisters.length; i++) {
+            PlatformKind kind = target().arch.getLargestStorableKind(savedRegisters[i].getRegisterCategory());
+            assert kind != Kind.Illegal;
+            StackSlot spillSlot = getResult().getFrameMap().allocateSpillSlot(kind);
+            savedRegisterLocations[i] = spillSlot;
+        }
+        return emitSaveRegisters(savedRegisters, savedRegisterLocations, supportsRemove);
+    }
+
+    @Override
+    public SaveRegistersOp emitSaveAllRegisters() {
+        // We are saving all registers.
+        // TODO Save upper half of YMM registers.
+        return emitSaveAllRegisters(cpuxmmRegisters, false);
+    }
+
     protected void emitRestoreRegisters(AMD64SaveRegistersOp save) {
         append(new AMD64RestoreRegistersOp(save.getSlots().clone(), save));
     }
@@ -196,19 +251,11 @@
         boolean destroysRegisters = hotspotLinkage.destroysRegisters();
 
         AMD64SaveRegistersOp save = null;
-        StackSlot[] savedRegisterLocations = null;
         if (destroysRegisters) {
             if (getStub() != null) {
                 if (getStub().preservesRegisters()) {
                     Register[] savedRegisters = getResult().getFrameMap().registerConfig.getAllocatableRegisters();
-                    savedRegisterLocations = new StackSlot[savedRegisters.length];
-                    for (int i = 0; i < savedRegisters.length; i++) {
-                        PlatformKind kind = target().arch.getLargestStorableKind(savedRegisters[i].getRegisterCategory());
-                        assert kind != Kind.Illegal;
-                        StackSlot spillSlot = getResult().getFrameMap().allocateSpillSlot(kind);
-                        savedRegisterLocations[i] = spillSlot;
-                    }
-                    save = emitSaveRegisters(savedRegisters, savedRegisterLocations);
+                    save = emitSaveAllRegisters(savedRegisters, true);
                 }
             }
         }
@@ -233,9 +280,9 @@
         if (destroysRegisters) {
             if (getStub() != null) {
                 if (getStub().preservesRegisters()) {
-                    assert !((AMD64HotSpotLIRGenerationResult) getResult()).getCalleeSaveInfo().containsKey(currentRuntimeCallInfo);
-                    ((AMD64HotSpotLIRGenerationResult) getResult()).getCalleeSaveInfo().put(currentRuntimeCallInfo, save);
-
+                    AMD64HotSpotLIRGenerationResult generationResult = (AMD64HotSpotLIRGenerationResult) getResult();
+                    assert !generationResult.getCalleeSaveInfo().containsKey(currentRuntimeCallInfo);
+                    generationResult.getCalleeSaveInfo().put(currentRuntimeCallInfo, save);
                     emitRestoreRegisters(save);
                 } else {
                     assert zapRegisters();
@@ -246,6 +293,21 @@
         return result;
     }
 
+    public Value emitUncommonTrapCall(Value trapRequest, SaveRegistersOp saveRegisterOp) {
+        ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(UNCOMMON_TRAP);
+
+        Register thread = getProviders().getRegisters().getThreadRegister();
+        append(new AMD64HotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), thread));
+        Variable result = super.emitForeignCall(linkage, null, thread.asValue(Kind.Long), trapRequest);
+        append(new AMD64HotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaFpOffset(), thread));
+
+        Map<LIRFrameState, SaveRegistersOp> calleeSaveInfo = ((AMD64HotSpotLIRGenerationResult) getResult()).getCalleeSaveInfo();
+        assert !calleeSaveInfo.containsKey(currentRuntimeCallInfo);
+        calleeSaveInfo.put(currentRuntimeCallInfo, saveRegisterOp);
+
+        return result;
+    }
+
     protected AMD64ZapRegistersOp emitZapRegisters(Register[] zappedRegisters, Constant[] zapValues) {
         AMD64ZapRegistersOp zap = new AMD64ZapRegistersOp(zappedRegisters, zapValues);
         append(zap);
@@ -374,6 +436,14 @@
         }
     }
 
+    public void emitPushInterpreterFrame(Value frameSize, Value framePc, Value senderSp, Value initialInfo) {
+        Variable frameSizeVariable = load(frameSize);
+        Variable framePcVariable = load(framePc);
+        Variable senderSpVariable = load(senderSp);
+        Variable initialInfoVariable = load(initialInfo);
+        append(new AMD64HotSpotPushInterpreterFrameOp(frameSizeVariable, framePcVariable, senderSpVariable, initialInfoVariable));
+    }
+
     @Override
     public Variable emitLoad(PlatformKind kind, Value address, Access access) {
         AMD64AddressValue loadAddress = asAddressValue(address);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLeaveCurrentStackFrameOp.java	Mon Apr 14 17:21:49 2014 -1000
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2013, 2014, 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 com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Pops the current frame off the stack including the return address.
+ */
+@Opcode("LEAVE_CURRENT_STACK_FRAME")
+final class AMD64HotSpotLeaveCurrentStackFrameOp extends AMD64HotSpotEpilogueOp {
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        leaveFrameAndRestoreRbp(crb, masm);
+        masm.addq(rsp, crb.target.arch.getReturnAddressSize());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLeaveDeoptimizedStackFrameOp.java	Mon Apr 14 17:21:49 2014 -1000
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.amd64;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.amd64.AMD64.*;
+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.*;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Pops the current frame off the stack including the return address.
+ */
+@Opcode("LEAVE_DEOPTIMIZED_STACK_FRAME")
+final class AMD64HotSpotLeaveDeoptimizedStackFrameOp extends AMD64HotSpotEpilogueOp {
+
+    @Use(REG) AllocatableValue frameSize;
+    @Use(REG) AllocatableValue framePointer;
+
+    public AMD64HotSpotLeaveDeoptimizedStackFrameOp(AllocatableValue frameSize, AllocatableValue initialInfo) {
+        this.frameSize = frameSize;
+        this.framePointer = initialInfo;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        masm.addq(rsp, asRegister(frameSize));
+        // Restore the frame pointer before stack bang because if a stack overflow is thrown it
+        // needs to be pushed (and preserved).
+        masm.movq(rbp, asRegister(framePointer));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLeaveUnpackFramesStackFrameOp.java	Mon Apr 14 17:21:49 2014 -1000
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.amd64;
+
+import static com.oracle.graal.amd64.AMD64.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.hotspot.stubs.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.amd64.*;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Emits code that leaves a stack frame which is tailored to call the C++ method
+ * {@link DeoptimizationStub#UNPACK_FRAMES Deoptimization::unpack_frames}.
+ */
+@Opcode("LEAVE_UNPACK_FRAMES_STACK_FRAME")
+final class AMD64HotSpotLeaveUnpackFramesStackFrameOp extends AMD64LIRInstruction {
+
+    private final Register thread;
+    private final int threadLastJavaSpOffset;
+    private final int threadLastJavaPcOffset;
+    private final int threadLastJavaFpOffset;
+
+    AMD64HotSpotLeaveUnpackFramesStackFrameOp(Register thread, int threadLastJavaSpOffset, int threadLastJavaPcOffset, int threadLastJavaFpOffset) {
+        this.thread = thread;
+        this.threadLastJavaSpOffset = threadLastJavaSpOffset;
+        this.threadLastJavaPcOffset = threadLastJavaPcOffset;
+        this.threadLastJavaFpOffset = threadLastJavaFpOffset;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        // Restore stack pointer.
+        masm.movq(rsp, new AMD64Address(thread, threadLastJavaSpOffset));
+
+        // Clear last Java frame values.
+        masm.movslq(new AMD64Address(thread, threadLastJavaSpOffset), 0);
+        masm.movslq(new AMD64Address(thread, threadLastJavaPcOffset), 0);
+        masm.movslq(new AMD64Address(thread, threadLastJavaFpOffset), 0);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotPushInterpreterFrameOp.java	Mon Apr 14 17:21:49 2014 -1000
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.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.hotspot.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.amd64.*;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Pushes an interpreter frame to the stack.
+ */
+@Opcode("PUSH_INTERPRETER_FRAME")
+final class AMD64HotSpotPushInterpreterFrameOp extends AMD64LIRInstruction {
+
+    @Alive(REG) AllocatableValue frameSize;
+    @Alive(REG) AllocatableValue framePc;
+    @Alive(REG) AllocatableValue senderSp;
+    @Alive(REG) AllocatableValue initialInfo;
+
+    AMD64HotSpotPushInterpreterFrameOp(AllocatableValue frameSize, AllocatableValue framePc, AllocatableValue senderSp, AllocatableValue initialInfo) {
+        this.frameSize = frameSize;
+        this.framePc = framePc;
+        this.senderSp = senderSp;
+        this.initialInfo = initialInfo;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        final Register frameSizeRegister = asRegister(frameSize);
+        final Register framePcRegister = asRegister(framePc);
+        final Register senderSpRegister = asRegister(senderSp);
+        final Register initialInfoRegister = asRegister(initialInfo);
+        final HotSpotVMConfig config = HotSpotGraalRuntime.runtime().getConfig();
+        final int wordSize = HotSpotGraalRuntime.runtime().getTarget().wordSize;
+
+        // We'll push PC and BP by hand.
+        masm.subq(frameSizeRegister, 2 * wordSize);
+
+        // Push return address.
+        masm.push(framePcRegister);
+
+        // Prolog
+        masm.push(initialInfoRegister);
+        masm.movq(initialInfoRegister, rsp);
+        masm.subq(rsp, frameSizeRegister);
+
+        // This value is corrected by layout_activation_impl.
+        masm.movptr(new AMD64Address(initialInfoRegister, config.frameInterpreterFrameLastSpOffset * wordSize), 0);
+
+        // Make the frame walkable.
+        masm.movq(new AMD64Address(initialInfoRegister, config.frameInterpreterFrameSenderSpOffset * wordSize), senderSpRegister);
+    }
+}
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotReturnOp.java	Mon Apr 14 15:36:27 2014 -1000
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotReturnOp.java	Mon Apr 14 17:21:49 2014 -1000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -29,13 +29,14 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.*;
 import com.oracle.graal.lir.asm.*;
 
 /**
  * Returns from a function.
  */
 @Opcode("RETURN")
-final class AMD64HotSpotReturnOp extends AMD64HotSpotEpilogueOp {
+final class AMD64HotSpotReturnOp extends AMD64HotSpotEpilogueOp implements BlockEndOp {
 
     @Use({REG, ILLEGAL}) protected Value value;
     private final boolean isStub;
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotUnwindOp.java	Mon Apr 14 15:36:27 2014 -1000
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotUnwindOp.java	Mon Apr 14 17:21:49 2014 -1000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -31,6 +31,7 @@
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.*;
 import com.oracle.graal.lir.amd64.*;
 import com.oracle.graal.lir.asm.*;
 
@@ -38,7 +39,7 @@
  * Removes the current frame and jumps to the {@link UnwindExceptionToCallerStub}.
  */
 @Opcode("UNWIND")
-final class AMD64HotSpotUnwindOp extends AMD64HotSpotEpilogueOp {
+final class AMD64HotSpotUnwindOp extends AMD64HotSpotEpilogueOp implements BlockEndOp {
 
     @Use({REG}) protected RegisterValue exception;
 
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerator.java	Mon Apr 14 15:36:27 2014 -1000
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerator.java	Mon Apr 14 17:21:49 2014 -1000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, 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
@@ -35,6 +35,7 @@
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.type.*;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
 import com.oracle.graal.lir.hsail.*;
 import com.oracle.graal.lir.hsail.HSAILControlFlow.CondMoveOp;
 import com.oracle.graal.lir.hsail.HSAILControlFlow.DeoptimizeOp;
@@ -286,15 +287,15 @@
     }
 
     public void emitTailcall(Value[] args, Value address) {
-        throw GraalInternalError.shouldNotReachHere("NYI");
+        throw GraalInternalError.unimplemented();
     }
 
     public void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason) {
-        throw GraalInternalError.shouldNotReachHere("NYI");
+        throw GraalInternalError.unimplemented();
     }
 
     public StackSlot getLockSlot(int lockDepth) {
-        throw GraalInternalError.shouldNotReachHere("NYI");
+        throw GraalInternalError.unimplemented();
     }
 
     @Override
@@ -310,4 +311,32 @@
         append(new HSAILMove.UncompressPointer(result, asAllocatable(pointer), encoding.base, encoding.shift, encoding.alignment, nonNull));
         return result;
     }
+
+    public void emitLeaveCurrentStackFrame() {
+        throw GraalInternalError.unimplemented();
+    }
+
+    public void emitLeaveDeoptimizedStackFrame(Value frameSize, Value initialInfo) {
+        throw GraalInternalError.unimplemented();
+    }
+
+    public void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp) {
+        throw GraalInternalError.unimplemented();
+    }
+
+    public void emitLeaveUnpackFramesStackFrame() {
+        throw GraalInternalError.unimplemented();
+    }
+
+    public SaveRegistersOp emitSaveAllRegisters() {
+        throw GraalInternalError.unimplemented();
+    }
+
+    public void emitPushInterpreterFrame(Value frameSize, Value framePc, Value senderSp, Value initialInfo) {
+        throw GraalInternalError.unimplemented();
+    }
+
+    public Value emitUncommonTrapCall(Value trapRequest, SaveRegistersOp saveRegisterOp) {
+        throw GraalInternalError.unimplemented();
+    }
 }
--- a/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotLIRGenerator.java	Mon Apr 14 15:36:27 2014 -1000
+++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotLIRGenerator.java	Mon Apr 14 17:21:49 2014 -1000
@@ -31,6 +31,7 @@
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.HotSpotVMConfig.CompressEncoding;
 import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
 
 /**
  * LIR generator specialized for PTX HotSpot.
@@ -70,4 +71,32 @@
         // TODO
         throw GraalInternalError.unimplemented();
     }
+
+    public void emitLeaveCurrentStackFrame() {
+        throw GraalInternalError.unimplemented();
+    }
+
+    public void emitLeaveDeoptimizedStackFrame(Value frameSize, Value initialInfo) {
+        throw GraalInternalError.unimplemented();
+    }
+
+    public void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp) {
+        throw GraalInternalError.unimplemented();
+    }
+
+    public void emitLeaveUnpackFramesStackFrame() {
+        throw GraalInternalError.unimplemented();
+    }
+
+    public SaveRegistersOp emitSaveAllRegisters() {
+        throw GraalInternalError.unimplemented();
+    }
+
+    public void emitPushInterpreterFrame(Value frameSize, Value framePc, Value senderSp, Value initialInfo) {
+        throw GraalInternalError.unimplemented();
+    }
+
+    public Value emitUncommonTrapCall(Value trapRequest, SaveRegistersOp saveRegisterOp) {
+        throw GraalInternalError.unimplemented();
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCDeoptimizationStub.java	Mon Apr 14 17:21:49 2014 -1000
@@ -0,0 +1,45 @@
+/*
+ * 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.sparc;
+
+import static com.oracle.graal.sparc.SPARC.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.stubs.*;
+
+final class SPARCDeoptimizationStub extends DeoptimizationStub {
+
+    private RegisterConfig registerConfig;
+
+    public SPARCDeoptimizationStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
+        super(providers, target, linkage);
+        registerConfig = new SPARCHotSpotRegisterConfig(target, new Register[]{o0, o1, o2, o3, o4, o5, o7, l0, l1, l2, l3, l4, l5, l6, l7, i0, i1, i2, i3, i4, i5, f0, f1, f2, f3, f4, f5, f6, f7});
+    }
+
+    @Override
+    public RegisterConfig getRegisterConfig() {
+        return registerConfig;
+    }
+}
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCDeoptimizeOp.java	Mon Apr 14 15:36:27 2014 -1000
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCDeoptimizeOp.java	Mon Apr 14 17:21:49 2014 -1000
@@ -49,6 +49,6 @@
         // [Deopt Handler Code]
         // 0xffffffff749bb60c: call 0xffffffff748da540 ; {runtime_call}
         // 0xffffffff749bb610: nop
-        SPARCCall.directCall(crb, masm, crb.foreignCalls.lookupForeignCall(UNCOMMON_TRAP), null, false, info);
+        SPARCCall.directCall(crb, masm, crb.foreignCalls.lookupForeignCall(UNCOMMON_TRAP_HANDLER), null, false, info);
     }
 }
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotDeoptimizeCallerOp.java	Mon Apr 14 15:36:27 2014 -1000
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotDeoptimizeCallerOp.java	Mon Apr 14 17:21:49 2014 -1000
@@ -47,7 +47,7 @@
         // HotSpotFrameContext frameContext = backend.new HotSpotFrameContext(isStub);
         // frameContext.enter(crb);
         Register scratch = g3;
-        SPARCCall.indirectJmp(crb, masm, scratch, crb.foreignCalls.lookupForeignCall(UNCOMMON_TRAP));
+        SPARCCall.indirectJmp(crb, masm, scratch, crb.foreignCalls.lookupForeignCall(UNCOMMON_TRAP_HANDLER));
 
         // frameContext.leave(crb);
     }
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotForeignCallsProvider.java	Mon Apr 14 15:36:27 2014 -1000
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotForeignCallsProvider.java	Mon Apr 14 17:21:49 2014 -1000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, 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
@@ -46,7 +46,8 @@
 
     @Override
     public void initialize(HotSpotProviders providers, HotSpotVMConfig config) {
-        Kind word = providers.getCodeCache().getTarget().wordKind;
+        TargetDescription target = providers.getCodeCache().getTarget();
+        Kind word = target.wordKind;
 
         // The calling convention for the exception handler stub is (only?) defined in
         // TemplateInterpreterGenerator::generate_throw_exception()
@@ -60,6 +61,8 @@
         register(new HotSpotForeignCallLinkage(EXCEPTION_HANDLER, 0L, PRESERVES_REGISTERS, LEAF_NOFP, outgoingExceptionCc, incomingExceptionCc, NOT_REEXECUTABLE, ANY_LOCATION));
         register(new HotSpotForeignCallLinkage(EXCEPTION_HANDLER_IN_CALLER, JUMP_ADDRESS, PRESERVES_REGISTERS, LEAF_NOFP, outgoingExceptionCc, incomingExceptionCc, NOT_REEXECUTABLE, ANY_LOCATION));
 
+        link(new SPARCDeoptimizationStub(providers, target, registerStubCall(UNCOMMON_TRAP_HANDLER, REEXECUTABLE, LEAF, NO_LOCATIONS)));
+
         super.initialize(providers, config);
     }
 
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Mon Apr 14 15:36:27 2014 -1000
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Mon Apr 14 17:21:49 2014 -1000
@@ -35,6 +35,7 @@
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
 import com.oracle.graal.lir.sparc.*;
 import com.oracle.graal.lir.sparc.SPARCMove.LoadOp;
 import com.oracle.graal.lir.sparc.SPARCMove.StoreConstantOp;
@@ -258,4 +259,39 @@
         // TODO
         throw GraalInternalError.unimplemented();
     }
+
+    public SaveRegistersOp emitSaveAllRegisters() {
+        // TODO Auto-generated method stub
+        throw GraalInternalError.unimplemented();
+    }
+
+    public void emitLeaveCurrentStackFrame() {
+        // TODO Auto-generated method stub
+        throw GraalInternalError.unimplemented();
+    }
+
+    public void emitLeaveDeoptimizedStackFrame(Value frameSize, Value initialInfo) {
+        // TODO Auto-generated method stub
+        throw GraalInternalError.unimplemented();
+    }
+
+    public void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp) {
+        // TODO Auto-generated method stub
+        throw GraalInternalError.unimplemented();
+    }
+
+    public void emitLeaveUnpackFramesStackFrame() {
+        // TODO Auto-generated method stub
+        throw GraalInternalError.unimplemented();
+    }
+
+    public void emitPushInterpreterFrame(Value frameSize, Value framePc, Value senderSp, Value initialInfo) {
+        // TODO Auto-generated method stub
+        throw GraalInternalError.unimplemented();
+    }
+
+    public Value emitUncommonTrapCall(Value trapRequest, SaveRegistersOp saveRegisterOp) {
+        // TODO Auto-generated method stub
+        throw GraalInternalError.unimplemented();
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java	Mon Apr 14 15:36:27 2014 -1000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java	Mon Apr 14 17:21:49 2014 -1000
@@ -45,9 +45,9 @@
 public abstract class HotSpotBackend extends Backend {
 
     /**
-     * Descriptor for SharedRuntime::deopt_blob()-&gt;uncommon_trap().
+     * Descriptor for {@link DeoptimizationStub}.
      */
-    public static final ForeignCallDescriptor UNCOMMON_TRAP = new ForeignCallDescriptor("deoptimize", void.class);
+    public static final ForeignCallDescriptor UNCOMMON_TRAP_HANDLER = new ForeignCallDescriptor("uncommonTrapHandler", void.class);
 
     /**
      * Descriptor for {@link ExceptionHandlerStub}. This stub is called by the
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledRuntimeStub.java	Mon Apr 14 15:36:27 2014 -1000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledRuntimeStub.java	Mon Apr 14 17:21:49 2014 -1000
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.hotspot;
 
+import static com.oracle.graal.hotspot.HotSpotBackend.*;
+
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.code.CompilationResult.Call;
 import com.oracle.graal.api.code.CompilationResult.DataPatch;
@@ -41,8 +43,8 @@
 
     public HotSpotCompiledRuntimeStub(TargetDescription target, Stub stub, CompilationResult compResult) {
         super(target, compResult);
+        this.stubName = stub.toString();
         assert checkStubInvariants(compResult);
-        this.stubName = stub.toString();
     }
 
     /**
@@ -67,8 +69,13 @@
             Call call = (Call) infopoint;
             assert call.target instanceof HotSpotForeignCallLinkage : this + " cannot have non runtime call: " + call.target;
             HotSpotForeignCallLinkage linkage = (HotSpotForeignCallLinkage) call.target;
-            assert !linkage.isCompiledStub() : this + " cannot call compiled stub " + linkage;
+            assert !linkage.isCompiledStub() || linkage.getDescriptor() == UNCOMMON_TRAP_HANDLER : this + " cannot call compiled stub " + linkage;
         }
         return true;
     }
+
+    @Override
+    public String toString() {
+        return stubName != null ? stubName : super.toString();
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRGenerator.java	Mon Apr 14 15:36:27 2014 -1000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRGenerator.java	Mon Apr 14 17:21:49 2014 -1000
@@ -27,6 +27,7 @@
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.hotspot.HotSpotVMConfig.CompressEncoding;
 import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
 import com.oracle.graal.nodes.spi.*;
 
 /**
@@ -43,8 +44,22 @@
      */
     void emitTailcall(Value[] args, Value address);
 
+    void emitLeaveCurrentStackFrame();
+
+    void emitLeaveDeoptimizedStackFrame(Value frameSize, Value initialInfo);
+
+    void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp);
+
+    void emitLeaveUnpackFramesStackFrame();
+
+    SaveRegistersOp emitSaveAllRegisters();
+
     void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason);
 
+    void emitPushInterpreterFrame(Value frameSize, Value framePc, Value senderSp, Value initialInfo);
+
+    Value emitUncommonTrapCall(Value trapRequest, SaveRegistersOp saveRegisterOp);
+
     /**
      * Gets a stack slot for a lock at a given lock nesting depth.
      */
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Mon Apr 14 15:36:27 2014 -1000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Mon Apr 14 17:21:49 2014 -1000
@@ -962,7 +962,10 @@
         return javaThreadAnchorOffset + javaFrameAnchorFlagsOffset;
     }
 
+    // These are only valid on AMD64.
     @HotSpotVMConstant(name = "frame::arg_reg_save_area_bytes", archs = {"amd64"}) @Stable public int runtimeCallStackSize;
+    @HotSpotVMConstant(name = "frame::interpreter_frame_sender_sp_offset", archs = {"amd64"}) @Stable public int frameInterpreterFrameSenderSpOffset;
+    @HotSpotVMConstant(name = "frame::interpreter_frame_last_sp_offset", archs = {"amd64"}) @Stable public int frameInterpreterFrameLastSpOffset;
 
     @HotSpotVMField(name = "PtrQueue::_active", type = "bool", get = HotSpotVMField.Type.OFFSET) @Stable public int ptrQueueActiveOffset;
     @HotSpotVMField(name = "PtrQueue::_buf", type = "void**", get = HotSpotVMField.Type.OFFSET) @Stable public int ptrQueueBufferOffset;
@@ -1348,7 +1351,6 @@
     }
 
     @Stable public long handleDeoptStub;
-    @Stable public long uncommonTrapStub;
 
     @HotSpotVMField(name = "StubRoutines::_aescrypt_encryptBlock", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long aescryptEncryptBlockStub;
     @HotSpotVMField(name = "StubRoutines::_aescrypt_decryptBlock", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long aescryptDecryptBlockStub;
@@ -1418,6 +1420,10 @@
 
     @Stable public int graalCountersSize;
 
+    @Stable public long deoptimizationFetchUnrollInfo;
+    @Stable public long deoptimizationUncommonTrap;
+    @Stable public long deoptimizationUnpackFrames;
+
     @HotSpotVMConstant(name = "Deoptimization::Reason_none") @Stable public int deoptReasonNone;
     @HotSpotVMConstant(name = "Deoptimization::Reason_null_check") @Stable public int deoptReasonNullCheck;
     @HotSpotVMConstant(name = "Deoptimization::Reason_range_check") @Stable public int deoptReasonRangeCheck;
@@ -1448,6 +1454,19 @@
     @HotSpotVMConstant(name = "Deoptimization::_reason_shift") @Stable public int deoptimizationReasonShift;
     @HotSpotVMConstant(name = "Deoptimization::_debug_id_shift") @Stable public int deoptimizationDebugIdShift;
 
+    @HotSpotVMConstant(name = "Deoptimization::Unpack_deopt") @Stable public int deoptimizationUnpackDeopt;
+    @HotSpotVMConstant(name = "Deoptimization::Unpack_exception") @Stable public int deoptimizationUnpackException;
+    @HotSpotVMConstant(name = "Deoptimization::Unpack_uncommon_trap") @Stable public int deoptimizationUnpackUncommonTrap;
+    @HotSpotVMConstant(name = "Deoptimization::Unpack_reexecute") @Stable public int deoptimizationUnpackReexecute;
+
+    @HotSpotVMField(name = "Deoptimization::UnrollBlock::_size_of_deoptimized_frame", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset;
+    @HotSpotVMField(name = "Deoptimization::UnrollBlock::_caller_adjustment", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int deoptimizationUnrollBlockCallerAdjustmentOffset;
+    @HotSpotVMField(name = "Deoptimization::UnrollBlock::_number_of_frames", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int deoptimizationUnrollBlockNumberOfFramesOffset;
+    @HotSpotVMField(name = "Deoptimization::UnrollBlock::_total_frame_sizes", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int deoptimizationUnrollBlockTotalFrameSizesOffset;
+    @HotSpotVMField(name = "Deoptimization::UnrollBlock::_frame_sizes", type = "intptr_t*", get = HotSpotVMField.Type.OFFSET) @Stable public int deoptimizationUnrollBlockFrameSizesOffset;
+    @HotSpotVMField(name = "Deoptimization::UnrollBlock::_frame_pcs", type = "address*", get = HotSpotVMField.Type.OFFSET) @Stable public int deoptimizationUnrollBlockFramePcsOffset;
+    @HotSpotVMField(name = "Deoptimization::UnrollBlock::_initial_info", type = "intptr_t", get = HotSpotVMField.Type.OFFSET) @Stable public int deoptimizationUnrollBlockInitialInfoOffset;
+
     @HotSpotVMConstant(name = "vmIntrinsics::_invokeBasic") @Stable public int vmIntrinsicInvokeBasic;
     @HotSpotVMConstant(name = "vmIntrinsics::_linkToVirtual") @Stable public int vmIntrinsicLinkToVirtual;
     @HotSpotVMConstant(name = "vmIntrinsics::_linkToStatic") @Stable public int vmIntrinsicLinkToStatic;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java	Mon Apr 14 15:36:27 2014 -1000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java	Mon Apr 14 17:21:49 2014 -1000
@@ -30,6 +30,7 @@
 import static com.oracle.graal.hotspot.nodes.NewArrayStubCall.*;
 import static com.oracle.graal.hotspot.nodes.NewInstanceStubCall.*;
 import static com.oracle.graal.hotspot.nodes.NewMultiArrayStubCall.*;
+import static com.oracle.graal.hotspot.nodes.UncommonTrapCallNode.*;
 import static com.oracle.graal.hotspot.nodes.VMErrorNode.*;
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 import static com.oracle.graal.hotspot.replacements.MonitorSnippets.*;
@@ -37,6 +38,7 @@
 import static com.oracle.graal.hotspot.replacements.SystemSubstitutions.*;
 import static com.oracle.graal.hotspot.replacements.ThreadSubstitutions.*;
 import static com.oracle.graal.hotspot.replacements.WriteBarrierSnippets.*;
+import static com.oracle.graal.hotspot.stubs.DeoptimizationStub.*;
 import static com.oracle.graal.hotspot.stubs.ExceptionHandlerStub.*;
 import static com.oracle.graal.hotspot.stubs.NewArrayStub.*;
 import static com.oracle.graal.hotspot.stubs.NewInstanceStub.*;
@@ -64,7 +66,7 @@
         super(runtime, metaAccess, codeCache);
     }
 
-    private static void link(Stub stub) {
+    protected static void link(Stub stub) {
         stub.getLinkage().setCompiledStub(stub);
     }
 
@@ -101,7 +103,6 @@
     public void initialize(HotSpotProviders providers, HotSpotVMConfig c) {
         TargetDescription target = providers.getCodeCache().getTarget();
 
-        registerForeignCall(UNCOMMON_TRAP, c.uncommonTrapStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
         registerForeignCall(DEOPT_HANDLER, c.handleDeoptStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
         registerForeignCall(IC_MISS_HANDLER, c.inlineCacheMissStub(), NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
 
@@ -114,8 +115,11 @@
 
         registerForeignCall(EXCEPTION_HANDLER_FOR_PC, c.exceptionHandlerForPcAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, ANY_LOCATION);
         registerForeignCall(EXCEPTION_HANDLER_FOR_RETURN_ADDRESS, c.exceptionHandlerForReturnAddressAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, ANY_LOCATION);
+        registerForeignCall(FETCH_UNROLL_INFO, c.deoptimizationFetchUnrollInfo, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, ANY_LOCATION);
         registerForeignCall(NEW_ARRAY_C, c.newArrayAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, ANY_LOCATION);
         registerForeignCall(NEW_INSTANCE_C, c.newInstanceAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, ANY_LOCATION);
+        registerForeignCall(UNCOMMON_TRAP, c.deoptimizationUncommonTrap, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, NOT_REEXECUTABLE, ANY_LOCATION);
+        registerForeignCall(UNPACK_FRAMES, c.deoptimizationUnpackFrames, NativeCall, DESTROYS_REGISTERS, LEAF, NOT_REEXECUTABLE, ANY_LOCATION);
         registerForeignCall(VM_MESSAGE_C, c.vmMessageAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, NO_LOCATIONS);
 
         link(new NewInstanceStub(providers, target, registerStubCall(NEW_INSTANCE, REEXECUTABLE, NOT_LEAF, ANY_LOCATION)));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EnterUnpackFramesStackFrameNode.java	Mon Apr 14 17:21:49 2014 -1000
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2013, 2014, 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.api.meta.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.stubs.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.word.*;
+
+/**
+ * Emits code to enter a low-level stack frame specifically to call out to the C++ method
+ * {@link DeoptimizationStub#UNPACK_FRAMES Deoptimization::unpack_frames}.
+ */
+public class EnterUnpackFramesStackFrameNode extends FixedWithNextNode implements LIRLowerable {
+
+    @Input private ValueNode framePc;
+    @Input private ValueNode senderSp;
+    @Input private ValueNode senderFp;
+
+    public EnterUnpackFramesStackFrameNode(ValueNode framePc, ValueNode senderSp, ValueNode senderFp) {
+        super(StampFactory.forVoid());
+        this.framePc = framePc;
+        this.senderSp = senderSp;
+        this.senderFp = senderFp;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        Value operandValue = gen.operand(framePc);
+        Value senderSpValue = gen.operand(senderSp);
+        Value senderFpValue = gen.operand(senderFp);
+        ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitEnterUnpackFramesStackFrame(operandValue, senderSpValue, senderFpValue);
+    }
+
+    @NodeIntrinsic
+    public static native void enterUnpackFramesStackFrame(Word framePc, Word senderSp, Word senderFp);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/LeaveCurrentStackFrameNode.java	Mon Apr 14 17:21:49 2014 -1000
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2013, 2014, 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.*;
+
+/**
+ * Emits code to leave (pop) the current low-level stack frame. This operation also removes the
+ * return address if its location is on the stack.
+ */
+public class LeaveCurrentStackFrameNode extends FixedWithNextNode implements LIRLowerable {
+
+    public LeaveCurrentStackFrameNode() {
+        super(StampFactory.forVoid());
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLeaveCurrentStackFrame();
+    }
+
+    @NodeIntrinsic
+    public static native void leaveCurrentStackFrame();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/LeaveDeoptimizedStackFrameNode.java	Mon Apr 14 17:21:49 2014 -1000
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2013, 2014, 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.api.meta.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.stubs.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.word.*;
+
+/**
+ * Emits code to leave (pop) the current low-level stack frame which is being deoptimized. This node
+ * is only used in {@link DeoptimizationStub}.
+ */
+public class LeaveDeoptimizedStackFrameNode extends FixedWithNextNode implements LIRLowerable {
+
+    @Input private ValueNode frameSize;
+    @Input private ValueNode initialInfo;
+
+    public LeaveDeoptimizedStackFrameNode(ValueNode frameSize, ValueNode initialInfo) {
+        super(StampFactory.forVoid());
+        this.frameSize = frameSize;
+        this.initialInfo = initialInfo;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        Value frameSizeValue = gen.operand(frameSize);
+        Value initialInfoValue = gen.operand(initialInfo);
+        ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLeaveDeoptimizedStackFrame(frameSizeValue, initialInfoValue);
+    }
+
+    @NodeIntrinsic
+    public static native void leaveDeoptimizedStackFrame(int frameSize, Word initialInfo);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/LeaveUnpackFramesStackFrameNode.java	Mon Apr 14 17:21:49 2014 -1000
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2013, 2014, 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.hotspot.stubs.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+
+/**
+ * Emits code to leave a low-level stack frame specifically to call out to the C++ method
+ * {@link DeoptimizationStub#UNPACK_FRAMES Deoptimization::unpack_frames}.
+ */
+public class LeaveUnpackFramesStackFrameNode extends FixedWithNextNode implements LIRLowerable {
+
+    public LeaveUnpackFramesStackFrameNode() {
+        super(StampFactory.forVoid());
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLeaveUnpackFramesStackFrame();
+    }
+
+    @NodeIntrinsic
+    public static native void leaveUnpackFramesStackFrame();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/PushInterpreterFrameNode.java	Mon Apr 14 17:21:49 2014 -1000
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2013, 2014, 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.api.meta.*;
+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.*;
+
+/**
+ * A call to the runtime code implementing the uncommon trap logic.
+ */
+public class PushInterpreterFrameNode extends FixedWithNextNode implements LIRLowerable {
+
+    @Input private ValueNode framePc;
+    @Input private ValueNode frameSize;
+    @Input private ValueNode senderSp;
+    @Input private ValueNode initialInfo;
+
+    public PushInterpreterFrameNode(ValueNode frameSize, ValueNode framePc, ValueNode senderSp, ValueNode initialInfo) {
+        super(StampFactory.forVoid());
+        this.frameSize = frameSize;
+        this.framePc = framePc;
+        this.senderSp = senderSp;
+        this.initialInfo = initialInfo;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        Value frameSizeValue = gen.operand(frameSize);
+        Value framePcValue = gen.operand(framePc);
+        Value senderSpValue = gen.operand(senderSp);
+        Value initialInfoValue = gen.operand(initialInfo);
+        ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitPushInterpreterFrame(frameSizeValue, framePcValue, senderSpValue, initialInfoValue);
+    }
+
+    @NodeIntrinsic
+    public static native void pushInterpreterFrame(Word frameSize, Word framePc, Word senderSp, Word initialInfo);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SaveAllRegistersNode.java	Mon Apr 14 17:21:49 2014 -1000
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2013, 2014, 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.api.meta.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.lir.StandardOp.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+
+/**
+ * Saves all allocatable registers.
+ */
+public class SaveAllRegistersNode extends FixedWithNextNode implements LIRLowerable {
+
+    private SaveRegistersOp saveRegistersOp;
+
+    public SaveAllRegistersNode() {
+        super(StampFactory.forKind(Kind.Long));
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        saveRegistersOp = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitSaveAllRegisters();
+    }
+
+    /**
+     * @return the map from registers to the stack locations in they are saved
+     */
+    public SaveRegistersOp getSaveRegistersOp() {
+        assert saveRegistersOp != null : "saved registers op has not yet been created";
+        return saveRegistersOp;
+    }
+
+    /**
+     * @return a token that couples this node to an {@link UncommonTrapCallNode} so that the latter
+     *         has access to the {@linkplain SaveRegistersOp#getMap register save map}
+     */
+    @NodeIntrinsic
+    public static native long saveAllRegisters();
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/StubForeignCallNode.java	Mon Apr 14 15:36:27 2014 -1000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/StubForeignCallNode.java	Mon Apr 14 17:21:49 2014 -1000
@@ -68,7 +68,7 @@
     @Override
     public void generate(NodeLIRBuilderTool gen) {
         assert graph().start() instanceof StubStartNode;
-        ForeignCallLinkage linkage = gen.getLIRGeneratorTool().getForeignCalls().lookupForeignCall(descriptor);
+        ForeignCallLinkage linkage = foreignCalls.lookupForeignCall(descriptor);
         Value[] operands = operands(gen);
         Value result = gen.getLIRGeneratorTool().emitForeignCall(linkage, null, operands);
         if (result != null) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/UncommonTrapCallNode.java	Mon Apr 14 17:21:49 2014 -1000
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2013, 2014, 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.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.word.*;
+
+/**
+ * A call to the runtime code implementing the uncommon trap logic.
+ */
+@NodeInfo(allowedUsageTypes = {InputType.Memory})
+public class UncommonTrapCallNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Multi {
+
+    @Input private ValueNode trapRequest;
+    @Input private SaveAllRegistersNode registerSaver;
+    private final ForeignCallsProvider foreignCalls;
+    public static final ForeignCallDescriptor UNCOMMON_TRAP = new ForeignCallDescriptor("uncommonTrap", Word.class, Word.class, int.class);
+
+    public UncommonTrapCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ValueNode registerSaver, ValueNode trapRequest) {
+        super(StampFactory.forKind(Kind.fromJavaClass(UNCOMMON_TRAP.getResultType())));
+        this.trapRequest = trapRequest;
+        this.registerSaver = (SaveAllRegistersNode) registerSaver;
+        this.foreignCalls = foreignCalls;
+    }
+
+    @Override
+    public LocationIdentity[] getLocationIdentities() {
+        return foreignCalls.getKilledLocations(UNCOMMON_TRAP);
+    }
+
+    public SaveRegistersOp getSaveRegistersOp() {
+        return registerSaver.getSaveRegistersOp();
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        Value trapRequestValue = gen.operand(trapRequest);
+        Value result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitUncommonTrapCall(trapRequestValue, getSaveRegistersOp());
+        gen.setResult(this, result);
+    }
+
+    @NodeIntrinsic
+    public static native Word uncommonTrap(long registerSaver, int trapRequest);
+
+    public MemoryCheckpoint asMemoryCheckpoint() {
+        return null;
+    }
+
+    public MemoryPhiNode asMemoryPhi() {
+        return null;
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java	Mon Apr 14 15:36:27 2014 -1000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java	Mon Apr 14 17:21:49 2014 -1000
@@ -80,6 +80,20 @@
         return config().threadExceptionPcOffset;
     }
 
+    public static final LocationIdentity LAST_JAVA_PC_LOCATION = new NamedLocationIdentity("LastJavaPc");
+
+    @Fold
+    public static int threadLastJavaPcOffset() {
+        return config().threadLastJavaPcOffset();
+    }
+
+    public static final LocationIdentity LAST_JAVA_FP_LOCATION = new NamedLocationIdentity("LastJavaFp");
+
+    @Fold
+    public static int threadLastJavaFpOffset() {
+        return config().threadLastJavaFpOffset();
+    }
+
     public static final LocationIdentity TLAB_TOP_LOCATION = new NamedLocationIdentity("TlabTop");
 
     @Fold
@@ -111,6 +125,16 @@
         return config().pendingExceptionOffset;
     }
 
+    public static final LocationIdentity PENDING_DEOPTIMIZATION_LOCATION = new NamedLocationIdentity("PendingDeoptimization");
+
+    /**
+     * @see HotSpotVMConfig#pendingDeoptimizationOffset
+     */
+    @Fold
+    private static int threadPendingDeoptimizationOffset() {
+        return config().pendingDeoptimizationOffset;
+    }
+
     public static final LocationIdentity OBJECT_RESULT_LOCATION = new NamedLocationIdentity("ObjectResult");
 
     @Fold
@@ -140,6 +164,14 @@
         thread.writeWord(threadExceptionPcOffset(), value, EXCEPTION_PC_LOCATION);
     }
 
+    public static void writeLastJavaPc(Word thread, Word value) {
+        thread.writeWord(threadLastJavaPcOffset(), value, LAST_JAVA_PC_LOCATION);
+    }
+
+    public static void writeLastJavaFp(Word thread, Word value) {
+        thread.writeWord(threadLastJavaFpOffset(), value, LAST_JAVA_FP_LOCATION);
+    }
+
     public static Word readTlabTop(Word thread) {
         return thread.readWord(threadTlabTopOffset(), TLAB_TOP_LOCATION);
     }
@@ -174,6 +206,22 @@
     }
 
     /**
+     * Reads the pending deoptimization value for the given thread.
+     * 
+     * @return {@code true} if there was a pending deoptimization
+     */
+    public static int readPendingDeoptimization(Word thread) {
+        return thread.readInt(threadPendingDeoptimizationOffset(), PENDING_DEOPTIMIZATION_LOCATION);
+    }
+
+    /**
+     * Writes the pending deoptimization value for the given thread.
+     */
+    public static void writePendingDeoptimization(Word thread, int value) {
+        thread.writeInt(threadPendingDeoptimizationOffset(), value, PENDING_DEOPTIMIZATION_LOCATION);
+    }
+
+    /**
      * Gets and clears the object result from a runtime call stored in a thread local.
      *
      * @return the object that was in the thread local
@@ -498,6 +546,9 @@
     @NodeIntrinsic(value = ReadRegisterNode.class, setStampFromReturnType = true)
     public static native Word registerAsWord(@ConstantNodeParameter Register register, @ConstantNodeParameter boolean directUse, @ConstantNodeParameter boolean incoming);
 
+    @NodeIntrinsic(value = WriteRegisterNode.class, setStampFromReturnType = true)
+    public static native void writeRegisterAsWord(@ConstantNodeParameter Register register, Word value);
+
     @SuppressWarnings("unused")
     @NodeIntrinsic(value = UnsafeLoadNode.class, setStampFromReturnType = true)
     private static Word loadWordFromObjectIntrinsic(Object object, long offset, @ConstantNodeParameter Kind wordKind, @ConstantNodeParameter LocationIdentity locationIdentity) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/DeoptimizationStub.java	Mon Apr 14 17:21:49 2014 -1000
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2013, 2014, 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.replacements.HotSpotReplacementsUtil.*;
+import static com.oracle.graal.hotspot.stubs.StubUtil.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.*;
+import com.oracle.graal.graph.*;
+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.replacements.*;
+import com.oracle.graal.replacements.Snippet.*;
+import com.oracle.graal.word.*;
+
+/**
+ * Deoptimization stub.
+ *
+ * This is the entry point for code which is returning to a de-optimized frame.
+ *
+ * The steps taken by this frame are as follows:
+ *
+ * - push a dummy "register_save" and save the return values (O0, O1, F0/F1, G1) and all potentially
+ * live registers (at a pollpoint many registers can be live).
+ *
+ * - call the C routine: Deoptimization::fetch_unroll_info (this function returns information about
+ * the number and size of interpreter frames which are equivalent to the frame which is being
+ * deoptimized)
+ *
+ * - deallocate the unpack frame, restoring only results values. Other volatile registers will now
+ * be captured in the vframeArray as needed.
+ *
+ * - deallocate the deoptimization frame
+ *
+ * - in a loop using the information returned in the previous step push new interpreter frames (take
+ * care to propagate the return values through each new frame pushed)
+ *
+ * - create a dummy "unpack_frame" and save the return values (O0, O1, F0)
+ *
+ * - call the C routine: Deoptimization::unpack_frames (this function lays out values on the
+ * interpreter frame which was just created)
+ *
+ * - deallocate the dummy unpack_frame
+ *
+ * - ensure that all the return values are correctly set and then do a return to the interpreter
+ * entry point
+ */
+public class DeoptimizationStub extends SnippetStub {
+
+    private final TargetDescription target;
+
+    public DeoptimizationStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
+        super(providers, target, linkage);
+        this.target = target;
+    }
+
+    @Override
+    public boolean preservesRegisters() {
+        return false;
+    }
+
+    @Override
+    protected Object getConstantParameterValue(int index, String name) {
+        switch (index) {
+            case 0:
+                return providers.getRegisters().getThreadRegister();
+            case 1:
+                return providers.getRegisters().getStackPointerRegister();
+            default:
+                throw GraalInternalError.shouldNotReachHere("unknown parameter " + name + " at index " + index);
+        }
+    }
+
+    /**
+     * Uncommon trap.
+     *
+     * We save the argument return registers. We call the first C routine, fetch_unroll_info(). This
+     * routine captures the return values and returns a structure which describes the current frame
+     * size and the sizes of all replacement frames. The current frame is compiled code and may
+     * contain many inlined functions, each with their own JVM state. We pop the current frame, then
+     * push all the new frames. Then we call the C routine unpack_frames() to populate these frames.
+     * Finally unpack_frames() returns us the new target address. Notice that callee-save registers
+     * are BLOWN here; they have already been captured in the vframeArray at the time the return PC
+     * was patched.
+     *
+     * <p>
+     * <b>ATTENTION: We cannot do any complicated operations e.g. logging via printf in this snippet
+     * because we change the current stack layout and so the code is very sensitive to register
+     * allocation.</b>
+     */
+    @Snippet
+    private static void uncommonTrapHandler(@ConstantParameter Register threadRegister, @ConstantParameter Register stackPointerRegister) {
+        final Word thread = registerAsWord(threadRegister);
+        long registerSaver = SaveAllRegistersNode.saveAllRegisters();
+
+        final int actionAndReason = readPendingDeoptimization(thread);
+        writePendingDeoptimization(thread, -1);
+
+        final Word unrollBlock = UncommonTrapCallNode.uncommonTrap(registerSaver, actionAndReason);
+
+        // Pop all the frames we must move/replace.
+        //
+        // Frame picture (youngest to oldest)
+        // 1: self-frame (no frame link)
+        // 2: deoptimizing frame (no frame link)
+        // 3: caller of deoptimizing frame (could be compiled/interpreted).
+
+        // Pop self-frame.
+        LeaveCurrentStackFrameNode.leaveCurrentStackFrame();
+
+        // Load the initial info we should save (e.g. frame pointer).
+        final Word initialInfo = unrollBlock.readWord(deoptimizationUnrollBlockInitialInfoOffset());
+
+        // Pop deoptimized frame
+        final int sizeOfDeoptimizedFrame = unrollBlock.readInt(deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset());
+        LeaveDeoptimizedStackFrameNode.leaveDeoptimizedStackFrame(sizeOfDeoptimizedFrame, initialInfo);
+
+        /*
+         * Stack bang to make sure there's enough room for the interpreter frames. Bang stack for
+         * total size of the interpreter frames plus shadow page size. Bang one page at a time
+         * because large sizes can bang beyond yellow and red zones.
+         */
+        final int totalFrameSizes = unrollBlock.readInt(deoptimizationUnrollBlockTotalFrameSizesOffset());
+        final int bangPages = NumUtil.roundUp(totalFrameSizes, pageSize()) / pageSize() + stackShadowPages();
+        Word stackPointer = readRegister(stackPointerRegister);
+
+        for (int i = 1; i < bangPages; i++) {
+            stackPointer.writeInt(-(i * pageSize()), i);
+        }
+
+        // Load number of interpreter frames.
+        final int numberOfFrames = unrollBlock.readInt(deoptimizationUnrollBlockNumberOfFramesOffset());
+
+        // Load address of array of frame sizes.
+        final Word frameSizes = unrollBlock.readWord(deoptimizationUnrollBlockFrameSizesOffset());
+
+        // Load address of array of frame PCs.
+        final Word framePcs = unrollBlock.readWord(deoptimizationUnrollBlockFramePcsOffset());
+
+        /*
+         * Get the current stack pointer (sender's original SP) before adjustment so that we can
+         * save it in the skeletal interpreter frame.
+         */
+        Word senderSp = readRegister(stackPointerRegister);
+
+        // Adjust old interpreter frame to make space for new frame's extra Java locals.
+        final int callerAdjustment = unrollBlock.readInt(deoptimizationUnrollBlockCallerAdjustmentOffset());
+        writeRegister(stackPointerRegister, readRegister(stackPointerRegister).subtract(callerAdjustment));
+
+        for (int i = 0; i < numberOfFrames; i++) {
+            final Word frameSize = frameSizes.readWord(i * wordSize());
+            final Word framePc = framePcs.readWord(i * wordSize());
+
+            // Push an interpreter frame onto the stack.
+            PushInterpreterFrameNode.pushInterpreterFrame(frameSize, framePc, senderSp, initialInfo);
+
+            // Get the current stack pointer (sender SP) and pass it to next frame.
+            senderSp = readRegister(stackPointerRegister);
+        }
+
+        // Get final return address.
+        final Word framePc = framePcs.readWord(numberOfFrames * wordSize());
+
+        /*
+         * Enter a frame to call out to unpack frames. Since we changed the stack pointer to an
+         * unknown alignment we need to align it here before calling C++ code.
+         */
+        final Word senderFp = initialInfo;
+        EnterUnpackFramesStackFrameNode.enterUnpackFramesStackFrame(framePc, senderSp, senderFp);
+
+        // Pass uncommon trap mode to unpack frames.
+        final int mode = deoptimizationUnpackUncommonTrap();
+        unpackFrames(UNPACK_FRAMES, thread, mode);
+
+        LeaveUnpackFramesStackFrameNode.leaveUnpackFramesStackFrame();
+    }
+
+    /**
+     * Reads the value of the passed register as a Word.
+     */
+    private static Word readRegister(Register register) {
+        return registerAsWord(register, false, false);
+    }
+
+    /**
+     * Writes the value of the passed register.
+     *
+     * @param value value the register should be set to
+     */
+    private static void writeRegister(Register register, Word value) {
+        writeRegisterAsWord(register, value);
+    }
+
+    @Fold
+    private static int stackShadowPages() {
+        return config().useStackBanging ? config().stackShadowPages : 0;
+    }
+
+    @Fold
+    private static int deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset() {
+        return config().deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset;
+    }
+
+    @Fold
+    private static int deoptimizationUnrollBlockCallerAdjustmentOffset() {
+        return config().deoptimizationUnrollBlockCallerAdjustmentOffset;
+    }
+
+    @Fold
+    private static int deoptimizationUnrollBlockNumberOfFramesOffset() {
+        return config().deoptimizationUnrollBlockNumberOfFramesOffset;
+    }
+
+    @Fold
+    private static int deoptimizationUnrollBlockTotalFrameSizesOffset() {
+        return config().deoptimizationUnrollBlockTotalFrameSizesOffset;
+    }
+
+    @Fold
+    private static int deoptimizationUnrollBlockFrameSizesOffset() {
+        return config().deoptimizationUnrollBlockFrameSizesOffset;
+    }
+
+    @Fold
+    private static int deoptimizationUnrollBlockFramePcsOffset() {
+        return config().deoptimizationUnrollBlockFramePcsOffset;
+    }
+
+    @Fold
+    private static int deoptimizationUnrollBlockInitialInfoOffset() {
+        return config().deoptimizationUnrollBlockInitialInfoOffset;
+    }
+
+    @Fold
+    private static int deoptimizationUnpackDeopt() {
+        return config().deoptimizationUnpackDeopt;
+    }
+
+    @Fold
+    private static int deoptimizationUnpackUncommonTrap() {
+        return config().deoptimizationUnpackUncommonTrap;
+    }
+
+    public static final ForeignCallDescriptor FETCH_UNROLL_INFO = descriptorFor(DeoptimizationStub.class, "fetchUnrollInfo");
+    public static final ForeignCallDescriptor UNPACK_FRAMES = descriptorFor(DeoptimizationStub.class, "unpackFrames");
+
+    @NodeIntrinsic(value = StubForeignCallNode.class, setStampFromReturnType = true)
+    public static native Word fetchUnrollInfo(@ConstantNodeParameter ForeignCallDescriptor fetchUnrollInfo, Word thread);
+
+    @NodeIntrinsic(value = StubForeignCallNode.class, setStampFromReturnType = true)
+    public static native int unpackFrames(@ConstantNodeParameter ForeignCallDescriptor unpackFrames, Word thread, int mode);
+}
--- a/src/cpu/x86/vm/sharedRuntime_x86_64.cpp	Mon Apr 14 15:36:27 2014 -1000
+++ b/src/cpu/x86/vm/sharedRuntime_x86_64.cpp	Mon Apr 14 17:21:49 2014 -1000
@@ -3360,10 +3360,9 @@
 
 #ifdef GRAAL
   int implicit_exception_uncommon_trap_offset = __ pc() - start;
+
   __ pushptr(Address(r15_thread, in_bytes(JavaThread::graal_implicit_exception_pc_offset())));
 
-  int uncommon_trap_offset = __ pc() - start;
-
   // Save everything in sight.
   RegisterSaver::save_live_registers(masm, 0, &frame_size_in_words);
   // fetch_unroll_info needs to call last_java_frame()
@@ -3643,7 +3642,6 @@
   _deopt_blob = DeoptimizationBlob::create(&buffer, oop_maps, 0, exception_offset, reexecute_offset, frame_size_in_words);
   _deopt_blob->set_unpack_with_exception_in_tls_offset(exception_in_tls_offset);
 #ifdef GRAAL
-  _deopt_blob->set_uncommon_trap_offset(uncommon_trap_offset);
   _deopt_blob->set_implicit_exception_uncommon_trap_offset(implicit_exception_uncommon_trap_offset);
 #endif
 }
--- a/src/cpu/x86/vm/vmStructs_x86.hpp	Mon Apr 14 15:36:27 2014 -1000
+++ b/src/cpu/x86/vm/vmStructs_x86.hpp	Mon Apr 14 17:21:49 2014 -1000
@@ -47,6 +47,8 @@
 
 #define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) \
   declare_constant(frame::arg_reg_save_area_bytes)                  \
+  declare_constant(frame::interpreter_frame_sender_sp_offset)       \
+  declare_constant(frame::interpreter_frame_last_sp_offset)         \
   declare_constant(VM_Version::CPU_CX8)                             \
   declare_constant(VM_Version::CPU_CMOV)                            \
   declare_constant(VM_Version::CPU_FXSR)                            \
--- a/src/share/vm/code/codeBlob.hpp	Mon Apr 14 15:36:27 2014 -1000
+++ b/src/share/vm/code/codeBlob.hpp	Mon Apr 14 17:21:49 2014 -1000
@@ -358,8 +358,6 @@
   int _unpack_with_exception_in_tls;
 
 #ifdef GRAAL
-  // (thomaswue) Offset when Graal calls uncommon_trap.
-  int _uncommon_trap_offset;
   int _implicit_exception_uncommon_trap_offset;
 #endif
 
@@ -417,12 +415,6 @@
   address unpack_with_exception_in_tls() const   { return code_begin() + _unpack_with_exception_in_tls; }
 
 #ifdef GRAAL
-  // (thomaswue) Offset when Graal calls uncommon_trap.
-  void set_uncommon_trap_offset(int offset) {
-    _uncommon_trap_offset = offset;
-    assert(contains(code_begin() + _uncommon_trap_offset), "must be PC inside codeblob");
-  }
-  address uncommon_trap() const                  { return code_begin() + _uncommon_trap_offset;     }
   void set_implicit_exception_uncommon_trap_offset(int offset) {
     _implicit_exception_uncommon_trap_offset = offset;
     assert(contains(code_begin() + _implicit_exception_uncommon_trap_offset), "must be PC inside codeblob");
--- a/src/share/vm/graal/graalCompilerToVM.cpp	Mon Apr 14 15:36:27 2014 -1000
+++ b/src/share/vm/graal/graalCompilerToVM.cpp	Mon Apr 14 17:21:49 2014 -1000
@@ -157,7 +157,6 @@
   //------------------------------------------------------------------------------------------------
 
   set_address("handleDeoptStub", SharedRuntime::deopt_blob()->unpack());
-  set_address("uncommonTrapStub", SharedRuntime::deopt_blob()->uncommon_trap());
 
   set_address("registerFinalizerAddress", SharedRuntime::register_finalizer);
   set_address("exceptionHandlerForReturnAddressAddress", SharedRuntime::exception_handler_for_return_address);
@@ -191,6 +190,10 @@
   set_address("writeBarrierPostAddress", GraalRuntime::write_barrier_post);
   set_address("validateObject", GraalRuntime::validate_object);
 
+  set_address("deoptimizationFetchUnrollInfo", Deoptimization::fetch_unroll_info);
+  set_address("deoptimizationUncommonTrap", Deoptimization::uncommon_trap);
+  set_address("deoptimizationUnpackFrames", Deoptimization::unpack_frames);
+
   //------------------------------------------------------------------------------------------------
 
   set_int("graalCountersThreadOffset", in_bytes(JavaThread::graal_counters_offset()));
--- a/src/share/vm/runtime/deoptimization.cpp	Mon Apr 14 15:36:27 2014 -1000
+++ b/src/share/vm/runtime/deoptimization.cpp	Mon Apr 14 17:21:49 2014 -1000
@@ -357,7 +357,10 @@
     unpack_sp = deoptee.unextended_sp();
 
 #ifdef ASSERT
-  assert(cb->is_deoptimization_stub() || cb->is_uncommon_trap_stub(), "just checking");
+  assert(cb->is_deoptimization_stub() ||
+         cb->is_uncommon_trap_stub() ||
+         strcmp("Stub<DeoptimizationStub.uncommonTrapHandler>", cb->name()) == 0,
+         err_msg("unexpected code blob: %s", cb->name()));
 #endif
 #else
   intptr_t* unpack_sp = stub_frame.sender(&dummy_map).unextended_sp();