Chromium Code Reviews| Index: base/android/jni_android.cc |
| diff --git a/base/android/jni_android.cc b/base/android/jni_android.cc |
| index e6d6e56c2677c29f046c600bc34b7f833b6b32a3..8f857d82dc560524ff5d8269e398cfedf98c815a 100644 |
| --- a/base/android/jni_android.cc |
| +++ b/base/android/jni_android.cc |
| @@ -4,12 +4,23 @@ |
| #include "base/android/jni_android.h" |
| +#include <map> |
| + |
| #include "base/android/scoped_java_ref.h" |
| +#include "base/atomicops.h" |
| +#include "base/lazy_instance.h" |
| #include "base/logging.h" |
| +#include "base/threading/platform_thread.h" |
| namespace { |
| JavaVM* g_jvm = 0; |
| jobject g_application_context = NULL; |
| + |
| +typedef std::map<std::string, jmethodID> MethodIDMap; |
| +base::LazyInstance<MethodIDMap> g_method_id_map = LAZY_INSTANCE_INITIALIZER; |
|
joth
2011/12/02 14:10:13
fwiw, I think we're happy to use LeakyLazyInstance
|
| +const base::subtle::AtomicWord kUnlocked = 0; |
| +const base::subtle::AtomicWord kLocked = 1; |
| +base::subtle::AtomicWord g_method_id_map_lock = kUnlocked; |
| } |
| namespace base { |
| @@ -47,10 +58,56 @@ jobject GetApplicationContext() { |
| return g_application_context; |
| } |
| -MethodID::MethodID(JNIEnv* env, const char* class_name, const char* method, |
| - const char* jni_signature) { |
| +jmethodID GetMethodIDFromClassName(JNIEnv* env, |
| + const char* class_name, |
| + const char* method, |
| + const char* jni_signature) { |
| + DCHECK_EQ(std::string::npos, std::string(class_name).find('!')); |
| + DCHECK_EQ(std::string::npos, std::string(method).find('!')); |
| + DCHECK_EQ(std::string::npos, std::string(jni_signature).find('!')); |
| + std::string key(class_name); |
| + key += '!'; |
| + key += method; |
| + key += '!'; |
| + key += jni_signature; |
|
joth
2011/12/02 14:10:13
shame we have to do this everytime we lookup a sym
|
| + |
| + MethodIDMap* map = g_method_id_map.Pointer(); |
| + bool found = false; |
| + |
| + while (base::subtle::Acquire_CompareAndSwap(&g_method_id_map_lock, |
| + kUnlocked, |
| + kLocked) != kUnlocked) { |
| + base::PlatformThread::YieldCurrentThread(); |
| + } |
|
joth
2011/12/02 14:10:13
looks sufficiently fun to benefit from having some
|
| + MethodIDMap::const_iterator iter = map->find(key); |
| + if (iter != map->end()) { |
| + found = true; |
| + } |
| + base::subtle::Release_Store(&g_method_id_map_lock, kUnlocked); |
| + |
| + // Addition to the map does not invalidate this iterator. |
| + if (found) { |
| + return iter->second; |
| + } |
| + |
| ScopedJavaLocalRef<jclass> clazz(env, env->FindClass(class_name)); |
| - id_ = GetMethodID(env, clazz.obj(), method, jni_signature); |
| + jmethodID id = GetMethodID(env, clazz.obj(), method, jni_signature); |
| + |
| + while (base::subtle::Acquire_CompareAndSwap(&g_method_id_map_lock, |
| + kUnlocked, |
| + kLocked) != kUnlocked) { |
| + base::PlatformThread::YieldCurrentThread(); |
| + } |
| + // Another thread may have populated the map already. |
| + iter = map->find(key); |
| + if (iter == map->end()) { |
|
joth
2011/12/02 14:10:13
nit: rather than walk the tree twice here, you can
|
| + map->insert(std::make_pair(key, id)); |
| + } else { |
| + DCHECK_EQ(id, iter->second); |
| + } |
| + base::subtle::Release_Store(&g_method_id_map_lock, kUnlocked); |
| + |
| + return id; |
| } |
| jmethodID GetMethodID(JNIEnv* env, |