summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/users_guide/8.0.2-notes.rst4
-rw-r--r--includes/stg/Types.h4
-rw-r--r--rts/RtsFlags.c5
-rw-r--r--rts/posix/OSMem.c30
-rw-r--r--rts/sm/MBlock.c6
-rw-r--r--rts/sm/OSMem.h5
-rw-r--r--rts/win32/OSMem.c9
7 files changed, 49 insertions, 14 deletions
diff --git a/docs/users_guide/8.0.2-notes.rst b/docs/users_guide/8.0.2-notes.rst
index 66cbe31c81..924998fba9 100644
--- a/docs/users_guide/8.0.2-notes.rst
+++ b/docs/users_guide/8.0.2-notes.rst
@@ -33,6 +33,10 @@ Compiler
initial cmm from STG-to-C-- code generation and :ghc-flag:`-ddump-cmm-verbose`
to obtain the intermediates from all C-- pipeline stages.
+- The RTS :ghc-flag: `-xb` now reads the base heap address in any base,
+ defaulting to decimal, hexadecimal if the address starts with `0x`, and
+ octal if the address starts with `0`.
+
Runtime system
~~~~~~~~~~~~~~
diff --git a/includes/stg/Types.h b/includes/stg/Types.h
index 0ad3c5c77d..3a08eb2f85 100644
--- a/includes/stg/Types.h
+++ b/includes/stg/Types.h
@@ -124,6 +124,8 @@ typedef uint32_t StgHalfWord;
#define FMT_HexWord FMT_HexWord64
#define FMT_Int FMT_Int64
+#define strToStgWord strtoull
+
#elif SIZEOF_VOID_P == 4
typedef int32_t StgInt;
typedef uint32_t StgWord;
@@ -139,6 +141,8 @@ typedef uint16_t StgHalfWord;
#define FMT_HexWord FMT_HexWord32
#define FMT_Int FMT_Int32
+#define strToStgWord strtoul
+
#else
#error GHC untested on this architecture: sizeof(void *) != 4 or 8
#endif
diff --git a/rts/RtsFlags.c b/rts/RtsFlags.c
index 92b7e871df..c994a0ce88 100644
--- a/rts/RtsFlags.c
+++ b/rts/RtsFlags.c
@@ -271,6 +271,9 @@ usage_text[] = {
" -O<size> Sets the minimum size of the old generation (default 1M)",
" -M<size> Sets the maximum heap size (default unlimited) Egs: -M256k -M1G",
" -H<size> Sets the minimum heap size (default 0M) Egs: -H24m -H1G",
+" -xb<addr> Sets the address from which a suitable start for the heap memory",
+" will be searched from. This is useful if the default address",
+" clashes with some third-party library.",
" -m<n> Minimum % of heap which must be available (default 3%)",
" -G<n> Number of generations (default: 2)",
" -c<n> Use in-place compaction instead of copying in the oldest generation",
@@ -1293,7 +1296,7 @@ error = rtsTrue;
OPTION_UNSAFE;
if (rts_argv[arg][3] != '\0') {
RtsFlags.GcFlags.heapBase
- = strtol(rts_argv[arg]+3, (char **) NULL, 16);
+ = strToStgWord(rts_argv[arg]+3, (char **) NULL, 0);
} else {
errorBelch("-xb: requires argument");
error = rtsTrue;
diff --git a/rts/posix/OSMem.c b/rts/posix/OSMem.c
index 99620ee31e..6e9af3e9c3 100644
--- a/rts/posix/OSMem.c
+++ b/rts/posix/OSMem.c
@@ -450,16 +450,18 @@ osTryReserveHeapMemory (W_ len, void *hint)
return start;
}
-void *osReserveHeapMemory(W_ *len)
+void *osReserveHeapMemory(void *startAddressPtr, W_ *len)
{
int attempt;
void *at;
/* We want to ensure the heap starts at least 8 GB inside the address space,
- to make sure that any dynamically loaded code will be close enough to the
- original code so that short relocations will work. This is in particular
- important on Darwin/Mach-O, because object files not compiled as shared
- libraries are position independent but cannot be loaded about 4GB.
+ since we want to reserve the address space below that address for code.
+ Specifically, we need to make sure that any dynamically loaded code will
+ be close enough to the original code so that short relocations will work.
+ This is in particular important on Darwin/Mach-O, because object files
+ not compiled as shared libraries are position independent but cannot be
+ loaded above 4GB.
We do so with a hint to the mmap, and we verify the OS satisfied our
hint. We loop, shifting our hint by 1 BLOCK_SIZE every time, in case
@@ -472,6 +474,19 @@ void *osReserveHeapMemory(W_ *len)
*/
+ W_ minimumAddress = (W_)8 * (1 << 30);
+ // We don't use minimumAddress (0x200000000) as default because we know
+ // it can clash with third-party libraries. See ticket #12573.
+ W_ startAddress = 0x4200000000;
+ if (startAddressPtr) {
+ startAddress = (W_)startAddressPtr;
+ }
+ if (startAddress < minimumAddress) {
+ errorBelch(
+ "Provided heap start address %p is lower than minimum address %p",
+ (void*)startAddress, (void*)minimumAddress);
+ }
+
attempt = 0;
while (1) {
if (*len < MBLOCK_SIZE) {
@@ -479,7 +494,7 @@ void *osReserveHeapMemory(W_ *len)
barf("osReserveHeapMemory: Failed to allocate heap storage");
}
- void *hint = (void*)((W_)8 * (1 << 30) + attempt * BLOCK_SIZE);
+ void *hint = (void*)(startAddress + attempt * BLOCK_SIZE);
at = osTryReserveHeapMemory(*len, hint);
if (at == NULL) {
// This means that mmap failed which we take to mean that we asked
@@ -487,7 +502,7 @@ void *osReserveHeapMemory(W_ *len)
// limits. In this case we reduce our allocation request by a factor
// of two and try again.
*len /= 2;
- } else if ((W_)at >= ((W_)8 * (1 << 30))) {
+ } else if ((W_)at >= minimumAddress) {
// Success! We were given a block of memory starting above the 8 GB
// mark, which is what we were looking for.
break;
@@ -498,6 +513,7 @@ void *osReserveHeapMemory(W_ *len)
sysErrorBelch("unable to release reserved heap");
}
}
+ attempt++;
}
return at;
diff --git a/rts/sm/MBlock.c b/rts/sm/MBlock.c
index 4be7fd4356..f6640d173c 100644
--- a/rts/sm/MBlock.c
+++ b/rts/sm/MBlock.c
@@ -662,7 +662,11 @@ initMBlocks(void)
#else
size = (W_)1 << 40; // 1 TByte
#endif
- void *addr = osReserveHeapMemory(&size);
+ void *startAddress = NULL;
+ if (RtsFlags.GcFlags.heapBase) {
+ startAddress = (void*) RtsFlags.GcFlags.heapBase;
+ }
+ void *addr = osReserveHeapMemory(startAddress, &size);
mblock_address_space.begin = (W_)addr;
mblock_address_space.end = (W_)addr + size;
diff --git a/rts/sm/OSMem.h b/rts/sm/OSMem.h
index 660942827d..69d87c201e 100644
--- a/rts/sm/OSMem.h
+++ b/rts/sm/OSMem.h
@@ -58,7 +58,10 @@ roundUpToPage (size_t x)
// to the amount of memory actually reserved.
//
// This function is called once when the block allocator is initialized.
-void *osReserveHeapMemory(W_ *len);
+//
+// startAddress must be greater or equal than 8 * (1 << 30), and can be
+// NULL, in which case a default will be picked by the RTS.
+void *osReserveHeapMemory(void *startAddress, W_ *len);
// Commit (allocate memory for) a piece of address space, which must
// be within the previously reserved space After this call, it is safe
diff --git a/rts/win32/OSMem.c b/rts/win32/OSMem.c
index 3450267d9c..3d9a304fda 100644
--- a/rts/win32/OSMem.c
+++ b/rts/win32/OSMem.c
@@ -430,19 +430,20 @@ void setExecutable (void *p, W_ len, rtsBool exec)
static void* heap_base = NULL;
-void *osReserveHeapMemory (W_ *len)
+void *osReserveHeapMemory (void *startAddress, W_ *len)
{
void *start;
- heap_base = VirtualAlloc(NULL, *len + MBLOCK_SIZE,
+ heap_base = VirtualAlloc(startAddress, *len + MBLOCK_SIZE,
MEM_RESERVE, PAGE_READWRITE);
if (heap_base == NULL) {
if (GetLastError() == ERROR_NOT_ENOUGH_MEMORY) {
errorBelch("out of memory");
} else {
sysErrorBelch(
- "osReserveHeapMemory: VirtualAlloc MEM_RESERVE %llu bytes failed",
- len + MBLOCK_SIZE);
+ "osReserveHeapMemory: VirtualAlloc MEM_RESERVE %llu bytes \
+ at address %p bytes failed",
+ len + MBLOCK_SIZE, startAddress);
}
stg_exit(EXIT_FAILURE);
}