fixes a serious codegen bug that caused to emit wrong barriers in rare cases
This commit is contained in:
parent
5cea6807e1
commit
89cbf092b2
3 changed files with 71 additions and 13 deletions
|
|
@ -685,19 +685,23 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) =
|
||||||
else:
|
else:
|
||||||
var a: TLoc
|
var a: TLoc
|
||||||
initLocExprSingleUse(p, e.sons[0], a)
|
initLocExprSingleUse(p, e.sons[0], a)
|
||||||
let typ = skipTypes(a.t, abstractInst)
|
if d.k == locNone:
|
||||||
case typ.kind
|
let typ = skipTypes(a.t, abstractInst)
|
||||||
of tyRef:
|
# dest = *a; <-- We do not know that 'dest' is on the heap!
|
||||||
d.s = OnHeap
|
# It is completely wrong to set 'd.s' here, unless it's not yet
|
||||||
of tyVar:
|
# been assigned to.
|
||||||
d.s = OnUnknown
|
case typ.kind
|
||||||
if tfVarIsPtr notin typ.flags and p.module.compileToCpp and
|
of tyRef:
|
||||||
e.kind == nkHiddenDeref:
|
d.s = OnHeap
|
||||||
putIntoDest(p, d, e.typ, rdLoc(a))
|
of tyVar:
|
||||||
return
|
d.s = OnUnknown
|
||||||
of tyPtr:
|
if tfVarIsPtr notin typ.flags and p.module.compileToCpp and
|
||||||
d.s = OnUnknown # BUGFIX!
|
e.kind == nkHiddenDeref:
|
||||||
else: internalError(e.info, "genDeref " & $a.t.kind)
|
putIntoDest(p, d, e.typ, rdLoc(a))
|
||||||
|
return
|
||||||
|
of tyPtr:
|
||||||
|
d.s = OnUnknown # BUGFIX!
|
||||||
|
else: internalError(e.info, "genDeref " & $a.t.kind)
|
||||||
if enforceDeref and mt == ctPtrToArray:
|
if enforceDeref and mt == ctPtrToArray:
|
||||||
# we lie about the type for better C interop: 'ptr array[3,T]' is
|
# we lie about the type for better C interop: 'ptr array[3,T]' is
|
||||||
# translated to 'ptr T', but for deref'ing this produces wrong code.
|
# translated to 'ptr T', but for deref'ing this produces wrong code.
|
||||||
|
|
|
||||||
53
tests/parallel/twrong_refcounts.nim
Normal file
53
tests/parallel/twrong_refcounts.nim
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
discard """
|
||||||
|
output: "Success"
|
||||||
|
"""
|
||||||
|
|
||||||
|
import math, threadPool
|
||||||
|
|
||||||
|
# ---
|
||||||
|
|
||||||
|
type
|
||||||
|
Person = object
|
||||||
|
age: int
|
||||||
|
friend: ref Person
|
||||||
|
|
||||||
|
var
|
||||||
|
people: seq[ref Person] = @[]
|
||||||
|
|
||||||
|
proc newPerson(age:int): ref Person =
|
||||||
|
result.new()
|
||||||
|
result.age = age
|
||||||
|
|
||||||
|
proc greet(p:Person) =
|
||||||
|
#echo p.age, ", ", p.friend.age
|
||||||
|
p.friend.age += 1
|
||||||
|
|
||||||
|
# ---
|
||||||
|
|
||||||
|
proc setup =
|
||||||
|
for i in 0 .. <20:
|
||||||
|
people.add newPerson(i + 1)
|
||||||
|
for i in 0 .. <20:
|
||||||
|
people[i].friend = people[random(20)]
|
||||||
|
|
||||||
|
proc update =
|
||||||
|
var countA: array[20, int]
|
||||||
|
var countB: array[20, int]
|
||||||
|
|
||||||
|
for i, p in people:
|
||||||
|
countA[i] = getRefCount(p)
|
||||||
|
parallel:
|
||||||
|
for i in 0 .. people.high:
|
||||||
|
spawn greet(people[i][])
|
||||||
|
for i, p in people:
|
||||||
|
countB[i] = getRefCount(p)
|
||||||
|
|
||||||
|
for i in 0 .. <20:
|
||||||
|
doAssert countA[i] == countB[i]
|
||||||
|
echo "Success"
|
||||||
|
|
||||||
|
# ---
|
||||||
|
|
||||||
|
when isMainModule:
|
||||||
|
setup()
|
||||||
|
update()
|
||||||
1
todo.txt
1
todo.txt
|
|
@ -2,6 +2,7 @@ version 0.10.4
|
||||||
==============
|
==============
|
||||||
|
|
||||||
- make 'nil' work for 'add' and 'len'
|
- make 'nil' work for 'add' and 'len'
|
||||||
|
- enable parameter info for nimsuggest
|
||||||
|
|
||||||
version 1.0
|
version 1.0
|
||||||
===========
|
===========
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue