diff options
author | Araq <rumpf_a@web.de> | 2015-03-12 01:44:57 +0100 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2015-03-12 01:45:15 +0100 |
commit | f514be0772628f1045171139893d05c6aad76ee6 (patch) | |
tree | a0beb8a020f7330d22e5e406bb7a351a18a3e6d2 | |
parent | 5a21892da0d16cc0fb321dadb17140a4808b0c17 (diff) | |
download | Nim-f514be0772628f1045171139893d05c6aad76ee6.tar.gz |
fixes #2286
-rw-r--r-- | compiler/lowerings.nim | 51 | ||||
-rw-r--r-- | tests/parallel/tconvexhull.nim | 2 | ||||
-rw-r--r-- | tests/parallel/tmissing_deepcopy.nim | 40 | ||||
-rw-r--r-- | tests/testament/tester.nim | 6 |
4 files changed, 77 insertions, 22 deletions
diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim index 0f670ae7a..a51ca9ed6 100644 --- a/compiler/lowerings.nim +++ b/compiler/lowerings.nim @@ -23,7 +23,7 @@ proc newTupleAccess*(tup: PNode, i: int): PNode = lit.intVal = i addSon(result, lit) -proc addVar*(father, v: PNode) = +proc addVar*(father, v: PNode) = var vpart = newNodeI(nkIdentDefs, v.info, 3) vpart.sons[0] = v vpart.sons[1] = ast.emptyNode @@ -53,7 +53,7 @@ proc lowerTupleUnpacking*(n: PNode; owner: PSym): PNode = let tempAsNode = newSymNode(temp) v.addVar(tempAsNode) result.add(v) - + result.add newAsgnStmt(tempAsNode, value) for i in 0 .. n.len-3: 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) 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 assert field.kind == skField var deref = newNodeI(nkHiddenDeref, info) @@ -109,7 +109,7 @@ proc newDotExpr(obj, b: PSym): PNode = addSon(result, newSymNode(field)) 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 var deref = newNodeI(nkHiddenDeref, info) deref.typ = a.typ.skipTypes(abstractInst).sons[0] @@ -144,7 +144,7 @@ proc getFieldFromObj*(t: PType; v: PSym): PSym = if t == nil: break 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 result = indirectAccess(a, b.name.s & $b.id, info) @@ -158,11 +158,11 @@ proc genAddrOf*(n: PNode): PNode = result.typ.rawAddSon(n.typ) proc genDeref*(n: PNode): PNode = - result = newNodeIT(nkHiddenDeref, n.info, + result = newNodeIT(nkHiddenDeref, n.info, n.typ.skipTypes(abstractInst).sons[0]) result.add n -proc callCodegenProc*(name: string, arg1: PNode; +proc callCodegenProc*(name: string, arg1: PNode; arg2, arg3: PNode = nil): PNode = result = newNodeI(nkCall, arg1.info) let sym = magicsys.getCompilerProc(name) @@ -203,6 +203,17 @@ proc flowVarKind(t: PType): TFlowVarKind = elif containsGarbageCollectedRef(t): fvInvalid 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; v: PNode; useShallowCopy=false): PSym = 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 varSection.add vpart if varInit != nil: - if useShallowCopy: + if useShallowCopy and typeNeedsNoDeepCopy(typ): varInit.add newFastAsgnStmt(newSymNode(result), v) else: let deepCopyCall = newNodeI(nkCall, varInit.info, 3) @@ -236,10 +247,10 @@ proc f_wrapper(thread, args) = fv.owner = thread # optional nimArgsPassingDone() # signal parent that the work is done - # + # args.fv.blob = f(a, b, ...) nimFlowVarSignal(args.fv) - + # - or - f(a, b, ...) barrierLeave(args.barrier) # for parallel statement @@ -261,7 +272,7 @@ proc createWrapperProc(f: PNode; threadParam, argsParam: PSym; var threadLocalBarrier: PSym if barrier != nil: var varSection2 = newNodeI(nkVarSection, barrier.info) - threadLocalBarrier = addLocalVar(varSection2, nil, argsParam.owner, + threadLocalBarrier = addLocalVar(varSection2, nil, argsParam.owner, barrier.typ, barrier) body.add varSection2 body.add callCodegenProc("barrierEnter", threadLocalBarrier.newSymNode) @@ -285,7 +296,7 @@ proc createWrapperProc(f: PNode; threadParam, argsParam: PSym; elif fv != nil: let fk = fv.typ.sons[1].flowVarKind 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])) body.add newAsgnStmt(indirectAccess(threadLocalProm.newSymNode, 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.rawAddSon(objType) -proc setupArgsForConcurrency(n: PNode; objType: PType; scratchObj: PSym, - castExpr, call, +proc setupArgsForConcurrency(n: PNode; objType: PType; scratchObj: PSym, + castExpr, call, varSection, varInit, result: PNode) = let formals = n[0].typ.n let tmpName = getIdent(genPrefix) @@ -385,7 +396,7 @@ proc genHigh(n: PNode): PNode = result.sons[1] = n proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym; - castExpr, call, + castExpr, call, varSection, varInit, result: PNode) = let formals = n[0].typ.n 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) fieldB.typ = getSysType(tyInt) objType.addField(fieldB) - + if getMagic(n) == mSlice: let a = genAddrOf(n[1]) field.typ = a.typ @@ -464,7 +475,7 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym; useShallowCopy=true) 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 = # if 'barrier' != nil, then it is in a 'parallel' section and we # generate quite different code @@ -530,10 +541,10 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType; var varSection = newNodeI(nkVarSection, n.info) var varInit = newNodeI(nkStmtList, n.info) if barrier.isNil: - setupArgsForConcurrency(n, objType, scratchObj, castExpr, call, + setupArgsForConcurrency(n, objType, scratchObj, castExpr, call, varSection, varInit, result) else: - setupArgsForParallelism(n, objType, scratchObj, castExpr, call, + setupArgsForParallelism(n, objType, scratchObj, castExpr, call, varSection, varInit, result) var barrierAsExpr: PNode = nil @@ -566,7 +577,7 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType; fvAsExpr = indirectAccess(castExpr, field, n.info) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), genAddrOf(dest)) - let wrapper = createWrapperProc(fn, threadParam, argsParam, + let wrapper = createWrapperProc(fn, threadParam, argsParam, varSection, varInit, call, barrierAsExpr, fvAsExpr, spawnKind) result.add callCodegenProc("nimSpawn", wrapper.newSymNode, diff --git a/tests/parallel/tconvexhull.nim b/tests/parallel/tconvexhull.nim index d7e4f7716..dffe5339b 100644 --- a/tests/parallel/tconvexhull.nim +++ b/tests/parallel/tconvexhull.nim @@ -6,7 +6,7 @@ true true true''' -ccodeCheck: "!'deepcopy('" +ccodeCheck: "\\i ! @'deepCopy(' .*" """ # parallel convex hull for Nim bigbreak diff --git a/tests/parallel/tmissing_deepcopy.nim b/tests/parallel/tmissing_deepcopy.nim new file mode 100644 index 000000000..53481e4df --- /dev/null +++ b/tests/parallel/tmissing_deepcopy.nim @@ -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() diff --git a/tests/testament/tester.nim b/tests/testament/tester.nim index 54ab67d85..7cf902704 100644 --- a/tests/testament/tester.nim +++ b/tests/testament/tester.nim @@ -148,7 +148,11 @@ proc codegenCheck(test: TTest, check: string, given: var TSpec) = let genFile = generatedFile(path, name, test.target) echo genFile 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 except ValueError: given.err = reInvalidPeg |