30
30
extern uintnat caml_percent_free; /* major_gc.c */
32
#ifdef USE_MMAP_INSTEAD_OF_MALLOC
33
extern char * caml_aligned_mmap (asize_t size, int modulo, void ** block);
34
extern void caml_aligned_munmap (char * addr, asize_t size);
32
/* Page table management */
34
#define Page(p) ((uintnat) (p) >> Page_log)
35
#define Page_mask ((uintnat) -1 << Page_log)
39
/* 64-bit implementation:
40
The page table is represented sparsely as a hash table
41
with linear probing */
44
mlsize_t size; /* size == 1 << (wordsize - shift) */
46
mlsize_t mask; /* mask == size - 1 */
48
uintnat * entries; /* [size] */
51
static struct page_table caml_page_table;
53
/* Page table entries are the logical 'or' of
54
- the key: address of a page (low Page_log bits = 0)
55
- the data: a 8-bit integer */
57
#define Page_entry_matches(entry,addr) \
58
((((entry) ^ (addr)) & Page_mask) == 0)
60
/* Multiplicative Fibonacci hashing
61
(Knuth, TAOCP vol 3, section 6.4, page 518).
62
HASH_FACTOR is (sqrt(5) - 1) / 2 * 2^wordsize. */
64
#define HASH_FACTOR 11400714819323198486UL
66
#define HASH_FACTOR 2654435769UL
68
#define Hash(v) (((v) * HASH_FACTOR) >> caml_page_table.shift)
70
int caml_page_table_lookup(void * addr)
75
/* The first hit is almost always successful, so optimize for this case */
76
e = caml_page_table.entries[h];
77
if (Page_entry_matches(e, (uintnat)addr)) return e & 0xFF;
80
h = (h + 1) & caml_page_table.mask;
81
e = caml_page_table.entries[h];
82
if (Page_entry_matches(e, (uintnat)addr)) return e & 0xFF;
86
int caml_page_table_initialize(mlsize_t bytesize)
88
uintnat pagesize = Page(bytesize);
90
caml_page_table.size = 1;
91
caml_page_table.shift = 8 * sizeof(uintnat);
92
/* Aim for initial load factor between 1/4 and 1/2 */
93
while (caml_page_table.size < 2 * pagesize) {
94
caml_page_table.size <<= 1;
95
caml_page_table.shift -= 1;
97
caml_page_table.mask = caml_page_table.size - 1;
98
caml_page_table.occupancy = 0;
99
caml_page_table.entries = calloc(caml_page_table.size, sizeof(uintnat));
100
if (caml_page_table.entries == NULL)
106
static int caml_page_table_resize(void)
108
struct page_table old = caml_page_table;
109
uintnat * new_entries;
112
caml_gc_message (0x08, "Growing page table to %lu entries\n",
113
caml_page_table.size);
115
new_entries = calloc(2 * old.size, sizeof(uintnat));
116
if (new_entries == NULL) {
117
caml_gc_message (0x08, "No room for growing page table\n", 0);
121
caml_page_table.size = 2 * old.size;
122
caml_page_table.shift = old.shift - 1;
123
caml_page_table.mask = caml_page_table.size - 1;
124
caml_page_table.occupancy = old.occupancy;
125
caml_page_table.entries = new_entries;
127
for (i = 0; i < old.size; i++) {
128
uintnat e = old.entries[i];
129
if (e == 0) continue;
131
while (caml_page_table.entries[h] != 0)
132
h = (h + 1) & caml_page_table.mask;
133
caml_page_table.entries[h] = e;
140
static int caml_page_table_modify(uintnat page, int toclear, int toset)
144
Assert ((page & ~Page_mask) == 0);
146
/* Resize to keep load factor below 1/2 */
147
if (caml_page_table.occupancy * 2 >= caml_page_table.size) {
148
if (caml_page_table_resize() != 0) return -1;
150
h = Hash(Page(page));
152
if (caml_page_table.entries[h] == 0) {
153
caml_page_table.entries[h] = page | toset;
154
caml_page_table.occupancy++;
157
if (Page_entry_matches(caml_page_table.entries[h], page)) {
158
caml_page_table.entries[h] =
159
(caml_page_table.entries[h] & ~toclear) | toset;
162
h = (h + 1) & caml_page_table.mask;
169
/* 32-bit implementation:
170
The page table is represented as a 2-level array of unsigned char */
172
CAMLexport unsigned char * caml_page_table[Pagetable1_size];
173
static unsigned char caml_page_table_empty[Pagetable2_size] = { 0, };
175
int caml_page_table_initialize(mlsize_t bytesize)
178
for (i = 0; i < Pagetable1_size; i++)
179
caml_page_table[i] = caml_page_table_empty;
183
static int caml_page_table_modify(uintnat page, int toclear, int toset)
185
uintnat i = Pagetable_index1(page);
186
uintnat j = Pagetable_index2(page);
188
if (caml_page_table[i] == caml_page_table_empty) {
189
unsigned char * new_tbl = calloc(Pagetable2_size, 1);
190
if (new_tbl == 0) return -1;
191
caml_page_table[i] = new_tbl;
193
caml_page_table[i][j] = (caml_page_table[i][j] & ~toclear) | toset;
199
int caml_page_table_add(int kind, void * start, void * end)
201
uintnat pstart = (uintnat) start & Page_mask;
202
uintnat pend = ((uintnat) end - 1) & Page_mask;
205
for (p = pstart; p <= pend; p += Page_size)
206
if (caml_page_table_modify(p, 0, kind) != 0) return -1;
210
int caml_page_table_remove(int kind, void * start, void * end)
212
uintnat pstart = (uintnat) start & Page_mask;
213
uintnat pend = ((uintnat) end - 1) & Page_mask;
216
for (p = pstart; p <= pend; p += Page_size)
217
if (caml_page_table_modify(p, kind, 0) != 0) return -1;
37
221
/* Allocate a block of the requested size, to be passed to
38
222
[caml_add_to_heap] later.
93
266
caml_gc_message (0x04, "Growing heap to %luk bytes\n",
94
267
(caml_stat_heap_size + Chunk_size (m)) / 1024);
96
/* Extend the page table as needed. */
97
if (Page (m) < caml_page_low){
98
page_table_entry *block, *new_page_table;
99
asize_t new_page_low = Page (m);
100
asize_t new_size = caml_page_high - new_page_low;
102
caml_gc_message (0x08, "Growing page table to %lu entries\n", new_size);
103
block = malloc (new_size * sizeof (page_table_entry));
105
caml_gc_message (0x08, "No room for growing page table\n", 0);
108
new_page_table = block - new_page_low;
109
for (i = new_page_low; i < caml_page_low; i++){
110
new_page_table [i] = Not_in_heap;
112
for (i = caml_page_low; i < caml_page_high; i++){
113
new_page_table [i] = caml_page_table [i];
115
free (caml_page_table + caml_page_low);
116
caml_page_table = new_page_table;
117
caml_page_low = new_page_low;
119
if (Page (m + Chunk_size (m)) > caml_page_high){
120
page_table_entry *block, *new_page_table;
121
asize_t new_page_high = Page (m + Chunk_size (m));
122
asize_t new_size = new_page_high - caml_page_low;
124
caml_gc_message (0x08, "Growing page table to %lu entries\n", new_size);
125
block = malloc (new_size * sizeof (page_table_entry));
127
caml_gc_message (0x08, "No room for growing page table\n", 0);
130
new_page_table = block - caml_page_low;
131
for (i = caml_page_low; i < caml_page_high; i++){
132
new_page_table [i] = caml_page_table [i];
134
for (i = caml_page_high; i < new_page_high; i++){
135
new_page_table [i] = Not_in_heap;
137
free (caml_page_table + caml_page_low);
138
caml_page_table = new_page_table;
139
caml_page_high = new_page_high;
142
/* Mark the pages as being in the heap. */
143
for (i = Page (m); i < Page (m + Chunk_size (m)); i++){
144
caml_page_table [i] = In_heap;
269
/* Register block in page table */
270
if (caml_page_table_add(In_heap, m, m + Chunk_size(m)) != 0)
147
273
/* Chain this heap chunk. */