summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/vmgen.nim6
-rw-r--r--tests/vm/tvmmisc.nim130
2 files changed, 134 insertions, 2 deletions
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index 5ba15bb2b..f084ab7ba 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -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:
@@ -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:
diff --git a/tests/vm/tvmmisc.nim b/tests/vm/tvmmisc.nim
index 61a187faf..f05bb6dec 100644
--- a/tests/vm/tvmmisc.nim
+++ b/tests/vm/tvmmisc.nim
@@ -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()