# HG changeset patch # User jcbeyler # Date 1539111807 25200 # Tue Oct 09 12:03:27 2018 -0700 # Node ID 04e88e5173ae9e8f08add7c6ee25d343c411f982 # Parent a986ec4ff214ee7ce35d6ed9824de0ec253edebe [mq]: lock_reformat diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIGlobalRefLocker.cpp b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIGlobalRefLocker.cpp --- a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIGlobalRefLocker.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIGlobalRefLocker.cpp @@ -20,10 +20,12 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + #include #include #include #include "jni_tools.h" +#include "ExceptionCheckingJniEnv.hpp" extern "C" { @@ -35,28 +37,18 @@ * Signature: (JJ)V */ JNIEXPORT void JNICALL Java_nsk_share_gc_lock_jniref_JNIGlobalRefLocker_criticalNative - (JNIEnv *env, jobject o, jlong enterTime, jlong sleepTime) { + (JNIEnv *jni_env, jobject o, jlong enterTime, jlong sleepTime) { + ExceptionCheckingJniEnvPtr env(jni_env); + jobject obj; jobject gref; time_t start_time, current_time; if (objFieldId == NULL) { jclass klass = env->GetObjectClass(o); - if (klass == NULL) { - printf("Error: GetObjectClass returned NULL\n"); - return; - } objFieldId = env->GetFieldID(klass, "obj", "Ljava/lang/Object;"); - if (objFieldId == NULL) { - printf("Error: GetFieldID returned NULL\n"); - return; - } } obj = env->GetObjectField(o, objFieldId); - if (obj == NULL) { - printf("Error: GetObjectField returned NULL\n"); - return; - } env->SetObjectField(o, objFieldId, NULL); start_time = time(NULL); enterTime /= 1000; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/libJNIGlobalRefLocker.cpp b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/libJNIGlobalRefLocker.cpp --- a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/libJNIGlobalRefLocker.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/libJNIGlobalRefLocker.cpp @@ -24,3 +24,4 @@ #include "JNIGlobalRefLocker.cpp" #include "jni_tools.cpp" #include "nsk_tools.cpp" +#include "ExceptionCheckingJniEnv.cpp" diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jni/ExceptionCheckingJniEnv.cpp b/test/hotspot/jtreg/vmTestbase/nsk/share/jni/ExceptionCheckingJniEnv.cpp new file mode 100644 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jni/ExceptionCheckingJniEnv.cpp @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, Google and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include + +#include "ExceptionCheckingJniEnv.hpp" + +namespace { + +template +class JNIVerifier { + public: + JNIVerifier(ExceptionCheckingJniEnv *env, const std::string& base_msg) + : _env(env), _base_msg(base_msg) { + } + + ~JNIVerifier() { + JNIEnv* jni_env = _env->GetJNIEnv(); + if (jni_env->ExceptionCheck()) { + _env->HandleError(_base_msg.c_str()); + } else { + if (!_return_error.empty()) { + const std::string msg = _base_msg + ":" + _return_error; + _env->HandleError(msg.c_str()); + } + } + } + + T ResultNotNull(T ptr) { + if (ptr == NULL) { + _return_error = "Return is NULL"; + } + return ptr; + } + + private: + ExceptionCheckingJniEnv* _env; + std::string _base_msg; + std::string _return_error; +}; + +} + +jclass ExceptionCheckingJniEnv::GetObjectClass(jobject obj) { + JNIVerifier marker(this, "GetObjectClass"); + return marker.ResultNotNull(_jni_env->GetObjectClass(obj)); +} + +jfieldID ExceptionCheckingJniEnv::GetFieldID(jclass klass, const char *name, const char* type) { + JNIVerifier marker(this, "GetObjectClass"); + return marker.ResultNotNull(_jni_env->GetFieldID(klass, name, type)); +} + +jobject ExceptionCheckingJniEnv::GetObjectField(jobject obj, jfieldID field) { + JNIVerifier marker(this, "GetObjectField"); + return marker.ResultNotNull(_jni_env->GetObjectField(obj, field)); +} + +void ExceptionCheckingJniEnv::SetObjectField(jobject obj, jfieldID field, jobject value) { + JNIVerifier<> marker(this, "SetObjectField"); + _jni_env->SetObjectField(obj, field, value); +} + +jobject ExceptionCheckingJniEnv::NewGlobalRef(jobject obj) { + JNIVerifier marker(this, "GetObjectField"); + return marker.ResultNotNull(_jni_env->NewGlobalRef(obj)); +} + +void ExceptionCheckingJniEnv::DeleteGlobalRef(jobject obj) { + JNIVerifier<> marker(this, "DeleteGlobalRef"); + _jni_env->DeleteGlobalRef(obj); +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jni/ExceptionCheckingJniEnv.hpp b/test/hotspot/jtreg/vmTestbase/nsk/share/jni/ExceptionCheckingJniEnv.hpp new file mode 100644 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jni/ExceptionCheckingJniEnv.hpp @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, Google and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +#ifndef NSK_EXCEPTIONCHECKINGJNIENV_DEFINED +#define NSK_EXCEPTIONCHECKINGJNIENV_DEFINED + +#include + +/** + * ExceptionCheckingJniEnv wraps around the JNIEnv data structure and + * methods to enable automatic exception checking. This allows test writers + * and readers to concentrate on what the test is to do and leave the + * error checking and throwing to this data structure and subsystem. + * + * For example: + * + * ... JNIEnv* env ... + * jclass klass = env->GetObjectClass(o); + * if (klass == NULL) { + * printf("Error: GetObjectClass returned NULL\n"); + * return; + * } + * if (env->ExceptionCheck()) { + * ... + * } + * + * Can be simplified to: + * ... ExceptionCheckingJniEnv* env ... + * jclass klass = env->GetObjectClass(o); + * + * Where now the JNI Exception checking and the NULL return checking are done + * internally and will perform whatever action the ErrorHandler requires. + * + * By default, the error handler describes the exception via the JNI + * ExceptionDescribe method and calls FatalError. + * + * Note: at a future date, this will also include the tracing mechanism done in + * NSK_VERIFY, which will thus embed its logic into the ExceptionCheckingJniEnv + * and clearing that up for the code readers and writers. + */ +class ExceptionCheckingJniEnv { + public: + // JNIEnv API redefinitions. + jfieldID GetFieldID(jclass klass, const char *name, const char* type); + jclass GetObjectClass(jobject obj); + jobject GetObjectField(jobject obj, jfieldID field); + void SetObjectField(jobject obj, jfieldID field, jobject value); + + jobject NewGlobalRef(jobject obj); + void DeleteGlobalRef(jobject obj); + + // ExceptionCheckingJniEnv methods. + JNIEnv* GetJNIEnv() { + return _jni_env; + } + + void HandleError(const char* msg) { + if (_error_handler) { + _error_handler(_jni_env, msg); + } + } + + typedef void (*ErrorHandler)(JNIEnv* env, const char* error_message); + + static void FatalError(JNIEnv* env, const char* message) { + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + } + env->FatalError(message); + } + + ExceptionCheckingJniEnv(JNIEnv* jni_env, ErrorHandler error_handler) : + _jni_env(jni_env), _error_handler(error_handler) {} + + private: + JNIEnv* _jni_env; + ErrorHandler _error_handler; +}; + +// We cannot use unique_ptr due to this being gnu98++, so use this instead: +class ExceptionCheckingJniEnvPtr { + private: + ExceptionCheckingJniEnv _env; + + public: + ExceptionCheckingJniEnv* operator->() { + return &_env; + } + + ExceptionCheckingJniEnvPtr( + JNIEnv* jni_env, + ExceptionCheckingJniEnv::ErrorHandler error_handler = ExceptionCheckingJniEnv::FatalError) : + _env(jni_env, error_handler) { + } +}; + +#endif # HG changeset patch # User jcbeyler # Date 1539111890 25200 # Tue Oct 09 12:04:50 2018 -0700 # Node ID 3d0bd22ed01358f890eaf8767c231da42b2a575f # Parent 04e88e5173ae9e8f08add7c6ee25d343c411f982 [mq]: without_string diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jni/ExceptionCheckingJniEnv.cpp b/test/hotspot/jtreg/vmTestbase/nsk/share/jni/ExceptionCheckingJniEnv.cpp --- a/test/hotspot/jtreg/vmTestbase/nsk/share/jni/ExceptionCheckingJniEnv.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jni/ExceptionCheckingJniEnv.cpp @@ -22,8 +22,6 @@ * questions. */ -#include - #include "ExceptionCheckingJniEnv.hpp" namespace { @@ -31,22 +29,42 @@ template class JNIVerifier { public: - JNIVerifier(ExceptionCheckingJniEnv *env, const std::string& base_msg) - : _env(env), _base_msg(base_msg) { + JNIVerifier(ExceptionCheckingJniEnv *env, const char* base_msg) + : _env(env), _base_msg(base_msg), _return_error(NULL) { } ~JNIVerifier() { JNIEnv* jni_env = _env->GetJNIEnv(); if (jni_env->ExceptionCheck()) { - _env->HandleError(_base_msg.c_str()); - } else { - if (!_return_error.empty()) { - const std::string msg = _base_msg + ":" + _return_error; - _env->HandleError(msg.c_str()); - } + _env->HandleError(_base_msg); + return; + } + + if (_return_error != NULL) { + ProcessReturnError(); } } + void ProcessReturnError() { + int len = snprintf(NULL, 0, "%s : %s", _base_msg, _return_error) + 1; + + if (len <= 0) { + _env->HandleError(_return_error); + return; + } + + char* full_message = (char*) malloc(len); + if (full_message == NULL) { + _env->HandleError(_return_error); + return; + } + + snprintf(full_message, len, "%s : %s", _base_msg, _return_error); + + _env->HandleError(full_message); + free(full_message); + } + T ResultNotNull(T ptr) { if (ptr == NULL) { _return_error = "Return is NULL"; @@ -56,8 +74,8 @@ private: ExceptionCheckingJniEnv* _env; - std::string _base_msg; - std::string _return_error; + const char* _base_msg; + const char* _return_error; }; }