summary refs log tree commit diff stats
path: root/lib/system/mm/go.nim
blob: 8e8558bea98eb70c46c6f652925f39c34eecc5b3 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
when defined(windows):
  const goLib = "libgo.dll"
elif defined(macosx):
  const goLib = "libgo.dylib"
else:
  const goLib = "libgo.so"

proc initGC() = discard
proc GC_disable() = discard
proc GC_enable() = discard
proc go_gc() {.importc: "go_gc", dynlib: goLib.}
proc GC_fullCollect() = go_gc()
proc GC_setStrategy(strategy: GC_Strategy) = discard
proc GC_enableMarkAndSweep() = discard
proc GC_disableMarkAndSweep() = discard

const
  goNumSizeClasses = 67

type
  goMStats = object
    alloc: uint64          # bytes allocated and still in use
    total_alloc: uint64    # bytes allocated (even if freed)
    sys: uint64            # bytes obtained from system
    nlookup: uint64        # number of pointer lookups
    nmalloc: uint64        # number of mallocs
    nfree: uint64          # number of frees
    heap_objects: uint64   # total number of allocated objects
    pause_total_ns: uint64 # cumulative nanoseconds in GC stop-the-world pauses since the program started
    numgc: uint32          # number of completed GC cycles

proc goMemStats(): goMStats {.importc: "go_mem_stats", dynlib: goLib.}
proc goMalloc(size: uint): pointer {.importc: "go_malloc", 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 writebarrierptr(dest: PPointer, src: pointer) {.importc: "writebarrierptr", codegenDecl:"$1 $2$3 __asm__ (\"main.Atomic_store_pointer\");\n$1 $2$3", dynlib: goLib.}

proc `$`*(x: uint64): string {.noSideEffect, raises: [].}

proc GC_getStatistics(): string =
  var mstats = goMemStats()
  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] number of completed GC cycles: " & $(mstats.numgc) & "\n" &
           "[GC] total GC pause time [ms]: " & $(mstats.pause_total_ns div 1000_000)

proc getOccupiedMem(): int =
  var mstats = goMemStats()
  result = int(mstats.alloc)

proc getFreeMem(): int =
  var mstats = goMemStats()
  result = int(mstats.sys - mstats.alloc)

proc getTotalMem(): int =
  var mstats = goMemStats()
  result = int(mstats.sys)

proc nimGC_setStackBottom(theStackBottom: pointer) = discard

proc allocImpl(size: Natural): pointer =
  result = goMalloc(size.uint)

proc alloc0Impl(size: Natural): pointer =
  result = goMalloc(size.uint)

proc reallocImpl(p: pointer, newsize: Natural): pointer =
  doAssert false, "not implemented"

proc realloc0Impl(p: pointer, oldsize, newsize: Natural): pointer =
  doAssert false, "not implemented"

proc deallocImpl(p: pointer) =
  discard

proc allocSharedImpl(size: Natural): pointer = allocImpl(size)
proc allocShared0Impl(size: Natural): pointer = alloc0Impl(size)
proc reallocSharedImpl(p: pointer, newsize: Natural): pointer = reallocImpl(p, newsize)
proc reallocShared0Impl(p: pointer, oldsize, newsize: Natural): pointer = realloc0Impl(p, oldsize, newsize)
proc deallocSharedImpl(p: pointer) = deallocImpl(p)

when hasThreadSupport:
  proc getFreeSharedMem(): int = discard
  proc getTotalSharedMem(): int = discard
  proc getOccupiedSharedMem(): int = discard

proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} =
  writebarrierptr(addr(result), goMalloc(size.uint))
  if typ.finalizer != nil:
    goSetFinalizer(result, typ.finalizer)

proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
  writebarrierptr(addr(result), newObj(typ, size))

proc newObjNoInit(typ: PNimType, size: int): pointer =
  writebarrierptr(addr(result), newObj(typ, size))

proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.} =
  writebarrierptr(addr(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 newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
  writebarrierptr(addr(result), newSeq(typ, len))

proc nimNewSeqOfCap(typ: PNimType, cap: int): pointer {.compilerproc.} =
  result = newObj(typ, cap * typ.base.size + GenericSeqSize)
  cast[PGenericSeq](result).len = 0
  cast[PGenericSeq](result).reserved = cap
  cast[PGenericSeq](result).elemSize = typ.base.size

proc typedMemMove(dest: pointer, src: pointer, size: uint) {.importc: "typedmemmove", dynlib: goLib.}

proc growObj(old: pointer, newsize: int): pointer =
  # the Go GC doesn't have a realloc
  var metadataOld = cast[PGenericSeq](old)
  if metadataOld.elemSize == 0:
    metadataOld.elemSize = 1
  let oldsize = cast[PGenericSeq](old).len * cast[PGenericSeq](old).elemSize + GenericSeqSize
  writebarrierptr(addr(result), goMalloc(newsize.uint))
  typedMemMove(result, old, oldsize.uint)

proc nimGCref(p: pointer) {.compilerproc, inline.} = discard
proc nimGCunref(p: pointer) {.compilerproc, inline.} = discard
proc nimGCunrefNoCycle(p: pointer) {.compilerProc, inline.} = discard
proc nimGCunrefRC1(p: pointer) {.compilerProc, inline.} = discard
proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} = discard

proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
  writebarrierptr(dest, src)
proc asgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
  writebarrierptr(dest, src)
proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerproc, inline,
  deprecated: "old compiler compat".} = asgnRef(dest, src)

type
  MemRegion = object

proc alloc(r: var MemRegion, size: int): pointer =
  result = alloc(size)
proc alloc0(r: var MemRegion, size: int): pointer =
  result = alloc0Impl(size)
proc dealloc(r: var MemRegion, p: pointer) = dealloc(p)
proc deallocOsPages(r: var MemRegion) {.inline.} = discard
proc deallocOsPages() {.inline.} = discard