1
1
package scala .async .internal
2
2
3
+ import java .util
4
+ import java .util .function .{IntConsumer , IntPredicate }
5
+
6
+ import scala .collection .immutable .IntMap
7
+
3
8
trait LiveVariables {
4
9
self : AsyncMacro =>
5
10
import c .universe ._
@@ -17,19 +22,22 @@ trait LiveVariables {
17
22
def fieldsToNullOut (asyncStates : List [AsyncState ], liftables : List [Tree ]): Map [Int , List [Tree ]] = {
18
23
// live variables analysis:
19
24
// the result map indicates in which states a given field should be nulled out
20
- val liveVarsMap : Map [Tree , Set [ Int ] ] = liveVars(asyncStates, liftables)
25
+ val liveVarsMap : Map [Tree , StateSet ] = liveVars(asyncStates, liftables)
21
26
22
27
var assignsOf = Map [Int , List [Tree ]]()
23
28
24
- for ((fld, where) <- liveVarsMap; state <- where)
25
- assignsOf get state match {
26
- case None =>
27
- assignsOf += (state -> List (fld))
28
- case Some (trees) if ! trees.exists(_.symbol == fld.symbol) =>
29
- assignsOf += (state -> (fld +: trees))
30
- case _ =>
31
- /* do nothing */
32
- }
29
+ for ((fld, where) <- liveVarsMap) {
30
+ where.foreach { new IntConsumer { def accept (state : Int ): Unit = {
31
+ assignsOf get state match {
32
+ case None =>
33
+ assignsOf += (state -> List (fld))
34
+ case Some (trees) if ! trees.exists(_.symbol == fld.symbol) =>
35
+ assignsOf += (state -> (fld +: trees))
36
+ case _ =>
37
+ // do nothing
38
+ }
39
+ }}}
40
+ }
33
41
34
42
assignsOf
35
43
}
@@ -46,9 +54,9 @@ trait LiveVariables {
46
54
* @param liftables the lifted fields
47
55
* @return a map which indicates for a given field (the key) the states in which it should be nulled out
48
56
*/
49
- def liveVars (asyncStates : List [AsyncState ], liftables : List [Tree ]): Map [Tree , Set [ Int ] ] = {
57
+ def liveVars (asyncStates : List [AsyncState ], liftables : List [Tree ]): Map [Tree , StateSet ] = {
50
58
val liftedSyms : Set [Symbol ] = // include only vars
51
- liftables.filter {
59
+ liftables.iterator. filter {
52
60
case ValDef (mods, _, _, _) => mods.hasFlag(MUTABLE )
53
61
case _ => false
54
62
}.map(_.symbol).toSet
@@ -122,20 +130,30 @@ trait LiveVariables {
122
130
* A state `i` is contained in the list that is the value to which
123
131
* key `j` maps iff control can flow from state `j` to state `i`.
124
132
*/
125
- val cfg : Map [Int , List [Int ]] = asyncStates.map(as => as.state -> as.nextStates).toMap
133
+ val cfg : Map [Int , Array [Int ]] = {
134
+ var res = IntMap .empty[Array [Int ]]
135
+
136
+ for (as <- asyncStates) res = res.updated(as.state, as.nextStates)
137
+ res
138
+ }
126
139
127
140
/** Tests if `state1` is a predecessor of `state2`.
128
141
*/
129
142
def isPred (state1 : Int , state2 : Int ): Boolean = {
130
- val seen = scala.collection.mutable. HashSet [ Int ] ()
143
+ val seen = new StateSet ()
131
144
132
145
def isPred0 (state1 : Int , state2 : Int ): Boolean =
133
146
if (state1 == state2) false
134
- else if (seen(state1)) false // breaks cycles in the CFG
147
+ else if (seen.contains (state1)) false // breaks cycles in the CFG
135
148
else cfg get state1 match {
136
149
case Some (nextStates) =>
137
150
seen += state1
138
- nextStates.contains(state2) || nextStates.exists(isPred0(_, state2))
151
+ var i = 0
152
+ while (i < nextStates.length) {
153
+ if (nextStates(i) == state2 || isPred0(nextStates(i), state2)) return true
154
+ i += 1
155
+ }
156
+ false
139
157
case None =>
140
158
false
141
159
}
@@ -164,8 +182,8 @@ trait LiveVariables {
164
182
* 7. repeat if something has changed
165
183
*/
166
184
167
- var LVentry = Map [ Int , Set [Symbol ]]() withDefaultValue Set [Symbol ]()
168
- var LVexit = Map [ Int , Set [Symbol ]]() withDefaultValue Set [Symbol ]()
185
+ var LVentry = IntMap [ Set [Symbol ]]() withDefaultValue Set [Symbol ]()
186
+ var LVexit = IntMap [ Set [Symbol ]]() withDefaultValue Set [Symbol ]()
169
187
170
188
// All fields are declared to be dead at the exit of the final async state, except for the ones
171
189
// that cannot be nulled out at all (those in noNull), because they have been captured by a nested def.
@@ -174,6 +192,14 @@ trait LiveVariables {
174
192
var currStates = List (finalState) // start at final state
175
193
var captured : Set [Symbol ] = Set ()
176
194
195
+ def contains (as : Array [Int ], a : Int ): Boolean = {
196
+ var i = 0
197
+ while (i < as.length) {
198
+ if (as(i) == a) return true
199
+ i += 1
200
+ }
201
+ false
202
+ }
177
203
while (! currStates.isEmpty) {
178
204
var entryChanged : List [AsyncState ] = Nil
179
205
@@ -183,19 +209,19 @@ trait LiveVariables {
183
209
captured ++= referenced.captured
184
210
val LVentryNew = LVexit (cs.state) ++ referenced.used
185
211
if (! LVentryNew .sameElements(LVentryOld )) {
186
- LVentry = LVentry + (cs.state -> LVentryNew )
212
+ LVentry = LVentry .updated (cs.state, LVentryNew )
187
213
entryChanged ::= cs
188
214
}
189
215
}
190
216
191
- val pred = entryChanged.flatMap(cs => asyncStates.filter(_.nextStates. contains(cs.state)))
217
+ val pred = entryChanged.flatMap(cs => asyncStates.filter(state => contains(state.nextStates, cs.state)))
192
218
var exitChanged : List [AsyncState ] = Nil
193
219
194
220
for (p <- pred) {
195
221
val LVexitOld = LVexit (p.state)
196
222
val LVexitNew = p.nextStates.flatMap(succ => LVentry (succ)).toSet
197
223
if (! LVexitNew .sameElements(LVexitOld )) {
198
- LVexit = LVexit + (p.state -> LVexitNew )
224
+ LVexit = LVexit .updated (p.state, LVexitNew )
199
225
exitChanged ::= p
200
226
}
201
227
}
@@ -210,53 +236,64 @@ trait LiveVariables {
210
236
}
211
237
}
212
238
213
- def lastUsagesOf (field : Tree , at : AsyncState ): Set [ Int ] = {
239
+ def lastUsagesOf (field : Tree , at : AsyncState ): StateSet = {
214
240
val avoid = scala.collection.mutable.HashSet [AsyncState ]()
215
241
216
- def lastUsagesOf0 (field : Tree , at : AsyncState ): Set [Int ] = {
217
- if (avoid(at)) Set ()
242
+ val result = new StateSet
243
+ def lastUsagesOf0 (field : Tree , at : AsyncState ): Unit = {
244
+ if (avoid(at)) ()
218
245
else if (captured(field.symbol)) {
219
- Set ()
246
+ ()
220
247
}
221
248
else LVentry get at.state match {
222
249
case Some (fields) if fields.contains(field.symbol) =>
223
- Set ( at.state)
250
+ result += at.state
224
251
case _ =>
225
252
avoid += at
226
- val preds = asyncStates.filter(_.nextStates.contains(at.state)).toSet
227
- preds.flatMap(p => lastUsagesOf0(field, p))
253
+ for (state <- asyncStates) {
254
+ if (contains(state.nextStates, at.state)) {
255
+ lastUsagesOf0(field, state)
256
+ }
257
+ }
228
258
}
229
259
}
230
260
231
261
lastUsagesOf0(field, at)
262
+ result
232
263
}
233
264
234
- val lastUsages : Map [Tree , Set [ Int ] ] =
235
- liftables.map(fld => fld -> lastUsagesOf(fld, finalState)).toMap
265
+ val lastUsages : Map [Tree , StateSet ] =
266
+ liftables.iterator. map(fld => fld -> lastUsagesOf(fld, finalState)).toMap
236
267
237
268
if (AsyncUtils .verbose) {
238
269
for ((fld, lastStates) <- lastUsages)
239
- AsyncUtils .vprintln(s " field ${fld.symbol.name} is last used in states ${lastStates.mkString(" , " )}" )
270
+ AsyncUtils .vprintln(s " field ${fld.symbol.name} is last used in states ${lastStates.iterator. mkString(" , " )}" )
240
271
}
241
272
242
- val nullOutAt : Map [Tree , Set [ Int ] ] =
273
+ val nullOutAt : Map [Tree , StateSet ] =
243
274
for ((fld, lastStates) <- lastUsages) yield {
244
- val killAt = lastStates.flatMap { s =>
245
- if (s == finalState.state) Set ()
246
- else {
275
+ var result = new StateSet
276
+ lastStates.foreach( new IntConsumer { def accept ( s : Int ) : Unit = {
277
+ if (s != finalState.state) {
247
278
val lastAsyncState = asyncStates.find(_.state == s).get
248
279
val succNums = lastAsyncState.nextStates
249
280
// all successor states that are not indirect predecessors
250
281
// filter out successor states where the field is live at the entry
251
- succNums.filter(num => ! isPred(num, s)).filterNot(num => LVentry (num).contains(fld.symbol))
282
+ var i = 0
283
+ while (i < succNums.length) {
284
+ val num = succNums(i)
285
+ if (! isPred(num, s) && ! LVentry (num).contains(fld.symbol))
286
+ result += num
287
+ i += 1
288
+ }
252
289
}
253
- }
254
- (fld, killAt )
290
+ }})
291
+ (fld, result )
255
292
}
256
293
257
294
if (AsyncUtils .verbose) {
258
295
for ((fld, killAt) <- nullOutAt)
259
- AsyncUtils .vprintln(s " field ${fld.symbol.name} should be nulled out in states ${killAt.mkString(" , " )}" )
296
+ AsyncUtils .vprintln(s " field ${fld.symbol.name} should be nulled out in states ${killAt.iterator. mkString(" , " )}" )
260
297
}
261
298
262
299
nullOutAt
0 commit comments