blob: 5bc28f132a1f70d393abaaa03dca574ac3ffe019 [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
Ian Rogers44d6ff12014-03-06 23:11:11 -080022#ifdef __LP64__
Ian Rogersef7d42f2014-01-06 12:55:46 -080023#include <stdint.h>
Andreas Gampe74240812014-04-17 10:35:09 -070024#include "atomic.h"
Ian Rogers44d6ff12014-03-06 23:11:11 -080025#include "runtime.h"
Andreas Gampe74240812014-04-17 10:35:09 -070026#else
27#include "base/stl_util.h" // STLDeleteElements
Ian Rogers44d6ff12014-03-06 23:11:11 -080028#endif
29
Ian Rogersef7d42f2014-01-06 12:55:46 -080030namespace art {
31
32// Abstraction to keep monitors small enough to fit in a lock word (32bits). On 32bit systems the
33// monitor id loses the alignment bits of the Monitor*.
34class MonitorPool {
35 public:
36 static MonitorPool* Create() {
37#ifndef __LP64__
38 return nullptr;
39#else
40 return new MonitorPool();
41#endif
42 }
43
Andreas Gampe74240812014-04-17 10:35:09 -070044 static Monitor* CreateMonitor(Thread* self, Thread* owner, mirror::Object* obj, int32_t hash_code)
45 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
46#ifndef __LP64__
47 return new Monitor(self, owner, obj, hash_code);
48#else
49 return GetMonitorPool()->CreateMonitorInPool(self, owner, obj, hash_code);
50#endif
51 }
52
53 static void ReleaseMonitor(Thread* self, Monitor* monitor) {
54#ifndef __LP64__
55 delete monitor;
56#else
57 GetMonitorPool()->ReleaseMonitorToPool(self, monitor);
58#endif
59 }
60
61 static void ReleaseMonitors(Thread* self, std::list<Monitor*>* monitors) {
62#ifndef __LP64__
63 STLDeleteElements(monitors);
64#else
65 GetMonitorPool()->ReleaseMonitorsToPool(self, monitors);
66#endif
67 }
68
Ian Rogersef7d42f2014-01-06 12:55:46 -080069 static Monitor* MonitorFromMonitorId(MonitorId mon_id) {
70#ifndef __LP64__
71 return reinterpret_cast<Monitor*>(mon_id << 3);
72#else
Andreas Gampe74240812014-04-17 10:35:09 -070073 return GetMonitorPool()->LookupMonitor(mon_id);
Ian Rogersef7d42f2014-01-06 12:55:46 -080074#endif
75 }
76
77 static MonitorId MonitorIdFromMonitor(Monitor* mon) {
78#ifndef __LP64__
79 return reinterpret_cast<MonitorId>(mon) >> 3;
80#else
81 return mon->GetMonitorId();
82#endif
83 }
84
Andreas Gampe74240812014-04-17 10:35:09 -070085 static MonitorId ComputeMonitorId(Monitor* mon, Thread* self) {
Ian Rogersef7d42f2014-01-06 12:55:46 -080086#ifndef __LP64__
Ian Rogersef7d42f2014-01-06 12:55:46 -080087 return MonitorIdFromMonitor(mon);
88#else
Andreas Gampe74240812014-04-17 10:35:09 -070089 return GetMonitorPool()->ComputeMonitorIdInPool(mon, self);
Ian Rogersef7d42f2014-01-06 12:55:46 -080090#endif
91 }
92
Andreas Gampe74240812014-04-17 10:35:09 -070093 static MonitorPool* GetMonitorPool() {
Ian Rogersef7d42f2014-01-06 12:55:46 -080094#ifndef __LP64__
Andreas Gampe74240812014-04-17 10:35:09 -070095 return nullptr;
Ian Rogersef7d42f2014-01-06 12:55:46 -080096#else
Andreas Gampe74240812014-04-17 10:35:09 -070097 return Runtime::Current()->GetMonitorPool();
Ian Rogersef7d42f2014-01-06 12:55:46 -080098#endif
99 }
100
101 private:
102#ifdef __LP64__
Andreas Gampe74240812014-04-17 10:35:09 -0700103 // When we create a monitor pool, threads have not been initialized, yet, so ignore thread-safety
104 // analysis.
105 MonitorPool() NO_THREAD_SAFETY_ANALYSIS;
Ian Rogersef7d42f2014-01-06 12:55:46 -0800106
Andreas Gampe74240812014-04-17 10:35:09 -0700107 void AllocateChunk() EXCLUSIVE_LOCKS_REQUIRED(Locks::allocated_monitor_ids_lock_);
Ian Rogersef7d42f2014-01-06 12:55:46 -0800108
Andreas Gampe74240812014-04-17 10:35:09 -0700109 Monitor* CreateMonitorInPool(Thread* self, Thread* owner, mirror::Object* obj, int32_t hash_code)
110 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
Ian Rogersef7d42f2014-01-06 12:55:46 -0800111
Andreas Gampe74240812014-04-17 10:35:09 -0700112 void ReleaseMonitorToPool(Thread* self, Monitor* monitor);
113 void ReleaseMonitorsToPool(Thread* self, std::list<Monitor*>* monitors);
Ian Rogersef7d42f2014-01-06 12:55:46 -0800114
Andreas Gampe74240812014-04-17 10:35:09 -0700115 // Note: This is safe as we do not ever move chunks.
116 Monitor* LookupMonitor(MonitorId mon_id) {
117 size_t offset = MonitorIdToOffset(mon_id);
118 size_t index = offset / kChunkSize;
119 size_t offset_in_chunk = offset % kChunkSize;
120 uintptr_t base = *(monitor_chunks_.LoadRelaxed()+index);
121 return reinterpret_cast<Monitor*>(base + offset_in_chunk);
122 }
Ian Rogersef7d42f2014-01-06 12:55:46 -0800123
Andreas Gampe74240812014-04-17 10:35:09 -0700124 static bool IsInChunk(uintptr_t base_addr, Monitor* mon) {
125 uintptr_t mon_ptr = reinterpret_cast<uintptr_t>(mon);
126 return base_addr <= mon_ptr && (mon_ptr - base_addr < kChunkSize);
127 }
128
129 // Note: This is safe as we do not ever move chunks.
130 MonitorId ComputeMonitorIdInPool(Monitor* mon, Thread* self) {
131 MutexLock mu(self, *Locks::allocated_monitor_ids_lock_);
132 for (size_t index = 0; index < num_chunks_; ++index) {
133 uintptr_t chunk_addr = *(monitor_chunks_.LoadRelaxed() + index);
134 if (IsInChunk(chunk_addr, mon)) {
135 return OffsetToMonitorId(reinterpret_cast<uintptr_t>(mon) - chunk_addr + index * kChunkSize);
136 }
137 }
138 LOG(FATAL) << "Did not find chunk that contains monitor.";
139 return 0;
140 }
141
142 static size_t MonitorIdToOffset(MonitorId id) {
143 return id << 3;
144 }
145
146 static MonitorId OffsetToMonitorId(size_t offset) {
147 return static_cast<MonitorId>(offset >> 3);
148 }
149
150 // TODO: There are assumptions in the code that monitor addresses are 8B aligned (>>3).
151 static constexpr size_t kMonitorAlignment = 8;
152 // Size of a monitor, rounded up to a multiple of alignment.
153 static constexpr size_t kAlignedMonitorSize = (sizeof(Monitor) + kMonitorAlignment - 1) &
154 -kMonitorAlignment;
155 // As close to a page as we can get seems a good start.
156 static constexpr size_t kChunkCapacity = kPageSize / kAlignedMonitorSize;
157 // Chunk size that is referenced in the id. We can collapse this to the actually used storage
158 // in a chunk, i.e., kChunkCapacity * kAlignedMonitorSize, but this will mean proper divisions.
159 static constexpr size_t kChunkSize = kPageSize;
160 // The number of initial chunks storable in monitor_chunks_. The number is large enough to make
161 // resizing unlikely, but small enough to not waste too much memory.
162 static constexpr size_t kInitialChunkStorage = 8U;
163
164 // List of memory chunks. Each chunk is kChunkSize.
165 Atomic<uintptr_t*> monitor_chunks_;
166 // Number of chunks stored.
167 size_t num_chunks_ GUARDED_BY(Locks::allocated_monitor_ids_lock_);
168 // Number of chunks storable.
169 size_t capacity_ GUARDED_BY(Locks::allocated_monitor_ids_lock_);
170
171 // To avoid race issues when resizing, we keep all the previous arrays.
172 std::vector<uintptr_t*> old_chunk_arrays_ GUARDED_BY(Locks::allocated_monitor_ids_lock_);
173
174 // Start of free list of monitors.
175 // Note: these point to the right memory regions, but do *not* denote initialized objects.
176 Monitor* first_free_ GUARDED_BY(Locks::allocated_monitor_ids_lock_);
Ian Rogersef7d42f2014-01-06 12:55:46 -0800177#endif
178};
179
180} // namespace art
181
182#endif // ART_RUNTIME_MONITOR_POOL_H_