xref: /aosp_15_r20/art/openjdkjvmti/jvmti_weak_table.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_H_
33*795d594fSAndroid Build Coastguard Worker #define ART_OPENJDKJVMTI_JVMTI_WEAK_TABLE_H_
34*795d594fSAndroid Build Coastguard Worker 
35*795d594fSAndroid Build Coastguard Worker #include <unordered_map>
36*795d594fSAndroid Build Coastguard Worker 
37*795d594fSAndroid Build Coastguard Worker #include "base/globals.h"
38*795d594fSAndroid Build Coastguard Worker #include "base/macros.h"
39*795d594fSAndroid Build Coastguard Worker #include "base/mutex.h"
40*795d594fSAndroid Build Coastguard Worker #include "gc/system_weak.h"
41*795d594fSAndroid Build Coastguard Worker #include "gc_root-inl.h"
42*795d594fSAndroid Build Coastguard Worker #include "jvmti.h"
43*795d594fSAndroid Build Coastguard Worker #include "jvmti_allocator.h"
44*795d594fSAndroid Build Coastguard Worker #include "mirror/object.h"
45*795d594fSAndroid Build Coastguard Worker #include "thread-current-inl.h"
46*795d594fSAndroid Build Coastguard Worker 
47*795d594fSAndroid Build Coastguard Worker namespace openjdkjvmti {
48*795d594fSAndroid Build Coastguard Worker 
49*795d594fSAndroid Build Coastguard Worker class EventHandler;
50*795d594fSAndroid Build Coastguard Worker 
51*795d594fSAndroid Build Coastguard Worker // A system-weak container mapping objects to elements of the template type. This corresponds
52*795d594fSAndroid Build Coastguard Worker // to a weak hash map. For historical reasons the stored value is called "tag."
53*795d594fSAndroid Build Coastguard Worker template <typename T>
54*795d594fSAndroid Build Coastguard Worker class JvmtiWeakTable : public art::gc::SystemWeakHolder {
55*795d594fSAndroid Build Coastguard Worker  public:
JvmtiWeakTable()56*795d594fSAndroid Build Coastguard Worker   JvmtiWeakTable()
57*795d594fSAndroid Build Coastguard Worker       : art::gc::SystemWeakHolder(art::kTaggingLockLevel),
58*795d594fSAndroid Build Coastguard Worker         update_since_last_sweep_(false) {
59*795d594fSAndroid Build Coastguard Worker   }
60*795d594fSAndroid Build Coastguard Worker 
61*795d594fSAndroid Build Coastguard Worker   // Remove the mapping for the given object, returning whether such a mapping existed (and the old
62*795d594fSAndroid Build Coastguard Worker   // value).
63*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE bool Remove(art::ObjPtr<art::mirror::Object> obj, /* out */ T* tag)
64*795d594fSAndroid Build Coastguard Worker       REQUIRES_SHARED(art::Locks::mutator_lock_)
65*795d594fSAndroid Build Coastguard Worker       REQUIRES(!allow_disallow_lock_);
66*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE bool RemoveLocked(art::ObjPtr<art::mirror::Object> obj, /* out */ T* tag)
67*795d594fSAndroid Build Coastguard Worker       REQUIRES_SHARED(art::Locks::mutator_lock_)
68*795d594fSAndroid Build Coastguard Worker       REQUIRES(allow_disallow_lock_);
69*795d594fSAndroid Build Coastguard Worker 
70*795d594fSAndroid Build Coastguard Worker   // Set the mapping for the given object. Returns true if this overwrites an already existing
71*795d594fSAndroid Build Coastguard Worker   // mapping.
72*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE virtual bool Set(art::ObjPtr<art::mirror::Object> obj, T tag)
73*795d594fSAndroid Build Coastguard Worker       REQUIRES_SHARED(art::Locks::mutator_lock_)
74*795d594fSAndroid Build Coastguard Worker       REQUIRES(!allow_disallow_lock_);
75*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE virtual bool SetLocked(art::ObjPtr<art::mirror::Object> obj, T tag)
76*795d594fSAndroid Build Coastguard Worker       REQUIRES_SHARED(art::Locks::mutator_lock_)
77*795d594fSAndroid Build Coastguard Worker       REQUIRES(allow_disallow_lock_);
78*795d594fSAndroid Build Coastguard Worker 
79*795d594fSAndroid Build Coastguard Worker   // Return the value associated with the given object. Returns true if the mapping exists, false
80*795d594fSAndroid Build Coastguard Worker   // otherwise.
GetTag(art::ObjPtr<art::mirror::Object> obj,T * result)81*795d594fSAndroid Build Coastguard Worker   bool GetTag(art::ObjPtr<art::mirror::Object> obj, /* out */ T* result)
82*795d594fSAndroid Build Coastguard Worker       REQUIRES_SHARED(art::Locks::mutator_lock_)
83*795d594fSAndroid Build Coastguard Worker       REQUIRES(!allow_disallow_lock_) {
84*795d594fSAndroid Build Coastguard Worker     art::Thread* self = art::Thread::Current();
85*795d594fSAndroid Build Coastguard Worker     art::MutexLock mu(self, allow_disallow_lock_);
86*795d594fSAndroid Build Coastguard Worker     Wait(self);
87*795d594fSAndroid Build Coastguard Worker 
88*795d594fSAndroid Build Coastguard Worker     return GetTagLocked(self, obj, result);
89*795d594fSAndroid Build Coastguard Worker   }
GetTagLocked(art::ObjPtr<art::mirror::Object> obj,T * result)90*795d594fSAndroid Build Coastguard Worker   bool GetTagLocked(art::ObjPtr<art::mirror::Object> obj, /* out */ T* result)
91*795d594fSAndroid Build Coastguard Worker       REQUIRES_SHARED(art::Locks::mutator_lock_)
92*795d594fSAndroid Build Coastguard Worker       REQUIRES(allow_disallow_lock_) {
93*795d594fSAndroid Build Coastguard Worker     art::Thread* self = art::Thread::Current();
94*795d594fSAndroid Build Coastguard Worker     allow_disallow_lock_.AssertHeld(self);
95*795d594fSAndroid Build Coastguard Worker     Wait(self);
96*795d594fSAndroid Build Coastguard Worker 
97*795d594fSAndroid Build Coastguard Worker     return GetTagLocked(self, obj, result);
98*795d594fSAndroid Build Coastguard Worker   }
99*795d594fSAndroid Build Coastguard Worker 
100*795d594fSAndroid Build Coastguard Worker   // Sweep the container. DO NOT CALL MANUALLY.
101*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE void Sweep(art::IsMarkedVisitor* visitor)
102*795d594fSAndroid Build Coastguard Worker       REQUIRES_SHARED(art::Locks::mutator_lock_)
103*795d594fSAndroid Build Coastguard Worker       REQUIRES(!allow_disallow_lock_);
104*795d594fSAndroid Build Coastguard Worker 
105*795d594fSAndroid Build Coastguard Worker   // Return all objects that have a value mapping in tags.
106*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE
107*795d594fSAndroid Build Coastguard Worker   jvmtiError GetTaggedObjects(jvmtiEnv* jvmti_env,
108*795d594fSAndroid Build Coastguard Worker                               jint tag_count,
109*795d594fSAndroid Build Coastguard Worker                               const T* tags,
110*795d594fSAndroid Build Coastguard Worker                               /* out */ jint* count_ptr,
111*795d594fSAndroid Build Coastguard Worker                               /* out */ jobject** object_result_ptr,
112*795d594fSAndroid Build Coastguard Worker                               /* out */ T** tag_result_ptr)
113*795d594fSAndroid Build Coastguard Worker       REQUIRES_SHARED(art::Locks::mutator_lock_)
114*795d594fSAndroid Build Coastguard Worker       REQUIRES(!allow_disallow_lock_);
115*795d594fSAndroid Build Coastguard Worker 
116*795d594fSAndroid Build Coastguard Worker   // Locking functions, to allow coarse-grained locking and amortization.
117*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE  void Lock() ACQUIRE(allow_disallow_lock_);
118*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE void Unlock() RELEASE(allow_disallow_lock_);
119*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE void AssertLocked() ASSERT_CAPABILITY(allow_disallow_lock_);
120*795d594fSAndroid Build Coastguard Worker 
121*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE art::ObjPtr<art::mirror::Object> Find(T tag)
122*795d594fSAndroid Build Coastguard Worker       REQUIRES_SHARED(art::Locks::mutator_lock_)
123*795d594fSAndroid Build Coastguard Worker       REQUIRES(!allow_disallow_lock_);
124*795d594fSAndroid Build Coastguard Worker 
125*795d594fSAndroid Build Coastguard Worker  protected:
126*795d594fSAndroid Build Coastguard Worker   // Should HandleNullSweep be called when Sweep detects the release of an object?
DoesHandleNullOnSweep()127*795d594fSAndroid Build Coastguard Worker   virtual bool DoesHandleNullOnSweep() {
128*795d594fSAndroid Build Coastguard Worker     return false;
129*795d594fSAndroid Build Coastguard Worker   }
130*795d594fSAndroid Build Coastguard Worker   // If DoesHandleNullOnSweep returns true, this function will be called.
HandleNullSweep(T tag)131*795d594fSAndroid Build Coastguard Worker   virtual void HandleNullSweep([[maybe_unused]] T tag) {}
132*795d594fSAndroid Build Coastguard Worker 
133*795d594fSAndroid Build Coastguard Worker  private:
134*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE
135*795d594fSAndroid Build Coastguard Worker   bool SetLocked(art::Thread* self, art::ObjPtr<art::mirror::Object> obj, T tag)
136*795d594fSAndroid Build Coastguard Worker       REQUIRES_SHARED(art::Locks::mutator_lock_)
137*795d594fSAndroid Build Coastguard Worker       REQUIRES(allow_disallow_lock_);
138*795d594fSAndroid Build Coastguard Worker 
139*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE
140*795d594fSAndroid Build Coastguard Worker   bool RemoveLocked(art::Thread* self, art::ObjPtr<art::mirror::Object> obj, /* out */ T* tag)
141*795d594fSAndroid Build Coastguard Worker       REQUIRES_SHARED(art::Locks::mutator_lock_)
142*795d594fSAndroid Build Coastguard Worker       REQUIRES(allow_disallow_lock_);
143*795d594fSAndroid Build Coastguard Worker 
GetTagLocked(art::Thread * self,art::ObjPtr<art::mirror::Object> obj,T * result)144*795d594fSAndroid Build Coastguard Worker   bool GetTagLocked(art::Thread* self, art::ObjPtr<art::mirror::Object> obj, /* out */ T* result)
145*795d594fSAndroid Build Coastguard Worker       REQUIRES_SHARED(art::Locks::mutator_lock_)
146*795d594fSAndroid Build Coastguard Worker       REQUIRES(allow_disallow_lock_) {
147*795d594fSAndroid Build Coastguard Worker     auto it = tagged_objects_.find(art::GcRoot<art::mirror::Object>(obj));
148*795d594fSAndroid Build Coastguard Worker     if (it != tagged_objects_.end()) {
149*795d594fSAndroid Build Coastguard Worker       *result = it->second;
150*795d594fSAndroid Build Coastguard Worker       return true;
151*795d594fSAndroid Build Coastguard Worker     }
152*795d594fSAndroid Build Coastguard Worker 
153*795d594fSAndroid Build Coastguard Worker     // Performance optimization: To avoid multiple table updates, ensure that during GC we
154*795d594fSAndroid Build Coastguard Worker     // only update once. See the comment on the implementation of GetTagSlowPath.
155*795d594fSAndroid Build Coastguard Worker     if (art::gUseReadBarrier &&
156*795d594fSAndroid Build Coastguard Worker         self != nullptr &&
157*795d594fSAndroid Build Coastguard Worker         self->GetIsGcMarking() &&
158*795d594fSAndroid Build Coastguard Worker         !update_since_last_sweep_) {
159*795d594fSAndroid Build Coastguard Worker       return GetTagSlowPath(self, obj, result);
160*795d594fSAndroid Build Coastguard Worker     }
161*795d594fSAndroid Build Coastguard Worker 
162*795d594fSAndroid Build Coastguard Worker     return false;
163*795d594fSAndroid Build Coastguard Worker   }
164*795d594fSAndroid Build Coastguard Worker 
165*795d594fSAndroid Build Coastguard Worker   // Slow-path for GetTag. We didn't find the object, but we might be storing from-pointers and
166*795d594fSAndroid Build Coastguard Worker   // are asked to retrieve with a to-pointer.
167*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE
168*795d594fSAndroid Build Coastguard Worker   bool GetTagSlowPath(art::Thread* self, art::ObjPtr<art::mirror::Object> obj, /* out */ T* result)
169*795d594fSAndroid Build Coastguard Worker       REQUIRES_SHARED(art::Locks::mutator_lock_)
170*795d594fSAndroid Build Coastguard Worker       REQUIRES(allow_disallow_lock_);
171*795d594fSAndroid Build Coastguard Worker 
172*795d594fSAndroid Build Coastguard Worker   // Update the table by doing read barriers on each element, ensuring that to-space pointers
173*795d594fSAndroid Build Coastguard Worker   // are stored.
174*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE
175*795d594fSAndroid Build Coastguard Worker   void UpdateTableWithReadBarrier()
176*795d594fSAndroid Build Coastguard Worker       REQUIRES_SHARED(art::Locks::mutator_lock_)
177*795d594fSAndroid Build Coastguard Worker       REQUIRES(allow_disallow_lock_);
178*795d594fSAndroid Build Coastguard Worker 
179*795d594fSAndroid Build Coastguard Worker   template <bool kHandleNull>
180*795d594fSAndroid Build Coastguard Worker   void SweepImpl(art::IsMarkedVisitor* visitor)
181*795d594fSAndroid Build Coastguard Worker       REQUIRES_SHARED(art::Locks::mutator_lock_)
182*795d594fSAndroid Build Coastguard Worker       REQUIRES(!allow_disallow_lock_);
183*795d594fSAndroid Build Coastguard Worker 
184*795d594fSAndroid Build Coastguard Worker   enum TableUpdateNullTarget {
185*795d594fSAndroid Build Coastguard Worker     kIgnoreNull,
186*795d594fSAndroid Build Coastguard Worker     kRemoveNull,
187*795d594fSAndroid Build Coastguard Worker     kCallHandleNull
188*795d594fSAndroid Build Coastguard Worker   };
189*795d594fSAndroid Build Coastguard Worker 
190*795d594fSAndroid Build Coastguard Worker   template <typename Updater, TableUpdateNullTarget kTargetNull>
191*795d594fSAndroid Build Coastguard Worker   void UpdateTableWith(Updater& updater)
192*795d594fSAndroid Build Coastguard Worker       REQUIRES_SHARED(art::Locks::mutator_lock_)
193*795d594fSAndroid Build Coastguard Worker       REQUIRES(allow_disallow_lock_);
194*795d594fSAndroid Build Coastguard Worker 
195*795d594fSAndroid Build Coastguard Worker   template <typename Storage, class Allocator = JvmtiAllocator<T>>
196*795d594fSAndroid Build Coastguard Worker   struct ReleasableContainer;
197*795d594fSAndroid Build Coastguard Worker 
198*795d594fSAndroid Build Coastguard Worker   struct HashGcRoot {
operatorHashGcRoot199*795d594fSAndroid Build Coastguard Worker     size_t operator()(const art::GcRoot<art::mirror::Object>& r) const
200*795d594fSAndroid Build Coastguard Worker         REQUIRES_SHARED(art::Locks::mutator_lock_) {
201*795d594fSAndroid Build Coastguard Worker       return reinterpret_cast<uintptr_t>(r.Read<art::kWithoutReadBarrier>());
202*795d594fSAndroid Build Coastguard Worker     }
203*795d594fSAndroid Build Coastguard Worker   };
204*795d594fSAndroid Build Coastguard Worker 
205*795d594fSAndroid Build Coastguard Worker   struct EqGcRoot {
operatorEqGcRoot206*795d594fSAndroid Build Coastguard Worker     bool operator()(const art::GcRoot<art::mirror::Object>& r1,
207*795d594fSAndroid Build Coastguard Worker                     const art::GcRoot<art::mirror::Object>& r2) const
208*795d594fSAndroid Build Coastguard Worker         REQUIRES_SHARED(art::Locks::mutator_lock_) {
209*795d594fSAndroid Build Coastguard Worker       return r1.Read<art::kWithoutReadBarrier>() == r2.Read<art::kWithoutReadBarrier>();
210*795d594fSAndroid Build Coastguard Worker     }
211*795d594fSAndroid Build Coastguard Worker   };
212*795d594fSAndroid Build Coastguard Worker 
213*795d594fSAndroid Build Coastguard Worker   using TagAllocator = JvmtiAllocator<std::pair<const art::GcRoot<art::mirror::Object>, T>>;
214*795d594fSAndroid Build Coastguard Worker   using TagMap = std::unordered_map<art::GcRoot<art::mirror::Object>,
215*795d594fSAndroid Build Coastguard Worker                                     T,
216*795d594fSAndroid Build Coastguard Worker                                     HashGcRoot,
217*795d594fSAndroid Build Coastguard Worker                                     EqGcRoot,
218*795d594fSAndroid Build Coastguard Worker                                     TagAllocator>;
219*795d594fSAndroid Build Coastguard Worker 
220*795d594fSAndroid Build Coastguard Worker   TagMap tagged_objects_ GUARDED_BY(allow_disallow_lock_) GUARDED_BY(art::Locks::mutator_lock_);
221*795d594fSAndroid Build Coastguard Worker   // To avoid repeatedly scanning the whole table, remember if we did that since the last sweep.
222*795d594fSAndroid Build Coastguard Worker   bool update_since_last_sweep_;
223*795d594fSAndroid Build Coastguard Worker };
224*795d594fSAndroid Build Coastguard Worker 
225*795d594fSAndroid Build Coastguard Worker }  // namespace openjdkjvmti
226*795d594fSAndroid Build Coastguard Worker 
227*795d594fSAndroid Build Coastguard Worker #endif  // ART_OPENJDKJVMTI_JVMTI_WEAK_TABLE_H_
228