Import Upstream version 20180207
[hcoop/debian/mlton.git] / runtime / platform / mremap.c
CommitLineData
7f918cf1
CE
1#define GC_SMALLEST_PAGESIZE 4096
2/* #define DEBUG_MREMAP 1 */
3
4/* Used to allocate at the head and tail of an existing allocation */
5static void *GC_extendHead (void *base, size_t length);
6static void *GC_extendTail (void *base, size_t length);
7
8void *GC_mremap (void *base, size_t oldLength, size_t newLength) {
9 static void* cacheAddress = 0;
10 static size_t cacheOldLength = 0;
11 static size_t cacheNewLength = 0;
12 static size_t cacheTailSize;
13 static size_t cacheHeadSize;
14
15 void* tail;
16 void* head;
17 void* alloc;
18 size_t growth, bsLow, bsHigh, bsTry;
19
20#ifdef DEBUG_MREMAP
21 fprintf(stderr, "remap(%08X, %d, %d)\n", (size_t)base, oldLength, newLength);
22 fflush(stderr);
23#endif
24
25 if (newLength == oldLength)
26 return base;
27 if (newLength < oldLength) {
28 GC_release((char*)base + newLength, oldLength-newLength);
29 return base;
30 }
31
32 growth = newLength-oldLength;
33
34 if (cacheAddress == base &&
35 cacheOldLength == oldLength &&
36 cacheNewLength > newLength) /* cache only during backoff */
37 goto GC_mremap_cached;
38
39 /* Start probing for the available tail length */
40 bsLow = 0;
41 bsHigh = (growth+GC_SMALLEST_PAGESIZE-1)/GC_SMALLEST_PAGESIZE;
42 /* Round bsHigh to a power of two -> allocation works with all page sizes */
43 for (bsTry = 1; bsTry <= bsHigh; bsTry += bsTry) { }
44 bsHigh = bsTry;
45 while (bsHigh - bsLow > 1) {
46 bsTry = (bsHigh + bsLow)/2;
47 tail = (char*)base + oldLength;
48 alloc = GC_extendTail(tail, bsTry*GC_SMALLEST_PAGESIZE);
49
50 if (tail == alloc) {
51 GC_release(alloc, bsTry*GC_SMALLEST_PAGESIZE);
52 bsLow = bsTry;
53 } else {
54 if (alloc != (void*)-1)
55 GC_release(alloc, bsTry*GC_SMALLEST_PAGESIZE);
56 bsHigh = bsTry;
57 }
58 }
59 cacheTailSize = bsLow*GC_SMALLEST_PAGESIZE;
60
61 /* Start probing for the available head length */
62 bsLow = 0;
63 bsHigh = (growth+GC_SMALLEST_PAGESIZE-1)/GC_SMALLEST_PAGESIZE;
64 /* Round bsHigh to a power of two -> allocation works with all page sizes */
65 for (bsTry = 1; bsTry <= bsHigh; bsTry += bsTry) { }
66 bsHigh = bsTry;
67 while (bsHigh - bsLow > 1) {
68 bsTry = (bsHigh + bsLow)/2;
69 head = (char*)base - bsTry*GC_SMALLEST_PAGESIZE;
70 alloc = GC_extendHead(head, bsTry*GC_SMALLEST_PAGESIZE);
71
72 if (head == alloc) {
73 GC_release(alloc, bsTry*GC_SMALLEST_PAGESIZE);
74 bsLow = bsTry;
75 } else {
76 if (alloc != (void*)-1)
77 GC_release(alloc, bsTry*GC_SMALLEST_PAGESIZE);
78 bsHigh = bsTry;
79 }
80 }
81 cacheHeadSize = bsLow*GC_SMALLEST_PAGESIZE;
82
83#ifdef DEBUG_MREMAP
84 fprintf(stderr, "Expansion detects: %10d/%10d/%10d = %10d\n",
85 cacheHeadSize, oldLength, cacheTailSize,
86 cacheHeadSize+ oldLength+ cacheTailSize);
87 fflush(stderr);
88#endif
89
90 cacheAddress = base;
91 cacheOldLength = oldLength;
92
93GC_mremap_cached:
94 cacheNewLength = newLength;
95
96 /* Is there enough free space? */
97 if (cacheTailSize + cacheHeadSize < growth) {
98 /* No, there's not. Try to move it instead. */
99 alloc = GC_mmapAnon(0, newLength);
100 if (alloc != (void*)-1) {
101 memcpy(alloc, base, oldLength);
102 GC_release(base, oldLength);
103 return alloc;
104 }
105 /* Failed even to move it */
106 return (void*)-1;
107 }
108
109#ifdef DEBUG_MREMAP
110 fprintf(stderr, "Expansion attempts %d bytes\n", newLength);
111 fflush(stderr);
112#endif
113
114 if (growth <= cacheTailSize) {
115 tail = (char*)base + oldLength;
116 alloc = GC_extendTail(tail, growth);
117 if (alloc != tail) {
118 /* This shouldn't happen; we tested for the memory! */
119 if (alloc != (void*)-1)
120 GC_release(alloc, growth);
121 return (void*)-1;
122 }
123 return base;
124 }
125
126 if (cacheTailSize > 0) {
127 tail = (char*)base + oldLength;
128 alloc = GC_extendTail(tail, cacheTailSize);
129 if (alloc != tail) {
130 /* This shouldn't happen; we tested for the memory! */
131 if (alloc != (void*)-1)
132 GC_release(alloc, cacheTailSize);
133 return (void*)-1;
134 }
135 } else {
136 tail = 0; /* quell warning */
137 }
138
139 head = (char*)base - (growth-cacheTailSize);
140 alloc = GC_extendHead(head, growth-cacheTailSize);
141 if (alloc != head) {
142 /* This shouldn't happen; we tested for the memory! */
143 if (alloc != (void*)-1)
144 GC_release(alloc, growth-cacheTailSize);
145 if (cacheTailSize > 0)
146 GC_release(tail, cacheTailSize);
147 return (void*)-1;
148 }
149
150 memmove(head, base, oldLength);
151 return head;
152}