Path: blob/master/src/java.desktop/macosx/native/libosxapp/JNIUtilities.h
41152 views
/*1* Copyright (c) 2020, 2021, 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#ifndef __JNIUTILITIES_H26#define __JNIUTILITIES_H2728#include "jni.h"29#include "jni_util.h"3031#import <Cocoa/Cocoa.h>3233/******** LOGGING SUPPORT *********/3435#define LOG_NULL(dst_var, name) \36if (dst_var == NULL) { \37NSLog(@"Bad JNI lookup %s\n", name); \38NSLog(@"%@",[NSThread callStackSymbols]); \39if ([NSThread isMainThread] == NO) { \40if ((*env)->ExceptionOccurred(env) == NULL) { \41JNU_ThrowInternalError(env, "Bad JNI Lookup"); \42} \43} else { \44if ((*env)->ExceptionOccurred(env) != NULL) { \45(*env)->ExceptionDescribe(env); \46} \47} \48[NSException raise:NSGenericException format:@"JNI Lookup Exception"]; \49}5051/******** GET CLASS SUPPORT *********/5253#define GET_CLASS(dst_var, cls) \54if (dst_var == NULL) { \55dst_var = (*env)->FindClass(env, cls); \56if (dst_var != NULL) dst_var = (*env)->NewGlobalRef(env, dst_var); \57} \58LOG_NULL(dst_var, cls); \59CHECK_NULL(dst_var);6061#define DECLARE_CLASS(dst_var, cls) \62static jclass dst_var = NULL; \63GET_CLASS(dst_var, cls);6465#define GET_CLASS_RETURN(dst_var, cls, ret) \66if (dst_var == NULL) { \67dst_var = (*env)->FindClass(env, cls); \68if (dst_var != NULL) dst_var = (*env)->NewGlobalRef(env, dst_var); \69} \70LOG_NULL(dst_var, cls); \71CHECK_NULL_RETURN(dst_var, ret);7273#define DECLARE_CLASS_RETURN(dst_var, cls, ret) \74static jclass dst_var = NULL; \75GET_CLASS_RETURN(dst_var, cls, ret);767778/******** GET METHOD SUPPORT *********/7980#define GET_METHOD(dst_var, cls, name, signature) \81if (dst_var == NULL) { \82dst_var = (*env)->GetMethodID(env, cls, name, signature); \83} \84LOG_NULL(dst_var, name); \85CHECK_NULL(dst_var);8687#define DECLARE_METHOD(dst_var, cls, name, signature) \88static jmethodID dst_var = NULL; \89GET_METHOD(dst_var, cls, name, signature);9091#define GET_METHOD_RETURN(dst_var, cls, name, signature, ret) \92if (dst_var == NULL) { \93dst_var = (*env)->GetMethodID(env, cls, name, signature); \94} \95LOG_NULL(dst_var, name); \96CHECK_NULL_RETURN(dst_var, ret);9798#define DECLARE_METHOD_RETURN(dst_var, cls, name, signature, ret) \99static jmethodID dst_var = NULL; \100GET_METHOD_RETURN(dst_var, cls, name, signature, ret);101102#define GET_STATIC_METHOD(dst_var, cls, name, signature) \103if (dst_var == NULL) { \104dst_var = (*env)->GetStaticMethodID(env, cls, name, signature); \105} \106LOG_NULL(dst_var, name); \107CHECK_NULL(dst_var);108109#define DECLARE_STATIC_METHOD(dst_var, cls, name, signature) \110static jmethodID dst_var = NULL; \111GET_STATIC_METHOD(dst_var, cls, name, signature);112113#define GET_STATIC_METHOD_RETURN(dst_var, cls, name, signature, ret) \114if (dst_var == NULL) { \115dst_var = (*env)->GetStaticMethodID(env, cls, name, signature); \116} \117LOG_NULL(dst_var, name); \118CHECK_NULL_RETURN(dst_var, ret);119120#define DECLARE_STATIC_METHOD_RETURN(dst_var, cls, name, signature, ret) \121static jmethodID dst_var = NULL; \122GET_STATIC_METHOD_RETURN(dst_var, cls, name, signature, ret);123124/******** GET FIELD SUPPORT *********/125126127#define GET_FIELD(dst_var, cls, name, signature) \128if (dst_var == NULL) { \129dst_var = (*env)->GetFieldID(env, cls, name, signature); \130} \131LOG_NULL(dst_var, name); \132CHECK_NULL(dst_var);133134#define DECLARE_FIELD(dst_var, cls, name, signature) \135static jfieldID dst_var = NULL; \136GET_FIELD(dst_var, cls, name, signature);137138#define GET_FIELD_RETURN(dst_var, cls, name, signature, ret) \139if (dst_var == NULL) { \140dst_var = (*env)->GetFieldID(env, cls, name, signature); \141} \142LOG_NULL(dst_var, name); \143CHECK_NULL_RETURN(dst_var, ret);144145#define DECLARE_FIELD_RETURN(dst_var, cls, name, signature, ret) \146static jfieldID dst_var = NULL; \147GET_FIELD_RETURN(dst_var, cls, name, signature, ret);148149#define GET_STATIC_FIELD_RETURN(dst_var, cls, name, signature, ret) \150if (dst_var == NULL) { \151dst_var = (*env)->GetStaticFieldID(env, cls, name, signature); \152} \153LOG_NULL(dst_var, name); \154CHECK_NULL_RETURN(dst_var, ret);155156#define DECLARE_STATIC_FIELD_RETURN(dst_var, cls, name, signature, ret) \157static jfieldID dst_var = NULL; \158GET_STATIC_FIELD_RETURN(dst_var, cls, name, signature, ret);159160/********* EXCEPTION_HANDLING *********/161162/*163* Some explanation to set context of the bigger picture.164* Before returning to Java from JNI, NSExceptions are caught - so long as165* the body of the native method is wrapped in the ENTER/EXIT macros.166* So if we want to directly return to Java from some nested Objective-C167* function when detecting a Java exception, we just need to raise an168* NSException. Then clear that right before returning to Java,169* leaving the Java exception to be seen back in Java-land.170*171* But if the current thread is the Appkit thread we might as well clear172* the Java Exception right now since there's nothing to receive it.173* In such a case control will propagate back to the run loop which might174* terminate the application. One drawback of that is that the location of175* termination does not show where the NSException originated.176* And for whatever reason, something swallows that exception.177* So as a debugging aid, when on the AppKit thread we can provide a178* way (via an env. var.) to log the location.179* Additionally provide a similar way to prevent the NSException being180* raised and instead just clear the Java Exception.181* Together these provide alternate behaviours for more debugging info182* or maybe a way for the app to continue running depending on the exact183* nature of the problem that has been detected and how survivable it is.184*/185#define CHECK_EXCEPTION() \186if ((*env)->ExceptionOccurred(env) != NULL) { \187if ([NSThread isMainThread] == YES) { \188if (getenv("JNU_APPKIT_TRACE")) { \189(*env)->ExceptionDescribe(env); \190NSLog(@"%@",[NSThread callStackSymbols]); \191} else { \192(*env)->ExceptionClear(env); \193} \194} \195if (getenv("JNU_NO_COCOA_EXCEPTION") == NULL) { \196[NSException raise:NSGenericException format:@"Java Exception"]; \197} else { \198(*env)->ExceptionClear(env); \199} \200};201202#define CHECK_EXCEPTION_NULL_RETURN(x, y) \203CHECK_EXCEPTION(); \204if ((x) == NULL) { \205return y; \206};207208/* Create a pool and initiate a try block to catch any exception */209#define JNI_COCOA_ENTER(env) \210NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; \211@try {212213/* Don't allow NSExceptions to escape to Java.214* If there is a Java exception that has been thrown that should escape.215* And ensure we drain the auto-release pool.216*/217#define JNI_COCOA_EXIT(env) \218} \219@catch (NSException *e) { \220NSLog(@"%@", [e callStackSymbols]); \221} \222@finally { \223[pool drain]; \224};225226/* Same as above but adds a clean up action.227* Requires that whatever is being cleaned up is in scope.228*/229#define JNI_COCOA_EXIT_WITH_ACTION(env, action) \230} \231@catch (NSException *e) { \232{ action; }; \233NSLog(@"%@", [e callStackSymbols]); \234} \235@finally { \236[pool drain]; \237};238239/******** STRING CONVERSION SUPPORT *********/240241JNIEXPORT NSString* JavaStringToNSString(JNIEnv *env, jstring jstr);242243JNIEXPORT jstring NSStringToJavaString(JNIEnv* env, NSString *str);244245JNIEXPORT NSString* NormalizedPathNSStringFromJavaString(JNIEnv *env, jstring pathStr);246247JNIEXPORT jstring NormalizedPathJavaStringFromNSString(JNIEnv* env, NSString *str);248249#endif /* __JNIUTILITIES_H */250251252