summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/writetracking.nim146
1 files changed, 61 insertions, 85 deletions
diff --git a/compiler/writetracking.nim b/compiler/writetracking.nim
index cf9ad91cc..2589959e8 100644
--- a/compiler/writetracking.nim
+++ b/compiler/writetracking.nim
@@ -42,7 +42,7 @@ proc returnsNewExpr*(n: PNode): NewLocation =
   of nkCurly, nkBracket, nkPar, nkObjConstr, nkClosure,
       nkIfExpr, nkIfStmt, nkWhenStmt, nkCaseStmt, nkTryStmt:
     result = newLit
-    for i in 0 .. <n.len:
+    for i in ord(n.kind == nkObjConstr) .. <n.len:
       let x = returnsNewExpr(n.sons[i])
       case x
       of newNone: return newNone
@@ -54,36 +54,6 @@ proc returnsNewExpr*(n: PNode): NewLocation =
   else:
     result = newNone
 
-proc root(owner: PSym; n: PNode; heapAccess: var bool): PSym =
-  ## returns 'nil' if the 'root' could not be detected.
-  case n.kind
-  of nkSym:
-    result = n.sym
-  of nkHiddenDeref, nkDerefExpr:
-    result = root(owner, n.sons[0], heapAccess)
-    heapAccess = true
-  of nkHiddenAddr, nkObjUpConv, nkObjDownConv,
-      nkDotExpr, nkBracketExpr, nkCheckedFieldExpr:
-    result = root(owner, n.sons[0], heapAccess)
-  of nkHiddenStdConv, nkHiddenSubConv, nkConv, nkStmtList, nkStmtListExpr,
-      nkBlockStmt, nkBlockExpr, nkCast:
-    result = root(owner, n.lastSon, heapAccess)
-  of nkCallKinds:
-    # builtin slice keeps lvalue-ness:
-    if getMagic(n) == mSlice:
-      result = root(owner, n.sons[1], heapAccess)
-      heapAccess = true
-    else:
-      # 'p().foo = x' --> treat as  'let tmp = p(); tmp.foo = x'
-      result = newSym(skTemp, getIdent(":tmp"), owner, n.sons[0].info)
-      #result.typ = n.sons[0].typ.sons[0]
-      #result.ast = n.sons[0]
-      # XXX
-  of nkPar:
-    localError(n.info, "writeSetAnalysis: too implement")
-  else:
-    discard
-
 proc deps(w: var W; dest, src: PNode) =
   # let x = (localA, localB)
   # compute 'returnsNew' property:
@@ -141,20 +111,32 @@ proc deps(w: var W; n: PNode) =
       else:
         depsArgs(w, n)
 
-proc allRoots(n: PNode; result: var seq[PSym]) =
+type
+  RootInfo = enum
+    rootIsResultOrParam,
+    rootIsHeapAccess
+
+proc allRoots(n: PNode; result: var seq[PSym]; info: var set[RootInfo]) =
   case n.kind
   of nkSym:
-    if n.sym notin result: result.add n.sym
-  of nkDotExpr, nkBracketExpr, nkHiddenDeref, nkDerefExpr, nkCheckedFieldExpr,
+    if n.sym.kind in {skParam, skVar, skTemp, skLet, skResult, skForVar}:
+      if result.isNil: result = @[]
+      if n.sym notin result:
+        if n.sym.kind in {skResult, skParam}: incl(info, rootIsResultOrParam)
+        result.add n.sym
+  of nkHiddenDeref, nkDerefExpr:
+    incl(info, rootIsHeapAccess)
+    allRoots(n.sons[0], result, info)
+  of nkDotExpr, nkBracketExpr, nkCheckedFieldExpr,
       nkHiddenAddr, nkObjUpConv, nkObjDownConv:
-    allRoots(n.sons[0], result)
+    allRoots(n.sons[0], result, info)
   of nkExprEqExpr, nkExprColonExpr, nkHiddenStdConv, nkHiddenSubConv, nkConv,
       nkStmtList, nkStmtListExpr, nkBlockStmt, nkBlockExpr, nkOfBranch,
       nkElifBranch, nkElse, nkExceptBranch, nkFinally, nkCast:
-    allRoots(n.lastSon, result)
+    allRoots(n.lastSon, result, info)
   of nkCallKinds:
     if getMagic(n) == mSlice:
-      allRoots(n.sons[1], result)
+      allRoots(n.sons[1], result, info)
     else:
       # we do significantly better here by using the available escape
       # information:
@@ -172,12 +154,16 @@ proc allRoots(n: PNode; result: var seq[PSym]) =
           let paramType = typ.n.sons[i]
           if paramType.typ.isCompileTimeOnly: continue
           if sfEscapes in paramType.sym.flags or paramType.typ.kind == tyVar:
-            allRoots(it, result)
+            allRoots(it, result, info)
         else:
-          allRoots(it, result)
+          allRoots(it, result, info)
   else:
     for i in 0..<n.safeLen:
-      allRoots(n.sons[i], result)
+      allRoots(n.sons[i], result, info)
+
+proc allRoots(n: PNode; result: var seq[PSym]) =
+  var dummy: set[RootInfo]
+  allRoots(n, result, dummy)
 
 proc hasSym(n: PNode; x: PSym): bool =
   when false:
@@ -187,9 +173,9 @@ proc hasSym(n: PNode; x: PSym): bool =
       for i in 0..safeLen(n)-1:
         if hasSym(n.sons[i], x): return true
   else:
-    var tmp: seq[PSym] = @[]
+    var tmp: seq[PSym]
     allRoots(n, tmp)
-    result = x in tmp
+    result = not tmp.isNil and x in tmp
 
 when debug:
   proc `$`*(x: PSym): string = x.name.s
@@ -204,15 +190,12 @@ proc possibleAliases(w: W; result: var seq[PSym]) =
     inc todo
     when debug:
       if w.owner.name.s == "m3": echo "select ", x, " ", todo, " ", result.len
-    var dummy = false
     for dest, src in items(w.assignments):
       if src.hasSym(x):
         # dest = f(..., s, ...)
-        let r = root(w.owner, dest, dummy)
-        if r != nil and r notin result:
-          result.add r
-          when debug:
-            if w.owner.name.s == "m3": echo "A ", result
+        allRoots(dest, result)
+        when debug:
+          if w.owner.name.s == "m3": echo "A ", result
       elif dest.kind == nkSym and dest.sym == x:
         # s = f(..., x, ....)
         allRoots(src, result)
@@ -222,54 +205,47 @@ proc possibleAliases(w: W; result: var seq[PSym]) =
         when debug:
           if w.owner.name.s == "m3": echo "C ", x, " ", todo, " ", result.len
 
-proc possibleAliases(w: W; s: PSym): seq[PSym] =
-  result = @[s]
-  possibleAliases(w, result)
-
 proc markDirty(w: W) =
   for dest, src in items(w.assignments):
-    var heapAccess = src == w.markAsWrittenTo
-    let r = root(w.owner, dest, heapAccess)
+    var r: seq[PSym] = nil
+    var info: set[RootInfo]
+    allRoots(dest, r, info)
     when debug:
       if w.owner.info ?? "temp18":
         echo "ASGN ", dest,  " = ", src, " |", heapAccess, " ", r.name.s
-    if heapAccess and r != nil:
-      if r.kind in {skParam, skVar, skTemp, skLet, skResult, skForVar}:
-        # we have an assignment like:
-        # local.foo = bar
-        # --> check which parameter it may alias and mark these parameters
-        # as dirty:
-        let aliases = possibleAliases(w, r)
-        for a in aliases:
-          if a.kind == skParam and a.owner == w.owner:
-            incl(a.flags, sfWrittenTo)
-      else:
-        internalError(dest.info, "dunno what to do " & $r.kind)
+    if rootIsHeapAccess in info or src == w.markAsWrittenTo:
+      # we have an assignment like:
+      # local.foo = bar
+      # --> 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 heapAccess = src == w.markAsEscaping
-    let r = root(w.owner, dest, heapAccess)
-    if r != nil and (heapAccess or r.kind == skResult):
-      if r.kind in {skParam, skVar, skTemp, skLet, skResult, skForVar}:
-        let aliases = possibleAliases(w, r)
-        var destIsParam = false
-        for a in aliases:
-          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)
-      else:
-        internalError(dest.info, "dunno what to do " & $r.kind)
+    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
ision' href='/ahoang/Nim/blame/compiler/nimlexbase.nim?h=devel&id=9e92455a534956bfbb0a7ec5e6f2bdffd7268818'>^
e25474154 ^
b731e6ef1 ^
e25474154 ^



2df9b442c ^
e25474154 ^
b731e6ef1 ^
e25474154 ^

2df9b442c ^

e25474154 ^


6c5693e63 ^
e25474154 ^





b731e6ef1 ^
e25474154 ^

92b8fac94 ^
e25474154 ^




e25474154 ^
6c5693e63 ^
e25474154 ^


dc669155e ^
e25474154 ^
92b8fac94 ^
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169