xref: /aosp_15_r20/art/runtime/monitor_pool.h (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2014 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 #ifndef ART_RUNTIME_MONITOR_POOL_H_
18*795d594fSAndroid Build Coastguard Worker #define ART_RUNTIME_MONITOR_POOL_H_
19*795d594fSAndroid Build Coastguard Worker 
20*795d594fSAndroid Build Coastguard Worker #include "monitor.h"
21*795d594fSAndroid Build Coastguard Worker 
22*795d594fSAndroid Build Coastguard Worker #include "base/allocator.h"
23*795d594fSAndroid Build Coastguard Worker #include "base/macros.h"
24*795d594fSAndroid Build Coastguard Worker #ifdef __LP64__
25*795d594fSAndroid Build Coastguard Worker #include <stdint.h>
26*795d594fSAndroid Build Coastguard Worker #include "base/atomic.h"
27*795d594fSAndroid Build Coastguard Worker #include "runtime.h"
28*795d594fSAndroid Build Coastguard Worker #else
29*795d594fSAndroid Build Coastguard Worker #include "base/stl_util.h"     // STLDeleteElements
30*795d594fSAndroid Build Coastguard Worker #endif
31*795d594fSAndroid Build Coastguard Worker 
32*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
33*795d594fSAndroid Build Coastguard Worker 
34*795d594fSAndroid Build Coastguard Worker // Abstraction to keep monitors small enough to fit in a lock word (32bits). On 32bit systems the
35*795d594fSAndroid Build Coastguard Worker // monitor id loses the alignment bits of the Monitor*.
36*795d594fSAndroid Build Coastguard Worker class MonitorPool {
37*795d594fSAndroid Build Coastguard Worker  public:
Create()38*795d594fSAndroid Build Coastguard Worker   static MonitorPool* Create() {
39*795d594fSAndroid Build Coastguard Worker #ifndef __LP64__
40*795d594fSAndroid Build Coastguard Worker     return nullptr;
41*795d594fSAndroid Build Coastguard Worker #else
42*795d594fSAndroid Build Coastguard Worker     return new MonitorPool();
43*795d594fSAndroid Build Coastguard Worker #endif
44*795d594fSAndroid Build Coastguard Worker   }
45*795d594fSAndroid Build Coastguard Worker 
CreateMonitor(Thread * self,Thread * owner,ObjPtr<mirror::Object> obj,int32_t hash_code)46*795d594fSAndroid Build Coastguard Worker   static Monitor* CreateMonitor(Thread* self,
47*795d594fSAndroid Build Coastguard Worker                                 Thread* owner,
48*795d594fSAndroid Build Coastguard Worker                                 ObjPtr<mirror::Object> obj,
49*795d594fSAndroid Build Coastguard Worker                                 int32_t hash_code)
50*795d594fSAndroid Build Coastguard Worker       REQUIRES_SHARED(Locks::mutator_lock_) {
51*795d594fSAndroid Build Coastguard Worker #ifndef __LP64__
52*795d594fSAndroid Build Coastguard Worker     Monitor* mon = new Monitor(self, owner, obj, hash_code);
53*795d594fSAndroid Build Coastguard Worker     DCHECK_ALIGNED(mon, LockWord::kMonitorIdAlignment);
54*795d594fSAndroid Build Coastguard Worker     return mon;
55*795d594fSAndroid Build Coastguard Worker #else
56*795d594fSAndroid Build Coastguard Worker     return GetMonitorPool()->CreateMonitorInPool(self, owner, obj, hash_code);
57*795d594fSAndroid Build Coastguard Worker #endif
58*795d594fSAndroid Build Coastguard Worker   }
59*795d594fSAndroid Build Coastguard Worker 
ReleaseMonitor(Thread * self,Monitor * monitor)60*795d594fSAndroid Build Coastguard Worker   static void ReleaseMonitor(Thread* self, Monitor* monitor) {
61*795d594fSAndroid Build Coastguard Worker #ifndef __LP64__
62*795d594fSAndroid Build Coastguard Worker     UNUSED(self);
63*795d594fSAndroid Build Coastguard Worker     delete monitor;
64*795d594fSAndroid Build Coastguard Worker #else
65*795d594fSAndroid Build Coastguard Worker     GetMonitorPool()->ReleaseMonitorToPool(self, monitor);
66*795d594fSAndroid Build Coastguard Worker #endif
67*795d594fSAndroid Build Coastguard Worker   }
68*795d594fSAndroid Build Coastguard Worker 
ReleaseMonitors(Thread * self,MonitorList::Monitors * monitors)69*795d594fSAndroid Build Coastguard Worker   static void ReleaseMonitors(Thread* self, MonitorList::Monitors* monitors) {
70*795d594fSAndroid Build Coastguard Worker #ifndef __LP64__
71*795d594fSAndroid Build Coastguard Worker     UNUSED(self);
72*795d594fSAndroid Build Coastguard Worker     STLDeleteElements(monitors);
73*795d594fSAndroid Build Coastguard Worker #else
74*795d594fSAndroid Build Coastguard Worker     GetMonitorPool()->ReleaseMonitorsToPool(self, monitors);
75*795d594fSAndroid Build Coastguard Worker #endif
76*795d594fSAndroid Build Coastguard Worker   }
77*795d594fSAndroid Build Coastguard Worker 
MonitorFromMonitorId(MonitorId mon_id)78*795d594fSAndroid Build Coastguard Worker   static Monitor* MonitorFromMonitorId(MonitorId mon_id) {
79*795d594fSAndroid Build Coastguard Worker #ifndef __LP64__
80*795d594fSAndroid Build Coastguard Worker     return reinterpret_cast<Monitor*>(mon_id << LockWord::kMonitorIdAlignmentShift);
81*795d594fSAndroid Build Coastguard Worker #else
82*795d594fSAndroid Build Coastguard Worker     return GetMonitorPool()->LookupMonitor(mon_id);
83*795d594fSAndroid Build Coastguard Worker #endif
84*795d594fSAndroid Build Coastguard Worker   }
85*795d594fSAndroid Build Coastguard Worker 
MonitorIdFromMonitor(Monitor * mon)86*795d594fSAndroid Build Coastguard Worker   static MonitorId MonitorIdFromMonitor(Monitor* mon) {
87*795d594fSAndroid Build Coastguard Worker #ifndef __LP64__
88*795d594fSAndroid Build Coastguard Worker     return reinterpret_cast<MonitorId>(mon) >> LockWord::kMonitorIdAlignmentShift;
89*795d594fSAndroid Build Coastguard Worker #else
90*795d594fSAndroid Build Coastguard Worker     return mon->GetMonitorId();
91*795d594fSAndroid Build Coastguard Worker #endif
92*795d594fSAndroid Build Coastguard Worker   }
93*795d594fSAndroid Build Coastguard Worker 
ComputeMonitorId(Monitor * mon,Thread * self)94*795d594fSAndroid Build Coastguard Worker   static MonitorId ComputeMonitorId(Monitor* mon, Thread* self) {
95*795d594fSAndroid Build Coastguard Worker #ifndef __LP64__
96*795d594fSAndroid Build Coastguard Worker     UNUSED(self);
97*795d594fSAndroid Build Coastguard Worker     return MonitorIdFromMonitor(mon);
98*795d594fSAndroid Build Coastguard Worker #else
99*795d594fSAndroid Build Coastguard Worker     return GetMonitorPool()->ComputeMonitorIdInPool(mon, self);
100*795d594fSAndroid Build Coastguard Worker #endif
101*795d594fSAndroid Build Coastguard Worker   }
102*795d594fSAndroid Build Coastguard Worker 
GetMonitorPool()103*795d594fSAndroid Build Coastguard Worker   static MonitorPool* GetMonitorPool() {
104*795d594fSAndroid Build Coastguard Worker #ifndef __LP64__
105*795d594fSAndroid Build Coastguard Worker     return nullptr;
106*795d594fSAndroid Build Coastguard Worker #else
107*795d594fSAndroid Build Coastguard Worker     return Runtime::Current()->GetMonitorPool();
108*795d594fSAndroid Build Coastguard Worker #endif
109*795d594fSAndroid Build Coastguard Worker   }
110*795d594fSAndroid Build Coastguard Worker 
~MonitorPool()111*795d594fSAndroid Build Coastguard Worker   ~MonitorPool() {
112*795d594fSAndroid Build Coastguard Worker #ifdef __LP64__
113*795d594fSAndroid Build Coastguard Worker     FreeInternal();
114*795d594fSAndroid Build Coastguard Worker #endif
115*795d594fSAndroid Build Coastguard Worker   }
116*795d594fSAndroid Build Coastguard Worker 
117*795d594fSAndroid Build Coastguard Worker  private:
118*795d594fSAndroid Build Coastguard Worker #ifdef __LP64__
119*795d594fSAndroid Build Coastguard Worker   // When we create a monitor pool, threads have not been initialized, yet, so ignore thread-safety
120*795d594fSAndroid Build Coastguard Worker   // analysis.
121*795d594fSAndroid Build Coastguard Worker   MonitorPool() NO_THREAD_SAFETY_ANALYSIS;
122*795d594fSAndroid Build Coastguard Worker 
123*795d594fSAndroid Build Coastguard Worker   void AllocateChunk() REQUIRES(Locks::allocated_monitor_ids_lock_);
124*795d594fSAndroid Build Coastguard Worker 
125*795d594fSAndroid Build Coastguard Worker   // Release all chunks and metadata. This is done on shutdown, where threads have been destroyed,
126*795d594fSAndroid Build Coastguard Worker   // so ignore thead-safety analysis.
127*795d594fSAndroid Build Coastguard Worker   void FreeInternal() NO_THREAD_SAFETY_ANALYSIS;
128*795d594fSAndroid Build Coastguard Worker 
129*795d594fSAndroid Build Coastguard Worker   Monitor* CreateMonitorInPool(Thread* self,
130*795d594fSAndroid Build Coastguard Worker                                Thread* owner,
131*795d594fSAndroid Build Coastguard Worker                                ObjPtr<mirror::Object> obj,
132*795d594fSAndroid Build Coastguard Worker                                int32_t hash_code)
133*795d594fSAndroid Build Coastguard Worker       REQUIRES_SHARED(Locks::mutator_lock_);
134*795d594fSAndroid Build Coastguard Worker 
135*795d594fSAndroid Build Coastguard Worker   void ReleaseMonitorToPool(Thread* self, Monitor* monitor);
136*795d594fSAndroid Build Coastguard Worker   void ReleaseMonitorsToPool(Thread* self, MonitorList::Monitors* monitors);
137*795d594fSAndroid Build Coastguard Worker 
138*795d594fSAndroid Build Coastguard Worker   // Note: This is safe as we do not ever move chunks.  All needed entries in the monitor_chunks_
139*795d594fSAndroid Build Coastguard Worker   // data structure are read-only once we get here.  Updates happen-before this call because
140*795d594fSAndroid Build Coastguard Worker   // the lock word was stored with release semantics and we read it with acquire semantics to
141*795d594fSAndroid Build Coastguard Worker   // retrieve the id.
LookupMonitor(MonitorId mon_id)142*795d594fSAndroid Build Coastguard Worker   Monitor* LookupMonitor(MonitorId mon_id) {
143*795d594fSAndroid Build Coastguard Worker     size_t offset = MonitorIdToOffset(mon_id);
144*795d594fSAndroid Build Coastguard Worker     size_t index = offset / kChunkSize;
145*795d594fSAndroid Build Coastguard Worker     size_t top_index = index / kMaxListSize;
146*795d594fSAndroid Build Coastguard Worker     size_t list_index = index % kMaxListSize;
147*795d594fSAndroid Build Coastguard Worker     size_t offset_in_chunk = offset % kChunkSize;
148*795d594fSAndroid Build Coastguard Worker     uintptr_t base = monitor_chunks_[top_index][list_index];
149*795d594fSAndroid Build Coastguard Worker     return reinterpret_cast<Monitor*>(base + offset_in_chunk);
150*795d594fSAndroid Build Coastguard Worker   }
151*795d594fSAndroid Build Coastguard Worker 
IsInChunk(uintptr_t base_addr,Monitor * mon)152*795d594fSAndroid Build Coastguard Worker   static bool IsInChunk(uintptr_t base_addr, Monitor* mon) {
153*795d594fSAndroid Build Coastguard Worker     uintptr_t mon_ptr = reinterpret_cast<uintptr_t>(mon);
154*795d594fSAndroid Build Coastguard Worker     return base_addr <= mon_ptr && (mon_ptr - base_addr < kChunkSize);
155*795d594fSAndroid Build Coastguard Worker   }
156*795d594fSAndroid Build Coastguard Worker 
ComputeMonitorIdInPool(Monitor * mon,Thread * self)157*795d594fSAndroid Build Coastguard Worker   MonitorId ComputeMonitorIdInPool(Monitor* mon, Thread* self) {
158*795d594fSAndroid Build Coastguard Worker     MutexLock mu(self, *Locks::allocated_monitor_ids_lock_);
159*795d594fSAndroid Build Coastguard Worker     for (size_t i = 0; i <= current_chunk_list_index_; ++i) {
160*795d594fSAndroid Build Coastguard Worker       for (size_t j = 0; j < ChunkListCapacity(i); ++j) {
161*795d594fSAndroid Build Coastguard Worker         if (j >= num_chunks_ && i == current_chunk_list_index_) {
162*795d594fSAndroid Build Coastguard Worker           break;
163*795d594fSAndroid Build Coastguard Worker         }
164*795d594fSAndroid Build Coastguard Worker         uintptr_t chunk_addr = monitor_chunks_[i][j];
165*795d594fSAndroid Build Coastguard Worker         if (IsInChunk(chunk_addr, mon)) {
166*795d594fSAndroid Build Coastguard Worker           return OffsetToMonitorId(
167*795d594fSAndroid Build Coastguard Worker               reinterpret_cast<uintptr_t>(mon) - chunk_addr
168*795d594fSAndroid Build Coastguard Worker               + i * (kMaxListSize * kChunkSize) + j * kChunkSize);
169*795d594fSAndroid Build Coastguard Worker         }
170*795d594fSAndroid Build Coastguard Worker       }
171*795d594fSAndroid Build Coastguard Worker     }
172*795d594fSAndroid Build Coastguard Worker     LOG(FATAL) << "Did not find chunk that contains monitor.";
173*795d594fSAndroid Build Coastguard Worker     return 0;
174*795d594fSAndroid Build Coastguard Worker   }
175*795d594fSAndroid Build Coastguard Worker 
MonitorIdToOffset(MonitorId id)176*795d594fSAndroid Build Coastguard Worker   static constexpr size_t MonitorIdToOffset(MonitorId id) {
177*795d594fSAndroid Build Coastguard Worker     return id << 3;
178*795d594fSAndroid Build Coastguard Worker   }
179*795d594fSAndroid Build Coastguard Worker 
OffsetToMonitorId(size_t offset)180*795d594fSAndroid Build Coastguard Worker   static constexpr MonitorId OffsetToMonitorId(size_t offset) {
181*795d594fSAndroid Build Coastguard Worker     return static_cast<MonitorId>(offset >> 3);
182*795d594fSAndroid Build Coastguard Worker   }
183*795d594fSAndroid Build Coastguard Worker 
ChunkListCapacity(size_t index)184*795d594fSAndroid Build Coastguard Worker   static constexpr size_t ChunkListCapacity(size_t index) {
185*795d594fSAndroid Build Coastguard Worker     return kInitialChunkStorage << index;
186*795d594fSAndroid Build Coastguard Worker   }
187*795d594fSAndroid Build Coastguard Worker 
188*795d594fSAndroid Build Coastguard Worker   // TODO: There are assumptions in the code that monitor addresses are 8B aligned (>>3).
189*795d594fSAndroid Build Coastguard Worker   static constexpr size_t kMonitorAlignment = 8;
190*795d594fSAndroid Build Coastguard Worker   // Size of a monitor, rounded up to a multiple of alignment.
191*795d594fSAndroid Build Coastguard Worker   static constexpr size_t kAlignedMonitorSize = (sizeof(Monitor) + kMonitorAlignment - 1) &
192*795d594fSAndroid Build Coastguard Worker                                                 -kMonitorAlignment;
193*795d594fSAndroid Build Coastguard Worker   // Size of the chunks holding the actual monitors. The bottom bits of the monitor id are the
194*795d594fSAndroid Build Coastguard Worker   // index into such a chunk. We can collapse this to the actually used storage
195*795d594fSAndroid Build Coastguard Worker   // in a chunk, i.e., kChunkCapacity * kAlignedMonitorSize, but this would mean proper divisions.
196*795d594fSAndroid Build Coastguard Worker   static constexpr size_t kChunkSize = 4096;
197*795d594fSAndroid Build Coastguard Worker   static_assert(IsPowerOfTwo(kChunkSize), "kChunkSize must be power of 2");
198*795d594fSAndroid Build Coastguard Worker   static constexpr size_t kChunkCapacity = kChunkSize / kAlignedMonitorSize;
199*795d594fSAndroid Build Coastguard Worker   // The number of chunks of storage that can be referenced by the initial chunk list.
200*795d594fSAndroid Build Coastguard Worker   // The total number of usable monitor chunks is typically 255 times this number, so it
201*795d594fSAndroid Build Coastguard Worker   // should be large enough that we don't run out. We run out of address bits if it's > 512.
202*795d594fSAndroid Build Coastguard Worker   // Currently we set it a bit smaller, to save half a page per process.  We make it tiny in
203*795d594fSAndroid Build Coastguard Worker   // debug builds to catch growth errors. The only value we really expect to tune.
204*795d594fSAndroid Build Coastguard Worker   static constexpr size_t kInitialChunkStorage = kIsDebugBuild ? 8U : 256U;
205*795d594fSAndroid Build Coastguard Worker   static_assert(IsPowerOfTwo(kInitialChunkStorage), "kInitialChunkStorage must be power of 2");
206*795d594fSAndroid Build Coastguard Worker   // The number of lists, each containing pointers to storage chunks.
207*795d594fSAndroid Build Coastguard Worker   static constexpr size_t kMaxChunkLists = 8;  //  Dictated by 3 bit index. Don't increase above 8.
208*795d594fSAndroid Build Coastguard Worker   static_assert(IsPowerOfTwo(kMaxChunkLists), "kMaxChunkLists must be power of 2");
209*795d594fSAndroid Build Coastguard Worker   static constexpr size_t kMaxListSize = kInitialChunkStorage << (kMaxChunkLists - 1);
210*795d594fSAndroid Build Coastguard Worker   // We lose 3 bits in monitor id due to 3 bit monitor_chunks_ index, and gain it back from
211*795d594fSAndroid Build Coastguard Worker   // the 3 bit alignment constraint on monitors:
212*795d594fSAndroid Build Coastguard Worker   static_assert(kMaxListSize * kChunkSize < (1 << LockWord::kMonitorIdSize),
213*795d594fSAndroid Build Coastguard Worker       "Monitor id bits don't fit");
214*795d594fSAndroid Build Coastguard Worker   static_assert(IsPowerOfTwo(kMaxListSize), "kMaxListSize must be power of 2");
215*795d594fSAndroid Build Coastguard Worker 
216*795d594fSAndroid Build Coastguard Worker   // Array of pointers to lists (again arrays) of pointers to chunks containing monitors.
217*795d594fSAndroid Build Coastguard Worker   // Zeroth entry points to a list (array) of kInitialChunkStorage pointers to chunks.
218*795d594fSAndroid Build Coastguard Worker   // Each subsequent list as twice as large as the preceding one.
219*795d594fSAndroid Build Coastguard Worker   // Monitor Ids are effectively interpreted as follows:
220*795d594fSAndroid Build Coastguard Worker   //     Top 3 bits (of 28): index into monitor_chunks_.
221*795d594fSAndroid Build Coastguard Worker   //     Next 16 bits: index into the chunk list, i.e. monitor_chunks_[i].
222*795d594fSAndroid Build Coastguard Worker   //     Last 9 bits: offset within chunk, expressed as multiple of kMonitorAlignment.
223*795d594fSAndroid Build Coastguard Worker   // If we set kInitialChunkStorage to 512, this would allow us to use roughly 128K chunks of
224*795d594fSAndroid Build Coastguard Worker   // monitors, which is 0.5GB of monitors.  With this maximum setting, the largest chunk list
225*795d594fSAndroid Build Coastguard Worker   // contains 64K entries, and we make full use of the available index space. With a
226*795d594fSAndroid Build Coastguard Worker   // kInitialChunkStorage value of 256, this is proportionately reduced to 0.25GB of monitors.
227*795d594fSAndroid Build Coastguard Worker   // Updates to monitor_chunks_ are guarded by allocated_monitor_ids_lock_ .
228*795d594fSAndroid Build Coastguard Worker   // No field in this entire data structure is ever updated once a monitor id whose lookup
229*795d594fSAndroid Build Coastguard Worker   // requires it has been made visible to another thread.  Thus readers never race with
230*795d594fSAndroid Build Coastguard Worker   // updates, in spite of the fact that they acquire no locks.
231*795d594fSAndroid Build Coastguard Worker   uintptr_t* monitor_chunks_[kMaxChunkLists];  //  uintptr_t is really a Monitor* .
232*795d594fSAndroid Build Coastguard Worker   // Highest currently used index in monitor_chunks_ . Used for newly allocated chunks.
233*795d594fSAndroid Build Coastguard Worker   size_t current_chunk_list_index_ GUARDED_BY(Locks::allocated_monitor_ids_lock_);
234*795d594fSAndroid Build Coastguard Worker   // Number of chunk pointers stored in monitor_chunks_[current_chunk_list_index_] so far.
235*795d594fSAndroid Build Coastguard Worker   size_t num_chunks_ GUARDED_BY(Locks::allocated_monitor_ids_lock_);
236*795d594fSAndroid Build Coastguard Worker   // After the initial allocation, this is always equal to
237*795d594fSAndroid Build Coastguard Worker   // ChunkListCapacity(current_chunk_list_index_).
238*795d594fSAndroid Build Coastguard Worker   size_t current_chunk_list_capacity_ GUARDED_BY(Locks::allocated_monitor_ids_lock_);
239*795d594fSAndroid Build Coastguard Worker 
240*795d594fSAndroid Build Coastguard Worker   using Allocator = TrackingAllocator<uint8_t, kAllocatorTagMonitorPool>;
241*795d594fSAndroid Build Coastguard Worker   Allocator allocator_;
242*795d594fSAndroid Build Coastguard Worker 
243*795d594fSAndroid Build Coastguard Worker   // Start of free list of monitors.
244*795d594fSAndroid Build Coastguard Worker   // Note: these point to the right memory regions, but do *not* denote initialized objects.
245*795d594fSAndroid Build Coastguard Worker   Monitor* first_free_ GUARDED_BY(Locks::allocated_monitor_ids_lock_);
246*795d594fSAndroid Build Coastguard Worker #endif
247*795d594fSAndroid Build Coastguard Worker };
248*795d594fSAndroid Build Coastguard Worker 
249*795d594fSAndroid Build Coastguard Worker }  // namespace art
250*795d594fSAndroid Build Coastguard Worker 
251*795d594fSAndroid Build Coastguard Worker #endif  // ART_RUNTIME_MONITOR_POOL_H_
252