blob: 875b3fe73d9d72223aff96847eaa5b7d9a92cdc5 [file] [log] [blame]
Ian Rogersef7d42f2014-01-06 12:55:46 -08001/*
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
Ian Rogersb0fa5dc2014-04-28 16:47:08 -070020#include "monitor.h"
21
Mathieu Chartierbad02672014-08-25 13:08:22 -070022#include "base/allocator.h"
Ian Rogers44d6ff12014-03-06 23:11:11 -080023#ifdef __LP64__
Ian Rogersef7d42f2014-01-06 12:55:46 -080024#include <stdint.h>
Andreas Gampe74240812014-04-17 10:35:09 -070025#include "atomic.h"
Ian Rogers44d6ff12014-03-06 23:11:11 -080026#include "runtime.h"
Andreas Gampe74240812014-04-17 10:35:09 -070027#else
28#include "base/stl_util.h" // STLDeleteElements
Ian Rogers44d6ff12014-03-06 23:11:11 -080029#endif
30
Ian Rogersef7d42f2014-01-06 12:55:46 -080031namespace 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*.
35class MonitorPool {
36 public:
37 static MonitorPool* Create() {
38#ifndef __LP64__
39 return nullptr;
40#else
41 return new MonitorPool();
42#endif
43 }
44
Andreas Gampe74240812014-04-17 10:35:09 -070045 static Monitor* CreateMonitor(Thread* self, Thread* owner, mirror::Object* obj, int32_t hash_code)
Mathieu Chartier90443472015-07-16 20:32:27 -070046 SHARED_REQUIRES(Locks::mutator_lock_) {
Andreas Gampe74240812014-04-17 10:35:09 -070047#ifndef __LP64__
Hiroshi Yamauchie15ea082015-02-09 17:11:42 -080048 Monitor* mon = new Monitor(self, owner, obj, hash_code);
49 DCHECK_ALIGNED(mon, LockWord::kMonitorIdAlignment);
50 return mon;
Andreas Gampe74240812014-04-17 10:35:09 -070051#else
52 return GetMonitorPool()->CreateMonitorInPool(self, owner, obj, hash_code);
53#endif
54 }
55
56 static void ReleaseMonitor(Thread* self, Monitor* monitor) {
57#ifndef __LP64__
Ian Rogers6a3c1fc2014-10-31 00:33:20 -070058 UNUSED(self);
Andreas Gampe74240812014-04-17 10:35:09 -070059 delete monitor;
60#else
61 GetMonitorPool()->ReleaseMonitorToPool(self, monitor);
62#endif
63 }
64
Mathieu Chartierbad02672014-08-25 13:08:22 -070065 static void ReleaseMonitors(Thread* self, MonitorList::Monitors* monitors) {
Andreas Gampe74240812014-04-17 10:35:09 -070066#ifndef __LP64__
Ian Rogers6a3c1fc2014-10-31 00:33:20 -070067 UNUSED(self);
Andreas Gampe74240812014-04-17 10:35:09 -070068 STLDeleteElements(monitors);
69#else
70 GetMonitorPool()->ReleaseMonitorsToPool(self, monitors);
71#endif
72 }
73
Ian Rogersef7d42f2014-01-06 12:55:46 -080074 static Monitor* MonitorFromMonitorId(MonitorId mon_id) {
75#ifndef __LP64__
Hiroshi Yamauchie15ea082015-02-09 17:11:42 -080076 return reinterpret_cast<Monitor*>(mon_id << LockWord::kMonitorIdAlignmentShift);
Ian Rogersef7d42f2014-01-06 12:55:46 -080077#else
Andreas Gampe74240812014-04-17 10:35:09 -070078 return GetMonitorPool()->LookupMonitor(mon_id);
Ian Rogersef7d42f2014-01-06 12:55:46 -080079#endif
80 }
81
82 static MonitorId MonitorIdFromMonitor(Monitor* mon) {
83#ifndef __LP64__
Hiroshi Yamauchie15ea082015-02-09 17:11:42 -080084 return reinterpret_cast<MonitorId>(mon) >> LockWord::kMonitorIdAlignmentShift;
Ian Rogersef7d42f2014-01-06 12:55:46 -080085#else
86 return mon->GetMonitorId();
87#endif
88 }
89
Andreas Gampe74240812014-04-17 10:35:09 -070090 static MonitorId ComputeMonitorId(Monitor* mon, Thread* self) {
Ian Rogersef7d42f2014-01-06 12:55:46 -080091#ifndef __LP64__
Ian Rogers6a3c1fc2014-10-31 00:33:20 -070092 UNUSED(self);
Ian Rogersef7d42f2014-01-06 12:55:46 -080093 return MonitorIdFromMonitor(mon);
94#else
Andreas Gampe74240812014-04-17 10:35:09 -070095 return GetMonitorPool()->ComputeMonitorIdInPool(mon, self);
Ian Rogersef7d42f2014-01-06 12:55:46 -080096#endif
97 }
98
Andreas Gampe74240812014-04-17 10:35:09 -070099 static MonitorPool* GetMonitorPool() {
Ian Rogersef7d42f2014-01-06 12:55:46 -0800100#ifndef __LP64__
Andreas Gampe74240812014-04-17 10:35:09 -0700101 return nullptr;
Ian Rogersef7d42f2014-01-06 12:55:46 -0800102#else
Andreas Gampe74240812014-04-17 10:35:09 -0700103 return Runtime::Current()->GetMonitorPool();
Ian Rogersef7d42f2014-01-06 12:55:46 -0800104#endif
105 }
106
Andreas Gampe057134b2016-03-10 08:33:45 -0800107 ~MonitorPool() {
108#ifdef __LP64__
109 FreeInternal();
110#endif
111 }
112
Ian Rogersef7d42f2014-01-06 12:55:46 -0800113 private:
114#ifdef __LP64__
Andreas Gampe74240812014-04-17 10:35:09 -0700115 // When we create a monitor pool, threads have not been initialized, yet, so ignore thread-safety
116 // analysis.
117 MonitorPool() NO_THREAD_SAFETY_ANALYSIS;
Ian Rogersef7d42f2014-01-06 12:55:46 -0800118
Mathieu Chartier90443472015-07-16 20:32:27 -0700119 void AllocateChunk() REQUIRES(Locks::allocated_monitor_ids_lock_);
Ian Rogersef7d42f2014-01-06 12:55:46 -0800120
Andreas Gampe057134b2016-03-10 08:33:45 -0800121 // Release all chunks and metadata. This is done on shutdown, where threads have been destroyed,
122 // so ignore thead-safety analysis.
123 void FreeInternal() NO_THREAD_SAFETY_ANALYSIS;
124
Andreas Gampe74240812014-04-17 10:35:09 -0700125 Monitor* CreateMonitorInPool(Thread* self, Thread* owner, mirror::Object* obj, int32_t hash_code)
Mathieu Chartier90443472015-07-16 20:32:27 -0700126 SHARED_REQUIRES(Locks::mutator_lock_);
Ian Rogersef7d42f2014-01-06 12:55:46 -0800127
Andreas Gampe74240812014-04-17 10:35:09 -0700128 void ReleaseMonitorToPool(Thread* self, Monitor* monitor);
Mathieu Chartierbad02672014-08-25 13:08:22 -0700129 void ReleaseMonitorsToPool(Thread* self, MonitorList::Monitors* monitors);
Ian Rogersef7d42f2014-01-06 12:55:46 -0800130
Andreas Gampe74240812014-04-17 10:35:09 -0700131 // Note: This is safe as we do not ever move chunks.
132 Monitor* LookupMonitor(MonitorId mon_id) {
133 size_t offset = MonitorIdToOffset(mon_id);
134 size_t index = offset / kChunkSize;
135 size_t offset_in_chunk = offset % kChunkSize;
136 uintptr_t base = *(monitor_chunks_.LoadRelaxed()+index);
137 return reinterpret_cast<Monitor*>(base + offset_in_chunk);
138 }
Ian Rogersef7d42f2014-01-06 12:55:46 -0800139
Andreas Gampe74240812014-04-17 10:35:09 -0700140 static bool IsInChunk(uintptr_t base_addr, Monitor* mon) {
141 uintptr_t mon_ptr = reinterpret_cast<uintptr_t>(mon);
142 return base_addr <= mon_ptr && (mon_ptr - base_addr < kChunkSize);
143 }
144
145 // Note: This is safe as we do not ever move chunks.
146 MonitorId ComputeMonitorIdInPool(Monitor* mon, Thread* self) {
147 MutexLock mu(self, *Locks::allocated_monitor_ids_lock_);
148 for (size_t index = 0; index < num_chunks_; ++index) {
149 uintptr_t chunk_addr = *(monitor_chunks_.LoadRelaxed() + index);
150 if (IsInChunk(chunk_addr, mon)) {
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700151 return OffsetToMonitorId(
152 reinterpret_cast<uintptr_t>(mon) - chunk_addr + index * kChunkSize);
Andreas Gampe74240812014-04-17 10:35:09 -0700153 }
154 }
155 LOG(FATAL) << "Did not find chunk that contains monitor.";
156 return 0;
157 }
158
159 static size_t MonitorIdToOffset(MonitorId id) {
160 return id << 3;
161 }
162
163 static MonitorId OffsetToMonitorId(size_t offset) {
164 return static_cast<MonitorId>(offset >> 3);
165 }
166
167 // TODO: There are assumptions in the code that monitor addresses are 8B aligned (>>3).
168 static constexpr size_t kMonitorAlignment = 8;
169 // Size of a monitor, rounded up to a multiple of alignment.
170 static constexpr size_t kAlignedMonitorSize = (sizeof(Monitor) + kMonitorAlignment - 1) &
171 -kMonitorAlignment;
172 // As close to a page as we can get seems a good start.
173 static constexpr size_t kChunkCapacity = kPageSize / kAlignedMonitorSize;
174 // Chunk size that is referenced in the id. We can collapse this to the actually used storage
175 // in a chunk, i.e., kChunkCapacity * kAlignedMonitorSize, but this will mean proper divisions.
176 static constexpr size_t kChunkSize = kPageSize;
177 // The number of initial chunks storable in monitor_chunks_. The number is large enough to make
178 // resizing unlikely, but small enough to not waste too much memory.
179 static constexpr size_t kInitialChunkStorage = 8U;
180
181 // List of memory chunks. Each chunk is kChunkSize.
182 Atomic<uintptr_t*> monitor_chunks_;
183 // Number of chunks stored.
184 size_t num_chunks_ GUARDED_BY(Locks::allocated_monitor_ids_lock_);
185 // Number of chunks storable.
186 size_t capacity_ GUARDED_BY(Locks::allocated_monitor_ids_lock_);
187
188 // To avoid race issues when resizing, we keep all the previous arrays.
Andreas Gampe4464a3e2016-03-03 20:15:47 -0800189 std::vector<std::unique_ptr<uintptr_t[]>> old_chunk_arrays_
190 GUARDED_BY(Locks::allocated_monitor_ids_lock_);
Andreas Gampe74240812014-04-17 10:35:09 -0700191
Ian Rogers13735952014-10-08 12:43:28 -0700192 typedef TrackingAllocator<uint8_t, kAllocatorTagMonitorPool> Allocator;
Mathieu Chartierbad02672014-08-25 13:08:22 -0700193 Allocator allocator_;
194
Andreas Gampe74240812014-04-17 10:35:09 -0700195 // Start of free list of monitors.
196 // Note: these point to the right memory regions, but do *not* denote initialized objects.
197 Monitor* first_free_ GUARDED_BY(Locks::allocated_monitor_ids_lock_);
Ian Rogersef7d42f2014-01-06 12:55:46 -0800198#endif
199};
200
201} // namespace art
202
203#endif // ART_RUNTIME_MONITOR_POOL_H_