summary refs log tree commit diff stats
path: root/lib/system/alloc.nim
diff options
context:
space:
mode:
Diffstat (limited to 'lib/system/alloc.nim')
-rwxr-xr-xlib/system/alloc.nim71
1 files changed, 29 insertions, 42 deletions
diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim
index 2280415e1..c12dc253a 100755
--- a/lib/system/alloc.nim
+++ b/lib/system/alloc.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nimrod's Runtime Library
-#        (c) Copyright 2009 Andreas Rumpf
+#        (c) Copyright 2011 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -80,7 +80,7 @@ else:
 # system immediately.
 
 const
-  ChunkOsReturn = 256 * PageSize
+  ChunkOsReturn = 256 * PageSize # 1 MB
   InitialMemoryRequest = ChunkOsReturn div 2 # < ChunkOsReturn!
   SmallChunkSize = PageSize
 
@@ -101,6 +101,7 @@ type
     next: ptr TFreeCell  # next free cell in chunk (overlaid with refcount)
     zeroField: int       # 0 means cell is not used (overlaid with typ field)
                          # 1 means cell is manually managed pointer
+                         # otherwise a PNimType is stored in there
 
   PChunk = ptr TBaseChunk
   PBigChunk = ptr TBigChunk
@@ -151,6 +152,7 @@ type
   TAllocator {.final, pure.} = object
     llmem: PLLChunk
     currMem, maxMem, freeMem: int # memory sizes (allocated from OS)
+    lastSize: int # needed for the case that OS gives us pages linearly 
     freeSmallChunks: array[0..SmallChunkSize div MemAlign-1, PSmallChunk]
     freeChunksList: PBigChunk # XXX make this a datastructure with O(1) access
     chunkStarts: TIntSet
@@ -167,10 +169,7 @@ proc getMaxMem(a: var TAllocator): int =
   # maxPagesCount may not be up to date. Thus we use the
   # maximum of these both values here:
   return max(a.currMem, a.maxMem)
-   
-var
-  allocator: TAllocator
-    
+  
 proc llAlloc(a: var TAllocator, size: int): pointer =
   # *low-level* alloc for the memory managers data structures. Deallocation
   # is never done.
@@ -192,10 +191,10 @@ proc IntSetGet(t: TIntSet, key: int): PTrunk =
     it = it.next
   result = nil
 
-proc IntSetPut(t: var TIntSet, key: int): PTrunk = 
+proc IntSetPut(a: var TAllocator, t: var TIntSet, key: int): PTrunk = 
   result = IntSetGet(t, key)
   if result == nil:
-    result = cast[PTrunk](llAlloc(allocator, sizeof(result[])))
+    result = cast[PTrunk](llAlloc(a, sizeof(result[])))
     result.next = t.data[key and high(t.data)]
     t.data[key and high(t.data)] = result
     result.key = key
@@ -208,8 +207,8 @@ proc Contains(s: TIntSet, key: int): bool =
   else: 
     result = false
   
-proc Incl(s: var TIntSet, key: int) = 
-  var t = IntSetPut(s, key shr TrunkShift)
+proc Incl(a: var TAllocator, s: var TIntSet, key: int) = 
+  var t = IntSetPut(a, s, key shr TrunkShift)
   var u = key and TrunkMask
   t.bits[u shr IntShift] = t.bits[u shr IntShift] or (1 shl (u and IntMask))
 
@@ -219,18 +218,6 @@ proc Excl(s: var TIntSet, key: int) =
     var u = key and TrunkMask
     t.bits[u shr IntShift] = t.bits[u shr IntShift] and not
         (1 shl (u and IntMask))
-
-proc ContainsOrIncl(s: var TIntSet, key: int): bool = 
-  var t = IntSetGet(s, key shr TrunkShift)
-  if t != nil: 
-    var u = key and TrunkMask
-    result = (t.bits[u shr IntShift] and (1 shl (u and IntMask))) != 0
-    if not result: 
-      t.bits[u shr IntShift] = t.bits[u shr IntShift] or
-          (1 shl (u and IntMask))
-  else: 
-    Incl(s, key)
-    result = false
    
 # ------------- chunk management ----------------------------------------------
 proc pageIndex(c: PChunk): int {.inline.} = 
@@ -241,9 +228,7 @@ proc pageIndex(p: pointer): int {.inline.} =
 
 proc pageAddr(p: pointer): PChunk {.inline.} = 
   result = cast[PChunk](cast[TAddress](p) and not PageMask)
-  assert(Contains(allocator.chunkStarts, pageIndex(result)))
-
-var lastSize = PageSize
+  #assert(Contains(allocator.chunkStarts, pageIndex(result)))
 
 proc requestOsChunks(a: var TAllocator, size: int): PBigChunk = 
   incCurrMem(a, size)
@@ -263,6 +248,7 @@ proc requestOsChunks(a: var TAllocator, size: int): PBigChunk =
     #echo("Next already allocated!")
     next.prevSize = size
   # set result.prevSize:
+  var lastSize = if a.lastSize != 0: a.lastSize else: PageSize
   var prv = cast[TAddress](result) -% lastSize
   assert((nxt and PageMask) == 0)
   var prev = cast[PChunk](prv)
@@ -271,7 +257,7 @@ proc requestOsChunks(a: var TAllocator, size: int): PBigChunk =
     result.prevSize = lastSize
   else:
     result.prevSize = 0 # unknown
-  lastSize = size # for next request
+  a.lastSize = size # for next request
 
 proc freeOsChunks(a: var TAllocator, p: pointer, size: int) = 
   # update next.prevSize:
@@ -287,8 +273,8 @@ proc freeOsChunks(a: var TAllocator, p: pointer, size: int) =
   dec(a.freeMem, size)
   #c_fprintf(c_stdout, "[Alloc] back to OS: %ld\n", size)
 
-proc isAccessible(p: pointer): bool {.inline.} = 
-  result = Contains(allocator.chunkStarts, pageIndex(p))
+proc isAccessible(a: TAllocator, p: pointer): bool {.inline.} = 
+  result = Contains(a.chunkStarts, pageIndex(p))
 
 proc contains[T](list, x: T): bool = 
   var it = list
@@ -337,7 +323,7 @@ proc updatePrevSize(a: var TAllocator, c: PBigChunk,
                     prevSize: int) {.inline.} = 
   var ri = cast[PChunk](cast[TAddress](c) +% c.size)
   assert((cast[TAddress](ri) and PageMask) == 0)
-  if isAccessible(ri):
+  if isAccessible(a, ri):
     ri.prevSize = prevSize
   
 proc freeBigChunk(a: var TAllocator, c: PBigChunk) = 
@@ -347,7 +333,7 @@ proc freeBigChunk(a: var TAllocator, c: PBigChunk) =
   when coalescRight:
     var ri = cast[PChunk](cast[TAddress](c) +% c.size)
     assert((cast[TAddress](ri) and PageMask) == 0)
-    if isAccessible(ri) and chunkUnused(ri):
+    if isAccessible(a, ri) and chunkUnused(ri):
       assert(not isSmallChunk(ri))
       if not isSmallChunk(ri):
         ListRemove(a.freeChunksList, cast[PBigChunk](ri))
@@ -357,7 +343,7 @@ proc freeBigChunk(a: var TAllocator, c: PBigChunk) =
     if c.prevSize != 0: 
       var le = cast[PChunk](cast[TAddress](c) -% c.prevSize)
       assert((cast[TAddress](le) and PageMask) == 0)
-      if isAccessible(le) and chunkUnused(le):
+      if isAccessible(a, le) and chunkUnused(le):
         assert(not isSmallChunk(le))
         if not isSmallChunk(le):
           ListRemove(a.freeChunksList, cast[PBigChunk](le))
@@ -366,7 +352,7 @@ proc freeBigChunk(a: var TAllocator, c: PBigChunk) =
           c = cast[PBigChunk](le)
 
   if c.size < ChunkOsReturn: 
-    incl(a.chunkStarts, pageIndex(c))
+    incl(a, a.chunkStarts, pageIndex(c))
     updatePrevSize(a, c, c.size)
     ListAdd(a.freeChunksList, c)
     c.used = false
@@ -383,7 +369,7 @@ proc splitChunk(a: var TAllocator, c: PBigChunk, size: int) =
   rest.prevSize = size
   updatePrevSize(a, c, rest.size)
   c.size = size
-  incl(a.chunkStarts, pageIndex(rest))
+  incl(a, a.chunkStarts, pageIndex(rest))
   ListAdd(a.freeChunksList, rest)
 
 proc getBigChunk(a: var TAllocator, size: int): PBigChunk = 
@@ -410,7 +396,7 @@ proc getBigChunk(a: var TAllocator, size: int): PBigChunk =
       result = requestOsChunks(a, size)
   result.prevSize = 0 # XXX why is this needed?
   result.used = true
-  incl(a.chunkStarts, pageIndex(result))
+  incl(a, a.chunkStarts, pageIndex(result))
   dec(a.freeMem, size)
 
 proc getSmallChunk(a: var TAllocator): PSmallChunk = 
@@ -472,7 +458,7 @@ proc rawAlloc(a: var TAllocator, requestedSize: int): pointer =
     assert c.size == size
     result = addr(c.data)
     assert((cast[TAddress](result) and (MemAlign-1)) == 0)
-  assert(isAccessible(result))
+  assert(isAccessible(a, result))
 
 proc rawDealloc(a: var TAllocator, p: pointer) = 
   var c = pageAddr(p)
@@ -509,7 +495,7 @@ proc rawDealloc(a: var TAllocator, p: pointer) =
     freeBigChunk(a, cast[PBigChunk](c))
 
 proc isAllocatedPtr(a: TAllocator, p: pointer): bool = 
-  if isAccessible(p):
+  if isAccessible(a, p):
     var c = pageAddr(p)
     if not chunkUnused(c):
       if isSmallChunk(c):
@@ -522,11 +508,12 @@ proc isAllocatedPtr(a: TAllocator, p: pointer): bool =
         var c = cast[PBigChunk](c)
         result = p == addr(c.data) and cast[ptr TFreeCell](p).zeroField >% 1
 
+var
+  allocator {.rtlThreadVar.}: TAllocator
+
 # ---------------------- interface to programs -------------------------------
 
 when not defined(useNimRtl):
-  var heapLock: TSysLock
-  InitSysLock(HeapLock)
 
   proc unlockedAlloc(size: int): pointer {.inline.} =
     result = rawAlloc(allocator, size+sizeof(TFreeCell))
@@ -545,18 +532,18 @@ when not defined(useNimRtl):
     assert(not isAllocatedPtr(allocator, x))
 
   proc alloc(size: int): pointer =
-    when hasThreadSupport: AquireSys(HeapLock)
+    when hasThreadSupport and hasSharedHeap: AquireSys(HeapLock)
     result = unlockedAlloc(size)
-    when hasThreadSupport: ReleaseSys(HeapLock)
+    when hasThreadSupport and hasSharedHeap: ReleaseSys(HeapLock)
 
   proc alloc0(size: int): pointer =
     result = alloc(size)
     zeroMem(result, size)
 
   proc dealloc(p: pointer) =
-    when hasThreadSupport: AquireSys(HeapLock)
+    when hasThreadSupport and hasSharedHeap: AquireSys(HeapLock)
     unlockedDealloc(p)
-    when hasThreadSupport: ReleaseSys(HeapLock)
+    when hasThreadSupport and hasSharedHeap: ReleaseSys(HeapLock)
 
   proc ptrSize(p: pointer): int =
     var x = cast[pointer](cast[TAddress](p) -% sizeof(TFreeCell))