Skip to content

Commit c6d7f14

Browse files
committed
Merge remote-tracking branch 'origin/develop'
2 parents b16e56c + f098535 commit c6d7f14

File tree

12 files changed

+132
-104
lines changed

12 files changed

+132
-104
lines changed

.github/workflows/release.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,8 @@ jobs:
8686
include:
8787
- runner: [self-hosted, linux, normal]
8888
os: ubuntu-24.04
89-
- runner: MacM1
90-
os: self-macos-12
89+
- runner: [self-hosted, self-macos-latest]
90+
os: self-macos-latest
9191

9292
runs-on: ${{ matrix.runner }}
9393
steps:

.github/workflows/test.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ jobs:
1717
include:
1818
- runner: [self-hosted, linux, normal]
1919
os: ubuntu-24.04
20-
- runner: MacM1
21-
os: self-macos-12
20+
- runner: [self-hosted, self-macos-latest]
21+
os: self-macos-latest
2222
runs-on: ${{ matrix.runner }}
2323
steps:
2424
- name: 'Check out code'

INSTALL.md

Lines changed: 55 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ python3 -m pip install pybind11 lit
3030
```
3131

3232
## macOS / Homebrew
33-
33+
In order to install the dependencies on macOS, you must have Homebrew installed and on your `PATH`.
3434
```shell
3535
brew update
3636
brew install \
@@ -40,19 +40,70 @@ brew install \
4040
fmt \
4141
git \
4242
gmp \
43+
grep \
4344
jemalloc \
45+
libffi
4446
libyaml \
4547
llvm@15 \
4648
maven \
4749
mpfr \
4850
pkg-config \
4951
python3 \
5052
z3
53+
```
54+
55+
To ensure that the backend can use pybind11 correctly, we must create an virtual
56+
environment and install the `pybind11` package:
57+
```shell
58+
python3 -m venv venv
59+
source venv/bin/activate
5160
python3 -m pip install pybind11 lit
5261
```
5362

63+
Guarantee that you have the JDK installed and on your `PATH`:
64+
```shell
65+
export PATH="/opt/homebrew/opt/openjdk/bin:$PATH"
66+
```
67+
68+
Some tests rely on GNU Grep options, which are not available on macOS by
69+
default. To ensure that the tests run correctly, you add the path of
70+
GNU Grep to your `PATH` in your shell profile:
71+
```shell
72+
export PATH=/opt/homebrew/Cellar/grep/3.11/libexec/gnubin/:$PATH
73+
```
74+
5475
# Building
5576

77+
## Environment Variables
78+
79+
If you're building on macOS, type the following command or epermanently
80+
add it your `env` (`.zshrc`, `.bashrc`, etc.), so that the Homebrew
81+
installation of LLVM gets picked up correctly. We recommend adding it to
82+
your shell profile.
83+
```shell
84+
export LLVM_DIR=$($(brew --prefix llvm@15)/bin/llvm-config --cmakedir)
85+
```
86+
87+
If you don't usually use the `clang` from your Homebrew installation as
88+
your default compiler, you can set the following CMake flg to use these
89+
`clang` and `clang++`:
90+
```shell
91+
-DCMAKE_C_COMPILER="$(brew --prefix llvm@15)/bin/clang" \
92+
-DCMAKE_CXX_COMPILER="$(brew --prefix llvm@15)/bin/clang++"
93+
```
94+
Once again, we recommend adding them and other llvm binaries to your
95+
`PATH` in your shell profile:
96+
```shell
97+
export PATH="$(brew --prefix llvm@15)/bin:$PATH"
98+
```
99+
100+
Some tests rely on GNU Grep options, which are not available on macOS by
101+
default. To ensure that the tests run correctly, you can create an alias
102+
for GNU Grep:
103+
```shell
104+
alias grep=ggrep
105+
```
106+
56107
Once the system dependencies have been installed, the backend can be built
57108
locally with:
58109
```shell
@@ -66,12 +117,6 @@ cmake .. \
66117
make -j$(nproc) install
67118
```
68119

69-
If you're building on macOS, add the following option to your CMake invocation
70-
so that the Homebrew installation of LLVM gets picked up correctly.
71-
```shell
72-
-DLLVM_DIR=$($(brew --prefix llvm@15)/bin/llvm-config --cmakedir)
73-
```
74-
75120
Additionally, to build the pattern-matching compiler, run:
76121
```shell
77122
cd matching
@@ -91,7 +136,8 @@ To run the integration tests, run:
91136
```shell
92137
lit test
93138
```
94-
from the root source directory.
139+
from the root source directory. You can use `-v` to see which test is being executed
140+
and the output of failling tests.
95141

96142
There is also a unit test suite for backend internals;
97143
Add the following option to your CMake invocation to enable it:
@@ -113,7 +159,7 @@ and conform to best practices.
113159

114160
```shell
115161
# Ubuntu
116-
apt install shellcheck clang-format-12 iwyu
162+
apt install shellcheck clang-format-15 iwyu
117163

118164
# macOS
119165
brew install shellcheck clang-format iwyu

cmake/FixHomebrew.cmake

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,15 @@ if(APPLE)
2020
include_directories(AFTER SYSTEM "${BREW_PREFIX}/include")
2121
link_directories(AFTER "${BREW_PREFIX}/lib")
2222
set(ENV{PKG_CONFIG_PATH} "${BREW_PREFIX}/opt/libffi/lib/pkgconfig")
23+
24+
# Use LLD as the linker
25+
# This is necessary as the default linker used by CMake on macOS is
26+
# ld64, which currently has some incompatibilities with Homebrew and XCode15.
27+
# See: https://github.com/orgs/Homebrew/discussions/4794#discussioncomment-7044468
28+
# Adding this flag avoid the following errors:
29+
# ld: warning: duplicate -rpath ... ignored
30+
# ld: warning: ignoring duplicate libraries ...
31+
add_link_options("-fuse-ld=lld")
32+
2333
endif() # USE_NIX
2434
endif() # APPLE

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: 34 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -22,37 +22,28 @@ class arena {
2222
initialize_semispace();
2323
}
2424

25+
char *evacuate(char *scan_ptr);
26+
2527
// Allocates the requested number of bytes as a contiguous region and returns a
2628
// pointer to the first allocated byte.
2729
void *kore_arena_alloc(size_t requested);
2830

2931
// 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-
}
32+
// Returns nullptr if nothing has been allocated ever in that arena.
33+
char *arena_start_ptr() const { return current_addr_ptr; }
3534

3635
// Returns a pointer to a location holding the address of last allocated
3736
// byte in the given arena plus 1.
38-
// This address is 0 if nothing has been allocated ever in that arena.
39-
char **arena_end_ptr() { return &allocation_ptr; }
40-
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-
}
37+
// This address is nullptr if nothing has been allocated ever in that arena.
38+
char *arena_end_ptr() { return allocation_ptr; }
4739

4840
// Clears the current allocation space by setting its start back to its first
4941
// block. It is used during garbage collection to effectively collect all of the
50-
// arena.
42+
// arena. Resets the tripwire.
5143
void arena_clear();
5244

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.
45+
// Resizes the last allocation.
46+
// Returns the address of the byte following the last newly allocated byte.
5647
void *arena_resize_last_alloc(ssize_t increase) {
5748
return (allocation_ptr += increase);
5849
}
@@ -71,10 +62,8 @@ class arena {
7162
void arena_swap_and_clear();
7263

7364
// 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.
65+
// of bytes they are apart. Undefined behavior will result if the pointers
66+
// don't belong to the same arena
7867
static ssize_t ptr_diff(char *ptr1, char *ptr2) { return ptr1 - ptr2; }
7968

8069
// Given a starting pointer to an address allocated in an arena and a size in
@@ -84,11 +73,11 @@ class arena {
8473
// 1st argument: the starting pointer
8574
// 2nd argument: the size in bytes to add to the starting pointer
8675
// 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.
89-
static char *move_ptr(char *ptr, size_t size, char const *arena_end_ptr) {
76+
// Return value: starting pointer + size unless this points to unallocated space
77+
// in which case nullptr is returned
78+
static char *move_ptr(char *ptr, size_t size, char const *end_ptr) {
9079
char *next_ptr = ptr + size;
91-
return (next_ptr == arena_end_ptr) ? 0 : next_ptr;
80+
return (next_ptr == end_ptr) ? nullptr : next_ptr;
9281
}
9382

9483
// Returns the ID of the semispace where the given address was allocated.
@@ -97,15 +86,6 @@ class arena {
9786
static char get_arena_semispace_id_of_object(void *ptr);
9887

9988
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-
10989
//
11090
// We update the number of 1MB blocks actually written to, only when we need this value,
11191
// or before a garbage collection rather than trying to determine when we write to a fresh block.
@@ -121,13 +101,6 @@ class arena {
121101
}
122102

123103
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-
131104
//
132105
// Current semispace where allocations are being made.
133106
//
@@ -146,9 +119,22 @@ class arena {
146119
= 0; // notional number of BLOCK_SIZE blocks in collection semispace
147120
};
148121

122+
inline char arena::get_arena_semispace_id_of_object(void *ptr) {
123+
//
124+
// We don't have to deal with the "1 past the end of block" case because
125+
// a valid pointer will always point into our hyperblock - we will never return
126+
// an allocation anywhere near the end of our hyperblock.
127+
//
128+
// Set the low bits to 1 to get the address of the last byte in the hyperblock.
129+
//
130+
uintptr_t end_address
131+
= reinterpret_cast<uintptr_t>(ptr) | (HYPERBLOCK_SIZE - 1);
132+
return *reinterpret_cast<char *>(end_address);
133+
}
134+
149135
// Macro to define a new arena with the given ID. Supports IDs ranging from 0 to
150136
// 127.
151-
#define REGISTER_ARENA(name, id) static thread_local arena name(id)
137+
#define REGISTER_ARENA(name, id) thread_local arena name(id)
152138

153139
#ifdef __MACH__
154140
//
@@ -169,8 +155,11 @@ inline void *arena::kore_arena_alloc(size_t requested) {
169155
// collect when allowed.
170156
//
171157
time_for_collection = true;
172-
tripwire = current_addr_ptr
173-
+ HYPERBLOCK_SIZE; // won't trigger again until arena swap
158+
//
159+
// We move the tripwire to 1 past the end of our hyperblock so that we have
160+
// a well defined comparison that will always be false until the next arena swap.
161+
//
162+
tripwire = current_addr_ptr + HYPERBLOCK_SIZE;
174163
}
175164
void *result = allocation_ptr;
176165
allocation_ptr += requested;

include/runtime/header.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,10 @@ struct kore_alloc_heap {
9191
template <typename... Tags>
9292
static void *allocate(size_t size, Tags...) {
9393
if (during_gc()) {
94-
return ::operator new(size);
94+
auto *result = (string *)::operator new(size + sizeof(blockheader));
95+
init_with_len(result, size);
96+
result->h.hdr |= NOT_YOUNG_OBJECT_BIT;
97+
return result->data;
9598
}
9699
bool enabled = gc_enabled;
97100
gc_enabled = false;
@@ -103,7 +106,7 @@ struct kore_alloc_heap {
103106

104107
static void deallocate(size_t size, void *data) {
105108
if (during_gc()) {
106-
::operator delete(data);
109+
::operator delete((char *)data - sizeof(blockheader));
107110
}
108111
}
109112
};

runtime/alloc/arena.cpp

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,11 @@
77

88
#include "runtime/alloc.h"
99
#include "runtime/arena.h"
10+
#include "runtime/collect.h"
1011
#include "runtime/header.h"
1112

1213
extern size_t const VAR_BLOCK_SIZE = BLOCK_SIZE;
1314

14-
__attribute__((always_inline)) char
15-
arena::get_arena_semispace_id_of_object(void *ptr) {
16-
return mem_block_header(ptr)->semispace;
17-
}
18-
1915
#ifdef __MACH__
2016
//
2117
// thread_local disabled for Apple
@@ -46,19 +42,19 @@ void arena::initialize_semispace() {
4642
}
4743
//
4844
// 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.
45+
// HYPERBLOCK_SIZE boundry. This is so we can get end of the hyperblock by setting the low bits of any
46+
// address within the space to 1.
5047
// We don't worry about unused address space either side of our aligned address space because there will be no
5148
// memory mapped to it.
5249
//
5350
current_addr_ptr = reinterpret_cast<char *>(
5451
std::align(HYPERBLOCK_SIZE, HYPERBLOCK_SIZE, addr, request));
5552
//
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.
53+
// We put a semispace id in the last byte of the hyperblock so we can identify which semispace an address
54+
// belongs to by setting the low bits to 1 to access this id.
5855
//
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);
56+
current_addr_ptr[HYPERBLOCK_SIZE - 1] = allocation_semispace_id;
57+
allocation_ptr = current_addr_ptr;
6258
//
6359
// We set the tripwire for this space so we get trigger a garbage collection when we pass BLOCK_SIZE of memory
6460
// allocated from this space.

0 commit comments

Comments
 (0)