mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-26 17:24:02 +00:00
Merge branch 'devel' of github.com:nim-lang/Nim into devel
This commit is contained in:
@@ -222,6 +222,8 @@ __clang__
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
#define COMMA ,
|
||||
|
||||
#include <limits.h>
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
@@ -2627,3 +2627,17 @@ proc utimes*(path: cstring, times: ptr array [2, Timeval]): int {.
|
||||
## Returns zero on success.
|
||||
##
|
||||
## For more information read http://www.unix.com/man-page/posix/3/utimes/.
|
||||
|
||||
proc handle_signal(sig: cint, handler: proc (a: cint) {.noconv.}) {.importc: "signal", header: "<signal.h>".}
|
||||
|
||||
template onSignal*(signals: varargs[cint], body: untyped): stmt =
|
||||
## Setup code to be executed when Unix signals are received. Example:
|
||||
## from posix import SIGINT, SIGTERM
|
||||
## onSignal(SIGINT, SIGTERM):
|
||||
## echo "bye"
|
||||
|
||||
for s in signals:
|
||||
handle_signal(s,
|
||||
proc (sig: cint) {.noconv.} =
|
||||
body
|
||||
)
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
include "system/inclrtl"
|
||||
|
||||
import os, oids, tables, strutils, macros, times
|
||||
import os, oids, tables, strutils, macros, times, heapqueue
|
||||
|
||||
import nativesockets, net
|
||||
|
||||
@@ -354,21 +354,27 @@ proc `or`*[T, Y](fut1: Future[T], fut2: Future[Y]): Future[void] =
|
||||
|
||||
type
|
||||
PDispatcherBase = ref object of RootRef
|
||||
timers: seq[tuple[finishAt: float, fut: Future[void]]]
|
||||
timers: HeapQueue[tuple[finishAt: float, fut: Future[void]]]
|
||||
|
||||
proc processTimers(p: PDispatcherBase) =
|
||||
var oldTimers = p.timers
|
||||
p.timers = @[]
|
||||
for t in oldTimers:
|
||||
if epochTime() >= t.finishAt:
|
||||
t.fut.complete()
|
||||
else:
|
||||
p.timers.add(t)
|
||||
proc processTimers(p: PDispatcherBase) {.inline.} =
|
||||
while p.timers.len > 0 and epochTime() >= p.timers[0].finishAt:
|
||||
p.timers.pop().fut.complete()
|
||||
|
||||
proc adjustedTimeout(p: PDispatcherBase, timeout: int): int {.inline.} =
|
||||
# If dispatcher has active timers this proc returns the timeout
|
||||
# of the nearest timer. Returns `timeout` otherwise.
|
||||
result = timeout
|
||||
if p.timers.len > 0:
|
||||
let timerTimeout = p.timers[0].finishAt
|
||||
let curTime = epochTime()
|
||||
if timeout == -1 or (curTime + (timeout / 1000)) > timerTimeout:
|
||||
result = int((timerTimeout - curTime) * 1000)
|
||||
if result < 0: result = 0
|
||||
|
||||
when defined(windows) or defined(nimdoc):
|
||||
import winlean, sets, hashes
|
||||
type
|
||||
CompletionKey = Dword
|
||||
CompletionKey = ULONG_PTR
|
||||
|
||||
CompletionData* = object
|
||||
fd*: AsyncFD # TODO: Rename this.
|
||||
@@ -396,7 +402,7 @@ when defined(windows) or defined(nimdoc):
|
||||
new result
|
||||
result.ioPort = createIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 1)
|
||||
result.handles = initSet[AsyncFD]()
|
||||
result.timers = @[]
|
||||
result.timers.newHeapQueue()
|
||||
|
||||
var gDisp{.threadvar.}: PDispatcher ## Global dispatcher
|
||||
proc getGlobalDispatcher*(): PDispatcher =
|
||||
@@ -427,11 +433,13 @@ when defined(windows) or defined(nimdoc):
|
||||
raise newException(ValueError,
|
||||
"No handles or timers registered in dispatcher.")
|
||||
|
||||
let llTimeout =
|
||||
if timeout == -1: winlean.INFINITE
|
||||
else: timeout.int32
|
||||
let at = p.adjustedTimeout(timeout)
|
||||
var llTimeout =
|
||||
if at == -1: winlean.INFINITE
|
||||
else: at.int32
|
||||
|
||||
var lpNumberOfBytesTransferred: Dword
|
||||
var lpCompletionKey: ULONG
|
||||
var lpCompletionKey: ULONG_PTR
|
||||
var customOverlapped: PCustomOverlapped
|
||||
let res = getQueuedCompletionStatus(p.ioPort,
|
||||
addr lpNumberOfBytesTransferred, addr lpCompletionKey,
|
||||
@@ -956,7 +964,7 @@ else:
|
||||
proc newDispatcher*(): PDispatcher =
|
||||
new result
|
||||
result.selector = newSelector()
|
||||
result.timers = @[]
|
||||
result.timers.newHeapQueue()
|
||||
|
||||
var gDisp{.threadvar.}: PDispatcher ## Global dispatcher
|
||||
proc getGlobalDispatcher*(): PDispatcher =
|
||||
@@ -1014,7 +1022,7 @@ else:
|
||||
|
||||
proc poll*(timeout = 500) =
|
||||
let p = getGlobalDispatcher()
|
||||
for info in p.selector.select(timeout):
|
||||
for info in p.selector.select(p.adjustedTimeout(timeout)):
|
||||
let data = PData(info.key.data)
|
||||
assert data.fd == info.key.fd.AsyncFD
|
||||
#echo("In poll ", data.fd.cint)
|
||||
@@ -1215,7 +1223,7 @@ proc sleepAsync*(ms: int): Future[void] =
|
||||
## ``ms`` milliseconds.
|
||||
var retFuture = newFuture[void]("sleepAsync")
|
||||
let p = getGlobalDispatcher()
|
||||
p.timers.add((epochTime() + (ms / 1000), retFuture))
|
||||
p.timers.push((epochTime() + (ms / 1000), retFuture))
|
||||
return retFuture
|
||||
|
||||
proc accept*(socket: AsyncFD,
|
||||
|
||||
@@ -162,7 +162,7 @@ proc read*(f: AsyncFile, size: int): Future[string] =
|
||||
# Request completed immediately.
|
||||
var bytesRead: DWord
|
||||
let overlappedRes = getOverlappedResult(f.fd.Handle,
|
||||
cast[POverlapped](ol)[], bytesRead, false.WinBool)
|
||||
cast[POverlapped](ol), bytesRead, false.WinBool)
|
||||
if not overlappedRes.bool:
|
||||
let err = osLastError()
|
||||
if err.int32 == ERROR_HANDLE_EOF:
|
||||
@@ -282,7 +282,7 @@ proc write*(f: AsyncFile, data: string): Future[void] =
|
||||
# Request completed immediately.
|
||||
var bytesWritten: DWord
|
||||
let overlappedRes = getOverlappedResult(f.fd.Handle,
|
||||
cast[POverlapped](ol)[], bytesWritten, false.WinBool)
|
||||
cast[POverlapped](ol), bytesWritten, false.WinBool)
|
||||
if not overlappedRes.bool:
|
||||
retFuture.fail(newException(OSError, osErrorMsg(osLastError())))
|
||||
else:
|
||||
|
||||
107
lib/pure/collections/heapqueue.nim
Normal file
107
lib/pure/collections/heapqueue.nim
Normal file
@@ -0,0 +1,107 @@
|
||||
##[ Heap queue algorithm (a.k.a. priority queue). Ported from Python heapq.
|
||||
|
||||
Heaps are arrays for which a[k] <= a[2*k+1] and a[k] <= a[2*k+2] for
|
||||
all k, counting elements from 0. For the sake of comparison,
|
||||
non-existing elements are considered to be infinite. The interesting
|
||||
property of a heap is that a[0] is always its smallest element.
|
||||
|
||||
]##
|
||||
|
||||
type HeapQueue*[T] = distinct seq[T]
|
||||
|
||||
proc newHeapQueue*[T](): HeapQueue[T] {.inline.} = HeapQueue[T](newSeq[T]())
|
||||
proc newHeapQueue*[T](h: var HeapQueue[T]) {.inline.} = h = HeapQueue[T](newSeq[T]())
|
||||
|
||||
proc len*[T](h: HeapQueue[T]): int {.inline.} = seq[T](h).len
|
||||
proc `[]`*[T](h: HeapQueue[T], i: int): T {.inline.} = seq[T](h)[i]
|
||||
proc `[]=`[T](h: var HeapQueue[T], i: int, v: T) {.inline.} = seq[T](h)[i] = v
|
||||
proc add[T](h: var HeapQueue[T], v: T) {.inline.} = seq[T](h).add(v)
|
||||
|
||||
proc heapCmp[T](x, y: T): bool {.inline.} =
|
||||
return (x < y)
|
||||
|
||||
# 'heap' is a heap at all indices >= startpos, except possibly for pos. pos
|
||||
# is the index of a leaf with a possibly out-of-order value. Restore the
|
||||
# heap invariant.
|
||||
proc siftdown[T](heap: var HeapQueue[T], startpos, p: int) =
|
||||
var pos = p
|
||||
var newitem = heap[pos]
|
||||
# Follow the path to the root, moving parents down until finding a place
|
||||
# newitem fits.
|
||||
while pos > startpos:
|
||||
let parentpos = (pos - 1) shr 1
|
||||
let parent = heap[parentpos]
|
||||
if heapCmp(newitem, parent):
|
||||
heap[pos] = parent
|
||||
pos = parentpos
|
||||
else:
|
||||
break
|
||||
heap[pos] = newitem
|
||||
|
||||
proc siftup[T](heap: var HeapQueue[T], p: int) =
|
||||
let endpos = len(heap)
|
||||
var pos = p
|
||||
let startpos = pos
|
||||
let newitem = heap[pos]
|
||||
# Bubble up the smaller child until hitting a leaf.
|
||||
var childpos = 2*pos + 1 # leftmost child position
|
||||
while childpos < endpos:
|
||||
# Set childpos to index of smaller child.
|
||||
let rightpos = childpos + 1
|
||||
if rightpos < endpos and not heapCmp(heap[childpos], heap[rightpos]):
|
||||
childpos = rightpos
|
||||
# Move the smaller child up.
|
||||
heap[pos] = heap[childpos]
|
||||
pos = childpos
|
||||
childpos = 2*pos + 1
|
||||
# The leaf at pos is empty now. Put newitem there, and bubble it up
|
||||
# to its final resting place (by sifting its parents down).
|
||||
heap[pos] = newitem
|
||||
siftdown(heap, startpos, pos)
|
||||
|
||||
proc push*[T](heap: var HeapQueue[T], item: T) =
|
||||
## Push item onto heap, maintaining the heap invariant.
|
||||
(seq[T](heap)).add(item)
|
||||
siftdown(heap, 0, len(heap)-1)
|
||||
|
||||
proc pop*[T](heap: var HeapQueue[T]): T =
|
||||
## Pop the smallest item off the heap, maintaining the heap invariant.
|
||||
let lastelt = seq[T](heap).pop()
|
||||
if heap.len > 0:
|
||||
result = heap[0]
|
||||
heap[0] = lastelt
|
||||
siftup(heap, 0)
|
||||
else:
|
||||
result = lastelt
|
||||
|
||||
proc replace*[T](heap: var HeapQueue[T], item: T): T =
|
||||
## Pop and return the current smallest value, and add the new item.
|
||||
## This is more efficient than pop() followed by push(), and can be
|
||||
## more appropriate when using a fixed-size heap. Note that the value
|
||||
## returned may be larger than item! That constrains reasonable uses of
|
||||
## this routine unless written as part of a conditional replacement:
|
||||
|
||||
## if item > heap[0]:
|
||||
## item = replace(heap, item)
|
||||
result = heap[0]
|
||||
heap[0] = item
|
||||
siftup(heap, 0)
|
||||
|
||||
proc pushpop*[T](heap: var HeapQueue[T], item: T): T =
|
||||
## Fast version of a push followed by a pop.
|
||||
if heap.len > 0 and heapCmp(heap[0], item):
|
||||
swap(item, heap[0])
|
||||
siftup(heap, 0)
|
||||
return item
|
||||
|
||||
when isMainModule:
|
||||
# Simple sanity test
|
||||
var heap = newHeapQueue[int]()
|
||||
let data = [1, 3, 5, 7, 9, 2, 4, 6, 8, 0]
|
||||
for item in data:
|
||||
push(heap, item)
|
||||
doAssert(heap[0] == 0)
|
||||
var sort = newSeq[int]()
|
||||
while heap.len > 0:
|
||||
sort.add(pop(heap))
|
||||
doAssert(sort == @[0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
|
||||
@@ -663,6 +663,27 @@ proc sort*[A, B](t: OrderedTableRef[A, B],
|
||||
## contrast to the `sort` for count tables).
|
||||
t[].sort(cmp)
|
||||
|
||||
proc del*[A, B](t: var OrderedTable[A, B], key: A) =
|
||||
## deletes `key` from ordered hash table `t`. O(n) comlexity.
|
||||
var prev = -1
|
||||
let hc = hash(key)
|
||||
forAllOrderedPairs:
|
||||
if t.data[h].hcode == hc:
|
||||
if t.first == h:
|
||||
t.first = t.data[h].next
|
||||
else:
|
||||
t.data[prev].next = t.data[h].next
|
||||
var zeroValue : type(t.data[h])
|
||||
t.data[h] = zeroValue
|
||||
dec t.counter
|
||||
break
|
||||
else:
|
||||
prev = h
|
||||
|
||||
proc del*[A, B](t: var OrderedTableRef[A, B], key: A) =
|
||||
## deletes `key` from ordered hash table `t`. O(n) comlexity.
|
||||
t[].del(key)
|
||||
|
||||
# ------------------------------ count tables -------------------------------
|
||||
|
||||
type
|
||||
@@ -984,6 +1005,26 @@ when isMainModule:
|
||||
s3[p1] = 30_000
|
||||
s3[p2] = 45_000
|
||||
|
||||
block: # Ordered table should preserve order after deletion
|
||||
var
|
||||
s4 = initOrderedTable[int, int]()
|
||||
s4[1] = 1
|
||||
s4[2] = 2
|
||||
s4[3] = 3
|
||||
|
||||
var prev = 0
|
||||
for i in s4.values:
|
||||
doAssert(prev < i)
|
||||
prev = i
|
||||
|
||||
s4.del(2)
|
||||
doAssert(2 notin s4)
|
||||
doAssert(s4.len == 2)
|
||||
prev = 0
|
||||
for i in s4.values:
|
||||
doAssert(prev < i)
|
||||
prev = i
|
||||
|
||||
var
|
||||
t1 = initCountTable[string]()
|
||||
t2 = initCountTable[string]()
|
||||
|
||||
@@ -54,6 +54,7 @@ type
|
||||
lvlAll, ## all levels active
|
||||
lvlDebug, ## debug level (and any above) active
|
||||
lvlInfo, ## info level (and any above) active
|
||||
lvlNotice, ## info notice (and any above) active
|
||||
lvlWarn, ## warn level (and any above) active
|
||||
lvlError, ## error level (and any above) active
|
||||
lvlFatal, ## fatal level (and any above) active
|
||||
@@ -61,7 +62,7 @@ type
|
||||
|
||||
const
|
||||
LevelNames*: array [Level, string] = [
|
||||
"DEBUG", "DEBUG", "INFO", "WARN", "ERROR", "FATAL", "NONE"
|
||||
"DEBUG", "DEBUG", "INFO", "NOTICE", "WARN", "ERROR", "FATAL", "NONE"
|
||||
]
|
||||
|
||||
defaultFmtStr* = "$levelname " ## default format string
|
||||
@@ -258,22 +259,47 @@ template log*(level: Level, args: varargs[string, `$`]) =
|
||||
|
||||
template debug*(args: varargs[string, `$`]) =
|
||||
## Logs a debug message to all registered handlers.
|
||||
##
|
||||
## Messages that are useful to the application developer only and are usually
|
||||
## turned off in release.
|
||||
log(lvlDebug, args)
|
||||
|
||||
template info*(args: varargs[string, `$`]) =
|
||||
## Logs an info message to all registered handlers.
|
||||
##
|
||||
## Messages that are generated during the normal operation of an application
|
||||
## and are of no particular importance. Useful to aggregate for potential
|
||||
## later analysis.
|
||||
log(lvlInfo, args)
|
||||
|
||||
template notice*(args: varargs[string, `$`]) =
|
||||
## Logs an notice message to all registered handlers.
|
||||
##
|
||||
## Semantically very similar to `info`, but meant to be messages you want to
|
||||
## be actively notified about (depending on your application).
|
||||
## These could be, for example, grouped by hour and mailed out.
|
||||
log(lvlNotice, args)
|
||||
|
||||
template warn*(args: varargs[string, `$`]) =
|
||||
## Logs a warning message to all registered handlers.
|
||||
##
|
||||
## A non-error message that may indicate a potential problem rising or
|
||||
## impacted performance.
|
||||
log(lvlWarn, args)
|
||||
|
||||
template error*(args: varargs[string, `$`]) =
|
||||
## Logs an error message to all registered handlers.
|
||||
##
|
||||
## A application-level error condition. For example, some user input generated
|
||||
## an exception. The application will continue to run, but functionality or
|
||||
## data was impacted, possibly visible to users.
|
||||
log(lvlError, args)
|
||||
|
||||
template fatal*(args: varargs[string, `$`]) =
|
||||
## Logs a fatal error message to all registered handlers.
|
||||
##
|
||||
## A application-level fatal condition. FATAL usually means that the application
|
||||
## cannot go on and will exit (but this logging event will not do that for you).
|
||||
log(lvlFatal, args)
|
||||
|
||||
proc addHandler*(handler: Logger) =
|
||||
|
||||
@@ -20,9 +20,9 @@
|
||||
## var msg = createMessage("Hello from Nim's SMTP",
|
||||
## "Hello!.\n Is this awesome or what?",
|
||||
## @["foo@gmail.com"])
|
||||
## var smtp = connect("smtp.gmail.com", 465, true, true)
|
||||
## smtp.auth("username", "password")
|
||||
## smtp.sendmail("username@gmail.com", @["foo@gmail.com"], $msg)
|
||||
## var smtpConn = connect("smtp.gmail.com", Port 465, true, true)
|
||||
## smtpConn.auth("username", "password")
|
||||
## smtpConn.sendmail("username@gmail.com", @["foo@gmail.com"], $msg)
|
||||
##
|
||||
##
|
||||
## For SSL support this module relies on OpenSSL. If you want to
|
||||
@@ -31,6 +31,8 @@
|
||||
import net, strutils, strtabs, base64, os
|
||||
import asyncnet, asyncdispatch
|
||||
|
||||
export Port
|
||||
|
||||
type
|
||||
Smtp* = object
|
||||
sock: Socket
|
||||
@@ -258,8 +260,8 @@ when not defined(testing) and isMainModule:
|
||||
# "Hello, my name is dom96.\n What\'s yours?", @["dominik@localhost"])
|
||||
#echo(msg)
|
||||
|
||||
#var smtp = connect("localhost", 25, False, True)
|
||||
#smtp.sendmail("root@localhost", @["dominik@localhost"], $msg)
|
||||
#var smtpConn = connect("localhost", Port 25, false, true)
|
||||
#smtpConn.sendmail("root@localhost", @["dominik@localhost"], $msg)
|
||||
|
||||
#echo(decode("a17sm3701420wbe.12"))
|
||||
proc main() {.async.} =
|
||||
|
||||
@@ -1291,7 +1291,7 @@ const
|
||||
when hasThreadSupport and defined(tcc) and not compileOption("tlsEmulation"):
|
||||
# tcc doesn't support TLS
|
||||
{.error: "``--tlsEmulation:on`` must be used when using threads with tcc backend".}
|
||||
|
||||
|
||||
when defined(boehmgc):
|
||||
when defined(windows):
|
||||
const boehmLib = "boehmgc.dll"
|
||||
@@ -2565,8 +2565,9 @@ when not defined(JS): #and not defined(nimscript):
|
||||
{.push stack_trace: off, profiler:off.}
|
||||
|
||||
when not defined(nimscript) and not defined(nogc):
|
||||
proc initGC()
|
||||
when not defined(boehmgc) and not defined(useMalloc) and not defined(gogc):
|
||||
when not defined(gcStack):
|
||||
proc initGC()
|
||||
when not defined(boehmgc) and not defined(useMalloc) and not defined(gogc) and not defined(gcStack):
|
||||
proc initAllocator() {.inline.}
|
||||
|
||||
proc initStackBottom() {.inline, compilerproc.} =
|
||||
|
||||
@@ -36,33 +36,34 @@ type
|
||||
BaseChunk = object
|
||||
next: Chunk
|
||||
size: int
|
||||
head, last: ptr ObjHeader # first and last object in chunk that
|
||||
head, tail: ptr ObjHeader # first and last object in chunk that
|
||||
# has a finalizer attached to it
|
||||
|
||||
type
|
||||
StackPtr = object
|
||||
chunk: pointer
|
||||
bump: pointer
|
||||
remaining: int
|
||||
current: Chunk
|
||||
|
||||
MemRegion* = object
|
||||
remaining: int
|
||||
chunk: pointer
|
||||
head, last: Chunk
|
||||
bump: pointer
|
||||
head, tail: Chunk
|
||||
nextChunkSize, totalSize: int
|
||||
hole: ptr Hole # we support individual freeing
|
||||
lock: SysLock
|
||||
when hasThreadSupport:
|
||||
lock: SysLock
|
||||
|
||||
var
|
||||
region {.threadVar.}: MemRegion
|
||||
tlRegion {.threadVar.}: MemRegion
|
||||
|
||||
template withRegion*(r: MemRegion; body: untyped) =
|
||||
let oldRegion = region
|
||||
region = r
|
||||
let oldRegion = tlRegion
|
||||
tlRegion = r
|
||||
try:
|
||||
body
|
||||
finally:
|
||||
region = oldRegion
|
||||
tlRegion = oldRegion
|
||||
|
||||
template inc(p: pointer, s: int) =
|
||||
p = cast[pointer](cast[int](p) +% s)
|
||||
@@ -71,7 +72,7 @@ template `+!`(p: pointer, s: int): pointer =
|
||||
cast[pointer](cast[int](p) +% s)
|
||||
|
||||
template `-!`(p: pointer, s: int): pointer =
|
||||
cast[pointer](cast[int](p) +% s)
|
||||
cast[pointer](cast[int](p) -% s)
|
||||
|
||||
proc allocSlowPath(r: var MemRegion; size: int) =
|
||||
# we need to ensure that the underlying linked list
|
||||
@@ -84,7 +85,7 @@ proc allocSlowPath(r: var MemRegion; size: int) =
|
||||
r.nextChunkSize =
|
||||
if r.totalSize < 64 * 1024: PageSize*4
|
||||
else: r.nextChunkSize*2
|
||||
var s = align(size+sizeof(BaseChunk), PageSize)
|
||||
var s = roundup(size+sizeof(BaseChunk), PageSize)
|
||||
var fresh: Chunk
|
||||
if s > r.nextChunkSize:
|
||||
fresh = cast[Chunk](osAllocPages(s))
|
||||
@@ -97,22 +98,25 @@ proc allocSlowPath(r: var MemRegion; size: int) =
|
||||
else:
|
||||
s = r.nextChunkSize
|
||||
fresh.size = s
|
||||
fresh.final = nil
|
||||
r.totalSize += s
|
||||
let old = r.last
|
||||
fresh.head = nil
|
||||
fresh.tail = nil
|
||||
inc r.totalSize, s
|
||||
let old = r.tail
|
||||
if old == nil:
|
||||
r.head = fresh
|
||||
else:
|
||||
r.last.next = fresh
|
||||
r.chunk = fresh +! sizeof(BaseChunk)
|
||||
r.last = fresh
|
||||
r.tail.next = fresh
|
||||
r.bump = fresh +! sizeof(BaseChunk)
|
||||
r.tail = fresh
|
||||
r.remaining = s - sizeof(BaseChunk)
|
||||
|
||||
proc alloc(r: var MemRegion; size: int): pointer {.inline.} =
|
||||
if unlikely(r.remaining < size): allocSlowPath(r, size)
|
||||
if size > r.remaining:
|
||||
allocSlowPath(r, size)
|
||||
sysAssert(size <= r.remaining, "size <= r.remaining")
|
||||
dec(r.remaining, size)
|
||||
result = r.chunk
|
||||
inc r.chunk, size
|
||||
result = r.bump
|
||||
inc r.bump, size
|
||||
|
||||
proc runFinalizers(c: Chunk) =
|
||||
var it = c.head
|
||||
@@ -120,228 +124,241 @@ proc runFinalizers(c: Chunk) =
|
||||
# indivually freed objects with finalizer stay in the list, but
|
||||
# their typ is nil then:
|
||||
if it.typ != nil and it.typ.finalizer != nil:
|
||||
(cast[Finalizer](cell.typ.finalizer))(cell+!sizeof(ObjHeader))
|
||||
it = it.next
|
||||
(cast[Finalizer](it.typ.finalizer))(it+!sizeof(ObjHeader))
|
||||
it = it.nextFinal
|
||||
|
||||
proc dealloc(r: var MemRegion; p: pointer) =
|
||||
let it = p-!sizeof(ObjHeader)
|
||||
let it = cast[ptr ObjHeader](p-!sizeof(ObjHeader))
|
||||
if it.typ != nil and it.typ.finalizer != nil:
|
||||
(cast[Finalizer](cell.typ.finalizer))(p)
|
||||
(cast[Finalizer](it.typ.finalizer))(p)
|
||||
it.typ = nil
|
||||
|
||||
proc deallocAll(head: Chunk) =
|
||||
proc deallocAll(r: var MemRegion; head: Chunk) =
|
||||
var it = head
|
||||
while it != nil:
|
||||
let nxt = it.next
|
||||
runFinalizers(it)
|
||||
dec r.totalSize, it.size
|
||||
osDeallocPages(it, it.size)
|
||||
it = it.next
|
||||
it = nxt
|
||||
|
||||
proc deallocAll*(r: var MemRegion) =
|
||||
deallocAll(r.head)
|
||||
deallocAll(r, r.head)
|
||||
zeroMem(addr r, sizeof r)
|
||||
|
||||
proc obstackPtr*(r: MemRegion): StackPtr =
|
||||
result.chunk = r.chunk
|
||||
result.bump = r.bump
|
||||
result.remaining = r.remaining
|
||||
result.current = r.last
|
||||
result.current = r.tail
|
||||
|
||||
proc setObstackPtr*(r: MemRegion; sp: StackPtr) =
|
||||
template computeRemaining(r): untyped =
|
||||
r.tail.size -% (cast[int](r.bump) -% cast[int](r.tail))
|
||||
|
||||
proc setObstackPtr*(r: var MemRegion; sp: StackPtr) =
|
||||
# free everything after 'sp':
|
||||
if sp.current != nil:
|
||||
deallocAll(sp.current.next)
|
||||
r.chunk = sp.chunk
|
||||
deallocAll(r, sp.current.next)
|
||||
sp.current.next = nil
|
||||
else:
|
||||
deallocAll(r, r.head)
|
||||
r.head = nil
|
||||
r.bump = sp.bump
|
||||
r.tail = sp.current
|
||||
r.remaining = sp.remaining
|
||||
r.last = sp.current
|
||||
|
||||
proc obstackPtr*(): StackPtr = tlRegion.obstackPtr()
|
||||
proc setObstackPtr*(sp: StackPtr) = tlRegion.setObstackPtr(sp)
|
||||
|
||||
proc joinRegion*(dest: var MemRegion; src: MemRegion) =
|
||||
# merging is not hard.
|
||||
if dest.head.isNil:
|
||||
dest.head = src.head
|
||||
else:
|
||||
dest.last.next = src.head
|
||||
dest.last = src.last
|
||||
dest.chunk = src.chunk
|
||||
dest.tail.next = src.head
|
||||
dest.tail = src.tail
|
||||
dest.bump = src.bump
|
||||
dest.remaining = src.remaining
|
||||
dest.nextChunkSize = max(dest.nextChunkSize, src.nextChunkSize)
|
||||
dest.totalSize += src.totalSize
|
||||
if dest.hole.size < src.hole.size:
|
||||
dest.hole = src.hole
|
||||
inc dest.totalSize, src.totalSize
|
||||
|
||||
proc isOnHeap*(r: MemRegion; p: pointer): bool =
|
||||
# the last chunk is the largest, so check it first. It's also special
|
||||
# the tail chunk is the largest, so check it first. It's also special
|
||||
# in that contains the current bump pointer:
|
||||
if r.last >= p and p < r.chunk:
|
||||
if r.tail >= p and p < r.bump:
|
||||
return true
|
||||
var it = r.head
|
||||
while it != r.last:
|
||||
while it != r.tail:
|
||||
if it >= p and p <= it+!it.size: return true
|
||||
it = it.next
|
||||
|
||||
proc isInteriorPointer(r: MemRegion; p: pointer): pointer =
|
||||
discard " we cannot patch stack pointers anyway!"
|
||||
when false:
|
||||
# essential feature for later: copy data over from one region to another
|
||||
|
||||
type
|
||||
PointerStackChunk = object
|
||||
next, prev: ptr PointerStackChunk
|
||||
len: int
|
||||
data: array[128, pointer]
|
||||
proc isInteriorPointer(r: MemRegion; p: pointer): pointer =
|
||||
discard " we cannot patch stack pointers anyway!"
|
||||
|
||||
template head(s: PointerStackChunk): untyped = s.prev
|
||||
template tail(s: PointerStackChunk): untyped = s.next
|
||||
type
|
||||
PointerStackChunk = object
|
||||
next, prev: ptr PointerStackChunk
|
||||
len: int
|
||||
data: array[128, pointer]
|
||||
|
||||
include chains
|
||||
template head(s: PointerStackChunk): untyped = s.prev
|
||||
template tail(s: PointerStackChunk): untyped = s.next
|
||||
|
||||
proc push(r: var MemRegion; s: var PointerStackChunk; x: pointer) =
|
||||
if s.len < high(s.data):
|
||||
s.data[s.len] = x
|
||||
inc s.len
|
||||
else:
|
||||
let fresh = cast[ptr PointerStackChunk](alloc(r, sizeof(PointerStackChunk)))
|
||||
fresh.len = 1
|
||||
fresh.data[0] = x
|
||||
fresh.next = nil
|
||||
fresh.prev = nil
|
||||
append(s, fresh)
|
||||
include chains
|
||||
|
||||
|
||||
proc genericDeepCopyAux(dr: var MemRegion; stack: var PointerStackChunk;
|
||||
dest, src: pointer, mt: PNimType) {.benign.}
|
||||
proc genericDeepCopyAux(dr: var MemRegion; stack: var PointerStackChunk;
|
||||
dest, src: pointer, n: ptr TNimNode) {.benign.} =
|
||||
var
|
||||
d = cast[ByteAddress](dest)
|
||||
s = cast[ByteAddress](src)
|
||||
case n.kind
|
||||
of nkSlot:
|
||||
genericDeepCopyAux(cast[pointer](d +% n.offset),
|
||||
cast[pointer](s +% n.offset), n.typ)
|
||||
of nkList:
|
||||
for i in 0..n.len-1:
|
||||
genericDeepCopyAux(dest, src, n.sons[i])
|
||||
of nkCase:
|
||||
var dd = selectBranch(dest, n)
|
||||
var m = selectBranch(src, n)
|
||||
# reset if different branches are in use; note different branches also
|
||||
# imply that's not self-assignment (``x = x``)!
|
||||
if m != dd and dd != nil:
|
||||
genericResetAux(dest, dd)
|
||||
copyMem(cast[pointer](d +% n.offset), cast[pointer](s +% n.offset),
|
||||
n.typ.size)
|
||||
if m != nil:
|
||||
genericDeepCopyAux(dest, src, m)
|
||||
of nkNone: sysAssert(false, "genericDeepCopyAux")
|
||||
|
||||
proc copyDeepString(dr: var MemRegion; stack: var PointerStackChunk; src: NimString): NimString {.inline.} =
|
||||
result = rawNewStringNoInit(dr, src.len)
|
||||
result.len = src.len
|
||||
c_memcpy(result.data, src.data, src.len + 1)
|
||||
|
||||
proc genericDeepCopyAux(dr: var MemRegion; stack: var PointerStackChunk;
|
||||
dest, src: pointer, mt: PNimType) =
|
||||
var
|
||||
d = cast[ByteAddress](dest)
|
||||
s = cast[ByteAddress](src)
|
||||
sysAssert(mt != nil, "genericDeepCopyAux 2")
|
||||
case mt.kind
|
||||
of tyString:
|
||||
var x = cast[PPointer](dest)
|
||||
var s2 = cast[PPointer](s)[]
|
||||
if s2 == nil:
|
||||
x[] = nil
|
||||
proc push(r: var MemRegion; s: var PointerStackChunk; x: pointer) =
|
||||
if s.len < high(s.data):
|
||||
s.data[s.len] = x
|
||||
inc s.len
|
||||
else:
|
||||
x[] = copyDeepString(cast[NimString](s2))
|
||||
of tySequence:
|
||||
var s2 = cast[PPointer](src)[]
|
||||
var seq = cast[PGenericSeq](s2)
|
||||
var x = cast[PPointer](dest)
|
||||
if s2 == nil:
|
||||
x[] = nil
|
||||
return
|
||||
sysAssert(dest != nil, "genericDeepCopyAux 3")
|
||||
x[] = newSeq(mt, seq.len)
|
||||
var dst = cast[ByteAddress](cast[PPointer](dest)[])
|
||||
for i in 0..seq.len-1:
|
||||
genericDeepCopyAux(dr, stack,
|
||||
cast[pointer](dst +% i*% mt.base.size +% GenericSeqSize),
|
||||
cast[pointer](cast[ByteAddress](s2) +% i *% mt.base.size +%
|
||||
GenericSeqSize),
|
||||
mt.base)
|
||||
of tyObject:
|
||||
# we need to copy m_type field for tyObject, as it could be empty for
|
||||
# sequence reallocations:
|
||||
var pint = cast[ptr PNimType](dest)
|
||||
pint[] = cast[ptr PNimType](src)[]
|
||||
if mt.base != nil:
|
||||
genericDeepCopyAux(dr, stack, dest, src, mt.base)
|
||||
genericDeepCopyAux(dr, stack, dest, src, mt.node)
|
||||
of tyTuple:
|
||||
genericDeepCopyAux(dr, stack, dest, src, mt.node)
|
||||
of tyArray, tyArrayConstr:
|
||||
for i in 0..(mt.size div mt.base.size)-1:
|
||||
genericDeepCopyAux(dr, stack,
|
||||
cast[pointer](d +% i*% mt.base.size),
|
||||
cast[pointer](s +% i*% mt.base.size), mt.base)
|
||||
of tyRef:
|
||||
let s2 = cast[PPointer](src)[]
|
||||
if s2 == nil:
|
||||
cast[PPointer](dest)[] = nil
|
||||
else:
|
||||
# we modify the header of the cell temporarily; instead of the type
|
||||
# field we store a forwarding pointer. XXX This is bad when the cloning
|
||||
# fails due to OOM etc.
|
||||
let x = usrToCell(s2)
|
||||
let forw = cast[int](x.typ)
|
||||
if (forw and 1) == 1:
|
||||
# we stored a forwarding pointer, so let's use that:
|
||||
let z = cast[pointer](forw and not 1)
|
||||
unsureAsgnRef(cast[PPointer](dest), z)
|
||||
let fresh = cast[ptr PointerStackChunk](alloc(r, sizeof(PointerStackChunk)))
|
||||
fresh.len = 1
|
||||
fresh.data[0] = x
|
||||
fresh.next = nil
|
||||
fresh.prev = nil
|
||||
append(s, fresh)
|
||||
|
||||
|
||||
proc genericDeepCopyAux(dr: var MemRegion; stack: var PointerStackChunk;
|
||||
dest, src: pointer, mt: PNimType) {.benign.}
|
||||
proc genericDeepCopyAux(dr: var MemRegion; stack: var PointerStackChunk;
|
||||
dest, src: pointer, n: ptr TNimNode) {.benign.} =
|
||||
var
|
||||
d = cast[ByteAddress](dest)
|
||||
s = cast[ByteAddress](src)
|
||||
case n.kind
|
||||
of nkSlot:
|
||||
genericDeepCopyAux(cast[pointer](d +% n.offset),
|
||||
cast[pointer](s +% n.offset), n.typ)
|
||||
of nkList:
|
||||
for i in 0..n.len-1:
|
||||
genericDeepCopyAux(dest, src, n.sons[i])
|
||||
of nkCase:
|
||||
var dd = selectBranch(dest, n)
|
||||
var m = selectBranch(src, n)
|
||||
# reset if different branches are in use; note different branches also
|
||||
# imply that's not self-assignment (``x = x``)!
|
||||
if m != dd and dd != nil:
|
||||
genericResetAux(dest, dd)
|
||||
copyMem(cast[pointer](d +% n.offset), cast[pointer](s +% n.offset),
|
||||
n.typ.size)
|
||||
if m != nil:
|
||||
genericDeepCopyAux(dest, src, m)
|
||||
of nkNone: sysAssert(false, "genericDeepCopyAux")
|
||||
|
||||
proc copyDeepString(dr: var MemRegion; stack: var PointerStackChunk; src: NimString): NimString {.inline.} =
|
||||
result = rawNewStringNoInit(dr, src.len)
|
||||
result.len = src.len
|
||||
c_memcpy(result.data, src.data, src.len + 1)
|
||||
|
||||
proc genericDeepCopyAux(dr: var MemRegion; stack: var PointerStackChunk;
|
||||
dest, src: pointer, mt: PNimType) =
|
||||
var
|
||||
d = cast[ByteAddress](dest)
|
||||
s = cast[ByteAddress](src)
|
||||
sysAssert(mt != nil, "genericDeepCopyAux 2")
|
||||
case mt.kind
|
||||
of tyString:
|
||||
var x = cast[PPointer](dest)
|
||||
var s2 = cast[PPointer](s)[]
|
||||
if s2 == nil:
|
||||
x[] = nil
|
||||
else:
|
||||
let realType = x.typ
|
||||
let z = newObj(realType, realType.base.size)
|
||||
x[] = copyDeepString(cast[NimString](s2))
|
||||
of tySequence:
|
||||
var s2 = cast[PPointer](src)[]
|
||||
var seq = cast[PGenericSeq](s2)
|
||||
var x = cast[PPointer](dest)
|
||||
if s2 == nil:
|
||||
x[] = nil
|
||||
return
|
||||
sysAssert(dest != nil, "genericDeepCopyAux 3")
|
||||
x[] = newSeq(mt, seq.len)
|
||||
var dst = cast[ByteAddress](cast[PPointer](dest)[])
|
||||
for i in 0..seq.len-1:
|
||||
genericDeepCopyAux(dr, stack,
|
||||
cast[pointer](dst +% i*% mt.base.size +% GenericSeqSize),
|
||||
cast[pointer](cast[ByteAddress](s2) +% i *% mt.base.size +%
|
||||
GenericSeqSize),
|
||||
mt.base)
|
||||
of tyObject:
|
||||
# we need to copy m_type field for tyObject, as it could be empty for
|
||||
# sequence reallocations:
|
||||
var pint = cast[ptr PNimType](dest)
|
||||
pint[] = cast[ptr PNimType](src)[]
|
||||
if mt.base != nil:
|
||||
genericDeepCopyAux(dr, stack, dest, src, mt.base)
|
||||
genericDeepCopyAux(dr, stack, dest, src, mt.node)
|
||||
of tyTuple:
|
||||
genericDeepCopyAux(dr, stack, dest, src, mt.node)
|
||||
of tyArray, tyArrayConstr:
|
||||
for i in 0..(mt.size div mt.base.size)-1:
|
||||
genericDeepCopyAux(dr, stack,
|
||||
cast[pointer](d +% i*% mt.base.size),
|
||||
cast[pointer](s +% i*% mt.base.size), mt.base)
|
||||
of tyRef:
|
||||
let s2 = cast[PPointer](src)[]
|
||||
if s2 == nil:
|
||||
cast[PPointer](dest)[] = nil
|
||||
else:
|
||||
# we modify the header of the cell temporarily; instead of the type
|
||||
# field we store a forwarding pointer. XXX This is bad when the cloning
|
||||
# fails due to OOM etc.
|
||||
let x = usrToCell(s2)
|
||||
let forw = cast[int](x.typ)
|
||||
if (forw and 1) == 1:
|
||||
# we stored a forwarding pointer, so let's use that:
|
||||
let z = cast[pointer](forw and not 1)
|
||||
unsureAsgnRef(cast[PPointer](dest), z)
|
||||
else:
|
||||
let realType = x.typ
|
||||
let z = newObj(realType, realType.base.size)
|
||||
|
||||
unsureAsgnRef(cast[PPointer](dest), z)
|
||||
x.typ = cast[PNimType](cast[int](z) or 1)
|
||||
genericDeepCopyAux(dr, stack, z, s2, realType.base)
|
||||
x.typ = realType
|
||||
else:
|
||||
copyMem(dest, src, mt.size)
|
||||
|
||||
proc joinAliveDataFromRegion*(dest: var MemRegion; src: var MemRegion;
|
||||
root: pointer): pointer =
|
||||
# we mark the alive data and copy only alive data over to 'dest'.
|
||||
# This is O(liveset) but it nicely compacts memory, so it's fine.
|
||||
# We use the 'typ' field as a forwarding pointer. The forwarding
|
||||
# pointers have bit 0 set, so we can disambiguate them.
|
||||
# We allocate a temporary stack in 'src' that we later free:
|
||||
var s: PointerStackChunk
|
||||
s.len = 1
|
||||
s.data[0] = root
|
||||
while s.len > 0:
|
||||
var p: pointer
|
||||
if s.tail == nil:
|
||||
p = s.data[s.len-1]
|
||||
dec s.len
|
||||
unsureAsgnRef(cast[PPointer](dest), z)
|
||||
x.typ = cast[PNimType](cast[int](z) or 1)
|
||||
genericDeepCopyAux(dr, stack, z, s2, realType.base)
|
||||
x.typ = realType
|
||||
else:
|
||||
p = s.tail.data[s.tail.len-1]
|
||||
dec s.tail.len
|
||||
if s.tail.len == 0:
|
||||
unlink(s, s.tail)
|
||||
copyMem(dest, src, mt.size)
|
||||
|
||||
proc joinAliveDataFromRegion*(dest: var MemRegion; src: var MemRegion;
|
||||
root: pointer): pointer =
|
||||
# we mark the alive data and copy only alive data over to 'dest'.
|
||||
# This is O(liveset) but it nicely compacts memory, so it's fine.
|
||||
# We use the 'typ' field as a forwarding pointer. The forwarding
|
||||
# pointers have bit 0 set, so we can disambiguate them.
|
||||
# We allocate a temporary stack in 'src' that we later free:
|
||||
var s: PointerStackChunk
|
||||
s.len = 1
|
||||
s.data[0] = root
|
||||
while s.len > 0:
|
||||
var p: pointer
|
||||
if s.tail == nil:
|
||||
p = s.data[s.len-1]
|
||||
dec s.len
|
||||
else:
|
||||
p = s.tail.data[s.tail.len-1]
|
||||
dec s.tail.len
|
||||
if s.tail.len == 0:
|
||||
unlink(s, s.tail)
|
||||
|
||||
proc rawNewObj(r: var MemRegion, typ: PNimType, size: int): pointer =
|
||||
var res = cast[ptr ObjHeader](alloc(r, size + sizeof(ObjHeader)))
|
||||
res.typ = typ
|
||||
if typ.finalizer != nil:
|
||||
res.nextFinal = r.chunk.head
|
||||
r.chunk.head = res
|
||||
res.nextFinal = r.head.head
|
||||
r.head.head = res
|
||||
result = res +! sizeof(ObjHeader)
|
||||
|
||||
proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||
result = rawNewObj(typ, size, region)
|
||||
result = rawNewObj(tlRegion, typ, size)
|
||||
zeroMem(result, size)
|
||||
when defined(memProfiler): nimProfile(size)
|
||||
|
||||
proc newObjNoInit(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||
result = rawNewObj(typ, size, region)
|
||||
result = rawNewObj(tlRegion, typ, size)
|
||||
when defined(memProfiler): nimProfile(size)
|
||||
|
||||
proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} =
|
||||
@@ -351,7 +368,7 @@ proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} =
|
||||
cast[PGenericSeq](result).reserved = len
|
||||
|
||||
proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||
result = rawNewObj(typ, size, gch)
|
||||
result = rawNewObj(tlRegion, typ, size)
|
||||
zeroMem(result, size)
|
||||
|
||||
proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
|
||||
@@ -360,23 +377,63 @@ proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
|
||||
cast[PGenericSeq](result).len = len
|
||||
cast[PGenericSeq](result).reserved = len
|
||||
|
||||
proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer =
|
||||
collectCT(gch)
|
||||
var ol = usrToCell(old)
|
||||
sysAssert(ol.typ != nil, "growObj: 1")
|
||||
gcAssert(ol.typ.kind in {tyString, tySequence}, "growObj: 2")
|
||||
|
||||
var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(Cell)))
|
||||
var elemSize = 1
|
||||
if ol.typ.kind != tyString: elemSize = ol.typ.base.size
|
||||
|
||||
var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
|
||||
copyMem(res, ol, oldsize + sizeof(Cell))
|
||||
zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(Cell)),
|
||||
newsize-oldsize)
|
||||
sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3")
|
||||
result = cellToUsr(res)
|
||||
proc growObj(region: var MemRegion; old: pointer, newsize: int): pointer =
|
||||
let typ = cast[ptr ObjHeader](old -! sizeof(ObjHeader)).typ
|
||||
result = rawNewObj(region, typ, newsize)
|
||||
let elemSize = if typ.kind == tyString: 1 else: typ.base.size
|
||||
let oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
|
||||
copyMem(result, old, oldsize)
|
||||
zeroMem(result +! oldsize, newsize-oldsize)
|
||||
|
||||
proc growObj(old: pointer, newsize: int): pointer {.rtl.} =
|
||||
result = growObj(old, newsize, region)
|
||||
result = growObj(tlRegion, old, newsize)
|
||||
|
||||
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
|
||||
|
||||
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 = 0
|
||||
proc getTotalSharedMem(): int = 0
|
||||
proc getOccupiedSharedMem(): int = 0
|
||||
|
||||
proc GC_disable() = discard
|
||||
proc GC_enable() = discard
|
||||
proc GC_fullCollect() = discard
|
||||
proc GC_setStrategy(strategy: GC_Strategy) = discard
|
||||
proc GC_enableMarkAndSweep() = discard
|
||||
proc GC_disableMarkAndSweep() = discard
|
||||
proc GC_getStatistics(): string = return ""
|
||||
|
||||
proc getOccupiedMem(): int =
|
||||
result = tlRegion.totalSize - tlRegion.remaining
|
||||
proc getFreeMem(): int = tlRegion.remaining
|
||||
proc getTotalMem(): int =
|
||||
result = tlRegion.totalSize
|
||||
|
||||
proc setStackBottom(theStackBottom: pointer) = discard
|
||||
|
||||
@@ -97,6 +97,8 @@ proc rawWriteStackTrace(): string =
|
||||
else:
|
||||
result = "No stack traceback available\n"
|
||||
|
||||
proc getStackTrace*(): string = rawWriteStackTrace()
|
||||
|
||||
proc unhandledException(e: ref Exception) {.
|
||||
compilerproc, asmNoStackFrame.} =
|
||||
when NimStackTrace:
|
||||
|
||||
@@ -389,15 +389,30 @@ elif defined(nogc) and defined(useMalloc):
|
||||
|
||||
when not defined(useNimRtl):
|
||||
proc alloc(size: Natural): pointer =
|
||||
result = cmalloc(size)
|
||||
if result == nil: raiseOutOfMem()
|
||||
var x = cmalloc(size + sizeof(size))
|
||||
if x == nil: raiseOutOfMem()
|
||||
|
||||
cast[ptr int](x)[] = size
|
||||
result = cast[pointer](cast[int](x) + sizeof(size))
|
||||
|
||||
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)
|
||||
var x = cast[pointer](cast[int](p) - sizeof(newsize))
|
||||
let oldsize = cast[ptr int](x)[]
|
||||
|
||||
x = crealloc(x, newsize + sizeof(newsize))
|
||||
|
||||
if x == nil: raiseOutOfMem()
|
||||
|
||||
cast[ptr int](x)[] = newsize
|
||||
result = cast[pointer](cast[int](x) + sizeof(newsize))
|
||||
|
||||
if newsize > oldsize:
|
||||
zeroMem(cast[pointer](cast[int](result) + oldsize), newsize - oldsize)
|
||||
|
||||
proc dealloc(p: pointer) = cfree(cast[pointer](cast[int](p) - sizeof(int)))
|
||||
|
||||
proc allocShared(size: Natural): pointer =
|
||||
result = cmalloc(size)
|
||||
@@ -511,11 +526,12 @@ elif defined(nogc):
|
||||
include "system/cellsets"
|
||||
|
||||
else:
|
||||
include "system/alloc"
|
||||
when not defined(gcStack):
|
||||
include "system/alloc"
|
||||
|
||||
include "system/cellsets"
|
||||
when not leakDetector and not useCellIds:
|
||||
sysAssert(sizeof(Cell) == sizeof(FreeCell), "sizeof FreeCell")
|
||||
include "system/cellsets"
|
||||
when not leakDetector and not useCellIds:
|
||||
sysAssert(sizeof(Cell) == sizeof(FreeCell), "sizeof FreeCell")
|
||||
when compileOption("gc", "v2"):
|
||||
include "system/gc2"
|
||||
elif defined(gcStack):
|
||||
|
||||
@@ -121,3 +121,5 @@ else:
|
||||
importc: "pthread_cond_signal", header: "<pthread.h>", noSideEffect.}
|
||||
proc deinitSysCond(cond: var SysCond) {.noSideEffect,
|
||||
importc: "pthread_cond_destroy", header: "<pthread.h>".}
|
||||
|
||||
{.pop.}
|
||||
|
||||
@@ -228,7 +228,8 @@ 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) and not defined(gogc):
|
||||
not defined(gcMarkAndSweep) and not defined(gogc) and
|
||||
not defined(gcStack):
|
||||
when false: # compileOption("gc", "v2"):
|
||||
for i in newLen..result.len-1:
|
||||
let len0 = gch.tempStack.len
|
||||
|
||||
@@ -36,6 +36,8 @@ type
|
||||
DWORD* = int32
|
||||
PDWORD* = ptr DWORD
|
||||
LPINT* = ptr int32
|
||||
ULONG_PTR* = uint
|
||||
PULONG_PTR* = ptr uint
|
||||
HDC* = Handle
|
||||
HGLRC* = Handle
|
||||
|
||||
@@ -759,17 +761,17 @@ const
|
||||
ERROR_NETNAME_DELETED* = 64
|
||||
|
||||
proc createIoCompletionPort*(FileHandle: Handle, ExistingCompletionPort: Handle,
|
||||
CompletionKey: DWORD,
|
||||
CompletionKey: ULONG_PTR,
|
||||
NumberOfConcurrentThreads: DWORD): Handle{.stdcall,
|
||||
dynlib: "kernel32", importc: "CreateIoCompletionPort".}
|
||||
|
||||
proc getQueuedCompletionStatus*(CompletionPort: Handle,
|
||||
lpNumberOfBytesTransferred: PDWORD, lpCompletionKey: PULONG,
|
||||
lpNumberOfBytesTransferred: PDWORD, lpCompletionKey: PULONG_PTR,
|
||||
lpOverlapped: ptr POVERLAPPED,
|
||||
dwMilliseconds: DWORD): WINBOOL{.stdcall,
|
||||
dynlib: "kernel32", importc: "GetQueuedCompletionStatus".}
|
||||
|
||||
proc getOverlappedResult*(hFile: Handle, lpOverlapped: OVERLAPPED,
|
||||
proc getOverlappedResult*(hFile: Handle, lpOverlapped: POVERLAPPED,
|
||||
lpNumberOfBytesTransferred: var DWORD, bWait: WINBOOL): WINBOOL{.
|
||||
stdcall, dynlib: "kernel32", importc: "GetOverlappedResult".}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user