-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgc.c
125 lines (107 loc) · 2.38 KB
/
gc.c
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
#include <math.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "intern.h"
#include "utils.h"
typedef struct {
size_t size, used;
uint8_t *body;
} Heap;
enum {
MiB = 1024 * 1024,
HEAP_RATIO = 2,
};
static size_t init_size = 1 * MiB;
// 64 is enough large, it can use up the entire 64-bit memory space
static Heap *heaps[64];
static size_t heaps_length;
static uintptr_t *stack_base;
static bool stress;
void sch_set_gc_init_size(double init_mib)
{
init_size = round(init_mib * MiB);
}
void sch_set_gc_stress(bool b)
{
stress = b;
}
static inline size_t align(size_t size)
{
return (size + 7U) / 8U * 8U;
}
static Heap *heap_new(size_t size)
{
Heap *h = xcalloc(1, sizeof(Heap));
h->size = size;
h->used = 0;
h->body = xcalloc(1, size);
return h;
}
void gc_fin(void)
{
for (size_t i = 0; i < heaps_length; i++) {
free(heaps[i]->body);
free(heaps[i]);
}
}
void gc_init(uintptr_t *sp)
{
stack_base = sp;
init_size = align(init_size);
heaps[0] = heap_new(init_size);
heaps_length = 1;
}
static void *allocate(size_t size)
{
size = align(size);
Heap *heap = heaps[heaps_length-1]; // use the last heap only
if (heap->used + size > heap->size)
return NULL;
uint8_t *ret = heap->body + heap->used;
heap->used += size;
return ret;
}
size_t gc_stack_get_size(uintptr_t *sp)
{
return (uint8_t *) stack_base - (uint8_t *) sp;
}
static bool enough_free_space(void)
{
static const size_t minreq = sizeof(Continuation); // maybe the largest
Heap *heap = heaps[heaps_length-1];
return (heap->size - heap->used) >= minreq;
}
static void increase_heaps(void)
{
Heap *heap = heaps[heaps_length-1];
heaps[heaps_length++] = heap_new(heap->size * HEAP_RATIO);
}
static void gc(void)
{
// collects nothing
if (!enough_free_space())
increase_heaps();
}
static double heaps_size(void)
{
// Sum of a geometric sequence
return init_size * (pow(HEAP_RATIO, heaps_length) - 1)
/ (HEAP_RATIO - 1);
}
void *gc_malloc(size_t size)
{
if (stress)
gc();
void *p = allocate(size);
if (!stress && p == NULL) {
gc();
p = allocate(size);
}
if (p == NULL)
error("out of memory; heap (~%lld MiB) exhausted",
llround(heaps_size() / MiB));
return p;
}