1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef ART_RUNTIME_MONITOR_POOL_H_
18 #define ART_RUNTIME_MONITOR_POOL_H_
19 
20 #include "monitor.h"
21 
22 #include "base/allocator.h"
23 #ifdef __LP64__
24 #include <stdint.h>
25 #include "atomic.h"
26 #include "runtime.h"
27 #else
28 #include "base/stl_util.h"     // STLDeleteElements
29 #endif
30 
31 namespace art {
32 
33 // Abstraction to keep monitors small enough to fit in a lock word (32bits). On 32bit systems the
34 // monitor id loses the alignment bits of the Monitor*.
35 class MonitorPool {
36  public:
Create()37   static MonitorPool* Create() {
38 #ifndef __LP64__
39     return nullptr;
40 #else
41     return new MonitorPool();
42 #endif
43   }
44 
CreateMonitor(Thread * self,Thread * owner,mirror::Object * obj,int32_t hash_code)45   static Monitor* CreateMonitor(Thread* self, Thread* owner, mirror::Object* obj, int32_t hash_code)
46       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
47 #ifndef __LP64__
48     Monitor* mon = new Monitor(self, owner, obj, hash_code);
49     DCHECK_ALIGNED(mon, LockWord::kMonitorIdAlignment);
50     return mon;
51 #else
52     return GetMonitorPool()->CreateMonitorInPool(self, owner, obj, hash_code);
53 #endif
54   }
55 
ReleaseMonitor(Thread * self,Monitor * monitor)56   static void ReleaseMonitor(Thread* self, Monitor* monitor) {
57 #ifndef __LP64__
58     UNUSED(self);
59     delete monitor;
60 #else
61     GetMonitorPool()->ReleaseMonitorToPool(self, monitor);
62 #endif
63   }
64 
ReleaseMonitors(Thread * self,MonitorList::Monitors * monitors)65   static void ReleaseMonitors(Thread* self, MonitorList::Monitors* monitors) {
66 #ifndef __LP64__
67     UNUSED(self);
68     STLDeleteElements(monitors);
69 #else
70     GetMonitorPool()->ReleaseMonitorsToPool(self, monitors);
71 #endif
72   }
73 
MonitorFromMonitorId(MonitorId mon_id)74   static Monitor* MonitorFromMonitorId(MonitorId mon_id) {
75 #ifndef __LP64__
76     return reinterpret_cast<Monitor*>(mon_id << LockWord::kMonitorIdAlignmentShift);
77 #else
78     return GetMonitorPool()->LookupMonitor(mon_id);
79 #endif
80   }
81 
MonitorIdFromMonitor(Monitor * mon)82   static MonitorId MonitorIdFromMonitor(Monitor* mon) {
83 #ifndef __LP64__
84     return reinterpret_cast<MonitorId>(mon) >> LockWord::kMonitorIdAlignmentShift;
85 #else
86     return mon->GetMonitorId();
87 #endif
88   }
89 
ComputeMonitorId(Monitor * mon,Thread * self)90   static MonitorId ComputeMonitorId(Monitor* mon, Thread* self) {
91 #ifndef __LP64__
92     UNUSED(self);
93     return MonitorIdFromMonitor(mon);
94 #else
95     return GetMonitorPool()->ComputeMonitorIdInPool(mon, self);
96 #endif
97   }
98 
GetMonitorPool()99   static MonitorPool* GetMonitorPool() {
100 #ifndef __LP64__
101     return nullptr;
102 #else
103     return Runtime::Current()->GetMonitorPool();
104 #endif
105   }
106 
107  private:
108 #ifdef __LP64__
109   // When we create a monitor pool, threads have not been initialized, yet, so ignore thread-safety
110   // analysis.
111   MonitorPool() NO_THREAD_SAFETY_ANALYSIS;
112 
113   void AllocateChunk() EXCLUSIVE_LOCKS_REQUIRED(Locks::allocated_monitor_ids_lock_);
114 
115   Monitor* CreateMonitorInPool(Thread* self, Thread* owner, mirror::Object* obj, int32_t hash_code)
116       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
117 
118   void ReleaseMonitorToPool(Thread* self, Monitor* monitor);
119   void ReleaseMonitorsToPool(Thread* self, MonitorList::Monitors* monitors);
120 
121   // Note: This is safe as we do not ever move chunks.
LookupMonitor(MonitorId mon_id)122   Monitor* LookupMonitor(MonitorId mon_id) {
123     size_t offset = MonitorIdToOffset(mon_id);
124     size_t index = offset / kChunkSize;
125     size_t offset_in_chunk = offset % kChunkSize;
126     uintptr_t base = *(monitor_chunks_.LoadRelaxed()+index);
127     return reinterpret_cast<Monitor*>(base + offset_in_chunk);
128   }
129 
IsInChunk(uintptr_t base_addr,Monitor * mon)130   static bool IsInChunk(uintptr_t base_addr, Monitor* mon) {
131     uintptr_t mon_ptr = reinterpret_cast<uintptr_t>(mon);
132     return base_addr <= mon_ptr && (mon_ptr - base_addr < kChunkSize);
133   }
134 
135   // Note: This is safe as we do not ever move chunks.
ComputeMonitorIdInPool(Monitor * mon,Thread * self)136   MonitorId ComputeMonitorIdInPool(Monitor* mon, Thread* self) {
137     MutexLock mu(self, *Locks::allocated_monitor_ids_lock_);
138     for (size_t index = 0; index < num_chunks_; ++index) {
139       uintptr_t chunk_addr = *(monitor_chunks_.LoadRelaxed() + index);
140       if (IsInChunk(chunk_addr, mon)) {
141         return OffsetToMonitorId(
142             reinterpret_cast<uintptr_t>(mon) - chunk_addr + index * kChunkSize);
143       }
144     }
145     LOG(FATAL) << "Did not find chunk that contains monitor.";
146     return 0;
147   }
148 
MonitorIdToOffset(MonitorId id)149   static size_t MonitorIdToOffset(MonitorId id) {
150     return id << 3;
151   }
152 
OffsetToMonitorId(size_t offset)153   static MonitorId OffsetToMonitorId(size_t offset) {
154     return static_cast<MonitorId>(offset >> 3);
155   }
156 
157   // TODO: There are assumptions in the code that monitor addresses are 8B aligned (>>3).
158   static constexpr size_t kMonitorAlignment = 8;
159   // Size of a monitor, rounded up to a multiple of alignment.
160   static constexpr size_t kAlignedMonitorSize = (sizeof(Monitor) + kMonitorAlignment - 1) &
161                                                 -kMonitorAlignment;
162   // As close to a page as we can get seems a good start.
163   static constexpr size_t kChunkCapacity = kPageSize / kAlignedMonitorSize;
164   // Chunk size that is referenced in the id. We can collapse this to the actually used storage
165   // in a chunk, i.e., kChunkCapacity * kAlignedMonitorSize, but this will mean proper divisions.
166   static constexpr size_t kChunkSize = kPageSize;
167   // The number of initial chunks storable in monitor_chunks_. The number is large enough to make
168   // resizing unlikely, but small enough to not waste too much memory.
169   static constexpr size_t kInitialChunkStorage = 8U;
170 
171   // List of memory chunks. Each chunk is kChunkSize.
172   Atomic<uintptr_t*> monitor_chunks_;
173   // Number of chunks stored.
174   size_t num_chunks_ GUARDED_BY(Locks::allocated_monitor_ids_lock_);
175   // Number of chunks storable.
176   size_t capacity_ GUARDED_BY(Locks::allocated_monitor_ids_lock_);
177 
178   // To avoid race issues when resizing, we keep all the previous arrays.
179   std::vector<uintptr_t*> old_chunk_arrays_ GUARDED_BY(Locks::allocated_monitor_ids_lock_);
180 
181   typedef TrackingAllocator<uint8_t, kAllocatorTagMonitorPool> Allocator;
182   Allocator allocator_;
183 
184   // Start of free list of monitors.
185   // Note: these point to the right memory regions, but do *not* denote initialized objects.
186   Monitor* first_free_ GUARDED_BY(Locks::allocated_monitor_ids_lock_);
187 #endif
188 };
189 
190 }  // namespace art
191 
192 #endif  // ART_RUNTIME_MONITOR_POOL_H_
193