# # # 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. ## The algorithm operates in 2 phases: ## ## * Collecting information about assignments (and pass-by-var calls). ## * Computing an aliasing relation based on the assignments. This relation ## is then used to compute the 'writes' and 'escapes' effects. import intsets, idents, ast, trees, msgs, types, options, lineinfos 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 RootInfo = enum rootIsResultOrParam, rootIsHeapAccess, rootIsSym, markAsWrittenTo, markAsEscaping Assignment = object # \ # Note that the transitive closures MUST be computed in # phase 2 of the algorithm. dest, src: seq[ptr TSym] # we use 'ptr' here to save RC ops and GC cycles destNoTc, srcNoTc: int # length of 'dest', 'src' without the # transitive closure destInfo: set[RootInfo] info: TLineInfo W = object # WriteTrackContext owner: PSym returnsNew: AssignToResult # assignments to 'result' assignments: seq[Assignment] # list of all assignments in this proc proc allRoots(n: PNode; result: var seq[ptr TSym]; info: var set[RootInfo]) = case n.kind of nkSym: if n.sym.kind in {skParam, skVar, skTemp, skLet, skResult, skForVar}: if n.sym.kind in {skResult, skParam}: incl(info, rootIsResultOrParam) result.add(cast[ptr TSym](n.sym)) of nkHiddenDeref, nkDerefExpr: incl(info, rootIsHeapAccess) allRoots(n[0], result, info) of nkDotExpr, nkBracketExpr, nkCheckedFieldExpr, nkHiddenAddr, nkObjUpConv, nkObjDownConv: allRoots(n[0], result, info) of nkExprEqExpr, nkExprColonExpr, nkHiddenStdConv, nkHiddenSubConv, nkConv, nkStmtList, nkStmtListExpr, nkBlockStmt, nkBlockExpr, nkOfBranch, nkElifBranch, nkElse, nkExceptBranch, nkFinally, nkCast: allRoots(n.lastSon, result, info) of nkCallKinds: if getMagic(n) == mSlice: allRoots(n[1], result, info) else: # we do significantly better here by using the available escape # information: if n[0].typ.isNil: return var typ = n[0].typ if typ != nil: typ = skipTypes(typ, abstractInst) if typ.kind != tyProc: typ = nil else: assert(typ.len == typ.n.len) for i in 1.. 0 and a.dest[0] == x and rootIsSym in a.destInfo: # x = f(..., y, ....) for i in 0..