summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--changelog.md3
-rw-r--r--doc/nimc.rst14
-rw-r--r--lib/system/alloc.nim3
-rw-r--r--lib/system/osalloc.nim31
-rw-r--r--tests/arc/tarcmisc.nim2
5 files changed, 46 insertions, 7 deletions
diff --git a/changelog.md b/changelog.md
index bc64e9579..d44f28b94 100644
--- a/changelog.md
+++ b/changelog.md
@@ -391,6 +391,9 @@
 - The `gc:orc` algorithm was refined so that custom container types can participate in the
   cycle collection process.
 
+- On embedded devices `malloc` can now be used instead of `mmap` via `-d:nimAllocPagesViaMalloc`.
+  This is only supported for `--gc:orc` or `--gc:arc`.
+
 
 ## Compiler changes
 
diff --git a/doc/nimc.rst b/doc/nimc.rst
index 2b9f33cb5..070956860 100644
--- a/doc/nimc.rst
+++ b/doc/nimc.rst
@@ -176,7 +176,7 @@ directories (in this order; later files overwrite previous settings):
    ``%APPDATA%/nim/nim.cfg`` (Windows).
    This file can be skipped with the `--skipUserCfg`:option: command line
    option.
-3) ``$parentDir/nim.cfg`` where ``$parentDir`` stands for any parent 
+3) ``$parentDir/nim.cfg`` where ``$parentDir`` stands for any parent
    directory of the project file's path.
    These files can be skipped with the `--skipParentCfg`:option:
    command-line option.
@@ -634,6 +634,18 @@ optimization in the compiler and linker.
 Check the `Cross-compilation`_ section for instructions on how to compile the
 program for your target.
 
+
+nimAllocPagesViaMalloc
+----------------------
+
+Nim's default allocator is based on TLSF, this algorithm was designed for embedded
+devices. This allocator gets blocks/pages of memory via a currently undocumented
+`osalloc` API which usually uses POSIX's `mmap` call. On many environments `mmap`
+is not available but C's `malloc` is. You can use the `nimAllocPagesViaMalloc`
+define to use `malloc` instead of `mmap`. `nimAllocPagesViaMalloc` is currently
+only supported with `--gc:arc` or `--gc:orc`. (Since version 1.6)
+
+
 Nim for realtime systems
 ========================
 
diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim
index c598b8250..479458950 100644
--- a/lib/system/alloc.nim
+++ b/lib/system/alloc.nim
@@ -749,8 +749,9 @@ proc rawAlloc(a: var MemRegion, requestedSize: int): pointer =
     inc(a.allocCounter)
   sysAssert(allocInv(a), "rawAlloc: begin")
   sysAssert(roundup(65, 8) == 72, "rawAlloc: roundup broken")
-  sysAssert(requestedSize >= sizeof(FreeCell), "rawAlloc: requested size too small")
   var size = roundup(requestedSize, MemAlign)
+  sysAssert(size >= sizeof(FreeCell), "rawAlloc: requested size too small")
+
   sysAssert(size >= requestedSize, "insufficient allocated size!")
   #c_fprintf(stdout, "alloc; size: %ld; %ld\n", requestedSize, size)
   if size <= SmallChunkSize-smallChunkOverhead():
diff --git a/lib/system/osalloc.nim b/lib/system/osalloc.nim
index 32d3b166d..2830adb48 100644
--- a/lib/system/osalloc.nim
+++ b/lib/system/osalloc.nim
@@ -28,7 +28,30 @@ const doNotUnmap = not (defined(amd64) or defined(i386)) or
                    defined(windows) or defined(nimAllocNoUnmap)
 
 
-when defined(emscripten) and not defined(StandaloneHeapSize):
+when defined(nimAllocPagesViaMalloc):
+  when not defined(gcArc) and not defined(gcOrc):
+    {.error: "-d:nimAllocPagesViaMalloc is only supported with --gc:arc or --gc:orc".}
+
+  proc osTryAllocPages(size: int): pointer {.inline.} =
+    let base = c_malloc(csize_t size + PageSize - 1 + sizeof(uint32))
+    if base == nil: raiseOutOfMem()
+    # memory layout: padding + offset (4 bytes) + user_data
+    # in order to deallocate: read offset at user_data - 4 bytes,
+    # then deallocate user_data - offset
+    let offset = PageSize - (cast[int](base) and (PageSize - 1))
+    cast[ptr uint32](base +! (offset - sizeof(uint32)))[] = uint32(offset)
+    result = base +! offset
+
+  proc osAllocPages(size: int): pointer {.inline.} =
+    result = osTryAllocPages(size)
+    if result == nil: raiseOutOfMem()
+
+  proc osDeallocPages(p: pointer, size: int) {.inline.} =
+    # read offset at p - 4 bytes, then deallocate (p - offset) pointer
+    let offset = cast[ptr uint32](p -! sizeof(uint32))[]
+    c_free(p -! offset)
+
+elif defined(emscripten) and not defined(StandaloneHeapSize):
   const
     PROT_READ  = 1             # page can be read
     PROT_WRITE = 2             # page can be written
@@ -197,11 +220,11 @@ elif defined(posix) and not defined(StandaloneHeapSize):
     PROT_WRITE = 2             # page can be written
 
   when defined(netbsd) or defined(openbsd):
-      # OpenBSD security for setjmp/longjmp coroutines
-      var MAP_STACK {.importc: "MAP_STACK", header: "<sys/mman.h>".}: cint
+    # OpenBSD security for setjmp/longjmp coroutines
+    var MAP_STACK {.importc: "MAP_STACK", header: "<sys/mman.h>".}: cint
   else:
     const MAP_STACK = 0             # avoid sideeffects
-    
+
   when defined(macosx) or defined(freebsd):
     const MAP_ANONYMOUS = 0x1000
     const MAP_PRIVATE = 0x02        # Changes are private
diff --git a/tests/arc/tarcmisc.nim b/tests/arc/tarcmisc.nim
index 5d5d8e914..7daea62c8 100644
--- a/tests/arc/tarcmisc.nim
+++ b/tests/arc/tarcmisc.nim
@@ -34,7 +34,7 @@ closed
 destroying variable: 20
 destroying variable: 10
 '''
-  cmd: "nim c --gc:arc --deepcopy:on $file"
+  cmd: "nim c --gc:arc --deepcopy:on -d:nimAllocPagesViaMalloc $file"
 """
 
 proc takeSink(x: sink string): bool = true