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