diff options
Diffstat (limited to 'lib/system/alloc.nim')
-rw-r--r-- | lib/system/alloc.nim | 148 |
1 files changed, 1 insertions, 147 deletions
diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim index 67d380391..e0fd53b7b 100644 --- a/lib/system/alloc.nim +++ b/lib/system/alloc.nim @@ -13,153 +13,7 @@ # - make searching for block O(1) {.push profiler:off.} -proc roundup(x, v: int): int {.inline.} = - result = (x + (v-1)) and not (v-1) - sysAssert(result >= x, "roundup: result < x") - #return ((-x) and (v-1)) +% x - -sysAssert(roundup(14, PageSize) == PageSize, "invalid PageSize") -sysAssert(roundup(15, 8) == 16, "roundup broken") -sysAssert(roundup(65, 8) == 72, "roundup broken 2") - -# ------------ platform specific chunk allocation code ----------------------- - -# some platforms have really weird unmap behaviour: unmap(blockStart, PageSize) -# really frees the whole block. Happens for Linux/PowerPC for example. Amd64 -# and x86 are safe though; Windows is special because MEM_RELEASE can only be -# used with a size of 0. We also allow unmapping to be turned off with -# -d:nimAllocNoUnmap: -const doNotUnmap = not (defined(amd64) or defined(i386)) or - defined(windows) or defined(nimAllocNoUnmap) - - -when defined(emscripten): - const - PROT_READ = 1 # page can be read - PROT_WRITE = 2 # page can be written - MAP_PRIVATE = 2'i32 # Changes are private - - var MAP_ANONYMOUS {.importc: "MAP_ANONYMOUS", header: "<sys/mman.h>".}: cint - type - PEmscriptenMMapBlock = ptr EmscriptenMMapBlock - EmscriptenMMapBlock {.pure, inheritable.} = object - realSize: int # size of previous chunk; for coalescing - realPointer: pointer # if < PageSize it is a small chunk - - proc mmap(adr: pointer, len: int, prot, flags, fildes: cint, - off: int): pointer {.header: "<sys/mman.h>".} - - proc munmap(adr: pointer, len: int) {.header: "<sys/mman.h>".} - - proc osAllocPages(block_size: int): pointer {.inline.} = - let realSize = block_size + sizeof(EmscriptenMMapBlock) + PageSize + 1 - result = mmap(nil, realSize, PROT_READ or PROT_WRITE, - MAP_PRIVATE or MAP_ANONYMOUS, -1, 0) - if result == nil or result == cast[pointer](-1): - raiseOutOfMem() - - let realPointer = result - let pos = cast[int](result) - - # Convert pointer to PageSize correct one. - var new_pos = cast[ByteAddress](pos) +% (PageSize - (pos %% PageSize)) - if (new_pos-pos)< sizeof(EmscriptenMMapBlock): - new_pos = new_pos +% PageSize - result = cast[pointer](new_pos) - - var mmapDescrPos = cast[ByteAddress](result) -% sizeof(EmscriptenMMapBlock) - - var mmapDescr = cast[EmscriptenMMapBlock](mmapDescrPos) - mmapDescr.realSize = realSize - mmapDescr.realPointer = realPointer - - c_fprintf(c_stdout, "[Alloc] size %d %d realSize:%d realPos:%d\n", block_size, cast[int](result), realSize, cast[int](realPointer)) - - proc osDeallocPages(p: pointer, size: int) {.inline} = - var mmapDescrPos = cast[ByteAddress](p) -% sizeof(EmscriptenMMapBlock) - var mmapDescr = cast[EmscriptenMMapBlock](mmapDescrPos) - munmap(mmapDescr.realPointer, mmapDescr.realSize) - -elif defined(posix): - const - PROT_READ = 1 # page can be read - PROT_WRITE = 2 # page can be written - MAP_PRIVATE = 2'i32 # Changes are private - - when defined(macosx) or defined(bsd): - const MAP_ANONYMOUS = 0x1000 - elif defined(solaris): - const MAP_ANONYMOUS = 0x100 - else: - var - MAP_ANONYMOUS {.importc: "MAP_ANONYMOUS", header: "<sys/mman.h>".}: cint - - proc mmap(adr: pointer, len: int, prot, flags, fildes: cint, - off: int): pointer {.header: "<sys/mman.h>".} - - proc munmap(adr: pointer, len: int) {.header: "<sys/mman.h>".} - - proc osAllocPages(size: int): pointer {.inline.} = - result = mmap(nil, size, PROT_READ or PROT_WRITE, - MAP_PRIVATE or MAP_ANONYMOUS, -1, 0) - if result == nil or result == cast[pointer](-1): - raiseOutOfMem() - - proc osDeallocPages(p: pointer, size: int) {.inline} = - when reallyOsDealloc: munmap(p, size) - -elif defined(windows): - const - MEM_RESERVE = 0x2000 - MEM_COMMIT = 0x1000 - MEM_TOP_DOWN = 0x100000 - PAGE_READWRITE = 0x04 - - MEM_DECOMMIT = 0x4000 - MEM_RELEASE = 0x8000 - - proc virtualAlloc(lpAddress: pointer, dwSize: int, flAllocationType, - flProtect: int32): pointer {. - header: "<windows.h>", stdcall, importc: "VirtualAlloc".} - - proc virtualFree(lpAddress: pointer, dwSize: int, - dwFreeType: int32) {.header: "<windows.h>", stdcall, - importc: "VirtualFree".} - - proc osAllocPages(size: int): pointer {.inline.} = - result = virtualAlloc(nil, size, MEM_RESERVE or MEM_COMMIT, - PAGE_READWRITE) - if result == nil: raiseOutOfMem() - - proc osDeallocPages(p: pointer, size: int) {.inline.} = - # according to Microsoft, 0 is the only correct value for MEM_RELEASE: - # This means that the OS has some different view over how big the block is - # that we want to free! So, we cannot reliably release the memory back to - # 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) - #VirtualFree(p, size, MEM_DECOMMIT) - -elif hostOS == "standalone": - var - theHeap: array[1024*PageSize, float64] # 'float64' for alignment - bumpPointer = cast[int](addr theHeap) - - proc osAllocPages(size: int): pointer {.inline.} = - if size+bumpPointer < cast[int](addr theHeap) + sizeof(theHeap): - result = cast[pointer](bumpPointer) - inc bumpPointer, size - else: - raiseOutOfMem() - - proc osDeallocPages(p: pointer, size: int) {.inline.} = - if bumpPointer-size == cast[int](p): - dec bumpPointer, size -else: - {.error: "Port memory manager to your platform".} - -# --------------------- end of non-portable code ----------------------------- +include osalloc # We manage *chunks* of memory. Each chunk is a multiple of the page size. # Each chunk starts at an address that is divisible by the page size. Chunks |