xref: /aosp_15_r20/art/runtime/jni/jni_id_manager.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2019 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #include "jni_id_manager.h"
18*795d594fSAndroid Build Coastguard Worker 
19*795d594fSAndroid Build Coastguard Worker #include <algorithm>
20*795d594fSAndroid Build Coastguard Worker #include <cstdint>
21*795d594fSAndroid Build Coastguard Worker #include <type_traits>
22*795d594fSAndroid Build Coastguard Worker 
23*795d594fSAndroid Build Coastguard Worker #include "android-base/macros.h"
24*795d594fSAndroid Build Coastguard Worker #include "art_field-inl.h"
25*795d594fSAndroid Build Coastguard Worker #include "art_method-inl.h"
26*795d594fSAndroid Build Coastguard Worker #include "base/globals.h"
27*795d594fSAndroid Build Coastguard Worker #include "base/locks.h"
28*795d594fSAndroid Build Coastguard Worker #include "base/mutex.h"
29*795d594fSAndroid Build Coastguard Worker #include "base/pointer_size.h"
30*795d594fSAndroid Build Coastguard Worker #include "class_root-inl.h"
31*795d594fSAndroid Build Coastguard Worker #include "gc/allocation_listener.h"
32*795d594fSAndroid Build Coastguard Worker #include "gc/heap.h"
33*795d594fSAndroid Build Coastguard Worker #include "jni/jni_internal.h"
34*795d594fSAndroid Build Coastguard Worker #include "jni_id_type.h"
35*795d594fSAndroid Build Coastguard Worker #include "mirror/array-inl.h"
36*795d594fSAndroid Build Coastguard Worker #include "mirror/array.h"
37*795d594fSAndroid Build Coastguard Worker #include "mirror/class-alloc-inl.h"
38*795d594fSAndroid Build Coastguard Worker #include "mirror/class-inl.h"
39*795d594fSAndroid Build Coastguard Worker #include "mirror/class.h"
40*795d594fSAndroid Build Coastguard Worker #include "mirror/class_ext-inl.h"
41*795d594fSAndroid Build Coastguard Worker #include "mirror/object-inl.h"
42*795d594fSAndroid Build Coastguard Worker #include "obj_ptr-inl.h"
43*795d594fSAndroid Build Coastguard Worker #include "reflective_handle_scope-inl.h"
44*795d594fSAndroid Build Coastguard Worker #include "reflective_handle_scope.h"
45*795d594fSAndroid Build Coastguard Worker #include "reflective_value_visitor.h"
46*795d594fSAndroid Build Coastguard Worker #include "thread-inl.h"
47*795d594fSAndroid Build Coastguard Worker #include "thread.h"
48*795d594fSAndroid Build Coastguard Worker 
49*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
50*795d594fSAndroid Build Coastguard Worker namespace jni {
51*795d594fSAndroid Build Coastguard Worker 
52*795d594fSAndroid Build Coastguard Worker constexpr bool kTraceIds = false;
53*795d594fSAndroid Build Coastguard Worker 
54*795d594fSAndroid Build Coastguard Worker // TODO This whole thing could be done lock & wait free (since we never remove anything from the
55*795d594fSAndroid Build Coastguard Worker // ids list). It's not clear this would be worthwile though.
56*795d594fSAndroid Build Coastguard Worker 
57*795d594fSAndroid Build Coastguard Worker namespace {
58*795d594fSAndroid Build Coastguard Worker 
IdToIndex(uintptr_t id)59*795d594fSAndroid Build Coastguard Worker static constexpr size_t IdToIndex(uintptr_t id) {
60*795d594fSAndroid Build Coastguard Worker   return id >> 1;
61*795d594fSAndroid Build Coastguard Worker }
62*795d594fSAndroid Build Coastguard Worker 
IndexToId(size_t index)63*795d594fSAndroid Build Coastguard Worker static constexpr uintptr_t IndexToId(size_t index) {
64*795d594fSAndroid Build Coastguard Worker   return (index << 1) + 1;
65*795d594fSAndroid Build Coastguard Worker }
66*795d594fSAndroid Build Coastguard Worker 
CanUseIdArrays(ArtMethod * t)67*795d594fSAndroid Build Coastguard Worker static bool CanUseIdArrays(ArtMethod* t) {
68*795d594fSAndroid Build Coastguard Worker   // We cannot use ID arrays from the ClassExt object for obsolete and default conflict methods. The
69*795d594fSAndroid Build Coastguard Worker   // ID arrays hold an ID corresponding to the methods in the methods_list. Obsolete methods aren't
70*795d594fSAndroid Build Coastguard Worker   // in the method list. For default conflicting methods it is difficult to find the class that
71*795d594fSAndroid Build Coastguard Worker   // contains the copied method, so we omit using ID arrays. For Default conflicting methods we
72*795d594fSAndroid Build Coastguard Worker   // cannot use the canonical method because canonicalizing would return a method from one of the
73*795d594fSAndroid Build Coastguard Worker   // interface classes. If we use that method ID and invoke it via the CallNonVirtual JNI interface,
74*795d594fSAndroid Build Coastguard Worker   // it wouldn't throw the expected ICCE.
75*795d594fSAndroid Build Coastguard Worker   return !(t->IsObsolete() || t->IsDefaultConflicting());
76*795d594fSAndroid Build Coastguard Worker }
77*795d594fSAndroid Build Coastguard Worker 
78*795d594fSAndroid Build Coastguard Worker template <typename ArtType>
GetIds(ObjPtr<mirror::Class> k,ArtType * t)79*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::PointerArray> GetIds(ObjPtr<mirror::Class> k, ArtType* t)
80*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
81*795d594fSAndroid Build Coastguard Worker   ObjPtr<mirror::Object> ret;
82*795d594fSAndroid Build Coastguard Worker   if constexpr (std::is_same_v<ArtType, ArtField>) {
83*795d594fSAndroid Build Coastguard Worker     ret = t->IsStatic() ? k->GetStaticFieldIds() : k->GetInstanceFieldIds();
84*795d594fSAndroid Build Coastguard Worker   } else {
85*795d594fSAndroid Build Coastguard Worker     ret = CanUseIdArrays(t) ? k->GetMethodIds() : nullptr;
86*795d594fSAndroid Build Coastguard Worker   }
87*795d594fSAndroid Build Coastguard Worker   DCHECK(ret.IsNull() || ret->IsArrayInstance()) << "Should have bailed out early!";
88*795d594fSAndroid Build Coastguard Worker   if (kIsDebugBuild && !ret.IsNull()) {
89*795d594fSAndroid Build Coastguard Worker     if (kRuntimePointerSize == PointerSize::k32) {
90*795d594fSAndroid Build Coastguard Worker       CHECK(ret->IsIntArray());
91*795d594fSAndroid Build Coastguard Worker     } else {
92*795d594fSAndroid Build Coastguard Worker       CHECK(ret->IsLongArray());
93*795d594fSAndroid Build Coastguard Worker     }
94*795d594fSAndroid Build Coastguard Worker   }
95*795d594fSAndroid Build Coastguard Worker   return down_cast<mirror::PointerArray*>(ret.Ptr());
96*795d594fSAndroid Build Coastguard Worker }
97*795d594fSAndroid Build Coastguard Worker 
98*795d594fSAndroid Build Coastguard Worker template <typename ArtType>
99*795d594fSAndroid Build Coastguard Worker bool ShouldReturnPointer(ObjPtr<mirror::Class> klass, ArtType* t)
100*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_);
101*795d594fSAndroid Build Coastguard Worker 
102*795d594fSAndroid Build Coastguard Worker template <>
ShouldReturnPointer(ObjPtr<mirror::Class> klass,ArtMethod * t)103*795d594fSAndroid Build Coastguard Worker bool ShouldReturnPointer(ObjPtr<mirror::Class> klass, [[maybe_unused]] ArtMethod* t) {
104*795d594fSAndroid Build Coastguard Worker   ObjPtr<mirror::ClassExt> ext(klass->GetExtData());
105*795d594fSAndroid Build Coastguard Worker   if (ext.IsNull()) {
106*795d594fSAndroid Build Coastguard Worker     return true;
107*795d594fSAndroid Build Coastguard Worker   }
108*795d594fSAndroid Build Coastguard Worker   ObjPtr<mirror::Object> arr = ext->GetJMethodIDs();
109*795d594fSAndroid Build Coastguard Worker   return arr.IsNull() || !arr->IsArrayInstance();
110*795d594fSAndroid Build Coastguard Worker }
111*795d594fSAndroid Build Coastguard Worker 
112*795d594fSAndroid Build Coastguard Worker template<>
ShouldReturnPointer(ObjPtr<mirror::Class> klass,ArtField * t)113*795d594fSAndroid Build Coastguard Worker bool ShouldReturnPointer(ObjPtr<mirror::Class> klass, ArtField* t) {
114*795d594fSAndroid Build Coastguard Worker   ObjPtr<mirror::ClassExt> ext(klass->GetExtData());
115*795d594fSAndroid Build Coastguard Worker   if (ext.IsNull()) {
116*795d594fSAndroid Build Coastguard Worker     return true;
117*795d594fSAndroid Build Coastguard Worker   }
118*795d594fSAndroid Build Coastguard Worker   ObjPtr<mirror::Object> arr = t->IsStatic() ? ext->GetStaticJFieldIDs()
119*795d594fSAndroid Build Coastguard Worker                                              : ext->GetInstanceJFieldIDs();
120*795d594fSAndroid Build Coastguard Worker   return arr.IsNull() || !arr->IsArrayInstance();
121*795d594fSAndroid Build Coastguard Worker }
122*795d594fSAndroid Build Coastguard Worker 
123*795d594fSAndroid Build Coastguard Worker 
124*795d594fSAndroid Build Coastguard Worker // Forces the appropriate id array to be present if possible. Returns true if allocation was
125*795d594fSAndroid Build Coastguard Worker // attempted but failed.
126*795d594fSAndroid Build Coastguard Worker template <typename ArtType>
127*795d594fSAndroid Build Coastguard Worker bool EnsureIdsArray(Thread* self, ObjPtr<mirror::Class> k, ArtType* t)
128*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_);
129*795d594fSAndroid Build Coastguard Worker 
130*795d594fSAndroid Build Coastguard Worker template <>
EnsureIdsArray(Thread * self,ObjPtr<mirror::Class> k,ArtField * field)131*795d594fSAndroid Build Coastguard Worker bool EnsureIdsArray(Thread* self, ObjPtr<mirror::Class> k, ArtField* field) {
132*795d594fSAndroid Build Coastguard Worker   ScopedExceptionStorage ses(self);
133*795d594fSAndroid Build Coastguard Worker   StackHandleScope<1> hs(self);
134*795d594fSAndroid Build Coastguard Worker   Handle<mirror::Class> h_k(hs.NewHandle(k));
135*795d594fSAndroid Build Coastguard Worker   if (Locks::mutator_lock_->IsExclusiveHeld(self)) {
136*795d594fSAndroid Build Coastguard Worker     return false;
137*795d594fSAndroid Build Coastguard Worker   } else {
138*795d594fSAndroid Build Coastguard Worker     // NB This modifies the class to allocate the ClassExt and the ids array.
139*795d594fSAndroid Build Coastguard Worker     field->IsStatic() ? mirror::Class::EnsureStaticFieldIds(h_k)
140*795d594fSAndroid Build Coastguard Worker                       : mirror::Class::EnsureInstanceFieldIds(h_k);
141*795d594fSAndroid Build Coastguard Worker   }
142*795d594fSAndroid Build Coastguard Worker   if (self->IsExceptionPending()) {
143*795d594fSAndroid Build Coastguard Worker     self->AssertPendingOOMException();
144*795d594fSAndroid Build Coastguard Worker     ses.SuppressOldException("Failed to allocate maps for jmethodIDs. ");
145*795d594fSAndroid Build Coastguard Worker     return true;
146*795d594fSAndroid Build Coastguard Worker   }
147*795d594fSAndroid Build Coastguard Worker   return false;
148*795d594fSAndroid Build Coastguard Worker }
149*795d594fSAndroid Build Coastguard Worker 
150*795d594fSAndroid Build Coastguard Worker template <>
EnsureIdsArray(Thread * self,ObjPtr<mirror::Class> k,ArtMethod * method)151*795d594fSAndroid Build Coastguard Worker bool EnsureIdsArray(Thread* self, ObjPtr<mirror::Class> k, ArtMethod* method) {
152*795d594fSAndroid Build Coastguard Worker   if (!CanUseIdArrays(method)) {
153*795d594fSAndroid Build Coastguard Worker     if (kTraceIds) {
154*795d594fSAndroid Build Coastguard Worker       LOG(INFO) << "jmethodID for Obsolete / Default conflicting method " << method->PrettyMethod()
155*795d594fSAndroid Build Coastguard Worker                 << " requested!";
156*795d594fSAndroid Build Coastguard Worker     }
157*795d594fSAndroid Build Coastguard Worker     // No ids array for obsolete / default conflicting methods. Just do a linear scan.
158*795d594fSAndroid Build Coastguard Worker     return false;
159*795d594fSAndroid Build Coastguard Worker   }
160*795d594fSAndroid Build Coastguard Worker   StackHandleScope<1> hs(self);
161*795d594fSAndroid Build Coastguard Worker   Handle<mirror::Class> h_k(hs.NewHandle(k));
162*795d594fSAndroid Build Coastguard Worker   if (Locks::mutator_lock_->IsExclusiveHeld(self) || !Locks::mutator_lock_->IsSharedHeld(self)) {
163*795d594fSAndroid Build Coastguard Worker     return false;
164*795d594fSAndroid Build Coastguard Worker   } else {
165*795d594fSAndroid Build Coastguard Worker     // NB This modifies the class to allocate the ClassExt and the ids array.
166*795d594fSAndroid Build Coastguard Worker     mirror::Class::EnsureMethodIds(h_k);
167*795d594fSAndroid Build Coastguard Worker   }
168*795d594fSAndroid Build Coastguard Worker   if (self->IsExceptionPending()) {
169*795d594fSAndroid Build Coastguard Worker     self->AssertPendingOOMException();
170*795d594fSAndroid Build Coastguard Worker     return true;
171*795d594fSAndroid Build Coastguard Worker   }
172*795d594fSAndroid Build Coastguard Worker   return false;
173*795d594fSAndroid Build Coastguard Worker }
174*795d594fSAndroid Build Coastguard Worker 
175*795d594fSAndroid Build Coastguard Worker template <typename ArtType>
176*795d594fSAndroid Build Coastguard Worker size_t GetIdOffset(ObjPtr<mirror::Class> k, ArtType* t, PointerSize pointer_size)
177*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_);
178*795d594fSAndroid Build Coastguard Worker template <>
GetIdOffset(ObjPtr<mirror::Class> k,ArtField * f,PointerSize ptr_size)179*795d594fSAndroid Build Coastguard Worker size_t GetIdOffset(ObjPtr<mirror::Class> k, ArtField* f, [[maybe_unused]] PointerSize ptr_size) {
180*795d594fSAndroid Build Coastguard Worker   return f->IsStatic() ? k->GetStaticFieldIdOffset(f) : k->GetInstanceFieldIdOffset(f);
181*795d594fSAndroid Build Coastguard Worker }
182*795d594fSAndroid Build Coastguard Worker template <>
GetIdOffset(ObjPtr<mirror::Class> k,ArtMethod * method,PointerSize pointer_size)183*795d594fSAndroid Build Coastguard Worker size_t GetIdOffset(ObjPtr<mirror::Class> k, ArtMethod* method, PointerSize pointer_size) {
184*795d594fSAndroid Build Coastguard Worker   return CanUseIdArrays(method) ? k->GetMethodIdOffset(method, pointer_size) : -1;
185*795d594fSAndroid Build Coastguard Worker }
186*795d594fSAndroid Build Coastguard Worker 
187*795d594fSAndroid Build Coastguard Worker // Calls the relevant PrettyMethod/PrettyField on the input.
188*795d594fSAndroid Build Coastguard Worker template <typename ArtType>
189*795d594fSAndroid Build Coastguard Worker std::string PrettyGeneric(ArtType t) REQUIRES_SHARED(Locks::mutator_lock_);
190*795d594fSAndroid Build Coastguard Worker template <>
PrettyGeneric(ArtMethod * f)191*795d594fSAndroid Build Coastguard Worker std::string PrettyGeneric(ArtMethod* f) {
192*795d594fSAndroid Build Coastguard Worker   return f->PrettyMethod();
193*795d594fSAndroid Build Coastguard Worker }
194*795d594fSAndroid Build Coastguard Worker template <>
PrettyGeneric(ReflectiveHandle<ArtMethod> f)195*795d594fSAndroid Build Coastguard Worker std::string PrettyGeneric(ReflectiveHandle<ArtMethod> f) {
196*795d594fSAndroid Build Coastguard Worker   return f->PrettyMethod();
197*795d594fSAndroid Build Coastguard Worker }
198*795d594fSAndroid Build Coastguard Worker template <>
PrettyGeneric(ArtField * f)199*795d594fSAndroid Build Coastguard Worker std::string PrettyGeneric(ArtField* f) {
200*795d594fSAndroid Build Coastguard Worker   return f->PrettyField();
201*795d594fSAndroid Build Coastguard Worker }
202*795d594fSAndroid Build Coastguard Worker template <>
PrettyGeneric(ReflectiveHandle<ArtField> f)203*795d594fSAndroid Build Coastguard Worker std::string PrettyGeneric(ReflectiveHandle<ArtField> f) {
204*795d594fSAndroid Build Coastguard Worker   return f->PrettyField();
205*795d594fSAndroid Build Coastguard Worker }
206*795d594fSAndroid Build Coastguard Worker 
207*795d594fSAndroid Build Coastguard Worker // Checks if the field or method can use the ID array from class extension.
208*795d594fSAndroid Build Coastguard Worker template <typename ArtType>
209*795d594fSAndroid Build Coastguard Worker bool CanUseIdArrays(ReflectiveHandle<ArtType> t) REQUIRES_SHARED(Locks::mutator_lock_);
210*795d594fSAndroid Build Coastguard Worker template <>
CanUseIdArrays(ReflectiveHandle<ArtField> t)211*795d594fSAndroid Build Coastguard Worker bool CanUseIdArrays([[maybe_unused]] ReflectiveHandle<ArtField> t) {
212*795d594fSAndroid Build Coastguard Worker   return true;
213*795d594fSAndroid Build Coastguard Worker }
214*795d594fSAndroid Build Coastguard Worker template <>
CanUseIdArrays(ReflectiveHandle<ArtMethod> t)215*795d594fSAndroid Build Coastguard Worker bool CanUseIdArrays(ReflectiveHandle<ArtMethod> t) {
216*795d594fSAndroid Build Coastguard Worker   return CanUseIdArrays(t.Get());
217*795d594fSAndroid Build Coastguard Worker }
218*795d594fSAndroid Build Coastguard Worker 
219*795d594fSAndroid Build Coastguard Worker // Get the canonical (non-copied) version of the field or method. Only relevant for methods.
220*795d594fSAndroid Build Coastguard Worker template <typename ArtType>
221*795d594fSAndroid Build Coastguard Worker ArtType* Canonicalize(ReflectiveHandle<ArtType> t) REQUIRES_SHARED(Locks::mutator_lock_);
222*795d594fSAndroid Build Coastguard Worker template <>
Canonicalize(ReflectiveHandle<ArtField> t)223*795d594fSAndroid Build Coastguard Worker ArtField* Canonicalize(ReflectiveHandle<ArtField> t) {
224*795d594fSAndroid Build Coastguard Worker   return t.Get();
225*795d594fSAndroid Build Coastguard Worker }
226*795d594fSAndroid Build Coastguard Worker template <>
Canonicalize(ReflectiveHandle<ArtMethod> t)227*795d594fSAndroid Build Coastguard Worker ArtMethod* Canonicalize(ReflectiveHandle<ArtMethod> t) {
228*795d594fSAndroid Build Coastguard Worker   if (UNLIKELY(t->IsCopied())) {
229*795d594fSAndroid Build Coastguard Worker     return t->GetCanonicalMethod();
230*795d594fSAndroid Build Coastguard Worker   }
231*795d594fSAndroid Build Coastguard Worker   return t.Get();
232*795d594fSAndroid Build Coastguard Worker }
233*795d594fSAndroid Build Coastguard Worker 
234*795d594fSAndroid Build Coastguard Worker };  // namespace
235*795d594fSAndroid Build Coastguard Worker 
236*795d594fSAndroid Build Coastguard Worker // We increment the id by 2 each time to allow us to use the LSB as a flag that the ID is an index
237*795d594fSAndroid Build Coastguard Worker // and not a pointer. This gives us 2**31 unique methods that can be addressed on 32-bit art, which
238*795d594fSAndroid Build Coastguard Worker // should be more than enough.
239*795d594fSAndroid Build Coastguard Worker template <>
GetNextId(JniIdType type)240*795d594fSAndroid Build Coastguard Worker uintptr_t JniIdManager::GetNextId<ArtField>(JniIdType type) {
241*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(type, JniIdType::kIndices);
242*795d594fSAndroid Build Coastguard Worker   uintptr_t res = next_field_id_;
243*795d594fSAndroid Build Coastguard Worker   next_field_id_ += 2;
244*795d594fSAndroid Build Coastguard Worker   CHECK_GT(next_field_id_, res) << "jfieldID Overflow";
245*795d594fSAndroid Build Coastguard Worker   return res;
246*795d594fSAndroid Build Coastguard Worker }
247*795d594fSAndroid Build Coastguard Worker 
248*795d594fSAndroid Build Coastguard Worker template <>
GetNextId(JniIdType type)249*795d594fSAndroid Build Coastguard Worker uintptr_t JniIdManager::GetNextId<ArtMethod>(JniIdType type) {
250*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(type, JniIdType::kIndices);
251*795d594fSAndroid Build Coastguard Worker   uintptr_t res = next_method_id_;
252*795d594fSAndroid Build Coastguard Worker   next_method_id_ += 2;
253*795d594fSAndroid Build Coastguard Worker   CHECK_GT(next_method_id_, res) << "jmethodID Overflow";
254*795d594fSAndroid Build Coastguard Worker   return res;
255*795d594fSAndroid Build Coastguard Worker }
256*795d594fSAndroid Build Coastguard Worker template <>
GetGenericMap()257*795d594fSAndroid Build Coastguard Worker std::vector<ArtField*>& JniIdManager::GetGenericMap<ArtField>() {
258*795d594fSAndroid Build Coastguard Worker   return field_id_map_;
259*795d594fSAndroid Build Coastguard Worker }
260*795d594fSAndroid Build Coastguard Worker 
261*795d594fSAndroid Build Coastguard Worker template <>
GetGenericMap()262*795d594fSAndroid Build Coastguard Worker std::vector<ArtMethod*>& JniIdManager::GetGenericMap<ArtMethod>() {
263*795d594fSAndroid Build Coastguard Worker   return method_id_map_;
264*795d594fSAndroid Build Coastguard Worker }
265*795d594fSAndroid Build Coastguard Worker template <>
GetLinearSearchStartId(ReflectiveHandle<ArtField> t)266*795d594fSAndroid Build Coastguard Worker size_t JniIdManager::GetLinearSearchStartId<ArtField>(
267*795d594fSAndroid Build Coastguard Worker     [[maybe_unused]] ReflectiveHandle<ArtField> t) {
268*795d594fSAndroid Build Coastguard Worker   return deferred_allocation_field_id_start_;
269*795d594fSAndroid Build Coastguard Worker }
270*795d594fSAndroid Build Coastguard Worker 
271*795d594fSAndroid Build Coastguard Worker template <>
GetLinearSearchStartId(ReflectiveHandle<ArtMethod> m)272*795d594fSAndroid Build Coastguard Worker size_t JniIdManager::GetLinearSearchStartId<ArtMethod>(ReflectiveHandle<ArtMethod> m) {
273*795d594fSAndroid Build Coastguard Worker   if (CanUseIdArrays(m)) {
274*795d594fSAndroid Build Coastguard Worker     // If we are searching because we couldn't allocate because of defer allocate scope, then we
275*795d594fSAndroid Build Coastguard Worker     // should only look from deferred_allocation_method_id_start_. Once we exit the deferred scope
276*795d594fSAndroid Build Coastguard Worker     // all these method ids will be updated to the id arrays in the respective ClassExt objects.
277*795d594fSAndroid Build Coastguard Worker     return deferred_allocation_method_id_start_;
278*795d594fSAndroid Build Coastguard Worker   } else {
279*795d594fSAndroid Build Coastguard Worker     // If we cannot use ID arrays, then the method can be anywhere in the list.
280*795d594fSAndroid Build Coastguard Worker     return 1;
281*795d594fSAndroid Build Coastguard Worker   }
282*795d594fSAndroid Build Coastguard Worker }
283*795d594fSAndroid Build Coastguard Worker 
284*795d594fSAndroid Build Coastguard Worker // TODO need to fix races in here with visitors
285*795d594fSAndroid Build Coastguard Worker template <typename ArtType>
EncodeGenericId(ReflectiveHandle<ArtType> t)286*795d594fSAndroid Build Coastguard Worker uintptr_t JniIdManager::EncodeGenericId(ReflectiveHandle<ArtType> t) {
287*795d594fSAndroid Build Coastguard Worker   static_assert(std::is_same_v<ArtType, ArtField> || std::is_same_v<ArtType, ArtMethod>,
288*795d594fSAndroid Build Coastguard Worker                 "Expected ArtField or ArtMethod");
289*795d594fSAndroid Build Coastguard Worker   Runtime* runtime = Runtime::Current();
290*795d594fSAndroid Build Coastguard Worker   JniIdType id_type = runtime->GetJniIdType();
291*795d594fSAndroid Build Coastguard Worker   if (id_type == JniIdType::kPointer || t == nullptr) {
292*795d594fSAndroid Build Coastguard Worker     return reinterpret_cast<uintptr_t>(t.Get());
293*795d594fSAndroid Build Coastguard Worker   }
294*795d594fSAndroid Build Coastguard Worker   Thread* self = Thread::Current();
295*795d594fSAndroid Build Coastguard Worker   ScopedExceptionStorage ses(self);
296*795d594fSAndroid Build Coastguard Worker   DCHECK(!t->GetDeclaringClass().IsNull()) << "Null declaring class " << PrettyGeneric(t);
297*795d594fSAndroid Build Coastguard Worker   size_t off = -1;
298*795d594fSAndroid Build Coastguard Worker   bool allocation_failure = false;
299*795d594fSAndroid Build Coastguard Worker   // When we cannot use ID arrays, we just fallback to looking through the list to obtain the ID.
300*795d594fSAndroid Build Coastguard Worker   // These are rare cases so shouldn't be a problem for performance. See CanUseIdArrays for more
301*795d594fSAndroid Build Coastguard Worker   // information.
302*795d594fSAndroid Build Coastguard Worker   if (CanUseIdArrays(t)) {
303*795d594fSAndroid Build Coastguard Worker     off = GetIdOffset(t->GetDeclaringClass(), Canonicalize(t), kRuntimePointerSize);
304*795d594fSAndroid Build Coastguard Worker     // Here is the earliest point we can suspend.
305*795d594fSAndroid Build Coastguard Worker     allocation_failure = EnsureIdsArray(self, t->GetDeclaringClass(), t.Get());
306*795d594fSAndroid Build Coastguard Worker   }
307*795d594fSAndroid Build Coastguard Worker   if (allocation_failure) {
308*795d594fSAndroid Build Coastguard Worker     self->AssertPendingOOMException();
309*795d594fSAndroid Build Coastguard Worker     ses.SuppressOldException("OOM exception while trying to allocate JNI ids.");
310*795d594fSAndroid Build Coastguard Worker     return 0u;
311*795d594fSAndroid Build Coastguard Worker   } else if (ShouldReturnPointer(t->GetDeclaringClass(), t.Get())) {
312*795d594fSAndroid Build Coastguard Worker     // TODO(mythria): Check why we return a pointer here instead of falling back
313*795d594fSAndroid Build Coastguard Worker     // to the slow path of finding the ID by looping through the ID -> method
314*795d594fSAndroid Build Coastguard Worker     // map. This seem incorrect. For example, if we are in ScopedEnableSuspendAllJniIdQueries
315*795d594fSAndroid Build Coastguard Worker     // scope, we don't allocate ID arrays. We would then incorrectly return a
316*795d594fSAndroid Build Coastguard Worker     // pointer here.
317*795d594fSAndroid Build Coastguard Worker     return reinterpret_cast<uintptr_t>(t.Get());
318*795d594fSAndroid Build Coastguard Worker   }
319*795d594fSAndroid Build Coastguard Worker   ObjPtr<mirror::Class> klass = t->GetDeclaringClass();
320*795d594fSAndroid Build Coastguard Worker   ObjPtr<mirror::PointerArray> ids(GetIds(klass, t.Get()));
321*795d594fSAndroid Build Coastguard Worker   uintptr_t cur_id = 0;
322*795d594fSAndroid Build Coastguard Worker   if (!ids.IsNull()) {
323*795d594fSAndroid Build Coastguard Worker     DCHECK_GT(ids->GetLength(), static_cast<int32_t>(off)) << " is " << PrettyGeneric(t);
324*795d594fSAndroid Build Coastguard Worker     DCHECK_LE(0, static_cast<int32_t>(off)) << " is " << PrettyGeneric(t);
325*795d594fSAndroid Build Coastguard Worker     cur_id = ids->GetElementPtrSize<uintptr_t>(off, kRuntimePointerSize);
326*795d594fSAndroid Build Coastguard Worker   }
327*795d594fSAndroid Build Coastguard Worker   if (cur_id != 0) {
328*795d594fSAndroid Build Coastguard Worker     return cur_id;
329*795d594fSAndroid Build Coastguard Worker   }
330*795d594fSAndroid Build Coastguard Worker   WriterMutexLock mu(self, *Locks::jni_id_lock_);
331*795d594fSAndroid Build Coastguard Worker   ScopedAssertNoThreadSuspension sants("EncodeJniId critical section.");
332*795d594fSAndroid Build Coastguard Worker   // Check the ids array for a racing id.
333*795d594fSAndroid Build Coastguard Worker   constexpr std::pair<size_t, size_t> counts {
334*795d594fSAndroid Build Coastguard Worker     std::is_same_v<ArtType, ArtField> ? 1 : 0,
335*795d594fSAndroid Build Coastguard Worker     std::is_same_v<ArtType, ArtField> ? 0 : 1,
336*795d594fSAndroid Build Coastguard Worker   };
337*795d594fSAndroid Build Coastguard Worker   StackReflectiveHandleScope<counts.first, counts.second> hs(self);
338*795d594fSAndroid Build Coastguard Worker   t = hs.NewHandle(Canonicalize(t));
339*795d594fSAndroid Build Coastguard Worker   if (!ids.IsNull()) {
340*795d594fSAndroid Build Coastguard Worker     // It's possible we got suspended and structurally redefined during the EnsureIdsArray. We need
341*795d594fSAndroid Build Coastguard Worker     // to get the information again.
342*795d594fSAndroid Build Coastguard Worker     ids = GetIds(klass, t.Get());
343*795d594fSAndroid Build Coastguard Worker     off = GetIdOffset(klass, Canonicalize(t), kRuntimePointerSize);
344*795d594fSAndroid Build Coastguard Worker     CHECK(!ids.IsNull());
345*795d594fSAndroid Build Coastguard Worker     cur_id = ids->GetElementPtrSize<uintptr_t>(off, kRuntimePointerSize);
346*795d594fSAndroid Build Coastguard Worker     if (cur_id != 0) {
347*795d594fSAndroid Build Coastguard Worker       // We were racing some other thread and lost.
348*795d594fSAndroid Build Coastguard Worker       return cur_id;
349*795d594fSAndroid Build Coastguard Worker     }
350*795d594fSAndroid Build Coastguard Worker   } else {
351*795d594fSAndroid Build Coastguard Worker     // We cannot allocate anything here or don't have an ids array (we might be an obsolete method).
352*795d594fSAndroid Build Coastguard Worker     DCHECK(!CanUseIdArrays(t) || deferred_allocation_refcount_ > 0u)
353*795d594fSAndroid Build Coastguard Worker         << "deferred_allocation_refcount_: " << deferred_allocation_refcount_
354*795d594fSAndroid Build Coastguard Worker         << " t: " << PrettyGeneric(t);
355*795d594fSAndroid Build Coastguard Worker     // Check to see if we raced and lost to another thread.
356*795d594fSAndroid Build Coastguard Worker     const std::vector<ArtType*>& vec = GetGenericMap<ArtType>();
357*795d594fSAndroid Build Coastguard Worker     bool found = false;
358*795d594fSAndroid Build Coastguard Worker     // simple count-while.
359*795d594fSAndroid Build Coastguard Worker     size_t search_start_index = IdToIndex(GetLinearSearchStartId(t));
360*795d594fSAndroid Build Coastguard Worker     size_t index = std::count_if(vec.cbegin() + search_start_index,
361*795d594fSAndroid Build Coastguard Worker                                  vec.cend(),
362*795d594fSAndroid Build Coastguard Worker                                  [&found, &self, t](const ArtType* candidate) {
363*795d594fSAndroid Build Coastguard Worker                                    Locks::mutator_lock_->AssertSharedHeld(self);
364*795d594fSAndroid Build Coastguard Worker                                    found = found || candidate == t.Get();
365*795d594fSAndroid Build Coastguard Worker                                    return !found;
366*795d594fSAndroid Build Coastguard Worker                                  }) +
367*795d594fSAndroid Build Coastguard Worker                    search_start_index;
368*795d594fSAndroid Build Coastguard Worker     if (found) {
369*795d594fSAndroid Build Coastguard Worker       // We were either racing some other thread and lost or this thread was asked to encode the
370*795d594fSAndroid Build Coastguard Worker       // same method multiple times while holding the mutator lock.
371*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(vec[index], t.Get())
372*795d594fSAndroid Build Coastguard Worker           << "Expected: " << PrettyGeneric(vec[index]) << " got " << PrettyGeneric(t)
373*795d594fSAndroid Build Coastguard Worker           << " at index " << index << " (id: " << IndexToId(index) << ").";
374*795d594fSAndroid Build Coastguard Worker       return IndexToId(index);
375*795d594fSAndroid Build Coastguard Worker     }
376*795d594fSAndroid Build Coastguard Worker   }
377*795d594fSAndroid Build Coastguard Worker   cur_id = GetNextId<ArtType>(id_type);
378*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(cur_id % 2, 1u);
379*795d594fSAndroid Build Coastguard Worker   size_t cur_index = IdToIndex(cur_id);
380*795d594fSAndroid Build Coastguard Worker   std::vector<ArtType*>& vec = GetGenericMap<ArtType>();
381*795d594fSAndroid Build Coastguard Worker   vec.reserve(cur_index + 1);
382*795d594fSAndroid Build Coastguard Worker   vec.resize(std::max(vec.size(), cur_index + 1), nullptr);
383*795d594fSAndroid Build Coastguard Worker   vec[cur_index] = t.Get();
384*795d594fSAndroid Build Coastguard Worker   if (ids.IsNull()) {
385*795d594fSAndroid Build Coastguard Worker     if (kIsDebugBuild && CanUseIdArrays(t)) {
386*795d594fSAndroid Build Coastguard Worker       CHECK_NE(deferred_allocation_refcount_, 0u)
387*795d594fSAndroid Build Coastguard Worker           << "Failed to allocate ids array despite not being forbidden from doing so!";
388*795d594fSAndroid Build Coastguard Worker       Locks::mutator_lock_->AssertExclusiveHeld(self);
389*795d594fSAndroid Build Coastguard Worker     }
390*795d594fSAndroid Build Coastguard Worker   } else {
391*795d594fSAndroid Build Coastguard Worker     ids->SetElementPtrSize(off, reinterpret_cast<void*>(cur_id), kRuntimePointerSize);
392*795d594fSAndroid Build Coastguard Worker   }
393*795d594fSAndroid Build Coastguard Worker   return cur_id;
394*795d594fSAndroid Build Coastguard Worker }
395*795d594fSAndroid Build Coastguard Worker 
EncodeFieldId(ArtField * field)396*795d594fSAndroid Build Coastguard Worker jfieldID JniIdManager::EncodeFieldId(ArtField* field) {
397*795d594fSAndroid Build Coastguard Worker   StackArtFieldHandleScope<1> rhs(Thread::Current());
398*795d594fSAndroid Build Coastguard Worker   return EncodeFieldId(rhs.NewHandle(field));
399*795d594fSAndroid Build Coastguard Worker }
400*795d594fSAndroid Build Coastguard Worker 
EncodeFieldId(ReflectiveHandle<ArtField> field)401*795d594fSAndroid Build Coastguard Worker jfieldID JniIdManager::EncodeFieldId(ReflectiveHandle<ArtField> field) {
402*795d594fSAndroid Build Coastguard Worker   auto* res = reinterpret_cast<jfieldID>(EncodeGenericId(field));
403*795d594fSAndroid Build Coastguard Worker   if (kTraceIds && field != nullptr) {
404*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << "Returning " << res << " for field " << field->PrettyField();
405*795d594fSAndroid Build Coastguard Worker   }
406*795d594fSAndroid Build Coastguard Worker   return res;
407*795d594fSAndroid Build Coastguard Worker }
408*795d594fSAndroid Build Coastguard Worker 
EncodeMethodId(ArtMethod * method)409*795d594fSAndroid Build Coastguard Worker jmethodID JniIdManager::EncodeMethodId(ArtMethod* method) {
410*795d594fSAndroid Build Coastguard Worker   StackArtMethodHandleScope<1> rhs(Thread::Current());
411*795d594fSAndroid Build Coastguard Worker   return EncodeMethodId(rhs.NewHandle(method));
412*795d594fSAndroid Build Coastguard Worker }
413*795d594fSAndroid Build Coastguard Worker 
EncodeMethodId(ReflectiveHandle<ArtMethod> method)414*795d594fSAndroid Build Coastguard Worker jmethodID JniIdManager::EncodeMethodId(ReflectiveHandle<ArtMethod> method) {
415*795d594fSAndroid Build Coastguard Worker   auto* res = reinterpret_cast<jmethodID>(EncodeGenericId(method));
416*795d594fSAndroid Build Coastguard Worker   if (kTraceIds && method != nullptr) {
417*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << "Returning " << res << " for method " << method->PrettyMethod();
418*795d594fSAndroid Build Coastguard Worker   }
419*795d594fSAndroid Build Coastguard Worker   return res;
420*795d594fSAndroid Build Coastguard Worker }
421*795d594fSAndroid Build Coastguard Worker 
VisitRoots(RootVisitor * visitor)422*795d594fSAndroid Build Coastguard Worker void JniIdManager::VisitRoots(RootVisitor *visitor) {
423*795d594fSAndroid Build Coastguard Worker   pointer_marker_.VisitRootIfNonNull(visitor, RootInfo(kRootVMInternal));
424*795d594fSAndroid Build Coastguard Worker }
425*795d594fSAndroid Build Coastguard Worker 
Init(Thread * self)426*795d594fSAndroid Build Coastguard Worker void JniIdManager::Init(Thread* self) {
427*795d594fSAndroid Build Coastguard Worker   // When compiling we don't want to have anything to do with any of this, which is fine since JNI
428*795d594fSAndroid Build Coastguard Worker   // ids won't be created during AOT compilation. This also means we don't need to do any
429*795d594fSAndroid Build Coastguard Worker   // complicated stuff with the image-writer.
430*795d594fSAndroid Build Coastguard Worker   if (!Runtime::Current()->IsAotCompiler()) {
431*795d594fSAndroid Build Coastguard Worker     // Allocate the marker
432*795d594fSAndroid Build Coastguard Worker     StackHandleScope<3> hs(self);
433*795d594fSAndroid Build Coastguard Worker     Handle<mirror::Object> marker_obj(
434*795d594fSAndroid Build Coastguard Worker         hs.NewHandle(GetClassRoot<mirror::Object>()->AllocObject(self)));
435*795d594fSAndroid Build Coastguard Worker     CHECK(!marker_obj.IsNull());
436*795d594fSAndroid Build Coastguard Worker     pointer_marker_ = GcRoot<mirror::Object>(marker_obj.Get());
437*795d594fSAndroid Build Coastguard Worker     // Manually mark class-ext as having all pointer-ids to avoid any annoying loops.
438*795d594fSAndroid Build Coastguard Worker     Handle<mirror::Class> class_ext_class(hs.NewHandle(GetClassRoot<mirror::ClassExt>()));
439*795d594fSAndroid Build Coastguard Worker     mirror::Class::EnsureExtDataPresent(class_ext_class, self);
440*795d594fSAndroid Build Coastguard Worker     Handle<mirror::ClassExt> class_ext_ext(hs.NewHandle(class_ext_class->GetExtData()));
441*795d594fSAndroid Build Coastguard Worker     class_ext_ext->SetIdsArraysForClassExtExtData(marker_obj.Get());
442*795d594fSAndroid Build Coastguard Worker   }
443*795d594fSAndroid Build Coastguard Worker }
444*795d594fSAndroid Build Coastguard Worker 
VisitReflectiveTargets(ReflectiveValueVisitor * rvv)445*795d594fSAndroid Build Coastguard Worker void JniIdManager::VisitReflectiveTargets(ReflectiveValueVisitor* rvv) {
446*795d594fSAndroid Build Coastguard Worker   art::WriterMutexLock mu(Thread::Current(), *Locks::jni_id_lock_);
447*795d594fSAndroid Build Coastguard Worker   for (auto it = field_id_map_.begin(); it != field_id_map_.end(); ++it) {
448*795d594fSAndroid Build Coastguard Worker     ArtField* old_field = *it;
449*795d594fSAndroid Build Coastguard Worker     uintptr_t id = IndexToId(std::distance(field_id_map_.begin(), it));
450*795d594fSAndroid Build Coastguard Worker     ArtField* new_field =
451*795d594fSAndroid Build Coastguard Worker         rvv->VisitField(old_field, JniIdReflectiveSourceInfo(reinterpret_cast<jfieldID>(id)));
452*795d594fSAndroid Build Coastguard Worker     if (old_field != new_field) {
453*795d594fSAndroid Build Coastguard Worker       *it = new_field;
454*795d594fSAndroid Build Coastguard Worker       ObjPtr<mirror::Class> old_class(old_field->GetDeclaringClass());
455*795d594fSAndroid Build Coastguard Worker       ObjPtr<mirror::Class> new_class(new_field->GetDeclaringClass());
456*795d594fSAndroid Build Coastguard Worker       ObjPtr<mirror::ClassExt> old_ext_data(old_class->GetExtData());
457*795d594fSAndroid Build Coastguard Worker       ObjPtr<mirror::ClassExt> new_ext_data(new_class->GetExtData());
458*795d594fSAndroid Build Coastguard Worker       if (!old_ext_data.IsNull()) {
459*795d594fSAndroid Build Coastguard Worker         CHECK(!old_ext_data->HasInstanceFieldPointerIdMarker() &&
460*795d594fSAndroid Build Coastguard Worker               !old_ext_data->HasStaticFieldPointerIdMarker())
461*795d594fSAndroid Build Coastguard Worker             << old_class->PrettyClass();
462*795d594fSAndroid Build Coastguard Worker         // Clear the old field mapping.
463*795d594fSAndroid Build Coastguard Worker         if (old_field->IsStatic()) {
464*795d594fSAndroid Build Coastguard Worker           size_t old_off = ArraySlice<ArtField>(old_class->GetSFieldsPtr()).OffsetOf(old_field);
465*795d594fSAndroid Build Coastguard Worker           ObjPtr<mirror::PointerArray> old_statics(old_ext_data->GetStaticJFieldIDsPointerArray());
466*795d594fSAndroid Build Coastguard Worker           if (!old_statics.IsNull()) {
467*795d594fSAndroid Build Coastguard Worker             old_statics->SetElementPtrSize(old_off, 0, kRuntimePointerSize);
468*795d594fSAndroid Build Coastguard Worker           }
469*795d594fSAndroid Build Coastguard Worker         } else {
470*795d594fSAndroid Build Coastguard Worker           size_t old_off = ArraySlice<ArtField>(old_class->GetIFieldsPtr()).OffsetOf(old_field);
471*795d594fSAndroid Build Coastguard Worker           ObjPtr<mirror::PointerArray> old_instances(
472*795d594fSAndroid Build Coastguard Worker               old_ext_data->GetInstanceJFieldIDsPointerArray());
473*795d594fSAndroid Build Coastguard Worker           if (!old_instances.IsNull()) {
474*795d594fSAndroid Build Coastguard Worker             old_instances->SetElementPtrSize(old_off, 0, kRuntimePointerSize);
475*795d594fSAndroid Build Coastguard Worker           }
476*795d594fSAndroid Build Coastguard Worker         }
477*795d594fSAndroid Build Coastguard Worker       }
478*795d594fSAndroid Build Coastguard Worker       if (!new_ext_data.IsNull()) {
479*795d594fSAndroid Build Coastguard Worker         CHECK(!new_ext_data->HasInstanceFieldPointerIdMarker() &&
480*795d594fSAndroid Build Coastguard Worker               !new_ext_data->HasStaticFieldPointerIdMarker())
481*795d594fSAndroid Build Coastguard Worker             << new_class->PrettyClass();
482*795d594fSAndroid Build Coastguard Worker         // Set the new field mapping.
483*795d594fSAndroid Build Coastguard Worker         if (new_field->IsStatic()) {
484*795d594fSAndroid Build Coastguard Worker           size_t new_off = ArraySlice<ArtField>(new_class->GetSFieldsPtr()).OffsetOf(new_field);
485*795d594fSAndroid Build Coastguard Worker           ObjPtr<mirror::PointerArray> new_statics(new_ext_data->GetStaticJFieldIDsPointerArray());
486*795d594fSAndroid Build Coastguard Worker           if (!new_statics.IsNull()) {
487*795d594fSAndroid Build Coastguard Worker             new_statics->SetElementPtrSize(new_off, id, kRuntimePointerSize);
488*795d594fSAndroid Build Coastguard Worker           }
489*795d594fSAndroid Build Coastguard Worker         } else {
490*795d594fSAndroid Build Coastguard Worker           size_t new_off = ArraySlice<ArtField>(new_class->GetIFieldsPtr()).OffsetOf(new_field);
491*795d594fSAndroid Build Coastguard Worker           ObjPtr<mirror::PointerArray> new_instances(
492*795d594fSAndroid Build Coastguard Worker               new_ext_data->GetInstanceJFieldIDsPointerArray());
493*795d594fSAndroid Build Coastguard Worker           if (!new_instances.IsNull()) {
494*795d594fSAndroid Build Coastguard Worker             new_instances->SetElementPtrSize(new_off, id, kRuntimePointerSize);
495*795d594fSAndroid Build Coastguard Worker           }
496*795d594fSAndroid Build Coastguard Worker         }
497*795d594fSAndroid Build Coastguard Worker       }
498*795d594fSAndroid Build Coastguard Worker     }
499*795d594fSAndroid Build Coastguard Worker   }
500*795d594fSAndroid Build Coastguard Worker   for (auto it = method_id_map_.begin(); it != method_id_map_.end(); ++it) {
501*795d594fSAndroid Build Coastguard Worker     ArtMethod* old_method = *it;
502*795d594fSAndroid Build Coastguard Worker     uintptr_t id = IndexToId(std::distance(method_id_map_.begin(), it));
503*795d594fSAndroid Build Coastguard Worker     ArtMethod* new_method =
504*795d594fSAndroid Build Coastguard Worker         rvv->VisitMethod(old_method, JniIdReflectiveSourceInfo(reinterpret_cast<jmethodID>(id)));
505*795d594fSAndroid Build Coastguard Worker     if (old_method != new_method) {
506*795d594fSAndroid Build Coastguard Worker       *it = new_method;
507*795d594fSAndroid Build Coastguard Worker       ObjPtr<mirror::Class> old_class(old_method->GetDeclaringClass());
508*795d594fSAndroid Build Coastguard Worker       ObjPtr<mirror::Class> new_class(new_method->GetDeclaringClass());
509*795d594fSAndroid Build Coastguard Worker       ObjPtr<mirror::ClassExt> old_ext_data(old_class->GetExtData());
510*795d594fSAndroid Build Coastguard Worker       ObjPtr<mirror::ClassExt> new_ext_data(new_class->GetExtData());
511*795d594fSAndroid Build Coastguard Worker       if (!old_ext_data.IsNull()) {
512*795d594fSAndroid Build Coastguard Worker         CHECK(!old_ext_data->HasMethodPointerIdMarker()) << old_class->PrettyClass();
513*795d594fSAndroid Build Coastguard Worker         // Clear the old method mapping.
514*795d594fSAndroid Build Coastguard Worker         size_t old_off = ArraySlice<ArtMethod>(old_class->GetMethodsPtr()).OffsetOf(old_method);
515*795d594fSAndroid Build Coastguard Worker         ObjPtr<mirror::PointerArray> old_methods(old_ext_data->GetJMethodIDsPointerArray());
516*795d594fSAndroid Build Coastguard Worker         if (!old_methods.IsNull()) {
517*795d594fSAndroid Build Coastguard Worker           old_methods->SetElementPtrSize(old_off, 0, kRuntimePointerSize);
518*795d594fSAndroid Build Coastguard Worker         }
519*795d594fSAndroid Build Coastguard Worker       }
520*795d594fSAndroid Build Coastguard Worker       if (!new_ext_data.IsNull()) {
521*795d594fSAndroid Build Coastguard Worker         CHECK(!new_ext_data->HasMethodPointerIdMarker()) << new_class->PrettyClass();
522*795d594fSAndroid Build Coastguard Worker         // Set the new method mapping.
523*795d594fSAndroid Build Coastguard Worker         size_t new_off = ArraySlice<ArtMethod>(new_class->GetMethodsPtr()).OffsetOf(new_method);
524*795d594fSAndroid Build Coastguard Worker         ObjPtr<mirror::PointerArray> new_methods(new_ext_data->GetJMethodIDsPointerArray());
525*795d594fSAndroid Build Coastguard Worker         if (!new_methods.IsNull()) {
526*795d594fSAndroid Build Coastguard Worker           new_methods->SetElementPtrSize(new_off, id, kRuntimePointerSize);
527*795d594fSAndroid Build Coastguard Worker         }
528*795d594fSAndroid Build Coastguard Worker       }
529*795d594fSAndroid Build Coastguard Worker     }
530*795d594fSAndroid Build Coastguard Worker   }
531*795d594fSAndroid Build Coastguard Worker }
532*795d594fSAndroid Build Coastguard Worker 
DecodeGenericId(uintptr_t t)533*795d594fSAndroid Build Coastguard Worker template <typename ArtType> ArtType* JniIdManager::DecodeGenericId(uintptr_t t) {
534*795d594fSAndroid Build Coastguard Worker   if (Runtime::Current()->GetJniIdType() == JniIdType::kIndices && (t % 2) == 1) {
535*795d594fSAndroid Build Coastguard Worker     ReaderMutexLock mu(Thread::Current(), *Locks::jni_id_lock_);
536*795d594fSAndroid Build Coastguard Worker     size_t index = IdToIndex(t);
537*795d594fSAndroid Build Coastguard Worker     DCHECK_GT(GetGenericMap<ArtType>().size(), index);
538*795d594fSAndroid Build Coastguard Worker     return GetGenericMap<ArtType>().at(index);
539*795d594fSAndroid Build Coastguard Worker   } else {
540*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ((t % 2), 0u) << "id: " << t;
541*795d594fSAndroid Build Coastguard Worker     return reinterpret_cast<ArtType*>(t);
542*795d594fSAndroid Build Coastguard Worker   }
543*795d594fSAndroid Build Coastguard Worker }
544*795d594fSAndroid Build Coastguard Worker 
DecodeMethodId(jmethodID method)545*795d594fSAndroid Build Coastguard Worker ArtMethod* JniIdManager::DecodeMethodId(jmethodID method) {
546*795d594fSAndroid Build Coastguard Worker   return DecodeGenericId<ArtMethod>(reinterpret_cast<uintptr_t>(method));
547*795d594fSAndroid Build Coastguard Worker }
548*795d594fSAndroid Build Coastguard Worker 
DecodeFieldId(jfieldID field)549*795d594fSAndroid Build Coastguard Worker ArtField* JniIdManager::DecodeFieldId(jfieldID field) {
550*795d594fSAndroid Build Coastguard Worker   return DecodeGenericId<ArtField>(reinterpret_cast<uintptr_t>(field));
551*795d594fSAndroid Build Coastguard Worker }
552*795d594fSAndroid Build Coastguard Worker 
GetPointerMarker()553*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Object> JniIdManager::GetPointerMarker() {
554*795d594fSAndroid Build Coastguard Worker   return pointer_marker_.Read();
555*795d594fSAndroid Build Coastguard Worker }
556*795d594fSAndroid Build Coastguard Worker 
557*795d594fSAndroid Build Coastguard Worker // This whole defer system is an annoying requirement to allow us to generate IDs during heap-walks
558*795d594fSAndroid Build Coastguard Worker // such as those required for instrumentation tooling.
559*795d594fSAndroid Build Coastguard Worker //
560*795d594fSAndroid Build Coastguard Worker // The defer system works with the normal id-assignment routine to ensure that all the class-ext
561*795d594fSAndroid Build Coastguard Worker // data structures are eventually created and filled in. Basically how it works is the id-assignment
562*795d594fSAndroid Build Coastguard Worker // function will check to see if it has a strong mutator-lock. If it does not then it will try to
563*795d594fSAndroid Build Coastguard Worker // allocate the class-ext data structures normally and fail if it is unable to do so. In the case
564*795d594fSAndroid Build Coastguard Worker // where mutator-lock is being held exclusive no attempt to allocate will be made and the thread
565*795d594fSAndroid Build Coastguard Worker // will CHECK that allocations are being deferred (or that the method is obsolete, in which case
566*795d594fSAndroid Build Coastguard Worker // there is no class-ext to store the method->id map in).
567*795d594fSAndroid Build Coastguard Worker //
568*795d594fSAndroid Build Coastguard Worker // Once the thread is done holding the exclusive mutator-lock it will go back and fill-in the
569*795d594fSAndroid Build Coastguard Worker // class-ext data of all the methods that were added. We do this without the exclusive mutator-lock
570*795d594fSAndroid Build Coastguard Worker // on a copy of the maps before we decrement the deferred refcount. This ensures that any other
571*795d594fSAndroid Build Coastguard Worker // threads running at the same time know they need to perform a linear scan of the id-map. Since we
572*795d594fSAndroid Build Coastguard Worker // don't have the mutator-lock anymore other threads can allocate the class-ext data, meaning our
573*795d594fSAndroid Build Coastguard Worker // copy is fine. The only way additional methods could end up on the id-maps after our copy without
574*795d594fSAndroid Build Coastguard Worker // having class-ext data is if another thread picked up the exclusive mutator-lock and added another
575*795d594fSAndroid Build Coastguard Worker // defer, in which case that thread would fix-up the remaining ids. In this way we maintain eventual
576*795d594fSAndroid Build Coastguard Worker // consistency between the class-ext method/field->id maps and the JniIdManager id->method/field
577*795d594fSAndroid Build Coastguard Worker // maps.
578*795d594fSAndroid Build Coastguard Worker //
579*795d594fSAndroid Build Coastguard Worker // TODO It is possible that another thread to gain the mutator-lock and allocate new ids without
580*795d594fSAndroid Build Coastguard Worker // calling StartDefer. This is basically a race that we should try to catch but doing so is
581*795d594fSAndroid Build Coastguard Worker // rather difficult and since this defer system is only used in very rare circumstances unlikely to
582*795d594fSAndroid Build Coastguard Worker // be worth the trouble.
StartDefer()583*795d594fSAndroid Build Coastguard Worker void JniIdManager::StartDefer() {
584*795d594fSAndroid Build Coastguard Worker   Thread* self = Thread::Current();
585*795d594fSAndroid Build Coastguard Worker   WriterMutexLock mu(self, *Locks::jni_id_lock_);
586*795d594fSAndroid Build Coastguard Worker   if (deferred_allocation_refcount_++ == 0) {
587*795d594fSAndroid Build Coastguard Worker     deferred_allocation_field_id_start_ = next_field_id_;
588*795d594fSAndroid Build Coastguard Worker     deferred_allocation_method_id_start_ = next_method_id_;
589*795d594fSAndroid Build Coastguard Worker   }
590*795d594fSAndroid Build Coastguard Worker }
591*795d594fSAndroid Build Coastguard Worker 
592*795d594fSAndroid Build Coastguard Worker class JniIdDeferStackReflectiveScope : public BaseReflectiveHandleScope {
593*795d594fSAndroid Build Coastguard Worker  public:
REQUIRES_SHARED(art::Locks::mutator_lock_)594*795d594fSAndroid Build Coastguard Worker   JniIdDeferStackReflectiveScope() REQUIRES_SHARED(art::Locks::mutator_lock_)
595*795d594fSAndroid Build Coastguard Worker       : BaseReflectiveHandleScope(), methods_(), fields_() {
596*795d594fSAndroid Build Coastguard Worker     PushScope(Thread::Current());
597*795d594fSAndroid Build Coastguard Worker   }
598*795d594fSAndroid Build Coastguard Worker 
Initialize(const std::vector<ArtMethod * > & methods,const std::vector<ArtField * > & fields)599*795d594fSAndroid Build Coastguard Worker   void Initialize(const std::vector<ArtMethod*>& methods, const std::vector<ArtField*>& fields)
600*795d594fSAndroid Build Coastguard Worker       REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(Roles::uninterruptible_) {
601*795d594fSAndroid Build Coastguard Worker     methods_ = methods;
602*795d594fSAndroid Build Coastguard Worker     fields_ = fields;
603*795d594fSAndroid Build Coastguard Worker   }
604*795d594fSAndroid Build Coastguard Worker 
REQUIRES_SHARED(Locks::mutator_lock_)605*795d594fSAndroid Build Coastguard Worker   ~JniIdDeferStackReflectiveScope() REQUIRES_SHARED(Locks::mutator_lock_) {
606*795d594fSAndroid Build Coastguard Worker     PopScope();
607*795d594fSAndroid Build Coastguard Worker   }
608*795d594fSAndroid Build Coastguard Worker 
VisitTargets(ReflectiveValueVisitor * visitor)609*795d594fSAndroid Build Coastguard Worker   void VisitTargets(ReflectiveValueVisitor* visitor) override
610*795d594fSAndroid Build Coastguard Worker       REQUIRES_SHARED(Locks::mutator_lock_) {
611*795d594fSAndroid Build Coastguard Worker     for (auto it = methods_.begin(); it != methods_.end(); ++it) {
612*795d594fSAndroid Build Coastguard Worker       if (*it == nullptr) {
613*795d594fSAndroid Build Coastguard Worker         continue;
614*795d594fSAndroid Build Coastguard Worker       }
615*795d594fSAndroid Build Coastguard Worker       *it = visitor->VisitMethod(*it, ReflectiveHandleScopeSourceInfo(this));
616*795d594fSAndroid Build Coastguard Worker     }
617*795d594fSAndroid Build Coastguard Worker     for (auto it = fields_.begin(); it != fields_.end(); ++it) {
618*795d594fSAndroid Build Coastguard Worker       if (*it == nullptr) {
619*795d594fSAndroid Build Coastguard Worker         continue;
620*795d594fSAndroid Build Coastguard Worker       }
621*795d594fSAndroid Build Coastguard Worker       *it = visitor->VisitField(*it, ReflectiveHandleScopeSourceInfo(this));
622*795d594fSAndroid Build Coastguard Worker     }
623*795d594fSAndroid Build Coastguard Worker   }
624*795d594fSAndroid Build Coastguard Worker 
GetFieldPtr(size_t idx)625*795d594fSAndroid Build Coastguard Worker   ArtField** GetFieldPtr(size_t idx) REQUIRES_SHARED(Locks::mutator_lock_) {
626*795d594fSAndroid Build Coastguard Worker     return &fields_[idx];
627*795d594fSAndroid Build Coastguard Worker   }
628*795d594fSAndroid Build Coastguard Worker 
GetMethodPtr(size_t idx)629*795d594fSAndroid Build Coastguard Worker   ArtMethod** GetMethodPtr(size_t idx) REQUIRES_SHARED(Locks::mutator_lock_) {
630*795d594fSAndroid Build Coastguard Worker     return &methods_[idx];
631*795d594fSAndroid Build Coastguard Worker   }
632*795d594fSAndroid Build Coastguard Worker 
NumFields() const633*795d594fSAndroid Build Coastguard Worker   size_t NumFields() const {
634*795d594fSAndroid Build Coastguard Worker     return fields_.size();
635*795d594fSAndroid Build Coastguard Worker   }
NumMethods() const636*795d594fSAndroid Build Coastguard Worker   size_t NumMethods() const {
637*795d594fSAndroid Build Coastguard Worker     return methods_.size();
638*795d594fSAndroid Build Coastguard Worker   }
639*795d594fSAndroid Build Coastguard Worker 
640*795d594fSAndroid Build Coastguard Worker  private:
641*795d594fSAndroid Build Coastguard Worker   std::vector<ArtMethod*> methods_;
642*795d594fSAndroid Build Coastguard Worker   std::vector<ArtField*> fields_;
643*795d594fSAndroid Build Coastguard Worker };
644*795d594fSAndroid Build Coastguard Worker 
EndDefer()645*795d594fSAndroid Build Coastguard Worker void JniIdManager::EndDefer() {
646*795d594fSAndroid Build Coastguard Worker   // Fixup the method->id map.
647*795d594fSAndroid Build Coastguard Worker   Thread* self = Thread::Current();
648*795d594fSAndroid Build Coastguard Worker   auto set_id = [&](auto** t, uintptr_t id) REQUIRES_SHARED(Locks::mutator_lock_) {
649*795d594fSAndroid Build Coastguard Worker     if (t == nullptr) {
650*795d594fSAndroid Build Coastguard Worker       return;
651*795d594fSAndroid Build Coastguard Worker     }
652*795d594fSAndroid Build Coastguard Worker     bool alloc_failure = EnsureIdsArray(self, (*t)->GetDeclaringClass(), *t);
653*795d594fSAndroid Build Coastguard Worker     ObjPtr<mirror::Class> klass((*t)->GetDeclaringClass());
654*795d594fSAndroid Build Coastguard Worker     size_t off = GetIdOffset(klass, (*t), kRuntimePointerSize);
655*795d594fSAndroid Build Coastguard Worker     ObjPtr<mirror::PointerArray> ids = GetIds(klass, (*t));
656*795d594fSAndroid Build Coastguard Worker     CHECK(!alloc_failure) << "Could not allocate jni ids array!";
657*795d594fSAndroid Build Coastguard Worker     if (ids.IsNull()) {
658*795d594fSAndroid Build Coastguard Worker       return;
659*795d594fSAndroid Build Coastguard Worker     }
660*795d594fSAndroid Build Coastguard Worker     if (kIsDebugBuild) {
661*795d594fSAndroid Build Coastguard Worker       uintptr_t old_id = ids->GetElementPtrSize<uintptr_t, kRuntimePointerSize>(off);
662*795d594fSAndroid Build Coastguard Worker       if (old_id != 0) {
663*795d594fSAndroid Build Coastguard Worker         DCHECK_EQ(old_id, id);
664*795d594fSAndroid Build Coastguard Worker       }
665*795d594fSAndroid Build Coastguard Worker     }
666*795d594fSAndroid Build Coastguard Worker     ids->SetElementPtrSize(off, reinterpret_cast<void*>(id), kRuntimePointerSize);
667*795d594fSAndroid Build Coastguard Worker   };
668*795d594fSAndroid Build Coastguard Worker   // To ensure eventual consistency this depends on the fact that the method_id_map_ and
669*795d594fSAndroid Build Coastguard Worker   // field_id_map_ are the ultimate source of truth and no id is ever reused to be valid. It also
670*795d594fSAndroid Build Coastguard Worker   // relies on all threads always getting calling StartDefer if they are going to be allocating jni
671*795d594fSAndroid Build Coastguard Worker   // ids while suspended. If a thread tries to do so while it doesn't have a scope we could miss
672*795d594fSAndroid Build Coastguard Worker   // ids.
673*795d594fSAndroid Build Coastguard Worker   // TODO We should use roles or something to verify that this requirement is not broken.
674*795d594fSAndroid Build Coastguard Worker   //
675*795d594fSAndroid Build Coastguard Worker   // If another thread comes along and adds more methods to the list after
676*795d594fSAndroid Build Coastguard Worker   // copying either (1) the id-maps are already present for the method and everything is fine, (2)
677*795d594fSAndroid Build Coastguard Worker   // the thread is not suspended and so can create the ext-data and id lists or, (3) the thread also
678*795d594fSAndroid Build Coastguard Worker   // suspended everything and incremented the deferred_allocation_refcount_ so it will fix up new
679*795d594fSAndroid Build Coastguard Worker   // ids when it finishes.
680*795d594fSAndroid Build Coastguard Worker   Locks::mutator_lock_->AssertNotExclusiveHeld(self);
681*795d594fSAndroid Build Coastguard Worker   Locks::mutator_lock_->AssertSharedHeld(self);
682*795d594fSAndroid Build Coastguard Worker   JniIdDeferStackReflectiveScope jidsrs;
683*795d594fSAndroid Build Coastguard Worker   uintptr_t method_start_id;
684*795d594fSAndroid Build Coastguard Worker   uintptr_t field_start_id;
685*795d594fSAndroid Build Coastguard Worker   {
686*795d594fSAndroid Build Coastguard Worker     ReaderMutexLock mu(self, *Locks::jni_id_lock_);
687*795d594fSAndroid Build Coastguard Worker     ScopedAssertNoThreadSuspension sants(__FUNCTION__);
688*795d594fSAndroid Build Coastguard Worker     jidsrs.Initialize(method_id_map_, field_id_map_);
689*795d594fSAndroid Build Coastguard Worker     method_start_id = deferred_allocation_method_id_start_;
690*795d594fSAndroid Build Coastguard Worker     field_start_id = deferred_allocation_field_id_start_;
691*795d594fSAndroid Build Coastguard Worker   }
692*795d594fSAndroid Build Coastguard Worker 
693*795d594fSAndroid Build Coastguard Worker   for (size_t index = kIsDebugBuild ? 0 : IdToIndex(method_start_id); index < jidsrs.NumMethods();
694*795d594fSAndroid Build Coastguard Worker        ++index) {
695*795d594fSAndroid Build Coastguard Worker     set_id(jidsrs.GetMethodPtr(index), IndexToId(index));
696*795d594fSAndroid Build Coastguard Worker   }
697*795d594fSAndroid Build Coastguard Worker   for (size_t index = kIsDebugBuild ? 0 : IdToIndex(field_start_id); index < jidsrs.NumFields();
698*795d594fSAndroid Build Coastguard Worker        ++index) {
699*795d594fSAndroid Build Coastguard Worker     set_id(jidsrs.GetFieldPtr(index), IndexToId(index));
700*795d594fSAndroid Build Coastguard Worker   }
701*795d594fSAndroid Build Coastguard Worker   WriterMutexLock mu(self, *Locks::jni_id_lock_);
702*795d594fSAndroid Build Coastguard Worker   DCHECK_GE(deferred_allocation_refcount_, 1u);
703*795d594fSAndroid Build Coastguard Worker   if (--deferred_allocation_refcount_ == 0) {
704*795d594fSAndroid Build Coastguard Worker     deferred_allocation_field_id_start_ = 0;
705*795d594fSAndroid Build Coastguard Worker     deferred_allocation_method_id_start_ = 0;
706*795d594fSAndroid Build Coastguard Worker   }
707*795d594fSAndroid Build Coastguard Worker }
708*795d594fSAndroid Build Coastguard Worker 
ScopedEnableSuspendAllJniIdQueries()709*795d594fSAndroid Build Coastguard Worker ScopedEnableSuspendAllJniIdQueries::ScopedEnableSuspendAllJniIdQueries()
710*795d594fSAndroid Build Coastguard Worker     : manager_(Runtime::Current()->GetJniIdManager()) {
711*795d594fSAndroid Build Coastguard Worker   manager_->StartDefer();
712*795d594fSAndroid Build Coastguard Worker }
713*795d594fSAndroid Build Coastguard Worker 
~ScopedEnableSuspendAllJniIdQueries()714*795d594fSAndroid Build Coastguard Worker ScopedEnableSuspendAllJniIdQueries::~ScopedEnableSuspendAllJniIdQueries() {
715*795d594fSAndroid Build Coastguard Worker   manager_->EndDefer();
716*795d594fSAndroid Build Coastguard Worker }
717*795d594fSAndroid Build Coastguard Worker 
718*795d594fSAndroid Build Coastguard Worker };  // namespace jni
719*795d594fSAndroid Build Coastguard Worker };  // namespace art
720