src/core/android/SDL_android.cpp
changeset 6284 1893d507ba42
parent 6212 78d854de3a66
child 6307 6048116f40b1
     1.1 --- a/src/core/android/SDL_android.cpp	Tue Feb 07 19:34:24 2012 -0500
     1.2 +++ b/src/core/android/SDL_android.cpp	Sun Feb 12 20:57:32 2012 -0500
     1.3 @@ -20,6 +20,7 @@
     1.4  */
     1.5  #include "SDL_config.h"
     1.6  #include "SDL_stdinc.h"
     1.7 +#include "SDL_assert.h"
     1.8  
     1.9  #ifdef __ANDROID__
    1.10  
    1.11 @@ -203,6 +204,41 @@
    1.12  /*******************************************************************************
    1.13               Functions called by SDL into Java
    1.14  *******************************************************************************/
    1.15 +
    1.16 +class LocalReferenceHolder
    1.17 +{
    1.18 +private:
    1.19 +    static int s_active;
    1.20 +
    1.21 +public:
    1.22 +    static bool IsActive() {
    1.23 +        return s_active > 0;
    1.24 +    }
    1.25 +
    1.26 +public:
    1.27 +    LocalReferenceHolder() : m_env(NULL) { }
    1.28 +    ~LocalReferenceHolder() {
    1.29 +        if (m_env) {
    1.30 +            m_env->PopLocalFrame(NULL);
    1.31 +            --s_active;
    1.32 +        }
    1.33 +    }
    1.34 +
    1.35 +    bool init(JNIEnv *env, jint capacity = 16) {
    1.36 +        if (env->PushLocalFrame(capacity) < 0) {
    1.37 +            SDL_SetError("Failed to allocate enough JVM local references");
    1.38 +            return false;
    1.39 +        }
    1.40 +        ++s_active;
    1.41 +        m_env = env;
    1.42 +        return true;
    1.43 +    }
    1.44 +
    1.45 +protected:
    1.46 +    JNIEnv *m_env;
    1.47 +};
    1.48 +int LocalReferenceHolder::s_active;
    1.49 +
    1.50  extern "C" SDL_bool Android_JNI_CreateContext(int majorVersion, int minorVersion)
    1.51  {
    1.52      if (mEnv->CallStaticBooleanMethod(mActivityClass, midCreateGLContext, majorVersion, minorVersion)) {
    1.53 @@ -351,6 +387,8 @@
    1.54  // Test for an exception and call SDL_SetError with its detail if one occurs
    1.55  static bool Android_JNI_ExceptionOccurred()
    1.56  {
    1.57 +    SDL_assert(LocalReferenceHolder::IsActive());
    1.58 +
    1.59      jthrowable exception = mEnv->ExceptionOccurred();
    1.60      if (exception != NULL) {
    1.61          jmethodID mid;
    1.62 @@ -373,16 +411,11 @@
    1.63                      exceptionMessage, 0);
    1.64              SDL_SetError("%s: %s", exceptionNameUTF8, exceptionMessageUTF8);
    1.65              mEnv->ReleaseStringUTFChars(exceptionMessage, exceptionMessageUTF8);
    1.66 -            mEnv->DeleteLocalRef(exceptionMessage);
    1.67          } else {
    1.68              SDL_SetError("%s", exceptionNameUTF8);
    1.69          }
    1.70  
    1.71          mEnv->ReleaseStringUTFChars(exceptionName, exceptionNameUTF8);
    1.72 -        mEnv->DeleteLocalRef(exceptionName);
    1.73 -        mEnv->DeleteLocalRef(classClass);
    1.74 -        mEnv->DeleteLocalRef(exceptionClass);
    1.75 -        mEnv->DeleteLocalRef(exception);
    1.76  
    1.77          return true;
    1.78      }
    1.79 @@ -392,6 +425,7 @@
    1.80  
    1.81  static int Android_JNI_FileOpen(SDL_RWops* ctx)
    1.82  {
    1.83 +    LocalReferenceHolder refs;
    1.84      int result = 0;
    1.85  
    1.86      jmethodID mid;
    1.87 @@ -402,13 +436,8 @@
    1.88      jobject readableByteChannel;
    1.89      jstring fileNameJString;
    1.90  
    1.91 -    bool allocatedLocalFrame = false;
    1.92 -
    1.93 -    if (mEnv->PushLocalFrame(16) < 0) {
    1.94 -        SDL_SetError("Failed to allocate enough JVM local references");
    1.95 +    if (!refs.init(mEnv)) {
    1.96          goto failure;
    1.97 -    } else {
    1.98 -        allocatedLocalFrame = true;
    1.99      }
   1.100  
   1.101      fileNameJString = (jstring)ctx->hidden.androidio.fileName;
   1.102 @@ -481,16 +510,18 @@
   1.103          }
   1.104      }
   1.105  
   1.106 -    if (allocatedLocalFrame) {
   1.107 -        mEnv->PopLocalFrame(NULL);
   1.108 -    }
   1.109 -
   1.110      return result;
   1.111  }
   1.112  
   1.113  extern "C" int Android_JNI_FileOpen(SDL_RWops* ctx,
   1.114          const char* fileName, const char*)
   1.115  {
   1.116 +    LocalReferenceHolder refs;
   1.117 +
   1.118 +    if (!refs.init(mEnv)) {
   1.119 +        return -1;
   1.120 +    }
   1.121 +
   1.122      if (!ctx) {
   1.123          return -1;
   1.124      }
   1.125 @@ -499,7 +530,6 @@
   1.126      ctx->hidden.androidio.fileName = fileNameJString;
   1.127      ctx->hidden.androidio.fileNameRef = mEnv->NewGlobalRef(fileNameJString);
   1.128      ctx->hidden.androidio.inputStreamRef = NULL;
   1.129 -    mEnv->DeleteLocalRef(fileNameJString);
   1.130  
   1.131      return Android_JNI_FileOpen(ctx);
   1.132  }
   1.133 @@ -507,9 +537,14 @@
   1.134  extern "C" size_t Android_JNI_FileRead(SDL_RWops* ctx, void* buffer,
   1.135          size_t size, size_t maxnum)
   1.136  {
   1.137 +    LocalReferenceHolder refs;
   1.138      int bytesRemaining = size * maxnum;
   1.139      int bytesRead = 0;
   1.140  
   1.141 +    if (!refs.init(mEnv)) {
   1.142 +        return -1;
   1.143 +    }
   1.144 +
   1.145      jobject readableByteChannel = (jobject)ctx->hidden.androidio.readableByteChannel;
   1.146      jmethodID readMethod = (jmethodID)ctx->hidden.androidio.readMethod;
   1.147      jobject byteBuffer = mEnv->NewDirectByteBuffer(buffer, bytesRemaining);
   1.148 @@ -519,7 +554,6 @@
   1.149          int result = mEnv->CallIntMethod(readableByteChannel, readMethod, byteBuffer);
   1.150  
   1.151          if (Android_JNI_ExceptionOccurred()) {
   1.152 -            mEnv->DeleteLocalRef(byteBuffer);
   1.153              return 0;
   1.154          }
   1.155  
   1.156 @@ -532,8 +566,6 @@
   1.157          ctx->hidden.androidio.position += result;
   1.158      }
   1.159  
   1.160 -    mEnv->DeleteLocalRef(byteBuffer);
   1.161 -
   1.162      return bytesRead / size;
   1.163  }
   1.164  
   1.165 @@ -546,8 +578,14 @@
   1.166  
   1.167  static int Android_JNI_FileClose(SDL_RWops* ctx, bool release)
   1.168  {
   1.169 +    LocalReferenceHolder refs;
   1.170      int result = 0;
   1.171  
   1.172 +    if (!refs.init(mEnv)) {
   1.173 +        SDL_SetError("Failed to allocate enough JVM local references");
   1.174 +        return -1;
   1.175 +    }
   1.176 +
   1.177      if (ctx) {
   1.178          if (release) {
   1.179              mEnv->DeleteGlobalRef((jobject)ctx->hidden.androidio.fileNameRef);