summaryrefslogtreecommitdiff
path: root/examples/scala-js/tools/shared/src/main/scala/scala/scalajs/tools/optimizer/GenIncOptimizer.scala
diff options
context:
space:
mode:
Diffstat (limited to 'examples/scala-js/tools/shared/src/main/scala/scala/scalajs/tools/optimizer/GenIncOptimizer.scala')
-rw-r--r--examples/scala-js/tools/shared/src/main/scala/scala/scalajs/tools/optimizer/GenIncOptimizer.scala921
1 files changed, 0 insertions, 921 deletions
diff --git a/examples/scala-js/tools/shared/src/main/scala/scala/scalajs/tools/optimizer/GenIncOptimizer.scala b/examples/scala-js/tools/shared/src/main/scala/scala/scalajs/tools/optimizer/GenIncOptimizer.scala
deleted file mode 100644
index 47e1f87..0000000
--- a/examples/scala-js/tools/shared/src/main/scala/scala/scalajs/tools/optimizer/GenIncOptimizer.scala
+++ /dev/null
@@ -1,921 +0,0 @@
-/* __ *\
-** ________ ___ / / ___ __ ____ Scala.js tools **
-** / __/ __// _ | / / / _ | __ / // __/ (c) 2013-2014, LAMP/EPFL **
-** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ **
-** /____/\___/_/ |_/____/_/ | |__/ /____/ **
-** |/____/ **
-\* */
-
-
-package scala.scalajs.tools.optimizer
-
-import language.higherKinds
-
-import scala.annotation.{switch, tailrec}
-
-import scala.collection.{GenMap, GenTraversableOnce, GenIterable, GenIterableLike}
-import scala.collection.mutable
-
-import scala.scalajs.ir._
-import Definitions.isConstructorName
-import Infos.OptimizerHints
-import Trees._
-import Types._
-
-import scala.scalajs.tools.sem._
-
-import scala.scalajs.tools.javascript
-import javascript.Trees.{Tree => JSTree}
-import javascript.ScalaJSClassEmitter
-
-import scala.scalajs.tools.logging._
-
-/** Incremental optimizer.
- * An incremental optimizer consumes the reachability analysis produced by
- * an [[Analyzer]], as well as trees for classes, trait impls, etc., and
- * optimizes them in an incremental way.
- * It maintains state between runs to do a minimal amount of work on every
- * run, based on detecting what parts of the program must be re-optimized,
- * and keeping optimized results from previous runs for the rest.
- */
-abstract class GenIncOptimizer(semantics: Semantics) {
- import GenIncOptimizer._
-
- protected val CollOps: AbsCollOps
-
- private val classEmitter = new ScalaJSClassEmitter(semantics)
-
- private var logger: Logger = _
-
- /** Are we in batch mode? I.e., are we running from scratch?
- * Various parts of the algorithm can be skipped entirely when running in
- * batch mode.
- */
- private var batchMode: Boolean = false
-
- /** Should positions be considered when comparing tree hashes */
- private var considerPositions: Boolean = _
-
- private var objectClass: Class = _
- private val classes = CollOps.emptyMap[String, Class]
- private val traitImpls = CollOps.emptyParMap[String, TraitImpl]
-
- protected def getInterface(encodedName: String): InterfaceType
-
- /** Schedule a method for processing in the PROCESS PASS */
- protected def scheduleMethod(method: MethodImpl): Unit
-
- protected def newMethodImpl(owner: MethodContainer,
- encodedName: String): MethodImpl
-
- def findTraitImpl(encodedName: String): TraitImpl = traitImpls(encodedName)
- def findClass(encodedName: String): Class = classes(encodedName)
-
- def getTraitImpl(encodedName: String): Option[TraitImpl] = traitImpls.get(encodedName)
- def getClass(encodedName: String): Option[Class] = classes.get(encodedName)
-
- type GetClassTreeIfChanged =
- (String, Option[String]) => Option[(ClassDef, Option[String])]
-
- private def withLogger[A](logger: Logger)(body: => A): A = {
- assert(this.logger == null)
- this.logger = logger
- try body
- finally this.logger = null
- }
-
- /** Update the incremental analyzer with a new run. */
- def update(analyzer: Analyzer,
- getClassTreeIfChanged: GetClassTreeIfChanged, considerPositions: Boolean,
- logger: Logger): Unit = withLogger(logger) {
-
- batchMode = objectClass == null
- this.considerPositions = considerPositions
- logger.debug(s"Optimizer batch mode: $batchMode")
-
- logTime(logger, "Incremental part of inc. optimizer") {
- /* UPDATE PASS */
- updateAndTagEverything(analyzer, getClassTreeIfChanged)
- }
-
- logTime(logger, "Optimizer part of inc. optimizer") {
- /* PROCESS PASS */
- processAllTaggedMethods()
- }
- }
-
- /** Incremental part: update state and detect what needs to be re-optimized.
- * UPDATE PASS ONLY. (This IS the update pass).
- */
- private def updateAndTagEverything(analyzer: Analyzer,
- getClassTreeIfChanged: GetClassTreeIfChanged): Unit = {
-
- val neededClasses = CollOps.emptyParMap[String, analyzer.ClassInfo]
- val neededTraitImpls = CollOps.emptyParMap[String, analyzer.ClassInfo]
- for {
- classInfo <- analyzer.classInfos.values
- if classInfo.isNeededAtAll
- } {
- if (classInfo.isClass && classInfo.isAnySubclassInstantiated)
- CollOps.put(neededClasses, classInfo.encodedName, classInfo)
- else if (classInfo.isImplClass)
- CollOps.put(neededTraitImpls, classInfo.encodedName, classInfo)
- }
-
- /* Remove deleted trait impls, and update existing trait impls.
- * We don't even have to notify callers in case of additions or removals
- * because callers have got to be invalidated by themselves.
- * Only changed methods need to trigger notifications.
- *
- * Non-batch mode only.
- */
- assert(!batchMode || traitImpls.isEmpty)
- if (!batchMode) {
- CollOps.retain(traitImpls) { (traitImplName, traitImpl) =>
- CollOps.remove(neededTraitImpls, traitImplName).fold {
- /* Deleted trait impl. Mark all its methods as deleted, and remove it
- * from known trait impls.
- */
- traitImpl.methods.values.foreach(_.delete())
-
- false
- } { traitImplInfo =>
- /* Existing trait impl. Update it. */
- val (added, changed, removed) =
- traitImpl.updateWith(traitImplInfo, getClassTreeIfChanged)
- for (method <- changed)
- traitImpl.myInterface.tagStaticCallersOf(method)
-
- true
- }
- }
- }
-
- /* Add new trait impls.
- * Easy, we don't have to notify anyone.
- */
- for (traitImplInfo <- neededTraitImpls.values) {
- val traitImpl = new TraitImpl(traitImplInfo.encodedName)
- CollOps.put(traitImpls, traitImpl.encodedName, traitImpl)
- traitImpl.updateWith(traitImplInfo, getClassTreeIfChanged)
- }
-
- if (!batchMode) {
- /* Class removals:
- * * If a class is deleted or moved, delete its entire subtree (because
- * all its descendants must also be deleted or moved).
- * * If an existing class was instantiated but is no more, notify callers
- * of its methods.
- *
- * Non-batch mode only.
- */
- val objectClassStillExists =
- objectClass.walkClassesForDeletions(neededClasses.get(_))
- assert(objectClassStillExists, "Uh oh, java.lang.Object was deleted!")
-
- /* Class changes:
- * * Delete removed methods, update existing ones, add new ones
- * * Update the list of ancestors
- * * Class newly instantiated
- *
- * Non-batch mode only.
- */
- objectClass.walkForChanges(
- CollOps.remove(neededClasses, _).get,
- getClassTreeIfChanged,
- Set.empty)
- }
-
- /* Class additions:
- * * Add new classes (including those that have moved from elsewhere).
- * In batch mode, we avoid doing notifications.
- */
-
- // Group children by (immediate) parent
- val newChildrenByParent = CollOps.emptyAccMap[String, Analyzer#ClassInfo]
-
- for (classInfo <- neededClasses.values) {
- val superInfo = classInfo.superClass
- if (superInfo == null) {
- assert(batchMode, "Trying to add java.lang.Object in incremental mode")
- objectClass = new Class(None, classInfo.encodedName)
- classes += classInfo.encodedName -> objectClass
- objectClass.setupAfterCreation(classInfo, getClassTreeIfChanged)
- } else {
- CollOps.acc(newChildrenByParent, superInfo.encodedName, classInfo)
- }
- }
-
- val getNewChildren =
- (name: String) => CollOps.getAcc(newChildrenByParent, name)
-
- // Walk the tree to add children
- if (batchMode) {
- objectClass.walkForAdditions(getNewChildren, getClassTreeIfChanged)
- } else {
- val existingParents =
- CollOps.parFlatMapKeys(newChildrenByParent)(classes.get)
- for (parent <- existingParents)
- parent.walkForAdditions(getNewChildren, getClassTreeIfChanged)
- }
-
- }
-
- /** Optimizer part: process all methods that need reoptimizing.
- * PROCESS PASS ONLY. (This IS the process pass).
- */
- protected def processAllTaggedMethods(): Unit
-
- protected def logProcessingMethods(count: Int): Unit =
- logger.debug(s"Optimizing $count methods.")
-
- /** Base class for [[Class]] and [[TraitImpl]]. */
- abstract class MethodContainer(val encodedName: String) {
- def thisType: Type
-
- val myInterface = getInterface(encodedName)
-
- val methods = mutable.Map.empty[String, MethodImpl]
-
- var lastVersion: Option[String] = None
-
- private def reachableMethodsOf(info: Analyzer#ClassInfo): Set[String] = {
- (for {
- methodInfo <- info.methodInfos.values
- if methodInfo.isReachable && !methodInfo.isAbstract
- } yield {
- methodInfo.encodedName
- }).toSet
- }
-
- /** UPDATE PASS ONLY. Global concurrency safe but not on same instance */
- def updateWith(info: Analyzer#ClassInfo,
- getClassTreeIfChanged: GetClassTreeIfChanged): (Set[String], Set[String], Set[String]) = {
- myInterface.ancestors = info.ancestors.map(_.encodedName).toList
-
- val addedMethods = Set.newBuilder[String]
- val changedMethods = Set.newBuilder[String]
- val deletedMethods = Set.newBuilder[String]
-
- val reachableMethods = reachableMethodsOf(info)
- val methodSetChanged = methods.keySet != reachableMethods
- if (methodSetChanged) {
- // Remove deleted methods
- methods retain { (methodName, method) =>
- if (reachableMethods.contains(methodName)) {
- true
- } else {
- deletedMethods += methodName
- method.delete()
- false
- }
- }
- // Clear lastVersion if there are new methods
- if (reachableMethods.exists(!methods.contains(_)))
- lastVersion = None
- }
- for ((tree, version) <- getClassTreeIfChanged(encodedName, lastVersion)) {
- lastVersion = version
- this match {
- case cls: Class =>
- cls.isModuleClass = tree.kind == ClassKind.ModuleClass
- cls.fields = for (field @ VarDef(_, _, _, _) <- tree.defs) yield field
- case _ =>
- }
- tree.defs.foreach {
- case methodDef: MethodDef if methodDef.name.isInstanceOf[Ident] &&
- reachableMethods.contains(methodDef.name.name) =>
- val methodName = methodDef.name.name
-
- val methodInfo = info.methodInfos(methodName)
- methods.get(methodName).fold {
- addedMethods += methodName
- val method = newMethodImpl(this, methodName)
- method.updateWith(methodInfo, methodDef)
- methods(methodName) = method
- method
- } { method =>
- if (method.updateWith(methodInfo, methodDef))
- changedMethods += methodName
- method
- }
-
- case _ => // ignore
- }
- }
-
- (addedMethods.result(), changedMethods.result(), deletedMethods.result())
- }
- }
-
- /** Class in the class hierarchy (not an interface).
- * A class may be a module class.
- * A class knows its superclass and the interfaces it implements. It also
- * maintains a list of its direct subclasses, so that the instances of
- * [[Class]] form a tree of the class hierarchy.
- */
- class Class(val superClass: Option[Class],
- _encodedName: String) extends MethodContainer(_encodedName) {
- if (encodedName == Definitions.ObjectClass) {
- assert(superClass.isEmpty)
- assert(objectClass == null)
- } else {
- assert(superClass.isDefined)
- }
-
- /** Parent chain from this to Object. */
- val parentChain: List[Class] =
- this :: superClass.fold[List[Class]](Nil)(_.parentChain)
-
- /** Reverse parent chain from Object to this. */
- val reverseParentChain: List[Class] =
- parentChain.reverse
-
- def thisType: Type = ClassType(encodedName)
-
- var interfaces: Set[InterfaceType] = Set.empty
- var subclasses: CollOps.ParIterable[Class] = CollOps.emptyParIterable
- var isInstantiated: Boolean = false
-
- var isModuleClass: Boolean = false
- var hasElidableModuleAccessor: Boolean = false
-
- var fields: List[VarDef] = Nil
- var isInlineable: Boolean = false
- var tryNewInlineable: Option[RecordValue] = None
-
- override def toString(): String =
- encodedName
-
- /** Walk the class hierarchy tree for deletions.
- * This includes "deleting" classes that were previously instantiated but
- * are no more.
- * UPDATE PASS ONLY. Not concurrency safe on same instance.
- */
- def walkClassesForDeletions(
- getClassInfoIfNeeded: String => Option[Analyzer#ClassInfo]): Boolean = {
- def sameSuperClass(info: Analyzer#ClassInfo): Boolean =
- if (info.superClass == null) superClass.isEmpty
- else superClass.exists(_.encodedName == info.superClass.encodedName)
-
- getClassInfoIfNeeded(encodedName) match {
- case Some(classInfo) if sameSuperClass(classInfo) =>
- // Class still exists. Recurse.
- subclasses = subclasses.filter(
- _.walkClassesForDeletions(getClassInfoIfNeeded))
- if (isInstantiated && !classInfo.isInstantiated)
- notInstantiatedAnymore()
- true
- case _ =>
- // Class does not exist or has been moved. Delete the entire subtree.
- deleteSubtree()
- false
- }
- }
-
- /** Delete this class and all its subclasses. UPDATE PASS ONLY. */
- def deleteSubtree(): Unit = {
- delete()
- for (subclass <- subclasses)
- subclass.deleteSubtree()
- }
-
- /** UPDATE PASS ONLY. */
- private def delete(): Unit = {
- if (isInstantiated)
- notInstantiatedAnymore()
- for (method <- methods.values)
- method.delete()
- classes -= encodedName
- /* Note: no need to tag methods that call *statically* one of the methods
- * of the deleted classes, since they've got to be invalidated by
- * themselves.
- */
- }
-
- /** UPDATE PASS ONLY. */
- def notInstantiatedAnymore(): Unit = {
- assert(isInstantiated)
- isInstantiated = false
- for (intf <- interfaces) {
- intf.removeInstantiatedSubclass(this)
- for (methodName <- allMethods().keys)
- intf.tagDynamicCallersOf(methodName)
- }
- }
-
- /** UPDATE PASS ONLY. */
- def walkForChanges(
- getClassInfo: String => Analyzer#ClassInfo,
- getClassTreeIfChanged: GetClassTreeIfChanged,
- parentMethodAttributeChanges: Set[String]): Unit = {
-
- val classInfo = getClassInfo(encodedName)
-
- val (addedMethods, changedMethods, deletedMethods) =
- updateWith(classInfo, getClassTreeIfChanged)
-
- val oldInterfaces = interfaces
- val newInterfaces =
- classInfo.ancestors.map(info => getInterface(info.encodedName)).toSet
- interfaces = newInterfaces
-
- val methodAttributeChanges =
- (parentMethodAttributeChanges -- methods.keys ++
- addedMethods ++ changedMethods ++ deletedMethods)
-
- // Tag callers with dynamic calls
- val wasInstantiated = isInstantiated
- isInstantiated = classInfo.isInstantiated
- assert(!(wasInstantiated && !isInstantiated),
- "(wasInstantiated && !isInstantiated) should have been handled "+
- "during deletion phase")
-
- if (isInstantiated) {
- if (wasInstantiated) {
- val existingInterfaces = oldInterfaces.intersect(newInterfaces)
- for {
- intf <- existingInterfaces
- methodName <- methodAttributeChanges
- } {
- intf.tagDynamicCallersOf(methodName)
- }
- if (newInterfaces.size != oldInterfaces.size ||
- newInterfaces.size != existingInterfaces.size) {
- val allMethodNames = allMethods().keys
- for {
- intf <- oldInterfaces ++ newInterfaces -- existingInterfaces
- methodName <- allMethodNames
- } {
- intf.tagDynamicCallersOf(methodName)
- }
- }
- } else {
- val allMethodNames = allMethods().keys
- for (intf <- interfaces) {
- intf.addInstantiatedSubclass(this)
- for (methodName <- allMethodNames)
- intf.tagDynamicCallersOf(methodName)
- }
- }
- }
-
- // Tag callers with static calls
- for (methodName <- methodAttributeChanges)
- myInterface.tagStaticCallersOf(methodName)
-
- // Module class specifics
- updateHasElidableModuleAccessor()
-
- // Inlineable class
- if (updateIsInlineable(classInfo)) {
- for (method <- methods.values; if isConstructorName(method.encodedName))
- myInterface.tagStaticCallersOf(method.encodedName)
- }
-
- // Recurse in subclasses
- for (cls <- subclasses)
- cls.walkForChanges(getClassInfo, getClassTreeIfChanged,
- methodAttributeChanges)
- }
-
- /** UPDATE PASS ONLY. */
- def walkForAdditions(
- getNewChildren: String => GenIterable[Analyzer#ClassInfo],
- getClassTreeIfChanged: GetClassTreeIfChanged): Unit = {
-
- val subclassAcc = CollOps.prepAdd(subclasses)
-
- for (classInfo <- getNewChildren(encodedName)) {
- val cls = new Class(Some(this), classInfo.encodedName)
- CollOps.add(subclassAcc, cls)
- classes += classInfo.encodedName -> cls
- cls.setupAfterCreation(classInfo, getClassTreeIfChanged)
- cls.walkForAdditions(getNewChildren, getClassTreeIfChanged)
- }
-
- subclasses = CollOps.finishAdd(subclassAcc)
- }
-
- /** UPDATE PASS ONLY. */
- def updateHasElidableModuleAccessor(): Unit = {
- hasElidableModuleAccessor =
- isAdHocElidableModuleAccessor(encodedName) ||
- (isModuleClass && lookupMethod("init___").exists(isElidableModuleConstructor))
- }
-
- /** UPDATE PASS ONLY. */
- def updateIsInlineable(classInfo: Analyzer#ClassInfo): Boolean = {
- val oldTryNewInlineable = tryNewInlineable
- isInlineable = classInfo.optimizerHints.hasInlineAnnot
- if (!isInlineable) {
- tryNewInlineable = None
- } else {
- val allFields = reverseParentChain.flatMap(_.fields)
- val (fieldValues, fieldTypes) = (for {
- VarDef(Ident(name, originalName), tpe, mutable, rhs) <- allFields
- } yield {
- (rhs, RecordType.Field(name, originalName, tpe, mutable))
- }).unzip
- tryNewInlineable = Some(
- RecordValue(RecordType(fieldTypes), fieldValues)(Position.NoPosition))
- }
- tryNewInlineable != oldTryNewInlineable
- }
-
- /** UPDATE PASS ONLY. */
- def setupAfterCreation(classInfo: Analyzer#ClassInfo,
- getClassTreeIfChanged: GetClassTreeIfChanged): Unit = {
-
- updateWith(classInfo, getClassTreeIfChanged)
- interfaces =
- classInfo.ancestors.map(info => getInterface(info.encodedName)).toSet
-
- isInstantiated = classInfo.isInstantiated
-
- if (batchMode) {
- if (isInstantiated) {
- /* Only add the class to all its ancestor interfaces */
- for (intf <- interfaces)
- intf.addInstantiatedSubclass(this)
- }
- } else {
- val allMethodNames = allMethods().keys
-
- if (isInstantiated) {
- /* Add the class to all its ancestor interfaces + notify all callers
- * of any of the methods.
- * TODO: be more selective on methods that are notified: it is not
- * necessary to modify callers of methods defined in a parent class
- * that already existed in the previous run.
- */
- for (intf <- interfaces) {
- intf.addInstantiatedSubclass(this)
- for (methodName <- allMethodNames)
- intf.tagDynamicCallersOf(methodName)
- }
- }
-
- /* Tag static callers because the class could have been *moved*,
- * not just added.
- */
- for (methodName <- allMethodNames)
- myInterface.tagStaticCallersOf(methodName)
- }
-
- updateHasElidableModuleAccessor()
- updateIsInlineable(classInfo)
- }
-
- /** UPDATE PASS ONLY. */
- private def isElidableModuleConstructor(impl: MethodImpl): Boolean = {
- def isTriviallySideEffectFree(tree: Tree): Boolean = tree match {
- case _:VarRef | _:Literal | _:This => true
- case _ => false
- }
- def isElidableStat(tree: Tree): Boolean = tree match {
- case Block(stats) =>
- stats.forall(isElidableStat)
- case Assign(Select(This(), _, _), rhs) =>
- isTriviallySideEffectFree(rhs)
- case TraitImplApply(ClassType(traitImpl), methodName, List(This())) =>
- traitImpls(traitImpl).methods(methodName.name).originalDef.body match {
- case Skip() => true
- case _ => false
- }
- case StaticApply(This(), ClassType(cls), methodName, args) =>
- Definitions.isConstructorName(methodName.name) &&
- args.forall(isTriviallySideEffectFree) &&
- impl.owner.asInstanceOf[Class].superClass.exists { superCls =>
- superCls.encodedName == cls &&
- superCls.lookupMethod(methodName.name).exists(isElidableModuleConstructor)
- }
- case StoreModule(_, _) =>
- true
- case _ =>
- isTriviallySideEffectFree(tree)
- }
- isElidableStat(impl.originalDef.body)
- }
-
- /** All the methods of this class, including inherited ones.
- * It has () so we remember this is an expensive operation.
- * UPDATE PASS ONLY.
- */
- def allMethods(): scala.collection.Map[String, MethodImpl] = {
- val result = mutable.Map.empty[String, MethodImpl]
- for (parent <- reverseParentChain)
- result ++= parent.methods
- result
- }
-
- /** BOTH PASSES. */
- @tailrec
- final def lookupMethod(methodName: String): Option[MethodImpl] = {
- methods.get(methodName) match {
- case Some(impl) => Some(impl)
- case none =>
- superClass match {
- case Some(p) => p.lookupMethod(methodName)
- case none => None
- }
- }
- }
- }
-
- /** Trait impl. */
- class TraitImpl(_encodedName: String) extends MethodContainer(_encodedName) {
- def thisType: Type = NoType
- }
-
- /** Thing from which a [[MethodImpl]] can unregister itself from. */
- trait Unregisterable {
- /** UPDATE PASS ONLY. */
- def unregisterDependee(dependee: MethodImpl): Unit
- }
-
- /** Type of a class or interface.
- * Types are created on demand when a method is called on a given
- * [[ClassType]].
- *
- * Fully concurrency safe unless otherwise noted.
- */
- abstract class InterfaceType(val encodedName: String) extends Unregisterable {
-
- override def toString(): String =
- s"intf $encodedName"
-
- /** PROCESS PASS ONLY. Concurrency safe except with
- * [[addInstantiatedSubclass]] and [[removeInstantiatedSubclass]]
- */
- def instantiatedSubclasses: Iterable[Class]
-
- /** UPDATE PASS ONLY. Concurrency safe except with
- * [[instantiatedSubclasses]]
- */
- def addInstantiatedSubclass(x: Class): Unit
-
- /** UPDATE PASS ONLY. Concurrency safe except with
- * [[instantiatedSubclasses]]
- */
- def removeInstantiatedSubclass(x: Class): Unit
-
- /** PROCESS PASS ONLY. Concurrency safe except with [[ancestors_=]] */
- def ancestors: List[String]
-
- /** UPDATE PASS ONLY. Not concurrency safe. */
- def ancestors_=(v: List[String]): Unit
-
- /** PROCESS PASS ONLY. Concurrency safe except with [[ancestors_=]]. */
- def registerAskAncestors(asker: MethodImpl): Unit
-
- /** PROCESS PASS ONLY. */
- def registerDynamicCaller(methodName: String, caller: MethodImpl): Unit
-
- /** PROCESS PASS ONLY. */
- def registerStaticCaller(methodName: String, caller: MethodImpl): Unit
-
- /** UPDATE PASS ONLY. */
- def tagDynamicCallersOf(methodName: String): Unit
-
- /** UPDATE PASS ONLY. */
- def tagStaticCallersOf(methodName: String): Unit
- }
-
- /** A method implementation.
- * It must be concrete, and belong either to a [[Class]] or a [[TraitImpl]].
- *
- * A single instance is **not** concurrency safe (unless otherwise noted in
- * a method comment). However, the global state modifications are
- * concurrency safe.
- */
- abstract class MethodImpl(val owner: MethodContainer,
- val encodedName: String) extends OptimizerCore.MethodImpl
- with OptimizerCore.AbstractMethodID
- with Unregisterable {
- private[this] var _deleted: Boolean = false
-
- var optimizerHints: OptimizerHints = OptimizerHints.empty
- var originalDef: MethodDef = _
- var desugaredDef: JSTree = _
- var preciseInfo: Infos.MethodInfo = _
-
- def thisType: Type = owner.thisType
- def deleted: Boolean = _deleted
-
- override def toString(): String =
- s"$owner.$encodedName"
-
- /** PROCESS PASS ONLY. */
- def registerBodyAsker(asker: MethodImpl): Unit
-
- /** UPDATE PASS ONLY. */
- def tagBodyAskers(): Unit
-
- /** PROCESS PASS ONLY. */
- private def registerAskAncestors(intf: InterfaceType): Unit = {
- intf.registerAskAncestors(this)
- registeredTo(intf)
- }
-
- /** PROCESS PASS ONLY. */
- private def registerDynamicCall(intf: InterfaceType,
- methodName: String): Unit = {
- intf.registerDynamicCaller(methodName, this)
- registeredTo(intf)
- }
-
- /** PROCESS PASS ONLY. */
- private def registerStaticCall(intf: InterfaceType,
- methodName: String): Unit = {
- intf.registerStaticCaller(methodName, this)
- registeredTo(intf)
- }
-
- /** PROCESS PASS ONLY. */
- def registerAskBody(target: MethodImpl): Unit = {
- target.registerBodyAsker(this)
- registeredTo(target)
- }
-
- /** PROCESS PASS ONLY. */
- protected def registeredTo(intf: Unregisterable): Unit
-
- /** UPDATE PASS ONLY. */
- protected def unregisterFromEverywhere(): Unit
-
- /** Return true iff this is the first time this method is called since the
- * last reset (via [[resetTag]]).
- * UPDATE PASS ONLY.
- */
- protected def protectTag(): Boolean
-
- /** PROCESS PASS ONLY. */
- protected def resetTag(): Unit
-
- /** Returns true if the method's attributes changed.
- * Attributes are whether it is inlineable, and whether it is a trait
- * impl forwarder. Basically this is what is declared in
- * [[OptimizerCore.AbstractMethodID]].
- * In the process, tags all the body askers if the body changes.
- * UPDATE PASS ONLY. Not concurrency safe on same instance.
- */
- def updateWith(methodInfo: Analyzer#MethodInfo,
- methodDef: MethodDef): Boolean = {
- assert(!_deleted, "updateWith() called on a deleted method")
-
- val bodyChanged = {
- originalDef == null ||
- (methodDef.hash zip originalDef.hash).forall {
- case (h1, h2) => !Hashers.hashesEqual(h1, h2, considerPositions)
- }
- }
-
- if (bodyChanged)
- tagBodyAskers()
-
- val hints = methodInfo.optimizerHints
- val changed = hints != optimizerHints || bodyChanged
- if (changed) {
- val oldAttributes = (inlineable, isTraitImplForwarder)
-
- optimizerHints = hints
- originalDef = methodDef
- desugaredDef = null
- preciseInfo = null
- updateInlineable()
- tag()
-
- val newAttributes = (inlineable, isTraitImplForwarder)
- newAttributes != oldAttributes
- } else {
- false
- }
- }
-
- /** UPDATE PASS ONLY. Not concurrency safe on same instance. */
- def delete(): Unit = {
- assert(!_deleted, "delete() called twice")
- _deleted = true
- if (protectTag())
- unregisterFromEverywhere()
- }
-
- /** Concurrency safe with itself and [[delete]] on the same instance
- *
- * [[tag]] can be called concurrently with [[delete]] when methods in
- * traits/classes are updated.
- *
- * UPDATE PASS ONLY.
- */
- def tag(): Unit = if (protectTag()) {
- scheduleMethod(this)
- unregisterFromEverywhere()
- }
-
- /** PROCESS PASS ONLY. */
- def process(): Unit = if (!_deleted) {
- val (optimizedDef, info) = new Optimizer().optimize(thisType, originalDef)
- desugaredDef =
- if (owner.isInstanceOf[Class])
- classEmitter.genMethod(owner.encodedName, optimizedDef)
- else
- classEmitter.genTraitImplMethod(owner.encodedName, optimizedDef)
- preciseInfo = info
- resetTag()
- }
-
- /** All methods are PROCESS PASS ONLY */
- private class Optimizer extends OptimizerCore(semantics) {
- type MethodID = MethodImpl
-
- val myself: MethodImpl.this.type = MethodImpl.this
-
- protected def getMethodBody(method: MethodID): MethodDef = {
- MethodImpl.this.registerAskBody(method)
- method.originalDef
- }
-
- protected def dynamicCall(intfName: String,
- methodName: String): List[MethodID] = {
- val intf = getInterface(intfName)
- MethodImpl.this.registerDynamicCall(intf, methodName)
- intf.instantiatedSubclasses.flatMap(_.lookupMethod(methodName)).toList
- }
-
- protected def staticCall(className: String,
- methodName: String): Option[MethodID] = {
- val clazz = classes(className)
- MethodImpl.this.registerStaticCall(clazz.myInterface, methodName)
- clazz.lookupMethod(methodName)
- }
-
- protected def traitImplCall(traitImplName: String,
- methodName: String): Option[MethodID] = {
- val traitImpl = traitImpls(traitImplName)
- registerStaticCall(traitImpl.myInterface, methodName)
- traitImpl.methods.get(methodName)
- }
-
- protected def getAncestorsOf(intfName: String): List[String] = {
- val intf = getInterface(intfName)
- registerAskAncestors(intf)
- intf.ancestors
- }
-
- protected def hasElidableModuleAccessor(moduleClassName: String): Boolean =
- classes(moduleClassName).hasElidableModuleAccessor
-
- protected def tryNewInlineableClass(className: String): Option[RecordValue] =
- classes(className).tryNewInlineable
- }
- }
-
-}
-
-object GenIncOptimizer {
-
- private val isAdHocElidableModuleAccessor =
- Set("s_Predef$")
-
- private[optimizer] def logTime[A](logger: Logger,
- title: String)(body: => A): A = {
- val startTime = System.nanoTime()
- val result = body
- val endTime = System.nanoTime()
- val elapsedTime = endTime - startTime
- logger.time(title, elapsedTime)
- result
- }
-
- private[optimizer] trait AbsCollOps {
- type Map[K, V] <: mutable.Map[K, V]
- type ParMap[K, V] <: GenMap[K, V]
- type AccMap[K, V]
- type ParIterable[V] <: GenIterableLike[V, ParIterable[V]]
- type Addable[V]
-
- def emptyAccMap[K, V]: AccMap[K, V]
- def emptyMap[K, V]: Map[K, V]
- def emptyParMap[K, V]: ParMap[K, V]
- def emptyParIterable[V]: ParIterable[V]
-
- // Operations on ParMap
- def put[K, V](map: ParMap[K, V], k: K, v: V): Unit
- def remove[K, V](map: ParMap[K, V], k: K): Option[V]
- def retain[K, V](map: ParMap[K, V])(p: (K, V) => Boolean): Unit
-
- // Operations on AccMap
- def acc[K, V](map: AccMap[K, V], k: K, v: V): Unit
- def getAcc[K, V](map: AccMap[K, V], k: K): GenIterable[V]
- def parFlatMapKeys[A, B](map: AccMap[A, _])(
- f: A => GenTraversableOnce[B]): GenIterable[B]
-
- // Operations on ParIterable
- def prepAdd[V](it: ParIterable[V]): Addable[V]
- def add[V](addable: Addable[V], v: V): Unit
- def finishAdd[V](addable: Addable[V]): ParIterable[V]
-
- }
-
-}