Update V8 to version 4.2.36 (based on d0f3e5302c8d89fee4995b86a2b83c9ecf5d1e7a).
[chromium-blink-merge.git] / third_party / re2 / util / arena.cc
blob25753c5df5cca24eead3ca9e3f4527797e24b895
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.
5 #include "util/util.h"
7 namespace re2 {
9 // ----------------------------------------------------------------------
10 // UnsafeArena::UnsafeArena()
11 // UnsafeArena::~UnsafeArena()
12 // Destroying the arena automatically calls Reset()
13 // ----------------------------------------------------------------------
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);
25 first_blocks_[0].mem = reinterpret_cast<char*>(malloc(block_size_));
26 first_blocks_[0].size = block_size_;
28 Reset();
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);
39 // ----------------------------------------------------------------------
40 // UnsafeArena::Reset()
41 // Clears all the memory an arena is using.
42 // ----------------------------------------------------------------------
44 void UnsafeArena::Reset() {
45 FreeBlocks();
46 freestart_ = first_blocks_[0].mem;
47 remaining_ = first_blocks_[0].size;
48 last_alloc_ = NULL;
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;
59 freestart_when_empty_ = freestart_;
60 assert(!(reinterpret_cast<uintptr_t>(freestart_)&(kDefaultAlignment-1)));
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 // -------------------------------------------------------------
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();
85 block->mem = reinterpret_cast<char*>(malloc(block_size));
86 block->size = block_size;
88 return block;
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 // ----------------------------------------------------------------------
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
105 assert(align > 0 && 0 == (align & (align - 1))); // must be power of 2
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;
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;
128 if (size > remaining_) {
129 AllocatedBlock *block = AllocNewBlock(block_size_);
130 freestart_ = block->mem;
131 remaining_ = block->size;
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_);
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 // ----------------------------------------------------------------------
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;
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);
163 delete overflow_blocks_; // These should be used very rarely
164 overflow_blocks_ = NULL;
168 } // namespace re2