remove dropbits in favour of destructive moves

This commit is contained in:
Andrii Riabushenko 2018-12-08 19:18:00 +00:00
commit 0fdd7629b4

View file

@ -128,8 +128,7 @@ type
g: ControlFlowGraph g: ControlFlowGraph
jumpTargets: IntSet jumpTargets: IntSet
topLevelVars: PNode topLevelVars: PNode
destroys: OrderedTable[int, tuple[dropBit: PSym, destroy_call: PNode]] destroys: PNode
# Symbol to destructor call table
graph: ModuleGraph graph: ModuleGraph
emptyNode: PNode emptyNode: PNode
otherRead: PNode otherRead: PNode
@ -322,28 +321,6 @@ proc genDestroy(c: Con; t: PType; dest: PNode): PNode =
proc addTopVar(c: var Con; v: PNode) = proc addTopVar(c: var Con; v: PNode) =
c.topLevelVars.add newTree(nkIdentDefs, v, c.emptyNode, c.emptyNode) c.topLevelVars.add newTree(nkIdentDefs, v, c.emptyNode, c.emptyNode)
proc dropBit(c: var Con; s: PSym): PSym =
result = c.destroys.getOrDefault(s.id).dropBit
assert result != nil
proc addDestructor(c: var Con; s: PSym; destructor_call: PNode, dropBit: PSym = nil) =
let alreadyIn = c.destroys.hasKeyOrPut(s.id, (dropBit, destructor_call))
if alreadyIn:
let lineInfo = if s.ast != nil: s.ast.info else: c.owner.info
internalError(c.graph.config, lineInfo, "Destructor call for sym " & s.name.s & " is already injected")
proc registerDropBit(c: var Con; s: PSym) =
let result = newSym(skTemp, getIdent(c.graph.cache, s.name.s & "_AliveBit"), c.owner, s.info)
result.typ = getSysType(c.graph, s.info, tyBool)
let trueVal = newIntTypeNode(nkIntLit, 1, result.typ)
c.topLevelVars.add newTree(nkIdentDefs, newSymNode result, c.emptyNode, trueVal)
# generate:
# if not sinkParam_AliveBit: `=destroy`(sinkParam)
let t = s.typ.skipTypes({tyGenericInst, tyAlias, tySink})
if t.destructor != nil:
c.addDestructor(s, newTree(nkIfStmt,
newTree(nkElifBranch, newSymNode result, genDestroy(c, t, newSymNode s))), result)
proc getTemp(c: var Con; typ: PType; info: TLineInfo): PNode = proc getTemp(c: var Con; typ: PType; info: TLineInfo): PNode =
let sym = newSym(skTemp, getIdent(c.graph.cache, ":tmpD"), c.owner, info) let sym = newSym(skTemp, getIdent(c.graph.cache, ":tmpD"), c.owner, info)
sym.typ = typ sym.typ = typ
@ -359,16 +336,6 @@ template recurse(n, dest) =
proc isSinkParam(s: PSym): bool {.inline.} = proc isSinkParam(s: PSym): bool {.inline.} =
result = s.kind == skParam and s.typ.kind == tySink result = s.kind == skParam and s.typ.kind == tySink
proc destructiveMoveSink(n: PNode; c: var Con): PNode =
# generate: (chckMove(sinkParam_AliveBit); sinkParam_AliveBit = false; sinkParam)
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
let bit = newSymNode dropBit(c, n.sym)
if optMoveCheck in c.owner.options:
result.add callCodegenProc(c.graph, "chckMove", bit.info, bit)
result.add newTree(nkAsgn, bit,
newIntTypeNode(nkIntLit, 0, getSysType(c.graph, n.info, tyBool)))
result.add n
proc genMagicCall(n: PNode; c: var Con; magicname: string; m: TMagic): PNode = proc genMagicCall(n: PNode; c: var Con; magicname: string; m: TMagic): PNode =
result = newNodeI(nkCall, n.info) result = newNodeI(nkCall, n.info)
result.add(newSymNode(createMagic(c.graph, magicname, m))) result.add(newSymNode(createMagic(c.graph, magicname, m)))
@ -433,14 +400,11 @@ proc pArg(arg: PNode; c: var Con; isSink: bool): PNode =
elif arg.kind in {nkBracket, nkObjConstr, nkTupleConstr, nkBracket, nkCharLit..nkFloat128Lit}: elif arg.kind in {nkBracket, nkObjConstr, nkTupleConstr, nkBracket, nkCharLit..nkFloat128Lit}:
discard "object construction to sink parameter: nothing to do" discard "object construction to sink parameter: nothing to do"
result = arg result = arg
elif arg.kind == nkSym and arg.sym.kind in InterestingSyms and isLastRead(arg, c): elif arg.kind == nkSym and (isSinkParam(arg.sym) or
# if x is a variable and it its last read we eliminate its arg.sym.kind in InterestingSyms and isLastRead(arg, c)):
# destructor invokation, but don't. We need to reset its memory # it is the last read be final consumption. We need to reset the memory
# to disable its destructor which we have not elided: # to disable the destructor which we have not elided:
result = destructiveMoveVar(arg, c) result = destructiveMoveVar(arg, c)
elif arg.kind == nkSym and isSinkParam(arg.sym):
# mark the sink parameter as used:
result = destructiveMoveSink(arg, c)
elif arg.kind in {nkBlockExpr, nkBlockStmt}: elif arg.kind in {nkBlockExpr, nkBlockStmt}:
result = copyNode(arg) result = copyNode(arg)
result.add arg[0] result.add arg[0]
@ -572,13 +536,11 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
ri2[i] = pArg(ri[i], c, isSink = true) ri2[i] = pArg(ri[i], c, isSink = true)
result.add ri2 result.add ri2
of nkSym: of nkSym:
if ri.sym.kind != skParam and isLastRead(ri, c): if isSinkParam(ri.sym) or (ri.sym.kind != skParam and isLastRead(ri, c)):
# Rule 3: `=sink`(x, z); wasMoved(z) # Rule 3: `=sink`(x, z); wasMoved(z)
result = genSink(c, dest.typ, dest, ri) var snk = genSink(c, dest.typ, dest, ri)
result.add p(ri, c) snk.add ri
elif isSinkParam(ri.sym): result = newTree(nkStmtList, snk, genMagicCall(ri, c, "wasMoved", mWasMoved))
result = genSink(c, dest.typ, dest, ri)
result.add destructiveMoveSink(ri, c)
else: else:
result = genCopy(c, dest.typ, dest, ri) result = genCopy(c, dest.typ, dest, ri)
result.add p(ri, c) result.add p(ri, c)
@ -607,7 +569,7 @@ proc p(n: PNode; c: var Con): PNode =
c.addTopVar v c.addTopVar v
# make sure it's destroyed at the end of the proc: # make sure it's destroyed at the end of the proc:
if not isUnpackedTuple(it[0].sym): if not isUnpackedTuple(it[0].sym):
c.addDestructor(v.sym, genDestroy(c, v.typ, v)) c.destroys.add genDestroy(c, v.typ, v)
if ri.kind != nkEmpty: if ri.kind != nkEmpty:
let r = moveOrCopy(v, ri, c) let r = moveOrCopy(v, ri, c)
result.add r result.add r
@ -633,7 +595,7 @@ proc p(n: PNode; c: var Con): PNode =
sinkExpr.add n sinkExpr.add n
result.add sinkExpr result.add sinkExpr
result.add tmp result.add tmp
c.addDestructor(tmp.sym, genDestroy(c, n.typ, tmp)) c.destroys.add genDestroy(c, n.typ, tmp)
else: else:
result = n result = n
of nkAsgn, nkFastAsgn: of nkAsgn, nkFastAsgn:
@ -655,7 +617,7 @@ proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode =
var c: Con var c: Con
c.owner = owner c.owner = owner
c.topLevelVars = newNodeI(nkVarSection, n.info) c.topLevelVars = newNodeI(nkVarSection, n.info)
c.destroys = initOrderedTable[int, (PSym, PNode)](32) c.destroys = newNodeI(nkStmtList, n.info)
c.graph = g c.graph = g
c.emptyNode = newNodeI(nkEmpty, n.info) c.emptyNode = newNodeI(nkEmpty, n.info)
let cfg = constructCfg(owner, n) let cfg = constructCfg(owner, n)
@ -670,16 +632,15 @@ proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode =
let params = owner.typ.n let params = owner.typ.n
for i in 1 ..< params.len: for i in 1 ..< params.len:
let param = params[i].sym let param = params[i].sym
if param.typ.kind == tySink: registerDropBit(c, param) if param.typ.kind == tySink:
c.destroys.add genDestroy(c, param.typ.skipTypes({tyGenericInst, tyAlias, tySink}), params[i])
let body = p(n, c) let body = p(n, c)
result = newNodeI(nkStmtList, n.info) result = newNodeI(nkStmtList, n.info)
if c.topLevelVars.len > 0: if c.topLevelVars.len > 0:
result.add c.topLevelVars result.add c.topLevelVars
if c.destroys.len > 0: if c.destroys.len > 0:
var destroy_list = newNodeI(nkStmtList, n.info) result.add newTryFinally(body, c.destroys)
for val in c.destroys.values:
destroy_list.add val.destroy_call
result.add newTryFinally(body, destroy_list)
else: else:
result.add body result.add body