diff options
-rw-r--r-- | compiler/vm.nim | 27 | ||||
-rw-r--r-- | compiler/vmdef.nim | 2 | ||||
-rw-r--r-- | compiler/vmgen.nim | 22 | ||||
-rw-r--r-- | tests/vm/taddrof.nim | 110 | ||||
-rw-r--r-- | tests/vm/tanonproc.nim | 2 | ||||
-rw-r--r-- | tests/vm/tmitems_vm.nim | 4 |
6 files changed, 156 insertions, 11 deletions
diff --git a/compiler/vm.nim b/compiler/vm.nim index 52faeaf38..ce473c12a 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -606,6 +606,17 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = regs[ra].node = src.sons[idx] else: stackTrace(c, tos, pc, formatErrorIndexBound(idx, src.len-1)) + of opcLdArrAddr: + # a = addr(b[c]) + decodeBC(rkNodeAddr) + if regs[rc].intVal > high(int): + stackTrace(c, tos, pc, formatErrorIndexBound(regs[rc].intVal, high(int))) + let idx = regs[rc].intVal.int + let src = if regs[rb].kind == rkNode: regs[rb].node else: regs[rb].nodeAddr[] + if src.kind notin {nkEmpty..nkTripleStrLit} and idx <% src.len: + regs[ra].nodeAddr = addr src.sons[idx] + else: + stackTrace(c, tos, pc, formatErrorIndexBound(idx, src.len-1)) of opcLdStrIdx: decodeBC(rkInt) let idx = regs[rc].intVal.int @@ -643,9 +654,25 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = else: let n = src.sons[rc] regs[ra].node = n + of opcLdObjAddr: + # a = addr(b.c) + decodeBC(rkNodeAddr) + let src = if regs[rb].kind == rkNode: regs[rb].node else: regs[rb].nodeAddr[] + case src.kind + of nkEmpty..nkNilLit: + stackTrace(c, tos, pc, errNilAccess) + of nkObjConstr: + let n = src.sons[rc + 1] + if n.kind == nkExprColonExpr: + regs[ra].nodeAddr = addr n.sons[1] + else: + regs[ra].nodeAddr = addr src.sons[rc + 1] + else: + regs[ra].nodeAddr = addr src.sons[rc] of opcWrObj: # a.b = c decodeBC(rkNode) + assert regs[ra].node != nil let shiftedRb = rb + ord(regs[ra].node.kind == nkObjConstr) let dest = regs[ra].node if dest.kind == nkNilLit: diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index 54c18b03a..06e309678 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -42,8 +42,10 @@ type opcNodeToReg, opcLdArr, # a = b[c] + opcLdArrAddr, # a = addr(b[c]) opcWrArr, # a[b] = c opcLdObj, # a = b.c + opcLdObjAddr, # a = addr(b.c) opcWrObj, # a.b = c opcAddrReg, opcAddrNode, diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index cd66e3301..668c496c6 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -1417,12 +1417,11 @@ proc genAddr(c: PCtx, n: PNode, dest: var TDest, flags: TGenFlags) = gen(c, m, dest, flags) return - let af = if n[0].kind in {nkBracketExpr, nkDotExpr, nkCheckedFieldExpr}: {gfNode} - else: {gfNodeAddr} - let newflags = flags-{gfNode, gfNodeAddr}+af + let newflags = flags-{gfNode}+{gfNodeAddr} - if isGlobal(n.sons[0]): - gen(c, n.sons[0], dest, flags+af) + if isGlobal(n.sons[0]) or n[0].kind in {nkDotExpr, nkCheckedFieldExpr, nkBracketExpr}: + # checking for this pattern: addr(obj.field) / addr(array[i]) + gen(c, n.sons[0], dest, newflags) else: let tmp = c.genx(n.sons[0], newflags) if dest < 0: dest = c.getTemp(n.typ) @@ -1663,7 +1662,9 @@ proc genArrAccessOpcode(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode; let a = c.genx(n.sons[0], flags) let b = c.genIndex(n.sons[1], n.sons[0].typ) if dest < 0: dest = c.getTemp(n.typ) - if needsRegLoad(): + if opc == opcLdArr and {gfNodeAddr} * flags != {}: + c.gABC(n, opcLdArrAddr, dest, a, b) + elif needsRegLoad(): var cc = c.getTemp(n.typ) c.gABC(n, opc, cc, a, b) c.gABC(n, opcNodeToReg, dest, cc) @@ -1679,7 +1680,9 @@ proc genObjAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) = let a = c.genx(n.sons[0], flags) let b = genField(c, n.sons[1]) if dest < 0: dest = c.getTemp(n.typ) - if needsRegLoad(): + if {gfNodeAddr} * flags != {}: + c.gABC(n, opcLdObjAddr, dest, a, b) + elif needsRegLoad(): var cc = c.getTemp(n.typ) c.gABC(n, opcLdObj, cc, a, b) c.gABC(n, opcNodeToReg, dest, cc) @@ -1733,7 +1736,10 @@ proc genCheckedObjAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) = # Load the content now if dest < 0: dest = c.getTemp(n.typ) let fieldPos = genField(c, field) - if needsRegLoad(): + + if {gfNodeAddr} * flags != {}: + c.gABC(n, opcLdObjAddr, dest, objR, fieldPos) + elif needsRegLoad(): var cc = c.getTemp(accessExpr.typ) c.gABC(n, opcLdObj, cc, objR, fieldPos) c.gABC(n, opcNodeToReg, dest, cc) diff --git a/tests/vm/taddrof.nim b/tests/vm/taddrof.nim new file mode 100644 index 000000000..bbe9345d2 --- /dev/null +++ b/tests/vm/taddrof.nim @@ -0,0 +1,110 @@ +discard """ +nimout: ''' +true +true +[nil, nil, nil, nil] +[MyObjectRef(123, 321), nil, nil, nil] +['A', '\x00', '\x00', '\x00'] +MyObjectRef(123, 321) +(key: 8, val: 0) +''' +output: ''' +true +true +[nil, nil, nil, nil] +[MyObjectRef(123, 321), nil, nil, nil] +['A', '\x00', '\x00', '\x00'] +MyObjectRef(123, 321) +''' +""" + +type + MyObjectRef = ref object + a,b: int + + MyContainerObject = ref object + member: MyObjectRef + + MySuperContainerObject = ref object + member: MyContainerObject + arr: array[4, MyObjectRef] + + MyOtherObject = ref object + case kind: bool + of true: + member: MyObjectRef + else: + discard + +proc `$`(arg: MyObjectRef): string = + result = "MyObjectRef(" + result.addInt arg.a + result.add ", " + result.addInt arg.b + result.add ")" + +proc foobar(dst: var MyObjectRef) = + dst = new(MyObjectRef) + dst.a = 123 + dst.b = 321 + +proc changeChar(c: var char) = + c = 'A' + +proc test() = + # when it comes from a var, it works + var y: MyObjectRef + foobar(y) + echo y != nil + # when it comes from a member, it fails on VM + var x = new(MyContainerObject) + foobar(x.member) + echo x.member != nil + + # when it comes from an array, it fails on VM + var arr: array[4, MyObjectRef] + echo arr + foobar(arr[0]) + echo arr + + var arr2: array[4, char] + changeChar(arr2[0]) + echo arr2 + + + var z = MyOtherObject(kind: true) + foobar(z.member) + echo z.member + + # this still doesn't work + # var sc = new(MySuperContainerObject) + # sc.member = new(MyContainerObject) + # foobar(sc.member.member) + # echo sc.member.member + # foobar(sc.arr[1]) + # echo sc.arr + + #var str = "---" + #changeChar(str[1]) + #echo str + +test() +static: + test() + +type T = object + f: seq[tuple[key, val: int]] + +proc foo(s: var seq[tuple[key, val: int]]; i: int) = + s[i].key = 4*i + # r4 = addr(s[i]) + # r4[0] = 4*i + +proc bar() = + var s: T + s.f = newSeq[tuple[key, val: int]](3) + foo(s.f, 2) + echo s.f[2] + +static: + bar() diff --git a/tests/vm/tanonproc.nim b/tests/vm/tanonproc.nim index a89b53e83..1176c104e 100644 --- a/tests/vm/tanonproc.nim +++ b/tests/vm/tanonproc.nim @@ -42,7 +42,7 @@ proc getOrElse[T](o: Option[T], def: T): T = proc quoteStr(s: string): Option[string] = s.some.notEmpty.map(v => "`" & v & "`") -macro str(s: string): typed = +macro str(s: string): void = let x = s.strVal let y = quoteStr(x) let sn = newStrLitNode(y.getOrElse("NONE")) diff --git a/tests/vm/tmitems_vm.nim b/tests/vm/tmitems_vm.nim index 87835d1cd..787d52cc6 100644 --- a/tests/vm/tmitems_vm.nim +++ b/tests/vm/tmitems_vm.nim @@ -7,7 +7,7 @@ discard """ # bug #3731 var list {.compileTime.} = newSeq[int]() -macro calc*(): typed = +macro calc*(): void = list.add(1) for c in list.mitems: c = 13 @@ -19,7 +19,7 @@ calc() # bug #3859 import macros -macro m: typed = +macro m: void = var s = newseq[NimNode](3) # var s: array[3,NimNode] # not working either for i in 0..<s.len: s[i] = newLit(3) # works |