summaryrefslogtreecommitdiff
path: root/examples/scala-js/tools/jvm/src/main/scala/scala/scalajs/tools/optimizer/ParIncOptimizer.scala
blob: 422238e11169335359731c6295cfae28b80551c1 (plain) (blame)
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)

  }

}