Improve vm support for ref types
This commit is contained in:
parent
d08b9eb673
commit
236bc06b5f
4 changed files with 79 additions and 23 deletions
|
|
@ -204,22 +204,14 @@ proc asgnComplex(x: var TFullReg, y: TFullReg) =
|
||||||
of rkRegisterAddr: x.regAddr = y.regAddr
|
of rkRegisterAddr: x.regAddr = y.regAddr
|
||||||
of rkNodeAddr: x.nodeAddr = y.nodeAddr
|
of rkNodeAddr: x.nodeAddr = y.nodeAddr
|
||||||
|
|
||||||
proc putIntoNode(n: var PNode; x: TFullReg) =
|
proc writeField(n: var PNode, x: TFullReg) =
|
||||||
case x.kind
|
case x.kind
|
||||||
of rkNone: discard
|
of rkNone: discard
|
||||||
of rkInt: n.intVal = x.intVal
|
of rkInt: n.intVal = x.intVal
|
||||||
of rkFloat: n.floatVal = x.floatVal
|
of rkFloat: n.floatVal = x.floatVal
|
||||||
of rkNode:
|
of rkNode: n = x.node
|
||||||
if nfIsRef in x.node.flags:
|
of rkRegisterAddr: writeField(n, x.regAddr[])
|
||||||
n = x.node
|
of rkNodeAddr: n = x.nodeAddr[]
|
||||||
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[][]
|
|
||||||
|
|
||||||
proc putIntoReg(dest: var TFullReg; n: PNode) =
|
proc putIntoReg(dest: var TFullReg; n: PNode) =
|
||||||
case n.kind
|
case n.kind
|
||||||
|
|
@ -498,9 +490,6 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
asgnComplex(regs[ra], regs[instr.regB])
|
asgnComplex(regs[ra], regs[instr.regB])
|
||||||
of opcAsgnRef:
|
of opcAsgnRef:
|
||||||
asgnRef(regs[ra], regs[instr.regB])
|
asgnRef(regs[ra], regs[instr.regB])
|
||||||
of opcRegToNode:
|
|
||||||
decodeB(rkNode)
|
|
||||||
putIntoNode(regs[ra].node, regs[rb])
|
|
||||||
of opcNodeToReg:
|
of opcNodeToReg:
|
||||||
let ra = instr.regA
|
let ra = instr.regA
|
||||||
let rb = instr.regB
|
let rb = instr.regB
|
||||||
|
|
@ -559,7 +548,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
else:
|
else:
|
||||||
stackTrace(c, tos, pc, errIndexOutOfBounds)
|
stackTrace(c, tos, pc, errIndexOutOfBounds)
|
||||||
elif idx <% arr.len:
|
elif idx <% arr.len:
|
||||||
putIntoNode(arr.sons[idx], regs[rc])
|
writeField(arr.sons[idx], regs[rc])
|
||||||
else:
|
else:
|
||||||
stackTrace(c, tos, pc, errIndexOutOfBounds)
|
stackTrace(c, tos, pc, errIndexOutOfBounds)
|
||||||
of opcLdObj:
|
of opcLdObj:
|
||||||
|
|
@ -579,9 +568,9 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
if dest.kind == nkNilLit:
|
if dest.kind == nkNilLit:
|
||||||
stackTrace(c, tos, pc, errNilAccess)
|
stackTrace(c, tos, pc, errNilAccess)
|
||||||
elif dest.sons[shiftedRb].kind == nkExprColonExpr:
|
elif dest.sons[shiftedRb].kind == nkExprColonExpr:
|
||||||
putIntoNode(dest.sons[shiftedRb].sons[1], regs[rc])
|
writeField(dest.sons[shiftedRb].sons[1], regs[rc])
|
||||||
else:
|
else:
|
||||||
putIntoNode(dest.sons[shiftedRb], regs[rc])
|
writeField(dest.sons[shiftedRb], regs[rc])
|
||||||
of opcWrStrIdx:
|
of opcWrStrIdx:
|
||||||
decodeBC(rkNode)
|
decodeBC(rkNode)
|
||||||
let idx = regs[rb].intVal.int
|
let idx = regs[rb].intVal.int
|
||||||
|
|
@ -624,9 +613,24 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
let ra = instr.regA
|
let ra = instr.regA
|
||||||
let rc = instr.regC
|
let rc = instr.regC
|
||||||
case regs[ra].kind
|
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 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)
|
else: stackTrace(c, tos, pc, errNilAccess)
|
||||||
of opcAddInt:
|
of opcAddInt:
|
||||||
decodeBC(rkInt)
|
decodeBC(rkInt)
|
||||||
|
|
@ -1211,6 +1215,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
of opcNBindSym:
|
of opcNBindSym:
|
||||||
decodeBx(rkNode)
|
decodeBx(rkNode)
|
||||||
regs[ra].node = copyTree(c.constants.sons[rbx])
|
regs[ra].node = copyTree(c.constants.sons[rbx])
|
||||||
|
regs[ra].node.flags.incl nfIsRef
|
||||||
of opcNChild:
|
of opcNChild:
|
||||||
decodeBC(rkNode)
|
decodeBC(rkNode)
|
||||||
let idx = regs[rc].intVal.int
|
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])
|
var sym = newSym(k.TSymKind, getIdent(c.cache, name), c.module.owner, c.debug[pc])
|
||||||
incl(sym.flags, sfGenSym)
|
incl(sym.flags, sfGenSym)
|
||||||
regs[ra].node = newSymNode(sym)
|
regs[ra].node = newSymNode(sym)
|
||||||
|
regs[ra].node.flags.incl nfIsRef
|
||||||
of opcNccValue:
|
of opcNccValue:
|
||||||
decodeB(rkInt)
|
decodeB(rkInt)
|
||||||
let destKey = regs[rb].node.strVal
|
let destKey = regs[rb].node.strVal
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,6 @@ type
|
||||||
opcAsgnFloat,
|
opcAsgnFloat,
|
||||||
opcAsgnRef,
|
opcAsgnRef,
|
||||||
opcAsgnComplex,
|
opcAsgnComplex,
|
||||||
opcRegToNode,
|
|
||||||
opcNodeToReg,
|
opcNodeToReg,
|
||||||
|
|
||||||
opcLdArr, # a = b[c]
|
opcLdArr, # a = b[c]
|
||||||
|
|
|
||||||
7
tests/vm/tnilref.nim
Normal file
7
tests/vm/tnilref.nim
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
discard """
|
||||||
|
errormsg: "attempt to access a nil address"
|
||||||
|
"""
|
||||||
|
|
||||||
|
static:
|
||||||
|
var s: ref int
|
||||||
|
s[] = 1
|
||||||
|
|
@ -10,3 +10,48 @@ static:
|
||||||
b[5] = 'c'
|
b[5] = 'c'
|
||||||
doAssert a[] == "Hellocworld"
|
doAssert a[] == "Hellocworld"
|
||||||
doAssert b[] == "Hellocworld"
|
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
|
||||||
Loading…
Add table
Add a link
Reference in a new issue