summary refs log tree commit diff stats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/tlsfnim.nim698
1 files changed, 698 insertions, 0 deletions
diff --git a/lib/tlsfnim.nim b/lib/tlsfnim.nim
new file mode 100644
index 000000000..249607e2d
--- /dev/null
+++ b/lib/tlsfnim.nim
@@ -0,0 +1,698 @@
+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2008 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+
+# Memory manager. Based on:
+# Two Levels Segregate Fit memory allocator (TLSF)
+# Version 2.4.2
+#
+# Written by Miguel Masmano Tello <mimastel@doctor.upv.es>
+#
+# Thanks to Ismael Ripoll for his suggestions and reviews
+#
+# Copyright (C) 2008, 2007, 2006, 2005, 2004
+# 
+# This code is released using a dual license strategy: GPL/LGPL
+# You can choose the licence that better fits your requirements.
+# 
+# Released under the terms of the GNU General Public License Version 2.0
+# Released under the terms of the GNU Lesser General Public License Version 2.1
+
+
+# Some IMPORTANT TLSF parameters
+const
+  blockAlign = sizeof(pointer) * 2
+  maxFli = 30
+  maxLog2Sli = 5
+  maxSli = 1 shl maxLog2Sli
+  
+  fliOffset = 6 # tlsf structure just will manage blocks bigger than 128 bytes
+  smallBlock = 128
+  realFli = MaxFli - fliOffset
+  
+type
+  TFreePtr {.final.} = object
+    prev, next: PBhdr
+  Pbhdr = ptr Tbhdr
+  Tbhdr {.final.} = object
+    prevHdr: Pbhdr # this is just valid if the first bit of size is set
+    size: int # the size is stored in bytes 
+              # bit 0 indicates whether the block is used and
+              # bit 1 allows to know whether the previous block is free
+    freePtr: TFreePtr # at this offset bhdr.buffer starts (was a union in the
+                      # C version)
+  TAreaInfo  {.final.} = object  # This structure is embedded at the beginning
+                                 # of each area, giving us enough information 
+                                 # to cope with a set of areas
+    theEnd: Pbhdr
+    next: PAreaInfo
+  PAreaInfo = ptr TAreaInfo
+
+  TLSF {.final.} = object
+    tlsf_signature: int32 # the TLSF's structure signature
+    usedSize, maxSize: int
+    areaHead: PAreaInfo # A linked list holding all the existing areas
+
+    flBitmap: int32  # the first-level bitmap
+                     # This array should have a size of REAL_FLI bits
+    slBitmap: array[0..realFli, int32] # the second-level bitmap
+    matrix: array [0..realFli, array[0..maxSli, PBhdr]]
+  
+const
+  minBlockSize = sizeof(TFreePtr)
+  bhdrOverhead = sizeof(Tbhdr) - minBlockSize
+  tlsfSignature = 0x2A59FA59
+  ptrMask = sizeof(pointer) - 1
+  blockSize = 0xFFFFFFFF - ptrMask
+  memAlign = blockAlign - 1
+  blockState = 0x1
+  prevState = 0x2
+
+  freeBlock = 0x1 # bit 0 of the block size
+  usedBlock = 0x0
+
+  prevFree = 0x2 # bit 1 of the block size
+  prevUsed = 0x0
+  
+  defaultAreaSize = 64*1024 # 1024*10
+  pageSize = if defined(cpu32): 4096 else: 4096*2
+  
+
+proc getNextBlock(adr: pointer, r: int): PBhdr {.inline.} = 
+  return cast[PBhdr](cast[TAddress](adr) +% r)
+
+proc roundupSize(r: int): int = return (r +% memAlign) and not memAlign
+proc rounddownSize(r: int): int = return r and not memAlign
+proc roundup(x, v: int): int = return (((not x)+%1) and (v-%1)) +% x
+
+proc addSize(s: PTLSF, b: Pbhdr) =
+  inc(s.usedSize, (b.size and blockSize) + bhdrOverhead)
+  s.maxSize = max(s.maxSize, s.usedSize)
+
+proc removeSize(s: PTLSF, b: Pbhdr) =
+  dec(s.usedSize, (b.size and blockSize) + bhdrOverhead)
+
+# ------------ platform specific code -----------------------------------------
+
+when defined(posix): 
+  const # XXX: make these variables for portability?
+    PROT_READ  = 1             # page can be read 
+    PROT_WRITE = 2             # page can be written 
+    PROT_EXEC  = 4             # page can be executed 
+    PROT_NONE  = 0             # page can not be accessed 
+
+    MAP_SHARED    = 1          # Share changes 
+    MAP_PRIVATE   = 2          # Changes are private 
+    MAP_TYPE      = 0xf        # Mask for type of mapping 
+    MAP_FIXED     = 0x10       # Interpret addr exactly 
+    MAP_ANONYMOUS = 0x20       # don't use a file 
+
+    MAP_GROWSDOWN  = 0x100     # stack-like segment 
+    MAP_DENYWRITE  = 0x800     # ETXTBSY 
+    MAP_EXECUTABLE = 0x1000    # mark it as an executable 
+    MAP_LOCKED     = 0x2000    # pages are locked 
+    MAP_NORESERVE  = 0x4000    # don't check for reservations 
+
+  proc mmap(adr: pointer, len: int, prot, flags, fildes: cint,
+            off: int): pointer {.header: "<sys/mman.h>".}
+
+  proc getNewArea(size: var int): pointer {.inline.} = 
+    size = roundup(size, PageSize)
+    result = mmap(0, size, PROT_READ or PROT_WRITE, 
+                           MAP_PRIVATE or MAP_ANONYMOUS, -1, 0)
+    if result == nil or result == cast[pointer](-1):
+      raiseOutOfMem()
+  
+elif defined(windows): 
+  const
+    MEM_RESERVE = 0x2000 
+    MEM_COMMIT = 0x1000
+    MEM_TOP_DOWN = 0x100000
+    PAGE_READWRITE = 0x04
+
+  proc VirtualAlloc(lpAddress: pointer, dwSize: int, flAllocationType,
+                    flProtect: int32): pointer {.
+                    header: "<windows.h>", stdcall.}
+  
+  proc getNewArea(size: var int): pointer {.inline.} = 
+    size = roundup(size, PageSize)
+    result = VirtualAlloc(nil, size, MEM_RESERVE or MEM_COMMIT or MEM_TOP_DOWN,
+                          PAGE_READWRITE)
+    if result == nil: raiseOutOfMem()
+
+else: 
+  {.warning: "Generic code for allocating pages is used".}
+  # generic implementation relying on malloc:
+  proc malloc(size: int): pointer {.nodecl, importc.}
+  
+  proc getNewArea(size: var int): pointer {.inline.} = 
+    size = roundup(size, PageSize)
+    result = malloc(size)
+    if result == nil: raiseOutOfMem()
+
+# ---------------------------------------------------------------------------
+# small fixed size allocator:
+
+# Design: We manage pages. A page is of constant size, but not necessarily
+# the OS's page size. Pages are managed in a hash table taking advantage of
+# the fact that the OS is likely to give us pages with contingous numbers. 
+# A page contains either small fixed size objects of the same size or 
+# variable length objects. An object's size is always aligned at 16 byte
+# boundary. Huge objects are dealt with the TLSF algorithm. 
+# The design supports iterating over any object in a fast way. 
+
+# A bitset contains any page that starts an allocated page. The page may be
+# empty however. This bitset can be used to quickly determine if a given
+# page belongs to the GC heap. The design of the memory allocator makes it 
+# simple to return unused pages back to the OS.
+
+
+# Small bocks 
+# -----------
+#
+# If we use a list in the free object's space. Allocation and deallocation are
+# O(1). Since any object is of the same size, iteration is quite efficient too.
+# However, pointer detection is easy too: Just check if the type-field is nil.
+# Deallocation sets it to nil.
+# Algorithm:
+
+# i = 0
+# f = b.f # first free address
+# while i < max: 
+#  if a[i] == f: # not a valid block
+#    f = f.next  # next free address
+#  else:
+#    a[i] is a valid object of size s
+#  inc(i)
+
+# The zero count table is an array. Since we know that the RC is zero, we can
+# use the bits for an index into this array. Thus multiple ZCT tables are not
+# difficult to support and insertion and removal is O(1). We use negative
+# indexes for this. This makes it even fast enough (and necessary!) to do a ZCT
+# removal if the RC is incremented. 
+# 
+
+# Huge blocks
+# -----------
+#
+# Huge blocks are always rounded up to a multiple of the page size. These are
+# called *strides*. We also need to keep an index structure 
+# of (stridesize, pagelist). 
+# 
+
+const
+  MemAlign = 8
+  PageShift = if sizeof(int) == 4: 12 else: 13
+  PageSize = 1 shl PageShift
+type
+  TFreeList {.final.} = object
+    next, prev: ptr TFreeList
+
+  TPageDesc {.final.} = object  # the start of a stride always starts with this!
+    size: int                   # lowest bit is set, if it is a huge block
+    free: ptr TFreeList         # only used if it manages multiple cells
+    snext, sprev: ptr TPageDesc # next and prev pagedescs with the same size
+
+  TCellArray {.final.} = object
+    i: int # length
+    d: ptr array [0..1000_000, TCell]
+
+  TPageManager = table[page, ptr TPageDesc]
+
+  TGcHeap {.final.} = object
+    # structure that manages the garbage collected heap
+    zct: TCellArray
+    stackCells: TCellArray
+    smallBlocks: array [PageSize div MemAlign, ptr TPageDesc]
+    freeLists: array [PageSize div MemAlign, ptr TFreeList]
+    pages: TPageManager
+    usedPages: TPageList
+    freePages: TPageList
+
+# small blocks: 
+proc allocSmall(var h: TGcHeap, size: int): pointer = 
+  var s = align(size)
+  var f = h.freeLists[s]
+  if f != nil: 
+    f.prev = f.next # remove from list
+    f.next.prev = f.prev
+    return f
+  var p = h.smallBlocks[s]
+  if p == nil or p.free == nil:
+    p = newSmallBlock(s, p)
+    h.smallBlocks[s] = p
+  
+
+
+proc decRef(cell: PCell) {.inline.} =
+  assert(cell in ct.AT)
+  assert(cell.refcount > 0) # this should be the case!
+  assert(seqCheck(cell))
+  dec(cell.refcount)
+  if cell.refcount == 0:
+    # add to zero count table:
+    zct.d[zct.i] = cell
+    cell.recfcount = -zct.i
+    inc(zct.i)
+
+proc incRef(cell: PCell) {.inline.} =
+  assert(seqCheck(cell))
+  if cell.refcount < 0: 
+    # remove from zero count table:
+    zct.d[-cell.refcount] = zct.d[zct.i-1]
+    dec(zct.i) 
+    cell.refcount = 1
+  else:
+    inc(cell.refcount)
+
+proc asgnRef(dest: ppointer, src: pointer) =
+  # the code generator calls this proc!
+  assert(not isOnStack(dest))
+  # BUGFIX: first incRef then decRef!
+  if src != nil: incRef(usrToCell(src))
+  if dest^ != nil: decRef(usrToCell(dest^))
+  dest^ = src
+
+
+# ----------------------------------------------------------------------------
+#     helpers
+
+const
+  table: array[0..255, int8] = [
+      -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4,
+      4, 4, 4, 4, 4, 4, 4, 4, 4,
+      5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+      5, 5, 5, 5, 5, 5, 5, 5,
+      6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+      6, 6, 6, 6, 6, 6, 6, 6,
+      6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+      6, 6, 6, 6, 6, 6, 6, 6,
+      7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+      7, 7, 7, 7, 7, 7, 7, 7,
+      7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+      7, 7, 7, 7, 7, 7, 7, 7,
+      7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+      7, 7, 7, 7, 7, 7, 7, 7,
+      7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+      7, 7, 7, 7, 7, 7, 7, 7
+    ]
+
+proc ls_bit(i: int32): int {.inline.} = 
+  var 
+    a: int = 0
+    x: int = i and -i
+  if x <=% 0xffff:
+    if x <=% ff: a = 0
+    else: a = 8
+  elif x <=% 0xffffff: a = 16
+  else: a = 24
+  return table[x shr a] + a
+
+proc ms_bit(i: int): int {.inline.} = 
+  var
+    a = if i <=% 0xffff: (if i <=% 0xff: 0 else: 8) elif 
+           i <=% 0xffffff: 16 else: 24
+  return table[i shr a] + a
+
+proc set_bit[IX](nr: int, adr: var array[IX, int32]) {.inline.} =
+  adr[nr shr 5] = adr[nr shr 5] or (1 shl (nr and 0x1f))
+
+proc clear_bit[IX](nr: int, adr: var array[IX, int32]) {.inline.} =
+  adr[nr shr 5] = adr[nr shr 5] and not (1 shl (nr and 0x1f))
+
+proc mappingSearch(r, fl, sl: var int) {.inline.} = 
+  if r < smallBlock: 
+    fl = 0
+    sl = r div (smallBlock div maxSli)
+  else:
+    var t = (1 shl (ms_bit(r) - maxLog2Sli)) - 1
+    r = r + t
+    fl = ms_bit(r)
+    sl = (r shl (fl - maxLog2Sli)) - maxSli
+    fl = fl - fliOffset
+    r = r and not t
+
+proc mappingInsert(r: int, fl, sl: var int) {.inline.} = 
+  if r < smallBlock:
+    fl = 0
+    sl = r div (smallBlock div maxSli)
+  else:
+    fl = ms_bit(r)
+    sl = (r shr (fl - maxLog2Sli)) - maxSli
+    fl = fl - fliOffset
+
+proc findSuitableBlock(t: var TLSF, fl, sl: var int): Pbhdr =
+  var tmp = t.slBitmap[fl] and ((not 0) shl sl)
+  if tmp != 0:
+    sl = ls_bit(tmp)
+    result = t.matrix[fl][sl]
+  else:
+    fl = ls_bit(t.flBitmap and (not 0 shl (fl + 1)))
+    if fl > 0: # likely
+      sl = ls_bit(t.slBitmap[fl])
+      result = t.matrix[fl][sl]
+
+proc extractBlockHdr(b: Pbhdr, t: var TLSF, fl, sl: int) {.inline.} = 
+  t.matrix[fl][sl] = b.freePtr.next
+  if t.matrix[fl][sl] != nil:
+    t.matrix[fl][sl].freePtr.prev = nil
+  else:
+    clear_bit(sl, t.slBitmap[fl])
+    if t.slBitmap[fl] == 0:
+      clear_bit(fl, t.flBitmap)
+  b.freePtr.prev = nil
+  b.freePtr.next = nil
+
+proc extractBlock(b: Pbhdr, t: var TLSF, fl, sl: int) {.inline.} =
+  if b.freePtr.next != nil:
+    b.freePtr.next.freePtr.prev = b.freePtr.prev
+  if b.freePtr.prev != nil:
+    b.freePtr.prev.freePtr.next = b.freePtr.next
+  if t.matrix[fl][sl] == b:
+    t.matrix[fl][sl] = b.freePtr.next
+    if t.matrix[fl][sl] == nil:
+      clear_bit(sl, t.slBitmap[fl])
+      if t.slBitmap[fl] == 0:
+        clear_bit(fl, t.flBitmap)
+  b.freePtr.prev = nil
+  b.freePtr.next = nil
+
+proc insertBlock(b: Pbhdr, t: var TLSF, fl, sl: int) {.inline.} = 
+  b.freePtr.prev = nil
+  b.freePtr.next = t.matrix[fl][sl] 
+  if t.matrix[fl][sl] != nil:
+    t.matrix[fl][sl].freePtr.prev = b		
+  t.matrix[fl][sl] = b
+  set_bit(sl, t.slBitmap[fl])
+  set_bit(fl, t.flBitmap)
+
+proc getBuffer(b: Pbhdr): pointer {.inline.} = 
+  result = cast[pointer](addr(b.freePtr))
+
+proc processArea(area: pointer, size: int): Pbhdr =
+  var 
+    b, lb, ib: Pbhdr
+    ai: PAreaInfo
+  ib = cast[Pbhdr](area)
+  if sizeof(TAreaInfo) < minBlockSize:
+    ib.size = minBlockSize or usedBlock or prevUsed
+  else
+    ib.size = roundupSize(sizeof(TAreaInfo)) or usedBlock or prevUsed
+  b = getNextBlock(getBuffer(ib), ib.size and blockSize)
+  b.size = rounddownSize(size - 3 * bhdrOverhead - (ib.size and blockSize)) or
+           usedBlock or prevUsed
+  b.freePtr.prev = nil
+  b.freePtr.next = nil
+  lb = getNextBlock(getBuffer(b), b.size and blockSize)
+  lb.prevHdr = b
+  lb.size = 0 or usedBlock or prevFree
+  ai = cast[PAreaInfo](getBuffer(ib))
+  ai.next = nil
+  ai.theEnd = lb
+  return ib
+
+# ----------------------------------------------------------------------------
+#                  Begin of the allocator code
+
+proc initMemoryPool(memPoolSize: int, memPool: pointer): int = 
+  var
+    t: PLSF
+    b, ib: Pbhdr
+
+  if memPool == nil or memPoolSize < sizeof(TLSF) + bhdrOverhead * 8:
+    writeToStdErr("initMemoryPool(): memory_pool invalid\n")
+    return -1
+
+  if (cast[TAddress](memPool) and ptrMask) != 0:
+    writeToStdErr("initMemoryPool(): memPool must be aligned to a word\n")
+    return -1
+  t = cast[PLSF](memPool)
+  # Check if already initialised
+  if t.signature == tlsfSignature:
+    b = getNextBlock(memPool, roundupSize(sizeof(TLSF)))
+    return b.size and blockSize
+  zeroMem(memPool, sizeof(TLSF))
+
+  t.signature = tlsfSignature
+  ib = processArea(getNextBlock(memPool, roundupSize(sizeof(TLSF))), 
+                   rounddownSize(memPoolSize - sizeof(TLSF)))
+  b = getNextBlock(getBuffer(ib), ib.size and blockSize)
+  freeEx(getBuffer(b), t)
+  t.areaHead = cast[PAreaInfo](getBuffer(ib))
+
+  t.used_size = memPoolSize - (b.size and blockSize)
+  t.max_size = t.used_size
+  return b.size and blockSize
+
+
+proc addNewArea(area: pointer, areaSize: int, t: var TLSF): int = 
+  var
+    p, ptrPrev, ai: PAreaInfo
+    ib0, b0, lb0, ib1, b1, lb1, nextB: Pbhdr
+
+  zeroMem(area, areaSize)
+  p = t.areaHead
+  ptrPrev = 0
+
+  ib0 = processArea(area, areaSize)
+  b0 = getNextBlock(getBuffer(ib0), ib0.size and blockSize)
+  lb0 = getNextBlock(getBuffer(b0), b0.size and blockSize)
+
+  # Before inserting the new area, we have to merge this area with the
+  # already existing ones
+  while p != nil:
+    ib1 = cast[Pbhdr](cast[TAddress](p) -% bhdrOverhead) 
+    b1 = getNextBlock(getBuffer(ib1), ib1.size and blockSize)
+    lb1 = p.theEnd
+
+    # Merging the new area with the next physically contigous one
+    if cast[TAddress](ib1) == cast[TAddress](lb0) +% bhdrOverhead:
+      if t.areaHead == p:
+        t.areaHead = p.next
+        p = p.next
+      else:
+        ptrPrev.next = p.next
+        p = p.next
+      b0.size = rounddownSize((b0.size and blockSize) +
+                         (ib1.size and blockSize) + 2 * bhdrOverhead) or
+                         usedBlock or prevUsed
+      b1.prevHdr = b0
+      lb0 = lb1
+      continue
+
+    # Merging the new area with the previous physically contigous one
+    if getBuffer(lb1) == pointer(ib0):
+      if t.areaHead == p:
+        t.areaHead = p.next
+        p = p.next
+      else:
+        ptrPrev.next = p.next
+        p = p.next
+      lb1->size = rounddownSize((b0.size and blockSize) +
+                   (ib0.size and blockSize) + 2 * bhdrOverhead) or
+                   usedBlock or (lb1.size and prevState)
+      nextB = getNextBlock(getBuffer(lb1), lb1.size and blockSize)
+      nextB.prevHdr = lb1
+      b0 = lb1
+      ib0 = ib1
+      continue
+    ptrPrev = p
+    p = p.next
+
+  # Inserting the area in the list of linked areas 
+  ai = cast[PAreaInfo](getBuffer(ib0))
+  ai.next = t.areaHead
+  ai.theEnd = lb0
+  t.areaHead = ai
+  freeEx(getBuffer(b0), memPool)
+  return (b0.size and blockSize)
+
+proc mallocEx(asize: int, t: var TLSF): pointer = 
+  var
+    b, b2, nextB: Pbhdr
+    fl, sl, tmpSize, size: int
+
+  size = if asize < minBlockSize: minBlockSize else: roundupSize(asize)
+
+  # Rounding up the requested size and calculating fl and sl
+  mappingSearch(size, fl, sl)
+
+  # Searching a free block, recall that this function changes the values
+  # of fl and sl, so they are not longer valid when the function fails
+  b = findSuitableBlock(tlsf, fl, sl)
+  if b == nil: 
+    # Growing the pool size when needed 
+    # size plus enough room for the required headers:
+    var areaSize = max(size + bhdrOverhead * 8, defaultAreaSize)
+    var area = getNewArea(areaSize)
+    addNewArea(area, areaSize, t)
+    # Rounding up the requested size and calculating fl and sl
+    mappingSearch(size, fl, sl)
+    # Searching a free block
+    b = findSuitableBlock(t, fl, sl)
+    if b == nil: 
+      raiseOutOfMem()
+
+  extractBlockHdr(b, t, fl, sl)
+
+  #-- found:
+  nextB = getNextBlock(getBuffer(b), b.size and blockSize)
+  # Should the block be split?
+  tmpSize = (b.size and blockSize) - size
+  if tmpSize >= sizeof(Tbhdr):
+    dec(tmpSize, bhdrOverhead)
+    b2 = getNextBlock(getBuffer(b), size)
+    b2.size = tmpSize or freeBlock or prevUsed
+    nextB.prevHdr = b2
+    mappingInsert(tmpSize, fl, sl)
+    insertBlock(b2, t, fl, sl)
+
+    b.size = size or (b.size and prevState)
+  else:
+    nextB.size = nextB.size and not prevFree
+    b.size = b.size and not freeBlock # Now it's used
+
+  addSize(t, b)
+  return getBuffer(b)
+
+
+proc freeEx(p: pointer, t: var TLSF) =
+  var
+    fl = 0
+    sl = 0
+    b, tmpB: Pbhdr
+
+  assert(p != nil)
+  b = cast[Pbhdr](cast[TAddress](p) -% bhdrOverhead)
+  b.size = b.size or freeBlock
+
+  removeSize(t, b)
+  b.freePtr.prev = nil
+  b.freePtr.next = nil
+  tmpB = getNextBlock(getBuffer(b), b.size and blockSize)
+  if (tmpB.size and freeBlock) != 0:
+    mappingInsert(tmpB.size and blockSize, fl, sl)
+    extractBlock(tmpB, t, fl, sl)
+    inc(b.size, (tmpB.size and blockSize) + bhdrOverhead)
+  if (b.size and prevFree) != 0:
+    tmpB = b.prevHdr
+    mappingInsert(tmpB.size and blockSize, fl, sl)
+    extractBlock(tmpB, t, fl, sl)
+    inc(tmpB.size, (b.size and blockSize) + bhdrOverhead)
+    b = tmpB
+  mappingInsert(b.size and blockSize, fl, sl)
+  insertBlock(b, t, fl, sl)
+
+  tmpB = getNextBlock(getBuffer(b), b.size and blockSize)
+  tmpB.size = tmpB.size or prevFree
+  tmpB.prevHdr = b
+
+proc reallocEx(p: pointer, newSize: int, t: var TLSF): pointer = 
+  var
+    cpsize, fl, sl, tmpSize: int
+    b, tmpB, nextB: Pbhdr
+
+  assert(p != nil)
+  assert(newSize > 0)
+
+  b = cast[Pbhdr](cast[TAddress](p) -% bhdrOverhead)
+  nextB = getNextBlock(getBuffer(b), b.size and blockSize)
+  newSize = if newSize < minBlockSize: minBlockSize else: roundupSize(newSize)
+  tmpSize = b.size and blockSize
+  if newSize <= tmpSize:
+    removeSize(t, b)
+    if (nextB.size and freeBlock) != 0: 
+      mappingInsert(nextB.size and blockSize, fl, sl)
+      extractBlock(nextB, t, fl, sl)
+      inc(tmpSize, (nextB.size and blockSize) + bhdrOverhead)
+      nextB = getNextBlock(getBuffer(nextB), nextB.size and blockSize)
+      # We always reenter this free block because tmpSize will
+      # be greater then sizeof(Tbhdr)
+    dec(tmpSize, newSize)
+    if tmpSize >= sizeof(Tbhdr):
+      dec(tmpSize, bhdrOverhead)
+      tmpB = getNextBlock(getBuffer(b), newSize)
+      tmpB.size = tmpSize or freeBlock or prevUsed
+      nextB.prevHdr = tmpB
+      nextB.size = nextB.size or prevFree
+      mappingInsert(tmpSize, fl, sl)
+      insertBlock(tmpB, t, fl, sl)
+      b.size = newSize or (b.size and prevState)
+    addSize(t, b)
+    return getBuffer(b)
+  
+  if (nextB.size and freeBlock) != 0:
+    if newSize <= tmpSize + (nextB.size and blockSize):
+      removeSize(t, b)
+      mappingInsert(nextB.size and blockSize, fl, sl)
+      extractBlock(nextB, t, fl, sl)
+      inc(b.size, (nextB.size and blockSize) + bhdrOverhead)
+      nextB = getNextBlock(getBuffer(b), b.size and blockSize)
+      nextB.prevHdr = b
+      nextB.size = nextB.size and not prevFree
+      tmpSize = (b.size and blockSize) - newSize
+      if tmpSize >= sizeof(Tbhdr):
+        dec(tmpSize, bhdrOverhead)
+        tmpB = getNextBlock(getBuffer(b), newSize)
+        tmpB.size = tmpSize or freeBlock or prevUsed
+        nextB.prevHdr = tmpB
+        nextB.size = nextB.size or prevFree
+        mappingInsert(tmpSize, fl, sl)
+        insertBlock(tmpB, t, fl, sl)
+        b.size = newSize or (b.size and prevState)
+      addSize(t, b)
+      return getBuffer(b)
+
+  var ptrAux = mallocEx(newSize, t)
+  cpsize = if (b.size and blockSize) > newSize: newSize else:
+                                                (b.size and blockSize)
+  copyMem(ptrAux, p, cpsize)
+  freeEx(p, memPool)
+  return ptrAux
+
+
+proc ansiCrealloc(p: pointer, newSize: int, t: var TLSF): pointer = 
+  if p == nil: 
+    if newSize > 0: 
+      result = mallocEx(newSize, t)
+    else:
+      result = nil
+  elif newSize <= 0:
+    freeEx(p, t)
+    result = nil
+  else:
+    result = reallocEx(p, newSize, t)
+
+proc InitTLSF(t: var TLSF) = 
+  var areaSize = sizeof(TLSF) + BHDR_OVERHEAD * 8 # Just a safety constant
+  areaSize = max(areaSize, DEFAULT_areaSize)
+  var area = getNewArea(areaSize)
+  
+  
+  initMemoryPool(areaSize, area)
+
+  var
+    t: PLSF
+    b, ib: Pbhdr
+
+  t = cast[PLSF](memPool)
+  
+  zeroMem(area, areaSize)
+
+  t.signature = tlsfSignature
+  var ib = processArea(getNextBlock(memPool, roundupSize(sizeof(TLSF))), 
+                   rounddownSize(memPoolSize - sizeof(TLSF)))
+  var b = getNextBlock(getBuffer(ib), ib.size and blockSize)
+  freeEx(getBuffer(b), t)
+  t.areaHead = cast[PAreaInfo](getBuffer(ib))
+
+  t.used_size = memPoolSize - (b.size and blockSize)
+  t.max_size = t.used_size
+
+  # XXX