1 /* 2 * Copyright (C) 2013 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_COMPILER_UTILS_GROWABLE_ARRAY_H_ 18 #define ART_COMPILER_UTILS_GROWABLE_ARRAY_H_ 19 20 #include <stdint.h> 21 #include <stddef.h> 22 #include "arena_allocator.h" 23 24 namespace art { 25 26 // Type of growable list for memory tuning. 27 enum OatListKind { 28 kGrowableArrayMisc = 0, 29 kGrowableArrayBlockList, 30 kGrowableArraySSAtoDalvikMap, 31 kGrowableArrayDfsOrder, 32 kGrowableArrayDfsPostOrder, 33 kGrowableArrayDomPostOrderTraversal, 34 kGrowableArraySwitchTables, 35 kGrowableArrayFillArrayData, 36 kGrowableArraySuccessorBlocks, 37 kGrowableArrayPredecessors, 38 kGrowableArraySlowPaths, 39 kGNumListKinds 40 }; 41 42 template<typename T> 43 class GrowableArray { 44 public: 45 class Iterator { 46 public: Iterator(GrowableArray * g_list)47 explicit Iterator(GrowableArray* g_list) 48 : idx_(0), 49 g_list_(g_list) {} 50 Iterator()51 explicit Iterator() 52 : idx_(0), 53 g_list_(nullptr) {} 54 55 // NOTE: returns 0/NULL when no next. 56 // TODO: redo to make usage consistent with other iterators. Next()57 T Next() { 58 DCHECK(g_list_ != nullptr); 59 if (idx_ >= g_list_->Size()) { 60 return 0; 61 } else { 62 return g_list_->Get(idx_++); 63 } 64 } 65 Reset()66 void Reset() { 67 idx_ = 0; 68 } 69 Reset(GrowableArray * g_list)70 void Reset(GrowableArray* g_list) { 71 idx_ = 0; 72 g_list_ = g_list; 73 } 74 GetIndex()75 size_t GetIndex() const { 76 return idx_; 77 } 78 79 private: 80 size_t idx_; 81 GrowableArray* g_list_; 82 }; 83 84 GrowableArray(ArenaAllocator* arena, size_t init_length, OatListKind kind = kGrowableArrayMisc) arena_(arena)85 : arena_(arena), 86 num_allocated_(init_length), 87 num_used_(0), 88 kind_(kind) { 89 elem_list_ = static_cast<T*>(arena_->Alloc(sizeof(T) * init_length, 90 kArenaAllocGrowableArray)); 91 }; 92 93 94 // Expand the list size to at least new length. Resize(size_t new_length)95 void Resize(size_t new_length) { 96 if (new_length <= num_allocated_) return; 97 // If it's a small list double the size, else grow 1.5x. 98 size_t target_length = 99 (num_allocated_ < 128) ? num_allocated_ << 1 : num_allocated_ + (num_allocated_ >> 1); 100 if (new_length > target_length) { 101 target_length = new_length; 102 } 103 T* new_array = static_cast<T*>(arena_->Alloc(sizeof(T) * target_length, 104 kArenaAllocGrowableArray)); 105 memcpy(new_array, elem_list_, sizeof(T) * num_allocated_); 106 num_allocated_ = target_length; 107 elem_list_ = new_array; 108 }; 109 110 // NOTE: does not return storage, just resets use count. Reset()111 void Reset() { 112 num_used_ = 0; 113 } 114 115 // Insert an element to the end of a list, resizing if necessary. Insert(T elem)116 void Insert(T elem) { 117 if (num_used_ == num_allocated_) { 118 Resize(num_used_ + 1); 119 } 120 elem_list_[num_used_++] = elem; 121 } 122 InsertAt(size_t index,T elem)123 void InsertAt(size_t index, T elem) { 124 DCHECK(index <= Size()); 125 Insert(elem); 126 for (size_t i = Size() - 1; i > index; --i) { 127 elem_list_[i] = elem_list_[i - 1]; 128 } 129 elem_list_[index] = elem; 130 } 131 Add(T elem)132 void Add(T elem) { 133 Insert(elem); 134 } 135 Get(size_t index)136 T Get(size_t index) const { 137 DCHECK_LT(index, num_used_); 138 return elem_list_[index]; 139 }; 140 141 // Overwrite existing element at position index. List must be large enough. Put(size_t index,T elem)142 void Put(size_t index, T elem) { 143 DCHECK_LT(index, num_used_); 144 elem_list_[index] = elem; 145 } 146 Increment(size_t index)147 void Increment(size_t index) { 148 DCHECK_LT(index, num_used_); 149 elem_list_[index]++; 150 } 151 152 /* 153 * Remove an existing element from list. If there are more than one copy 154 * of the element, only the first one encountered will be deleted. 155 */ 156 // TODO: consider renaming this. Delete(T element)157 void Delete(T element) { 158 bool found = false; 159 for (size_t i = 0; i < num_used_ - 1; i++) { 160 if (!found && elem_list_[i] == element) { 161 found = true; 162 } 163 if (found) { 164 elem_list_[i] = elem_list_[i+1]; 165 } 166 } 167 // We should either have found the element, or it was the last (unscanned) element. 168 DCHECK(found || (element == elem_list_[num_used_ - 1])); 169 num_used_--; 170 }; 171 DeleteAt(size_t index)172 void DeleteAt(size_t index) { 173 for (size_t i = index; i < num_used_ - 1; i++) { 174 elem_list_[i] = elem_list_[i + 1]; 175 } 176 num_used_--; 177 }; 178 GetNumAllocated()179 size_t GetNumAllocated() const { return num_allocated_; } 180 Size()181 size_t Size() const { return num_used_; } 182 IsEmpty()183 bool IsEmpty() const { return num_used_ == 0; } 184 Pop()185 T Pop() { 186 DCHECK_GE(num_used_, (size_t)0); 187 return elem_list_[--num_used_]; 188 } 189 Peek()190 T Peek() const { 191 DCHECK_GE(num_used_, (size_t)0); 192 return elem_list_[num_used_ - 1]; 193 } 194 SetSize(size_t new_size)195 void SetSize(size_t new_size) { 196 Resize(new_size); 197 num_used_ = new_size; 198 } 199 GetRawStorage()200 T* GetRawStorage() const { return elem_list_; } 201 new(size_t size,ArenaAllocator * arena)202 static void* operator new(size_t size, ArenaAllocator* arena) { 203 return arena->Alloc(sizeof(GrowableArray<T>), kArenaAllocGrowableArray); 204 }; delete(void * p)205 static void operator delete(void* p) {} // Nop. 206 207 private: 208 ArenaAllocator* const arena_; 209 size_t num_allocated_; 210 size_t num_used_; 211 OatListKind kind_; 212 T* elem_list_; 213 }; 214 215 } // namespace art 216 217 #endif // ART_COMPILER_UTILS_GROWABLE_ARRAY_H_ 218