001/*
002 * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package com.oracle.graal.hotspot.stubs;
024
025import jdk.internal.jvmci.code.*;
026import static com.oracle.graal.hotspot.nodes.JumpToExceptionHandlerInCallerNode.*;
027import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
028import static com.oracle.graal.hotspot.stubs.ExceptionHandlerStub.*;
029import static com.oracle.graal.hotspot.stubs.StubUtil.*;
030
031import com.oracle.graal.api.replacements.*;
032import com.oracle.graal.compiler.common.spi.*;
033import com.oracle.graal.graph.Node.ConstantNodeParameter;
034import com.oracle.graal.graph.Node.NodeIntrinsic;
035import com.oracle.graal.hotspot.*;
036import com.oracle.graal.hotspot.meta.*;
037import com.oracle.graal.hotspot.nodes.*;
038import com.oracle.graal.nodes.*;
039import com.oracle.graal.replacements.*;
040import com.oracle.graal.replacements.Snippet.ConstantParameter;
041import com.oracle.graal.word.*;
042
043/**
044 * Stub called by an {@link UnwindNode}. This stub executes in the frame of the method throwing an
045 * exception and completes by jumping to the exception handler in the calling frame.
046 */
047public class UnwindExceptionToCallerStub extends SnippetStub {
048
049    public UnwindExceptionToCallerStub(HotSpotProviders providers, HotSpotForeignCallLinkage linkage) {
050        super("unwindExceptionToCaller", providers, linkage);
051    }
052
053    /**
054     * The current frame is unwound by this stub. Therefore, it does not need to save any registers
055     * as HotSpot uses a caller save convention.
056     */
057    @Override
058    public boolean preservesRegisters() {
059        return false;
060    }
061
062    @Override
063    protected Object getConstantParameterValue(int index, String name) {
064        assert index == 2;
065        return providers.getRegisters().getThreadRegister();
066    }
067
068    @Snippet
069    private static void unwindExceptionToCaller(Object exception, Word returnAddress, @ConstantParameter Register threadRegister) {
070        Pointer exceptionOop = Word.fromObject(exception);
071        if (logging()) {
072            printf("unwinding exception %p (", exceptionOop.rawValue());
073            decipher(exceptionOop.rawValue());
074            printf(") at %p (", returnAddress.rawValue());
075            decipher(returnAddress.rawValue());
076            printf(")\n");
077        }
078        Word thread = registerAsWord(threadRegister);
079        checkNoExceptionInThread(thread, assertionsEnabled());
080        checkExceptionNotNull(assertionsEnabled(), exception);
081
082        Word handlerInCallerPc = exceptionHandlerForReturnAddress(EXCEPTION_HANDLER_FOR_RETURN_ADDRESS, thread, returnAddress);
083
084        if (logging()) {
085            printf("handler for exception %p at return address %p is at %p (", exceptionOop.rawValue(), returnAddress.rawValue(), handlerInCallerPc.rawValue());
086            decipher(handlerInCallerPc.rawValue());
087            printf(")\n");
088        }
089
090        jumpToExceptionHandlerInCaller(handlerInCallerPc, exception, returnAddress);
091    }
092
093    @Fold
094    private static boolean logging() {
095        return Boolean.getBoolean("graal.logUnwindExceptionToCallerStub");
096    }
097
098    /**
099     * Determines if either Java assertions are enabled for {@link UnwindExceptionToCallerStub} or
100     * if this is a HotSpot build where the ASSERT mechanism is enabled.
101     * <p>
102     * This first check relies on the per-class assertion status which is why this method must be in
103     * this class.
104     */
105    @Fold
106    @SuppressWarnings("all")
107    private static boolean assertionsEnabled() {
108        boolean enabled = false;
109        assert enabled = true;
110        return enabled || cAssertionsEnabled();
111    }
112
113    public static final ForeignCallDescriptor EXCEPTION_HANDLER_FOR_RETURN_ADDRESS = newDescriptor(UnwindExceptionToCallerStub.class, "exceptionHandlerForReturnAddress", Word.class, Word.class,
114                    Word.class);
115
116    @NodeIntrinsic(value = StubForeignCallNode.class, setStampFromReturnType = true)
117    public static native Word exceptionHandlerForReturnAddress(@ConstantNodeParameter ForeignCallDescriptor exceptionHandlerForReturnAddress, Word thread, Word returnAddress);
118}