1 /*
   2  * Copyright (c) 2016, 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 package org.graalvm.compiler.hotspot.stubs;
  24 
  25 import static org.graalvm.compiler.core.common.LocationIdentity.any;
  26 import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.RegisterEffect.DESTROYS_REGISTERS;
  27 import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition.SAFEPOINT;
  28 import static org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProviderImpl.REEXECUTABLE;
  29 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.clearPendingException;
  30 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.registerAsWord;
  31 import static jdk.vm.ci.hotspot.HotSpotCallingConventionType.NativeCall;
  32 
  33 import org.graalvm.compiler.api.replacements.Fold;
  34 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
  35 import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
  36 import org.graalvm.compiler.graph.Node.NodeIntrinsic;
  37 import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
  38 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
  39 import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProviderImpl;
  40 import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
  41 import org.graalvm.compiler.hotspot.nodes.StubForeignCallNode;
  42 import org.graalvm.compiler.hotspot.word.KlassPointer;
  43 import org.graalvm.compiler.replacements.nodes.CStringConstant;
  44 import org.graalvm.compiler.word.Word;
  45 
  46 import jdk.vm.ci.code.Register;
  47 
  48 /**
  49  * Base class for stubs that create a runtime exception.
  50  */
  51 public class CreateExceptionStub extends SnippetStub {
  52 
  53     protected CreateExceptionStub(String snippetMethodName, HotSpotProviders providers, HotSpotForeignCallLinkage linkage) {
  54         super(snippetMethodName, providers, linkage);
  55     }
  56 
  57     @Fold
  58     static String getInternalClassName(Class<?> cls) {
  59         return cls.getName().replace('.', '/');
  60     }
  61 
  62     private static Word classAsCString(Class<?> cls) {
  63         return CStringConstant.cstring(getInternalClassName(cls));
  64     }
  65 
  66     protected static Object createException(Register threadRegister, Class<? extends Throwable> exception) {
  67         Word message = null;
  68         return createException(threadRegister, exception, message);
  69     }
  70 
  71     protected static Object createException(Register threadRegister, Class<? extends Throwable> exception, Word message) {
  72         Word thread = registerAsWord(threadRegister);
  73         throwAndPostJvmtiException(THROW_AND_POST_JVMTI_EXCEPTION, thread, classAsCString(exception), message);
  74         return clearPendingException(thread);
  75     }
  76 
  77     protected static Object createException(Register threadRegister, Class<? extends Throwable> exception, KlassPointer klass) {
  78         Word thread = registerAsWord(threadRegister);
  79         throwKlassExternalNameException(THROW_KLASS_EXTERNAL_NAME_EXCEPTION, thread, classAsCString(exception), klass);
  80         return clearPendingException(thread);
  81     }
  82 
  83     protected static Object createException(Register threadRegister, Class<? extends Throwable> exception, KlassPointer objKlass, KlassPointer targetKlass) {
  84         Word thread = registerAsWord(threadRegister);
  85         throwClassCastException(THROW_CLASS_CAST_EXCEPTION, thread, classAsCString(exception), objKlass, targetKlass);
  86         return clearPendingException(thread);
  87     }
  88 
  89     private static final ForeignCallDescriptor THROW_AND_POST_JVMTI_EXCEPTION = new ForeignCallDescriptor("throw_and_post_jvmti_exception", void.class, Word.class, Word.class, Word.class);
  90     private static final ForeignCallDescriptor THROW_KLASS_EXTERNAL_NAME_EXCEPTION = new ForeignCallDescriptor("throw_klass_external_name_exception", void.class, Word.class, Word.class,
  91                     KlassPointer.class);
  92     private static final ForeignCallDescriptor THROW_CLASS_CAST_EXCEPTION = new ForeignCallDescriptor("throw_class_cast_exception", void.class, Word.class, Word.class, KlassPointer.class,
  93                     KlassPointer.class);
  94 
  95     @NodeIntrinsic(StubForeignCallNode.class)
  96     private static native void throwAndPostJvmtiException(@ConstantNodeParameter ForeignCallDescriptor d, Word thread, Word type, Word message);
  97 
  98     @NodeIntrinsic(StubForeignCallNode.class)
  99     private static native void throwKlassExternalNameException(@ConstantNodeParameter ForeignCallDescriptor d, Word thread, Word type, KlassPointer klass);
 100 
 101     @NodeIntrinsic(StubForeignCallNode.class)
 102     private static native void throwClassCastException(@ConstantNodeParameter ForeignCallDescriptor d, Word thread, Word type, KlassPointer objKlass, KlassPointer targetKlass);
 103 
 104     public static void registerForeignCalls(GraalHotSpotVMConfig c, HotSpotForeignCallsProviderImpl foreignCalls) {
 105         foreignCalls.registerForeignCall(THROW_AND_POST_JVMTI_EXCEPTION, c.throwAndPostJvmtiExceptionAddress, NativeCall, DESTROYS_REGISTERS, SAFEPOINT, REEXECUTABLE, any());
 106         foreignCalls.registerForeignCall(THROW_KLASS_EXTERNAL_NAME_EXCEPTION, c.throwKlassExternalNameExceptionAddress, NativeCall, DESTROYS_REGISTERS, SAFEPOINT, REEXECUTABLE, any());
 107         foreignCalls.registerForeignCall(THROW_CLASS_CAST_EXCEPTION, c.throwClassCastExceptionAddress, NativeCall, DESTROYS_REGISTERS, SAFEPOINT, REEXECUTABLE, any());
 108     }
 109 }