diff options
author | Araq <rumpf_a@web.de> | 2017-01-30 19:01:03 +0100 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2017-01-30 19:01:03 +0100 |
commit | b26e6e3589f0564c6c3838cdd09d810dea6b1080 (patch) | |
tree | ecf2496f5592f38b3672e10ffb83b33084ba733c | |
parent | 6050102b76b406afea435d72378401f4300da9b9 (diff) | |
download | Nim-b26e6e3589f0564c6c3838cdd09d810dea6b1080.tar.gz |
fixes #5301
-rw-r--r-- | config/nim.cfg | 10 | ||||
-rw-r--r-- | lib/system/alloc.nim | 95 | ||||
-rw-r--r-- | lib/system/osalloc.nim | 7 |
3 files changed, 68 insertions, 44 deletions
diff --git a/config/nim.cfg b/config/nim.cfg index a5c9eeccd..48ab0d7bd 100644 --- a/config/nim.cfg +++ b/config/nim.cfg @@ -100,7 +100,7 @@ path="$lib/pure" @if windows: #gcc.path = r"$nim\dist\mingw\bin" @if gcc: - tlsEmulation:on + #tlsEmulation:on @end @end @@ -110,7 +110,13 @@ path="$lib/pure" gcc.options.always = "-w" gcc.cpp.options.always = "-w -fpermissive" @else: - gcc.options.always = "-w" + @if cpu32: + gcc.options.always = "-w -m32" + gcc.options.linker = "-m32" + @else: + gcc.options.always = "-w -m64" + gcc.options.linker = "-m64" + @end gcc.cpp.options.always = "-w -fpermissive" @end diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim index 9387c3128..e630aa3c1 100644 --- a/lib/system/alloc.nim +++ b/lib/system/alloc.nim @@ -54,7 +54,7 @@ type BaseChunk {.pure, inheritable.} = object prevSize: int # size of previous chunk; for coalescing size: int # if < PageSize it is a small chunk - used: bool # later will be optimized into prevSize... + origSize: int # 0th bit == 1 if 'used' SmallChunk = object of BaseChunk next, prev: PSmallChunk # chunks of the same size @@ -65,11 +65,11 @@ type BigChunk = object of BaseChunk # not necessarily > PageSize! next, prev: PBigChunk # chunks of the same (or bigger) size - align: int + heapLink: PBigChunk # linked list of all chunks for bulk 'deallocPages' data: AlignType # start of usable memory -template smallChunkOverhead(): expr = sizeof(SmallChunk)-sizeof(AlignType) -template bigChunkOverhead(): expr = sizeof(BigChunk)-sizeof(AlignType) +template smallChunkOverhead(): untyped = sizeof(SmallChunk)-sizeof(AlignType) +template bigChunkOverhead(): untyped = sizeof(BigChunk)-sizeof(AlignType) # ------------- chunk table --------------------------------------------------- # We use a PtrSet of chunk starts and a table[Page, chunksize] for chunk @@ -98,6 +98,7 @@ type currMem, maxMem, freeMem: int # memory sizes (allocated from OS) lastSize: int # needed for the case that OS gives us pages linearly freeChunksList: PBigChunk # XXX make this a datastructure with O(1) access + heapLink: PBigChunk # used to link every chunk for bulk 'deallocPages' chunkStarts: IntSet root, deleted, last, freeAvlNodes: PAvlNode locked, blockChunkSizeIncrease: bool # if locked, we cannot free pages. @@ -241,7 +242,7 @@ proc isSmallChunk(c: PChunk): bool {.inline.} = return c.size <= SmallChunkSize-smallChunkOverhead() proc chunkUnused(c: PChunk): bool {.inline.} = - result = not c.used + result = (c.origSize and 1) == 0 iterator allObjects(m: var MemRegion): pointer {.inline.} = m.locked = true @@ -310,12 +311,14 @@ proc requestOsChunks(a: var MemRegion, size: int): PBigChunk = incCurrMem(a, size) inc(a.freeMem, size) + result.heapLink = a.heapLink + result.origSize = size + a.heapLink = result sysAssert((cast[ByteAddress](result) and PageMask) == 0, "requestOsChunks 1") #zeroMem(result, size) result.next = nil result.prev = nil - result.used = false result.size = size # update next.prevSize: var nxt = cast[ByteAddress](result) +% size @@ -336,19 +339,21 @@ proc requestOsChunks(a: var MemRegion, size: int): PBigChunk = result.prevSize = 0 # unknown a.lastSize = size # for next request -proc freeOsChunks(a: var MemRegion, p: pointer, size: int) = - # update next.prevSize: - var c = cast[PChunk](p) - var nxt = cast[ByteAddress](p) +% c.size - sysAssert((nxt and PageMask) == 0, "freeOsChunks") - var next = cast[PChunk](nxt) - if pageIndex(next) in a.chunkStarts: - next.prevSize = 0 # XXX used - excl(a.chunkStarts, pageIndex(p)) - osDeallocPages(p, size) - decCurrMem(a, size) - dec(a.freeMem, size) - #c_fprintf(stdout, "[Alloc] back to OS: %ld\n", size) +when false: + # with the new linked list design this is not possible anymore: + proc freeOsChunks(a: var MemRegion, p: pointer, size: int) = + # update next.prevSize: + var c = cast[PChunk](p) + var nxt = cast[ByteAddress](p) +% c.size + sysAssert((nxt and PageMask) == 0, "freeOsChunks") + var next = cast[PChunk](nxt) + if pageIndex(next) in a.chunkStarts: + next.prevSize = 0 # XXX used + excl(a.chunkStarts, pageIndex(p)) + osDeallocPages(p, size) + decCurrMem(a, size) + dec(a.freeMem, size) + #c_fprintf(stdout, "[Alloc] back to OS: %ld\n", size) proc isAccessible(a: MemRegion, p: pointer): bool {.inline.} = result = contains(a.chunkStarts, pageIndex(p)) @@ -414,19 +419,20 @@ proc freeBigChunk(a: var MemRegion, c: PBigChunk) = excl(a.chunkStarts, pageIndex(c)) c = cast[PBigChunk](le) - if c.size < ChunkOsReturn or doNotUnmap or a.locked: - incl(a, a.chunkStarts, pageIndex(c)) - updatePrevSize(a, c, c.size) - listAdd(a.freeChunksList, c) - c.used = false - else: - freeOsChunks(a, c, c.size) + #if c.size < ChunkOsReturn or doNotUnmap or a.locked: + incl(a, a.chunkStarts, pageIndex(c)) + updatePrevSize(a, c, c.size) + listAdd(a.freeChunksList, c) + # set 'used' to false: + c.origSize = c.origSize and not 1 + #else: + # freeOsChunks(a, c, c.size) proc splitChunk(a: var MemRegion, c: PBigChunk, size: int) = var rest = cast[PBigChunk](cast[ByteAddress](c) +% size) sysAssert(rest notin a.freeChunksList, "splitChunk") rest.size = c.size - size - rest.used = false + rest.origSize = 0 # not used and size irrelevant rest.next = nil rest.prev = nil rest.prevSize = size @@ -461,7 +467,8 @@ proc getBigChunk(a: var MemRegion, size: int): PBigChunk = if result.size > size: splitChunk(a, result, size) result.prevSize = 0 # XXX why is this needed? - result.used = true + # set 'used' to to true: + result.origSize = result.origSize or 1 incl(a, a.chunkStarts, pageIndex(result)) dec(a.freeMem, size) @@ -704,18 +711,26 @@ proc realloc(allocator: var MemRegion, p: pointer, newsize: Natural): pointer = proc deallocOsPages(a: var MemRegion) = # we free every 'ordinarily' allocated page by iterating over the page bits: - for p in elements(a.chunkStarts): - var page = cast[PChunk](p shl PageShift) - when not doNotUnmap: - var size = if page.size < PageSize: PageSize else: page.size - osDeallocPages(page, size) - else: - # Linux on PowerPC for example frees MORE than asked if 'munmap' - # receives the start of an originally mmap'ed memory block. This is not - # too bad, but we must not access 'page.size' then as that could trigger - # a segfault. But we don't need to access 'page.size' here anyway, - # because calling munmap with PageSize suffices: - osDeallocPages(page, PageSize) + var it = a.heapLink + while it != nil: + let next = it.heapLink + sysAssert it.origSize >= PageSize, "origSize too small" + # note: + osDeallocPages(it, it.origSize and not 1) + it = next + when false: + for p in elements(a.chunkStarts): + var page = cast[PChunk](p shl PageShift) + when not doNotUnmap: + var size = if page.size < PageSize: PageSize else: page.size + osDeallocPages(page, size) + else: + # Linux on PowerPC for example frees MORE than asked if 'munmap' + # receives the start of an originally mmap'ed memory block. This is not + # too bad, but we must not access 'page.size' then as that could trigger + # a segfault. But we don't need to access 'page.size' here anyway, + # because calling munmap with PageSize suffices: + osDeallocPages(page, PageSize) # And then we free the pages that are in use for the page bits: llDeallocAll(a) diff --git a/lib/system/osalloc.nim b/lib/system/osalloc.nim index b0639a75a..a57a88e8f 100644 --- a/lib/system/osalloc.nim +++ b/lib/system/osalloc.nim @@ -132,7 +132,7 @@ elif defined(windows): header: "<windows.h>", stdcall, importc: "VirtualAlloc".} proc virtualFree(lpAddress: pointer, dwSize: int, - dwFreeType: int32) {.header: "<windows.h>", stdcall, + dwFreeType: int32): cint {.header: "<windows.h>", stdcall, importc: "VirtualFree".} proc osAllocPages(size: int): pointer {.inline.} = @@ -151,7 +151,10 @@ elif defined(windows): # Windows :-(. We have to live with MEM_DECOMMIT instead. # Well that used to be the case but MEM_DECOMMIT fragments the address # space heavily, so we now treat Windows as a strange unmap target. - when reallyOsDealloc: virtualFree(p, 0, MEM_RELEASE) + when reallyOsDealloc: + if virtualFree(p, 0, MEM_RELEASE) == 0: + cprintf "yes, failing!" + quit 1 #VirtualFree(p, size, MEM_DECOMMIT) elif hostOS == "standalone": |