summaryrefslogtreecommitdiff
path: root/examples/scala-js/tools/shared/src/main/scala/scala/scalajs/tools/optimizer/IncOptimizer.scala
blob: d115618c28fcb78bdbe38b06f4848762782598f4 (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
/*                     __                                               *\
**     ________ ___   / /  ___      __ ____  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.mutable

import scala.scalajs.tools.sem.Semantics

class IncOptimizer(semantics: Semantics) extends GenIncOptimizer(semantics) {

  protected object CollOps extends GenIncOptimizer.AbsCollOps {
    type Map[K, V] = mutable.Map[K, V]
    type ParMap[K, V] = mutable.Map[K, V]
    type AccMap[K, V] = mutable.Map[K, mutable.ListBuffer[V]]
    type ParIterable[V] = mutable.ListBuffer[V]
    type Addable[V] = mutable.ListBuffer[V]

    def emptyAccMap[K, V]: AccMap[K, V] = mutable.Map.empty
    def emptyMap[K, V]: Map[K, V] = mutable.Map.empty
    def emptyParMap[K, V]: ParMap[K, V] = mutable.Map.empty
    def emptyParIterable[V]: ParIterable[V] = mutable.ListBuffer.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.retain(p)

    // Operations on AccMap
    def acc[K, V](map: AccMap[K, V], k: K, v: V): Unit =
      map.getOrElseUpdate(k, mutable.ListBuffer.empty) += v

    def getAcc[K, V](map: AccMap[K, V], k: K): GenIterable[V] =
      map.getOrElse(k, Nil)

    def parFlatMapKeys[A, B](map: AccMap[A, _])(
        f: A => GenTraversableOnce[B]): GenIterable[B] =
      map.keys.flatMap(f).toList

    // Operations on ParIterable
    def prepAdd[V](it: ParIterable[V]): Addable[V] = it
    def add[V](addable: Addable[V], v: V): Unit = addable += v
    def finishAdd[V](addable: Addable[V]): ParIterable[V] = addable
  }

  private val _interfaces = mutable.Map.empty[String, InterfaceType]
  protected def getInterface(encodedName: String): InterfaceType =
    _interfaces.getOrElseUpdate(encodedName, new SeqInterfaceType(encodedName))

  private val methodsToProcess = mutable.ListBuffer.empty[MethodImpl]
  protected def scheduleMethod(method: MethodImpl): Unit =
    methodsToProcess += method

  protected def newMethodImpl(owner: MethodContainer,
      encodedName: String): MethodImpl = new SeqMethodImpl(owner, encodedName)

  protected def processAllTaggedMethods(): Unit = {
    logProcessingMethods(methodsToProcess.count(!_.deleted))
    for (method <- methodsToProcess)
      method.process()
    methodsToProcess.clear()
  }

  private class SeqInterfaceType(encName: String) extends InterfaceType(encName) {
    private val ancestorsAskers = mutable.Set.empty[MethodImpl]
    private val dynamicCallers = mutable.Map.empty[String, mutable.Set[MethodImpl]]
    private val staticCallers = mutable.Map.empty[String, mutable.Set[MethodImpl]]

    private var _ancestors: List[String] = encodedName :: Nil

    private var _instantiatedSubclasses: Set[Class] = Set.empty

    def instantiatedSubclasses: Iterable[Class] = _instantiatedSubclasses

    def addInstantiatedSubclass(x: Class): Unit =
      _instantiatedSubclasses += x

    def removeInstantiatedSubclass(x: Class): Unit =
      _instantiatedSubclasses -= x

    def ancestors: List[String] = _ancestors

    def ancestors_=(v: List[String]): Unit = {
      if (v != _ancestors) {
        _ancestors = v
        ancestorsAskers.foreach(_.tag())
        ancestorsAskers.clear()
      }
    }

    def registerAskAncestors(asker: MethodImpl): Unit =
      ancestorsAskers += asker

    def registerDynamicCaller(methodName: String, caller: MethodImpl): Unit =
      dynamicCallers.getOrElseUpdate(methodName, mutable.Set.empty) += caller

    def registerStaticCaller(methodName: String, caller: MethodImpl): Unit =
      staticCallers.getOrElseUpdate(methodName, mutable.Set.empty) += caller

    def unregisterDependee(dependee: MethodImpl): Unit = {
      ancestorsAskers -= dependee
      dynamicCallers.values.foreach(_ -= dependee)
      staticCallers.values.foreach(_ -= dependee)
    }

    def tagDynamicCallersOf(methodName: String): Unit =
      dynamicCallers.remove(methodName).foreach(_.foreach(_.tag()))

    def tagStaticCallersOf(methodName: String): Unit =
      staticCallers.remove(methodName).foreach(_.foreach(_.tag()))
  }

  private class SeqMethodImpl(owner: MethodContainer,
      encodedName: String) extends MethodImpl(owner, encodedName) {

    private val bodyAskers = mutable.Set.empty[MethodImpl]

    def registerBodyAsker(asker: MethodImpl): Unit =
      bodyAskers += asker

    def unregisterDependee(dependee: MethodImpl): Unit =
      bodyAskers -= dependee

    def tagBodyAskers(): Unit = {
      bodyAskers.foreach(_.tag())
      bodyAskers.clear()
    }

    private var _registeredTo: List[Unregisterable] = Nil
    private var tagged = false

    protected def registeredTo(intf: Unregisterable): Unit =
      _registeredTo ::= intf

    protected def unregisterFromEverywhere(): Unit = {
      _registeredTo.foreach(_.unregisterDependee(this))
      _registeredTo = Nil
    }

    protected def protectTag(): Boolean = {
      val res = !tagged
      tagged = true
      res
    }
    protected def resetTag(): Unit = tagged = false

  }

}