actors compile again

This commit is contained in:
Araq 2014-04-20 12:10:23 +02:00
commit c80d563afb
9 changed files with 68 additions and 30 deletions

View file

@ -162,6 +162,7 @@ proc wrapProcForSpawn*(owner: PSym; n: PNode): PNode =
argsParam.typ = ptrType argsParam.typ = ptrType
argsParam.position = 1 argsParam.position = 1
var objType = createObj(owner, n.info) var objType = createObj(owner, n.info)
incl(objType.flags, tfFinal)
let castExpr = createCastExpr(argsParam, objType) let castExpr = createCastExpr(argsParam, objType)
var scratchObj = newSym(skVar, getIdent"scratch", owner, n.info) var scratchObj = newSym(skVar, getIdent"scratch", owner, n.info)

View file

@ -71,7 +71,7 @@ type
init: seq[int] # list of initialized variables init: seq[int] # list of initialized variables
guards: TModel # nested guards guards: TModel # nested guards
locked: seq[PNode] # locked locations locked: seq[PNode] # locked locations
gcUnsafe: bool gcUnsafe, isRecursive: bool
PEffects = var TEffects PEffects = var TEffects
proc isLocalVar(a: PEffects, s: PSym): bool = proc isLocalVar(a: PEffects, s: PSym): bool =
@ -502,7 +502,9 @@ proc track(tracked: PEffects, n: PNode) =
# are indistinguishable from normal procs (both have tyProc type) and # are indistinguishable from normal procs (both have tyProc type) and
# we can detect them only by checking for attached nkEffectList. # we can detect them only by checking for attached nkEffectList.
if op != nil and op.kind == tyProc and op.n.sons[0].kind == nkEffectList: if op != nil and op.kind == tyProc and op.n.sons[0].kind == nkEffectList:
if notGcSafe(op) and not importedFromC(a): if a.kind == nkSym and a.sym == tracked.owner:
tracked.isRecursive = true
elif notGcSafe(op) and not importedFromC(a):
message(n.info, warnGcUnsafe, renderTree(n)) message(n.info, warnGcUnsafe, renderTree(n))
tracked.gcUnsafe = true tracked.gcUnsafe = true
var effectList = op.n.sons[0] var effectList = op.n.sons[0]

View file

@ -148,6 +148,9 @@ proc sumGeneric(t: PType): int =
result = ord(t.kind == tyGenericInvokation) result = ord(t.kind == tyGenericInvokation)
for i in 0 .. <t.len: result += t.sons[i].sumGeneric for i in 0 .. <t.len: result += t.sons[i].sumGeneric
break break
of tyProc:
# proc matche proc better than 'stmt' to disambiguate 'spawn'
return 1
of tyGenericParam, tyExpr, tyStatic, tyStmt, tyTypeDesc: break of tyGenericParam, tyExpr, tyStatic, tyStmt, tyTypeDesc: break
else: return 0 else: return 0

View file

@ -342,9 +342,10 @@ proc canFormAcycleAux(marker: var TIntSet, typ: PType, startId: int): bool =
result = t.id == startId result = t.id == startId
# Inheritance can introduce cyclic types, however this is not relevant # Inheritance can introduce cyclic types, however this is not relevant
# as the type that is passed to 'new' is statically known! # as the type that is passed to 'new' is statically known!
#if t.kind == tyObject and tfFinal notin t.flags: # er but we use it also for the write barrier ...
# # damn inheritance may introduce cycles: if t.kind == tyObject and tfFinal notin t.flags:
# result = true # damn inheritance may introduce cycles:
result = true
of tyProc: result = typ.callConv == ccClosure of tyProc: result = typ.callConv == ccClosure
else: discard else: discard

View file

@ -2018,7 +2018,7 @@ when not defined(sysFatal):
e.msg = message & arg e.msg = message & arg
raise e raise e
proc getTypeInfo*[T](x: T): pointer {.magic: "GetTypeInfo".} proc getTypeInfo*[T](x: T): pointer {.magic: "GetTypeInfo", gcsafe.}
## get type information for `x`. Ordinary code should not use this, but ## get type information for `x`. Ordinary code should not use this, but
## the `typeinfo` module instead. ## the `typeinfo` module instead.
@ -2209,10 +2209,14 @@ when not defined(JS): #and not defined(NimrodVM):
## Returns ``false`` if the end of the file has been reached, ``true`` ## Returns ``false`` if the end of the file has been reached, ``true``
## otherwise. If ``false`` is returned `line` contains no new data. ## otherwise. If ``false`` is returned `line` contains no new data.
when not defined(booting):
proc writeln*[Ty](f: TFile, x: varargs[Ty, `$`]) {.inline, proc writeln*[Ty](f: TFile, x: varargs[Ty, `$`]) {.inline,
tags: [FWriteIO].} tags: [FWriteIO], gcsafe.}
## writes the values `x` to `f` and then writes "\n". ## writes the values `x` to `f` and then writes "\n".
## May throw an IO exception. ## May throw an IO exception.
else:
proc writeln*[Ty](f: TFile, x: varargs[Ty, `$`]) {.inline,
tags: [FWriteIO].}
proc getFileSize*(f: TFile): int64 {.tags: [FReadIO], gcsafe.} proc getFileSize*(f: TFile): int64 {.tags: [FReadIO], gcsafe.}
## retrieves the file size (in bytes) of `f`. ## retrieves the file size (in bytes) of `f`.
@ -2935,3 +2939,6 @@ when not defined(booting):
template isStatic*(x): expr = compiles(static(x)) template isStatic*(x): expr = compiles(static(x))
# checks whether `x` is a value known at compile-time # checks whether `x` is a value known at compile-time
when hasThreadSupport:
when hostOS != "standalone": include "system/sysspawn"

View file

@ -7,10 +7,11 @@
# distribution, for details about the copyright. # distribution, for details about the copyright.
# #
proc genericResetAux(dest: pointer, n: ptr TNimNode) proc genericResetAux(dest: pointer, n: ptr TNimNode) {.gcsafe.}
proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) {.gcsafe.}
proc genericAssignAux(dest, src: pointer, n: ptr TNimNode, shallow: bool) = proc genericAssignAux(dest, src: pointer, n: ptr TNimNode,
shallow: bool) {.gcsafe.} =
var var
d = cast[TAddress](dest) d = cast[TAddress](dest)
s = cast[TAddress](src) s = cast[TAddress](src)
@ -139,8 +140,8 @@ proc genericAssignOpenArray(dest, src: pointer, len: int,
genericAssign(cast[pointer](d +% i*% mt.base.size), genericAssign(cast[pointer](d +% i*% mt.base.size),
cast[pointer](s +% i*% mt.base.size), mt.base) cast[pointer](s +% i*% mt.base.size), mt.base)
proc objectInit(dest: pointer, typ: PNimType) {.compilerProc.} proc objectInit(dest: pointer, typ: PNimType) {.compilerProc, gcsafe.}
proc objectInitAux(dest: pointer, n: ptr TNimNode) = proc objectInitAux(dest: pointer, n: ptr TNimNode) {.gcsafe.} =
var d = cast[TAddress](dest) var d = cast[TAddress](dest)
case n.kind case n.kind
of nkNone: sysAssert(false, "objectInitAux") of nkNone: sysAssert(false, "objectInitAux")
@ -184,7 +185,7 @@ else:
mixin destroy mixin destroy
for i in countup(0, r.len - 1): destroy(r[i]) for i in countup(0, r.len - 1): destroy(r[i])
proc genericReset(dest: pointer, mt: PNimType) {.compilerProc.} proc genericReset(dest: pointer, mt: PNimType) {.compilerProc, gcsafe.}
proc genericResetAux(dest: pointer, n: ptr TNimNode) = proc genericResetAux(dest: pointer, n: ptr TNimNode) =
var d = cast[TAddress](dest) var d = cast[TAddress](dest)
case n.kind case n.kind

View file

@ -1,7 +1,7 @@
# #
# #
# Nimrod's Runtime Library # Nimrod's Runtime Library
# (c) Copyright 2012 Andreas Rumpf # (c) Copyright 2014 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
@ -49,9 +49,9 @@ proc deinitRawChannel(p: pointer) =
deinitSysCond(c.cond) deinitSysCond(c.cond)
proc storeAux(dest, src: pointer, mt: PNimType, t: PRawChannel, proc storeAux(dest, src: pointer, mt: PNimType, t: PRawChannel,
mode: TLoadStoreMode) mode: TLoadStoreMode) {.gcsafe.}
proc storeAux(dest, src: pointer, n: ptr TNimNode, t: PRawChannel, proc storeAux(dest, src: pointer, n: ptr TNimNode, t: PRawChannel,
mode: TLoadStoreMode) = mode: TLoadStoreMode) {.gcsafe.} =
var var
d = cast[TAddress](dest) d = cast[TAddress](dest)
s = cast[TAddress](src) s = cast[TAddress](src)
@ -209,7 +209,6 @@ proc send*[TMsg](c: var TChannel[TMsg], msg: TMsg) =
proc llRecv(q: PRawChannel, res: pointer, typ: PNimType) = proc llRecv(q: PRawChannel, res: pointer, typ: PNimType) =
# to save space, the generic is as small as possible # to save space, the generic is as small as possible
acquireSys(q.lock)
q.ready = true q.ready = true
while q.count <= 0: while q.count <= 0:
waitSysCond(q.cond, q.lock) waitSysCond(q.cond, q.lock)
@ -218,17 +217,29 @@ proc llRecv(q: PRawChannel, res: pointer, typ: PNimType) =
releaseSys(q.lock) releaseSys(q.lock)
sysFatal(EInvalidValue, "cannot receive message of wrong type") sysFatal(EInvalidValue, "cannot receive message of wrong type")
rawRecv(q, res, typ) rawRecv(q, res, typ)
releaseSys(q.lock)
proc recv*[TMsg](c: var TChannel[TMsg]): TMsg = proc recv*[TMsg](c: var TChannel[TMsg]): TMsg =
## receives a message from the channel `c`. This blocks until ## receives a message from the channel `c`. This blocks until
## a message has arrived! You may use ``peek`` to avoid the blocking. ## a message has arrived! You may use ``peek`` to avoid the blocking.
var q = cast[PRawChannel](addr(c)) var q = cast[PRawChannel](addr(c))
acquireSys(q.lock)
llRecv(q, addr(result), cast[PNimType](getTypeInfo(result))) llRecv(q, addr(result), cast[PNimType](getTypeInfo(result)))
releaseSys(q.lock)
proc tryRecv*[TMsg](c: var TChannel[TMsg]): tuple[dataAvaliable: bool,
msg: TMsg] =
## try to receives a message from the channel `c` if available. Otherwise
## it returns ``(false, default(msg))``.
var q = cast[PRawChannel](addr(c))
if q.mask != ChannelDeadMask:
lockChannel(q):
llRecv(q, addr(result.msg), cast[PNimType](getTypeInfo(result.msg)))
result.dataAvaliable = true
proc peek*[TMsg](c: var TChannel[TMsg]): int = proc peek*[TMsg](c: var TChannel[TMsg]): int =
## returns the current number of messages in the channel `c`. Returns -1 ## returns the current number of messages in the channel `c`. Returns -1
## if the channel has been closed. ## if the channel has been closed. **Note**: This is dangerous to use
## as it encourages races. It's much better to use ``tryRecv`` instead.
var q = cast[PRawChannel](addr(c)) var q = cast[PRawChannel](addr(c))
if q.mask != ChannelDeadMask: if q.mask != ChannelDeadMask:
lockChannel(q): lockChannel(q):

View file

@ -10,7 +10,7 @@
# The generic ``repr`` procedure. It is an invaluable debugging tool. # The generic ``repr`` procedure. It is an invaluable debugging tool.
when not defined(useNimRtl): when not defined(useNimRtl):
proc reprAny(p: pointer, typ: PNimType): string {.compilerRtl.} proc reprAny(p: pointer, typ: PNimType): string {.compilerRtl, gcsafe.}
proc reprInt(x: int64): string {.compilerproc.} = return $x proc reprInt(x: int64): string {.compilerproc.} = return $x
proc reprFloat(x: float): string {.compilerproc.} = return $x proc reprFloat(x: float): string {.compilerproc.} = return $x
@ -78,7 +78,7 @@ proc reprEnum(e: int, typ: PNimType): string {.compilerRtl.} =
type type
PByteArray = ptr array[0.. 0xffff, int8] PByteArray = ptr array[0.. 0xffff, int8]
proc addSetElem(result: var string, elem: int, typ: PNimType) = proc addSetElem(result: var string, elem: int, typ: PNimType) {.gcsafe.} =
case typ.kind case typ.kind
of tyEnum: add result, reprEnum(elem, typ) of tyEnum: add result, reprEnum(elem, typ)
of tyBool: add result, reprBool(bool(elem)) of tyBool: add result, reprBool(bool(elem))
@ -147,7 +147,7 @@ when not defined(useNimRtl):
for i in 0..cl.indent-1: add result, ' ' for i in 0..cl.indent-1: add result, ' '
proc reprAux(result: var string, p: pointer, typ: PNimType, proc reprAux(result: var string, p: pointer, typ: PNimType,
cl: var TReprClosure) cl: var TReprClosure) {.gcsafe.}
proc reprArray(result: var string, p: pointer, typ: PNimType, proc reprArray(result: var string, p: pointer, typ: PNimType,
cl: var TReprClosure) = cl: var TReprClosure) =
@ -172,7 +172,7 @@ when not defined(useNimRtl):
add result, "]" add result, "]"
proc reprRecordAux(result: var string, p: pointer, n: ptr TNimNode, proc reprRecordAux(result: var string, p: pointer, n: ptr TNimNode,
cl: var TReprClosure) = cl: var TReprClosure) {.gcsafe.} =
case n.kind case n.kind
of nkNone: sysAssert(false, "reprRecordAux") of nkNone: sysAssert(false, "reprRecordAux")
of nkSlot: of nkSlot:

View file

@ -1,7 +1,18 @@
# Implements Nimrod's 'spawn'. #
#
# Nimrod's Runtime Library
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Implements Nimrod's 'spawn'.
when not defined(NimString):
{.error: "You must not import this module explicitly".}
{.push stackTrace:off.} {.push stackTrace:off.}
include system.syslocks
when (defined(x86) or defined(amd64)) and defined(gcc): when (defined(x86) or defined(amd64)) and defined(gcc):
proc cpuRelax {.inline.} = proc cpuRelax {.inline.} =
@ -10,12 +21,12 @@ elif (defined(x86) or defined(amd64)) and defined(vcc):
proc cpuRelax {.importc: "YieldProcessor", header: "<windows.h>".} proc cpuRelax {.importc: "YieldProcessor", header: "<windows.h>".}
elif defined(intelc): elif defined(intelc):
proc cpuRelax {.importc: "_mm_pause", header: "xmmintrin.h".} proc cpuRelax {.importc: "_mm_pause", header: "xmmintrin.h".}
else: elif false:
from os import sleep from os import sleep
proc cpuRelax {.inline.} = os.sleep(1) proc cpuRelax {.inline.} = os.sleep(1)
when defined(windows): when defined(windows) and not defined(gcc):
proc interlockedCompareExchange(p: pointer; exchange, comparand: int32): int32 proc interlockedCompareExchange(p: pointer; exchange, comparand: int32): int32
{.importc: "InterlockedCompareExchange", header: "<windows.h>", cdecl.} {.importc: "InterlockedCompareExchange", header: "<windows.h>", cdecl.}
@ -70,6 +81,7 @@ proc await(cv: var FastCondVar) =
# return # return
# cpuRelax() # cpuRelax()
#cv.slowPath = true #cv.slowPath = true
# XXX For some reason this crashes some test programs
await(cv.slow) await(cv.slow)
cv.event = false cv.event = false