xref: /aosp_15_r20/art/openjdkjvmti/jvmti_weak_table-inl.h (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /* Copyright (C) 2017 The Android Open Source Project
2*795d594fSAndroid Build Coastguard Worker  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * This file implements interfaces from the file jvmti.h. This implementation
5*795d594fSAndroid Build Coastguard Worker  * is licensed under the same terms as the file jvmti.h.  The
6*795d594fSAndroid Build Coastguard Worker  * copyright and license information for the file jvmti.h follows.
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
9*795d594fSAndroid Build Coastguard Worker  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
10*795d594fSAndroid Build Coastguard Worker  *
11*795d594fSAndroid Build Coastguard Worker  * This code is free software; you can redistribute it and/or modify it
12*795d594fSAndroid Build Coastguard Worker  * under the terms of the GNU General Public License version 2 only, as
13*795d594fSAndroid Build Coastguard Worker  * published by the Free Software Foundation.  Oracle designates this
14*795d594fSAndroid Build Coastguard Worker  * particular file as subject to the "Classpath" exception as provided
15*795d594fSAndroid Build Coastguard Worker  * by Oracle in the LICENSE file that accompanied this code.
16*795d594fSAndroid Build Coastguard Worker  *
17*795d594fSAndroid Build Coastguard Worker  * This code is distributed in the hope that it will be useful, but WITHOUT
18*795d594fSAndroid Build Coastguard Worker  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19*795d594fSAndroid Build Coastguard Worker  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20*795d594fSAndroid Build Coastguard Worker  * version 2 for more details (a copy is included in the LICENSE file that
21*795d594fSAndroid Build Coastguard Worker  * accompanied this code).
22*795d594fSAndroid Build Coastguard Worker  *
23*795d594fSAndroid Build Coastguard Worker  * You should have received a copy of the GNU General Public License version
24*795d594fSAndroid Build Coastguard Worker  * 2 along with this work; if not, write to the Free Software Foundation,
25*795d594fSAndroid Build Coastguard Worker  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
26*795d594fSAndroid Build Coastguard Worker  *
27*795d594fSAndroid Build Coastguard Worker  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
28*795d594fSAndroid Build Coastguard Worker  * or visit www.oracle.com if you need additional information or have any
29*795d594fSAndroid Build Coastguard Worker  * questions.
30*795d594fSAndroid Build Coastguard Worker  */
31*795d594fSAndroid Build Coastguard Worker 
32*795d594fSAndroid Build Coastguard Worker #ifndef ART_OPENJDKJVMTI_JVMTI_WEAK_TABLE_INL_H_
33*795d594fSAndroid Build Coastguard Worker #define ART_OPENJDKJVMTI_JVMTI_WEAK_TABLE_INL_H_
34*795d594fSAndroid Build Coastguard Worker 
35*795d594fSAndroid Build Coastguard Worker #include "jvmti_weak_table.h"
36*795d594fSAndroid Build Coastguard Worker 
37*795d594fSAndroid Build Coastguard Worker #include <limits>
38*795d594fSAndroid Build Coastguard Worker 
39*795d594fSAndroid Build Coastguard Worker #include <android-base/logging.h>
40*795d594fSAndroid Build Coastguard Worker 
41*795d594fSAndroid Build Coastguard Worker #include "art_jvmti.h"
42*795d594fSAndroid Build Coastguard Worker #include "gc/allocation_listener.h"
43*795d594fSAndroid Build Coastguard Worker #include "instrumentation.h"
44*795d594fSAndroid Build Coastguard Worker #include "jni/jni_env_ext-inl.h"
45*795d594fSAndroid Build Coastguard Worker #include "jvmti_allocator.h"
46*795d594fSAndroid Build Coastguard Worker #include "mirror/class.h"
47*795d594fSAndroid Build Coastguard Worker #include "mirror/object.h"
48*795d594fSAndroid Build Coastguard Worker #include "nativehelper/scoped_local_ref.h"
49*795d594fSAndroid Build Coastguard Worker #include "runtime.h"
50*795d594fSAndroid Build Coastguard Worker 
51*795d594fSAndroid Build Coastguard Worker namespace openjdkjvmti {
52*795d594fSAndroid Build Coastguard Worker 
53*795d594fSAndroid Build Coastguard Worker template <typename T>
Lock()54*795d594fSAndroid Build Coastguard Worker void JvmtiWeakTable<T>::Lock() {
55*795d594fSAndroid Build Coastguard Worker   allow_disallow_lock_.ExclusiveLock(art::Thread::Current());
56*795d594fSAndroid Build Coastguard Worker }
57*795d594fSAndroid Build Coastguard Worker template <typename T>
Unlock()58*795d594fSAndroid Build Coastguard Worker void JvmtiWeakTable<T>::Unlock() {
59*795d594fSAndroid Build Coastguard Worker   allow_disallow_lock_.ExclusiveUnlock(art::Thread::Current());
60*795d594fSAndroid Build Coastguard Worker }
61*795d594fSAndroid Build Coastguard Worker template <typename T>
AssertLocked()62*795d594fSAndroid Build Coastguard Worker void JvmtiWeakTable<T>::AssertLocked() {
63*795d594fSAndroid Build Coastguard Worker   allow_disallow_lock_.AssertHeld(art::Thread::Current());
64*795d594fSAndroid Build Coastguard Worker }
65*795d594fSAndroid Build Coastguard Worker 
66*795d594fSAndroid Build Coastguard Worker template <typename T>
UpdateTableWithReadBarrier()67*795d594fSAndroid Build Coastguard Worker void JvmtiWeakTable<T>::UpdateTableWithReadBarrier() {
68*795d594fSAndroid Build Coastguard Worker   update_since_last_sweep_ = true;
69*795d594fSAndroid Build Coastguard Worker 
70*795d594fSAndroid Build Coastguard Worker   auto WithReadBarrierUpdater = [&](const art::GcRoot<art::mirror::Object>& original_root,
71*795d594fSAndroid Build Coastguard Worker                                     [[maybe_unused]] art::mirror::Object* original_obj)
72*795d594fSAndroid Build Coastguard Worker                                     REQUIRES_SHARED(art::Locks::mutator_lock_) {
73*795d594fSAndroid Build Coastguard Worker                                       return original_root.Read<art::kWithReadBarrier>();
74*795d594fSAndroid Build Coastguard Worker                                     };
75*795d594fSAndroid Build Coastguard Worker 
76*795d594fSAndroid Build Coastguard Worker   UpdateTableWith<decltype(WithReadBarrierUpdater), kIgnoreNull>(WithReadBarrierUpdater);
77*795d594fSAndroid Build Coastguard Worker }
78*795d594fSAndroid Build Coastguard Worker 
79*795d594fSAndroid Build Coastguard Worker template <typename T>
GetTagSlowPath(art::Thread * self,art::ObjPtr<art::mirror::Object> obj,T * result)80*795d594fSAndroid Build Coastguard Worker bool JvmtiWeakTable<T>::GetTagSlowPath(art::Thread* self, art::ObjPtr<art::mirror::Object> obj, T* result) {
81*795d594fSAndroid Build Coastguard Worker   // Under concurrent GC, there is a window between moving objects and sweeping of system
82*795d594fSAndroid Build Coastguard Worker   // weaks in which mutators are active. We may receive a to-space object pointer in obj,
83*795d594fSAndroid Build Coastguard Worker   // but still have from-space pointers in the table. Explicitly update the table once.
84*795d594fSAndroid Build Coastguard Worker   // Note: this will keep *all* objects in the table live, but should be a rare occurrence.
85*795d594fSAndroid Build Coastguard Worker   UpdateTableWithReadBarrier();
86*795d594fSAndroid Build Coastguard Worker   return GetTagLocked(self, obj, result);
87*795d594fSAndroid Build Coastguard Worker }
88*795d594fSAndroid Build Coastguard Worker 
89*795d594fSAndroid Build Coastguard Worker template <typename T>
Remove(art::ObjPtr<art::mirror::Object> obj,T * tag)90*795d594fSAndroid Build Coastguard Worker bool JvmtiWeakTable<T>::Remove(art::ObjPtr<art::mirror::Object> obj, /* out */ T* tag) {
91*795d594fSAndroid Build Coastguard Worker   art::Thread* self = art::Thread::Current();
92*795d594fSAndroid Build Coastguard Worker   art::MutexLock mu(self, allow_disallow_lock_);
93*795d594fSAndroid Build Coastguard Worker   Wait(self);
94*795d594fSAndroid Build Coastguard Worker 
95*795d594fSAndroid Build Coastguard Worker   return RemoveLocked(self, obj, tag);
96*795d594fSAndroid Build Coastguard Worker }
97*795d594fSAndroid Build Coastguard Worker template <typename T>
RemoveLocked(art::ObjPtr<art::mirror::Object> obj,T * tag)98*795d594fSAndroid Build Coastguard Worker bool JvmtiWeakTable<T>::RemoveLocked(art::ObjPtr<art::mirror::Object> obj, T* tag) {
99*795d594fSAndroid Build Coastguard Worker   art::Thread* self = art::Thread::Current();
100*795d594fSAndroid Build Coastguard Worker   allow_disallow_lock_.AssertHeld(self);
101*795d594fSAndroid Build Coastguard Worker   Wait(self);
102*795d594fSAndroid Build Coastguard Worker 
103*795d594fSAndroid Build Coastguard Worker   return RemoveLocked(self, obj, tag);
104*795d594fSAndroid Build Coastguard Worker }
105*795d594fSAndroid Build Coastguard Worker 
106*795d594fSAndroid Build Coastguard Worker template <typename T>
RemoveLocked(art::Thread * self,art::ObjPtr<art::mirror::Object> obj,T * tag)107*795d594fSAndroid Build Coastguard Worker bool JvmtiWeakTable<T>::RemoveLocked(art::Thread* self, art::ObjPtr<art::mirror::Object> obj, T* tag) {
108*795d594fSAndroid Build Coastguard Worker   auto it = tagged_objects_.find(art::GcRoot<art::mirror::Object>(obj));
109*795d594fSAndroid Build Coastguard Worker   if (it != tagged_objects_.end()) {
110*795d594fSAndroid Build Coastguard Worker     if (tag != nullptr) {
111*795d594fSAndroid Build Coastguard Worker       *tag = it->second;
112*795d594fSAndroid Build Coastguard Worker     }
113*795d594fSAndroid Build Coastguard Worker     tagged_objects_.erase(it);
114*795d594fSAndroid Build Coastguard Worker     return true;
115*795d594fSAndroid Build Coastguard Worker   }
116*795d594fSAndroid Build Coastguard Worker 
117*795d594fSAndroid Build Coastguard Worker   if (art::gUseReadBarrier && self->GetIsGcMarking() && !update_since_last_sweep_) {
118*795d594fSAndroid Build Coastguard Worker     // Under concurrent GC, there is a window between moving objects and sweeping of system
119*795d594fSAndroid Build Coastguard Worker     // weaks in which mutators are active. We may receive a to-space object pointer in obj,
120*795d594fSAndroid Build Coastguard Worker     // but still have from-space pointers in the table. Explicitly update the table once.
121*795d594fSAndroid Build Coastguard Worker     // Note: this will keep *all* objects in the table live, but should be a rare occurrence.
122*795d594fSAndroid Build Coastguard Worker 
123*795d594fSAndroid Build Coastguard Worker     // Update the table.
124*795d594fSAndroid Build Coastguard Worker     UpdateTableWithReadBarrier();
125*795d594fSAndroid Build Coastguard Worker 
126*795d594fSAndroid Build Coastguard Worker     // And try again.
127*795d594fSAndroid Build Coastguard Worker     return RemoveLocked(self, obj, tag);
128*795d594fSAndroid Build Coastguard Worker   }
129*795d594fSAndroid Build Coastguard Worker 
130*795d594fSAndroid Build Coastguard Worker   // Not in here.
131*795d594fSAndroid Build Coastguard Worker   return false;
132*795d594fSAndroid Build Coastguard Worker }
133*795d594fSAndroid Build Coastguard Worker 
134*795d594fSAndroid Build Coastguard Worker template <typename T>
Set(art::ObjPtr<art::mirror::Object> obj,T new_tag)135*795d594fSAndroid Build Coastguard Worker bool JvmtiWeakTable<T>::Set(art::ObjPtr<art::mirror::Object> obj, T new_tag) {
136*795d594fSAndroid Build Coastguard Worker   art::Thread* self = art::Thread::Current();
137*795d594fSAndroid Build Coastguard Worker   art::MutexLock mu(self, allow_disallow_lock_);
138*795d594fSAndroid Build Coastguard Worker   Wait(self);
139*795d594fSAndroid Build Coastguard Worker 
140*795d594fSAndroid Build Coastguard Worker   return SetLocked(self, obj, new_tag);
141*795d594fSAndroid Build Coastguard Worker }
142*795d594fSAndroid Build Coastguard Worker template <typename T>
SetLocked(art::ObjPtr<art::mirror::Object> obj,T new_tag)143*795d594fSAndroid Build Coastguard Worker bool JvmtiWeakTable<T>::SetLocked(art::ObjPtr<art::mirror::Object> obj, T new_tag) {
144*795d594fSAndroid Build Coastguard Worker   art::Thread* self = art::Thread::Current();
145*795d594fSAndroid Build Coastguard Worker   allow_disallow_lock_.AssertHeld(self);
146*795d594fSAndroid Build Coastguard Worker   Wait(self);
147*795d594fSAndroid Build Coastguard Worker 
148*795d594fSAndroid Build Coastguard Worker   return SetLocked(self, obj, new_tag);
149*795d594fSAndroid Build Coastguard Worker }
150*795d594fSAndroid Build Coastguard Worker 
151*795d594fSAndroid Build Coastguard Worker template <typename T>
SetLocked(art::Thread * self,art::ObjPtr<art::mirror::Object> obj,T new_tag)152*795d594fSAndroid Build Coastguard Worker bool JvmtiWeakTable<T>::SetLocked(art::Thread* self, art::ObjPtr<art::mirror::Object> obj, T new_tag) {
153*795d594fSAndroid Build Coastguard Worker   auto it = tagged_objects_.find(art::GcRoot<art::mirror::Object>(obj));
154*795d594fSAndroid Build Coastguard Worker   if (it != tagged_objects_.end()) {
155*795d594fSAndroid Build Coastguard Worker     it->second = new_tag;
156*795d594fSAndroid Build Coastguard Worker     return true;
157*795d594fSAndroid Build Coastguard Worker   }
158*795d594fSAndroid Build Coastguard Worker 
159*795d594fSAndroid Build Coastguard Worker   if (art::gUseReadBarrier && self->GetIsGcMarking() && !update_since_last_sweep_) {
160*795d594fSAndroid Build Coastguard Worker     // Under concurrent GC, there is a window between moving objects and sweeping of system
161*795d594fSAndroid Build Coastguard Worker     // weaks in which mutators are active. We may receive a to-space object pointer in obj,
162*795d594fSAndroid Build Coastguard Worker     // but still have from-space pointers in the table. Explicitly update the table once.
163*795d594fSAndroid Build Coastguard Worker     // Note: this will keep *all* objects in the table live, but should be a rare occurrence.
164*795d594fSAndroid Build Coastguard Worker 
165*795d594fSAndroid Build Coastguard Worker     // Update the table.
166*795d594fSAndroid Build Coastguard Worker     UpdateTableWithReadBarrier();
167*795d594fSAndroid Build Coastguard Worker 
168*795d594fSAndroid Build Coastguard Worker     // And try again.
169*795d594fSAndroid Build Coastguard Worker     return SetLocked(self, obj, new_tag);
170*795d594fSAndroid Build Coastguard Worker   }
171*795d594fSAndroid Build Coastguard Worker 
172*795d594fSAndroid Build Coastguard Worker   // New element.
173*795d594fSAndroid Build Coastguard Worker   auto insert_it = tagged_objects_.emplace(art::GcRoot<art::mirror::Object>(obj), new_tag);
174*795d594fSAndroid Build Coastguard Worker   DCHECK(insert_it.second);
175*795d594fSAndroid Build Coastguard Worker   return false;
176*795d594fSAndroid Build Coastguard Worker }
177*795d594fSAndroid Build Coastguard Worker 
178*795d594fSAndroid Build Coastguard Worker template <typename T>
Sweep(art::IsMarkedVisitor * visitor)179*795d594fSAndroid Build Coastguard Worker void JvmtiWeakTable<T>::Sweep(art::IsMarkedVisitor* visitor) {
180*795d594fSAndroid Build Coastguard Worker   if (DoesHandleNullOnSweep()) {
181*795d594fSAndroid Build Coastguard Worker     SweepImpl<true>(visitor);
182*795d594fSAndroid Build Coastguard Worker   } else {
183*795d594fSAndroid Build Coastguard Worker     SweepImpl<false>(visitor);
184*795d594fSAndroid Build Coastguard Worker   }
185*795d594fSAndroid Build Coastguard Worker 
186*795d594fSAndroid Build Coastguard Worker   // Under concurrent GC, there is a window between moving objects and sweeping of system
187*795d594fSAndroid Build Coastguard Worker   // weaks in which mutators are active. We may receive a to-space object pointer in obj,
188*795d594fSAndroid Build Coastguard Worker   // but still have from-space pointers in the table. We explicitly update the table then
189*795d594fSAndroid Build Coastguard Worker   // to ensure we compare against to-space pointers. But we want to do this only once. Once
190*795d594fSAndroid Build Coastguard Worker   // sweeping is done, we know all objects are to-space pointers until the next GC cycle,
191*795d594fSAndroid Build Coastguard Worker   // so we re-enable the explicit update for the next marking.
192*795d594fSAndroid Build Coastguard Worker   update_since_last_sweep_ = false;
193*795d594fSAndroid Build Coastguard Worker }
194*795d594fSAndroid Build Coastguard Worker 
195*795d594fSAndroid Build Coastguard Worker template <typename T>
196*795d594fSAndroid Build Coastguard Worker template <bool kHandleNull>
SweepImpl(art::IsMarkedVisitor * visitor)197*795d594fSAndroid Build Coastguard Worker void JvmtiWeakTable<T>::SweepImpl(art::IsMarkedVisitor* visitor) {
198*795d594fSAndroid Build Coastguard Worker   art::Thread* self = art::Thread::Current();
199*795d594fSAndroid Build Coastguard Worker   art::MutexLock mu(self, allow_disallow_lock_);
200*795d594fSAndroid Build Coastguard Worker 
201*795d594fSAndroid Build Coastguard Worker   auto IsMarkedUpdater = [&]([[maybe_unused]] const art::GcRoot<art::mirror::Object>& original_root,
202*795d594fSAndroid Build Coastguard Worker                              art::mirror::Object* original_obj) {
203*795d594fSAndroid Build Coastguard Worker     return visitor->IsMarked(original_obj);
204*795d594fSAndroid Build Coastguard Worker   };
205*795d594fSAndroid Build Coastguard Worker 
206*795d594fSAndroid Build Coastguard Worker   UpdateTableWith<decltype(IsMarkedUpdater),
207*795d594fSAndroid Build Coastguard Worker                   kHandleNull ? kCallHandleNull : kRemoveNull>(IsMarkedUpdater);
208*795d594fSAndroid Build Coastguard Worker }
209*795d594fSAndroid Build Coastguard Worker 
210*795d594fSAndroid Build Coastguard Worker template <typename T>
211*795d594fSAndroid Build Coastguard Worker template <typename Updater, typename JvmtiWeakTable<T>::TableUpdateNullTarget kTargetNull>
UpdateTableWith(Updater & updater)212*795d594fSAndroid Build Coastguard Worker ALWAYS_INLINE inline void JvmtiWeakTable<T>::UpdateTableWith(Updater& updater) {
213*795d594fSAndroid Build Coastguard Worker   // We can't emplace within the map as a to-space reference could be the same as some
214*795d594fSAndroid Build Coastguard Worker   // from-space object reference in the map, causing correctness issues. The problem
215*795d594fSAndroid Build Coastguard Worker   // doesn't arise if all updated <K,V> pairs are inserted after the loop as by then such
216*795d594fSAndroid Build Coastguard Worker   // from-space object references would also have been taken care of.
217*795d594fSAndroid Build Coastguard Worker 
218*795d594fSAndroid Build Coastguard Worker   // Side vector to hold node handles of entries which are updated.
219*795d594fSAndroid Build Coastguard Worker   std::vector<typename TagMap::node_type> updated_node_handles;
220*795d594fSAndroid Build Coastguard Worker 
221*795d594fSAndroid Build Coastguard Worker   for (auto it = tagged_objects_.begin(); it != tagged_objects_.end();) {
222*795d594fSAndroid Build Coastguard Worker     DCHECK(!it->first.IsNull());
223*795d594fSAndroid Build Coastguard Worker     art::mirror::Object* original_obj = it->first.template Read<art::kWithoutReadBarrier>();
224*795d594fSAndroid Build Coastguard Worker     art::mirror::Object* target_obj = updater(it->first, original_obj);
225*795d594fSAndroid Build Coastguard Worker     if (original_obj != target_obj) {
226*795d594fSAndroid Build Coastguard Worker       if (kTargetNull == kIgnoreNull && target_obj == nullptr) {
227*795d594fSAndroid Build Coastguard Worker         // Ignore null target, don't do anything.
228*795d594fSAndroid Build Coastguard Worker       } else {
229*795d594fSAndroid Build Coastguard Worker         auto nh = tagged_objects_.extract(it++);
230*795d594fSAndroid Build Coastguard Worker         DCHECK(!nh.empty());
231*795d594fSAndroid Build Coastguard Worker         if (target_obj != nullptr) {
232*795d594fSAndroid Build Coastguard Worker           nh.key() = art::GcRoot<art::mirror::Object>(target_obj);
233*795d594fSAndroid Build Coastguard Worker           updated_node_handles.push_back(std::move(nh));
234*795d594fSAndroid Build Coastguard Worker         } else if (kTargetNull == kCallHandleNull) {
235*795d594fSAndroid Build Coastguard Worker           HandleNullSweep(nh.mapped());
236*795d594fSAndroid Build Coastguard Worker         }
237*795d594fSAndroid Build Coastguard Worker         continue;  // Iterator already updated above.
238*795d594fSAndroid Build Coastguard Worker       }
239*795d594fSAndroid Build Coastguard Worker     }
240*795d594fSAndroid Build Coastguard Worker     it++;
241*795d594fSAndroid Build Coastguard Worker   }
242*795d594fSAndroid Build Coastguard Worker   while (!updated_node_handles.empty()) {
243*795d594fSAndroid Build Coastguard Worker     auto ret = tagged_objects_.insert(std::move(updated_node_handles.back()));
244*795d594fSAndroid Build Coastguard Worker     DCHECK(ret.inserted);
245*795d594fSAndroid Build Coastguard Worker     updated_node_handles.pop_back();
246*795d594fSAndroid Build Coastguard Worker   }
247*795d594fSAndroid Build Coastguard Worker }
248*795d594fSAndroid Build Coastguard Worker 
249*795d594fSAndroid Build Coastguard Worker template <typename T>
250*795d594fSAndroid Build Coastguard Worker template <typename Storage, class Allocator>
251*795d594fSAndroid Build Coastguard Worker struct JvmtiWeakTable<T>::ReleasableContainer {
252*795d594fSAndroid Build Coastguard Worker   using allocator_type = Allocator;
253*795d594fSAndroid Build Coastguard Worker 
254*795d594fSAndroid Build Coastguard Worker   explicit ReleasableContainer(const allocator_type& alloc, size_t reserve = 10)
255*795d594fSAndroid Build Coastguard Worker       : allocator(alloc),
256*795d594fSAndroid Build Coastguard Worker         data(reserve > 0 ? allocator.allocate(reserve) : nullptr),
257*795d594fSAndroid Build Coastguard Worker         size(0),
258*795d594fSAndroid Build Coastguard Worker         capacity(reserve) {
259*795d594fSAndroid Build Coastguard Worker   }
260*795d594fSAndroid Build Coastguard Worker 
261*795d594fSAndroid Build Coastguard Worker   ~ReleasableContainer() {
262*795d594fSAndroid Build Coastguard Worker     if (data != nullptr) {
263*795d594fSAndroid Build Coastguard Worker       allocator.deallocate(data, capacity);
264*795d594fSAndroid Build Coastguard Worker       capacity = 0;
265*795d594fSAndroid Build Coastguard Worker       size = 0;
266*795d594fSAndroid Build Coastguard Worker     }
267*795d594fSAndroid Build Coastguard Worker   }
268*795d594fSAndroid Build Coastguard Worker 
269*795d594fSAndroid Build Coastguard Worker   Storage* Release() {
270*795d594fSAndroid Build Coastguard Worker     Storage* tmp = data;
271*795d594fSAndroid Build Coastguard Worker 
272*795d594fSAndroid Build Coastguard Worker     data = nullptr;
273*795d594fSAndroid Build Coastguard Worker     size = 0;
274*795d594fSAndroid Build Coastguard Worker     capacity = 0;
275*795d594fSAndroid Build Coastguard Worker 
276*795d594fSAndroid Build Coastguard Worker     return tmp;
277*795d594fSAndroid Build Coastguard Worker   }
278*795d594fSAndroid Build Coastguard Worker 
279*795d594fSAndroid Build Coastguard Worker   void Resize(size_t new_capacity) {
280*795d594fSAndroid Build Coastguard Worker     CHECK_GT(new_capacity, capacity);
281*795d594fSAndroid Build Coastguard Worker 
282*795d594fSAndroid Build Coastguard Worker     Storage* tmp = allocator.allocate(new_capacity);
283*795d594fSAndroid Build Coastguard Worker     DCHECK(tmp != nullptr);
284*795d594fSAndroid Build Coastguard Worker     if (data != nullptr) {
285*795d594fSAndroid Build Coastguard Worker       memcpy(tmp, data, sizeof(Storage) * size);
286*795d594fSAndroid Build Coastguard Worker     }
287*795d594fSAndroid Build Coastguard Worker     Storage* old = data;
288*795d594fSAndroid Build Coastguard Worker     data = tmp;
289*795d594fSAndroid Build Coastguard Worker     allocator.deallocate(old, capacity);
290*795d594fSAndroid Build Coastguard Worker     capacity = new_capacity;
291*795d594fSAndroid Build Coastguard Worker   }
292*795d594fSAndroid Build Coastguard Worker 
293*795d594fSAndroid Build Coastguard Worker   void Pushback(const Storage& elem) {
294*795d594fSAndroid Build Coastguard Worker     if (size == capacity) {
295*795d594fSAndroid Build Coastguard Worker       size_t new_capacity = 2 * capacity + 1;
296*795d594fSAndroid Build Coastguard Worker       Resize(new_capacity);
297*795d594fSAndroid Build Coastguard Worker     }
298*795d594fSAndroid Build Coastguard Worker     data[size++] = elem;
299*795d594fSAndroid Build Coastguard Worker   }
300*795d594fSAndroid Build Coastguard Worker 
301*795d594fSAndroid Build Coastguard Worker   Allocator allocator;
302*795d594fSAndroid Build Coastguard Worker   Storage* data;
303*795d594fSAndroid Build Coastguard Worker   size_t size;
304*795d594fSAndroid Build Coastguard Worker   size_t capacity;
305*795d594fSAndroid Build Coastguard Worker };
306*795d594fSAndroid Build Coastguard Worker 
307*795d594fSAndroid Build Coastguard Worker template <typename T>
308*795d594fSAndroid Build Coastguard Worker jvmtiError JvmtiWeakTable<T>::GetTaggedObjects(jvmtiEnv* jvmti_env,
309*795d594fSAndroid Build Coastguard Worker                                                jint tag_count,
310*795d594fSAndroid Build Coastguard Worker                                                const T* tags,
311*795d594fSAndroid Build Coastguard Worker                                                jint* count_ptr,
312*795d594fSAndroid Build Coastguard Worker                                                jobject** object_result_ptr,
313*795d594fSAndroid Build Coastguard Worker                                                T** tag_result_ptr) {
314*795d594fSAndroid Build Coastguard Worker   if (tag_count < 0) {
315*795d594fSAndroid Build Coastguard Worker     return ERR(ILLEGAL_ARGUMENT);
316*795d594fSAndroid Build Coastguard Worker   }
317*795d594fSAndroid Build Coastguard Worker   if (tag_count > 0) {
318*795d594fSAndroid Build Coastguard Worker     for (size_t i = 0; i != static_cast<size_t>(tag_count); ++i) {
319*795d594fSAndroid Build Coastguard Worker       if (tags[i] == 0) {
320*795d594fSAndroid Build Coastguard Worker         return ERR(ILLEGAL_ARGUMENT);
321*795d594fSAndroid Build Coastguard Worker       }
322*795d594fSAndroid Build Coastguard Worker     }
323*795d594fSAndroid Build Coastguard Worker   }
324*795d594fSAndroid Build Coastguard Worker   if (tags == nullptr) {
325*795d594fSAndroid Build Coastguard Worker     return ERR(NULL_POINTER);
326*795d594fSAndroid Build Coastguard Worker   }
327*795d594fSAndroid Build Coastguard Worker   if (count_ptr == nullptr) {
328*795d594fSAndroid Build Coastguard Worker     return ERR(NULL_POINTER);
329*795d594fSAndroid Build Coastguard Worker   }
330*795d594fSAndroid Build Coastguard Worker 
331*795d594fSAndroid Build Coastguard Worker   art::Thread* self = art::Thread::Current();
332*795d594fSAndroid Build Coastguard Worker   art::MutexLock mu(self, allow_disallow_lock_);
333*795d594fSAndroid Build Coastguard Worker   Wait(self);
334*795d594fSAndroid Build Coastguard Worker 
335*795d594fSAndroid Build Coastguard Worker   art::JNIEnvExt* jni_env = self->GetJniEnv();
336*795d594fSAndroid Build Coastguard Worker 
337*795d594fSAndroid Build Coastguard Worker   constexpr size_t kDefaultSize = 10;
338*795d594fSAndroid Build Coastguard Worker   size_t initial_object_size;
339*795d594fSAndroid Build Coastguard Worker   size_t initial_tag_size;
340*795d594fSAndroid Build Coastguard Worker   if (tag_count == 0) {
341*795d594fSAndroid Build Coastguard Worker     initial_object_size = (object_result_ptr != nullptr) ? tagged_objects_.size() : 0;
342*795d594fSAndroid Build Coastguard Worker     initial_tag_size = (tag_result_ptr != nullptr) ? tagged_objects_.size() : 0;
343*795d594fSAndroid Build Coastguard Worker   } else {
344*795d594fSAndroid Build Coastguard Worker     initial_object_size = initial_tag_size = kDefaultSize;
345*795d594fSAndroid Build Coastguard Worker   }
346*795d594fSAndroid Build Coastguard Worker   JvmtiAllocator<void> allocator(jvmti_env);
347*795d594fSAndroid Build Coastguard Worker   ReleasableContainer<jobject, JvmtiAllocator<jobject>> selected_objects(allocator,
348*795d594fSAndroid Build Coastguard Worker                                                                          initial_object_size);
349*795d594fSAndroid Build Coastguard Worker   ReleasableContainer<T, JvmtiAllocator<T>> selected_tags(allocator, initial_tag_size);
350*795d594fSAndroid Build Coastguard Worker 
351*795d594fSAndroid Build Coastguard Worker   size_t count = 0;
352*795d594fSAndroid Build Coastguard Worker   for (auto& pair : tagged_objects_) {
353*795d594fSAndroid Build Coastguard Worker     bool select;
354*795d594fSAndroid Build Coastguard Worker     if (tag_count > 0) {
355*795d594fSAndroid Build Coastguard Worker       select = false;
356*795d594fSAndroid Build Coastguard Worker       for (size_t i = 0; i != static_cast<size_t>(tag_count); ++i) {
357*795d594fSAndroid Build Coastguard Worker         if (tags[i] == pair.second) {
358*795d594fSAndroid Build Coastguard Worker           select = true;
359*795d594fSAndroid Build Coastguard Worker           break;
360*795d594fSAndroid Build Coastguard Worker         }
361*795d594fSAndroid Build Coastguard Worker       }
362*795d594fSAndroid Build Coastguard Worker     } else {
363*795d594fSAndroid Build Coastguard Worker       select = true;
364*795d594fSAndroid Build Coastguard Worker     }
365*795d594fSAndroid Build Coastguard Worker 
366*795d594fSAndroid Build Coastguard Worker     if (select) {
367*795d594fSAndroid Build Coastguard Worker       art::ObjPtr<art::mirror::Object> obj = pair.first.template Read<art::kWithReadBarrier>();
368*795d594fSAndroid Build Coastguard Worker       if (obj != nullptr) {
369*795d594fSAndroid Build Coastguard Worker         count++;
370*795d594fSAndroid Build Coastguard Worker         if (object_result_ptr != nullptr) {
371*795d594fSAndroid Build Coastguard Worker           selected_objects.Pushback(jni_env->AddLocalReference<jobject>(obj));
372*795d594fSAndroid Build Coastguard Worker         }
373*795d594fSAndroid Build Coastguard Worker         if (tag_result_ptr != nullptr) {
374*795d594fSAndroid Build Coastguard Worker           selected_tags.Pushback(pair.second);
375*795d594fSAndroid Build Coastguard Worker         }
376*795d594fSAndroid Build Coastguard Worker       }
377*795d594fSAndroid Build Coastguard Worker     }
378*795d594fSAndroid Build Coastguard Worker   }
379*795d594fSAndroid Build Coastguard Worker 
380*795d594fSAndroid Build Coastguard Worker   if (object_result_ptr != nullptr) {
381*795d594fSAndroid Build Coastguard Worker     *object_result_ptr = selected_objects.Release();
382*795d594fSAndroid Build Coastguard Worker   }
383*795d594fSAndroid Build Coastguard Worker   if (tag_result_ptr != nullptr) {
384*795d594fSAndroid Build Coastguard Worker     *tag_result_ptr = selected_tags.Release();
385*795d594fSAndroid Build Coastguard Worker   }
386*795d594fSAndroid Build Coastguard Worker   *count_ptr = static_cast<jint>(count);
387*795d594fSAndroid Build Coastguard Worker   return ERR(NONE);
388*795d594fSAndroid Build Coastguard Worker }
389*795d594fSAndroid Build Coastguard Worker 
390*795d594fSAndroid Build Coastguard Worker template <typename T>
391*795d594fSAndroid Build Coastguard Worker art::ObjPtr<art::mirror::Object> JvmtiWeakTable<T>::Find(T tag) {
392*795d594fSAndroid Build Coastguard Worker   art::Thread* self = art::Thread::Current();
393*795d594fSAndroid Build Coastguard Worker   art::MutexLock mu(self, allow_disallow_lock_);
394*795d594fSAndroid Build Coastguard Worker   Wait(self);
395*795d594fSAndroid Build Coastguard Worker 
396*795d594fSAndroid Build Coastguard Worker   for (auto& pair : tagged_objects_) {
397*795d594fSAndroid Build Coastguard Worker     if (tag == pair.second) {
398*795d594fSAndroid Build Coastguard Worker       art::ObjPtr<art::mirror::Object> obj = pair.first.template Read<art::kWithReadBarrier>();
399*795d594fSAndroid Build Coastguard Worker       if (obj != nullptr) {
400*795d594fSAndroid Build Coastguard Worker         return obj;
401*795d594fSAndroid Build Coastguard Worker       }
402*795d594fSAndroid Build Coastguard Worker     }
403*795d594fSAndroid Build Coastguard Worker   }
404*795d594fSAndroid Build Coastguard Worker   return nullptr;
405*795d594fSAndroid Build Coastguard Worker }
406*795d594fSAndroid Build Coastguard Worker 
407*795d594fSAndroid Build Coastguard Worker }  // namespace openjdkjvmti
408*795d594fSAndroid Build Coastguard Worker 
409*795d594fSAndroid Build Coastguard Worker #endif  // ART_OPENJDKJVMTI_JVMTI_WEAK_TABLE_INL_H_
410