made large parts of the stdlib gcsafe

This commit is contained in:
Araq
2014-04-20 20:01:24 +02:00
parent be6474af63
commit e6d17e6273
21 changed files with 138 additions and 113 deletions

View File

@@ -118,7 +118,7 @@ type
warnNilStatement, warnAnalysisLoophole,
warnDifferentHeaps, warnWriteToForeignHeap, warnImplicitClosure,
warnEachIdentIsTuple, warnShadowIdent,
warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe,
warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,
warnUninit, warnGcMem, warnUser,
hintSuccess, hintSuccessX,
hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,
@@ -387,6 +387,7 @@ const
warnProveField: "cannot prove that field '$1' is accessible [ProveField]",
warnProveIndex: "cannot prove index '$1' is valid [ProveIndex]",
warnGcUnsafe: "not GC-safe: '$1' [GcUnsafe]",
warnGcUnsafe2: "cannot prove '$1' is GC-safe. This will become a compile time error in the future.",
warnUninit: "'$1' might not have been initialized [Uninit]",
warnGcMem: "'$1' uses GC'ed memory [GcMem]",
warnUser: "$1 [User]",
@@ -408,7 +409,7 @@ const
hintUser: "$1 [User]"]
const
WarningsToStr*: array[0..25, string] = ["CannotOpenFile", "OctalEscape",
WarningsToStr*: array[0..26, string] = ["CannotOpenFile", "OctalEscape",
"XIsNeverRead", "XmightNotBeenInit",
"Deprecated", "ConfigDeprecated",
"SmallLshouldNotBeUsed", "UnknownMagic",
@@ -416,7 +417,7 @@ const
"CommentXIgnored", "NilStmt",
"AnalysisLoophole", "DifferentHeaps", "WriteToForeignHeap",
"ImplicitClosure", "EachIdentIsTuple", "ShadowIdent",
"ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "Uninit",
"ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit",
"GcMem", "User"]
HintsToStr*: array[0..15, string] = ["Success", "SuccessX", "LineTooLong",

View File

@@ -53,7 +53,7 @@ const
wPure, wHeader, wCompilerproc, wFinal, wSize, wExtern, wShallow,
wImportCpp, wImportObjC, wError, wIncompleteStruct, wByCopy, wByRef,
wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked,
wBorrow}
wBorrow, wGcSafe}
fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern,
wImportCpp, wImportObjC, wError}
varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
@@ -690,7 +690,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
if sym.typ != nil: incl(sym.typ.flags, tfThread)
of wGcSafe:
noVal(it)
incl(sym.flags, sfThread)
if sym.kind != skType: incl(sym.flags, sfThread)
if sym.typ != nil: incl(sym.typ.flags, tfGcSafe)
else: invalidPragma(it)
of wPacked:

View File

@@ -113,7 +113,8 @@ proc useVar(a: PEffects, n: PNode) =
if {sfGlobal, sfThread} * s.flags == {sfGlobal} and s.kind == skVar:
when trackGlobals:
a.addUse(copyNode(n))
if tfHasGCedMem in s.typ.flags or s.typ.isGCedMem:
if (tfHasGCedMem in s.typ.flags or s.typ.isGCedMem) and
tfGcSafe notin s.typ.flags:
message(n.info, warnGcUnsafe, renderTree(n))
a.gcUnsafe = true
@@ -517,6 +518,7 @@ proc track(tracked: PEffects, n: PNode) =
addEffect(tracked, createRaise(n))
addTag(tracked, createTag(n))
when trackGlobals: addUse(tracked, createAnyGlobal(n))
# XXX handle 'gcsafe' properly for callbacks!
else:
mergeEffects(tracked, effectList.sons[exceptionEffects], n)
mergeTags(tracked, effectList.sons[tagEffects], n)
@@ -704,7 +706,8 @@ proc trackProc*(s: PSym, body: PNode) =
"uses an unlisted global variable: ", hints=on, symbolPredicate)
effects.sons[usesEffects] = usesSpec
if sfThread in s.flags and t.gcUnsafe:
localError(s.info, "'$1' is not GC-safe" % s.name.s)
localError(s.info, warnGcUnsafe2, s.name.s)
#localError(s.info, "'$1' is not GC-safe" % s.name.s)
if not t.gcUnsafe: s.typ.flags.incl tfGcSafe
proc trackTopLevelStmt*(module: PSym; n: PNode) =

View File

@@ -7,6 +7,7 @@
# distribution, for details about the copyright.
#
include "system/inclrtl"
## This module contains the interface to the compiler's abstract syntax
## tree (`AST`:idx:). Macros operate on this tree.
@@ -109,19 +110,20 @@ const
nnkCallKinds* = {nnkCall, nnkInfix, nnkPrefix, nnkPostfix, nnkCommand,
nnkCallStrLit}
proc `[]`*(n: PNimrodNode, i: int): PNimrodNode {.magic: "NChild".}
proc `[]`*(n: PNimrodNode, i: int): PNimrodNode {.magic: "NChild", noSideEffect.}
## get `n`'s `i`'th child.
proc `[]=`*(n: PNimrodNode, i: int, child: PNimrodNode) {.magic: "NSetChild".}
proc `[]=`*(n: PNimrodNode, i: int, child: PNimrodNode) {.magic: "NSetChild",
noSideEffect.}
## set `n`'s `i`'th child to `child`.
proc `!`*(s: string): TNimrodIdent {.magic: "StrToIdent".}
proc `!`*(s: string): TNimrodIdent {.magic: "StrToIdent", noSideEffect.}
## constructs an identifier from the string `s`
proc `$`*(i: TNimrodIdent): string {.magic: "IdentToStr".}
proc `$`*(i: TNimrodIdent): string {.magic: "IdentToStr", noSideEffect.}
## converts a Nimrod identifier to a string
proc `$`*(s: PNimrodSymbol): string {.magic: "IdentToStr".}
proc `$`*(s: PNimrodSymbol): string {.magic: "IdentToStr", noSideEffect.}
## converts a Nimrod symbol to a string
proc `==`*(a, b: TNimrodIdent): bool {.magic: "EqIdent", noSideEffect.}
@@ -130,35 +132,36 @@ proc `==`*(a, b: TNimrodIdent): bool {.magic: "EqIdent", noSideEffect.}
proc `==`*(a, b: PNimrodNode): bool {.magic: "EqNimrodNode", noSideEffect.}
## compares two Nimrod nodes
proc len*(n: PNimrodNode): int {.magic: "NLen".}
proc len*(n: PNimrodNode): int {.magic: "NLen", noSideEffect.}
## returns the number of children of `n`.
proc add*(father, child: PNimrodNode): PNimrodNode {.magic: "NAdd", discardable.}
proc add*(father, child: PNimrodNode): PNimrodNode {.magic: "NAdd", discardable,
noSideEffect.}
## Adds the `child` to the `father` node. Returns the
## father node so that calls can be nested.
proc add*(father: PNimrodNode, children: varargs[PNimrodNode]): PNimrodNode {.
magic: "NAddMultiple", discardable.}
magic: "NAddMultiple", discardable, noSideEffect.}
## Adds each child of `children` to the `father` node.
## Returns the `father` node so that calls can be nested.
proc del*(father: PNimrodNode, idx = 0, n = 1) {.magic: "NDel".}
proc del*(father: PNimrodNode, idx = 0, n = 1) {.magic: "NDel", noSideEffect.}
## deletes `n` children of `father` starting at index `idx`.
proc kind*(n: PNimrodNode): TNimrodNodeKind {.magic: "NKind".}
proc kind*(n: PNimrodNode): TNimrodNodeKind {.magic: "NKind", noSideEffect.}
## returns the `kind` of the node `n`.
proc intVal*(n: PNimrodNode): BiggestInt {.magic: "NIntVal".}
proc floatVal*(n: PNimrodNode): BiggestFloat {.magic: "NFloatVal".}
proc symbol*(n: PNimrodNode): PNimrodSymbol {.magic: "NSymbol".}
proc ident*(n: PNimrodNode): TNimrodIdent {.magic: "NIdent".}
proc typ*(n: PNimrodNode): typedesc {.magic: "NGetType".}
proc strVal*(n: PNimrodNode): string {.magic: "NStrVal".}
proc intVal*(n: PNimrodNode): BiggestInt {.magic: "NIntVal", noSideEffect.}
proc floatVal*(n: PNimrodNode): BiggestFloat {.magic: "NFloatVal", noSideEffect.}
proc symbol*(n: PNimrodNode): PNimrodSymbol {.magic: "NSymbol", noSideEffect.}
proc ident*(n: PNimrodNode): TNimrodIdent {.magic: "NIdent", noSideEffect.}
proc typ*(n: PNimrodNode): typedesc {.magic: "NGetType", noSideEffect.}
proc strVal*(n: PNimrodNode): string {.magic: "NStrVal", noSideEffect.}
proc `intVal=`*(n: PNimrodNode, val: BiggestInt) {.magic: "NSetIntVal".}
proc `floatVal=`*(n: PNimrodNode, val: BiggestFloat) {.magic: "NSetFloatVal".}
proc `symbol=`*(n: PNimrodNode, val: PNimrodSymbol) {.magic: "NSetSymbol".}
proc `ident=`*(n: PNimrodNode, val: TNimrodIdent) {.magic: "NSetIdent".}
proc `intVal=`*(n: PNimrodNode, val: BiggestInt) {.magic: "NSetIntVal", noSideEffect.}
proc `floatVal=`*(n: PNimrodNode, val: BiggestFloat) {.magic: "NSetFloatVal", noSideEffect.}
proc `symbol=`*(n: PNimrodNode, val: PNimrodSymbol) {.magic: "NSetSymbol", noSideEffect.}
proc `ident=`*(n: PNimrodNode, val: TNimrodIdent) {.magic: "NSetIdent", noSideEffect.}
#proc `typ=`*(n: PNimrodNode, typ: typedesc) {.magic: "NSetType".}
# this is not sound! Unfortunately forbidding 'typ=' is not enough, as you
# can easily do:
@@ -166,24 +169,24 @@ proc `ident=`*(n: PNimrodNode, val: TNimrodIdent) {.magic: "NSetIdent".}
# let fake = semCheck(2.0)
# bracket[0] = fake # constructs a mixed array with ints and floats!
proc `strVal=`*(n: PNimrodNode, val: string) {.magic: "NSetStrVal".}
proc `strVal=`*(n: PNimrodNode, val: string) {.magic: "NSetStrVal", noSideEffect.}
proc newNimNode*(kind: TNimrodNodeKind,
n: PNimrodNode=nil): PNimrodNode {.magic: "NNewNimNode".}
n: PNimrodNode=nil): PNimrodNode {.magic: "NNewNimNode", noSideEffect.}
proc copyNimNode*(n: PNimrodNode): PNimrodNode {.magic: "NCopyNimNode".}
proc copyNimTree*(n: PNimrodNode): PNimrodNode {.magic: "NCopyNimTree".}
proc copyNimNode*(n: PNimrodNode): PNimrodNode {.magic: "NCopyNimNode", noSideEffect.}
proc copyNimTree*(n: PNimrodNode): PNimrodNode {.magic: "NCopyNimTree", noSideEffect.}
proc error*(msg: string) {.magic: "NError".}
proc error*(msg: string) {.magic: "NError", gcsafe.}
## writes an error message at compile time
proc warning*(msg: string) {.magic: "NWarning".}
proc warning*(msg: string) {.magic: "NWarning", gcsafe.}
## writes a warning message at compile time
proc hint*(msg: string) {.magic: "NHint".}
proc hint*(msg: string) {.magic: "NHint", gcsafe.}
## writes a hint message at compile time
proc newStrLitNode*(s: string): PNimrodNode {.compileTime.} =
proc newStrLitNode*(s: string): PNimrodNode {.compileTime, noSideEffect.} =
## creates a string literal node from `s`
result = newNimNode(nnkStrLit)
result.strVal = s
@@ -219,7 +222,7 @@ type
## any other means in the language currently)
proc bindSym*(ident: string, rule: TBindSymRule = brClosed): PNimrodNode {.
magic: "NBindSym".}
magic: "NBindSym", noSideEffect.}
## creates a node that binds `ident` to a symbol node. The bound symbol
## may be an overloaded symbol.
## If ``rule == brClosed`` either an ``nkClosedSymChoice`` tree is
@@ -230,11 +233,11 @@ proc bindSym*(ident: string, rule: TBindSymRule = brClosed): PNimrodNode {.
## returned even if the symbol is not ambiguous.
proc genSym*(kind: TNimrodSymKind = nskLet; ident = ""): PNimrodNode {.
magic: "NGenSym".}
magic: "NGenSym", noSideEffect.}
## generates a fresh symbol that is guaranteed to be unique. The symbol
## needs to occur in a declaration context.
proc callsite*(): PNimrodNode {.magic: "NCallSite".}
proc callsite*(): PNimrodNode {.magic: "NCallSite", gcsafe.}
## returns the AST if the invokation expression that invoked this macro.
proc toStrLit*(n: PNimrodNode): PNimrodNode {.compileTime.} =
@@ -242,19 +245,19 @@ proc toStrLit*(n: PNimrodNode): PNimrodNode {.compileTime.} =
## in a string literal node
return newStrLitNode(repr(n))
proc lineinfo*(n: PNimrodNode): string {.magic: "NLineInfo".}
proc lineinfo*(n: PNimrodNode): string {.magic: "NLineInfo", noSideEffect.}
## returns the position the node appears in the original source file
## in the form filename(line, col)
proc parseExpr*(s: string): PNimrodNode {.magic: "ParseExprToAst".}
proc parseExpr*(s: string): PNimrodNode {.magic: "ParseExprToAst", noSideEffect.}
## Compiles the passed string to its AST representation.
## Expects a single expression.
proc parseStmt*(s: string): PNimrodNode {.magic: "ParseStmtToAst".}
proc parseStmt*(s: string): PNimrodNode {.magic: "ParseStmtToAst", noSideEffect.}
## Compiles the passed string to its AST representation.
## Expects one or more statements.
proc getAst*(macroOrTemplate: expr): PNimrodNode {.magic: "ExpandToAst".}
proc getAst*(macroOrTemplate: expr): PNimrodNode {.magic: "ExpandToAst", noSideEffect.}
## Obtains the AST nodes returned from a macro or template invocation.
## Example:
##
@@ -263,7 +266,7 @@ proc getAst*(macroOrTemplate: expr): PNimrodNode {.magic: "ExpandToAst".}
## macro FooMacro() =
## var ast = getAst(BarTemplate())
proc quote*(bl: stmt, op = "``"): PNimrodNode {.magic: "QuoteAst".}
proc quote*(bl: stmt, op = "``"): PNimrodNode {.magic: "QuoteAst", noSideEffect.}
## Quasi-quoting operator.
## Accepts an expression or a block and returns the AST that represents it.
## Within the quoted AST, you are able to interpolate PNimrodNode expressions

View File

@@ -7,6 +7,8 @@
# distribution, for details about the copyright.
#
include "system/inclrtl"
import os, oids, tables, strutils, macros
import rawsockets
@@ -31,7 +33,7 @@ export TPort
type
PFutureBase* = ref object of PObject
cb: proc () {.closure.}
cb: proc () {.closure,gcsafe.}
finished: bool
PFuture*[T] = ref object of PFutureBase
@@ -68,7 +70,7 @@ proc fail*[T](future: PFuture[T], error: ref EBase) =
if future.cb != nil:
future.cb()
proc `callback=`*(future: PFutureBase, cb: proc () {.closure.}) =
proc `callback=`*(future: PFutureBase, cb: proc () {.closure,gcsafe.}) =
## Sets the callback proc to be called when the future completes.
##
## If future has already completed then ``cb`` will be called immediately.
@@ -80,7 +82,7 @@ proc `callback=`*(future: PFutureBase, cb: proc () {.closure.}) =
future.cb()
proc `callback=`*[T](future: PFuture[T],
cb: proc (future: PFuture[T]) {.closure.}) =
cb: proc (future: PFuture[T]) {.closure,gcsafe.}) =
## Sets the callback proc to be called when the future completes.
##
## If future has already completed then ``cb`` will be called immediately.
@@ -122,7 +124,7 @@ when defined(windows) or defined(nimdoc):
TCompletionData* = object
sock: TAsyncFD
cb: proc (sock: TAsyncFD, bytesTransferred: DWORD,
errcode: TOSErrorCode) {.closure.}
errcode: TOSErrorCode) {.closure,gcsafe.}
PDispatcher* = ref object
ioPort: THandle
@@ -237,7 +239,7 @@ when defined(windows) or defined(nimdoc):
let func =
cast[proc (s: TSocketHandle, name: ptr TSockAddr, namelen: cint,
lpSendBuffer: pointer, dwSendDataLength: dword,
lpdwBytesSent: PDWORD, lpOverlapped: POverlapped): bool {.stdcall.}](connectExPtr)
lpdwBytesSent: PDWORD, lpOverlapped: POverlapped): bool {.stdcall,gcsafe.}](connectExPtr)
result = func(s, name, namelen, lpSendBuffer, dwSendDataLength, lpdwBytesSent,
lpOverlapped)
@@ -251,7 +253,7 @@ when defined(windows) or defined(nimdoc):
cast[proc (listenSock, acceptSock: TSocketHandle, lpOutputBuffer: pointer,
dwReceiveDataLength, dwLocalAddressLength,
dwRemoteAddressLength: DWORD, lpdwBytesReceived: PDWORD,
lpOverlapped: POverlapped): bool {.stdcall.}](acceptExPtr)
lpOverlapped: POverlapped): bool {.stdcall,gcsafe.}](acceptExPtr)
result = func(listenSock, acceptSock, lpOutputBuffer, dwReceiveDataLength,
dwLocalAddressLength, dwRemoteAddressLength, lpdwBytesReceived,
lpOverlapped)
@@ -268,7 +270,7 @@ when defined(windows) or defined(nimdoc):
dwReceiveDataLength, dwLocalAddressLength,
dwRemoteAddressLength: DWORD, LocalSockaddr: ptr ptr TSockAddr,
LocalSockaddrLength: lpint, RemoteSockaddr: ptr ptr TSockAddr,
RemoteSockaddrLength: lpint) {.stdcall.}](getAcceptExSockAddrsPtr)
RemoteSockaddrLength: lpint) {.stdcall,gcsafe.}](getAcceptExSockAddrsPtr)
func(lpOutputBuffer, dwReceiveDataLength, dwLocalAddressLength,
dwRemoteAddressLength, LocalSockaddr, LocalSockaddrLength,
@@ -537,7 +539,7 @@ else:
from posix import EINTR, EAGAIN, EINPROGRESS, EWOULDBLOCK, MSG_PEEK
type
TAsyncFD* = distinct cint
TCallback = proc (sock: TAsyncFD): bool {.closure.}
TCallback = proc (sock: TAsyncFD): bool {.closure,gcsafe.}
PData* = ref object of PObject
sock: TAsyncFD
@@ -757,7 +759,7 @@ proc accept*(socket: TAsyncFD): PFuture[TAsyncFD] =
template createCb*(retFutureSym, iteratorNameSym: expr): stmt {.immediate.} =
var nameIterVar = iteratorNameSym
proc cb {.closure.} =
proc cb {.closure,gcsafe.} =
if not nameIterVar.finished:
var next = nameIterVar()
if next == nil:

View File

@@ -6,6 +6,8 @@
# distribution, for details about the copyright.
#
include "system/inclrtl"
import sockets, os
## This module implements an asynchronous event loop together with asynchronous sockets
@@ -98,13 +100,13 @@ type
fd*: TSocketHandle
deleVal*: PObject
handleRead*: proc (h: PObject) {.nimcall.}
handleWrite*: proc (h: PObject) {.nimcall.}
handleError*: proc (h: PObject) {.nimcall.}
hasDataBuffered*: proc (h: PObject): bool {.nimcall.}
handleRead*: proc (h: PObject) {.nimcall, gcsafe.}
handleWrite*: proc (h: PObject) {.nimcall, gcsafe.}
handleError*: proc (h: PObject) {.nimcall, gcsafe.}
hasDataBuffered*: proc (h: PObject): bool {.nimcall, gcsafe.}
open*: bool
task*: proc (h: PObject) {.nimcall.}
task*: proc (h: PObject) {.nimcall, gcsafe.}
mode*: TFileMode
PDelegate* = ref TDelegate
@@ -118,13 +120,13 @@ type
socket: TSocket
info: TInfo
handleRead*: proc (s: PAsyncSocket) {.closure.}
handleWrite: proc (s: PAsyncSocket) {.closure.}
handleConnect*: proc (s: PAsyncSocket) {.closure.}
handleRead*: proc (s: PAsyncSocket) {.closure, gcsafe.}
handleWrite: proc (s: PAsyncSocket) {.closure, gcsafe.}
handleConnect*: proc (s: PAsyncSocket) {.closure, gcsafe.}
handleAccept*: proc (s: PAsyncSocket) {.closure.}
handleAccept*: proc (s: PAsyncSocket) {.closure, gcsafe.}
handleTask*: proc (s: PAsyncSocket) {.closure.}
handleTask*: proc (s: PAsyncSocket) {.closure, gcsafe.}
lineBuffer: TaintedString ## Temporary storage for ``readLine``
sendBuffer: string ## Temporary storage for ``send``
@@ -213,7 +215,7 @@ proc asyncSockHandleRead(h: PObject) =
else:
PAsyncSocket(h).handleAccept(PAsyncSocket(h))
proc close*(sock: PAsyncSocket)
proc close*(sock: PAsyncSocket) {.gcsafe.}
proc asyncSockHandleWrite(h: PObject) =
when defined(ssl):
if PAsyncSocket(h).socket.isSSL and not
@@ -254,7 +256,7 @@ proc asyncSockHandleWrite(h: PObject) =
PAsyncSocket(h).deleg.mode = fmRead
when defined(ssl):
proc asyncSockDoHandshake(h: PObject) =
proc asyncSockDoHandshake(h: PObject) {.gcsafe.} =
if PAsyncSocket(h).socket.isSSL and not
PAsyncSocket(h).socket.gotHandshake:
if PAsyncSocket(h).sslNeedAccept:
@@ -437,7 +439,7 @@ proc isSendDataBuffered*(s: PAsyncSocket): bool =
return s.sendBuffer.len != 0
proc setHandleWrite*(s: PAsyncSocket,
handleWrite: proc (s: PAsyncSocket) {.closure.}) =
handleWrite: proc (s: PAsyncSocket) {.closure, gcsafe.}) =
## Setter for the ``handleWrite`` event.
##
## To remove this event you should use the ``delHandleWrite`` function.

View File

@@ -377,7 +377,7 @@ proc setCookie*(name, value: string) =
write(stdout, "Set-Cookie: ", name, "=", value, "\n")
var
gcookies: PStringTable = nil
gcookies {.threadvar.}: PStringTable
proc getCookie*(name: string): TaintedString =
## Gets a cookie. If no cookie of `name` exists, "" is returned.

View File

@@ -6,6 +6,8 @@
# distribution, for details about the copyright.
#
include "system/inclrtl"
import sockets, strutils, parseutils, times, os, asyncio
## This module **partially** implements an FTP client as specified
@@ -41,7 +43,7 @@ type
dummyA, dummyB: pointer # workaround a Nimrod API issue
asyncCSock: PAsyncSocket
asyncDSock: PAsyncSocket
handleEvent*: proc (ftp: PAsyncFTPClient, ev: TFTPEvent) {.closure.}
handleEvent*: proc (ftp: PAsyncFTPClient, ev: TFTPEvent){.closure,gcsafe.}
disp: PDispatcher
asyncDSockID: PDelegate
user, pass: string
@@ -59,7 +61,7 @@ type
JRetrText, JRetr, JStore
TFTPJob = object
prc: proc (ftp: PFTPClient, async: bool): bool {.nimcall.}
prc: proc (ftp: PFTPClient, async: bool): bool {.nimcall, gcsafe.}
case typ*: FTPJobType
of JRetrText:
lines: string
@@ -148,7 +150,8 @@ proc assertReply(received: TaintedString, expected: varargs[string]) =
[expected.join("' or '"), received.string])
proc createJob(ftp: PFTPClient,
prc: proc (ftp: PFTPClient, async: bool): bool {.nimcall.},
prc: proc (ftp: PFTPClient, async: bool): bool {.
nimcall,gcsafe.},
cmd: FTPJobType) =
if ftp.jobInProgress:
raise newException(EFTP, "Unable to do two jobs at once.")
@@ -558,7 +561,7 @@ proc csockHandleRead(s: PAsyncSocket, ftp: PAsyncFTPClient) =
proc asyncFTPClient*(address: string, port = TPort(21),
user, pass = "",
handleEvent: proc (ftp: PAsyncFTPClient, ev: TFTPEvent) {.closure.} =
handleEvent: proc (ftp: PAsyncFTPClient, ev: TFTPEvent) {.closure,gcsafe.} =
(proc (ftp: PAsyncFTPClient, ev: TFTPEvent) = discard)): PAsyncFTPClient =
## Create a ``PAsyncFTPClient`` object.
##

View File

@@ -477,7 +477,7 @@ proc nextAsync(s: PAsyncHTTPServer) =
s.path = data.substr(i, last-1)
proc asyncHTTPServer*(handleRequest: proc (server: PAsyncHTTPServer, client: TSocket,
path, query: string): bool {.closure.},
path, query: string): bool {.closure, gcsafe.},
port = TPort(80), address = "",
reuseAddr = false): PAsyncHTTPServer =
## Creates an Asynchronous HTTP server at ``port``.

View File

@@ -32,6 +32,8 @@
## **Warning:** The API of this module is unstable, and therefore is subject
## to change.
include "system/inclrtl"
import sockets, strutils, parseutils, times, asyncio, os
type
@@ -41,7 +43,7 @@ type
nick, user, realname, serverPass: string
case isAsync: bool
of true:
handleEvent: proc (irc: PAsyncIRC, ev: TIRCEvent) {.closure.}
handleEvent: proc (irc: PAsyncIRC, ev: TIRCEvent) {.closure, gcsafe.}
asyncSock: PAsyncSocket
myDispatcher: PDispatcher
of false:
@@ -445,7 +447,7 @@ proc asyncIRC*(address: string, port: TPort = 6667.TPort,
realname = "NimrodBot", serverPass = "",
joinChans: seq[string] = @[],
msgLimit: bool = true,
ircEvent: proc (irc: PAsyncIRC, ev: TIRCEvent) {.closure.}
ircEvent: proc (irc: PAsyncIRC, ev: TIRCEvent) {.closure,gcsafe.}
): PAsyncIRC =
## Use this function if you want to use asyncio's dispatcher.
##

View File

@@ -12,6 +12,8 @@
## Basic math routines for Nimrod.
## This module is available for the JavaScript target.
include "system/inclrtl"
{.push debugger:off .} # the user does not want to trace a part
# of the standard library!
@@ -127,25 +129,25 @@ proc variance*(x: openArray[float]): float {.noSideEffect.} =
result = result + diff*diff
result = result / toFloat(len(x))
proc random*(max: int): int
proc random*(max: int): int {.gcsafe.}
## returns a random number in the range 0..max-1. The sequence of
## random number is always the same, unless `randomize` is called
## which initializes the random number generator with a "random"
## number, i.e. a tickcount.
when not defined(windows):
proc random*(max: float): float
proc random*(max: float): float {.gcsafe.}
## returns a random number in the range 0..<max. The sequence of
## random number is always the same, unless `randomize` is called
## which initializes the random number generator with a "random"
## number, i.e. a tickcount. This is currently not supported for windows.
proc randomize*()
proc randomize*() {.gcsafe.}
## initializes the random number generator with a "random"
## number, i.e. a tickcount. Note: Does nothing for the JavaScript target,
## as JavaScript does not support this.
proc randomize*(seed: int)
proc randomize*(seed: int) {.gcsafe.}
## initializes the random number generator with a specific seed.
## Note: Does nothing for the JavaScript target,
## as JavaScript does not support this.
@@ -227,8 +229,8 @@ else:
result = int(floor(mathrandom() * float(max)))
proc random(max: float): float =
result = float(mathrandom() * float(max))
proc randomize() = nil
proc randomize(seed: int) = nil
proc randomize() = discard
proc randomize(seed: int) = discard
proc sqrt*(x: float): float {.importc: "Math.sqrt", nodecl.}
proc ln*(x: float): float {.importc: "Math.log", nodecl.}

View File

@@ -1564,7 +1564,7 @@ when defined(windows):
# ourselves. This has the additional benefit that the program's behaviour
# is always the same -- independent of the used C compiler.
var
ownArgv: seq[string]
ownArgv {.threadvar.}: seq[string]
proc paramCount*(): int {.rtl, extern: "nos$1", tags: [FReadIO].} =
## Returns the number of `command line arguments`:idx: given to the

View File

@@ -70,7 +70,7 @@ const
SymChars: TCharSet = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\x80'..'\xFF', '.',
'/', '\\'}
proc rawGetTok(c: var TCfgParser, tok: var TToken)
proc rawGetTok(c: var TCfgParser, tok: var TToken) {.gcsafe.}
proc open*(c: var TCfgParser, input: PStream, filename: string,
lineOffset = 0) {.

View File

@@ -26,6 +26,8 @@
## **Warning:** The API of this module is unstable, and therefore is subject
## to change.
include "system/inclrtl"
import sockets, strutils, os, strtabs, asyncio
type
@@ -82,7 +84,7 @@ type
TAsyncScgiState = object
handleRequest: proc (client: PAsyncSocket,
input: string, headers: PStringTable) {.closure.}
input: string, headers: PStringTable) {.closure,gcsafe.}
asyncServer: PAsyncSocket
disp: PDispatcher
PAsyncScgiState* = ref TAsyncScgiState
@@ -150,7 +152,7 @@ proc writeStatusOkTextContent*(c: TSocket, contentType = "text/html") =
"Content-Type: $1\r\L\r\L" % contentType)
proc run*(handleRequest: proc (client: TSocket, input: string,
headers: PStringTable): bool {.nimcall.},
headers: PStringTable): bool {.nimcall,gcsafe.},
port = TPort(4000)) =
## encapsulates the SCGI object and main loop.
var s: TScgiState
@@ -246,7 +248,8 @@ proc handleAccept(sock: PAsyncSocket, s: PAsyncScgiState) =
s.disp.register(client)
proc open*(handleRequest: proc (client: PAsyncSocket,
input: string, headers: PStringTable) {.closure.},
input: string, headers: PStringTable) {.
closure, gcsafe.},
port = TPort(4000), address = "127.0.0.1",
reuseAddr = false): PAsyncScgiState =
## Creates an ``PAsyncScgiState`` object which serves as a SCGI server.

View File

@@ -24,6 +24,8 @@
## Asynchronous sockets are supported, however a better alternative is to use
## the `asyncio <asyncio.html>`_ module.
include "system/inclrtl"
{.deadCodeElim: on.}
when hostOS == "solaris":
@@ -544,7 +546,7 @@ proc acceptAddr*(server: TSocket, client: var TSocket, address: var string) {.
else:
SSLError("Unknown error")
proc setBlocking*(s: TSocket, blocking: bool) {.tags: [].}
proc setBlocking*(s: TSocket, blocking: bool) {.tags: [], gcsafe.}
## Sets blocking mode on socket
when defined(ssl):

View File

@@ -12,6 +12,8 @@
## interface for Nimrod file objects (`TFile`) and strings. Other modules
## may provide other implementations for this standard stream interface.
include "system/inclrtl"
proc newEIO(msg: string): ref EIO =
new(result)
result.msg = msg
@@ -23,15 +25,15 @@ type
## here shouldn't be used directly. They are
## accessible so that a stream implementation
## can override them.
closeImpl*: proc (s: PStream) {.nimcall, tags: [].}
atEndImpl*: proc (s: PStream): bool {.nimcall, tags: [].}
setPositionImpl*: proc (s: PStream, pos: int) {.nimcall, tags: [].}
getPositionImpl*: proc (s: PStream): int {.nimcall, tags: [].}
closeImpl*: proc (s: PStream) {.nimcall, tags: [], gcsafe.}
atEndImpl*: proc (s: PStream): bool {.nimcall, tags: [], gcsafe.}
setPositionImpl*: proc (s: PStream, pos: int) {.nimcall, tags: [], gcsafe.}
getPositionImpl*: proc (s: PStream): int {.nimcall, tags: [], gcsafe.}
readDataImpl*: proc (s: PStream, buffer: pointer,
bufLen: int): int {.nimcall, tags: [FReadIO].}
bufLen: int): int {.nimcall, tags: [FReadIO], gcsafe.}
writeDataImpl*: proc (s: PStream, buffer: pointer, bufLen: int) {.nimcall,
tags: [FWriteIO].}
flushImpl*: proc (s: PStream) {.nimcall, tags: [FWriteIO].}
tags: [FWriteIO], gcsafe.}
flushImpl*: proc (s: PStream) {.nimcall, tags: [FWriteIO], gcsafe.}
proc flush*(s: PStream) =
## flushes the buffers that the stream `s` might use.

View File

@@ -135,38 +135,38 @@ type
months*: int ## The number of months
years*: int ## The number of years
proc getTime*(): TTime {.tags: [FTime].}
proc getTime*(): TTime {.tags: [FTime], gcsafe.}
## gets the current calendar time as a UNIX epoch value (number of seconds
## elapsed since 1970) with integer precission. Use epochTime for higher
## resolution.
proc getLocalTime*(t: TTime): TTimeInfo {.tags: [FTime], raises: [].}
proc getLocalTime*(t: TTime): TTimeInfo {.tags: [FTime], raises: [], gcsafe.}
## converts the calendar time `t` to broken-time representation,
## expressed relative to the user's specified time zone.
proc getGMTime*(t: TTime): TTimeInfo {.tags: [FTime], raises: [].}
proc getGMTime*(t: TTime): TTimeInfo {.tags: [FTime], raises: [], gcsafe.}
## converts the calendar time `t` to broken-down time representation,
## expressed in Coordinated Universal Time (UTC).
proc timeInfoToTime*(timeInfo: TTimeInfo): TTime {.tags: [].}
proc timeInfoToTime*(timeInfo: TTimeInfo): TTime {.tags: [], gcsafe.}
## converts a broken-down time structure to
## calendar time representation. The function ignores the specified
## contents of the structure members `weekday` and `yearday` and recomputes
## them from the other information in the broken-down time structure.
proc fromSeconds*(since1970: float): TTime {.tags: [], raises: [].}
proc fromSeconds*(since1970: float): TTime {.tags: [], raises: [], gcsafe.}
## Takes a float which contains the number of seconds since the unix epoch and
## returns a time object.
proc fromSeconds*(since1970: int64): TTime {.tags: [], raises: [].} =
proc fromSeconds*(since1970: int64): TTime {.tags: [], raises: [], gcsafe.} =
## Takes an int which contains the number of seconds since the unix epoch and
## returns a time object.
fromSeconds(float(since1970))
proc toSeconds*(time: TTime): float {.tags: [], raises: [].}
proc toSeconds*(time: TTime): float {.tags: [], raises: [], gcsafe.}
## Returns the time in seconds since the unix epoch.
proc `$` *(timeInfo: TTimeInfo): string {.tags: [], raises: [].}
proc `$` *(timeInfo: TTimeInfo): string {.tags: [], raises: [], gcsafe.}
## converts a `TTimeInfo` object to a string representation.
proc `$` *(time: TTime): string {.tags: [], raises: [].}
proc `$` *(time: TTime): string {.tags: [], raises: [], gcsafe.}
## converts a calendar time to a string representation.
proc `-`*(a, b: TTime): int64 {.
@@ -189,14 +189,15 @@ proc `==`*(a, b: TTime): bool {.
result = a - b == 0
when not defined(JS):
proc getTzname*(): tuple[nonDST, DST: string] {.tags: [FTime], raises: [].}
proc getTzname*(): tuple[nonDST, DST: string] {.tags: [FTime], raises: [],
gcsafe.}
## returns the local timezone; ``nonDST`` is the name of the local non-DST
## timezone, ``DST`` is the name of the local DST timezone.
proc getTimezone*(): int {.tags: [FTime], raises: [].}
proc getTimezone*(): int {.tags: [FTime], raises: [], gcsafe.}
## returns the offset of the local (non-DST) timezone in seconds west of UTC.
proc getStartMilsecs*(): int {.deprecated, tags: [FTime].}
proc getStartMilsecs*(): int {.deprecated, tags: [FTime], gcsafe.}
## get the miliseconds from the start of the program. **Deprecated since
## version 0.8.10.** Use ``epochTime`` or ``cpuTime`` instead.

View File

@@ -192,9 +192,6 @@ when defined(nimNewShared):
type
`shared`* {.magic: "Shared".}
guarded* {.magic: "Guarded".}
else:
{.pragma: gcsafe.}
#{.pragma: gcsafe.}
const NoFakeVars* = defined(NimrodVM) ## true if the backend doesn't support \
## "fake variables" like 'var EBADF {.importc.}: cint'.

View File

@@ -29,7 +29,7 @@ type
region: TMemRegion
PRawChannel = ptr TRawChannel
TLoadStoreMode = enum mStore, mLoad
TChannel*[TMsg] = TRawChannel ## a channel for thread communication
TChannel* {.gcsafe.}[TMsg] = TRawChannel ## a channel for thread communication
const ChannelDeadMask = -2

View File

@@ -16,6 +16,8 @@
# -> defined(useNimRtl) or appType == "lib" and not defined(createNimRtl)
# 3) Exported into nimrtl.
# -> appType == "lib" and defined(createNimRtl)
when not defined(nimNewShared):
{.pragma: gcsafe.}
when defined(createNimRtl):
when defined(useNimRtl):
@@ -24,7 +26,7 @@ when defined(createNimRtl):
{.error: "nimrtl must be built as a library!".}
when defined(createNimRtl):
{.pragma: rtl, exportc: "nimrtl_$1", dynlib.}
{.pragma: rtl, exportc: "nimrtl_$1", dynlib, gcsafe.}
{.pragma: inl.}
{.pragma: compilerRtl, compilerproc, exportc: "nimrtl_$1", dynlib.}
elif defined(useNimRtl):
@@ -34,11 +36,11 @@ elif defined(useNimRtl):
const nimrtl* = "nimrtl.dylib"
else:
const nimrtl* = "libnimrtl.so"
{.pragma: rtl, importc: "nimrtl_$1", dynlib: nimrtl.}
{.pragma: rtl, importc: "nimrtl_$1", dynlib: nimrtl, gcsafe.}
{.pragma: inl.}
{.pragma: compilerRtl, compilerproc, importc: "nimrtl_$1", dynlib: nimrtl.}
else:
{.pragma: rtl.}
{.pragma: rtl, gcsafe.}
{.pragma: inl, inline.}
{.pragma: compilerRtl, compilerproc.}

View File

@@ -256,9 +256,9 @@ type
## that **must not** be part of a message! Use
## a ``TThreadId`` for that.
when TArg is void:
dataFn: proc () {.nimcall.}
dataFn: proc () {.nimcall, gcsafe.}
else:
dataFn: proc (m: TArg) {.nimcall.}
dataFn: proc (m: TArg) {.nimcall, gcsafe.}
data: TArg
TThreadId*[TArg] = ptr TThread[TArg] ## the current implementation uses
## a pointer as a thread ID.