blob: 92d9ea282857a59a1ce25ddbc74f0a8801fe8026 [file] [log] [blame]
Mathieu Chartierd8195f12012-10-05 12:21:28 -07001/*
2 * Copyright (C) 2012 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
Brian Carlstromfc0e3212013-07-17 14:40:12 -070017#ifndef ART_RUNTIME_GC_ACCOUNTING_ATOMIC_STACK_H_
18#define ART_RUNTIME_GC_ACCOUNTING_ATOMIC_STACK_H_
Mathieu Chartierd8195f12012-10-05 12:21:28 -070019
20#include <string>
21
22#include "atomic_integer.h"
Elliott Hughes07ed66b2012-12-12 18:34:25 -080023#include "base/logging.h"
Elliott Hughes76160052012-12-12 16:31:20 -080024#include "base/macros.h"
Mathieu Chartierd8195f12012-10-05 12:21:28 -070025#include "UniquePtr.h"
Mathieu Chartierd8195f12012-10-05 12:21:28 -070026#include "mem_map.h"
27#include "utils.h"
28
29namespace art {
Ian Rogers1d54e732013-05-02 21:10:01 -070030namespace gc {
31namespace accounting {
Mathieu Chartierd8195f12012-10-05 12:21:28 -070032
33template <typename T>
34class AtomicStack {
35 public:
36 // Capacity is how many elements we can store in the stack.
37 static AtomicStack* Create(const std::string& name, size_t capacity) {
38 UniquePtr<AtomicStack> mark_stack(new AtomicStack(name, capacity));
39 mark_stack->Init();
40 return mark_stack.release();
41 }
42
Ian Rogers1d54e732013-05-02 21:10:01 -070043 ~AtomicStack() {}
Mathieu Chartierd8195f12012-10-05 12:21:28 -070044
45 void Reset() {
46 DCHECK(mem_map_.get() != NULL);
47 DCHECK(begin_ != NULL);
48 front_index_ = 0;
49 back_index_ = 0;
Ian Rogers1d54e732013-05-02 21:10:01 -070050 is_sorted_ = true;
Mathieu Chartierd8195f12012-10-05 12:21:28 -070051 int result = madvise(begin_, sizeof(T) * capacity_, MADV_DONTNEED);
52 if (result == -1) {
53 PLOG(WARNING) << "madvise failed";
54 }
55 }
56
57 // Beware: Mixing atomic pushes and atomic pops will cause ABA problem.
58
59 // Returns false if we overflowed the stack.
60 bool AtomicPushBack(const T& value) {
Ian Rogers56edc432013-01-18 16:51:51 -080061 int32_t index;
Ian Rogers1d54e732013-05-02 21:10:01 -070062 is_sorted_ = false;
Ian Rogers56edc432013-01-18 16:51:51 -080063 do {
64 index = back_index_;
65 if (UNLIKELY(static_cast<size_t>(index) >= capacity_)) {
66 // Stack overflow.
67 return false;
68 }
Brian Carlstromb9070092013-07-18 10:50:06 -070069 } while (!back_index_.compare_and_swap(index, index + 1));
Mathieu Chartierd8195f12012-10-05 12:21:28 -070070 begin_[index] = value;
71 return true;
72 }
73
74 void PushBack(const T& value) {
Ian Rogers1d54e732013-05-02 21:10:01 -070075 is_sorted_ = false;
Mathieu Chartierd8195f12012-10-05 12:21:28 -070076 int32_t index = back_index_;
77 DCHECK_LT(static_cast<size_t>(index), capacity_);
78 back_index_ = index + 1;
79 begin_[index] = value;
80 }
81
82 T PopBack() {
83 DCHECK_GT(back_index_, front_index_);
84 // Decrement the back index non atomically.
85 back_index_ = back_index_ - 1;
86 return begin_[back_index_];
87 }
88
Mathieu Chartierd8195f12012-10-05 12:21:28 -070089 // Take an item from the front of the stack.
90 T PopFront() {
91 int32_t index = front_index_;
Mathieu Chartier4b95e8f2013-07-15 16:32:50 -070092 DCHECK_LT(index, back_index_.load());
Mathieu Chartierd8195f12012-10-05 12:21:28 -070093 front_index_ = front_index_ + 1;
94 return begin_[index];
95 }
96
97 bool IsEmpty() const {
98 return Size() == 0;
99 }
100
101 size_t Size() const {
102 DCHECK_LE(front_index_, back_index_);
103 return back_index_ - front_index_;
104 }
105
Ian Rogers1d54e732013-05-02 21:10:01 -0700106 T* Begin() const {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800107 return const_cast<mirror::Object**>(begin_ + front_index_);
Mathieu Chartierd8195f12012-10-05 12:21:28 -0700108 }
109
Ian Rogers1d54e732013-05-02 21:10:01 -0700110 T* End() const {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800111 return const_cast<mirror::Object**>(begin_ + back_index_);
Mathieu Chartierd8195f12012-10-05 12:21:28 -0700112 }
113
114 size_t Capacity() const {
115 return capacity_;
116 }
117
118 // Will clear the stack.
119 void Resize(size_t new_capacity) {
120 capacity_ = new_capacity;
121 Init();
122 }
123
Ian Rogers1d54e732013-05-02 21:10:01 -0700124 void Sort() {
125 if (!is_sorted_) {
Mathieu Chartier4b95e8f2013-07-15 16:32:50 -0700126 int32_t start_back_index = back_index_.load();
127 int32_t start_front_index = front_index_.load();
Ian Rogers1d54e732013-05-02 21:10:01 -0700128 is_sorted_ = true;
129 std::sort(Begin(), End());
Mathieu Chartier4b95e8f2013-07-15 16:32:50 -0700130 CHECK_EQ(start_back_index, back_index_.load());
131 CHECK_EQ(start_front_index, front_index_.load());
Ian Rogers1d54e732013-05-02 21:10:01 -0700132 }
133 }
134
135 bool Contains(const T& value) const {
136 if (is_sorted_) {
137 return std::binary_search(Begin(), End(), value);
138 } else {
139 return std::find(Begin(), End(), value) != End();
140 }
141 }
142
Mathieu Chartierd8195f12012-10-05 12:21:28 -0700143 private:
144 AtomicStack(const std::string& name, const size_t capacity)
145 : name_(name),
146 back_index_(0),
147 front_index_(0),
148 begin_(NULL),
Ian Rogers1d54e732013-05-02 21:10:01 -0700149 capacity_(capacity),
150 is_sorted_(true) {
Mathieu Chartierd8195f12012-10-05 12:21:28 -0700151 }
152
153 // Size in number of elements.
154 void Init() {
155 mem_map_.reset(MemMap::MapAnonymous(name_.c_str(), NULL, capacity_ * sizeof(T), PROT_READ | PROT_WRITE));
jeffhao8161c032012-10-31 15:50:00 -0700156 CHECK(mem_map_.get() != NULL) << "couldn't allocate mark stack";
Mathieu Chartierd8195f12012-10-05 12:21:28 -0700157 byte* addr = mem_map_->Begin();
158 CHECK(addr != NULL);
159 begin_ = reinterpret_cast<T*>(addr);
160 Reset();
161 }
162
163 // Name of the mark stack.
164 std::string name_;
165
166 // Memory mapping of the atomic stack.
167 UniquePtr<MemMap> mem_map_;
168
169 // Back index (index after the last element pushed).
170 AtomicInteger back_index_;
171
172 // Front index, used for implementing PopFront.
173 AtomicInteger front_index_;
174
175 // Base of the atomic stack.
176 T* begin_;
177
178 // Maximum number of elements.
179 size_t capacity_;
180
Ian Rogers1d54e732013-05-02 21:10:01 -0700181 bool is_sorted_;
182
Mathieu Chartierd8195f12012-10-05 12:21:28 -0700183 DISALLOW_COPY_AND_ASSIGN(AtomicStack);
184};
185
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800186typedef AtomicStack<mirror::Object*> ObjectStack;
187
Ian Rogers1d54e732013-05-02 21:10:01 -0700188} // namespace accounting
189} // namespace gc
Mathieu Chartierd8195f12012-10-05 12:21:28 -0700190} // namespace art
191
Brian Carlstromfc0e3212013-07-17 14:40:12 -0700192#endif // ART_RUNTIME_GC_ACCOUNTING_ATOMIC_STACK_H_