# # # The Nim Compiler # (c) Copyright 2015 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # ## This module implements the write tracking analysis. Read my block post for ## a basic description of the algorithm and ideas. import idents, ast, astalgo, trees, renderer, msgs, types const debug = false type AssignToResult = enum asgnNil, # 'nil' is fine asgnNew, # 'new(result)' asgnOther # result = fooBar # not a 'new' --> 'result' might not 'new' NewLocation = enum newNone, newLit, newCall W = object # WriteTrackContext owner: PSym returnsNew: AssignToResult # assignments to 'result' markAsWrittenTo, markAsEscaping: PNode assignments: seq[(PNode, PNode)] # list of all assignments in this proc proc returnsNewExpr*(n: PNode): NewLocation = case n.kind of nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit, nkFloatLit..nkFloat64Lit, nkNilLit: result = newLit of nkExprEqExpr, nkExprColonExpr, nkHiddenStdConv, nkHiddenSubConv, nkStmtList, nkStmtListExpr, nkBlockStmt, nkBlockExpr, nkOfBranch, nkElifBranch, nkElse, nkExceptBranch, nkFinally, nkCast: result = returnsNewExpr(n.lastSon) of nkCurly, nkBracket, nkPar, nkObjConstr, nkClosure, nkIfExpr, nkIfStmt, nkWhenStmt, nkCaseStmt, nkTryStmt: result = newLit for i in ord(n.kind == nkObjConstr) .. check which parameter it may alias and mark these parameters # as dirty: possibleAliases(w, r) for a in r: if a.kind == skParam and a.owner == w.owner: incl(a.flags, sfWrittenTo) proc markEscaping(w: W) = # let p1 = p # let p2 = q # p2.x = call(..., p1, ...) for dest, src in items(w.assignments): var r: seq[PSym] = nil var info: set[RootInfo] allRoots(dest, r, info) if (r.len > 0) and (info != {} or src == w.markAsEscaping): possibleAliases(w, r) var destIsParam = false for a in r: if a.kind in {skResult, skParam} and a.owner == w.owner: destIsParam = true break if destIsParam: var victims: seq[PSym] = @[] allRoots(src, victims) possibleAliases(w, victims) for v in victims: if v.kind == skParam and v.owner == w.owner: incl(v.flags, sfEscapes) proc trackWrites*(owner: PSym; body: PNode) = var w: W w.owner = owner w.markAsWrittenTo = newNodeI(nkArgList, body.info) w.markAsEscaping = newNodeI(nkArgList, body.info) w.assignments = @[] deps(w, body) markDirty(w) markEscaping(w) if w.returnsNew != asgnOther and not isEmptyType(owner.typ.sons[0]) and containsGarbageCollectedRef(owner.typ.sons[0]): incl(owner.typ.flags, tfReturnsNew)