summary refs log tree commit diff stats
path: root/lib/system
diff options
context:
space:
mode:
Diffstat (limited to 'lib/system')
-rw-r--r--lib/system/arithm.nim2
-rw-r--r--lib/system/jssys.nim63
-rw-r--r--lib/system/mmdisp.nim198
-rw-r--r--lib/system/repr.nim18
-rw-r--r--lib/system/sysstr.nim6
-rw-r--r--lib/system/threads.nim6
6 files changed, 259 insertions, 34 deletions
diff --git a/lib/system/arithm.nim b/lib/system/arithm.nim
index 907907e24..69c558799 100644
--- a/lib/system/arithm.nim
+++ b/lib/system/arithm.nim
@@ -18,7 +18,7 @@ proc raiseDivByZero {.compilerproc, noinline.} =
   sysFatal(DivByZeroError, "division by zero")
 
 when defined(builtinOverflow):
-# Builtin compiler functions for improved performance
+  # Builtin compiler functions for improved performance
   when sizeof(clong) == 8:
     proc addInt64Overflow[T: int64|int](a, b: T, c: var T): bool {.
       importc: "__builtin_saddl_overflow", nodecl, nosideeffect.}
diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim
index f082023ee..242f42c16 100644
--- a/lib/system/jssys.nim
+++ b/lib/system/jssys.nim
@@ -37,9 +37,7 @@ type
 
 var
   framePtr {.importc, nodecl, volatile.}: PCallFrame
-  excHandler {.importc, nodecl, volatile.}: PSafePoint = nil
-    # list of exception handlers
-    # a global variable for the root of all try blocks
+  excHandler {.importc, nodecl, volatile.}: int = 0
   lastJSError {.importc, nodecl, volatile.}: PJSError = nil
 
 {.push stacktrace: off, profiler:off.}
@@ -52,9 +50,7 @@ proc nimCharToStr(x: char): string {.compilerproc.} =
   result[0] = x
 
 proc getCurrentExceptionMsg*(): string =
-  if excHandler != nil and excHandler.exc != nil:
-    return $excHandler.exc.msg
-  elif lastJSError != nil:
+  if lastJSError != nil:
     return $lastJSError.message
   else:
     return ""
@@ -99,32 +95,41 @@ proc rawWriteStackTrace(): string =
   else:
     result = "No stack traceback available\n"
 
-proc raiseException(e: ref Exception, ename: cstring) {.
+proc unhandledException(e: ref Exception) {.
     compilerproc, asmNoStackFrame.} =
-  e.name = ename
-  if excHandler != nil:
-    excHandler.exc = e
+  when NimStackTrace:
+    var buf = rawWriteStackTrace()
   else:
-    when NimStackTrace:
-      var buf = rawWriteStackTrace()
-    else:
-      var buf = ""
+    var buf = ""
     if e.msg != nil and e.msg[0] != '\0':
       add(buf, "Error: unhandled exception: ")
       add(buf, e.msg)
     else:
       add(buf, "Error: unhandled exception")
     add(buf, " [")
-    add(buf, ename)
+    add(buf, e.name)
     add(buf, "]\n")
     alert(buf)
-  asm """throw `e`;"""
+
+proc raiseException(e: ref Exception, ename: cstring) {.
+    compilerproc, asmNoStackFrame.} =
+  e.name = ename
+  when not defined(noUnhandledHandler):
+    if excHandler == 0:
+      unhandledException(e)
+  asm "throw `e`;"
 
 proc reraiseException() {.compilerproc, asmNoStackFrame.} =
-  if excHandler == nil:
+  if lastJSError == nil:
     raise newException(ReraiseError, "no exception to reraise")
   else:
-    asm """throw excHandler.exc;"""
+    when not defined(noUnhandledHandler):
+      if excHandler == 0:
+        var isNimException : bool
+        asm "`isNimException` = lastJSError.m_type;"
+        if isNimException:
+          unhandledException(cast[ref Exception](lastJSError))
+    asm "throw lastJSError;"
 
 proc raiseOverflow {.exportc: "raiseOverflow", noreturn.} =
   raise newException(OverflowError, "over- or underflow")
@@ -170,12 +175,28 @@ proc cstrToNimstr(c: cstring): string {.asmNoStackFrame, compilerproc.} =
 proc toJSStr(s: string): cstring {.asmNoStackFrame, compilerproc.} =
   asm """
     var len = `s`.length-1;
-    var result = new Array(len);
+    var asciiPart = new Array(len);
     var fcc = String.fromCharCode;
+    var nonAsciiPart = null;
+    var nonAsciiOffset = 0;
     for (var i = 0; i < len; ++i) {
-      result[i] = fcc(`s`[i]);
+      if (nonAsciiPart !== null) {
+        var offset = (i - nonAsciiOffset) * 2;
+        nonAsciiPart[offset] = "%";
+        nonAsciiPart[offset + 1] = `s`[i].toString(16);
+      }
+      else if (`s`[i] < 128)
+        asciiPart[i] = fcc(`s`[i]);
+      else {
+        asciiPart.length = i;
+        nonAsciiOffset = i;
+        nonAsciiPart = new Array((len - i) * 2);
+        --i;
+      }
     }
-    return result.join("");
+    asciiPart = asciiPart.join("");
+    return (nonAsciiPart === null) ?
+        asciiPart : asciiPart + decodeURIComponent(nonAsciiPart.join(""));
   """
 
 proc mnewString(len: int): string {.asmNoStackFrame, compilerproc.} =
diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim
index 86d834ceb..50f4cb4dc 100644
--- a/lib/system/mmdisp.nim
+++ b/lib/system/mmdisp.nim
@@ -7,7 +7,7 @@
 #    distribution, for details about the copyright.
 #
 
-# Nim high-level memory manager: It supports Boehm's GC, no GC and the
+# Nim high-level memory manager: It supports Boehm's GC, Go's GC, no GC and the
 # native Nim GC. The native Nim GC is the default.
 
 #{.push checks:on, assertions:on.}
@@ -195,6 +195,201 @@ when defined(boehmgc):
   proc deallocOsPages() {.inline.} = discard
 
   include "system/cellsets"
+
+elif defined(gogc):
+  when defined(windows):
+    const goLib = "libgo.dll"
+  elif defined(macosx):
+    const goLib = "libgo.dylib"
+  else:
+    const goLib = "libgo.so"
+
+  proc `div`[T: SomeUnsignedInt](x, y: T): T {.magic: "DivU", noSideEffect.}
+  proc `-`[T: SomeUnsignedInt](x, y: T): T {.magic: "SubU", noSideEffect.}
+
+  proc roundup(x, v: int): int {.inline.} =
+    result = (x + (v-1)) and not (v-1)
+
+  proc initGC() = discard
+  # runtime_setgcpercent is only available in GCC 5
+  proc GC_disable() = discard
+  proc GC_enable() = discard
+  proc goRuntimeGC(force: int32) {.importc: "runtime_gc", dynlib: goLib.}
+  proc GC_fullCollect() = goRuntimeGC(2)
+  proc GC_setStrategy(strategy: GC_Strategy) = discard
+  proc GC_enableMarkAndSweep() = discard
+  proc GC_disableMarkAndSweep() = discard
+
+  const
+    goNumSizeClasses = 67
+
+  type
+    cbool {.importc: "_Bool", nodecl.} = bool
+
+    goMStats_inner_struct = object
+        size: uint32
+        nmalloc: uint64
+        nfree: uint64
+
+    goMStats = object
+        # General statistics.
+        alloc: uint64            # bytes allocated and still in use
+        total_alloc: uint64      # bytes allocated (even if freed)
+        sys: uint64              # bytes obtained from system (should be sum of xxx_sys below, no locking, approximate)
+        nlookup: uint64          # number of pointer lookups
+        nmalloc: uint64          # number of mallocs
+        nfree: uint64            # number of frees
+        # Statistics about malloc heap.
+        # protected by mheap.Lock
+        heap_alloc: uint64       # bytes allocated and still in use
+        heap_sys: uint64         # bytes obtained from system
+        heap_idle: uint64        # bytes in idle spans
+        heap_inuse: uint64       # bytes in non-idle spans
+        heap_released: uint64    # bytes released to the OS
+        heap_objects: uint64 # total number of allocated objects
+        # Statistics about allocation of low-level fixed-size structures.
+        # Protected by FixAlloc locks.
+        stacks_inuse: uint64     # bootstrap stacks
+        stacks_sys: uint64
+        mspan_inuse: uint64      # MSpan structures
+        mspan_sys: uint64
+        mcache_inuse: uint64     # MCache structures
+        mcache_sys: uint64
+        buckhash_sys: uint64     # profiling bucket hash table
+        gc_sys: uint64
+        other_sys: uint64
+        # Statistics about garbage collector.
+        # Protected by mheap or stopping the world during GC.
+        next_gc: uint64          # next GC (in heap_alloc time)
+        last_gc: uint64          # last GC (in absolute time)
+        pause_total_ns: uint64
+        pause_ns: array[256, uint64]
+        numgc: uint32
+        enablegc: cbool
+        debuggc: cbool
+        # Statistics about allocation size classes.
+        by_size: array[goNumSizeClasses, goMStats_inner_struct]
+
+  proc goRuntime_ReadMemStats(a2: ptr goMStats) {.cdecl, importc: "runtime_ReadMemStats", codegenDecl: "$1 $2$3 __asm__ (\"runtime.ReadMemStats\");\n$1 $2$3", dynlib: goLib.}
+
+  proc GC_getStatistics(): string =
+    var mstats: goMStats
+    goRuntime_ReadMemStats(addr mstats)
+    result = "[GC] total allocated memory: " & $(mstats.total_alloc) & "\n" &
+             "[GC] total memory obtained from system: " & $(mstats.sys) & "\n" &
+             "[GC] occupied memory: " & $(mstats.alloc) & "\n" &
+             "[GC] number of pointer lookups: " & $(mstats.nlookup) & "\n" &
+             "[GC] number of mallocs: " & $(mstats.nmalloc) & "\n" &
+             "[GC] number of frees: " & $(mstats.nfree) & "\n" &
+             "[GC] heap objects: " & $(mstats.heap_objects) & "\n" &
+             "[GC] numgc: " & $(mstats.numgc) & "\n" &
+             "[GC] enablegc: " & $(mstats.enablegc) & "\n" &
+             "[GC] debuggc: " & $(mstats.debuggc) & "\n" &
+             "[GC] total pause time [ms]: " & $(mstats.pause_total_ns div 1000_000)
+
+  proc getOccupiedMem(): int =
+    var mstats: goMStats
+    goRuntime_ReadMemStats(addr mstats)
+    result = int(mstats.alloc)
+
+  proc getFreeMem(): int =
+    var mstats: goMStats
+    goRuntime_ReadMemStats(addr mstats)
+    result = int(mstats.sys - mstats.alloc)
+
+  proc getTotalMem(): int =
+    var mstats: goMStats
+    goRuntime_ReadMemStats(addr mstats)
+    result = int(mstats.sys)
+
+  proc setStackBottom(theStackBottom: pointer) = discard
+
+  proc alloc(size: Natural): pointer =
+    result = cmalloc(size)
+    if result == nil: raiseOutOfMem()
+
+  proc alloc0(size: Natural): pointer =
+    result = alloc(size)
+    zeroMem(result, size)
+
+  proc realloc(p: pointer, newsize: Natural): pointer =
+    result = crealloc(p, newsize)
+    if result == nil: raiseOutOfMem()
+
+  proc dealloc(p: pointer) = cfree(p)
+
+  proc allocShared(size: Natural): pointer =
+    result = cmalloc(size)
+    if result == nil: raiseOutOfMem()
+
+  proc allocShared0(size: Natural): pointer =
+    result = alloc(size)
+    zeroMem(result, size)
+
+  proc reallocShared(p: pointer, newsize: Natural): pointer =
+    result = crealloc(p, newsize)
+    if result == nil: raiseOutOfMem()
+
+  proc deallocShared(p: pointer) = cfree(p)
+
+  when hasThreadSupport:
+    proc getFreeSharedMem(): int = discard
+    proc getTotalSharedMem(): int = discard
+    proc getOccupiedSharedMem(): int = discard
+
+  const goFlagNoZero: uint32 = 1 shl 3
+  proc goRuntimeMallocGC(size: uint, typ: uint, flag: uint32): pointer {.importc: "runtime_mallocgc", dynlib: goLib.}
+  proc goFree(v: pointer) {.importc: "__go_free", dynlib: goLib.}
+
+  proc goSetFinalizer(obj: pointer, f: pointer) {.importc: "set_finalizer", codegenDecl:"$1 $2$3 __asm__ (\"main.Set_finalizer\");\n$1 $2$3", dynlib: goLib.}
+
+  proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} =
+    result = goRuntimeMallocGC(roundup(size, sizeof(pointer)).uint, 0.uint, 0.uint32)
+    if typ.finalizer != nil:
+      goSetFinalizer(result, typ.finalizer)
+
+  proc newObjNoInit(typ: PNimType, size: int): pointer =
+    result = goRuntimeMallocGC(roundup(size, sizeof(pointer)).uint, 0.uint, goFlagNoZero)
+    if typ.finalizer != nil:
+      goSetFinalizer(result, typ.finalizer)
+
+  proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.} =
+    result = newObj(typ, len * typ.base.size + GenericSeqSize)
+    cast[PGenericSeq](result).len = len
+    cast[PGenericSeq](result).reserved = len
+    cast[PGenericSeq](result).elemSize = typ.base.size
+
+  proc growObj(old: pointer, newsize: int): pointer =
+    # the Go GC doesn't have a realloc
+    var
+      oldsize = cast[PGenericSeq](old).len * cast[PGenericSeq](old).elemSize + GenericSeqSize
+    result = goRuntimeMallocGC(roundup(newsize, sizeof(pointer)).uint, 0.uint, goFlagNoZero)
+    copyMem(result, old, oldsize)
+    zeroMem(cast[pointer](cast[ByteAddress](result) +% oldsize), newsize - oldsize)
+    goFree(old)
+
+  proc nimGCref(p: pointer) {.compilerproc, inline.} = discard
+  proc nimGCunref(p: pointer) {.compilerproc, inline.} = discard
+
+  proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
+    dest[] = src
+  proc asgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
+    dest[] = src
+  proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerproc, inline.} =
+    dest[] = src
+
+  type
+    MemRegion = object {.final, pure.}
+  {.deprecated: [TMemRegion: MemRegion].}
+
+  proc alloc(r: var MemRegion, size: int): pointer =
+    result = alloc(size)
+  proc alloc0(r: var MemRegion, size: int): pointer =
+    result = alloc0(size)
+  proc dealloc(r: var MemRegion, p: pointer) = dealloc(p)
+  proc deallocOsPages(r: var MemRegion) {.inline.} = discard
+  proc deallocOsPages() {.inline.} = discard
+
 elif defined(nogc) and defined(useMalloc):
 
   when not defined(useNimRtl):
@@ -291,7 +486,6 @@ elif defined(nogc):
   proc GC_disableMarkAndSweep() = discard
   proc GC_getStatistics(): string = return ""
 
-
   proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} =
     result = alloc0(size)
 
diff --git a/lib/system/repr.nim b/lib/system/repr.nim
index f3b69954a..37056af3a 100644
--- a/lib/system/repr.nim
+++ b/lib/system/repr.nim
@@ -194,18 +194,24 @@ when not defined(useNimRtl):
   proc reprRecord(result: var string, p: pointer, typ: PNimType,
                   cl: var ReprClosure) =
     add result, "["
-    let oldLen = result.len
-    reprRecordAux(result, p, typ.node, cl)
-    if typ.base != nil: 
-      if oldLen != result.len: add result, ",\n"
-      reprRecordAux(result, p, typ.base.node, cl)
+    var curTyp = typ
+    var first = true
+    while curTyp.base != nil:
+      var part = ""
+      reprRecordAux(part, p, curTyp.node, cl)
+      if part.len > 0:
+        if not first:
+          add result, ",\n"
+        add result, part
+        first = false
+      curTyp = curTyp.base
     add result, "]"
 
   proc reprRef(result: var string, p: pointer, typ: PNimType,
                cl: var ReprClosure) =
     # we know that p is not nil here:
     when declared(CellSet):
-      when defined(boehmGC) or defined(nogc):
+      when defined(boehmGC) or defined(gogc) or defined(nogc):
         var cell = cast[PCell](p)
       else:
         var cell = usrToCell(p)
diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim
index 5b4020c8c..33629016f 100644
--- a/lib/system/sysstr.nim
+++ b/lib/system/sysstr.nim
@@ -50,12 +50,16 @@ proc rawNewStringNoInit(space: int): NimString {.compilerProc.} =
   if s < 7: s = 7
   result = allocStrNoInit(sizeof(TGenericSeq) + s + 1)
   result.reserved = s
+  when defined(gogc):
+    result.elemSize = 1
 
 proc rawNewString(space: int): NimString {.compilerProc.} =
   var s = space
   if s < 7: s = 7
   result = allocStr(sizeof(TGenericSeq) + s + 1)
   result.reserved = s
+  when defined(gogc):
+    result.elemSize = 1
 
 proc mnewString(len: int): NimString {.compilerProc.} =
   result = rawNewString(len)
@@ -216,7 +220,7 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {.
   elif newLen < result.len:
     # we need to decref here, otherwise the GC leaks!
     when not defined(boehmGC) and not defined(nogc) and
-         not defined(gcMarkAndSweep):
+         not defined(gcMarkAndSweep) and not defined(gogc):
       when compileOption("gc", "v2"):
         for i in newLen..result.len-1:
           let len0 = gch.tempStack.len
diff --git a/lib/system/threads.nim b/lib/system/threads.nim
index 865271a50..d77059f68 100644
--- a/lib/system/threads.nim
+++ b/lib/system/threads.nim
@@ -237,7 +237,7 @@ when not defined(useNimRtl):
       echo "too large thread local storage size requested"
       quit 1
   
-  when hasSharedHeap and not defined(boehmgc) and not defined(nogc):
+  when hasSharedHeap and not defined(boehmgc) and not defined(gogc) and not defined(nogc):
     var
       threadList: PGcThread
       
@@ -287,7 +287,7 @@ type
                                        ## a pointer as a thread ID.
 {.deprecated: [TThread: Thread, TThreadId: ThreadId].}
 
-when not defined(boehmgc) and not hasSharedHeap:
+when not defined(boehmgc) and not hasSharedHeap and not defined(gogc):
   proc deallocOsPages()
 
 template threadProcWrapperBody(closure: expr) {.immediate.} =
@@ -295,7 +295,7 @@ template threadProcWrapperBody(closure: expr) {.immediate.} =
   var t = cast[ptr Thread[TArg]](closure)
   when useStackMaskHack:
     var tls: ThreadLocalStorage
-  when not defined(boehmgc) and not defined(nogc) and not hasSharedHeap:
+  when not defined(boehmgc) and not defined(gogc) and not defined(nogc) and not hasSharedHeap:
     # init the GC for this thread:
     setStackBottom(addr(t))
     initGC()