diff -r 03a7ceb3487b src/core/android/SDL_android.cpp --- a/src/core/android/SDL_android.cpp Tue Feb 07 19:34:24 2012 -0500 +++ b/src/core/android/SDL_android.cpp Sat Feb 11 21:40:56 2012 -0500 @@ -203,6 +203,40 @@ /******************************************************************************* Functions called by SDL into Java *******************************************************************************/ + +class LocalReferenceHolder +{ +private: + static int s_active; + +public: + static bool IsActive() { + return s_active > 0; + } + +public: + LocalReferenceHolder() : m_env(NULL) { } + ~LocalReferenceHolder() { + if (m_env) { + m_env->PopLocalFrame(NULL); + --s_active; + } + } + + bool init(JNIEnv *env, jint capacity = 16) { + if (env->PushLocalFrame(capacity) < 0) { + return false; + } + ++s_active; + m_env = env; + return true; + } + +protected: + JNIEnv *m_env; +}; +int LocalReferenceHolder::s_active; + extern "C" SDL_bool Android_JNI_CreateContext(int majorVersion, int minorVersion) { if (mEnv->CallStaticBooleanMethod(mActivityClass, midCreateGLContext, majorVersion, minorVersion)) { @@ -351,6 +385,8 @@ // Test for an exception and call SDL_SetError with its detail if one occurs static bool Android_JNI_ExceptionOccurred() { + SDL_assert(LocalReferenceHolder::IsActive()); + jthrowable exception = mEnv->ExceptionOccurred(); if (exception != NULL) { jmethodID mid; @@ -373,16 +409,11 @@ exceptionMessage, 0); SDL_SetError("%s: %s", exceptionNameUTF8, exceptionMessageUTF8); mEnv->ReleaseStringUTFChars(exceptionMessage, exceptionMessageUTF8); - mEnv->DeleteLocalRef(exceptionMessage); } else { SDL_SetError("%s", exceptionNameUTF8); } mEnv->ReleaseStringUTFChars(exceptionName, exceptionNameUTF8); - mEnv->DeleteLocalRef(exceptionName); - mEnv->DeleteLocalRef(classClass); - mEnv->DeleteLocalRef(exceptionClass); - mEnv->DeleteLocalRef(exception); return true; } @@ -392,6 +423,7 @@ static int Android_JNI_FileOpen(SDL_RWops* ctx) { + LocalReferenceHolder refs; int result = 0; jmethodID mid; @@ -402,13 +434,9 @@ jobject readableByteChannel; jstring fileNameJString; - bool allocatedLocalFrame = false; - - if (mEnv->PushLocalFrame(16) < 0) { + if (!refs.init(mEnv)) { SDL_SetError("Failed to allocate enough JVM local references"); goto failure; - } else { - allocatedLocalFrame = true; } fileNameJString = (jstring)ctx->hidden.androidio.fileName; @@ -481,10 +509,6 @@ } } - if (allocatedLocalFrame) { - mEnv->PopLocalFrame(NULL); - } - return result; } @@ -507,9 +531,15 @@ extern "C" size_t Android_JNI_FileRead(SDL_RWops* ctx, void* buffer, size_t size, size_t maxnum) { + LocalReferenceHolder refs; int bytesRemaining = size * maxnum; int bytesRead = 0; + if (!refs.init(mEnv)) { + SDL_SetError("Failed to allocate enough JVM local references"); + return -1; + } + jobject readableByteChannel = (jobject)ctx->hidden.androidio.readableByteChannel; jmethodID readMethod = (jmethodID)ctx->hidden.androidio.readMethod; jobject byteBuffer = mEnv->NewDirectByteBuffer(buffer, bytesRemaining); @@ -519,7 +549,6 @@ int result = mEnv->CallIntMethod(readableByteChannel, readMethod, byteBuffer); if (Android_JNI_ExceptionOccurred()) { - mEnv->DeleteLocalRef(byteBuffer); return 0; } @@ -532,8 +561,6 @@ ctx->hidden.androidio.position += result; } - mEnv->DeleteLocalRef(byteBuffer); - return bytesRead / size; } @@ -546,8 +573,14 @@ static int Android_JNI_FileClose(SDL_RWops* ctx, bool release) { + LocalReferenceHolder refs; int result = 0; + if (!refs.init(mEnv)) { + SDL_SetError("Failed to allocate enough JVM local references"); + return -1; + } + if (ctx) { if (release) { mEnv->DeleteGlobalRef((jobject)ctx->hidden.androidio.fileNameRef);