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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
|
/* __ *\
** ________ ___ / / ___ __ ____ Scala.js tools **
** / __/ __// _ | / / / _ | __ / // __/ (c) 2013-2014, LAMP/EPFL **
** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ **
** /____/\___/_/ |_/____/_/ | |__/ /____/ **
** |/____/ **
\* */
package scala.scalajs.tools.optimizer
import scala.collection.{GenTraversableOnce, GenIterable}
import scala.collection.concurrent.TrieMap
import scala.collection.parallel.mutable.{ParTrieMap, ParArray}
import java.util.concurrent.atomic._
import scala.scalajs.tools.sem.Semantics
import ConcurrencyUtils._
class ParIncOptimizer(semantics: Semantics) extends GenIncOptimizer(semantics) {
protected object CollOps extends GenIncOptimizer.AbsCollOps {
type Map[K, V] = TrieMap[K, V]
type ParMap[K, V] = ParTrieMap[K, V]
type AccMap[K, V] = TrieMap[K, AtomicAcc[V]]
type ParIterable[V] = ParArray[V]
type Addable[V] = AtomicAcc[V]
def emptyAccMap[K, V]: AccMap[K, V] = TrieMap.empty
def emptyMap[K, V]: Map[K, V] = TrieMap.empty
def emptyParMap[K, V]: ParMap[K, V] = ParTrieMap.empty
def emptyParIterable[V]: ParIterable[V] = ParArray.empty
// Operations on ParMap
def put[K, V](map: ParMap[K, V], k: K, v: V): Unit = map.put(k, v)
def remove[K, V](map: ParMap[K, V], k: K): Option[V] = map.remove(k)
def retain[K, V](map: ParMap[K, V])(p: (K, V) => Boolean): Unit = {
map.foreach { case (k, v) =>
if (!p(k, v))
map.remove(k)
}
}
// Operations on AccMap
def acc[K, V](map: AccMap[K, V], k: K, v: V): Unit =
map.getOrPut(k, AtomicAcc.empty) += v
def getAcc[K, V](map: AccMap[K, V], k: K): GenIterable[V] =
map.get(k).fold[Iterable[V]](Nil)(_.removeAll()).toParArray
def parFlatMapKeys[A, B](map: AccMap[A, _])(
f: A => GenTraversableOnce[B]): GenIterable[B] =
map.keys.flatMap(f).toParArray
// Operations on ParIterable
def prepAdd[V](it: ParIterable[V]): Addable[V] =
AtomicAcc(it.toList)
def add[V](addable: Addable[V], v: V): Unit =
addable += v
def finishAdd[V](addable: Addable[V]): ParIterable[V] =
addable.removeAll().toParArray
}
private val _interfaces = TrieMap.empty[String, InterfaceType]
protected def getInterface(encodedName: String): InterfaceType =
_interfaces.getOrPut(encodedName, new ParInterfaceType(encodedName))
private val methodsToProcess: AtomicAcc[MethodImpl] = AtomicAcc.empty
protected def scheduleMethod(method: MethodImpl): Unit =
methodsToProcess += method
protected def newMethodImpl(owner: MethodContainer,
encodedName: String): MethodImpl = new ParMethodImpl(owner, encodedName)
protected def processAllTaggedMethods(): Unit = {
val methods = methodsToProcess.removeAll().toParArray
logProcessingMethods(methods.count(!_.deleted))
for (method <- methods)
method.process()
}
private class ParInterfaceType(encName: String) extends InterfaceType(encName) {
private val ancestorsAskers = TrieSet.empty[MethodImpl]
private val dynamicCallers = TrieMap.empty[String, TrieSet[MethodImpl]]
private val staticCallers = TrieMap.empty[String, TrieSet[MethodImpl]]
private var _ancestors: List[String] = encodedName :: Nil
private val _instantiatedSubclasses: TrieSet[Class] = TrieSet.empty
/** PROCESS PASS ONLY. Concurrency safe except with
* [[addInstantiatedSubclass]] and [[removeInstantiatedSubclass]]
*/
def instantiatedSubclasses: Iterable[Class] =
_instantiatedSubclasses.keys
/** UPDATE PASS ONLY. Concurrency safe except with
* [[instantiatedSubclasses]]
*/
def addInstantiatedSubclass(x: Class): Unit =
_instantiatedSubclasses += x
/** UPDATE PASS ONLY. Concurrency safe except with
* [[instantiatedSubclasses]]
*/
def removeInstantiatedSubclass(x: Class): Unit =
_instantiatedSubclasses -= x
/** PROCESS PASS ONLY. Concurrency safe except with [[ancestors_=]] */
def ancestors: List[String] = _ancestors
/** UPDATE PASS ONLY. Not concurrency safe. */
def ancestors_=(v: List[String]): Unit = {
if (v != _ancestors) {
_ancestors = v
ancestorsAskers.keysIterator.foreach(_.tag())
ancestorsAskers.clear()
}
}
/** PROCESS PASS ONLY. Concurrency safe except with [[ancestors_=]]. */
def registerAskAncestors(asker: MethodImpl): Unit =
ancestorsAskers += asker
/** PROCESS PASS ONLY. */
def registerDynamicCaller(methodName: String, caller: MethodImpl): Unit =
dynamicCallers.getOrPut(methodName, TrieSet.empty) += caller
/** PROCESS PASS ONLY. */
def registerStaticCaller(methodName: String, caller: MethodImpl): Unit =
staticCallers.getOrPut(methodName, TrieSet.empty) += caller
/** UPDATE PASS ONLY. */
def unregisterDependee(dependee: MethodImpl): Unit = {
ancestorsAskers -= dependee
dynamicCallers.valuesIterator.foreach(_ -= dependee)
staticCallers.valuesIterator.foreach(_ -= dependee)
}
/** UPDATE PASS ONLY. */
def tagDynamicCallersOf(methodName: String): Unit =
dynamicCallers.remove(methodName).foreach(_.keysIterator.foreach(_.tag()))
/** UPDATE PASS ONLY. */
def tagStaticCallersOf(methodName: String): Unit =
staticCallers.remove(methodName).foreach(_.keysIterator.foreach(_.tag()))
}
private class ParMethodImpl(owner: MethodContainer,
encodedName: String) extends MethodImpl(owner, encodedName) {
private val bodyAskers = TrieSet.empty[MethodImpl]
/** PROCESS PASS ONLY. */
def registerBodyAsker(asker: MethodImpl): Unit =
bodyAskers += asker
/** UPDATE PASS ONLY. */
def unregisterDependee(dependee: MethodImpl): Unit =
bodyAskers -= dependee
/** UPDATE PASS ONLY. */
def tagBodyAskers(): Unit = {
bodyAskers.keysIterator.foreach(_.tag())
bodyAskers.clear()
}
private val _registeredTo = AtomicAcc.empty[Unregisterable]
private val tagged = new AtomicBoolean(false)
protected def registeredTo(intf: Unregisterable): Unit =
_registeredTo += intf
protected def unregisterFromEverywhere(): Unit = {
_registeredTo.removeAll().foreach(_.unregisterDependee(this))
}
protected def protectTag(): Boolean = !tagged.getAndSet(true)
protected def resetTag(): Unit = tagged.set(false)
}
}
|