diff options
author | Andrii Riabushenko <cdome@bk.ru> | 2018-12-05 21:33:15 +0000 |
---|---|---|
committer | Andrii Riabushenko <cdome@bk.ru> | 2018-12-05 21:33:15 +0000 |
commit | 69347f6c95b35e8969cf650b59644b20ef1528de (patch) | |
tree | 97a6d1dfa1d17152dd713ab5165842510791cef2 /compiler | |
parent | 938d3ffad7cd3b76692c81ae983c3ce82b10c2d1 (diff) | |
download | Nim-69347f6c95b35e8969cf650b59644b20ef1528de.tar.gz |
implement everything
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/ast.nim | 2 | ||||
-rw-r--r-- | compiler/ccgexprs.nim | 8 | ||||
-rw-r--r-- | compiler/destroyer.nim | 101 | ||||
-rw-r--r-- | compiler/semexprs.nim | 3 |
4 files changed, 47 insertions, 67 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 7cf35450b..2b595aee1 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -627,7 +627,7 @@ type mIsPartOf, mAstToStr, mParallel, mSwap, mIsNil, mArrToSeq, mCopyStr, mCopyStrLast, mNewString, mNewStringOfCap, mParseBiggestFloat, - mMove, mWasMoved, mDestroy, + mMove, mDestroy, mReset, mArray, mOpenArray, mRange, mSet, mSeq, mOpt, mVarargs, mRef, mPtr, mVar, mDistinct, mVoid, mTuple, diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 34836d843..bf1494b3d 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1901,13 +1901,6 @@ proc binaryFloatArith(p: BProc, e: PNode, d: var TLoc, m: TMagic) = proc skipAddr(n: PNode): PNode = result = if n.kind in {nkAddr, nkHiddenAddr}: n[0] else: n -proc genWasMoved(p: BProc; n: PNode) = - var a: TLoc - initLocExpr(p, n[1].skipAddr, a) - resetLoc(p, a) - #linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n", - # addrLoc(p.config, a), getTypeDesc(p.module, a.t)) - proc genMove(p: BProc; n: PNode; d: var TLoc) = if d.k == locNone: getTemp(p, n.typ, d) var a: TLoc @@ -2046,7 +2039,6 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = initLocExpr(p, e.sons[2], b) genDeepCopy(p, a, b) of mDotDot, mEqCString: genCall(p, e, d) - of mWasMoved: genWasMoved(p, e) of mMove: genMove(p, e, d) of mDestroy: discard "ignore calls to the default destructor" of mSlice: diff --git a/compiler/destroyer.nim b/compiler/destroyer.nim index 352b4aaad..4703c31dd 100644 --- a/compiler/destroyer.nim +++ b/compiler/destroyer.nim @@ -100,12 +100,12 @@ Rule Pattern Transformed into finally: `=destroy`(x) 1.2 var x: sink T; stmts var x: sink T; stmts; ensureEmpty(x) 2 x = f() `=sink`(x, f()) -3 x = lastReadOf z `=sink`(x, z); wasMoved(z) +3 x = lastReadOf z `=sink`(x, z); 4.1 y = sinkParam `=sink`(y, sinkParam) 4.2 x = y `=`(x, y) # a copy 5.1 f_sink(g()) f_sink(g()) 5.2 f_sink(y) f_sink(copy y); # copy unless we can see it's the last read -5.3 f_sink(move y) f_sink(y); wasMoved(y) # explicit moves empties 'y' +5.3 f_sink(move y) f_sink(y); # explicit moves empties 'y' 5.4 f_noSink(g()) var tmp = bitwiseCopy(g()); f(tmp); `=destroy`(tmp) Remarks: Rule 1.2 is not yet implemented because ``sink`` is currently @@ -116,7 +116,7 @@ Remarks: Rule 1.2 is not yet implemented because ``sink`` is currently import intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees, - strutils, options, dfa, lowerings, tables, modulegraphs, + strutils, options, dfa, lowerings, tables, modulegraphs, msgs, lineinfos, parampatterns const @@ -127,20 +127,13 @@ type owner: PSym g: ControlFlowGraph jumpTargets: IntSet - tmpObj: PType - tmp: PSym - destroys, topLevelVars: PNode + topLevelVars: PNode + destroys: OrderedTable[int, tuple[enabled: bool, destroy_call: PNode]] # Symbol to destructor table toDropBit: Table[int, PSym] graph: ModuleGraph emptyNode: PNode otherRead: PNode -proc getTemp(c: var Con; typ: PType; info: TLineInfo): PNode = - # XXX why are temps fields in an object here? - let f = newSym(skField, getIdent(c.graph.cache, ":d" & $c.tmpObj.n.len), c.owner, info) - f.typ = typ - rawAddField c.tmpObj, f - result = rawDirectAccess(c.tmp, f) proc isHarmlessVar*(s: PSym; c: Con): bool = # 's' is harmless if it used only once and its @@ -333,6 +326,22 @@ proc dropBit(c: var Con; s: PSym): PSym = result = c.toDropBit.getOrDefault(s.id) assert result != nil +proc addDestructor(c: var Con; s: PSym; destructor_call: PNode) = + let alreadyIn = c.destroys.hasKeyOrPut(s.id, (true, 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 disableDestructor(c: var Con; s: PSym) = + ## disable destructor, but do not delete such that it can be enabled back again later + c.destroys.with_value(s.id, value): + value.enabled = false + +proc enableDestructor(c: var Con; s: PSym) = + ## if destructor does not exist then ignore, otherwise make sure destructor is enabled + c.destroys.with_value(s.id, value): + value.enabled = true + 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) @@ -343,8 +352,14 @@ proc registerDropBit(c: var Con; s: PSym) = # if not sinkParam_AliveBit: `=destroy`(sinkParam) let t = s.typ.skipTypes({tyGenericInst, tyAlias, tySink}) if t.destructor != nil: - c.destroys.add newTree(nkIfStmt, - newTree(nkElifBranch, newSymNode result, genDestroy(c, t, newSymNode s))) + c.addDestructor(s, newTree(nkIfStmt, + newTree(nkElifBranch, newSymNode result, genDestroy(c, t, newSymNode s)))) + +proc getTemp(c: var Con; typ: PType; info: TLineInfo): PNode = + let sym = newSym(skTemp, getIdent(c.graph.cache, ":tmpD"), c.owner, info) + sym.typ = typ + result = newSymNode(sym) + c.addTopVar(result) proc p(n: PNode; c: var Con): PNode @@ -370,31 +385,6 @@ proc genMagicCall(n: PNode; c: var Con; magicname: string; m: TMagic): PNode = result.add(newSymNode(createMagic(c.graph, magicname, m))) result.add n -proc genWasMoved(n: PNode; c: var Con): PNode = - # The mWasMoved builtin does not take the address. - result = genMagicCall(n, c, "wasMoved", mWasMoved) - -proc destructiveMoveVar(n: PNode; c: var Con): PNode = - # generate: (let tmp = v; reset(v); tmp) - # XXX: Strictly speaking we can only move if there is a ``=sink`` defined - # or if no ``=sink`` is defined and also no assignment. - result = newNodeIT(nkStmtListExpr, n.info, n.typ) - - var temp = newSym(skLet, getIdent(c.graph.cache, "blitTmp"), c.owner, n.info) - temp.typ = n.typ - var v = newNodeI(nkLetSection, n.info) - let tempAsNode = newSymNode(temp) - - var vpart = newNodeI(nkIdentDefs, tempAsNode.info, 3) - vpart.sons[0] = tempAsNode - vpart.sons[1] = c.emptyNode - vpart.sons[2] = n - add(v, vpart) - - result.add v - result.add genWasMoved(n, c) - result.add tempAsNode - proc passCopyToSink(n: PNode; c: var Con): PNode = result = newNodeIT(nkStmtListExpr, n.info, n.typ) let tmp = getTemp(c, n.typ, n.info) @@ -415,7 +405,7 @@ proc pArg(arg: PNode; c: var Con; isSink: bool): PNode = # typ is nil if we are in if/case expr branch with noreturn if arg_part.typ == nil: p(arg_part, c) else: pArg(arg_part, c, isSink) - + if isSink: if arg.kind in nkCallKinds: # recurse but skip the call expression in order to prevent @@ -431,9 +421,9 @@ proc pArg(arg: PNode; c: var Con; isSink: bool): PNode = result = arg elif arg.kind == nkSym and arg.sym.kind in InterestingSyms and isLastRead(arg, c): # if x is a variable and it its last read we eliminate its - # destructor invokation, but don't. We need to reset its memory - # to disable its destructor which we have not elided: - result = destructiveMoveVar(arg, c) + # destructor invocation + c.disableDestructor(arg.sym) + result = arg elif arg.kind == nkSym and isSinkParam(arg.sym): # mark the sink parameter as used: result = destructiveMoveSink(arg, c) @@ -566,9 +556,8 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode = of nkSym: if ri.sym.kind != skParam and isLastRead(ri, c): # Rule 3: `=sink`(x, z); wasMoved(z) - var snk = genSink(c, dest.typ, dest, ri) - snk.add p(ri, c) - result = newTree(nkStmtList, snk, genMagicCall(ri, c, "wasMoved", mWasMoved)) + result = genSink(c, dest.typ, dest, ri) + result.add p(ri, c) elif isSinkParam(ri.sym): result = genSink(c, dest.typ, dest, ri) result.add destructiveMoveSink(ri, c) @@ -599,7 +588,7 @@ proc p(n: PNode; c: var Con): PNode = # move the variable declaration to the top of the frame: c.addTopVar v # make sure it's destroyed at the end of the proc: - c.destroys.add genDestroy(c, v.typ, v) + c.addDestructor(v.sym, genDestroy(c, v.typ, v)) if ri.kind != nkEmpty: let r = moveOrCopy(v, ri, c) result.add r @@ -625,12 +614,13 @@ proc p(n: PNode; c: var Con): PNode = sinkExpr.add n result.add sinkExpr result.add tmp - c.destroys.add genDestroy(c, n.typ, tmp) + c.addDestructor(tmp.sym, genDestroy(c, n.typ, tmp)) else: result = n of nkAsgn, nkFastAsgn: if hasDestructor(n[0].typ): result = moveOrCopy(n[0], n[1], c) + c.enableDestructor(n[0].sym) else: result = copyNode(n) recurse(n, result) @@ -646,12 +636,9 @@ proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode = # echo "injecting into ", n var c: Con c.owner = owner - c.tmp = newSym(skTemp, getIdent(g.cache, ":d"), owner, n.info) - c.tmpObj = createObj(g, owner, n.info) - c.tmp.typ = c.tmpObj - c.destroys = newNodeI(nkStmtList, n.info) c.topLevelVars = newNodeI(nkVarSection, n.info) - c.toDropBit = initTable[int, PSym]() + c.toDropBit = initTable[int, PSym](16) + c.destroys = initOrderedTable[int, (bool, PNode)](16) c.graph = g c.emptyNode = newNodeI(nkEmpty, n.info) let cfg = constructCfg(owner, n) @@ -668,13 +655,15 @@ proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode = let param = params[i].sym if param.typ.kind == tySink: registerDropBit(c, param) let body = p(n, c) - if c.tmp.typ.n.len > 0: - c.addTopVar(newSymNode c.tmp) result = newNodeI(nkStmtList, n.info) if c.topLevelVars.len > 0: result.add c.topLevelVars if c.destroys.len > 0: - result.add newTryFinally(body, c.destroys) + var destroy_list = newNodeI(nkStmtList, n.info) + for val in c.destroys.values: + if val.enabled: + destroy_list.add val.destroy_call + result.add newTryFinally(body, destroy_list) else: result.add body diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 669862c56..517356434 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -614,8 +614,7 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) = const FakeVarParams = {mNew, mNewFinalize, mInc, ast.mDec, mIncl, mExcl, mSetLengthStr, mSetLengthSeq, mAppendStrCh, mAppendStrStr, mSwap, - mAppendSeqElem, mNewSeq, mReset, mShallowCopy, mDeepCopy, mMove, - mWasMoved} + mAppendSeqElem, mNewSeq, mReset, mShallowCopy, mDeepCopy, mMove} # get the real type of the callee # it may be a proc var with a generic alias type, so we skip over them |