diff options
| -rw-r--r-- | docs/users_guide/8.0.2-notes.rst | 4 | ||||
| -rw-r--r-- | includes/stg/Types.h | 4 | ||||
| -rw-r--r-- | rts/RtsFlags.c | 5 | ||||
| -rw-r--r-- | rts/posix/OSMem.c | 30 | ||||
| -rw-r--r-- | rts/sm/MBlock.c | 6 | ||||
| -rw-r--r-- | rts/sm/OSMem.h | 5 | ||||
| -rw-r--r-- | rts/win32/OSMem.c | 9 |
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); } |
