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
|
#define GC_SMALLEST_PAGESIZE 4096
/* #define DEBUG_MREMAP 1 */
/* Used to allocate at the head and tail of an existing allocation */
static void *GC_extendHead (void *base, size_t length);
static void *GC_extendTail (void *base, size_t length);
void *GC_mremap (void *base, size_t oldLength, size_t newLength) {
static void* cacheAddress = 0;
static size_t cacheOldLength = 0;
static size_t cacheNewLength = 0;
static size_t cacheTailSize;
static size_t cacheHeadSize;
void* tail;
void* head;
void* alloc;
size_t growth, bsLow, bsHigh, bsTry;
#ifdef DEBUG_MREMAP
fprintf(stderr, "remap(%08X, %d, %d)\n", (size_t)base, oldLength, newLength);
fflush(stderr);
#endif
if (newLength == oldLength)
return base;
if (newLength < oldLength) {
GC_release((char*)base + newLength, oldLength-newLength);
return base;
}
growth = newLength-oldLength;
if (cacheAddress == base &&
cacheOldLength == oldLength &&
cacheNewLength > newLength) /* cache only during backoff */
goto GC_mremap_cached;
/* Start probing for the available tail length */
bsLow = 0;
bsHigh = (growth+GC_SMALLEST_PAGESIZE-1)/GC_SMALLEST_PAGESIZE;
/* Round bsHigh to a power of two -> allocation works with all page sizes */
for (bsTry = 1; bsTry <= bsHigh; bsTry += bsTry) { }
bsHigh = bsTry;
while (bsHigh - bsLow > 1) {
bsTry = (bsHigh + bsLow)/2;
tail = (char*)base + oldLength;
alloc = GC_extendTail(tail, bsTry*GC_SMALLEST_PAGESIZE);
if (tail == alloc) {
GC_release(alloc, bsTry*GC_SMALLEST_PAGESIZE);
bsLow = bsTry;
} else {
if (alloc != (void*)-1)
GC_release(alloc, bsTry*GC_SMALLEST_PAGESIZE);
bsHigh = bsTry;
}
}
cacheTailSize = bsLow*GC_SMALLEST_PAGESIZE;
/* Start probing for the available head length */
bsLow = 0;
bsHigh = (growth+GC_SMALLEST_PAGESIZE-1)/GC_SMALLEST_PAGESIZE;
/* Round bsHigh to a power of two -> allocation works with all page sizes */
for (bsTry = 1; bsTry <= bsHigh; bsTry += bsTry) { }
bsHigh = bsTry;
while (bsHigh - bsLow > 1) {
bsTry = (bsHigh + bsLow)/2;
head = (char*)base - bsTry*GC_SMALLEST_PAGESIZE;
alloc = GC_extendHead(head, bsTry*GC_SMALLEST_PAGESIZE);
if (head == alloc) {
GC_release(alloc, bsTry*GC_SMALLEST_PAGESIZE);
bsLow = bsTry;
} else {
if (alloc != (void*)-1)
GC_release(alloc, bsTry*GC_SMALLEST_PAGESIZE);
bsHigh = bsTry;
}
}
cacheHeadSize = bsLow*GC_SMALLEST_PAGESIZE;
#ifdef DEBUG_MREMAP
fprintf(stderr, "Expansion detects: %10d/%10d/%10d = %10d\n",
cacheHeadSize, oldLength, cacheTailSize,
cacheHeadSize+ oldLength+ cacheTailSize);
fflush(stderr);
#endif
cacheAddress = base;
cacheOldLength = oldLength;
GC_mremap_cached:
cacheNewLength = newLength;
/* Is there enough free space? */
if (cacheTailSize + cacheHeadSize < growth) {
/* No, there's not. Try to move it instead. */
alloc = GC_mmapAnon(0, newLength);
if (alloc != (void*)-1) {
memcpy(alloc, base, oldLength);
GC_release(base, oldLength);
return alloc;
}
/* Failed even to move it */
return (void*)-1;
}
#ifdef DEBUG_MREMAP
fprintf(stderr, "Expansion attempts %d bytes\n", newLength);
fflush(stderr);
#endif
if (growth <= cacheTailSize) {
tail = (char*)base + oldLength;
alloc = GC_extendTail(tail, growth);
if (alloc != tail) {
/* This shouldn't happen; we tested for the memory! */
if (alloc != (void*)-1)
GC_release(alloc, growth);
return (void*)-1;
}
return base;
}
if (cacheTailSize > 0) {
tail = (char*)base + oldLength;
alloc = GC_extendTail(tail, cacheTailSize);
if (alloc != tail) {
/* This shouldn't happen; we tested for the memory! */
if (alloc != (void*)-1)
GC_release(alloc, cacheTailSize);
return (void*)-1;
}
} else {
tail = 0; /* quell warning */
}
head = (char*)base - (growth-cacheTailSize);
alloc = GC_extendHead(head, growth-cacheTailSize);
if (alloc != head) {
/* This shouldn't happen; we tested for the memory! */
if (alloc != (void*)-1)
GC_release(alloc, growth-cacheTailSize);
if (cacheTailSize > 0)
GC_release(tail, cacheTailSize);
return (void*)-1;
}
memmove(head, base, oldLength);
return head;
}
|