| Index: base/android/jni_android.cc
|
| diff --git a/base/android/jni_android.cc b/base/android/jni_android.cc
|
| index e6d6e56c2677c29f046c600bc34b7f833b6b32a3..dca2ca439d8a14cf6d6e1fc6a1426770ac99e1eb 100644
|
| --- a/base/android/jni_android.cc
|
| +++ b/base/android/jni_android.cc
|
| @@ -4,12 +4,49 @@
|
|
|
| #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;
|
| +
|
| +struct MethodIdentifier {
|
| + const char* class_name;
|
| + const char* method;
|
| + const char* jni_signature;
|
| +
|
| + bool operator<(const MethodIdentifier& other) const {
|
| + int r = strcmp(class_name, other.class_name);
|
| + if (r < 0) {
|
| + return true;
|
| + } else if (r > 0) {
|
| + return false;
|
| + }
|
| +
|
| + r = strcmp(method, other.method);
|
| + if (r < 0) {
|
| + return true;
|
| + } else if (r > 0) {
|
| + return false;
|
| + }
|
| +
|
| + return strcmp(jni_signature, other.jni_signature) < 0;
|
| + }
|
| +};
|
| +
|
| +typedef std::map<MethodIdentifier, jmethodID> MethodIDMap;
|
| +base::LazyInstance<MethodIDMap, base::LeakyLazyInstanceTraits<MethodIDMap> >
|
| + g_method_id_map = LAZY_INSTANCE_INITIALIZER;
|
| +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 +84,49 @@ 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) {
|
| + MethodIdentifier key;
|
| + key.class_name = class_name;
|
| + key.method = method;
|
| + key.jni_signature = jni_signature;
|
| +
|
| + 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();
|
| + }
|
| + 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.
|
| + std::pair<MethodIDMap::const_iterator, bool> result =
|
| + map->insert(std::make_pair(key, id));
|
| + DCHECK_EQ(id, result.first->second);
|
| + base::subtle::Release_Store(&g_method_id_map_lock, kUnlocked);
|
| +
|
| + return id;
|
| }
|
|
|
| jmethodID GetMethodID(JNIEnv* env,
|
|
|