fixes #2286
This commit is contained in:
parent
5a21892da0
commit
f514be0772
4 changed files with 77 additions and 22 deletions
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
40
tests/parallel/tmissing_deepcopy.nim
Normal file
40
tests/parallel/tmissing_deepcopy.nim
Normal 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()
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue