blob: 7b2f3c49bd328c7e0e9bc548eee98a713f09bb21 [file] [log] [blame]
Alex Light79d6c802019-06-27 15:50:11 +00001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef ART_RUNTIME_JNI_JNI_ID_MANAGER_H_
18#define ART_RUNTIME_JNI_JNI_ID_MANAGER_H_
19
20#include <atomic>
21#include <jni.h>
22#include <vector>
23
24#include "art_field.h"
25#include "art_method.h"
26#include "base/mutex.h"
Alex Lightf3677472019-06-26 16:31:53 -070027#include "jni_id_type.h"
Alex Light79d6c802019-06-27 15:50:11 +000028
29namespace art {
30namespace jni {
31
32class ScopedEnableSuspendAllJniIdQueries;
33class JniIdManager {
34 public:
Nicolas Geoffray4ac0e152019-09-18 06:14:50 +000035 class IdVisitor {
36 public:
37 virtual ~IdVisitor() {}
38 virtual void VisitMethodId(jmethodID id, ArtMethod** method) = 0;
39 virtual void VisitFieldId(jfieldID id, ArtField** field) = 0;
40 virtual bool ShouldVisitFields() = 0;
41 virtual bool ShouldVisitMethods() = 0;
42 };
43
44 template <typename T,
45 typename = typename std::enable_if<std::is_same_v<T, jmethodID> ||
46 std::is_same_v<T, jfieldID>>>
47 static constexpr bool IsIndexId(T val) {
48 return val == nullptr || reinterpret_cast<uintptr_t>(val) % 2 == 1;
49 }
50
Alex Light79d6c802019-06-27 15:50:11 +000051 ArtMethod* DecodeMethodId(jmethodID method) REQUIRES(!Locks::jni_id_lock_);
52 ArtField* DecodeFieldId(jfieldID field) REQUIRES(!Locks::jni_id_lock_);
53 jmethodID EncodeMethodId(ArtMethod* method) REQUIRES(!Locks::jni_id_lock_)
54 REQUIRES_SHARED(Locks::mutator_lock_);
55 jfieldID EncodeFieldId(ArtField* field) REQUIRES(!Locks::jni_id_lock_)
56 REQUIRES_SHARED(Locks::mutator_lock_);
57
Nicolas Geoffray4ac0e152019-09-18 06:14:50 +000058 void VisitIds(Thread* self, IdVisitor* visitor);
59
60 template<typename MethodVisitor, typename FieldVisitor>
61 void VisitIds(Thread* self, MethodVisitor m, FieldVisitor f) REQUIRES(!Locks::jni_id_lock_) {
62 struct FuncVisitor : public IdVisitor {
63 public:
64 FuncVisitor(MethodVisitor m, FieldVisitor f) : m_(m), f_(f) {}
65 bool ShouldVisitFields() override {
66 return true;
67 }
68 bool ShouldVisitMethods() override {
69 return true;
70 }
71 void VisitMethodId(jmethodID mid, ArtMethod** am) NO_THREAD_SAFETY_ANALYSIS override {
72 m_(mid, am);
73 }
74 void VisitFieldId(jfieldID fid, ArtField** af) NO_THREAD_SAFETY_ANALYSIS override {
75 f_(fid, af);
76 }
77
78 private:
79 MethodVisitor m_;
80 FieldVisitor f_;
81 };
82 FuncVisitor fv(m, f);
83 VisitIds(self, &fv);
84 }
85
Alex Light79d6c802019-06-27 15:50:11 +000086 private:
87 template <typename ArtType>
88 uintptr_t EncodeGenericId(ArtType* t) REQUIRES(!Locks::jni_id_lock_)
89 REQUIRES_SHARED(Locks::mutator_lock_);
90 template <typename ArtType>
91 ArtType* DecodeGenericId(uintptr_t input) REQUIRES(!Locks::jni_id_lock_);
92 template <typename ArtType> std::vector<ArtType*>& GetGenericMap() REQUIRES(Locks::jni_id_lock_);
Alex Lightf3677472019-06-26 16:31:53 -070093 template <typename ArtType>
94 uintptr_t GetNextId(JniIdType id, ArtType* t) REQUIRES(Locks::jni_id_lock_);
Alex Light79d6c802019-06-27 15:50:11 +000095 template <typename ArtType>
96 size_t GetLinearSearchStartId(ArtType* t) REQUIRES(Locks::jni_id_lock_);
97
98 void StartDefer() REQUIRES(!Locks::jni_id_lock_) REQUIRES_SHARED(Locks::mutator_lock_);
99 void EndDefer() REQUIRES(!Locks::jni_id_lock_) REQUIRES_SHARED(Locks::mutator_lock_);
100
101 uintptr_t next_method_id_ GUARDED_BY(Locks::jni_id_lock_) = 1u;
102 std::vector<ArtMethod*> method_id_map_ GUARDED_BY(Locks::jni_id_lock_);
103 uintptr_t next_field_id_ GUARDED_BY(Locks::jni_id_lock_) = 1u;
104 std::vector<ArtField*> field_id_map_ GUARDED_BY(Locks::jni_id_lock_);
105
106 // If non-zero indicates that some thread is trying to allocate ids without being able to update
107 // the method->id mapping (due to not being able to allocate or something). In this case decode
108 // and encode need to do a linear scan of the lists. The ScopedEnableSuspendAllJniIdQueries struct
109 // will deal with fixing everything up.
110 size_t deferred_allocation_refcount_ GUARDED_BY(Locks::jni_id_lock_) = 0;
111 // min jmethodID that might not have it's method->id mapping filled in.
112 uintptr_t deferred_allocation_method_id_start_ GUARDED_BY(Locks::jni_id_lock_) = 0u;
113 // min jfieldID that might not have it's field->id mapping filled in.
114 uintptr_t deferred_allocation_field_id_start_ GUARDED_BY(Locks::jni_id_lock_) = 0u;
115
116 friend class ScopedEnableSuspendAllJniIdQueries;
117};
118
119// A scope that will enable using the Encode/Decode JNI id functions with all threads suspended.
120// This is required since normally we need to be able to allocate to encode new ids. This should
121// only be used when absolutely required, for example to invoke user-callbacks during heap walking
122// or similar.
123class ScopedEnableSuspendAllJniIdQueries {
124 public:
125 ScopedEnableSuspendAllJniIdQueries() REQUIRES_SHARED(Locks::mutator_lock_);
126 ~ScopedEnableSuspendAllJniIdQueries() REQUIRES_SHARED(Locks::mutator_lock_);
127
128 private:
129 JniIdManager* manager_;
130};
131
132} // namespace jni
133} // namespace art
134
135#endif // ART_RUNTIME_JNI_JNI_ID_MANAGER_H_