OSDN Git Service

Merge "Use memory chunks for monitors on LP64"
[android-x86/art.git] / runtime / monitor_pool.h
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 #ifdef __LP64__
23 #include <stdint.h>
24 #include "atomic.h"
25 #include "runtime.h"
26 #else
27 #include "base/stl_util.h"     // STLDeleteElements
28 #endif
29
30 namespace 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*.
34 class MonitorPool {
35  public:
36   static MonitorPool* Create() {
37 #ifndef __LP64__
38     return nullptr;
39 #else
40     return new MonitorPool();
41 #endif
42   }
43
44   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
69   static Monitor* MonitorFromMonitorId(MonitorId mon_id) {
70 #ifndef __LP64__
71     return reinterpret_cast<Monitor*>(mon_id << 3);
72 #else
73     return GetMonitorPool()->LookupMonitor(mon_id);
74 #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
85   static MonitorId ComputeMonitorId(Monitor* mon, Thread* self) {
86 #ifndef __LP64__
87     return MonitorIdFromMonitor(mon);
88 #else
89     return GetMonitorPool()->ComputeMonitorIdInPool(mon, self);
90 #endif
91   }
92
93   static MonitorPool* GetMonitorPool() {
94 #ifndef __LP64__
95     return nullptr;
96 #else
97     return Runtime::Current()->GetMonitorPool();
98 #endif
99   }
100
101  private:
102 #ifdef __LP64__
103   // When we create a monitor pool, threads have not been initialized, yet, so ignore thread-safety
104   // analysis.
105   MonitorPool() NO_THREAD_SAFETY_ANALYSIS;
106
107   void AllocateChunk() EXCLUSIVE_LOCKS_REQUIRED(Locks::allocated_monitor_ids_lock_);
108
109   Monitor* CreateMonitorInPool(Thread* self, Thread* owner, mirror::Object* obj, int32_t hash_code)
110       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
111
112   void ReleaseMonitorToPool(Thread* self, Monitor* monitor);
113   void ReleaseMonitorsToPool(Thread* self, std::list<Monitor*>* monitors);
114
115   // 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   }
123
124   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_);
177 #endif
178 };
179
180 }  // namespace art
181
182 #endif  // ART_RUNTIME_MONITOR_POOL_H_