1 /*
2  * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 
25 package org.graalvm.compiler.hotspot.stubs;
26 
27 import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_OPTIONVALUES;
28 import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG;
29 import static org.graalvm.compiler.hotspot.nodes.JumpToExceptionHandlerInCallerNode.jumpToExceptionHandlerInCaller;
30 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.registerAsWord;
31 import static org.graalvm.compiler.hotspot.stubs.ExceptionHandlerStub.checkExceptionNotNull;
32 import static org.graalvm.compiler.hotspot.stubs.ExceptionHandlerStub.checkNoExceptionInThread;
33 import static org.graalvm.compiler.hotspot.stubs.StubUtil.cAssertionsEnabled;
34 import static org.graalvm.compiler.hotspot.stubs.StubUtil.decipher;
35 import static org.graalvm.compiler.hotspot.stubs.StubUtil.newDescriptor;
36 import static org.graalvm.compiler.hotspot.stubs.StubUtil.printf;
37 
38 import org.graalvm.compiler.api.replacements.Fold;
39 import org.graalvm.compiler.api.replacements.Fold.InjectedParameter;
40 import org.graalvm.compiler.api.replacements.Snippet;
41 import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
42 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
43 import org.graalvm.compiler.debug.Assertions;
44 import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
45 import org.graalvm.compiler.graph.Node.NodeIntrinsic;
46 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
47 import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
48 import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
49 import org.graalvm.compiler.hotspot.nodes.StubForeignCallNode;
50 import org.graalvm.compiler.nodes.UnwindNode;
51 import org.graalvm.compiler.options.OptionValues;
52 import org.graalvm.compiler.word.Word;
53 import jdk.internal.vm.compiler.word.Pointer;
54 
55 import jdk.vm.ci.code.Register;
56 
57 /**
58  * Stub called by an {@link UnwindNode}. This stub executes in the frame of the method throwing an
59  * exception and completes by jumping to the exception handler in the calling frame.
60  */
61 public class UnwindExceptionToCallerStub extends SnippetStub {
62 
UnwindExceptionToCallerStub(OptionValues options, HotSpotProviders providers, HotSpotForeignCallLinkage linkage)63     public UnwindExceptionToCallerStub(OptionValues options, HotSpotProviders providers, HotSpotForeignCallLinkage linkage) {
64         super("unwindExceptionToCaller", options, providers, linkage);
65     }
66 
67     @Override
getConstantParameterValue(int index, String name)68     protected Object getConstantParameterValue(int index, String name) {
69         if (index == 2) {
70             return providers.getRegisters().getThreadRegister();
71         }
72         throw new InternalError();
73     }
74 
75     @Snippet
unwindExceptionToCaller(Object exception, Word returnAddress, @ConstantParameter Register threadRegister)76     private static void unwindExceptionToCaller(Object exception, Word returnAddress, @ConstantParameter Register threadRegister) {
77         Pointer exceptionOop = Word.objectToTrackedPointer(exception);
78         if (logging(INJECTED_OPTIONVALUES)) {
79             printf("unwinding exception %p (", exceptionOop.rawValue());
80             decipher(exceptionOop.rawValue());
81             printf(") at %p (", returnAddress.rawValue());
82             decipher(returnAddress.rawValue());
83             printf(")\n");
84         }
85         Word thread = registerAsWord(threadRegister);
86         checkNoExceptionInThread(thread, assertionsEnabled(INJECTED_VMCONFIG));
87         checkExceptionNotNull(assertionsEnabled(INJECTED_VMCONFIG), exception);
88 
89         Word handlerInCallerPc = exceptionHandlerForReturnAddress(EXCEPTION_HANDLER_FOR_RETURN_ADDRESS, thread, returnAddress);
90 
91         if (logging(INJECTED_OPTIONVALUES)) {
92             printf("handler for exception %p at return address %p is at %p (", exceptionOop.rawValue(), returnAddress.rawValue(), handlerInCallerPc.rawValue());
93             decipher(handlerInCallerPc.rawValue());
94             printf(")\n");
95         }
96 
97         jumpToExceptionHandlerInCaller(handlerInCallerPc, exception, returnAddress);
98     }
99 
100     @Fold
logging(@old.InjectedParameter OptionValues options)101     static boolean logging(@Fold.InjectedParameter OptionValues options) {
102         return StubOptions.TraceUnwindStub.getValue(options);
103     }
104 
105     /**
106      * Determines if either Java assertions are enabled for Graal or if this is a HotSpot build
107      * where the ASSERT mechanism is enabled.
108      */
109     @Fold
110     @SuppressWarnings("all")
assertionsEnabled(@njectedParameter GraalHotSpotVMConfig config)111     static boolean assertionsEnabled(@InjectedParameter GraalHotSpotVMConfig config) {
112         return Assertions.assertionsEnabled() || cAssertionsEnabled(config);
113     }
114 
115     public static final ForeignCallDescriptor EXCEPTION_HANDLER_FOR_RETURN_ADDRESS = newDescriptor(UnwindExceptionToCallerStub.class, "exceptionHandlerForReturnAddress", Word.class, Word.class,
116                     Word.class);
117 
118     @NodeIntrinsic(value = StubForeignCallNode.class)
exceptionHandlerForReturnAddress(@onstantNodeParameter ForeignCallDescriptor exceptionHandlerForReturnAddress, Word thread, Word returnAddress)119     public static native Word exceptionHandlerForReturnAddress(@ConstantNodeParameter ForeignCallDescriptor exceptionHandlerForReturnAddress, Word thread, Word returnAddress);
120 }
121