Skip to content

Commit

Permalink
fix nim-lang#15704 nim-lang#15597 wrong VM register was freed (nim-la…
Browse files Browse the repository at this point in the history
…ng#15705)

* fix nim-lang#15704 nim-lang#15597 wrong VM register was freed

* same treatment for nkCheckedFieldExpr

* note concerning HighRegisterPressure

* bump NimPatch

* Update lib/system.nim

Co-authored-by: Andreas Rumpf <[email protected]>
  • Loading branch information
2 people authored and irdassis committed Feb 12, 2021
1 parent 5d59e1c commit 19e1dc5
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 2 deletions.
6 changes: 4 additions & 2 deletions compiler/vmgen.nim
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,8 @@ proc freeTemp(c: PCtx; r: TRegister) =
proc getTempRange(cc: PCtx; n: int; kind: TSlotKind): TRegister =
# if register pressure is high, we re-use more aggressively:
let c = cc.prc
# we could also customize via the following (with proper caching in ConfigRef):
# let highRegisterPressure = cc.config.getConfigVar("vm.highRegisterPressure", "40").parseInt
if c.maxSlots >= HighRegisterPressure or c.maxSlots+n >= high(TRegister):
for i in 0..c.maxSlots-n:
if not c.slots[i].inUse:
Expand Down Expand Up @@ -1508,14 +1510,14 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
let tmp = c.genx(ri)
c.preventFalseAlias(le[0], opcWrObj, objR, idx, tmp)
c.freeTemp(tmp)
c.freeTemp(idx)
# c.freeTemp(idx) # BUGFIX, see nkDotExpr
c.freeTemp(objR)
of nkDotExpr:
let dest = c.genx(le[0], {gfNode})
let idx = genField(c, le[1])
let tmp = c.genx(ri)
c.preventFalseAlias(le, opcWrObj, dest, idx, tmp)
c.freeTemp(idx)
# c.freeTemp(idx) # BUGFIX: idx is an immediate (field position), not a register
c.freeTemp(tmp)
c.freeTemp(dest)
of nkDerefExpr, nkHiddenDeref:
Expand Down
130 changes: 130 additions & 0 deletions tests/vm/tvmmisc.nim
Original file line number Diff line number Diff line change
Expand Up @@ -281,3 +281,133 @@ block: # bug #8007
# OK with seq & object variants
const d = @[Cost(kind: Fixed, cost: 999), Cost(kind: Dynamic, handler: foo)]
doAssert $d == "@[(kind: Fixed, cost: 999), (kind: Dynamic, handler: ...)]"

block: # VM wrong register free causes errors in unrelated code
block: # bug #15597
#[
Error: unhandled exception: 'sym' is not accessible using discriminant 'kind' of type 'TNode' [FieldDefect]
in /Users/timothee/git_clone/nim/Nim_prs/compiler/vm.nim(1176) rawExecute
in opcIndCall
in let prc = if not isClosure: bb.sym else: bb[0].sym
]#
proc bar2(head: string): string = "asdf"
proc gook(u1: int) = discard

type PathEntry = object
kind: int
path: string

iterator globOpt(): int =
var u1: int

gook(u1)
gook(u1)
gook(u1)
gook(u1)
gook(u1)
gook(u1)
gook(u1)
gook(u1)
gook(u1)
gook(u1)
gook(u1)
gook(u1)
gook(u1)
gook(u1)

var entry = PathEntry()
entry.path = bar2("")
if false:
echo "here2"

proc processAux(a: float) = discard

template bar(iter: untyped): untyped =
var ret: float
for x in iter: break
ret

proc main() =
processAux(bar(globOpt()))
static: main()

block: # ditto
# D20201024T133245
type Deque = object
proc initDeque2(initialSize: int = 4): Deque = Deque()
proc len2(a: Deque): int = 2
proc baz(dir: string): bool = true
proc bar2(head: string): string = "asdf"
proc bar3(path: var string) = path = path

type PathEntry = object
kind: int
path: string

proc initGlobOpt(dir: string, a1=false,a2=false,a3=false,a4=false): string = dir

iterator globOpt(dir: string): int =
var stack = initDeque2()
doAssert baz("")
let z = stack.len2
if stack.len2 >= 0:
var entry = PathEntry()
let current = if true: stack.len2 else: stack.len2
entry.path = bar2("")
bar3(entry.path)
if false:
echo "here2" # comment here => you get same error as https://github.com/nim-lang/Nim/issues/15704

proc processAux(a: float) = discard

template bar(iter: untyped): untyped =
var ret: float
for x in iter: break
ret
proc main() =
processAux(bar(globOpt(initGlobOpt("."))))
static: main()

block: # bug #15704
#[
Error: attempt to access a nil address kind: rkFloat
]#
type Deque = object
proc initDeque2(initialSize: int = 4): Deque = Deque()
proc len2(a: Deque): int = 2

proc baz(dir: string): bool = true
proc bar2(head: string): string = "asdf"
proc bar3(path: var string) = path = path

type PathEntry = object
kind: int
path: string
depth: int

proc initGlobOpt(dir: string, a1=false,a2=false,a3=false,a4=false): string =
dir

iterator globOpt(dir: string): int =
var stack = initDeque2()
doAssert baz("")
let z = stack.len2
var a5: int
if stack.len2 >= 0:
var entry = PathEntry()
if false:
echo "here"
let current = if true: stack.len2 else: stack.len2
entry.depth = 1
entry.path = bar2("")
bar3(entry.path)
proc processAux(a: float) = discard
template bar(iter: untyped): untyped =
var ret: float
for x in iter:
break
ret
const dir = "."
proc main() =
processAux(bar(globOpt(initGlobOpt(dir))))
static: main()

0 comments on commit 19e1dc5

Please sign in to comment.