1 // Copyright 2000 The RE2 Authors. All Rights Reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 #include "util/util.h" 6 7 namespace re2 { 8 9 // ---------------------------------------------------------------------- 10 // UnsafeArena::UnsafeArena() 11 // UnsafeArena::~UnsafeArena() 12 // Destroying the arena automatically calls Reset() 13 // ---------------------------------------------------------------------- 14 15 16 UnsafeArena::UnsafeArena(const size_t block_size) 17 : block_size_(block_size), 18 freestart_(NULL), // set for real in Reset() 19 last_alloc_(NULL), 20 remaining_(0), 21 blocks_alloced_(1), 22 overflow_blocks_(NULL) { 23 assert(block_size > kDefaultAlignment); 24 25 first_blocks_[0].mem = reinterpret_cast<char*>(malloc(block_size_)); 26 first_blocks_[0].size = block_size_; 27 28 Reset(); 29 } 30 31 UnsafeArena::~UnsafeArena() { 32 FreeBlocks(); 33 assert(overflow_blocks_ == NULL); // FreeBlocks() should do that 34 // The first X blocks stay allocated always by default. Delete them now. 35 for (int i = 0; i < blocks_alloced_; i++) 36 free(first_blocks_[i].mem); 37 } 38 39 // ---------------------------------------------------------------------- 40 // UnsafeArena::Reset() 41 // Clears all the memory an arena is using. 42 // ---------------------------------------------------------------------- 43 44 void UnsafeArena::Reset() { 45 FreeBlocks(); 46 freestart_ = first_blocks_[0].mem; 47 remaining_ = first_blocks_[0].size; 48 last_alloc_ = NULL; 49 50 // We do not know for sure whether or not the first block is aligned, 51 // so we fix that right now. 52 const int overage = reinterpret_cast<uintptr_t>(freestart_) & 53 (kDefaultAlignment-1); 54 if (overage > 0) { 55 const int waste = kDefaultAlignment - overage; 56 freestart_ += waste; 57 remaining_ -= waste; 58 } 59 freestart_when_empty_ = freestart_; 60 assert(!(reinterpret_cast<uintptr_t>(freestart_)&(kDefaultAlignment-1))); 61 } 62 63 // ------------------------------------------------------------- 64 // UnsafeArena::AllocNewBlock() 65 // Adds and returns an AllocatedBlock. 66 // The returned AllocatedBlock* is valid until the next call 67 // to AllocNewBlock or Reset. (i.e. anything that might 68 // affect overflow_blocks_). 69 // ------------------------------------------------------------- 70 71 UnsafeArena::AllocatedBlock* UnsafeArena::AllocNewBlock(const size_t block_size) { 72 AllocatedBlock *block; 73 // Find the next block. 74 if ( blocks_alloced_ < arraysize(first_blocks_) ) { 75 // Use one of the pre-allocated blocks 76 block = &first_blocks_[blocks_alloced_++]; 77 } else { // oops, out of space, move to the vector 78 if (overflow_blocks_ == NULL) overflow_blocks_ = new vector<AllocatedBlock>; 79 // Adds another block to the vector. 80 overflow_blocks_->resize(overflow_blocks_->size()+1); 81 // block points to the last block of the vector. 82 block = &overflow_blocks_->back(); 83 } 84 85 block->mem = reinterpret_cast<char*>(malloc(block_size)); 86 block->size = block_size; 87 88 return block; 89 } 90 91 // ---------------------------------------------------------------------- 92 // UnsafeArena::GetMemoryFallback() 93 // We take memory out of our pool, aligned on the byte boundary 94 // requested. If we don't have space in our current pool, we 95 // allocate a new block (wasting the remaining space in the 96 // current block) and give you that. If your memory needs are 97 // too big for a single block, we make a special your-memory-only 98 // allocation -- this is equivalent to not using the arena at all. 99 // ---------------------------------------------------------------------- 100 101 void* UnsafeArena::GetMemoryFallback(const size_t size, const int align) { 102 if (size == 0) 103 return NULL; // stl/stl_alloc.h says this is okay 104 105 assert(align > 0 && 0 == (align & (align - 1))); // must be power of 2 106 107 // If the object is more than a quarter of the block size, allocate 108 // it separately to avoid wasting too much space in leftover bytes 109 if (block_size_ == 0 || size > block_size_/4) { 110 // then it gets its own block in the arena 111 assert(align <= kDefaultAlignment); // because that's what new gives us 112 // This block stays separate from the rest of the world; in particular 113 // we don't update last_alloc_ so you can't reclaim space on this block. 114 return AllocNewBlock(size)->mem; 115 } 116 117 const int overage = 118 (reinterpret_cast<uintptr_t>(freestart_) & (align-1)); 119 if (overage) { 120 const int waste = align - overage; 121 freestart_ += waste; 122 if (waste < remaining_) { 123 remaining_ -= waste; 124 } else { 125 remaining_ = 0; 126 } 127 } 128 if (size > remaining_) { 129 AllocatedBlock *block = AllocNewBlock(block_size_); 130 freestart_ = block->mem; 131 remaining_ = block->size; 132 } 133 remaining_ -= size; 134 last_alloc_ = freestart_; 135 freestart_ += size; 136 assert((reinterpret_cast<uintptr_t>(last_alloc_) & (align-1)) == 0); 137 return reinterpret_cast<void*>(last_alloc_); 138 } 139 140 // ---------------------------------------------------------------------- 141 // UnsafeArena::FreeBlocks() 142 // Unlike GetMemory(), which does actual work, ReturnMemory() is a 143 // no-op: we don't "free" memory until Reset() is called. We do 144 // update some stats, though. Note we do no checking that the 145 // pointer you pass in was actually allocated by us, or that it 146 // was allocated for the size you say, so be careful here! 147 // FreeBlocks() does the work for Reset(), actually freeing all 148 // memory allocated in one fell swoop. 149 // ---------------------------------------------------------------------- 150 151 void UnsafeArena::FreeBlocks() { 152 for ( int i = 1; i < blocks_alloced_; ++i ) { // keep first block alloced 153 free(first_blocks_[i].mem); 154 first_blocks_[i].mem = NULL; 155 first_blocks_[i].size = 0; 156 } 157 blocks_alloced_ = 1; 158 if (overflow_blocks_ != NULL) { 159 vector<AllocatedBlock>::iterator it; 160 for (it = overflow_blocks_->begin(); it != overflow_blocks_->end(); ++it) { 161 free(it->mem); 162 } 163 delete overflow_blocks_; // These should be used very rarely 164 overflow_blocks_ = NULL; 165 } 166 } 167 168 } // namespace re2 169