diff options
author | Adriaan Moors <adriaan.moors@typesafe.com> | 2013-02-27 15:30:37 -0800 |
---|---|---|
committer | Adriaan Moors <adriaan.moors@typesafe.com> | 2013-02-27 15:30:37 -0800 |
commit | b98cc582fb8e06a6b7049e6688a80c8b38daba98 (patch) | |
tree | f7cca0b61bed92e913bc3ecfc3f47cfb215a1a8d /src | |
parent | 031c5be557ed49f02ab365d64e55f30c616a5939 (diff) | |
parent | 387b2590db6c4f16183ea309b7451ed1fe8365ab (diff) | |
download | scala-b98cc582fb8e06a6b7049e6688a80c8b38daba98.tar.gz scala-b98cc582fb8e06a6b7049e6688a80c8b38daba98.tar.bz2 scala-b98cc582fb8e06a6b7049e6688a80c8b38daba98.zip |
Merge pull request #2083 from scalamacros/ticket/6240
SI-6240 synchronization for runtime reflection
Diffstat (limited to 'src')
20 files changed, 1468 insertions, 331 deletions
diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala index c05c59d5ff..93fafda463 100644 --- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala +++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala @@ -352,15 +352,19 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => lazy val importer = compiler.mkImporter(u) lazy val exporter = importer.reverse - def typeCheck(tree: u.Tree, expectedType: u.Type, silent: Boolean = false, withImplicitViewsDisabled: Boolean = false, withMacrosDisabled: Boolean = false): u.Tree = compiler.withCleanupCaches { - if (compiler.settings.verbose.value) println("importing "+tree+", expectedType = "+expectedType) - var ctree: compiler.Tree = importer.importTree(tree) - var cexpectedType: compiler.Type = importer.importType(expectedType) - - if (compiler.settings.verbose.value) println("typing "+ctree+", expectedType = "+expectedType) - val ttree: compiler.Tree = compiler.typeCheck(ctree, cexpectedType, silent = silent, withImplicitViewsDisabled = withImplicitViewsDisabled, withMacrosDisabled = withMacrosDisabled) - val uttree = exporter.importTree(ttree) - uttree + private[this] val toolBoxLock = new Object + + def typeCheck(tree: u.Tree, expectedType: u.Type, silent: Boolean = false, withImplicitViewsDisabled: Boolean = false, withMacrosDisabled: Boolean = false): u.Tree = toolBoxLock.synchronized { + compiler.withCleanupCaches { + if (compiler.settings.verbose.value) println("importing "+tree+", expectedType = "+expectedType) + var ctree: compiler.Tree = importer.importTree(tree) + var cexpectedType: compiler.Type = importer.importType(expectedType) + + if (compiler.settings.verbose.value) println("typing "+ctree+", expectedType = "+expectedType) + val ttree: compiler.Tree = compiler.typeCheck(ctree, cexpectedType, silent = silent, withImplicitViewsDisabled = withImplicitViewsDisabled, withMacrosDisabled = withMacrosDisabled) + val uttree = exporter.importTree(ttree) + uttree + } } def inferImplicitValue(pt: u.Type, silent: Boolean = true, withMacrosDisabled: Boolean = false, pos: u.Position = u.NoPosition): u.Tree = { @@ -372,26 +376,28 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => inferImplicit(tree, viewTpe, isView = true, silent = silent, withMacrosDisabled = withMacrosDisabled, pos = pos) } - private def inferImplicit(tree: u.Tree, pt: u.Type, isView: Boolean, silent: Boolean, withMacrosDisabled: Boolean, pos: u.Position): u.Tree = compiler.withCleanupCaches { - if (compiler.settings.verbose.value) println("importing "+pt, ", tree = "+tree+", pos = "+pos) - var ctree: compiler.Tree = importer.importTree(tree) - var cpt: compiler.Type = importer.importType(pt) - var cpos: compiler.Position = importer.importPosition(pos) - - if (compiler.settings.verbose.value) println("inferring implicit %s of type %s, macros = %s".format(if (isView) "view" else "value", pt, !withMacrosDisabled)) - val itree: compiler.Tree = compiler.inferImplicit(ctree, cpt, isView = isView, silent = silent, withMacrosDisabled = withMacrosDisabled, pos = cpos) - val uitree = exporter.importTree(itree) - uitree + private def inferImplicit(tree: u.Tree, pt: u.Type, isView: Boolean, silent: Boolean, withMacrosDisabled: Boolean, pos: u.Position): u.Tree = toolBoxLock.synchronized { + compiler.withCleanupCaches { + if (compiler.settings.verbose.value) println("importing "+pt, ", tree = "+tree+", pos = "+pos) + var ctree: compiler.Tree = importer.importTree(tree) + var cpt: compiler.Type = importer.importType(pt) + var cpos: compiler.Position = importer.importPosition(pos) + + if (compiler.settings.verbose.value) println("inferring implicit %s of type %s, macros = %s".format(if (isView) "view" else "value", pt, !withMacrosDisabled)) + val itree: compiler.Tree = compiler.inferImplicit(ctree, cpt, isView = isView, silent = silent, withMacrosDisabled = withMacrosDisabled, pos = cpos) + val uitree = exporter.importTree(itree) + uitree + } } - def resetAllAttrs(tree: u.Tree): u.Tree = { + def resetAllAttrs(tree: u.Tree): u.Tree = toolBoxLock.synchronized { val ctree: compiler.Tree = importer.importTree(tree) val ttree: compiler.Tree = compiler.resetAllAttrs(ctree) val uttree = exporter.importTree(ttree) uttree } - def resetLocalAttrs(tree: u.Tree): u.Tree = { + def resetLocalAttrs(tree: u.Tree): u.Tree = toolBoxLock.synchronized { val ctree: compiler.Tree = importer.importTree(tree) val ttree: compiler.Tree = compiler.resetLocalAttrs(ctree) val uttree = exporter.importTree(ttree) @@ -401,14 +407,14 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => def showAttributed(tree: u.Tree, printTypes: Boolean = true, printIds: Boolean = true, printKinds: Boolean = false): String = compiler.showAttributed(importer.importTree(tree), printTypes, printIds, printKinds) - def parse(code: String): u.Tree = { + def parse(code: String): u.Tree = toolBoxLock.synchronized { if (compiler.settings.verbose.value) println("parsing "+code) val ctree: compiler.Tree = compiler.parse(code) val utree = exporter.importTree(ctree) utree } - def compile(tree: u.Tree): () => Any = { + def compile(tree: u.Tree): () => Any = toolBoxLock.synchronized { if (compiler.settings.verbose.value) println("importing "+tree) var ctree: compiler.Tree = importer.importTree(tree) diff --git a/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala b/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala index 3c2b128c52..768ebb055b 100644 --- a/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala +++ b/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala @@ -37,7 +37,7 @@ trait BaseTypeSeqs { * This is necessary because when run from reflection every base type sequence needs to have a * SynchronizedBaseTypeSeq as mixin. */ - class BaseTypeSeq protected[BaseTypeSeqs] (private[BaseTypeSeqs] val parents: List[Type], private[BaseTypeSeqs] val elems: Array[Type]) { + class BaseTypeSeq protected[reflect] (private[BaseTypeSeqs] val parents: List[Type], private[BaseTypeSeqs] val elems: Array[Type]) { self => if (Statistics.canEnable) Statistics.incCounter(baseTypeSeqCount) if (Statistics.canEnable) Statistics.incCounter(baseTypeSeqLenTotal, elems.length) diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index 6e4ca76382..7a3bdff1f8 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -1189,7 +1189,7 @@ trait Definitions extends api.StandardDefinitions { /** Is the symbol that of a parent which is added during parsing? */ lazy val isPossibleSyntheticParent = ProductClass.toSet[Symbol] + ProductRootClass + SerializableClass - private lazy val boxedValueClassesSet = boxedClass.values.toSet[Symbol] + BoxedUnitClass + lazy val boxedValueClassesSet = boxedClass.values.toSet[Symbol] + BoxedUnitClass /** Is symbol a value class? */ def isPrimitiveValueClass(sym: Symbol) = ScalaValueClasses contains sym @@ -1248,8 +1248,24 @@ trait Definitions extends api.StandardDefinitions { def init() { if (isInitialized) return + // forcing ScalaPackageClass first thing during startup is important, because syntheticCoreClasses such as AnyRefClass + // need to be entered into ScalaPackageClass, which entails calling ScalaPackageClass.info.decls.enter + // if ScalaPackageClass isn't initialized by that moment, the following will happen for runtime reflection: + // 1) initialization of ScalaPackageClass will trigger unpickling + // 2) unpickling will need to load some auxiliary types such as, for example, String + // 3) to load String, runtime reflection will call mirrorDefining(classOf[String]) + // 4) this, in turn, will call runtimeMirror(classOf[String].getClassLoader) + // 5) for some classloader configurations, the resulting mirror will be different from rootMirror + // 6) in that case, initialization of the resulting mirror will try to import definitions.syntheticCoreClasses into the mirror + // 7) this will force all the lazy vals corresponding to syntheticCoreClasses + // 8) by that time, the completer of ScalaPackageClass will have already called setInfo on ScalaPackageClass, so there won't be any stack overflow + // so far so good, but there's a subtle detail. if forcing of ScalaPackageClass was called by a syntheticCoreClasses lazy val, + // then this lazy val will be entered twice: once during step 7 and once when returning from the original call + // to avoid this we need to initialize ScalaPackageClass first and only then synthesize the core classes + ScalaPackageClass.initialize // force initialization of every symbol that is synthesized or hijacked by the compiler - val forced = symbolsNotPresentInBytecode + val forced1 = symbolsNotPresentInBytecode + val forced2 = NoSymbol isInitialized = true } //init diff --git a/src/reflect/scala/reflect/internal/Mirrors.scala b/src/reflect/scala/reflect/internal/Mirrors.scala index 0beb8e368f..80c05666af 100644 --- a/src/reflect/scala/reflect/internal/Mirrors.scala +++ b/src/reflect/scala/reflect/internal/Mirrors.scala @@ -239,6 +239,19 @@ trait Mirrors extends api.Mirrors { RootClass.info.decls enter EmptyPackage RootClass.info.decls enter RootPackage + + if (rootOwner != NoSymbol) { + // synthetic core classes are only present in root mirrors + // because Definitions.scala, which initializes and enters them, only affects rootMirror + // therefore we need to enter them manually for non-root mirrors + definitions.syntheticCoreClasses foreach (theirSym => { + val theirOwner = theirSym.owner + assert(theirOwner.isPackageClass, s"theirSym = $theirSym, theirOwner = $theirOwner") + val ourOwner = staticPackage(theirOwner.fullName) + val ourSym = theirSym // just copy the symbol into our branch of the symbol table + ourOwner.info.decls enter ourSym + }) + } } } @@ -262,34 +275,45 @@ trait Mirrors extends api.Mirrors { def mirror = thisMirror.asInstanceOf[Mirror] } - // This is the package _root_. The actual root cannot be referenced at - // the source level, but _root_ is essentially a function => <root>. - final object RootPackage extends ModuleSymbol(rootOwner, NoPosition, nme.ROOTPKG) with RootSymbol { + class RootPackage extends ModuleSymbol(rootOwner, NoPosition, nme.ROOTPKG) with RootSymbol { this setInfo NullaryMethodType(RootClass.tpe) RootClass.sourceModule = this override def isRootPackage = true } + + // This is the package _root_. The actual root cannot be referenced at + // the source level, but _root_ is essentially a function => <root>. + lazy val RootPackage = new RootPackage + + class RootClass extends PackageClassSymbol(rootOwner, NoPosition, tpnme.ROOT) with RootSymbol { + this setInfo rootLoader + + override def isRoot = true + override def isEffectiveRoot = true + override def isNestedClass = false + } + // This is <root>, the actual root of everything except the package _root_. // <root> and _root_ (RootPackage and RootClass) should be the only "well known" // symbols owned by NoSymbol. All owner chains should go through RootClass, // although it is probable that some symbols are created as direct children // of NoSymbol to ensure they will not be stumbled upon. (We should designate // a better encapsulated place for that.) - final object RootClass extends PackageClassSymbol(rootOwner, NoPosition, tpnme.ROOT) with RootSymbol { - this setInfo rootLoader + lazy val RootClass = new RootClass - override def isRoot = true - override def isEffectiveRoot = true - override def isNestedClass = false - } - // The empty package, which holds all top level types without given packages. - final object EmptyPackage extends ModuleSymbol(RootClass, NoPosition, nme.EMPTY_PACKAGE_NAME) with WellKnownSymbol { + class EmptyPackage extends ModuleSymbol(RootClass, NoPosition, nme.EMPTY_PACKAGE_NAME) with WellKnownSymbol { override def isEmptyPackage = true } - final object EmptyPackageClass extends PackageClassSymbol(RootClass, NoPosition, tpnme.EMPTY_PACKAGE_NAME) with WellKnownSymbol { + + // The empty package, which holds all top level types without given packages. + lazy val EmptyPackage = new EmptyPackage + + class EmptyPackageClass extends PackageClassSymbol(RootClass, NoPosition, tpnme.EMPTY_PACKAGE_NAME) with WellKnownSymbol { override def isEffectiveRoot = true override def isEmptyPackageClass = true } + + lazy val EmptyPackageClass = new EmptyPackageClass } } diff --git a/src/reflect/scala/reflect/internal/Names.scala b/src/reflect/scala/reflect/internal/Names.scala index c78ba72dfb..01ad18d3a0 100644 --- a/src/reflect/scala/reflect/internal/Names.scala +++ b/src/reflect/scala/reflect/internal/Names.scala @@ -21,7 +21,7 @@ trait LowPriorityNames { * @author Martin Odersky * @version 1.0, 05/02/2005 */ -trait Names extends api.Names with LowPriorityNames { +trait Names extends api.Names with LowPriorityNames { self => implicit def promoteTermNamesAsNecessary(name: Name): TermName = name.toTermName // Operations ------------------------------------------------------------- @@ -109,6 +109,26 @@ trait Names extends api.Names with LowPriorityNames { protected def newTypeName(cs: Array[Char], offset: Int, len: Int, cachedString: String): TypeName = newTermName(cs, offset, len, cachedString).toTypeName + protected def toTypeName(termName: TermName): TypeName = { + val h = hashValue(chrs, termName.index, termName.len) & HASH_MASK + var n = typeHashtable(h) + while ((n ne null) && n.start != termName.index) + n = n.next + + if (n ne null) n + else termName.createCompanionName(h) + } + + protected def toTermName(typeName: TypeName): TermName = { + val h = hashValue(chrs, typeName.index, typeName.len) & HASH_MASK + var n = termHashtable(h) + while ((n ne null) && n.start != typeName.index) + n = n.next + + if (n ne null) n + else typeName.createCompanionName(h) + } + /** Create a term name from string. */ def newTermName(s: String): TermName = newTermName(s.toCharArray(), 0, s.length(), null) @@ -145,7 +165,7 @@ trait Names extends api.Names with LowPriorityNames { * or Strings as Names. Give names the key functions the absence of which * make people want Strings all the time. */ - sealed abstract class Name(protected val index: Int, protected val len: Int) extends NameApi { + sealed abstract class Name(protected[Names] val index: Int, protected[Names] val len: Int) extends NameApi { type ThisNameType >: Null <: Name protected[this] def thisName: ThisNameType @@ -463,21 +483,21 @@ trait Names extends api.Names with LowPriorityNames { * TermName_R and TypeName_R recreate it each time toString is called. */ private class TermName_S(index0: Int, len0: Int, hash: Int, override val toString: String) extends TermName(index0, len0, hash) { - protected def createCompanionName(h: Int): TypeName = new TypeName_S(index, len, h, toString) + @inline final def createCompanionName(h: Int): TypeName = new TypeName_S(index, len, h, toString) override def newName(str: String): TermName = newTermNameCached(str) } private class TypeName_S(index0: Int, len0: Int, hash: Int, override val toString: String) extends TypeName(index0, len0, hash) { - protected def createCompanionName(h: Int): TermName = new TermName_S(index, len, h, toString) + @inline final def createCompanionName(h: Int): TermName = new TermName_S(index, len, h, toString) override def newName(str: String): TypeName = newTypeNameCached(str) } private class TermName_R(index0: Int, len0: Int, hash: Int) extends TermName(index0, len0, hash) { - protected def createCompanionName(h: Int): TypeName = new TypeName_R(index, len, h) + @inline final def createCompanionName(h: Int): TypeName = new TypeName_R(index, len, h) override def toString = new String(chrs, index, len) } private class TypeName_R(index0: Int, len0: Int, hash: Int) extends TypeName(index0, len0, hash) { - protected def createCompanionName(h: Int): TermName = new TermName_R(index, len, h) + @inline final def createCompanionName(h: Int): TermName = new TermName_R(index, len, h) override def toString = new String(chrs, index, len) } @@ -490,22 +510,14 @@ trait Names extends api.Names with LowPriorityNames { def isTermName: Boolean = true def isTypeName: Boolean = false def toTermName: TermName = this - def toTypeName: TypeName = { - val h = hashValue(chrs, index, len) & HASH_MASK - var n = typeHashtable(h) - while ((n ne null) && n.start != index) - n = n.next - - if (n ne null) n - else createCompanionName(h) - } + def toTypeName: TypeName = self.toTypeName(this) def newName(str: String): TermName = newTermName(str) def companionName: TypeName = toTypeName def subName(from: Int, to: Int): TermName = newTermName(chrs, start + from, to - from) def nameKind = "term" - protected def createCompanionName(h: Int): TypeName + def createCompanionName(h: Int): TypeName } implicit val TermNameTag = ClassTag[TermName](classOf[TermName]) @@ -518,15 +530,7 @@ trait Names extends api.Names with LowPriorityNames { typeHashtable(hash) = this def isTermName: Boolean = false def isTypeName: Boolean = true - def toTermName: TermName = { - val h = hashValue(chrs, index, len) & HASH_MASK - var n = termHashtable(h) - while ((n ne null) && n.start != index) - n = n.next - - if (n ne null) n - else createCompanionName(h) - } + def toTermName: TermName = self.toTermName(this) def toTypeName: TypeName = this def newName(str: String): TypeName = newTypeName(str) def companionName: TermName = toTermName diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala index bcda2bc1ae..09d1e649d9 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -265,6 +265,8 @@ trait StdNames { final val SourceFileATTR: NameType = "SourceFile" final val SyntheticATTR: NameType = "Synthetic" + final val scala_ : NameType = "scala" + def dropSingletonName(name: Name): TypeName = (name dropRight SINGLETON_SUFFIX.length).toTypeName def singletonName(name: Name): TypeName = (name append SINGLETON_SUFFIX).toTypeName def implClassName(name: Name): TypeName = (name append IMPL_CLASS_SUFFIX).toTypeName diff --git a/src/reflect/scala/reflect/internal/SymbolTable.scala b/src/reflect/scala/reflect/internal/SymbolTable.scala index f75855f1ec..e096bac990 100644 --- a/src/reflect/scala/reflect/internal/SymbolTable.scala +++ b/src/reflect/scala/reflect/internal/SymbolTable.scala @@ -209,6 +209,8 @@ abstract class SymbolTable extends macros.Universe finally popPhase(saved) } + def slowButSafeAtPhase[T](ph: Phase)(op: => T): T = + if (isCompilerUniverse) atPhase(ph)(op) else op /** Since when it is to be "at" a phase is inherently ambiguous, * a couple unambiguously named methods. @@ -221,6 +223,9 @@ abstract class SymbolTable extends macros.Universe @inline final def atPhaseNotLaterThan[T](target: Phase)(op: => T): T = if (isAtPhaseAfter(target)) atPhase(target)(op) else op + def slowButSafeAtPhaseNotLaterThan[T](target: Phase)(op: => T): T = + if (isCompilerUniverse) atPhaseNotLaterThan(target)(op) else op + final def isValid(period: Period): Boolean = period != 0 && runId(period) == currentRunId && { val pid = phaseId(period) diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index d9eb48ff2d..df17e3b751 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -91,10 +91,14 @@ trait Symbols extends api.Symbols { self: SymbolTable => children } + def selfType = { + if (!isCompilerUniverse && needsInitialize(isFlagRelated = false, mask = 0)) initialize + typeOfThis + } + def baseClasses = info.baseClasses def module = sourceModule def thisPrefix: Type = thisType - def selfType: Type = typeOfThis def typeSignature: Type = { fullyInitializeSymbol(this); info } def typeSignatureIn(site: Type): Type = { fullyInitializeSymbol(this); site memberInfo this } @@ -108,6 +112,8 @@ trait Symbols extends api.Symbols { self: SymbolTable => def setter: Symbol = setter(owner) } + case class SymbolKind(accurate: String, sanitized: String, abbreviation: String) + /** The class for all symbols */ abstract class Symbol protected[Symbols] (initOwner: Symbol, initPos: Position, initName: Name) extends SymbolContextApiImpl @@ -893,6 +899,13 @@ trait Symbols extends api.Symbols { self: SymbolTable => final def isInitialized: Boolean = validTo != NoPeriod + /** Some completers call sym.setInfo when still in-flight and then proceed with initialization (e.g. see LazyPackageType) + * setInfo sets _validTo to current period, which means that after a call to setInfo isInitialized will start returning true. + * Unfortunately, this doesn't mean that info becomes ready to be used, because subsequent initialization might change the info. + * Therefore we need this method to distinguish between initialized and really initialized symbol states. + */ + final def isFullyInitialized: Boolean = _validTo != NoPeriod && (flags & LOCKED) == 0 + /** Can this symbol be loaded by a reflective mirror? * * Scalac relies on `ScalaSignature' annotation to retain symbols across compilation runs. @@ -2248,7 +2261,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => else if (isTerm && (!isParameter || isParamAccessor)) "val" else "" - private case class SymbolKind(accurate: String, sanitized: String, abbreviation: String) private def symbolKind: SymbolKind = { var kind = if (isTermMacro) ("macro method", "macro method", "MAC") @@ -3007,8 +3019,8 @@ trait Symbols extends api.Symbols { self: SymbolTable => override def thisType: Type = { val period = thisTypePeriod if (period != currentPeriod) { - thisTypePeriod = currentPeriod if (!isValid(period)) thisTypeCache = ThisType(this) + thisTypePeriod = currentPeriod } thisTypeCache } @@ -3084,9 +3096,9 @@ trait Symbols extends api.Symbols { self: SymbolTable => override def typeOfThis = { val period = typeOfThisPeriod if (period != currentPeriod) { - typeOfThisPeriod = currentPeriod if (!isValid(period)) typeOfThisCache = singleType(owner.thisType, sourceModule) + typeOfThisPeriod = currentPeriod } typeOfThisCache } @@ -3097,9 +3109,9 @@ trait Symbols extends api.Symbols { self: SymbolTable => // Skip a package object class, because the members are also in // the package and we wish to avoid spurious ambiguities as in pos/t3999. if (!isPackageObjectClass) { + implicitMembersCacheValue = tp.implicitMembers implicitMembersCacheKey1 = tp implicitMembersCacheKey2 = tp.decls.elems - implicitMembersCacheValue = tp.implicitMembers } } implicitMembersCacheValue @@ -3207,10 +3219,11 @@ trait Symbols extends api.Symbols { self: SymbolTable => def name = nme.NO_NAME override def name_=(n: Name) = abort("Cannot set NoSymbol's name to " + n) - synchronized { - setInfo(NoType) - privateWithin = this - } + // Syncnote: no need to synchronize this, because NoSymbol's initialization is triggered by JavaUniverse.init + // which is called in universe's constructor - something that's inherently single-threaded + setInfo(NoType) + privateWithin = this + override def info_=(info: Type) = { infos = TypeHistory(1, NoType, null) unlock() diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index 546df8a207..76d6ec80be 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -2066,10 +2066,6 @@ trait Types extends api.Types { self: SymbolTable => def apply(value: Constant) = unique(new UniqueConstantType(value)) } - /* Syncnote: The `volatile` var and `pendingVolatiles` mutable set need not be protected - * with synchronized, because they are accessed only from isVolatile, which is called only from - * Typer. - */ private var volatileRecursions: Int = 0 private val pendingVolatiles = new mutable.HashSet[Symbol] @@ -3930,8 +3926,8 @@ trait Types extends api.Types { self: SymbolTable => /** @PP: Unable to see why these apparently constant types should need vals * in every TypeConstraint, I lifted them out. */ - private lazy val numericLoBound = IntClass.tpe - private lazy val numericHiBound = intersectionType(List(ByteClass.tpe, CharClass.tpe), ScalaPackageClass) + lazy val numericLoBound = IntClass.tpe + lazy val numericHiBound = intersectionType(List(ByteClass.tpe, CharClass.tpe), ScalaPackageClass) /** A class expressing upper and lower bounds constraints of type variables, * as well as their instantiations. diff --git a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala index 603fff4f1c..4d61e4178a 100644 --- a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala +++ b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala @@ -853,7 +853,7 @@ abstract class UnPickler { private val p = phase override def complete(sym: Symbol) : Unit = try { val tp = at(i, () => readType(sym.isTerm)) // after NMT_TRANSITION, revert `() => readType(sym.isTerm)` to `readType` - atPhase(p) (sym setInfo tp) + slowButSafeAtPhase(p)(sym setInfo tp) if (currentRunId != definedAtRunId) sym.setInfo(adaptToNewRunMap(tp)) } @@ -871,7 +871,7 @@ abstract class UnPickler { super.complete(sym) var alias = at(j, readSymbol) if (alias.isOverloaded) - alias = atPhase(picklerPhase)((alias suchThat (alt => sym.tpe =:= sym.owner.thisType.memberType(alt)))) + alias = slowButSafeAtPhase(picklerPhase)((alias suchThat (alt => sym.tpe =:= sym.owner.thisType.memberType(alt)))) sym.asInstanceOf[TermSymbol].setAlias(alias) } diff --git a/src/reflect/scala/reflect/runtime/Gil.scala b/src/reflect/scala/reflect/runtime/Gil.scala new file mode 100644 index 0000000000..cf6f1431d7 --- /dev/null +++ b/src/reflect/scala/reflect/runtime/Gil.scala @@ -0,0 +1,25 @@ +package scala.reflect +package runtime + +private[reflect] trait Gil { + self: SymbolTable => + + // fixme... please... + // there are the following avenues of optimization we discussed with Roland: + // 1) replace PackageScope locks with ConcurrentHashMap, because PackageScope materializers seem to be idempotent + // 2) unlock unpickling completers by verifying that they are idempotent or moving non-idempotent parts + // 3) remove the necessity in global state for isSubType + lazy val gil = new java.util.concurrent.locks.ReentrantLock + + @inline final def gilSynchronized[T](body: => T): T = { + if (isCompilerUniverse) body + else { + try { + gil.lock() + body + } finally { + gil.unlock() + } + } + } +} diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala index 778c826dc0..58ade961a7 100644 --- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala +++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala @@ -24,9 +24,9 @@ import scala.language.existentials import scala.runtime.{ScalaRunTime, BoxesRunTime} import scala.reflect.internal.util.Collections._ -private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { thisUniverse: SymbolTable => +private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse with TwoWayCaches { thisUniverse: SymbolTable => - private lazy val mirrors = new WeakHashMap[ClassLoader, WeakReference[JavaMirror]]() + lazy val mirrors = new WeakHashMap[ClassLoader, WeakReference[JavaMirror]]() private def createMirror(owner: Symbol, cl: ClassLoader): Mirror = { val jm = new JavaMirror(owner, cl) @@ -46,19 +46,11 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni trait JavaClassCompleter extends FlagAssigningCompleter - def init() = { - definitions.AnyValClass // force it. - - // establish root association to avoid cyclic dependency errors later - rootMirror.classToScala(classOf[java.lang.Object]).initialize - - // println("initializing definitions") - definitions.init() - } - - def runtimeMirror(cl: ClassLoader): Mirror = mirrors get cl match { - case Some(WeakReference(m)) => m - case _ => createMirror(rootMirror.RootClass, cl) + def runtimeMirror(cl: ClassLoader): Mirror = gilSynchronized { + mirrors get cl match { + case Some(WeakReference(m)) => m + case _ => createMirror(rootMirror.RootClass, cl) + } } /** The API of a mirror for a reflective universe */ @@ -71,6 +63,23 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni import definitions._ + override lazy val RootPackage = new RootPackage with SynchronizedTermSymbol + override lazy val RootClass = new RootClass with SynchronizedModuleClassSymbol + override lazy val EmptyPackage = new EmptyPackage with SynchronizedTermSymbol + override lazy val EmptyPackageClass = new EmptyPackageClass with SynchronizedModuleClassSymbol + + override def init() = { + super.init() + + // see an explanation of this in JavaUniverse.init() + RootPackage + RootClass + EmptyPackage + EmptyPackageClass + unpickler + rootLoader + } + /** The lazy type for root. */ override lazy val rootLoader = new LazyType with FlagAgnosticCompleter { @@ -667,7 +676,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni completeRest() } - def completeRest(): Unit = thisUniverse.synchronized { + def completeRest(): Unit = gilSynchronized { val tparams = clazz.rawInfo.typeParams val parents = try { @@ -883,7 +892,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni * The Scala package with given fully qualified name. Unlike `packageNameToScala`, * this one bypasses the cache. */ - private[JavaMirrors] def makeScalaPackage(fullname: String): ModuleSymbol = { + private[JavaMirrors] def makeScalaPackage(fullname: String): ModuleSymbol = gilSynchronized { val split = fullname lastIndexOf '.' val ownerModule: ModuleSymbol = if (split > 0) packageNameToScala(fullname take split) else this.RootPackage @@ -1246,11 +1255,6 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni case _ => abort(s"${sym}.enclosingRootClass = ${sym.enclosingRootClass}, which is not a RootSymbol") } - private lazy val syntheticCoreClasses: Map[(String, Name), Symbol] = { - def mapEntry(sym: Symbol): ((String, Name), Symbol) = (sym.owner.fullName, sym.name) -> sym - Map() ++ (definitions.syntheticCoreClasses map mapEntry) - } - /** 1. If `owner` is a package class (but not the empty package) and `name` is a term name, make a new package * <owner>.<name>, otherwise return NoSymbol. * Exception: If owner is root and a java class with given name exists, create symbol in empty package instead @@ -1260,22 +1264,20 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni override def missingHook(owner: Symbol, name: Name): Symbol = { if (owner.hasPackageFlag) { val mirror = mirrorThatLoaded(owner) - // todo. this makes toolbox tests pass, but it's a mere workaround for SI-5865 -// assert((owner.info decl name) == NoSymbol, s"already exists: $owner . $name") if (owner.isRootSymbol && mirror.tryJavaClass(name.toString).isDefined) return mirror.EmptyPackageClass.info decl name if (name.isTermName && !owner.isEmptyPackageClass) return mirror.makeScalaPackage( if (owner.isRootSymbol) name.toString else owner.fullName+"."+name) - syntheticCoreClasses get (owner.fullName, name) match { - case Some(tsym) => - // synthetic core classes are only present in root mirrors - // because Definitions.scala, which initializes and enters them, only affects rootMirror - // therefore we need to enter them manually for non-root mirrors - if (mirror ne thisUniverse.rootMirror) owner.info.decls enter tsym - return tsym - case None => - } + if (name == tpnme.AnyRef && owner.owner.isRoot && owner.name == tpnme.scala_) + // when we synthesize the scala.AnyRef symbol, we need to add it to the scope of the scala package + // the problem is that adding to the scope implies doing something like `owner.info.decls enter anyRef` + // which entails running a completer for the scala package + // which will try to unpickle the stuff in scala/package.class + // which will transitively load scala.AnyRef + // which doesn't exist yet, because it hasn't been added to the scope yet + // this missing hook ties the knot without introducing synchronization problems like before + return definitions.AnyRefClass } info("*** missing: "+name+"/"+name.isTermName+"/"+owner+"/"+owner.hasPackageFlag+"/"+owner.info.decls.getClass) super.missingHook(owner, name) diff --git a/src/reflect/scala/reflect/runtime/JavaUniverse.scala b/src/reflect/scala/reflect/runtime/JavaUniverse.scala index e18435d5b0..cee243fb29 100644 --- a/src/reflect/scala/reflect/runtime/JavaUniverse.scala +++ b/src/reflect/scala/reflect/runtime/JavaUniverse.scala @@ -17,12 +17,1040 @@ class JavaUniverse extends internal.SymbolTable with ReflectSetup with runtime.S def forInteractive = false def forScaladoc = false - def log(msg: => AnyRef): Unit = println(" [] "+msg) + def log(msg: => AnyRef): Unit = if (settings.debug.value) println(" [] "+msg) type TreeCopier = InternalTreeCopierOps def newStrictTreeCopier: TreeCopier = new StrictTreeCopier def newLazyTreeCopier: TreeCopier = new LazyTreeCopier init() + + def init() { + definitions.init() + + // workaround for http://groups.google.com/group/scala-internals/browse_thread/thread/97840ba4fd37b52e + // constructors are by definition single-threaded, so we initialize all lazy vals (and local object) in advance + // in order to avoid deadlocks later (e.g. one thread holds a global reflection lock and waits for definitions.Something to initialize, + // whereas another thread holds a definitions.Something initialization lock and needs a global reflection lock to complete the initialization) + + // the list of lzycompute methods is mined by a simple python script + // #!/usr/bin/env python + // import os, sys, re, glob, fnmatch + // from subprocess import check_call, check_output + // root = check_output(["git", "rev-parse", "--show-toplevel"]).strip() + // root = os.path.join(root, "build/quick/classes/reflect/scala/reflect") + // classfiles = [] + // for container, dirnames, filenames in os.walk(root): + // for filename in fnmatch.filter(filenames, '*.class'): + // classfiles.append(os.path.join(container, filename)) + // for classfile in classfiles: + // blob = open(classfile).read() + // for found in re.findall(r"[\w\$]+\$lzycompute", blob): + // print found, "in", classfile[len(root) + 1:] + + + // ======== Exprs ======== + // NOFORCE: tree$lzycompute in api/Exprs$ExprImpl.class + // NOFORCE: staticType$lzycompute in api/Exprs$ExprImpl.class + // NOFORCE: value$lzycompute in api/Exprs$ExprImpl.class + // FORCE: Expr$lzycompute in api/Universe.class + // FORCE: FixedMirrorTreeCreator$lzycompute in internal/SymbolTable.class + // probably not used by runtime reflection, but better be safe than sorry + Expr + FixedMirrorTreeCreator + + // ======== Type tags ======== + // FORCE: WeakTypeTag$lzycompute in api/Universe.class + // FORCE: TypeTag$lzycompute in api/Universe.class + // NOFORCE: tpe$lzycompute in api/TypeTags$WeakTypeTagImpl.class + // TODO: validate that scala-reflect never uses TypeTags itself (we have StdTags, but they are in compiler, so it should be okay) + // FORCE: tpe$lzycompute in api/TypeTags$PredefTypeTag.class + // FORCE: FixedMirrorTypeCreator$lzycompute in internal/SymbolTable.class + // probably not used by runtime reflection, but better be safe than sorry + WeakTypeTag + TypeTag + TypeTag.Byte.tpe + TypeTag.Short.tpe + TypeTag.Char.tpe + TypeTag.Int.tpe + TypeTag.Long.tpe + TypeTag.Float.tpe + TypeTag.Double.tpe + TypeTag.Boolean.tpe + TypeTag.Unit.tpe + TypeTag.Any.tpe + TypeTag.AnyVal.tpe + TypeTag.AnyRef.tpe + TypeTag.Object.tpe + TypeTag.Nothing.tpe + TypeTag.Null.tpe + FixedMirrorTypeCreator + + // ======== Annotations ======== + // NOFORCE: isTrivial$lzycompute in internal/AnnotationInfos$AnnotationInfo.class + // looks like isTrivial just calls into Type.isTrivial, which cannot go back to the calling annotationinfo, so we're safe from deadlocks + // NOFORCE: forcedInfo$lzycompute in internal/AnnotationInfos$LazyAnnotationInfo.class + // I can't immediately see that the completer cannot call into one of the methods of the calling AnnotationInfo + // TODO: leaving this as a todo and for now we're at a mercy of chance + // NOFORCE: encodedBytes$lzycompute in internal/AnnotationInfos$ScalaSigBytes.class + // NOFORCE: sevenBitsMayBeZero$lzycompute in internal/AnnotationInfos$ScalaSigBytes.class + // these are just bit/byte twiddling, they don't call into reflection at all + // FORCE: UnmappableAnnotArg$lzycompute in internal/SymbolTable.class + // FORCE: LiteralAnnotArg$lzycompute in internal/SymbolTable.class + // FORCE: ArrayAnnotArg$lzycompute in internal/SymbolTable.class + // FORCE: NestedAnnotArg$lzycompute in internal/SymbolTable.class + // FORCE: ScalaSigBytes$lzycompute in internal/SymbolTable.class + // FORCE: AnnotationInfo$lzycompute in internal/SymbolTable.class + // FORCE: Annotation$lzycompute in internal/SymbolTable.class + // FORCE: UnmappableAnnotation$lzycompute in internal/SymbolTable.class + // FORCE: ThrownException$lzycompute in internal/SymbolTable.class + UnmappableAnnotArg + LiteralAnnotArg + ArrayAnnotArg + NestedAnnotArg + ScalaSigBytes + AnnotationInfo + Annotation + UnmappableAnnotation + ThrownException + + // ======== Importers ======== + // NOFORCE: symMap$lzycompute in internal/Importers$StandardImporter.class + // NOFORCE: tpeMap$lzycompute in internal/Importers$StandardImporter.class + // NOFORCE: fixups$lzycompute in internal/Importers$StandardImporter.class + // NOFORCE: reverse$lzycompute in internal/Importers$StandardImporter.class + // these are simple constructors, which don't call into reflection + // actually the first three of those could be non-lazy + + // ======== Mirrors ======== + // NOFORCE: RootPackage$lzycompute in runtime/JavaMirrors$JavaMirror.class + // NOFORCE: RootClass$lzycompute in runtime/JavaMirrors$JavaMirror.class + // NOFORCE: EmptyPackage$lzycompute in runtime/JavaMirrors$JavaMirror.class + // NOFORCE: EmptyPackageClass$lzycompute in runtime/JavaMirrors$JavaMirror.class + // NOFORCE: RootPackage$lzycompute in internal/Mirrors$Roots.class + // NOFORCE: RootClass$lzycompute in internal/Mirrors$Roots.class + // NOFORCE: EmptyPackage$lzycompute in internal/Mirrors$Roots.class + // NOFORCE: EmptyPackageClass$lzycompute in internal/Mirrors$Roots.class + // NOFORCE: unpickler$lzycompute in runtime/JavaMirrors$JavaMirror.class + // NOFORCE: rootLoader$lzycompute in runtime/JavaMirrors$JavaMirror.class + // these are already forced in JavaMirror.init() + // NOFORCE: universe$lzycompute in runtime/package$.class + // that's the scala.reflect.runtime.universe + // FORCE: 5scala$reflect$runtime$JavaMirrors$$mirrors$lzycompute in runtime/JavaUniverse.class + rootMirror + mirrors + + // ======== Names ======== + // FORCE: tpnme$lzycompute in internal/SymbolTable.class + // FORCE: fulltpnme$lzycompute in internal/SymbolTable.class + // FORCE: binarynme$lzycompute in internal/SymbolTable.class + // FORCE: nme$lzycompute in internal/SymbolTable.class + // FORCE: sn$lzycompute in internal/SymbolTable.class + // FORCE: raw$lzycompute in internal/StdNames$TermNames.class + // FORCE: Ascala$reflect$internal$SymbolTable$$SimpleNameOrdering$lzycompute in internal/SymbolTable.class + // FORCE: 6scala$reflect$internal$StdNames$$compactify$lzycompute in internal/SymbolTable.class + // probably most of these are already initialized by definitions.init() + // but better be safe than sorry + // NOFORCE: GetClassLoader$lzycompute in internal/StdNames$MSILNames.class + // MSIL has been eol'd. probably we shouldn't care anymore + // runtime reflection doesn't support MSIL anyways + tpnme + fulltpnme + binarynme + nme + sn + nme.raw + lowPriorityNameOrdering + nme.flattenedName() + + // ======== Attachments ======== + // FORCE: BackquotedIdentifierAttachment$lzycompute in internal/SymbolTable.class + // FORCE: CompoundTypeTreeOriginalAttachment$lzycompute in internal/SymbolTable.class + // FORCE: MacroExpansionAttachment$lzycompute in internal/SymbolTable.class + // FORCE: SuppressMacroExpansionAttachment$lzycompute in internal/SymbolTable.class + // probably not used by runtime reflection + // but better be safe than sorry + BackquotedIdentifierAttachment + CompoundTypeTreeOriginalAttachment + MacroExpansionAttachment + SuppressMacroExpansionAttachment + + // ======== TreeInfo ======== + // NOFORCE: DynamicUpdate$lzycompute in internal/TreeInfo.class + // NOFORCE: DynamicApplication$lzycompute in internal/TreeInfo.class + // NOFORCE: DynamicApplicationNamed$lzycompute in internal/TreeInfo.class + // NOFORCE: MacroImplReference$lzycompute in internal/TreeInfo.class + // NOFORCE: StripCast$lzycompute in internal/TreeInfo.class + // NOFORCE: Applied$lzycompute in internal/TreeInfo.class + // NOFORCE: IsTrue$lzycompute in internal/TreeInfo.class + // NOFORCE: IsFalse$lzycompute in internal/TreeInfo.class + // NOFORCE: IsIf$lzycompute in internal/TreeInfo.class + // TreeInfo is never instantiated by runtime reflection + + // ======== Miscellaneous ======== + // FORCE: BooleanFlag$lzycompute in api/Universe.class + // FORCE: traceSymbols$lzycompute in internal/SymbolTable.class + // FORCE: perRunCaches$lzycompute in internal/SymbolTable.class + // FORCE: typeDebug$lzycompute in internal/SymbolTable.class + // FORCE: str$lzycompute in internal/TypeDebugging$typeDebug$.class + // FORCE: ConsoleWriter$lzycompute in internal/SymbolTable.class + // FORCE: settings$lzycompute in runtime/JavaUniverse.class + // NOFORCE: Lscala$reflect$internal$util$TraceSymbolActivity$$findErasurePhase$lzycompute in internal/SymbolTable$traceSymbols$.class + // NOFORCE: lineIndices$lzycompute in internal/util/BatchSourceFile.class + // NOFORCE: extension$lzycompute in io/AbstractFile.class + // NOFORCE: in_s$lzycompute in io/File.class + // NOFORCE: out_s$lzycompute in io/File.class + // NOFORCE: in$lzycompute in io/File.class + // NOFORCE: out$lzycompute in io/File.class + // NOFORCE: in$lzycompute in io/Streamable$Bytes$class.class + // noforced guys don't call into reflection, so even when not initialized they don't pose a deadlock threat + // FORCE: Scope$lzycompute in internal/SymbolTable.class + // FORCE: EmptyScope$lzycompute in internal/SymbolTable.class + // FORCE: Flag$lzycompute in internal/SymbolTable.class + // FORCE: KindErrors$lzycompute in internal/SymbolTable.class + BooleanFlag + traceSymbols + perRunCaches + typeDebug + typeDebug.str + ConsoleWriter + settings + Scope + EmptyScope + Flag + KindErrors + + // ======== Transforms ======== + // NOFORCE: ObjectArray$lzycompute in internal/transform/Erasure$ErasureMap.class + // NOFORCE: ErasedObject$lzycompute in internal/transform/Erasure$ErasureMap.class + // too much hassle to force those, and they cannot be called back from reflection => safe from deadlocks + // FORCE: GenericArray$lzycompute in internal/transform/Transforms$$anonfun$3$$anon$1.class + // FORCE: scalaErasure$lzycompute in internal/transform/Transforms$$anonfun$3$$anon$1.class + // FORCE: specialScalaErasure$lzycompute in internal/transform/Transforms$$anonfun$3$$anon$1.class + // FORCE: javaErasure$lzycompute in internal/transform/Transforms$$anonfun$3$$anon$1.class + // FORCE: verifiedJavaErasure$lzycompute in internal/transform/Transforms$$anonfun$3$$anon$1.class + // FORCE: boxingErasure$lzycompute in internal/transform/Transforms$$anonfun$3$$anon$1.class + refChecks + uncurry + erasure + erasure.GenericArray + erasure.scalaErasure + erasure.specialScalaErasure + erasure.javaErasure + erasure.verifiedJavaErasure + erasure.boxingErasure + + // ======== Symbols ======== + // FORCE: NoSymbol$lzycompute in internal/SymbolTable.class + // FORCE: 6scala$reflect$internal$Symbols$$TypeHistory$lzycompute in internal/SymbolTable.class + // FORCE: SymbolKind$lzycompute in internal/Symbols$Symbol.class + NoSymbol + definitions.AnyRefClass.info + SymbolKind + + // ======== Trees ======== + // FORCE: PackageDef$lzycompute in internal/SymbolTable.class + // FORCE: ClassDef$lzycompute in internal/SymbolTable.class + // FORCE: ModuleDef$lzycompute in internal/SymbolTable.class + // FORCE: ValDef$lzycompute in internal/SymbolTable.class + // FORCE: DefDef$lzycompute in internal/SymbolTable.class + // FORCE: TypeDef$lzycompute in internal/SymbolTable.class + // FORCE: LabelDef$lzycompute in internal/SymbolTable.class + // FORCE: ImportSelector$lzycompute in internal/SymbolTable.class + // FORCE: Import$lzycompute in internal/SymbolTable.class + // FORCE: Template$lzycompute in internal/SymbolTable.class + // FORCE: Block$lzycompute in internal/SymbolTable.class + // FORCE: CaseDef$lzycompute in internal/SymbolTable.class + // FORCE: Alternative$lzycompute in internal/SymbolTable.class + // FORCE: Star$lzycompute in internal/SymbolTable.class + // FORCE: Bind$lzycompute in internal/SymbolTable.class + // FORCE: UnApply$lzycompute in internal/SymbolTable.class + // FORCE: ArrayValue$lzycompute in internal/SymbolTable.class + // FORCE: Function$lzycompute in internal/SymbolTable.class + // FORCE: Assign$lzycompute in internal/SymbolTable.class + // FORCE: AssignOrNamedArg$lzycompute in internal/SymbolTable.class + // FORCE: If$lzycompute in internal/SymbolTable.class + // FORCE: Match$lzycompute in internal/SymbolTable.class + // FORCE: Return$lzycompute in internal/SymbolTable.class + // FORCE: Try$lzycompute in internal/SymbolTable.class + // FORCE: Throw$lzycompute in internal/SymbolTable.class + // FORCE: New$lzycompute in internal/SymbolTable.class + // FORCE: Typed$lzycompute in internal/SymbolTable.class + // FORCE: TypeApply$lzycompute in internal/SymbolTable.class + // FORCE: Apply$lzycompute in internal/SymbolTable.class + // FORCE: ApplyDynamic$lzycompute in internal/SymbolTable.class + // FORCE: Super$lzycompute in internal/SymbolTable.class + // FORCE: This$lzycompute in internal/SymbolTable.class + // FORCE: Select$lzycompute in internal/SymbolTable.class + // FORCE: Ident$lzycompute in internal/SymbolTable.class + // FORCE: ReferenceToBoxed$lzycompute in internal/SymbolTable.class + // FORCE: Literal$lzycompute in internal/SymbolTable.class + // FORCE: Annotated$lzycompute in internal/SymbolTable.class + // FORCE: SingletonTypeTree$lzycompute in internal/SymbolTable.class + // FORCE: SelectFromTypeTree$lzycompute in internal/SymbolTable.class + // FORCE: CompoundTypeTree$lzycompute in internal/SymbolTable.class + // FORCE: AppliedTypeTree$lzycompute in internal/SymbolTable.class + // FORCE: TypeBoundsTree$lzycompute in internal/SymbolTable.class + // FORCE: ExistentialTypeTree$lzycompute in internal/SymbolTable.class + // FORCE: TypeTree$lzycompute in internal/SymbolTable.class + // FORCE: Modifiers$lzycompute in internal/SymbolTable.class + // FORCE: Constant$lzycompute in internal/SymbolTable.class + // FORCE: treeBuild$lzycompute in internal/SymbolTable.class + // FORCE: posAssigner$lzycompute in internal/SymbolTable.class + // FORCE: NoMods$lzycompute in api/Universe.class + // FORCE: EmptyTree$lzycompute in internal/SymbolTable.class + // FORCE: emptyValDef$lzycompute in internal/SymbolTable.class + // FORCE: EmptyTreeTypeSubstituter$lzycompute in internal/SymbolTable.class + // FORCE: 3scala$reflect$internal$Trees$$duplicator$lzycompute in internal/SymbolTable.class + PackageDef + ClassDef + ModuleDef + ValDef + DefDef + TypeDef + LabelDef + ImportSelector + Import + Template + Block + CaseDef + Alternative + Star + Bind + UnApply + ArrayValue + Function + Assign + AssignOrNamedArg + If + Match + Return + Try + Throw + New + Typed + TypeApply + Apply + ApplyDynamic + Super + This + Select + Ident + ReferenceToBoxed + Literal + Annotated + SingletonTypeTree + SelectFromTypeTree + CompoundTypeTree + AppliedTypeTree + TypeBoundsTree + ExistentialTypeTree + TypeTree + Modifiers + Constant + treeBuild + posAssigner + NoMods + EmptyTree + emptyValDef + EmptyTreeTypeSubstituter + Literal(Constant(42)).duplicate + + // ======== Types ======== + // FORCE: undoLog$lzycompute in internal/SymbolTable.class + // FORCE: UnmappableTree$lzycompute in internal/SymbolTable.class + // FORCE: NotNullType$lzycompute in internal/SymbolTable.class + // FORCE: ErrorType$lzycompute in internal/SymbolTable.class + // FORCE: WildcardType$lzycompute in internal/SymbolTable.class + // FORCE: BoundedWildcardType$lzycompute in internal/SymbolTable.class + // FORCE: NoType$lzycompute in internal/SymbolTable.class + // FORCE: NoPrefix$lzycompute in internal/SymbolTable.class + // FORCE: ThisType$lzycompute in internal/SymbolTable.class + // FORCE: SingleType$lzycompute in internal/SymbolTable.class + // FORCE: SuperType$lzycompute in internal/SymbolTable.class + // FORCE: TypeBounds$lzycompute in internal/SymbolTable.class + // NOFORCE: annotationArgRewriter$1$lzycompute in internal/Types$AsSeenFromMap.class + // local object => not a problem + // FORCE: RefinedType$lzycompute in internal/SymbolTable.class + // FORCE: ClassInfoType$lzycompute in internal/SymbolTable.class + // FORCE: ConstantType$lzycompute in internal/SymbolTable.class + // FORCE: TypeRef$lzycompute in internal/SymbolTable.class + // FORCE: MethodType$lzycompute in internal/SymbolTable.class + // FORCE: NullaryMethodType$lzycompute in internal/SymbolTable.class + // FORCE: PolyType$lzycompute in internal/SymbolTable.class + // FORCE: ExistentialType$lzycompute in internal/SymbolTable.class + // FORCE: OverloadedType$lzycompute in internal/SymbolTable.class + // FORCE: AntiPolyType$lzycompute in internal/SymbolTable.class + // FORCE: HasTypeMember$lzycompute in internal/SymbolTable.class + // FORCE: HasTypeParams$lzycompute in internal/SymbolTable.class + // FORCE: TypeVar$lzycompute in internal/SymbolTable.class + // FORCE: AnnotatedType$lzycompute in internal/SymbolTable.class + // FORCE: NamedType$lzycompute in internal/SymbolTable.class + // FORCE: DeBruijnIndex$lzycompute in internal/SymbolTable.class + // FORCE: DeBruijnBinder$lzycompute in internal/SymbolTable.class + // FORCE: ErasedValueType$lzycompute in internal/SymbolTable.class + // FORCE: GenPolyType$lzycompute in internal/SymbolTable.class + // FORCE: normalizeAliases$lzycompute in internal/SymbolTable.class + // FORCE: dropSingletonType$lzycompute in internal/SymbolTable.class + // FORCE: dropAllRefinements$lzycompute in internal/SymbolTable.class + // FORCE: dropRepeatedParamType$lzycompute in internal/SymbolTable.class + // FORCE: toDeBruijn$lzycompute in internal/SymbolTable.class + // FORCE: numericLoBound$lzycompute in internal/SymbolTable.class + // FORCE: numericHiBound$lzycompute in internal/SymbolTable.class + // FORCE: TypeConstraint$lzycompute in internal/SymbolTable.class + // FORCE: unwrapToClass$lzycompute in internal/SymbolTable.class + // FORCE: unwrapToStableClass$lzycompute in internal/SymbolTable.class + // FORCE: unwrapWrapperTypes$lzycompute in internal/SymbolTable.class + // FORCE: IsDependentCollector$lzycompute in internal/SymbolTable.class + // FORCE: ApproximateDependentMap$lzycompute in internal/SymbolTable.class + // FORCE: StripAnnotationsMap$lzycompute in internal/SymbolTable.class + // FORCE: wildcardToTypeVarMap$lzycompute in internal/SymbolTable.class + // FORCE: typeVarToOriginMap$lzycompute in internal/SymbolTable.class + // FORCE: ErroneousCollector$lzycompute in internal/SymbolTable.class + // NOFORCE: scala$reflect$internal$Types$$commonOwnerMapObj$lzycompute in internal/SymbolTable.class + // not used in runtime reflection, overridden to provide thread-safety + // FORCE: RecoverableCyclicReference$lzycompute in internal/SymbolTable.class + // FORCE: CyclicReference$lzycompute in internal/SymbolTable.class + // NOFORCE: scala$reflect$internal$Types$ClassInfoType$$enterRefs$lzycompute in internal/Types$ClassInfoType.class + // not used in runtime reflection, only called by typer + // NOFORCE: Jscala$reflect$internal$Types$InstantiateDependentMap$$StableArg$lzycompute in internal/Types$InstantiateDependentMap.class + // NOFORCE: Dscala$reflect$internal$Types$InstantiateDependentMap$$Arg$lzycompute in internal/Types$InstantiateDependentMap.class + // don't call into reflection + // NOFORCE: trans$1$lzycompute in internal/Types$SubstSymMap.class + // NOFORCE: trans$2$lzycompute in internal/Types$SubstTypeMap.class + // NOFORCE: treeTrans$1$lzycompute in internal/Types$InstantiateDependentMap.class + // local objects => we're fine + // FORCE: adaptToNewRunMap$lzycompute in internal/SymbolTable.class + // NOFORCE?! maxDepth$lzycompute in internal/BaseTypeSeqs$BaseTypeSeq.class + // NOFORCE?! maxDepth$lzycompute in runtime/SynchronizedOps$$anon$4.class + // NOFORCE?! maxDepth$lzycompute in runtime/SynchronizedOps$SynchronizedBaseTypeSeq$$anon$3.class + // it's totally not obvious whether typeDepth, which is called by maxDepth, + // can or cannot indirectly call into one of the methods of the calling BaseTypeSeq + // TODO: leaving this for further investigation risking to get a deadlock for now + undoLog + UnmappableTree + NotNullType + ErrorType + WildcardType + BoundedWildcardType + NoType + NoPrefix + ThisType + SingleType + SuperType + TypeBounds + RefinedType + ClassInfoType + ConstantType + TypeRef + MethodType + NullaryMethodType + PolyType + ExistentialType + OverloadedType + AntiPolyType + HasTypeMember + HasTypeParams + TypeVar + AnnotatedType + NamedType + DeBruijnIndex + DeBruijnBinder + ErasedValueType + GenPolyType + normalizeAliases + dropSingletonType + dropAllRefinements + dropRepeatedParamType + toDeBruijn + numericLoBound + numericHiBound + TypeConstraint + unwrapToClass + unwrapToStableClass + unwrapWrapperTypes + IsDependentCollector + ApproximateDependentMap + StripAnnotationsMap + wildcardToTypeVarMap + typeVarToOriginMap + ErroneousCollector + RecoverableCyclicReference + CyclicReference + adaptToNewRunMap + + // ======== JavaMirrors ======== + // NOFORCE: assocs$lzycompute in runtime/JavaMirrors$JavaMirror$JavaAnnotationProxy.class + // NOFORCE: jconstr$lzycompute in runtime/JavaMirrors$JavaMirror$JavaConstructorMirror.class + // NOFORCE: jfield$lzycompute in runtime/JavaMirrors$JavaMirror$JavaFieldMirror.class + // NOFORCE: jmeth$lzycompute in runtime/JavaMirrors$JavaMirror$JavaMethodMirror.class + // NOFORCE: signature$lzycompute in runtime/JavaMirrors$JavaMirror$JavaTemplateMirror.class + // NOFORCE: PrimitiveClass$lzycompute in runtime/JavaMirrors$JavaMirror$toAnnotArg$.class + // NOFORCE: EnumClass$lzycompute in runtime/JavaMirrors$JavaMirror$toAnnotArg$.class + // NOFORCE: ArrayClass$lzycompute in runtime/JavaMirrors$JavaMirror$toAnnotArg$.class + // NOFORCE: AnnotationClass$lzycompute in runtime/JavaMirrors$JavaMirror$toAnnotArg$.class + // NOFORCE: ConstantArg$lzycompute in runtime/JavaMirrors$JavaMirror$toAnnotArg$.class + // NOFORCE: Cscala$reflect$runtime$JavaMirrors$JavaMirror$$toAnnotArg$lzycompute in runtime/JavaMirrors$JavaMirror.class + // NOFORCE: Lscala$reflect$runtime$JavaMirrors$JavaMirror$$JavaAnnotationProxy$lzycompute in runtime/JavaMirrors$JavaMirror.class + // NOFORCE: Bscala$reflect$runtime$TwoWayCaches$TwoWayCache$$SomeRef$lzycompute in runtime/TwoWayCaches$TwoWayCache.class + // NOFORCE: bytecodelessMethodOwners$lzycompute in runtime/JavaMirrors$JavaMirror.class + // NOFORCE: bytecodefulObjectMethods$lzycompute in runtime/JavaMirrors$JavaMirror.class + // functionality from JavaMirrors cannot be called from reflect.internal, so there's no danger of deadlock + + // ======== Locks ======== + // locks in runtime reflection look like `lazy val XXXlock = new Object` + // since initializers don't call into reflection, there's no problem in not forcing those lazy vals here + + // ======== Definitions ======== + // FORCE: definitions$lzycompute in internal/SymbolTable.class + // FORCE: JavaLangPackage$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: JavaLangPackageClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ScalaPackage$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ScalaPackageClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: RuntimePackage$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: RuntimePackageClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: JavaLangEnumClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: anyparam$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: anyvalparam$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: anyrefparam$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: AnyClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: AnyRefClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ObjectClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: AnyTpe$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: AnyRefTpe$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ObjectTpe$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: AnyRefModule$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: AnyValClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: AnyValTpe$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: RuntimeNothingClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: RuntimeNullClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: NothingClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: NullClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: NothingTpe$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: NullTpe$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ClassCastExceptionClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: IndexOutOfBoundsExceptionClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: InvocationTargetExceptionClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: MatchErrorClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: NonLocalReturnControlClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: $NullPointerExceptionClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ThrowableClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: UninitializedErrorClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: PartialFunctionClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: AbstractPartialFunctionClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: SymbolClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: StringClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: StringModule$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ClassClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: DynamicClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: SysPackage$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: UnqualifiedModules$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: UnqualifiedOwners$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: PredefModule$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: PredefModuleClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: SpecializableModule$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: GroupOfSpecializable$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ConsoleModule$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ScalaRunTimeModule$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: SymbolModule$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: Symbol_apply$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: StringAddClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ArrowAssocClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: StringAdd_$plus$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: NotNullClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ScalaNumberClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: TraitSetterAnnotationClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: DelayedInitClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: TypeConstraintClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: SingletonClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: SerializableClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: JavaSerializableClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ComparableClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: CloneableClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: JavaCloneableClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: JavaNumberClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: RemoteInterfaceClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: RemoteExceptionClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ByNameParamClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: EqualsPatternClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: JavaRepeatedParamClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: RepeatedParamClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: MatchingStrategyClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ConsClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: IterableClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: IteratorClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ListClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: SeqClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: StringBuilderClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: TraversableClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ListModule$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: List_apply$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: NilModule$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: SeqModule$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: IteratorModule$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: Iterator_apply$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ArrayModule$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ArrayModule_overloadedApply$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ArrayClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: Array_apply$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: Array_update$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: Array_length$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: Array_clone$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: SoftReferenceClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: WeakReferenceClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: MethodClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: EmptyMethodCacheClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: MethodCacheClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ReflectPackage$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ReflectApiPackage$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ReflectRuntimePackage$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: PartialManifestClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: PartialManifestModule$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: FullManifestClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: FullManifestModule$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: OptManifestClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: NoManifest$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ExprsClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ExprClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ExprModule$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ClassTagModule$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ClassTagClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: TypeTagsClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: WeakTypeTagClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: WeakTypeTagModule$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: TypeTagClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: TypeTagModule$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ApiUniverseClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: JavaUniverseClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: MirrorClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: TypeCreatorClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: TreeCreatorClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: MacroContextClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: MacroImplAnnotation$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: StringContextClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ScalaSignatureAnnotation$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ScalaLongSignatureAnnotation$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: OptionClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: OptionModule$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: Option_apply$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: SomeClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: NoneModule$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: SomeModule$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ProductClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: TupleClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: FunctionClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: AbstractFunctionClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ProductRootClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ObjectArray$lzycompute in internal/Definitions$DefinitionsClass.class + // NOFORCE: ComparatorClass$lzycompute in internal/Definitions$DefinitionsClass.class + // NOFORCE: ValueTypeClass$lzycompute in internal/Definitions$DefinitionsClass.class + // NOFORCE: DelegateClass$lzycompute in internal/Definitions$DefinitionsClass.class + // NOFORCE: Delegate_scalaCallerTargets$lzycompute in internal/Definitions$DefinitionsClass.class + // MSIL has been eol'd. probably we shouldn't care anymore + // runtime reflection doesn't support MSIL anyways + // FORCE: Any_$eq$eq$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: Any_$bang$eq$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: Any_equals$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: Any_hashCode$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: Any_toString$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: Any_$hash$hash$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: Any_getClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: Any_isInstanceOf$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: Any_asInstanceOf$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: Object_$hash$hash$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: Object_$eq$eq$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: Object_$bang$eq$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: Object_eq$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: Object_ne$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: Object_isInstanceOf$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: Object_asInstanceOf$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: Object_synchronized$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: String_$plus$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ObjectRefClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: VolatileObjectRefClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: RuntimeStaticsModule$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: BoxesRunTimeModule$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: BoxesRunTimeClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: BoxedNumberClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: BoxedCharacterClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: BoxedBooleanClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: BoxedByteClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: BoxedShortClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: BoxedIntClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: BoxedLongClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: BoxedFloatClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: BoxedDoubleClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: Boxes_isNumberOrBool$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: Boxes_isNumber$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: BoxedUnitClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: BoxedUnitModule$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: AnnotationClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ClassfileAnnotationClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: StaticAnnotationClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: BridgeClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ElidableMethodClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ImplicitNotFoundClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: MigrationAnnotationClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ScalaStrictFPAttr$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: SerializableAttr$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: SwitchClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: TailrecClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: VarargsClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: uncheckedStableClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: uncheckedVarianceClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: BeanPropertyAttr$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: BooleanBeanPropertyAttr$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: CloneableAttr$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: CompileTimeOnlyAttr$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: DeprecatedAttr$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: DeprecatedNameAttr$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: $DeprecatedInheritanceAttr$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: DeprecatedOverridingAttr$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: NativeAttr$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: RemoteAttr$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ScalaInlineClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ScalaNoInlineClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: SerialVersionUIDAttr$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: SpecializedClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ThrowsClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: TransientAttr$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: UncheckedClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: UnspecializedClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: VolatileAttr$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: BeanGetterTargetClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: BeanSetterTargetClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: FieldTargetClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: GetterTargetClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ParamTargetClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: SetterTargetClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ClassTargetClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ObjectTargetClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: MethodTargetClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: LanguageFeatureAnnot$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: languageFeatureModule$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: experimentalModule$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: MacrosFeature$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: DynamicsFeature$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: PostfixOpsFeature$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ReflectiveCallsFeature$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ImplicitConversionsFeature$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: HigherKindsFeature$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ExistentialsFeature$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: metaAnnotations$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: AnnotationDefaultAttr$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: boxedClassValues$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: isUnbox$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: isBox$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: isPhantomClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: syntheticCoreClasses$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: syntheticCoreMethods$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: hijackedCoreClasses$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: symbolsNotPresentInBytecode$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: $isPossibleSyntheticParent$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: boxedValueClassesSet$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: abbrvTag$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: numericWeight$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: boxedModule$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: boxedClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: refClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: volatileRefClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: boxMethod$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: unboxMethod$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: UnitClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ByteClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ShortClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: CharClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: IntClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: LongClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: FloatClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: DoubleClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: BooleanClass$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: Boolean_and$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: Boolean_or$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: Boolean_not$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: UnitTpe$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ByteTpe$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ShortTpe$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: CharTpe$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: IntTpe$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: LongTpe$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: FloatTpe$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: DoubleTpe$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: BooleanTpe$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ScalaNumericValueClasses$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ScalaValueClassesNoUnit$lzycompute in internal/Definitions$DefinitionsClass.class + // FORCE: ScalaValueClasses$lzycompute in internal/Definitions$DefinitionsClass.class + definitions.JavaLangPackage + definitions.JavaLangPackageClass + definitions.ScalaPackage + definitions.ScalaPackageClass + definitions.RuntimePackage + definitions.RuntimePackageClass + definitions.JavaLangEnumClass + definitions.anyparam + definitions.anyvalparam + definitions.anyrefparam + definitions.AnyClass + definitions.AnyRefClass + definitions.ObjectClass + definitions.AnyTpe + definitions.AnyRefTpe + definitions.ObjectTpe + // FIXME: definitions.AnyRefModule + definitions.AnyValClass + definitions.AnyValTpe + definitions.RuntimeNothingClass + definitions.RuntimeNullClass + definitions.NothingClass + definitions.NullClass + definitions.NothingTpe + definitions.NullTpe + definitions.ClassCastExceptionClass + definitions.IndexOutOfBoundsExceptionClass + definitions.InvocationTargetExceptionClass + definitions.MatchErrorClass + definitions.NonLocalReturnControlClass + definitions.NullPointerExceptionClass + definitions.ThrowableClass + definitions.UninitializedErrorClass + definitions.PartialFunctionClass + definitions.AbstractPartialFunctionClass + definitions.SymbolClass + definitions.StringClass + definitions.StringModule + definitions.ClassClass + definitions.DynamicClass + definitions.SysPackage + definitions.UnqualifiedModules + definitions.UnqualifiedOwners + definitions.PredefModule + definitions.PredefModuleClass + definitions.SpecializableModule + definitions.GroupOfSpecializable + definitions.ConsoleModule + definitions.ScalaRunTimeModule + definitions.SymbolModule + definitions.Symbol_apply + definitions.StringAddClass + definitions.ArrowAssocClass + definitions.StringAdd_$plus + definitions.NotNullClass + definitions.ScalaNumberClass + definitions.TraitSetterAnnotationClass + definitions.DelayedInitClass + definitions.TypeConstraintClass + definitions.SingletonClass + definitions.SerializableClass + definitions.JavaSerializableClass + definitions.ComparableClass + definitions.CloneableClass + definitions.JavaCloneableClass + definitions.JavaNumberClass + definitions.RemoteInterfaceClass + definitions.RemoteExceptionClass + definitions.ByNameParamClass + definitions.EqualsPatternClass + definitions.JavaRepeatedParamClass + definitions.RepeatedParamClass + // FIXME: definitions.MatchingStrategyClass + definitions.ConsClass + definitions.IterableClass + definitions.IteratorClass + definitions.ListClass + definitions.SeqClass + definitions.StringBuilderClass + definitions.TraversableClass + definitions.ListModule + definitions.List_apply + definitions.NilModule + definitions.SeqModule + definitions.IteratorModule + definitions.Iterator_apply + definitions.ArrayModule + definitions.ArrayModule_overloadedApply + definitions.ArrayClass + definitions.Array_apply + definitions.Array_update + definitions.Array_length + definitions.Array_clone + definitions.SoftReferenceClass + definitions.WeakReferenceClass + definitions.MethodClass + definitions.EmptyMethodCacheClass + definitions.MethodCacheClass + definitions.ReflectPackage + definitions.ReflectApiPackage + definitions.ReflectRuntimePackage + definitions.PartialManifestClass + definitions.PartialManifestModule + definitions.FullManifestClass + definitions.FullManifestModule + definitions.OptManifestClass + definitions.NoManifest + definitions.ExprsClass + definitions.ExprClass + definitions.ExprModule + definitions.ClassTagModule + definitions.ClassTagClass + definitions.TypeTagsClass + definitions.WeakTypeTagClass + definitions.WeakTypeTagModule + definitions.TypeTagClass + definitions.TypeTagModule + definitions.ApiUniverseClass + definitions.JavaUniverseClass + definitions.MirrorClass + definitions.TypeCreatorClass + definitions.TreeCreatorClass + definitions.MacroContextClass + definitions.MacroImplAnnotation + definitions.StringContextClass + definitions.ScalaSignatureAnnotation + definitions.ScalaLongSignatureAnnotation + definitions.OptionClass + definitions.OptionModule + definitions.Option_apply + definitions.SomeClass + definitions.NoneModule + definitions.SomeModule + definitions.ProductClass + definitions.TupleClass + definitions.FunctionClass + definitions.AbstractFunctionClass + definitions.ProductRootClass + definitions.ObjectArray + definitions.Any_$eq$eq + definitions.Any_$bang$eq + definitions.Any_equals + definitions.Any_hashCode + definitions.Any_toString + definitions.Any_$hash$hash + definitions.Any_getClass + definitions.Any_isInstanceOf + definitions.Any_asInstanceOf + definitions.Object_$hash$hash + definitions.Object_$eq$eq + definitions.Object_$bang$eq + definitions.Object_eq + definitions.Object_ne + definitions.Object_isInstanceOf + definitions.Object_asInstanceOf + definitions.Object_synchronized + definitions.String_$plus + definitions.ObjectRefClass + definitions.VolatileObjectRefClass + definitions.RuntimeStaticsModule + definitions.BoxesRunTimeModule + definitions.BoxesRunTimeClass + definitions.BoxedNumberClass + definitions.BoxedCharacterClass + definitions.BoxedBooleanClass + definitions.BoxedByteClass + definitions.BoxedShortClass + definitions.BoxedIntClass + definitions.BoxedLongClass + definitions.BoxedFloatClass + definitions.BoxedDoubleClass + definitions.Boxes_isNumberOrBool + definitions.Boxes_isNumber + definitions.BoxedUnitClass + definitions.BoxedUnitModule + definitions.AnnotationClass + definitions.ClassfileAnnotationClass + definitions.StaticAnnotationClass + definitions.BridgeClass + definitions.ElidableMethodClass + definitions.ImplicitNotFoundClass + definitions.MigrationAnnotationClass + definitions.ScalaStrictFPAttr + definitions.SerializableAttr + definitions.SwitchClass + definitions.TailrecClass + definitions.VarargsClass + definitions.uncheckedStableClass + definitions.uncheckedVarianceClass + definitions.BeanPropertyAttr + definitions.BooleanBeanPropertyAttr + definitions.CloneableAttr + definitions.CompileTimeOnlyAttr + definitions.DeprecatedAttr + definitions.DeprecatedNameAttr + definitions.DeprecatedInheritanceAttr + definitions.DeprecatedOverridingAttr + definitions.NativeAttr + definitions.RemoteAttr + definitions.ScalaInlineClass + definitions.ScalaNoInlineClass + definitions.SerialVersionUIDAttr + definitions.SpecializedClass + definitions.ThrowsClass + definitions.TransientAttr + definitions.UncheckedClass + definitions.UnspecializedClass + definitions.VolatileAttr + definitions.BeanGetterTargetClass + definitions.BeanSetterTargetClass + definitions.FieldTargetClass + definitions.GetterTargetClass + definitions.ParamTargetClass + definitions.SetterTargetClass + definitions.ClassTargetClass + definitions.ObjectTargetClass + definitions.MethodTargetClass + definitions.LanguageFeatureAnnot + definitions.languageFeatureModule + definitions.experimentalModule + definitions.MacrosFeature + definitions.DynamicsFeature + definitions.PostfixOpsFeature + definitions.ReflectiveCallsFeature + definitions.ImplicitConversionsFeature + definitions.HigherKindsFeature + definitions.ExistentialsFeature + definitions.metaAnnotations + definitions.AnnotationDefaultAttr + definitions.boxedClassValues + definitions.isUnbox + definitions.isBox + definitions.isPhantomClass + definitions.syntheticCoreClasses + definitions.syntheticCoreMethods + definitions.hijackedCoreClasses + definitions.symbolsNotPresentInBytecode + definitions.isPossibleSyntheticParent + definitions.boxedValueClassesSet + definitions.abbrvTag + definitions.numericWeight + definitions.boxedModule + definitions.boxedClass + definitions.refClass + definitions.volatileRefClass + definitions.boxMethod + definitions.unboxMethod + definitions.UnitClass + definitions.ByteClass + definitions.ShortClass + definitions.CharClass + definitions.IntClass + definitions.LongClass + definitions.FloatClass + definitions.DoubleClass + definitions.BooleanClass + definitions.Boolean_and + definitions.Boolean_or + definitions.Boolean_not + definitions.UnitTpe + definitions.ByteTpe + definitions.ShortTpe + definitions.CharTpe + definitions.IntTpe + definitions.LongTpe + definitions.FloatTpe + definitions.DoubleTpe + definitions.BooleanTpe + definitions.ScalaNumericValueClasses + definitions.ScalaValueClassesNoUnit + definitions.ScalaValueClasses + } } diff --git a/src/reflect/scala/reflect/runtime/SymbolLoaders.scala b/src/reflect/scala/reflect/runtime/SymbolLoaders.scala index 311db64b91..bd5be44b35 100644 --- a/src/reflect/scala/reflect/runtime/SymbolLoaders.scala +++ b/src/reflect/scala/reflect/runtime/SymbolLoaders.scala @@ -15,37 +15,13 @@ private[reflect] trait SymbolLoaders { self: SymbolTable => * is found, a package is created instead. */ class TopClassCompleter(clazz: Symbol, module: Symbol) extends SymLoader with FlagAssigningCompleter { -// def makePackage() { -// println("wrong guess; making package "+clazz) -// val ptpe = newPackageType(module.moduleClass) -// for (sym <- List(clazz, module, module.moduleClass)) { -// sym setFlag Flags.PACKAGE -// sym setInfo ptpe -// } -// } - override def complete(sym: Symbol) = { debugInfo("completing "+sym+"/"+clazz.fullName) assert(sym == clazz || sym == module || sym == module.moduleClass) -// try { - atPhaseNotLaterThan(picklerPhase) { + slowButSafeAtPhaseNotLaterThan(picklerPhase) { val loadingMirror = mirrorThatLoaded(sym) val javaClass = loadingMirror.javaClass(clazz.javaClassName) loadingMirror.unpickleClass(clazz, module, javaClass) -// } catch { -// case ex: ClassNotFoundException => makePackage() -// case ex: NoClassDefFoundError => makePackage() - // Note: We catch NoClassDefFoundError because there are situations - // where a package and a class have the same name except for capitalization. - // It seems in this case the class is loaded even if capitalization differs - // but then a NoClassDefFound error is issued with a ("wrong name: ...") - // reason. (I guess this is a concession to Windows). - // The present behavior is a bit too forgiving, in that it masks - // all class load errors, not just wrong name errors. We should try - // to be more discriminating. To get on the right track simply delete - // the clause above and load a collection class such as collection.Iterable. - // You'll see an error that class `parallel` has the wrong name. -// } } } override def load(sym: Symbol) = complete(sym) @@ -97,18 +73,51 @@ private[reflect] trait SymbolLoaders { self: SymbolTable => 0 < dp && dp < (name.length - 1) } + // Since runtime reflection doesn't have a luxury of enumerating all classes + // on the classpath, it has to materialize symbols for top-level definitions + // (packages, classes, objects) on demand. + // + // Someone asks us for a class named `foo.Bar`? Easy. Let's speculatively create + // a package named `foo` and then look up `newTypeName("bar")` in its decls. + // This lookup, implemented in `SymbolLoaders.PackageScope` tests the waters by + // trying to to `Class.forName("foo.Bar")` and then creates a ClassSymbol upon + // success (the whole story is a bit longer, but the rest is irrelevant here). + // + // That's all neat, but these non-deterministic mutations of the global symbol + // table give a lot of trouble in multi-threaded setting. One of the popular + // reflection crashes happens when multiple threads happen to trigger symbol + // materialization multiple times for the same symbol, making subsequent + // reflective operations stumble upon outrageous stuff like overloaded packages. + // + // Short of significantly changing SymbolLoaders I see no other way than just + // to slap a global lock on materialization in runtime reflection. class PackageScope(pkgClass: Symbol) extends Scope(initFingerPrints = -1L) // disable fingerprinting as we do not know entries beforehand with SynchronizedScope { assert(pkgClass.isType) - // disable fingerprinting as we do not know entries beforehand - private val negatives = mutable.Set[Name]() // Syncnote: Performance only, so need not be protected. - override def lookupEntry(name: Name): ScopeEntry = { - val e = super.lookupEntry(name) - if (e != null) - e - else if (isInvalidClassName(name) || (negatives contains name)) - null - else { + + // materializing multiple copies of the same symbol in PackageScope is a very popular bug + // this override does its best to guard against it + override def enter[T <: Symbol](sym: T): T = { + val existing = super.lookupEntry(sym.name) + assert(existing == null || existing.sym.isMethod, s"pkgClass = $pkgClass, sym = $sym, existing = $existing") + super.enter(sym) + } + + // package scopes need to synchronize on the GIL + // because lookupEntry might cause changes to the global symbol table + override def syncLockSynchronized[T](body: => T): T = gilSynchronized(body) + private val negatives = new mutable.HashSet[Name] + override def lookupEntry(name: Name): ScopeEntry = syncLockSynchronized { + def lookupExisting: Option[ScopeEntry] = { + val e = super.lookupEntry(name) + if (e != null) + Some(e) + else if (isInvalidClassName(name) || (negatives contains name)) + Some(null) // TODO: omg + else + None + } + def materialize: ScopeEntry = { val path = if (pkgClass.isEmptyPackageClass) name.toString else pkgClass.fullName + "." + name @@ -137,6 +146,7 @@ private[reflect] trait SymbolLoaders { self: SymbolTable => null } } + lookupExisting getOrElse materialize } } diff --git a/src/reflect/scala/reflect/runtime/SymbolTable.scala b/src/reflect/scala/reflect/runtime/SymbolTable.scala index 5c08e9a508..d317d6a12b 100644 --- a/src/reflect/scala/reflect/runtime/SymbolTable.scala +++ b/src/reflect/scala/reflect/runtime/SymbolTable.scala @@ -8,7 +8,7 @@ import scala.reflect.internal.Flags._ * It can be used either from a reflexive universe (class scala.reflect.runtime.JavaUniverse), or else from * a runtime compiler that uses reflection to get a class information (class scala.tools.reflect.ReflectGlobal) */ -private[scala] trait SymbolTable extends internal.SymbolTable with JavaMirrors with SymbolLoaders with SynchronizedOps { +private[scala] trait SymbolTable extends internal.SymbolTable with JavaMirrors with SymbolLoaders with SynchronizedOps with Gil { def info(msg: => String) = if (settings.verbose.value) println("[reflect-compiler] "+msg) diff --git a/src/reflect/scala/reflect/runtime/SynchronizedOps.scala b/src/reflect/scala/reflect/runtime/SynchronizedOps.scala index 7b280e59b9..f9f4a26b42 100644 --- a/src/reflect/scala/reflect/runtime/SynchronizedOps.scala +++ b/src/reflect/scala/reflect/runtime/SynchronizedOps.scala @@ -8,28 +8,40 @@ private[reflect] trait SynchronizedOps extends internal.SymbolTable // Names + // this lock isn't subsumed by the reflection GIL + // because there's no way newXXXName methods are going to call anything reflective + // therefore we don't have a danger of a deadlock from having a fine-grained lock for name creation private lazy val nameLock = new Object - override def newTermName(s: String): TermName = nameLock.synchronized { super.newTermName(s) } - override def newTypeName(s: String): TypeName = nameLock.synchronized { super.newTypeName(s) } + // these three methods are the only gateways into name hashtable manipulations + // we need to protected them with a lock, because they are by far not atomic + override protected def newTermName(cs: Array[Char], offset: Int, len: Int, cachedString: String): TermName = + nameLock.synchronized { super.newTermName(cs, offset, len, cachedString) } + override protected def toTypeName(termName: TermName): TypeName = nameLock.synchronized { super.toTypeName(termName) } + override protected def toTermName(typeName: TypeName): TermName = nameLock.synchronized { super.toTermName(typeName) } // BaseTypeSeqs override protected def newBaseTypeSeq(parents: List[Type], elems: Array[Type]) = - new BaseTypeSeq(parents, elems) with SynchronizedBaseTypeSeq + // only need to synchronize BaseTypeSeqs if they contain refined types + if (elems.filter(_.isInstanceOf[RefinedType]).nonEmpty) new BaseTypeSeq(parents, elems) with SynchronizedBaseTypeSeq + else new BaseTypeSeq(parents, elems) trait SynchronizedBaseTypeSeq extends BaseTypeSeq { - override def apply(i: Int): Type = synchronized { super.apply(i) } - override def rawElem(i: Int) = synchronized { super.rawElem(i) } - override def typeSymbol(i: Int): Symbol = synchronized { super.typeSymbol(i) } - override def toList: List[Type] = synchronized { super.toList } - override def copy(head: Type, offset: Int): BaseTypeSeq = synchronized { super.copy(head, offset) } - override def map(f: Type => Type): BaseTypeSeq = synchronized { super.map(f) } - override def exists(p: Type => Boolean): Boolean = synchronized { super.exists(p) } - override lazy val maxDepth = synchronized { maxDepthOfElems } - override def toString = synchronized { super.toString } - - override def lateMap(f: Type => Type): BaseTypeSeq = new MappedBaseTypeSeq(this, f) with SynchronizedBaseTypeSeq + override def apply(i: Int): Type = gilSynchronized { super.apply(i) } + override def rawElem(i: Int) = gilSynchronized { super.rawElem(i) } + override def typeSymbol(i: Int): Symbol = gilSynchronized { super.typeSymbol(i) } + override def toList: List[Type] = gilSynchronized { super.toList } + override def copy(head: Type, offset: Int): BaseTypeSeq = gilSynchronized { super.copy(head, offset) } + override def map(f: Type => Type): BaseTypeSeq = gilSynchronized { super.map(f) } + override def exists(p: Type => Boolean): Boolean = gilSynchronized { super.exists(p) } + override lazy val maxDepth = gilSynchronized { maxDepthOfElems } + override def toString = gilSynchronized { super.toString } + + override def lateMap(f: Type => Type): BaseTypeSeq = + // only need to synchronize BaseTypeSeqs if they contain refined types + if (map(f).toList.filter(_.isInstanceOf[RefinedType]).nonEmpty) new MappedBaseTypeSeq(this, f) with SynchronizedBaseTypeSeq + else new MappedBaseTypeSeq(this, f) } // Scopes @@ -38,15 +50,19 @@ private[reflect] trait SynchronizedOps extends internal.SymbolTable override def newNestedScope(outer: Scope): Scope = new Scope(outer) with SynchronizedScope trait SynchronizedScope extends Scope { - override def isEmpty: Boolean = synchronized { super.isEmpty } - override def size: Int = synchronized { super.size } - override def enter[T <: Symbol](sym: T): T = synchronized { super.enter(sym) } - override def rehash(sym: Symbol, newname: Name) = synchronized { super.rehash(sym, newname) } - override def unlink(e: ScopeEntry) = synchronized { super.unlink(e) } - override def unlink(sym: Symbol) = synchronized { super.unlink(sym) } - override def lookupAll(name: Name) = synchronized { super.lookupAll(name) } - override def lookupEntry(name: Name) = synchronized { super.lookupEntry(name) } - override def lookupNextEntry(entry: ScopeEntry) = synchronized { super.lookupNextEntry(entry) } - override def toList: List[Symbol] = synchronized { super.toList } + // we can keep this lock fine-grained, because methods of Scope don't do anything extraordinary, which makes deadlocks impossible + // fancy subclasses of internal.Scopes#Scope should do synchronization themselves (e.g. see PackageScope for an example) + private lazy val syncLock = new Object + def syncLockSynchronized[T](body: => T): T = if (isCompilerUniverse) body else syncLock.synchronized { body } + override def isEmpty: Boolean = syncLockSynchronized { super.isEmpty } + override def size: Int = syncLockSynchronized { super.size } + override def enter[T <: Symbol](sym: T): T = syncLockSynchronized { super.enter(sym) } + override def rehash(sym: Symbol, newname: Name) = syncLockSynchronized { super.rehash(sym, newname) } + override def unlink(e: ScopeEntry) = syncLockSynchronized { super.unlink(e) } + override def unlink(sym: Symbol) = syncLockSynchronized { super.unlink(sym) } + override def lookupAll(name: Name) = syncLockSynchronized { super.lookupAll(name) } + override def lookupEntry(name: Name) = syncLockSynchronized { super.lookupEntry(name) } + override def lookupNextEntry(entry: ScopeEntry) = syncLockSynchronized { super.lookupNextEntry(entry) } + override def toList: List[Symbol] = syncLockSynchronized { super.toList } } } diff --git a/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala b/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala index 00f6952dc1..5a0ac01ac4 100644 --- a/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala +++ b/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala @@ -5,14 +5,18 @@ import scala.reflect.io.AbstractFile private[reflect] trait SynchronizedSymbols extends internal.Symbols { self: SymbolTable => - override protected def nextId() = synchronized { super.nextId() } + // we can keep this lock fine-grained, because nextId is just a simple increment, which makes deadlocks impossible + private lazy val nextIdLock = new Object + override protected def nextId() = nextIdLock.synchronized { super.nextId() } + // we can keep this lock fine-grained, because freshExistentialName is just a simple increment, which makes deadlocks impossible + private lazy val freshExistentialNameLock = new Object override protected def freshExistentialName(suffix: String) = - synchronized { super.freshExistentialName(suffix) } + freshExistentialNameLock.synchronized { super.freshExistentialName(suffix) } // Set the fields which point companions at one another. Returns the module. override def connectModuleToClass(m: ModuleSymbol, moduleClass: ClassSymbol): ModuleSymbol = - synchronized { super.connectModuleToClass(m, moduleClass) } + gilSynchronized { super.connectModuleToClass(m, moduleClass) } override def newFreeTermSymbol(name: TermName, value: => Any, flags: Long = 0L, origin: String = null): FreeTermSymbol = new FreeTermSymbol(name, value, origin) with SynchronizedTermSymbol initFlags flags @@ -24,35 +28,40 @@ private[reflect] trait SynchronizedSymbols extends internal.Symbols { self: Symb trait SynchronizedSymbol extends Symbol { - override def rawflags = synchronized { super.rawflags } - override def rawflags_=(x: Long) = synchronized { super.rawflags_=(x) } - - override def rawowner = synchronized { super.rawowner } - override def owner_=(owner: Symbol) = synchronized { super.owner_=(owner) } - - override def validTo = synchronized { super.validTo } - override def validTo_=(x: Period) = synchronized { super.validTo_=(x) } - - override def pos = synchronized { super.pos } - override def setPos(pos: Position): this.type = { synchronized { super.setPos(pos) }; this } - - override def privateWithin = synchronized { super.privateWithin } - override def privateWithin_=(sym: Symbol) = synchronized { super.privateWithin_=(sym) } - - override def info = synchronized { super.info } - override def info_=(info: Type) = synchronized { super.info_=(info) } - override def updateInfo(info: Type): Symbol = synchronized { super.updateInfo(info) } - override def rawInfo: Type = synchronized { super.rawInfo } - - override def typeParams: List[Symbol] = synchronized { super.typeParams } - - override def reset(completer: Type): this.type = synchronized { super.reset(completer) } - - override def infosString: String = synchronized { super.infosString } - - override def annotations: List[AnnotationInfo] = synchronized { super.annotations } - override def setAnnotations(annots: List[AnnotationInfo]): this.type = { synchronized { super.setAnnotations(annots) }; this } - + def gilSynchronizedIfNotInited[T](body: => T): T = { + if (isFullyInitialized) body + else gilSynchronized { body } + } + + override def validTo = gilSynchronizedIfNotInited { super.validTo } + override def info = gilSynchronizedIfNotInited { super.info } + override def rawInfo: Type = gilSynchronizedIfNotInited { super.rawInfo } + + override def typeParams: List[Symbol] = gilSynchronizedIfNotInited { + if (isCompilerUniverse) super.typeParams + else { + if (isMonomorphicType) Nil + else { + // analogously to the "info" getter, here we allow for two completions: + // one: sourceCompleter to LazyType, two: LazyType to completed type + if (validTo == NoPeriod) + rawInfo load this + if (validTo == NoPeriod) + rawInfo load this + + rawInfo.typeParams + } + } + } + override def unsafeTypeParams: List[Symbol] = gilSynchronizedIfNotInited { + if (isCompilerUniverse) super.unsafeTypeParams + else { + if (isMonomorphicType) Nil + else rawInfo.typeParams + } + } + + override def isStable: Boolean = gilSynchronized { super.isStable } // ------ creators ------------------------------------------------------------------- @@ -92,49 +101,38 @@ private[reflect] trait SynchronizedSymbols extends internal.Symbols { self: Symb override protected def createModuleSymbol(name: TermName, pos: Position, newFlags: Long): ModuleSymbol = new ModuleSymbol(this, pos, name) with SynchronizedTermSymbol initFlags newFlags - override protected def createPackageSymbol(name: TermName, pos: Position, newFlags: Long): ModuleSymbol = createModuleSymbol(name, pos, newFlags) + override protected def createPackageSymbol(name: TermName, pos: Position, newFlags: Long): ModuleSymbol = + createModuleSymbol(name, pos, newFlags) + + override protected def createValueParameterSymbol(name: TermName, pos: Position, newFlags: Long) = + new TermSymbol(this, pos, name) with SynchronizedTermSymbol initFlags newFlags - // TODO - // override protected def createValueParameterSymbol(name: TermName, pos: Position, newFlags: Long) - // override protected def createValueMemberSymbol(name: TermName, pos: Position, newFlags: Long) + override protected def createValueMemberSymbol(name: TermName, pos: Position, newFlags: Long) = + new TermSymbol(this, pos, name) with SynchronizedTermSymbol initFlags newFlags } // ------- subclasses --------------------------------------------------------------------- - trait SynchronizedTermSymbol extends TermSymbol with SynchronizedSymbol { - override def name_=(x: Name) = synchronized { super.name_=(x) } - override def rawname = synchronized { super.rawname } - override def referenced: Symbol = synchronized { super.referenced } - override def referenced_=(x: Symbol) = synchronized { super.referenced_=(x) } - } + trait SynchronizedTermSymbol extends SynchronizedSymbol trait SynchronizedMethodSymbol extends MethodSymbol with SynchronizedTermSymbol { - override def typeAsMemberOf(pre: Type): Type = synchronized { super.typeAsMemberOf(pre) } - override def paramss: List[List[Symbol]] = synchronized { super.paramss } - override def returnType: Type = synchronized { super.returnType } + // we can keep this lock fine-grained, because it's just a cache over asSeenFrom, which makes deadlocks impossible + // unfortunately we cannot elide this lock, because the cache depends on `pre` + private lazy val typeAsMemberOfLock = new Object + override def typeAsMemberOf(pre: Type): Type = gilSynchronizedIfNotInited { typeAsMemberOfLock.synchronized { super.typeAsMemberOf(pre) } } } + trait SynchronizedModuleSymbol extends ModuleSymbol with SynchronizedTermSymbol + trait SynchronizedTypeSymbol extends TypeSymbol with SynchronizedSymbol { - override def name_=(x: Name) = synchronized { super.name_=(x) } - override def rawname = synchronized { super.rawname } - override def typeConstructor: Type = synchronized { super.typeConstructor } - override def tpe: Type = synchronized { super.tpe } + // unlike with typeConstructor, a lock is necessary here, because tpe calculation relies on + // temporarily assigning NoType to tpeCache to detect cyclic reference errors + private lazy val tpeLock = new Object + override def tpe: Type = gilSynchronizedIfNotInited { tpeLock.synchronized { super.tpe } } } - trait SynchronizedClassSymbol extends ClassSymbol with SynchronizedTypeSymbol { - override def associatedFile = synchronized { super.associatedFile } - override def associatedFile_=(f: AbstractFile) = synchronized { super.associatedFile_=(f) } - override def thisSym: Symbol = synchronized { super.thisSym } - override def thisType: Type = synchronized { super.thisType } - override def typeOfThis: Type = synchronized { super.typeOfThis } - override def typeOfThis_=(tp: Type) = synchronized { super.typeOfThis_=(tp) } - override def children = synchronized { super.children } - override def addChild(sym: Symbol) = synchronized { super.addChild(sym) } - } + trait SynchronizedClassSymbol extends ClassSymbol with SynchronizedTypeSymbol - trait SynchronizedModuleClassSymbol extends ModuleClassSymbol with SynchronizedClassSymbol { - override def sourceModule = synchronized { super.sourceModule } - override def implicitMembers: Scope = synchronized { super.implicitMembers } - } + trait SynchronizedModuleClassSymbol extends ModuleClassSymbol with SynchronizedClassSymbol } diff --git a/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala b/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala index a3e7c28ca4..939363f8b4 100644 --- a/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala +++ b/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala @@ -12,8 +12,9 @@ private[reflect] trait SynchronizedTypes extends internal.Types { self: SymbolTa // No sharing of map objects: override protected def commonOwnerMap = new CommonOwnerMap - private object uniqueLock - + // we can keep this lock fine-grained, because super.unique just updates the cache + // and, in particular, doesn't call any reflection APIs which makes deadlocks impossible + private lazy val uniqueLock = new Object private val uniques = WeakHashMap[Type, WeakReference[Type]]() override def unique[T <: Type](tp: T): T = uniqueLock.synchronized { // we need to have weak uniques for runtime reflection @@ -37,46 +38,35 @@ private[reflect] trait SynchronizedTypes extends internal.Types { self: SymbolTa } class SynchronizedUndoLog extends UndoLog { - private val actualLock = new java.util.concurrent.locks.ReentrantLock - - final override def lock(): Unit = actualLock.lock() - final override def unlock(): Unit = actualLock.unlock() + final override def lock(): Unit = gil.lock() + final override def unlock(): Unit = gil.unlock() } override protected def newUndoLog = new SynchronizedUndoLog override protected def baseTypeOfNonClassTypeRef(tpe: NonClassTypeRef, clazz: Symbol) = - synchronized { super.baseTypeOfNonClassTypeRef(tpe, clazz) } - - private object subsametypeLock + gilSynchronized { super.baseTypeOfNonClassTypeRef(tpe, clazz) } override def isSameType(tp1: Type, tp2: Type): Boolean = - subsametypeLock.synchronized { super.isSameType(tp1, tp2) } + gilSynchronized { super.isSameType(tp1, tp2) } override def isDifferentType(tp1: Type, tp2: Type): Boolean = - subsametypeLock.synchronized { super.isDifferentType(tp1, tp2) } + gilSynchronized { super.isDifferentType(tp1, tp2) } override def isSubType(tp1: Type, tp2: Type, depth: Int): Boolean = - subsametypeLock.synchronized { super.isSubType(tp1, tp2, depth) } - - private object lubglbLock + gilSynchronized { super.isSubType(tp1, tp2, depth) } override def glb(ts: List[Type]): Type = - lubglbLock.synchronized { super.glb(ts) } + gilSynchronized { super.glb(ts) } override def lub(ts: List[Type]): Type = - lubglbLock.synchronized { super.lub(ts) } - - private object indentLock - - override protected def explain[T](op: String, p: (Type, T) => Boolean, tp1: Type, arg2: T): Boolean = { - indentLock.synchronized { super.explain(op, p, tp1, arg2) } - } + gilSynchronized { super.lub(ts) } - private object toStringLock + override protected def explain[T](op: String, p: (Type, T) => Boolean, tp1: Type, arg2: T): Boolean = + gilSynchronized { super.explain(op, p, tp1, arg2) } override protected def typeToString(tpe: Type): String = - toStringLock.synchronized(super.typeToString(tpe)) + gilSynchronized(super.typeToString(tpe)) /* The idea of caches is as follows. * When in reflexive mode, a cache is either null, or one sentinal @@ -89,18 +79,18 @@ private[reflect] trait SynchronizedTypes extends internal.Types { self: SymbolTa */ override protected def defineUnderlyingOfSingleType(tpe: SingleType) = - tpe.synchronized { super.defineUnderlyingOfSingleType(tpe) } + gilSynchronized { super.defineUnderlyingOfSingleType(tpe) } override protected def defineBaseTypeSeqOfCompoundType(tpe: CompoundType) = - tpe.synchronized { super.defineBaseTypeSeqOfCompoundType(tpe) } + gilSynchronized { super.defineBaseTypeSeqOfCompoundType(tpe) } override protected def defineBaseClassesOfCompoundType(tpe: CompoundType) = - tpe.synchronized { super.defineBaseClassesOfCompoundType(tpe) } + gilSynchronized { super.defineBaseClassesOfCompoundType(tpe) } override protected def defineParentsOfTypeRef(tpe: TypeRef) = - tpe.synchronized { super.defineParentsOfTypeRef(tpe) } + gilSynchronized { super.defineParentsOfTypeRef(tpe) } override protected def defineBaseTypeSeqOfTypeRef(tpe: TypeRef) = - tpe.synchronized { super.defineBaseTypeSeqOfTypeRef(tpe) } + gilSynchronized { super.defineBaseTypeSeqOfTypeRef(tpe) } } diff --git a/src/reflect/scala/reflect/runtime/TwoWayCache.scala b/src/reflect/scala/reflect/runtime/TwoWayCache.scala deleted file mode 100644 index 05debcba65..0000000000 --- a/src/reflect/scala/reflect/runtime/TwoWayCache.scala +++ /dev/null @@ -1,66 +0,0 @@ -package scala.reflect -package runtime - -import scala.collection.mutable.WeakHashMap -import java.lang.ref.WeakReference - -/** A cache that maintains a bijection between Java reflection type `J` - * and Scala reflection type `S`. - * - * The cache is two-way weak (i.e. is powered by weak references), - * so that neither Java artifacts prevent Scala artifacts from being garbage collected, - * nor the other way around. - */ -private[runtime] class TwoWayCache[J, S] { - - private val toScalaMap = new WeakHashMap[J, WeakReference[S]] - private val toJavaMap = new WeakHashMap[S, WeakReference[J]] - - def enter(j: J, s: S) = synchronized { - // debugInfo("cached: "+j+"/"+s) - toScalaMap(j) = new WeakReference(s) - toJavaMap(s) = new WeakReference(j) - } - - private object SomeRef { - def unapply[T](optRef: Option[WeakReference[T]]): Option[T] = - if (optRef.nonEmpty) { - val result = optRef.get.get - if (result != null) Some(result) else None - } else None - } - - def toScala(key: J)(body: => S): S = synchronized { - toScalaMap get key match { - case SomeRef(v) => - v - case _ => - val result = body - enter(key, result) - result - } - } - - def toJava(key: S)(body: => J): J = synchronized { - toJavaMap get key match { - case SomeRef(v) => - v - case _ => - val result = body - enter(result, key) - result - } - } - - def toJavaOption(key: S)(body: => Option[J]): Option[J] = synchronized { - toJavaMap get key match { - case SomeRef(v) => - Some(v) - case _ => - val result = body - for (value <- result) enter(value, key) - result - } - } -} - diff --git a/src/reflect/scala/reflect/runtime/TwoWayCaches.scala b/src/reflect/scala/reflect/runtime/TwoWayCaches.scala new file mode 100644 index 0000000000..6e2890e536 --- /dev/null +++ b/src/reflect/scala/reflect/runtime/TwoWayCaches.scala @@ -0,0 +1,68 @@ +package scala.reflect +package runtime + +import scala.collection.mutable.WeakHashMap +import java.lang.ref.WeakReference + +/** A cache that maintains a bijection between Java reflection type `J` + * and Scala reflection type `S`. + * + * The cache is two-way weak (i.e. is powered by weak references), + * so that neither Java artifacts prevent Scala artifacts from being garbage collected, + * nor the other way around. + */ +private[runtime] trait TwoWayCaches { self: SymbolTable => + class TwoWayCache[J, S] { + + private val toScalaMap = new WeakHashMap[J, WeakReference[S]] + private val toJavaMap = new WeakHashMap[S, WeakReference[J]] + + def enter(j: J, s: S) = gilSynchronized { + // debugInfo("cached: "+j+"/"+s) + toScalaMap(j) = new WeakReference(s) + toJavaMap(s) = new WeakReference(j) + } + + private object SomeRef { + def unapply[T](optRef: Option[WeakReference[T]]): Option[T] = + if (optRef.nonEmpty) { + val result = optRef.get.get + if (result != null) Some(result) else None + } else None + } + + def toScala(key: J)(body: => S): S = gilSynchronized { + toScalaMap get key match { + case SomeRef(v) => + v + case _ => + val result = body + enter(key, result) + result + } + } + + def toJava(key: S)(body: => J): J = gilSynchronized { + toJavaMap get key match { + case SomeRef(v) => + v + case _ => + val result = body + enter(result, key) + result + } + } + + def toJavaOption(key: S)(body: => Option[J]): Option[J] = gilSynchronized { + toJavaMap get key match { + case SomeRef(v) => + Some(v) + case _ => + val result = body + for (value <- result) enter(value, key) + result + } + } + } +} + |