summaryrefslogblamecommitdiff
path: root/examples/scala-js/tools/jvm/src/main/scala/scala/scalajs/tools/optimizer/ParIncOptimizer.scala
blob: 422238e11169335359731c6295cfae28b80551c1 (plain) (tree)



























































































































































































                                                                                  
/*                     __                                               *\
**     ________ ___   / /  ___      __ ____  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)

  }

}