-
Notifications
You must be signed in to change notification settings - Fork 5
/
regionheap.h
137 lines (114 loc) · 3.41 KB
/
regionheap.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/* -*- C++ -*- */
#pragma once
#ifndef REGIONHEAP_H
#define REGIONHEAP_H
#include "heaplayers.h"
#include <assert.h>
template <class SuperHeap,
unsigned int MultiplierNumerator = 2,
unsigned int MultiplierDenominator = 1,
size_t ChunkSize = 4096>
class RegionHeap : public SuperHeap {
public:
// enum { Alignment = SuperHeap::Alignment };
RegionHeap()
: _sizeRemaining (0),
_currentArena (nullptr),
_pastArenas (nullptr),
_lastChunkSize (ChunkSize)
{
static_assert(MultiplierNumerator >= MultiplierDenominator,
"Numerator must be at least as large as the denominator.");
static_assert(MultiplierNumerator * MultiplierDenominator > 0,
"Both the numerator and denominator need to be nonzero positive integers.");
}
~RegionHeap()
{
clear();
}
inline void * __attribute__((always_inline)) malloc (size_t sz) {
void * ptr;
// We assume sz is suitably aligned.
if (unlikely(!_currentArena || (_sizeRemaining < sz))) {
refill(sz);
if (!_currentArena) {
return nullptr;
}
}
// tprintf::tprintf("bump @ from @\n", sz, _sizeRemaining);
// Bump the pointer and update the amount of memory remaining.
_sizeRemaining -= sz;
ptr = _currentPointer; // Arena->arenaSpace;
_currentPointer += sz;
// _currentArena->arenaSpace += sz;
return ptr;
}
/// Free in a zone allocator is a no-op.
void __attribute__((always_inline)) free (void *) {}
void __attribute__((noinline)) clear()
{
Arena * ptr = _pastArenas;
while (ptr != nullptr) {
void * oldPtr = (void *) ptr;
ptr = ptr->nextArena;
SuperHeap::free (oldPtr);
}
if (_currentArena != nullptr) {
SuperHeap::free ((void *) _currentArena);
}
_sizeRemaining = 0;
_currentArena = nullptr;
_pastArenas = nullptr;
_lastChunkSize = ChunkSize;
}
private:
size_t getSize(void *);
RegionHeap (const RegionHeap&);
RegionHeap& operator=(const RegionHeap&);
void __attribute__((noinline)) refill(size_t sz) {
// Get more space in our arena since there's not enough room in this one.
// First, add this arena to our past arena list.
if (_currentArena) {
_currentArena->nextArena = _pastArenas;
_pastArenas = _currentArena;
}
// Now get more memory.
size_t allocSize = (int) _lastChunkSize;
_lastChunkSize *= MultiplierNumerator;
_lastChunkSize /= MultiplierDenominator;
if (allocSize < sz) {
allocSize += sz;
}
_currentArena =
(Arena *) SuperHeap::malloc(allocSize);
if (_currentArena) {
assert(_currentArena != nullptr);
// _currentArena->arenaSpace = (char *) (_currentArena + 1);
_currentPointer = (char *) (_currentArena + 1);
_currentArena->nextArena = nullptr;
_sizeRemaining = allocSize - sizeof(Arena);
} else {
_sizeRemaining = 0;
}
}
class Arena {
public:
Arena() {
static_assert((sizeof(Arena) % HL::MallocInfo::Alignment == 0),
"Alignment must match Arena size.");
}
// alignas(8) char * arenaSpace;
Arena * nextArena { nullptr };
};
/// Space left in the current arena.
size_t _sizeRemaining;
/// The current arena.
Arena * _currentArena;
/// The current bump pointer.
char * _currentPointer;
/// A linked list of past arenas.
Arena * _pastArenas;
/// Last size (which increases geometrically).
float _lastChunkSize;
};
#endif