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