Skip to content

Commit eb79b84

Browse files
authored
Further allocator refactoring (#1173)
Dead code eliminated: youngspace_size() arena_size() union memory_block_header and associated functionality replaced. The semispace id is now stored in the last byte of the hyperblock which simplifies address computations.
1 parent 8de42ea commit eb79b84

File tree

4 files changed

+35
-58
lines changed

4 files changed

+35
-58
lines changed

include/runtime/alloc.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ extern "C" {
1515

1616
char youngspace_collection_id(void);
1717
char oldspace_collection_id(void);
18-
size_t youngspace_size(void);
1918

2019
// allocates exactly requested bytes into the young generation
2120
void *kore_alloc(size_t requested);

include/runtime/arena.h

Lines changed: 29 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -27,32 +27,21 @@ class arena {
2727
void *kore_arena_alloc(size_t requested);
2828

2929
// Returns the address of the first byte that belongs in the given arena.
30-
// Returns 0 if nothing has been allocated ever in that arena.
31-
char *arena_start_ptr() const {
32-
return current_addr_ptr ? current_addr_ptr + sizeof(memory_block_header)
33-
: nullptr;
34-
}
30+
// Returns nullptr if nothing has been allocated ever in that arena.
31+
char *arena_start_ptr() const { return current_addr_ptr; }
3532

3633
// Returns a pointer to a location holding the address of last allocated
3734
// byte in the given arena plus 1.
38-
// This address is 0 if nothing has been allocated ever in that arena.
35+
// This address is nullptr if nothing has been allocated ever in that arena.
3936
char **arena_end_ptr() { return &allocation_ptr; }
4037

41-
// return the total number of allocatable bytes currently in the arena in its
42-
// active semispace.
43-
size_t arena_size() const {
44-
update_num_blocks();
45-
return BLOCK_SIZE * std::max(num_blocks, num_collection_blocks);
46-
}
47-
4838
// Clears the current allocation space by setting its start back to its first
4939
// block. It is used during garbage collection to effectively collect all of the
50-
// arena.
40+
// arena. Resets the tripwire.
5141
void arena_clear();
5242

53-
// Resizes the last allocation as long as the resize does not require a new
54-
// block allocation.
55-
// Returns the address of the byte following the last newlly allocated byte.
43+
// Resizes the last allocation.
44+
// Returns the address of the byte following the last newly allocated byte.
5645
void *arena_resize_last_alloc(ssize_t increase) {
5746
return (allocation_ptr += increase);
5847
}
@@ -71,10 +60,8 @@ class arena {
7160
void arena_swap_and_clear();
7261

7362
// Given two pointers to objects allocated in the same arena, return the number
74-
// of bytes they are separated by within the virtual block of memory represented
75-
// by the blocks of that arena. This difference will include blocks containing
76-
// sentinel bytes. Undefined behavior will result if the pointers belong to
77-
// different arenas.
63+
// of bytes they are apart. Undefined behavior will result if the pointers
64+
// don't belong to the same arena
7865
static ssize_t ptr_diff(char *ptr1, char *ptr2) { return ptr1 - ptr2; }
7966

8067
// Given a starting pointer to an address allocated in an arena and a size in
@@ -84,11 +71,11 @@ class arena {
8471
// 1st argument: the starting pointer
8572
// 2nd argument: the size in bytes to add to the starting pointer
8673
// 3rd argument: the address of last allocated byte in the arena plus 1
87-
// Return value: the address allocated in the arena after size bytes from the
88-
// starting pointer, or 0 if this is equal to the 3rd argument.
74+
// Return value: starting pointer + size unless this points to unallocated space
75+
// in which case nullptr is returned
8976
static char *move_ptr(char *ptr, size_t size, char const *arena_end_ptr) {
9077
char *next_ptr = ptr + size;
91-
return (next_ptr == arena_end_ptr) ? 0 : next_ptr;
78+
return (next_ptr == arena_end_ptr) ? nullptr : next_ptr;
9279
}
9380

9481
// Returns the ID of the semispace where the given address was allocated.
@@ -97,15 +84,6 @@ class arena {
9784
static char get_arena_semispace_id_of_object(void *ptr);
9885

9986
private:
100-
union memory_block_header {
101-
//
102-
// Currently the header just holds the semispace id. But we need it to be a
103-
// multiple of sizeof(char*) for alignment purposes so we add a dummy char*.
104-
//
105-
char semispace;
106-
char *alignment_dummy;
107-
};
108-
10987
//
11088
// We update the number of 1MB blocks actually written to, only when we need this value,
11189
// or before a garbage collection rather than trying to determine when we write to a fresh block.
@@ -121,13 +99,6 @@ class arena {
12199
}
122100

123101
void initialize_semispace();
124-
125-
static memory_block_header *mem_block_header(void *ptr) {
126-
uintptr_t address = reinterpret_cast<uintptr_t>(ptr);
127-
return reinterpret_cast<arena::memory_block_header *>(
128-
(address - 1) & ~(HYPERBLOCK_SIZE - 1));
129-
}
130-
131102
//
132103
// Current semispace where allocations are being made.
133104
//
@@ -146,6 +117,19 @@ class arena {
146117
= 0; // notional number of BLOCK_SIZE blocks in collection semispace
147118
};
148119

120+
inline char arena::get_arena_semispace_id_of_object(void *ptr) {
121+
//
122+
// We don't have to deal with the "1 past the end of block" case because
123+
// a valid pointer will always point into our hyperblock - we will never return
124+
// an allocation anywhere near the end of our hyperblock.
125+
//
126+
// Set the low bits to 1 to get the address of the last byte in the hyperblock.
127+
//
128+
uintptr_t end_address
129+
= reinterpret_cast<uintptr_t>(ptr) | (HYPERBLOCK_SIZE - 1);
130+
return *reinterpret_cast<char *>(end_address);
131+
}
132+
149133
// Macro to define a new arena with the given ID. Supports IDs ranging from 0 to
150134
// 127.
151135
#define REGISTER_ARENA(name, id) static thread_local arena name(id)
@@ -169,8 +153,11 @@ inline void *arena::kore_arena_alloc(size_t requested) {
169153
// collect when allowed.
170154
//
171155
time_for_collection = true;
172-
tripwire = current_addr_ptr
173-
+ HYPERBLOCK_SIZE; // won't trigger again until arena swap
156+
//
157+
// We move the tripwire to 1 past the end of our hyperblock so that we have
158+
// a well defined comparison that will always be false until the next arena swap.
159+
//
160+
tripwire = current_addr_ptr + HYPERBLOCK_SIZE;
174161
}
175162
void *result = allocation_ptr;
176163
allocation_ptr += requested;

runtime/alloc/arena.cpp

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,6 @@
1111

1212
extern size_t const VAR_BLOCK_SIZE = BLOCK_SIZE;
1313

14-
__attribute__((always_inline)) char
15-
arena::get_arena_semispace_id_of_object(void *ptr) {
16-
return mem_block_header(ptr)->semispace;
17-
}
18-
1914
#ifdef __MACH__
2015
//
2116
// thread_local disabled for Apple
@@ -46,19 +41,19 @@ void arena::initialize_semispace() {
4641
}
4742
//
4843
// We allocated 2 * HYPERBLOCK_SIZE worth of address space but we're only going to use 1, aligned on a
49-
// HYPERBLOCK_SIZE boundry. This is so we can get the start of the hyperblock by masking any address within it.
44+
// HYPERBLOCK_SIZE boundry. This is so we can get end of the hyperblock by setting the low bits of any
45+
// address within the space to 1.
5046
// We don't worry about unused address space either side of our aligned address space because there will be no
5147
// memory mapped to it.
5248
//
5349
current_addr_ptr = reinterpret_cast<char *>(
5450
std::align(HYPERBLOCK_SIZE, HYPERBLOCK_SIZE, addr, request));
5551
//
56-
// We put a memory_block_header at the beginning so we can identify the semispace a pointer belongs to
57-
// id by masking off the low bits to access this memory_block_header.
52+
// We put a semispace id in the last byte of the hyperblock so we can identify which semispace an address
53+
// belongs to by setting the low bits to 1 to access this id.
5854
//
59-
auto *header = reinterpret_cast<memory_block_header *>(current_addr_ptr);
60-
header->semispace = allocation_semispace_id;
61-
allocation_ptr = current_addr_ptr + sizeof(arena::memory_block_header);
55+
current_addr_ptr[HYPERBLOCK_SIZE - 1] = allocation_semispace_id;
56+
allocation_ptr = current_addr_ptr;
6257
//
6358
// We set the tripwire for this space so we get trigger a garbage collection when we pass BLOCK_SIZE of memory
6459
// allocated from this space.

runtime/lto/alloc.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,6 @@ char oldspace_collection_id() {
3939
return oldspace.get_arena_collection_semispace_id();
4040
}
4141

42-
size_t youngspace_size(void) {
43-
return youngspace.arena_size();
44-
}
45-
4642
void kore_alloc_swap(bool swap_old) {
4743
youngspace.arena_swap_and_clear();
4844
if (swap_old) {

0 commit comments

Comments
 (0)