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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
|
#define _GNU_SOURCE
#include "../gc.h"
#include "../platform.h"
#include "../util.h"
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
int main(int argc, char **argv) {
// As a test of the garbage collector, we're doing a bunch of random
// mutations.
gc_init();
srand(0);
gc_debug();
const struct value ZERO = {.bits = (0 << 2) | TAG_FIXNUM};
struct object *values = gc_alloc(64, 0);
struct object *value_slot_counts = gc_alloc(64, 0);
gc_root_push(&values);
gc_root_push(&value_slot_counts);
for (size_t i = 0; i < 1000000; i++) {
if ((rand() & 0b11) == 0) {
size_t value_slot_count = 3;
if (!value_slot_count)
value_slot_count = 1;
size_t untraced_slot_count = rand() & 255;
struct value value =
alloc_builtin_object(ZERO, value_slot_count, untraced_slot_count);
size_t i = rand() % 63;
gc_write_value_slot(values, i, value);
gc_write_value_slot(value_slot_counts, i,
integer_of_int(value_slot_count));
} else {
size_t i = rand() & 63;
struct value value = gc_read_value_slot(values, i);
struct value value_slot_count_value =
gc_read_value_slot(value_slot_counts, i);
if (!value.bits)
continue;
assume(get_tag(value) == TAG_BUILTIN_OBJECT);
assume(get_tag(value_slot_count_value) == TAG_FIXNUM);
struct object *obj = untag_ptr(value);
intptr_t value_slot_count = untag_fixnum(value_slot_count_value);
size_t j = rand() % value_slot_count;
size_t k = rand() % 63;
gc_write_value_slot(obj, j, gc_read_value_slot(values, k));
}
}
gc_debug();
return 0;
}
void panic_begin(void) {}
noreturn void panic_end(void) { abort(); }
static size_t read_cache_size(const char *path) {
int fd = open(path, O_RDONLY | O_CLOEXEC);
if (fd == -1)
fprintf(stderr, "open %s: %s\n", path, strerror(errno)), abort();
char buf[4096];
size_t len = 0;
for (;;) {
ssize_t ret = read(fd, &buf[len], sizeof(buf) - len);
if (ret == 0)
break;
else if (ret < 0 && errno == EINTR)
continue;
else if (ret < 0)
fprintf(stderr, "read %s: %s\n", path, strerror(errno)), abort();
else
len += ret;
}
if (close(fd))
fprintf(stderr, "close %s: %s\n", path, strerror(errno)), abort();
size_t i = 0, out = 0;
while (i < len) {
char ch = buf[i];
if ('0' <= ch && ch <= '9') {
out = 10 * out + (ch - '0');
i++;
} else {
break;
}
}
if (i < len) {
char ch = buf[i];
if (ch == 'K') {
out *= 1024;
i++;
} else if (ch == 'M') {
out *= 1024 * 1024;
i++;
}
}
if (i < len && buf[i] == '\n')
i++;
if (i != len) {
fprintf(stderr, "invalid cache size in %s: [", path);
for (size_t j = 0; j < len; j++) {
fprintf(stderr, "%s", i == j ? "|" : j ? " " : "");
char ch = buf[j];
if (' ' <= ch && ch <= '~' && ch != '\'' && ch != '\\')
fprintf(stderr, "'%c'", ch);
else if (ch == '\n')
fprintf(stderr, "'\\n'");
else if (ch == '\'')
fprintf(stderr, "\"'\"");
else if (ch == '\\')
fprintf(stderr, "'\\\\'");
else
fprintf(stderr, "%02hhx", buf[j]);
}
fprintf(stderr, "]\n");
abort();
}
return out;
}
size_t get_l1d_size(void) {
return read_cache_size("/sys/devices/system/cpu/cpu0/cache/index0/size");
}
size_t get_l3_size(void) {
return read_cache_size("/sys/devices/system/cpu/cpu0/cache/index2/size");
}
uintptr_t alloc_gc_region(size_t size) {
static uintptr_t base_ptr = 0x10000;
static size_t page_size = 0;
if (!page_size)
page_size = sysconf(_SC_PAGE_SIZE);
void *ptr = mmap((void *)base_ptr, size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (ptr == MAP_FAILED)
perror("alloc_gc_region"), exit(111);
base_ptr =
(((uintptr_t)ptr + size + page_size - 1) & ~(page_size - 1)) + page_size;
return (uintptr_t)ptr;
}
void clear_gc_region(uintptr_t addr, size_t size) {
void *new_ptr = mmap((void *)addr, size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
if (new_ptr == MAP_FAILED)
perror("clear_gc_region"), exit(111);
}
|