Skip to content

Commit

Permalink
Merge pull request #8871 from som-snytt/review/8821
Browse files Browse the repository at this point in the history
Tweak reusable instances [ci: last-only]
  • Loading branch information
retronym committed Apr 29, 2020
2 parents edf2952 + 9cbcb7f commit e99c3fb
Show file tree
Hide file tree
Showing 6 changed files with 31 additions and 21 deletions.
2 changes: 1 addition & 1 deletion src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ abstract class SymbolLoaders {
}
}
}
private val classFileDataReader: ReusableInstance[ReusableDataReader] = new ReusableInstance[ReusableDataReader](() => new ReusableDataReader(), enabled = true)
private val classFileDataReader: ReusableInstance[ReusableDataReader] = ReusableInstance[ReusableDataReader](new ReusableDataReader())
class ClassfileLoader(val classfile: AbstractFile, clazz: ClassSymbol, module: ModuleSymbol) extends SymbolLoader with FlagAssigningCompleter {
private object classfileParser extends {
val symbolTable: SymbolLoaders.this.symbolTable.type = SymbolLoaders.this.symbolTable
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/scala/tools/nsc/typechecker/Contexts.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1355,7 +1355,7 @@ trait Contexts { self: Analyzer =>
* the search continuing as long as no qualifying name is found.
*/
// OPT: moved this into a (cached) object to avoid costly and non-eliminated {Object,Int}Ref allocations
private[Contexts] final val symbolLookupCache = ReusableInstance[SymbolLookup](new SymbolLookup, enabled = true)
private[Contexts] final val symbolLookupCache = ReusableInstance[SymbolLookup](new SymbolLookup)
private[Contexts] final class SymbolLookup {
private[this] var lookupError: NameLookup = _ // set to non-null if a definite error is encountered
private[this] var inaccessible: NameLookup = _ // records inaccessible symbol for error reporting in case none is found
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/scala/tools/nsc/typechecker/Implicits.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1933,7 +1933,7 @@ trait Implicits {
def isShadowed(name: Name): Boolean
}
object Shadower {
private[this] val localShadowerCache = new ReusableInstance[LocalShadower](() => new LocalShadower, enabled = true)
private[this] val localShadowerCache = ReusableInstance[LocalShadower](new LocalShadower)

def using[T](local: Boolean)(f: Shadower => T): T =
if (local) localShadowerCache.using { shadower =>
Expand Down
2 changes: 1 addition & 1 deletion src/reflect/scala/reflect/internal/Variances.scala
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ trait Variances {
final def varianceInType(tp: Type)(tparam: Symbol): Variance = {
varianceInTypeCache.using(_.apply(tp, tparam))
}
private[this] val varianceInTypeCache = new ReusableInstance[varianceInType](() => new varianceInType, enabled = true)
private[this] val varianceInTypeCache = ReusableInstance[varianceInType](new varianceInType)

private final class varianceInType {
private[this] var tp: Type = _
Expand Down
2 changes: 1 addition & 1 deletion src/reflect/scala/reflect/internal/tpe/FindMembers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ trait FindMembers {
if (isNew) members.enter(sym)
}
}
private[reflect] val findMemberInstance: ReusableInstance[FindMember] = new ReusableInstance(() => new FindMember, enabled = isCompilerUniverse)
private[reflect] val findMemberInstance: ReusableInstance[FindMember] = ReusableInstance(new FindMember, enabled = isCompilerUniverse)

private[reflect] final class FindMember
extends FindMemberBase[Symbol] {
Expand Down
42 changes: 26 additions & 16 deletions src/reflect/scala/reflect/internal/util/ReusableInstance.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,38 @@
* additional information regarding copyright ownership.
*/

package scala
package reflect
package internal
package util
package scala.reflect.internal.util

/** A wrapper for a re-entrant, cached instance of a value of type `T`.
import scala.collection.mutable.ArrayBuffer
import scala.util.chaining._

/** A wrapper for a list of cached instances of a type `T`.
* The wrapper is recursion-reentrant: several instances are kept, so
* at each depth of reentrance we are reusing the instance for that.
*
* An instance is created upon creating this object, and more instances
* are allocated dynamically, on demand, when reentrance occurs.
*
* Not thread safe.
*/
final class ReusableInstance[T <: AnyRef](make: () => T, enabled: Boolean) {
private val cached = make()
private var taken = false
final class ReusableInstance[T <: AnyRef] private (make: => T, enabled: Boolean) {
private[this] val cache = if (enabled) new ArrayBuffer[T](ReusableInstance.InitialSize).tap(_.addOne(make)) else null
private[this] var taken = 0

@inline def using[R](action: T => R): R =
if (!enabled || taken) action(make())
else try {
taken = true
action(cached)
} finally taken = false
if (!enabled)
action(make)
else {
if (taken == cache.size)
cache += make
taken += 1
try action(cache(taken-1)) finally taken -= 1
}
}

object ReusableInstance {
def apply[T <: AnyRef](make: => T, enabled: Boolean): ReusableInstance[T] =
new ReusableInstance[T](make _, enabled)
}
private final val InitialSize = 4

def apply[T <: AnyRef](make: => T): ReusableInstance[T] = new ReusableInstance[T](make, enabled = true)
def apply[T <: AnyRef](make: => T, enabled: Boolean): ReusableInstance[T] = new ReusableInstance[T](make, enabled = enabled)
}

0 comments on commit e99c3fb

Please sign in to comment.