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.
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()
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_
;
31 UnsafeArena::~UnsafeArena() {
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() {
46 freestart_
= first_blocks_
[0].mem
;
47 remaining_
= first_blocks_
[0].size
;
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);
55 const int waste
= kDefaultAlignment
- overage
;
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
;
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
) {
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
;
118 (reinterpret_cast<uintptr_t>(freestart_
) & (align
-1));
120 const int waste
= align
- overage
;
122 if (waste
< remaining_
) {
128 if (size
> remaining_
) {
129 AllocatedBlock
*block
= AllocNewBlock(block_size_
);
130 freestart_
= block
->mem
;
131 remaining_
= block
->size
;
134 last_alloc_
= freestart_
;
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;
158 if (overflow_blocks_
!= NULL
) {
159 vector
<AllocatedBlock
>::iterator it
;
160 for (it
= overflow_blocks_
->begin(); it
!= overflow_blocks_
->end(); ++it
) {
163 delete overflow_blocks_
; // These should be used very rarely
164 overflow_blocks_
= NULL
;