diff options
author | Oscar Nihlgård <oscarnihlgard@gmail.com> | 2018-06-26 21:18:55 +0200 |
---|---|---|
committer | Oscar Nihlgård <oscarnihlgard@gmail.com> | 2018-06-26 21:25:27 +0200 |
commit | 236bc06b5f1a1a1fc4a711007aed0b60b6656a4f (patch) | |
tree | 1a80153e55305dd23e8e01cda36971d12f4fac63 | |
parent | d08b9eb6731a70504be6d856723fbc94dc7bd506 (diff) | |
download | Nim-236bc06b5f1a1a1fc4a711007aed0b60b6656a4f.tar.gz |
Improve vm support for ref types
-rw-r--r-- | compiler/vm.nim | 47 | ||||
-rw-r--r-- | compiler/vmdef.nim | 1 | ||||
-rw-r--r-- | tests/vm/tnilref.nim | 7 | ||||
-rw-r--r-- | tests/vm/tref.nim | 47 |
4 files changed, 79 insertions, 23 deletions
diff --git a/compiler/vm.nim b/compiler/vm.nim index 3e33e8256..b16eb0fd4 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -204,22 +204,14 @@ proc asgnComplex(x: var TFullReg, y: TFullReg) = of rkRegisterAddr: x.regAddr = y.regAddr of rkNodeAddr: x.nodeAddr = y.nodeAddr -proc putIntoNode(n: var PNode; x: TFullReg) = +proc writeField(n: var PNode, x: TFullReg) = case x.kind of rkNone: discard of rkInt: n.intVal = x.intVal of rkFloat: n.floatVal = x.floatVal - of rkNode: - if nfIsRef in x.node.flags: - n = x.node - else: - let destIsRef = nfIsRef in n.flags - n[] = x.node[] - # Ref-ness must be kept for the destination - if destIsRef: - n.flags.incl nfIsRef - of rkRegisterAddr: putIntoNode(n, x.regAddr[]) - of rkNodeAddr: n[] = x.nodeAddr[][] + of rkNode: n = x.node + of rkRegisterAddr: writeField(n, x.regAddr[]) + of rkNodeAddr: n = x.nodeAddr[] proc putIntoReg(dest: var TFullReg; n: PNode) = case n.kind @@ -498,9 +490,6 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = asgnComplex(regs[ra], regs[instr.regB]) of opcAsgnRef: asgnRef(regs[ra], regs[instr.regB]) - of opcRegToNode: - decodeB(rkNode) - putIntoNode(regs[ra].node, regs[rb]) of opcNodeToReg: let ra = instr.regA let rb = instr.regB @@ -559,7 +548,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = else: stackTrace(c, tos, pc, errIndexOutOfBounds) elif idx <% arr.len: - putIntoNode(arr.sons[idx], regs[rc]) + writeField(arr.sons[idx], regs[rc]) else: stackTrace(c, tos, pc, errIndexOutOfBounds) of opcLdObj: @@ -579,9 +568,9 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = if dest.kind == nkNilLit: stackTrace(c, tos, pc, errNilAccess) elif dest.sons[shiftedRb].kind == nkExprColonExpr: - putIntoNode(dest.sons[shiftedRb].sons[1], regs[rc]) + writeField(dest.sons[shiftedRb].sons[1], regs[rc]) else: - putIntoNode(dest.sons[shiftedRb], regs[rc]) + writeField(dest.sons[shiftedRb], regs[rc]) of opcWrStrIdx: decodeBC(rkNode) let idx = regs[rb].intVal.int @@ -624,9 +613,24 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = let ra = instr.regA let rc = instr.regC case regs[ra].kind - of rkNodeAddr: putIntoNode(regs[ra].nodeAddr[], regs[rc]) + of rkNodeAddr: + # XXX: Workaround for vmgen bug: + let n = regs[rc].regToNode + if (nfIsRef in regs[ra].nodeAddr[].flags or + regs[ra].nodeAddr[].kind == nkNilLit) and nfIsRef notin n.flags: + if regs[ra].nodeAddr[].kind == nkNilLit: + stackTrace(c, tos, pc, errNilAccess) + regs[ra].nodeAddr[][] = n[] + regs[ra].nodeAddr[].flags.incl nfIsRef + else: + regs[ra].nodeAddr[] = n of rkRegisterAddr: regs[ra].regAddr[] = regs[rc] - of rkNode: putIntoNode(regs[ra].node, regs[rc]) + of rkNode: + if regs[ra].node.kind == nkNilLit: + stackTrace(c, tos, pc, errNilAccess) + assert nfIsRef in regs[ra].node.flags + regs[ra].node[] = regs[rc].regToNode[] + regs[ra].node.flags.incl nfIsRef else: stackTrace(c, tos, pc, errNilAccess) of opcAddInt: decodeBC(rkInt) @@ -1211,6 +1215,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = of opcNBindSym: decodeBx(rkNode) regs[ra].node = copyTree(c.constants.sons[rbx]) + regs[ra].node.flags.incl nfIsRef of opcNChild: decodeBC(rkNode) let idx = regs[rc].intVal.int @@ -1572,7 +1577,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = var sym = newSym(k.TSymKind, getIdent(c.cache, name), c.module.owner, c.debug[pc]) incl(sym.flags, sfGenSym) regs[ra].node = newSymNode(sym) - + regs[ra].node.flags.incl nfIsRef of opcNccValue: decodeB(rkInt) let destKey = regs[rb].node.strVal diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index cec61ade5..f7466b392 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -36,7 +36,6 @@ type opcAsgnFloat, opcAsgnRef, opcAsgnComplex, - opcRegToNode, opcNodeToReg, opcLdArr, # a = b[c] diff --git a/tests/vm/tnilref.nim b/tests/vm/tnilref.nim new file mode 100644 index 000000000..5e27cf0cb --- /dev/null +++ b/tests/vm/tnilref.nim @@ -0,0 +1,7 @@ +discard """ + errormsg: "attempt to access a nil address" +""" + +static: + var s: ref int + s[] = 1 \ No newline at end of file diff --git a/tests/vm/tref.nim b/tests/vm/tref.nim index 517a67fb0..27b7bf313 100644 --- a/tests/vm/tref.nim +++ b/tests/vm/tref.nim @@ -9,4 +9,49 @@ static: b[5] = 'c' doAssert a[] == "Hellocworld" - doAssert b[] == "Hellocworld" \ No newline at end of file + doAssert b[] == "Hellocworld" + + proc notGlobal() = + var + a: ref string + b: ref string + new a + + a[] = "Hello world" + b = a + + b[5] = 'c' + doAssert a[] == "Hellocworld" + doAssert b[] == "Hellocworld" + notGlobal() + +static: # bug 6081 + block: + type Obj = object + field: ref int + var i: ref int + new(i) + var r = Obj(field: i) + var rr = r + r.field = nil + doAssert rr.field != nil + + proc foo() = # Proc to avoid special global logic + var s: seq[ref int] + var i: ref int + new(i) + s.add(i) + var head = s[0] + s[0] = nil + doAssert head != nil + + foo() + +static: + + block: # global alias + var s: ref int + new(s) + var ss = s + s[] = 1 + doAssert ss[] == 1 \ No newline at end of file |