Upstream version 9.37.197.0
[platform/framework/web/crosswalk.git] / src / content / browser / renderer_host / java / jni_helper.cc
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/browser/renderer_host/java/jni_helper.h"
6
7 #include <map>
8
9 #include "base/android/jni_android.h"
10 #include "base/lazy_instance.h"
11 #include "base/threading/platform_thread.h"
12
13 namespace content {
14
15 namespace {
16
17 struct MethodIdentifier {
18   const char* class_name;
19   const char* method;
20   const char* jni_signature;
21
22   bool operator<(const MethodIdentifier& other) const {
23     int r = strcmp(class_name, other.class_name);
24     if (r < 0) {
25       return true;
26     } else if (r > 0) {
27       return false;
28     }
29
30     r = strcmp(method, other.method);
31     if (r < 0) {
32       return true;
33     } else if (r > 0) {
34       return false;
35     }
36
37     return strcmp(jni_signature, other.jni_signature) < 0;
38   }
39 };
40
41 typedef std::map<MethodIdentifier, jmethodID> MethodIDMap;
42
43 const base::subtle::AtomicWord kUnlocked = 0;
44 const base::subtle::AtomicWord kLocked = 1;
45 base::subtle::AtomicWord g_method_id_map_lock = kUnlocked;
46
47 base::LazyInstance<MethodIDMap> g_method_id_map = LAZY_INSTANCE_INITIALIZER;
48
49 }  // namespace
50
51 jfieldID GetFieldID(JNIEnv* env,
52                     const base::android::JavaRef<jclass>& clazz,
53                     const char* field_name,
54                     const char* jni_signature) {
55   jfieldID field_id = env->GetFieldID(clazz.obj(), field_name, jni_signature);
56   CHECK(!base::android::ClearException(env) && field_id) <<
57       "Failed to find field " << field_name << " " << jni_signature;
58   return field_id;
59 }
60
61 jmethodID GetMethodIDFromClassName(JNIEnv* env,
62                                    const char* class_name,
63                                    const char* method,
64                                    const char* jni_signature) {
65   MethodIdentifier key;
66   key.class_name = class_name;
67   key.method = method;
68   key.jni_signature = jni_signature;
69
70   MethodIDMap* map = g_method_id_map.Pointer();
71   bool found = false;
72
73   while (base::subtle::Acquire_CompareAndSwap(&g_method_id_map_lock,
74                                               kUnlocked,
75                                               kLocked) != kUnlocked) {
76     base::PlatformThread::YieldCurrentThread();
77   }
78   MethodIDMap::const_iterator iter = map->find(key);
79   if (iter != map->end()) {
80     found = true;
81   }
82   base::subtle::Release_Store(&g_method_id_map_lock, kUnlocked);
83
84   // Addition to the map does not invalidate this iterator.
85   if (found) {
86     return iter->second;
87   }
88
89   base::android::ScopedJavaLocalRef<jclass> clazz(
90       env, env->FindClass(class_name));
91   jmethodID id = base::android::MethodID::Get<
92       base::android::MethodID::TYPE_INSTANCE>(
93           env, clazz.obj(), method, jni_signature);
94
95   while (base::subtle::Acquire_CompareAndSwap(&g_method_id_map_lock,
96                                               kUnlocked,
97                                               kLocked) != kUnlocked) {
98     base::PlatformThread::YieldCurrentThread();
99   }
100   // Another thread may have populated the map already.
101   std::pair<MethodIDMap::const_iterator, bool> result =
102       map->insert(std::make_pair(key, id));
103   DCHECK_EQ(id, result.first->second);
104   base::subtle::Release_Store(&g_method_id_map_lock, kUnlocked);
105
106   return id;
107 }
108
109 }  // namespace content