1ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers/*
2ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers * Copyright (C) 2014 The Android Open Source Project
3ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers *
4ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers * Licensed under the Apache License, Version 2.0 (the "License");
5ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers * you may not use this file except in compliance with the License.
6ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers * You may obtain a copy of the License at
7ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers *
8ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers *      http://www.apache.org/licenses/LICENSE-2.0
9ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers *
10ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers * Unless required by applicable law or agreed to in writing, software
11ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers * distributed under the License is distributed on an "AS IS" BASIS,
12ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers * See the License for the specific language governing permissions and
14ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers * limitations under the License.
15ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers */
16ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers
17ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers#ifndef ART_RUNTIME_MONITOR_POOL_H_
18ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers#define ART_RUNTIME_MONITOR_POOL_H_
19ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers
20b0fa5dc7769c1e054032f39de0a3f6d6dd06f8cfIan Rogers#include "monitor.h"
21b0fa5dc7769c1e054032f39de0a3f6d6dd06f8cfIan Rogers
22bad0267eaab9d6a522d05469ff90501deefdb88bMathieu Chartier#include "base/allocator.h"
2344d6ff197b340b5ac2a4094db148b39c366317ddIan Rogers#ifdef __LP64__
2444d6ff197b340b5ac2a4094db148b39c366317ddIan Rogers#include <stdint.h>
258f4b056427a9d2321e3aa4f21ca8ffb18b3e5ae6David Sehr#include "base/atomic.h"
2644d6ff197b340b5ac2a4094db148b39c366317ddIan Rogers#include "runtime.h"
2774240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe#else
2874240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe#include "base/stl_util.h"     // STLDeleteElements
2944d6ff197b340b5ac2a4094db148b39c366317ddIan Rogers#endif
30ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers
31ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogersnamespace art {
32ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers
33ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers// Abstraction to keep monitors small enough to fit in a lock word (32bits). On 32bit systems the
34ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers// monitor id loses the alignment bits of the Monitor*.
35ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogersclass MonitorPool {
36ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers public:
37ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers  static MonitorPool* Create() {
38ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers#ifndef __LP64__
39ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers    return nullptr;
40ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers#else
41ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers    return new MonitorPool();
42ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers#endif
43ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers  }
44ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers
4574240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe  static Monitor* CreateMonitor(Thread* self, Thread* owner, mirror::Object* obj, int32_t hash_code)
46bdf7f1c3ab65ccb70f62db5ab31dba060632d458Andreas Gampe      REQUIRES_SHARED(Locks::mutator_lock_) {
4774240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe#ifndef __LP64__
48e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi    Monitor* mon = new Monitor(self, owner, obj, hash_code);
49e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi    DCHECK_ALIGNED(mon, LockWord::kMonitorIdAlignment);
50e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi    return mon;
5174240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe#else
5274240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe    return GetMonitorPool()->CreateMonitorInPool(self, owner, obj, hash_code);
5374240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe#endif
5474240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe  }
5574240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe
5674240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe  static void ReleaseMonitor(Thread* self, Monitor* monitor) {
5774240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe#ifndef __LP64__
586a3c1fcb4ba42ad4d5d142c17a3712a6ddd3866fIan Rogers    UNUSED(self);
5974240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe    delete monitor;
6074240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe#else
6174240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe    GetMonitorPool()->ReleaseMonitorToPool(self, monitor);
6274240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe#endif
6374240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe  }
6474240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe
65bad0267eaab9d6a522d05469ff90501deefdb88bMathieu Chartier  static void ReleaseMonitors(Thread* self, MonitorList::Monitors* monitors) {
6674240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe#ifndef __LP64__
676a3c1fcb4ba42ad4d5d142c17a3712a6ddd3866fIan Rogers    UNUSED(self);
6874240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe    STLDeleteElements(monitors);
6974240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe#else
7074240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe    GetMonitorPool()->ReleaseMonitorsToPool(self, monitors);
7174240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe#endif
7274240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe  }
7374240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe
74ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers  static Monitor* MonitorFromMonitorId(MonitorId mon_id) {
75ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers#ifndef __LP64__
76e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi    return reinterpret_cast<Monitor*>(mon_id << LockWord::kMonitorIdAlignmentShift);
77ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers#else
7874240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe    return GetMonitorPool()->LookupMonitor(mon_id);
79ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers#endif
80ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers  }
81ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers
82ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers  static MonitorId MonitorIdFromMonitor(Monitor* mon) {
83ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers#ifndef __LP64__
84e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi    return reinterpret_cast<MonitorId>(mon) >> LockWord::kMonitorIdAlignmentShift;
85ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers#else
86ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers    return mon->GetMonitorId();
87ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers#endif
88ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers  }
89ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers
9074240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe  static MonitorId ComputeMonitorId(Monitor* mon, Thread* self) {
91ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers#ifndef __LP64__
926a3c1fcb4ba42ad4d5d142c17a3712a6ddd3866fIan Rogers    UNUSED(self);
93ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers    return MonitorIdFromMonitor(mon);
94ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers#else
9574240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe    return GetMonitorPool()->ComputeMonitorIdInPool(mon, self);
96ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers#endif
97ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers  }
98ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers
9974240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe  static MonitorPool* GetMonitorPool() {
100ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers#ifndef __LP64__
10174240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe    return nullptr;
102ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers#else
10374240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe    return Runtime::Current()->GetMonitorPool();
104ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers#endif
105ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers  }
106ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers
107057134bdf40981555a8bf56ab8d703a503b40f8fAndreas Gampe  ~MonitorPool() {
108057134bdf40981555a8bf56ab8d703a503b40f8fAndreas Gampe#ifdef __LP64__
109057134bdf40981555a8bf56ab8d703a503b40f8fAndreas Gampe    FreeInternal();
110057134bdf40981555a8bf56ab8d703a503b40f8fAndreas Gampe#endif
111057134bdf40981555a8bf56ab8d703a503b40f8fAndreas Gampe  }
112057134bdf40981555a8bf56ab8d703a503b40f8fAndreas Gampe
113ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers private:
114ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers#ifdef __LP64__
11574240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe  // When we create a monitor pool, threads have not been initialized, yet, so ignore thread-safety
11674240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe  // analysis.
11774240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe  MonitorPool() NO_THREAD_SAFETY_ANALYSIS;
118ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers
11990443477f9a0061581c420775ce3b7eeae7468bcMathieu Chartier  void AllocateChunk() REQUIRES(Locks::allocated_monitor_ids_lock_);
120ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers
121057134bdf40981555a8bf56ab8d703a503b40f8fAndreas Gampe  // Release all chunks and metadata. This is done on shutdown, where threads have been destroyed,
122057134bdf40981555a8bf56ab8d703a503b40f8fAndreas Gampe  // so ignore thead-safety analysis.
123057134bdf40981555a8bf56ab8d703a503b40f8fAndreas Gampe  void FreeInternal() NO_THREAD_SAFETY_ANALYSIS;
124057134bdf40981555a8bf56ab8d703a503b40f8fAndreas Gampe
12574240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe  Monitor* CreateMonitorInPool(Thread* self, Thread* owner, mirror::Object* obj, int32_t hash_code)
126bdf7f1c3ab65ccb70f62db5ab31dba060632d458Andreas Gampe      REQUIRES_SHARED(Locks::mutator_lock_);
127ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers
12874240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe  void ReleaseMonitorToPool(Thread* self, Monitor* monitor);
129bad0267eaab9d6a522d05469ff90501deefdb88bMathieu Chartier  void ReleaseMonitorsToPool(Thread* self, MonitorList::Monitors* monitors);
130ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers
131a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  // Note: This is safe as we do not ever move chunks.  All needed entries in the monitor_chunks_
132a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  // data structure are read-only once we get here.  Updates happen-before this call because
133a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  // the lock word was stored with release semantics and we read it with acquire semantics to
134a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  // retrieve the id.
13574240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe  Monitor* LookupMonitor(MonitorId mon_id) {
13674240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe    size_t offset = MonitorIdToOffset(mon_id);
13774240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe    size_t index = offset / kChunkSize;
138a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm    size_t top_index = index / kMaxListSize;
139a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm    size_t list_index = index % kMaxListSize;
14074240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe    size_t offset_in_chunk = offset % kChunkSize;
141a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm    uintptr_t base = monitor_chunks_[top_index][list_index];
14274240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe    return reinterpret_cast<Monitor*>(base + offset_in_chunk);
14374240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe  }
14474240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe
14574240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe  static bool IsInChunk(uintptr_t base_addr, Monitor* mon) {
14674240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe    uintptr_t mon_ptr = reinterpret_cast<uintptr_t>(mon);
14774240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe    return base_addr <= mon_ptr && (mon_ptr - base_addr < kChunkSize);
14874240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe  }
14974240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe
15074240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe  MonitorId ComputeMonitorIdInPool(Monitor* mon, Thread* self) {
15174240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe    MutexLock mu(self, *Locks::allocated_monitor_ids_lock_);
152a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm    for (size_t i = 0; i <= current_chunk_list_index_; ++i) {
153a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm      for (size_t j = 0; j < ChunkListCapacity(i); ++j) {
154a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm        if (j >= num_chunks_ && i == current_chunk_list_index_) {
155a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm          break;
156a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm        }
157a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm        uintptr_t chunk_addr = monitor_chunks_[i][j];
158a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm        if (IsInChunk(chunk_addr, mon)) {
159a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm          return OffsetToMonitorId(
160a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm              reinterpret_cast<uintptr_t>(mon) - chunk_addr
161a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm              + i * (kMaxListSize * kChunkSize) + j * kChunkSize);
162a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm        }
16374240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe      }
16474240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe    }
16574240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe    LOG(FATAL) << "Did not find chunk that contains monitor.";
16674240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe    return 0;
16774240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe  }
16874240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe
169a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  static constexpr size_t MonitorIdToOffset(MonitorId id) {
17074240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe    return id << 3;
17174240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe  }
17274240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe
173a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  static constexpr MonitorId OffsetToMonitorId(size_t offset) {
17474240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe    return static_cast<MonitorId>(offset >> 3);
17574240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe  }
176ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers
177a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  static constexpr size_t ChunkListCapacity(size_t index) {
178a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm    return kInitialChunkStorage << index;
179a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  }
180a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm
18174240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe  // TODO: There are assumptions in the code that monitor addresses are 8B aligned (>>3).
18274240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe  static constexpr size_t kMonitorAlignment = 8;
18374240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe  // Size of a monitor, rounded up to a multiple of alignment.
18474240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe  static constexpr size_t kAlignedMonitorSize = (sizeof(Monitor) + kMonitorAlignment - 1) &
18574240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe                                                -kMonitorAlignment;
18674240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe  // As close to a page as we can get seems a good start.
18774240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe  static constexpr size_t kChunkCapacity = kPageSize / kAlignedMonitorSize;
18874240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe  // Chunk size that is referenced in the id. We can collapse this to the actually used storage
18974240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe  // in a chunk, i.e., kChunkCapacity * kAlignedMonitorSize, but this will mean proper divisions.
19074240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe  static constexpr size_t kChunkSize = kPageSize;
191a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  static_assert(IsPowerOfTwo(kChunkSize), "kChunkSize must be power of 2");
192a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  // The number of chunks of storage that can be referenced by the initial chunk list.
193a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  // The total number of usable monitor chunks is typically 255 times this number, so it
194a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  // should be large enough that we don't run out. We run out of address bits if it's > 512.
195a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  // Currently we set it a bit smaller, to save half a page per process.  We make it tiny in
196a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  // debug builds to catch growth errors. The only value we really expect to tune.
197a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  static constexpr size_t kInitialChunkStorage = kIsDebugBuild ? 1U : 256U;
198a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  static_assert(IsPowerOfTwo(kInitialChunkStorage), "kInitialChunkStorage must be power of 2");
199a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  // The number of lists, each containing pointers to storage chunks.
200a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  static constexpr size_t kMaxChunkLists = 8;  //  Dictated by 3 bit index. Don't increase above 8.
201a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  static_assert(IsPowerOfTwo(kMaxChunkLists), "kMaxChunkLists must be power of 2");
202a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  static constexpr size_t kMaxListSize = kInitialChunkStorage << (kMaxChunkLists - 1);
203a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  // We lose 3 bits in monitor id due to 3 bit monitor_chunks_ index, and gain it back from
204a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  // the 3 bit alignment constraint on monitors:
205a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  static_assert(kMaxListSize * kChunkSize < (1 << LockWord::kMonitorIdSize),
206a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm      "Monitor id bits don't fit");
207a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  static_assert(IsPowerOfTwo(kMaxListSize), "kMaxListSize must be power of 2");
208a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm
209a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  // Array of pointers to lists (again arrays) of pointers to chunks containing monitors.
210a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  // Zeroth entry points to a list (array) of kInitialChunkStorage pointers to chunks.
211a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  // Each subsequent list as twice as large as the preceding one.
212a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  // Monitor Ids are interpreted as follows:
213a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  //     Top 3 bits (of 28): index into monitor_chunks_.
214a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  //     Next 16 bits: index into the chunk list, i.e. monitor_chunks_[i].
215a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  //     Last 9 bits: offset within chunk, expressed as multiple of kMonitorAlignment.
216a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  // If we set kInitialChunkStorage to 512, this would allow us to use roughly 128K chunks of
217a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  // monitors, which is 0.5GB of monitors.  With this maximum setting, the largest chunk list
218a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  // contains 64K entries, and we make full use of the available index space. With a
219a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  // kInitialChunkStorage value of 256, this is proportionately reduced to 0.25GB of monitors.
220a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  // Updates to monitor_chunks_ are guarded by allocated_monitor_ids_lock_ .
221a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  // No field in this entire data structure is ever updated once a monitor id whose lookup
222a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  // requires it has been made visible to another thread.  Thus readers never race with
223a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  // updates, in spite of the fact that they acquire no locks.
224a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  uintptr_t* monitor_chunks_[kMaxChunkLists];  //  uintptr_t is really a Monitor* .
225a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  // Highest currently used index in monitor_chunks_ . Used for newly allocated chunks.
226a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  size_t current_chunk_list_index_ GUARDED_BY(Locks::allocated_monitor_ids_lock_);
227a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  // Number of chunk pointers stored in monitor_chunks_[current_chunk_list_index_] so far.
22874240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe  size_t num_chunks_ GUARDED_BY(Locks::allocated_monitor_ids_lock_);
229a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  // After the initial allocation, this is always equal to
230a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  // ChunkListCapacity(current_chunk_list_index_).
231a319f4dbeea00701a0d12dc39b7bf0a5323f6b2aHans Boehm  size_t current_chunk_list_capacity_ GUARDED_BY(Locks::allocated_monitor_ids_lock_);
23274240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe
23313735955f39b3b304c37d2b2840663c131262c18Ian Rogers  typedef TrackingAllocator<uint8_t, kAllocatorTagMonitorPool> Allocator;
234bad0267eaab9d6a522d05469ff90501deefdb88bMathieu Chartier  Allocator allocator_;
235bad0267eaab9d6a522d05469ff90501deefdb88bMathieu Chartier
23674240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe  // Start of free list of monitors.
23774240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe  // Note: these point to the right memory regions, but do *not* denote initialized objects.
23874240819ae09e29b2753ef38f4eb4be1c2762e2eAndreas Gampe  Monitor* first_free_ GUARDED_BY(Locks::allocated_monitor_ids_lock_);
239ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers#endif
240ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers};
241ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers
242ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers}  // namespace art
243ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers
244ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers#endif  // ART_RUNTIME_MONITOR_POOL_H_
245