From 3d94a564f4c439ca0d1c2a0af807b9edeeb39299 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Str=C3=B8mme?= Date: Mon, 29 Sep 2014 14:16:28 +0200 Subject: Android: Improve cache logic in findClass() This change adds guards to ensure that we only do a class look-up once when calling QJNIEnvironmentPrivate::findClass(). IF someone calls findClass() with an environment that does not contain a "valid" class loader, we should fallback to loadClass(), but only once. Change-Id: If5fc82956db889f3269bb33c98a16c49cae55def Reviewed-by: Yoann Lopes --- src/corelib/kernel/qjni.cpp | 65 ++++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/src/corelib/kernel/qjni.cpp b/src/corelib/kernel/qjni.cpp index 173127b063..452e3464d6 100644 --- a/src/corelib/kernel/qjni.cpp +++ b/src/corelib/kernel/qjni.cpp @@ -80,38 +80,22 @@ static QString toDotEncodedClassName(const char *className) return QString::fromLatin1(className).replace(QLatin1Char('/'), QLatin1Char('.')); } -static jclass getCachedClass(const QString &classDotEnc) +static jclass getCachedClass(const QString &classDotEnc, bool *isCached = 0) { QHash::iterator it = cachedClasses->find(classDotEnc); + const bool found = (it != cachedClasses->end()); - if (it == cachedClasses->end()) - return 0; - - return it.value(); -} - -static jclass findClass(const char *className, JNIEnv *env) -{ - const QString &classDotEnc = toDotEncodedClassName(className); - jclass clazz = getCachedClass(classDotEnc); - if (clazz != 0) - return clazz; - - jclass fclazz = env->FindClass(className); - if (!exceptionCheckAndClear(env)) { - clazz = static_cast(env->NewGlobalRef(fclazz)); - env->DeleteLocalRef(fclazz); - } + if (isCached != 0) + *isCached = found; - cachedClasses->insert(classDotEnc, clazz); - return clazz; + return found ? it.value() : 0; } -static jclass loadClass(const char *className, JNIEnv *env) +static jclass loadClassDotEnc(const QString &classDotEnc, JNIEnv *env) { - const QString &classDotEnc = toDotEncodedClassName(className); - jclass clazz = getCachedClass(classDotEnc); - if (clazz != 0) + bool isCached = false; + jclass clazz = getCachedClass(classDotEnc, &isCached); + if (clazz != 0 || isCached) return clazz; QJNIObjectPrivate classLoader = QtAndroidPrivate::classLoader(); @@ -130,6 +114,11 @@ static jclass loadClass(const char *className, JNIEnv *env) return clazz; } +inline static jclass loadClass(const char *className, JNIEnv *env) +{ + return loadClassDotEnc(toDotEncodedClassName(className), env); +} + typedef QHash JMethodIDHash; Q_GLOBAL_STATIC(JMethodIDHash, cachedMethodID) @@ -224,12 +213,28 @@ JNIEnv *QJNIEnvironmentPrivate::operator->() jclass QJNIEnvironmentPrivate::findClass(const char *className, JNIEnv *env) { - jclass clazz = 0; - if (env != 0) - clazz = ::findClass(className, env); + const QString &classDotEnc = toDotEncodedClassName(className); + bool isCached = false; + jclass clazz = getCachedClass(classDotEnc, &isCached); + + const bool found = (clazz != 0) || (clazz == 0 && isCached); + + if (found) + return clazz; + + if (env != 0) { // We got an env. pointer (We expect this to be the right env. and call FindClass()) + jclass fclazz = env->FindClass(className); + if (!exceptionCheckAndClear(env)) { + clazz = static_cast(env->NewGlobalRef(fclazz)); + env->DeleteLocalRef(fclazz); + } + + if (clazz != 0) + cachedClasses->insert(classDotEnc, clazz); + } - if (clazz == 0) - clazz = loadClass(className, QJNIEnvironmentPrivate()); + if (clazz == 0) // We didn't get an env. pointer or we got one with the WRONG class loader... + clazz = loadClassDotEnc(classDotEnc, QJNIEnvironmentPrivate()); return clazz; } -- cgit v1.2.3