Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/instrument/JavaExceptions.c
38767 views
/*1* Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425/*26* Copyright 2003 Wily Technology, Inc.27*/2829#include <jni.h>30#include <jvmti.h>3132#include "JPLISAssert.h"33#include "Utilities.h"34#include "JavaExceptions.h"3536/**37* This module contains utility routines for manipulating Java throwables38* and JNIEnv throwable state from native code.39*/4041static jthrowable sFallbackInternalError = NULL;4243/*44* Local forward declarations.45*/4647/* insist on having a throwable. If we already have one, return it.48* If not, map to fallback49*/50jthrowable51forceFallback(jthrowable potentialException);525354jthrowable55forceFallback(jthrowable potentialException) {56if ( potentialException == NULL ) {57return sFallbackInternalError;58}59else {60return potentialException;61}62}6364/**65* Returns true if it properly sets up a fallback exception66*/67jboolean68initializeFallbackError(JNIEnv* jnienv) {69jplis_assert(isSafeForJNICalls(jnienv));70sFallbackInternalError = createInternalError(jnienv, NULL);71jplis_assert(isSafeForJNICalls(jnienv));72return (sFallbackInternalError != NULL);73}747576/*77* Map everything to InternalError.78*/79jthrowable80mapAllCheckedToInternalErrorMapper( JNIEnv * jnienv,81jthrowable throwableToMap) {82jthrowable mappedThrowable = NULL;83jstring message = NULL;8485jplis_assert(throwableToMap != NULL);86jplis_assert(isSafeForJNICalls(jnienv));87jplis_assert(!isUnchecked(jnienv, throwableToMap));8889message = getMessageFromThrowable(jnienv, throwableToMap);90mappedThrowable = createInternalError(jnienv, message);9192jplis_assert(isSafeForJNICalls(jnienv));93return mappedThrowable;94}959697jboolean98checkForThrowable( JNIEnv* jnienv) {99return (*jnienv)->ExceptionCheck(jnienv);100}101102jboolean103isSafeForJNICalls( JNIEnv * jnienv) {104return !(*jnienv)->ExceptionCheck(jnienv);105}106107108void109logThrowable( JNIEnv * jnienv) {110if ( checkForThrowable(jnienv) ) {111(*jnienv)->ExceptionDescribe(jnienv);112}113}114115116117/**118* Creates an exception or error with the fully qualified classname (ie java/lang/Error)119* and message passed to its constructor120*/121jthrowable122createThrowable( JNIEnv * jnienv,123const char * className,124jstring message) {125jthrowable exception = NULL;126jmethodID constructor = NULL;127jclass exceptionClass = NULL;128jboolean errorOutstanding = JNI_FALSE;129130jplis_assert(className != NULL);131jplis_assert(isSafeForJNICalls(jnienv));132133/* create new VMError with message from exception */134exceptionClass = (*jnienv)->FindClass(jnienv, className);135errorOutstanding = checkForAndClearThrowable(jnienv);136jplis_assert(!errorOutstanding);137138if (!errorOutstanding) {139constructor = (*jnienv)->GetMethodID( jnienv,140exceptionClass,141"<init>",142"(Ljava/lang/String;)V");143errorOutstanding = checkForAndClearThrowable(jnienv);144jplis_assert(!errorOutstanding);145}146147if (!errorOutstanding) {148exception = (*jnienv)->NewObject(jnienv, exceptionClass, constructor, message);149errorOutstanding = checkForAndClearThrowable(jnienv);150jplis_assert(!errorOutstanding);151}152153jplis_assert(isSafeForJNICalls(jnienv));154return exception;155}156157jthrowable158createInternalError(JNIEnv * jnienv, jstring message) {159return createThrowable( jnienv,160"java/lang/InternalError",161message);162}163164jthrowable165createThrowableFromJVMTIErrorCode(JNIEnv * jnienv, jvmtiError errorCode) {166const char * throwableClassName = NULL;167const char * message = NULL;168jstring messageString = NULL;169170switch ( errorCode ) {171case JVMTI_ERROR_NULL_POINTER:172throwableClassName = "java/lang/NullPointerException";173break;174175case JVMTI_ERROR_ILLEGAL_ARGUMENT:176throwableClassName = "java/lang/IllegalArgumentException";177break;178179case JVMTI_ERROR_OUT_OF_MEMORY:180throwableClassName = "java/lang/OutOfMemoryError";181break;182183case JVMTI_ERROR_CIRCULAR_CLASS_DEFINITION:184throwableClassName = "java/lang/ClassCircularityError";185break;186187case JVMTI_ERROR_FAILS_VERIFICATION:188throwableClassName = "java/lang/VerifyError";189break;190191case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_ADDED:192throwableClassName = "java/lang/UnsupportedOperationException";193message = "class redefinition failed: attempted to add a method";194break;195196case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED:197throwableClassName = "java/lang/UnsupportedOperationException";198message = "class redefinition failed: attempted to change the schema (add/remove fields)";199break;200201case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED:202throwableClassName = "java/lang/UnsupportedOperationException";203message = "class redefinition failed: attempted to change superclass or interfaces";204break;205206case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_DELETED:207throwableClassName = "java/lang/UnsupportedOperationException";208message = "class redefinition failed: attempted to delete a method";209break;210211case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_MODIFIERS_CHANGED:212throwableClassName = "java/lang/UnsupportedOperationException";213message = "class redefinition failed: attempted to change the class modifiers";214break;215216case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_MODIFIERS_CHANGED:217throwableClassName = "java/lang/UnsupportedOperationException";218message = "class redefinition failed: attempted to change method modifiers";219break;220221case JVMTI_ERROR_UNSUPPORTED_VERSION:222throwableClassName = "java/lang/UnsupportedClassVersionError";223break;224225case JVMTI_ERROR_NAMES_DONT_MATCH:226throwableClassName = "java/lang/NoClassDefFoundError";227message = "class names don't match";228break;229230case JVMTI_ERROR_INVALID_CLASS_FORMAT:231throwableClassName = "java/lang/ClassFormatError";232break;233234case JVMTI_ERROR_UNMODIFIABLE_CLASS:235throwableClassName = "java/lang/instrument/UnmodifiableClassException";236break;237238case JVMTI_ERROR_INVALID_CLASS:239throwableClassName = "java/lang/InternalError";240message = "class redefinition failed: invalid class";241break;242243case JVMTI_ERROR_CLASS_LOADER_UNSUPPORTED:244throwableClassName = "java/lang/UnsupportedOperationException";245message = "unsupported operation";246break;247248case JVMTI_ERROR_INTERNAL:249default:250throwableClassName = "java/lang/InternalError";251break;252}253254if ( message != NULL ) {255jboolean errorOutstanding;256257messageString = (*jnienv)->NewStringUTF(jnienv, message);258errorOutstanding = checkForAndClearThrowable(jnienv);259jplis_assert_msg(!errorOutstanding, "can't create exception java string");260}261return createThrowable( jnienv,262throwableClassName,263messageString);264265}266267268/**269* Calls toString() on the given message which is the same call made by270* Exception when passed a throwable to its constructor271*/272jstring273getMessageFromThrowable( JNIEnv* jnienv,274jthrowable exception) {275jclass exceptionClass = NULL;276jmethodID method = NULL;277jstring message = NULL;278jboolean errorOutstanding = JNI_FALSE;279280jplis_assert(isSafeForJNICalls(jnienv));281282/* call getMessage on exception */283exceptionClass = (*jnienv)->GetObjectClass(jnienv, exception);284errorOutstanding = checkForAndClearThrowable(jnienv);285jplis_assert(!errorOutstanding);286287if (!errorOutstanding) {288method = (*jnienv)->GetMethodID(jnienv,289exceptionClass,290"toString",291"()Ljava/lang/String;");292errorOutstanding = checkForAndClearThrowable(jnienv);293jplis_assert(!errorOutstanding);294}295296if (!errorOutstanding) {297message = (*jnienv)->CallObjectMethod(jnienv, exception, method);298errorOutstanding = checkForAndClearThrowable(jnienv);299jplis_assert(!errorOutstanding);300}301302jplis_assert(isSafeForJNICalls(jnienv));303304return message;305}306307308/**309* Returns whether the exception given is an unchecked exception:310* a subclass of Error or RuntimeException311*/312jboolean313isUnchecked( JNIEnv* jnienv,314jthrowable exception) {315jboolean result = JNI_FALSE;316317jplis_assert(isSafeForJNICalls(jnienv));318result = (exception == NULL) ||319isInstanceofClassName(jnienv, exception, "java/lang/Error") ||320isInstanceofClassName(jnienv, exception, "java/lang/RuntimeException");321jplis_assert(isSafeForJNICalls(jnienv));322return result;323}324325/*326* Returns the current throwable, if any. Clears the throwable state.327* Clients can use this to preserve the current throwable state on the stack.328*/329jthrowable330preserveThrowable(JNIEnv * jnienv) {331jthrowable result = (*jnienv)->ExceptionOccurred(jnienv);332if ( result != NULL ) {333(*jnienv)->ExceptionClear(jnienv);334}335return result;336}337338/*339* Installs the supplied throwable into the JNIEnv if the throwable is not null.340* Clients can use this to preserve the current throwable state on the stack.341*/342void343restoreThrowable( JNIEnv * jnienv,344jthrowable preservedException) {345throwThrowable( jnienv,346preservedException);347return;348}349350void351throwThrowable( JNIEnv * jnienv,352jthrowable exception) {353if ( exception != NULL ) {354jint result = (*jnienv)->Throw(jnienv, exception);355jplis_assert_msg(result == JNI_OK, "throwThrowable failed to re-throw");356}357return;358}359360361/*362* Always clears the JNIEnv throwable state. Returns true if an exception was present363* before the clearing operation.364*/365jboolean366checkForAndClearThrowable( JNIEnv * jnienv) {367jboolean result = (*jnienv)->ExceptionCheck(jnienv);368if ( result ) {369(*jnienv)->ExceptionClear(jnienv);370}371return result;372}373374/* creates a java.lang.InternalError and installs it into the JNIEnv */375void376createAndThrowInternalError(JNIEnv * jnienv) {377jthrowable internalError = createInternalError( jnienv, NULL);378throwThrowable(jnienv, forceFallback(internalError));379}380381void382createAndThrowThrowableFromJVMTIErrorCode(JNIEnv * jnienv, jvmtiError errorCode) {383jthrowable throwable = createThrowableFromJVMTIErrorCode(jnienv, errorCode);384throwThrowable(jnienv, forceFallback(throwable));385}386387void388mapThrownThrowableIfNecessary( JNIEnv * jnienv,389CheckedExceptionMapper mapper) {390jthrowable originalThrowable = NULL;391jthrowable resultThrowable = NULL;392393originalThrowable = preserveThrowable(jnienv);394395/* the throwable is now cleared, so JNI calls are safe */396if ( originalThrowable != NULL ) {397/* if there is an exception: we can just throw it if it is unchecked. If checked,398* we need to map it (mapper is conditional, will vary by usage, hence the callback)399*/400if ( isUnchecked(jnienv, originalThrowable) ) {401resultThrowable = originalThrowable;402}403else {404resultThrowable = (*mapper) (jnienv, originalThrowable);405}406}407408/* re-establish the correct throwable */409if ( resultThrowable != NULL ) {410throwThrowable(jnienv, forceFallback(resultThrowable));411}412413}414415416