This commit is contained in:
Araq 2015-03-12 01:44:57 +01:00
commit f514be0772
4 changed files with 77 additions and 22 deletions

View file

@ -23,7 +23,7 @@ proc newTupleAccess*(tup: PNode, i: int): PNode =
lit.intVal = i lit.intVal = i
addSon(result, lit) addSon(result, lit)
proc addVar*(father, v: PNode) = proc addVar*(father, v: PNode) =
var vpart = newNodeI(nkIdentDefs, v.info, 3) var vpart = newNodeI(nkIdentDefs, v.info, 3)
vpart.sons[0] = v vpart.sons[0] = v
vpart.sons[1] = ast.emptyNode vpart.sons[1] = ast.emptyNode
@ -53,7 +53,7 @@ proc lowerTupleUnpacking*(n: PNode; owner: PSym): PNode =
let tempAsNode = newSymNode(temp) let tempAsNode = newSymNode(temp)
v.addVar(tempAsNode) v.addVar(tempAsNode)
result.add(v) result.add(v)
result.add newAsgnStmt(tempAsNode, value) result.add newAsgnStmt(tempAsNode, value)
for i in 0 .. n.len-3: for i in 0 .. n.len-3:
if n.sons[i].kind == nkSym: v.addVar(n.sons[i]) if n.sons[i].kind == nkSym: v.addVar(n.sons[i])
@ -70,7 +70,7 @@ proc rawAddField*(obj: PType; field: PSym) =
field.position = sonsLen(obj.n) field.position = sonsLen(obj.n)
addSon(obj.n, newSymNode(field)) addSon(obj.n, newSymNode(field))
proc rawIndirectAccess*(a: PNode; field: PSym; info: TLineInfo): PNode = proc rawIndirectAccess*(a: PNode; field: PSym; info: TLineInfo): PNode =
# returns a[].field as a node # returns a[].field as a node
assert field.kind == skField assert field.kind == skField
var deref = newNodeI(nkHiddenDeref, info) var deref = newNodeI(nkHiddenDeref, info)
@ -109,7 +109,7 @@ proc newDotExpr(obj, b: PSym): PNode =
addSon(result, newSymNode(field)) addSon(result, newSymNode(field))
result.typ = field.typ result.typ = field.typ
proc indirectAccess*(a: PNode, b: string, info: TLineInfo): PNode = proc indirectAccess*(a: PNode, b: string, info: TLineInfo): PNode =
# returns a[].b as a node # returns a[].b as a node
var deref = newNodeI(nkHiddenDeref, info) var deref = newNodeI(nkHiddenDeref, info)
deref.typ = a.typ.skipTypes(abstractInst).sons[0] deref.typ = a.typ.skipTypes(abstractInst).sons[0]
@ -144,7 +144,7 @@ proc getFieldFromObj*(t: PType; v: PSym): PSym =
if t == nil: break if t == nil: break
t = t.skipTypes(abstractInst) t = t.skipTypes(abstractInst)
proc indirectAccess*(a: PNode, b: PSym, info: TLineInfo): PNode = proc indirectAccess*(a: PNode, b: PSym, info: TLineInfo): PNode =
# returns a[].b as a node # returns a[].b as a node
result = indirectAccess(a, b.name.s & $b.id, info) result = indirectAccess(a, b.name.s & $b.id, info)
@ -158,11 +158,11 @@ proc genAddrOf*(n: PNode): PNode =
result.typ.rawAddSon(n.typ) result.typ.rawAddSon(n.typ)
proc genDeref*(n: PNode): PNode = proc genDeref*(n: PNode): PNode =
result = newNodeIT(nkHiddenDeref, n.info, result = newNodeIT(nkHiddenDeref, n.info,
n.typ.skipTypes(abstractInst).sons[0]) n.typ.skipTypes(abstractInst).sons[0])
result.add n result.add n
proc callCodegenProc*(name: string, arg1: PNode; proc callCodegenProc*(name: string, arg1: PNode;
arg2, arg3: PNode = nil): PNode = arg2, arg3: PNode = nil): PNode =
result = newNodeI(nkCall, arg1.info) result = newNodeI(nkCall, arg1.info)
let sym = magicsys.getCompilerProc(name) let sym = magicsys.getCompilerProc(name)
@ -203,6 +203,17 @@ proc flowVarKind(t: PType): TFlowVarKind =
elif containsGarbageCollectedRef(t): fvInvalid elif containsGarbageCollectedRef(t): fvInvalid
else: fvBlob else: fvBlob
proc typeNeedsNoDeepCopy(t: PType): bool =
var t = t.skipTypes(abstractInst)
# for the tconvexhull example (and others) we're a bit lax here and pretend
# seqs and strings are *by value* only and 'shallow' doesn't exist!
if t.kind == tyString: return true
# note that seq[T] is fine, but 'var seq[T]' is not, so we need to skip 'var'
# for the stricter check and likewise we can skip 'seq' for a less
# strict check:
if t.kind in {tyVar, tySequence}: t = t.sons[0]
result = not containsGarbageCollectedRef(t)
proc addLocalVar(varSection, varInit: PNode; owner: PSym; typ: PType; proc addLocalVar(varSection, varInit: PNode; owner: PSym; typ: PType;
v: PNode; useShallowCopy=false): PSym = v: PNode; useShallowCopy=false): PSym =
result = newSym(skTemp, getIdent(genPrefix), owner, varSection.info) result = newSym(skTemp, getIdent(genPrefix), owner, varSection.info)
@ -215,7 +226,7 @@ proc addLocalVar(varSection, varInit: PNode; owner: PSym; typ: PType;
vpart.sons[2] = if varInit.isNil: v else: ast.emptyNode vpart.sons[2] = if varInit.isNil: v else: ast.emptyNode
varSection.add vpart varSection.add vpart
if varInit != nil: if varInit != nil:
if useShallowCopy: if useShallowCopy and typeNeedsNoDeepCopy(typ):
varInit.add newFastAsgnStmt(newSymNode(result), v) varInit.add newFastAsgnStmt(newSymNode(result), v)
else: else:
let deepCopyCall = newNodeI(nkCall, varInit.info, 3) let deepCopyCall = newNodeI(nkCall, varInit.info, 3)
@ -236,10 +247,10 @@ proc f_wrapper(thread, args) =
fv.owner = thread # optional fv.owner = thread # optional
nimArgsPassingDone() # signal parent that the work is done nimArgsPassingDone() # signal parent that the work is done
# #
args.fv.blob = f(a, b, ...) args.fv.blob = f(a, b, ...)
nimFlowVarSignal(args.fv) nimFlowVarSignal(args.fv)
# - or - # - or -
f(a, b, ...) f(a, b, ...)
barrierLeave(args.barrier) # for parallel statement barrierLeave(args.barrier) # for parallel statement
@ -261,7 +272,7 @@ proc createWrapperProc(f: PNode; threadParam, argsParam: PSym;
var threadLocalBarrier: PSym var threadLocalBarrier: PSym
if barrier != nil: if barrier != nil:
var varSection2 = newNodeI(nkVarSection, barrier.info) var varSection2 = newNodeI(nkVarSection, barrier.info)
threadLocalBarrier = addLocalVar(varSection2, nil, argsParam.owner, threadLocalBarrier = addLocalVar(varSection2, nil, argsParam.owner,
barrier.typ, barrier) barrier.typ, barrier)
body.add varSection2 body.add varSection2
body.add callCodegenProc("barrierEnter", threadLocalBarrier.newSymNode) body.add callCodegenProc("barrierEnter", threadLocalBarrier.newSymNode)
@ -285,7 +296,7 @@ proc createWrapperProc(f: PNode; threadParam, argsParam: PSym;
elif fv != nil: elif fv != nil:
let fk = fv.typ.sons[1].flowVarKind let fk = fv.typ.sons[1].flowVarKind
if fk == fvInvalid: if fk == fvInvalid:
localError(f.info, "cannot create a flowVar of type: " & localError(f.info, "cannot create a flowVar of type: " &
typeToString(fv.typ.sons[1])) typeToString(fv.typ.sons[1]))
body.add newAsgnStmt(indirectAccess(threadLocalProm.newSymNode, body.add newAsgnStmt(indirectAccess(threadLocalProm.newSymNode,
if fk == fvGC: "data" else: "blob", fv.info), call) if fk == fvGC: "data" else: "blob", fv.info), call)
@ -330,8 +341,8 @@ proc createCastExpr(argsParam: PSym; objType: PType): PNode =
result.typ = newType(tyPtr, objType.owner) result.typ = newType(tyPtr, objType.owner)
result.typ.rawAddSon(objType) result.typ.rawAddSon(objType)
proc setupArgsForConcurrency(n: PNode; objType: PType; scratchObj: PSym, proc setupArgsForConcurrency(n: PNode; objType: PType; scratchObj: PSym,
castExpr, call, castExpr, call,
varSection, varInit, result: PNode) = varSection, varInit, result: PNode) =
let formals = n[0].typ.n let formals = n[0].typ.n
let tmpName = getIdent(genPrefix) let tmpName = getIdent(genPrefix)
@ -385,7 +396,7 @@ proc genHigh(n: PNode): PNode =
result.sons[1] = n result.sons[1] = n
proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym; proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
castExpr, call, castExpr, call,
varSection, varInit, result: PNode) = varSection, varInit, result: PNode) =
let formals = n[0].typ.n let formals = n[0].typ.n
let tmpName = getIdent(genPrefix) let tmpName = getIdent(genPrefix)
@ -409,7 +420,7 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
var fieldB = newSym(skField, tmpName, objType.owner, n.info) var fieldB = newSym(skField, tmpName, objType.owner, n.info)
fieldB.typ = getSysType(tyInt) fieldB.typ = getSysType(tyInt)
objType.addField(fieldB) objType.addField(fieldB)
if getMagic(n) == mSlice: if getMagic(n) == mSlice:
let a = genAddrOf(n[1]) let a = genAddrOf(n[1])
field.typ = a.typ field.typ = a.typ
@ -464,7 +475,7 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
useShallowCopy=true) useShallowCopy=true)
call.add(threadLocal.newSymNode) call.add(threadLocal.newSymNode)
proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType; proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
barrier, dest: PNode = nil): PNode = barrier, dest: PNode = nil): PNode =
# if 'barrier' != nil, then it is in a 'parallel' section and we # if 'barrier' != nil, then it is in a 'parallel' section and we
# generate quite different code # generate quite different code
@ -530,10 +541,10 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
var varSection = newNodeI(nkVarSection, n.info) var varSection = newNodeI(nkVarSection, n.info)
var varInit = newNodeI(nkStmtList, n.info) var varInit = newNodeI(nkStmtList, n.info)
if barrier.isNil: if barrier.isNil:
setupArgsForConcurrency(n, objType, scratchObj, castExpr, call, setupArgsForConcurrency(n, objType, scratchObj, castExpr, call,
varSection, varInit, result) varSection, varInit, result)
else: else:
setupArgsForParallelism(n, objType, scratchObj, castExpr, call, setupArgsForParallelism(n, objType, scratchObj, castExpr, call,
varSection, varInit, result) varSection, varInit, result)
var barrierAsExpr: PNode = nil var barrierAsExpr: PNode = nil
@ -566,7 +577,7 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
fvAsExpr = indirectAccess(castExpr, field, n.info) fvAsExpr = indirectAccess(castExpr, field, n.info)
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), genAddrOf(dest)) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), genAddrOf(dest))
let wrapper = createWrapperProc(fn, threadParam, argsParam, let wrapper = createWrapperProc(fn, threadParam, argsParam,
varSection, varInit, call, varSection, varInit, call,
barrierAsExpr, fvAsExpr, spawnKind) barrierAsExpr, fvAsExpr, spawnKind)
result.add callCodegenProc("nimSpawn", wrapper.newSymNode, result.add callCodegenProc("nimSpawn", wrapper.newSymNode,

View file

@ -6,7 +6,7 @@ true
true true
true''' true'''
ccodeCheck: "!'deepcopy('" ccodeCheck: "\\i ! @'deepCopy(' .*"
""" """
# parallel convex hull for Nim bigbreak # parallel convex hull for Nim bigbreak

View file

@ -0,0 +1,40 @@
discard """
ccodeCheck: "\\i @'deepCopy(' .*"
"""
# bug #2286
import threadPool
type
Person = ref object
name: string
friend: Person
var
people: seq[Person] = @[]
proc newPerson(name:string): Person =
result.new()
result.name = name
proc greet(p:Person) =
p.friend.name &= "-MUT" # this line crashes the program
echo "Person {",
" name:", p.name, "(", cast[int](addr p.name),"),",
" friend:", p.friend.name, "(", cast[int](addr p.friend.name),") }"
proc setup =
for i in 0 .. <20:
people.add newPerson("Person" & $(i + 1))
for i in 0 .. <20:
people[i].friend = people[19-i]
proc update =
parallel:
for i in 0 .. people.high:
spawn people[i].greet()
when isMainModule:
setup()
update()

View file

@ -148,7 +148,11 @@ proc codegenCheck(test: TTest, check: string, given: var TSpec) =
let genFile = generatedFile(path, name, test.target) let genFile = generatedFile(path, name, test.target)
echo genFile echo genFile
let contents = readFile(genFile).string let contents = readFile(genFile).string
if contents.find(check.peg) < 0: if check[0] == '\\':
# little hack to get 'match' support:
if not contents.match(check.peg):
given.err = reCodegenFailure
elif contents.find(check.peg) < 0:
given.err = reCodegenFailure given.err = reCodegenFailure
except ValueError: except ValueError:
given.err = reInvalidPeg given.err = reInvalidPeg