From 21d5d3820b285b7c96fb2fadbaec7f5db12ebaa6 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Thu, 7 Feb 2013 14:05:54 +0100 Subject: moves Symbol#SymbolKind to Symbols Too bad I didn't notice that before. That will free up quite a bit of memory, removing an extraneous field in every single Symbol, namely the: private volatile Symbols.Symbol.SymbolKind$ SymbolKind$module --- src/reflect/scala/reflect/internal/Symbols.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/reflect') diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index d9eb48ff2d..b980f3d8c2 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -108,6 +108,8 @@ trait Symbols extends api.Symbols { self: SymbolTable => def setter: Symbol = setter(owner) } + private[Symbols] 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 @@ -2248,7 +2250,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") -- cgit v1.2.3 From 0262941b3c5016d84f111bb9956190d333c7acf2 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Sun, 3 Feb 2013 13:59:35 +0100 Subject: removes the crazy extraneous log --- src/reflect/scala/reflect/runtime/JavaUniverse.scala | 2 +- test/files/run/reflection-crazy-logs.check | 1 + test/files/run/reflection-crazy-logs.scala | 5 +++++ 3 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 test/files/run/reflection-crazy-logs.check create mode 100644 test/files/run/reflection-crazy-logs.scala (limited to 'src/reflect') diff --git a/src/reflect/scala/reflect/runtime/JavaUniverse.scala b/src/reflect/scala/reflect/runtime/JavaUniverse.scala index e18435d5b0..1b69ca4e89 100644 --- a/src/reflect/scala/reflect/runtime/JavaUniverse.scala +++ b/src/reflect/scala/reflect/runtime/JavaUniverse.scala @@ -17,7 +17,7 @@ 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 diff --git a/test/files/run/reflection-crazy-logs.check b/test/files/run/reflection-crazy-logs.check new file mode 100644 index 0000000000..27ba77ddaf --- /dev/null +++ b/test/files/run/reflection-crazy-logs.check @@ -0,0 +1 @@ +true diff --git a/test/files/run/reflection-crazy-logs.scala b/test/files/run/reflection-crazy-logs.scala new file mode 100644 index 0000000000..6844faabf6 --- /dev/null +++ b/test/files/run/reflection-crazy-logs.scala @@ -0,0 +1,5 @@ +import scala.reflect.runtime.universe._ + +object Test extends App { + println(typeOf[List[Any]] <:< typeOf[List[T] forSome { type T }]) +} \ No newline at end of file -- cgit v1.2.3 From a9dca512d8a99fd7b9866cfad6b8ae9b5f451f4b Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Tue, 29 Jan 2013 20:54:47 +0100 Subject: synchronizes symbols Synchronization via decoration would be neat if it actually worked. Unfortunately, root symbols never got decorated, therefore their children also never got decorated and all the way down to the very turtles. This commit fixes this sad issue by turning root symbols from objects to lazy vals. Yes, this is going to induce a performance penalty, which will hopefully not be high enough to invalidate this cornerstone of our synchronization strategy. Now when root symbols are lazy vals, they can be overridden in the runtime reflexive universe and decorated with SynchronizedSymbol, which makes their children sync and sound. --- src/reflect/scala/reflect/internal/Mirrors.scala | 35 ++++++++++++++-------- .../scala/reflect/runtime/JavaMirrors.scala | 5 ++++ .../reflect/runtime/SynchronizedSymbols.scala | 11 ++++--- 3 files changed, 35 insertions(+), 16 deletions(-) (limited to 'src/reflect') diff --git a/src/reflect/scala/reflect/internal/Mirrors.scala b/src/reflect/scala/reflect/internal/Mirrors.scala index 0beb8e368f..4771404b29 100644 --- a/src/reflect/scala/reflect/internal/Mirrors.scala +++ b/src/reflect/scala/reflect/internal/Mirrors.scala @@ -262,34 +262,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 => . - 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 => . + 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 , the actual root of everything except the package _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/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala index 778c826dc0..b38b7d0f94 100644 --- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala +++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala @@ -71,6 +71,11 @@ 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 + /** The lazy type for root. */ override lazy val rootLoader = new LazyType with FlagAgnosticCompleter { diff --git a/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala b/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala index 00f6952dc1..ba8ff82b1b 100644 --- a/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala +++ b/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala @@ -92,11 +92,14 @@ 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) - // TODO - // override protected def createValueParameterSymbol(name: TermName, pos: Position, newFlags: Long) - // override protected def createValueMemberSymbol(name: TermName, pos: Position, newFlags: Long) + override protected def createValueParameterSymbol(name: TermName, pos: Position, newFlags: Long) = + new TermSymbol(this, pos, name) with SynchronizedTermSymbol initFlags newFlags + + override protected def createValueMemberSymbol(name: TermName, pos: Position, newFlags: Long) = + new TermSymbol(this, pos, name) with SynchronizedTermSymbol initFlags newFlags } // ------- subclasses --------------------------------------------------------------------- -- cgit v1.2.3 From b2c2493b22e2b6b8feb8124a2503fbb794c0bde7 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Tue, 29 Jan 2013 20:52:10 +0100 Subject: reflection no longer uses atPhase and friends Mentioned methods mutate the global `atPhaseStack` variable, which can easily lead to imbalances and, ultimately, to the empty stack error. Luckily for us, there's only one dummy phase, SomePhase, which is used by runtime reflection, so there is absolutely zero need to invoke atPhase in non-compiler reflexive universes. The cleanest solution would be to override `atPhase` for runtime reflection, but it's @inline final, so I didn't want to pay performance penalties for something that's used three times in runtime reflection (during unpickling, in reflection-specific completers and in `Symbol.typeParams/unsafeTypeParams`). Therefore I added overrideable analogues of `atPhase` and `atPhaseNotLaterThan` which are called from the aforementioned code shared between the compiler and runtime reflection. I also had to duplicate the code of `Symbol.XXXtypeParams`, again due to them being very performance-sensitive. --- .../scala/reflect/internal/SymbolTable.scala | 5 +++++ .../reflect/internal/pickling/UnPickler.scala | 4 ++-- .../scala/reflect/runtime/SymbolLoaders.scala | 26 +--------------------- .../reflect/runtime/SynchronizedSymbols.scala | 24 +++++++++++++++++++- 4 files changed, 31 insertions(+), 28 deletions(-) (limited to 'src/reflect') 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/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/SymbolLoaders.scala b/src/reflect/scala/reflect/runtime/SymbolLoaders.scala index 311db64b91..23c0e1889f 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) diff --git a/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala b/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala index ba8ff82b1b..cf4a3bc7e2 100644 --- a/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala +++ b/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala @@ -44,7 +44,29 @@ private[reflect] trait SynchronizedSymbols extends internal.Symbols { self: Symb 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 typeParams: List[Symbol] = synchronized { + 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] = synchronized { + if (isCompilerUniverse) super.unsafeTypeParams + else { + if (isMonomorphicType) Nil + else rawInfo.typeParams + } + } override def reset(completer: Type): this.type = synchronized { super.reset(completer) } -- cgit v1.2.3 From 981da8edfcf3a2b6c727a8f12c6b81a9535fa50b Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Tue, 29 Jan 2013 20:42:55 +0100 Subject: cleans up initialization of runtime reflection At first I just tried to remove syntheticCoreClasses from missingHook and put them into the initializer of freshly created mirrors in order to reduce the non-determinism in mutations of the global symbol table. And then it didn't work, crashing on me claiming that AnyRef is missing. Apparently we still need AnyRefClass in missingHook, just because it's impossible to initialize (i.e. unpickle) ScalaPackageClass without it. And then it still didn't work, whining about multiple overloaded defs of some synthetic symbols. That was really tricky, but I figured it out as well by initializing ScalaPackageClass first before forcing any synthetic symbols (see the details in comments). --- .../scala/reflect/internal/Definitions.scala | 18 +++++++++++- src/reflect/scala/reflect/internal/Mirrors.scala | 13 +++++++++ src/reflect/scala/reflect/internal/StdNames.scala | 2 ++ src/reflect/scala/reflect/internal/Symbols.scala | 9 +++--- .../scala/reflect/runtime/JavaMirrors.scala | 33 ++++++---------------- .../scala/reflect/runtime/JavaUniverse.scala | 4 +++ .../scala/reflect/runtime/SymbolLoaders.scala | 9 ++++++ 7 files changed, 59 insertions(+), 29 deletions(-) (limited to 'src/reflect') diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index 6e4ca76382..52873dea12 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -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 4771404b29..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 + }) + } } } 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/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index b980f3d8c2..43832eba7f 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -3208,10 +3208,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/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala index b38b7d0f94..a61e3f7b83 100644 --- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala +++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala @@ -46,16 +46,6 @@ 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) @@ -1251,11 +1241,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 * ., otherwise return NoSymbol. * Exception: If owner is root and a java class with given name exists, create symbol in empty package instead @@ -1272,15 +1257,15 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni 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 1b69ca4e89..7321214a65 100644 --- a/src/reflect/scala/reflect/runtime/JavaUniverse.scala +++ b/src/reflect/scala/reflect/runtime/JavaUniverse.scala @@ -24,5 +24,9 @@ class JavaUniverse extends internal.SymbolTable with ReflectSetup with runtime.S def newLazyTreeCopier: TreeCopier = new LazyTreeCopier init() + + def init() { + definitions.init() + } } diff --git a/src/reflect/scala/reflect/runtime/SymbolLoaders.scala b/src/reflect/scala/reflect/runtime/SymbolLoaders.scala index 23c0e1889f..484053640f 100644 --- a/src/reflect/scala/reflect/runtime/SymbolLoaders.scala +++ b/src/reflect/scala/reflect/runtime/SymbolLoaders.scala @@ -76,6 +76,15 @@ private[reflect] trait SymbolLoaders { self: SymbolTable => class PackageScope(pkgClass: Symbol) extends Scope(initFingerPrints = -1L) // disable fingerprinting as we do not know entries beforehand with SynchronizedScope { assert(pkgClass.isType) + + // 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) + } + // 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 = { -- cgit v1.2.3 From 5b37cfb19a41fc1b775dbdaf247e765fb6d245e0 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Tue, 29 Jan 2013 20:47:37 +0100 Subject: introduces GIL to Scala reflection On a serious note, I feel really uncomfortable about having to juggle this slew of locks. Despite that I can't immediately find a deadlock, I'm 100% sure there is one hiding in the shadows. Hence, I'm abandoning all runtime reflection locks in favor of a single per-universe one. --- .../scala/reflect/internal/BaseTypeSeqs.scala | 2 +- src/reflect/scala/reflect/runtime/Gil.scala | 22 ++++++ .../scala/reflect/runtime/JavaMirrors.scala | 14 ++-- .../scala/reflect/runtime/SymbolLoaders.scala | 43 +++++++--- .../scala/reflect/runtime/SymbolTable.scala | 2 +- .../scala/reflect/runtime/SynchronizedOps.scala | 56 +++++++------ .../reflect/runtime/SynchronizedSymbols.scala | 92 +++++++++++----------- .../scala/reflect/runtime/SynchronizedTypes.scala | 48 +++++------ .../scala/reflect/runtime/TwoWayCache.scala | 66 ---------------- .../scala/reflect/runtime/TwoWayCaches.scala | 68 ++++++++++++++++ 10 files changed, 235 insertions(+), 178 deletions(-) create mode 100644 src/reflect/scala/reflect/runtime/Gil.scala delete mode 100644 src/reflect/scala/reflect/runtime/TwoWayCache.scala create mode 100644 src/reflect/scala/reflect/runtime/TwoWayCaches.scala (limited to 'src/reflect') 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/runtime/Gil.scala b/src/reflect/scala/reflect/runtime/Gil.scala new file mode 100644 index 0000000000..8a8bfebf8c --- /dev/null +++ b/src/reflect/scala/reflect/runtime/Gil.scala @@ -0,0 +1,22 @@ +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 = { + 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 a61e3f7b83..48d887b5c6 100644 --- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala +++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala @@ -24,7 +24,7 @@ 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]]() @@ -46,9 +46,11 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni trait JavaClassCompleter extends FlagAssigningCompleter - 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 */ @@ -662,7 +664,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 { @@ -878,7 +880,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 diff --git a/src/reflect/scala/reflect/runtime/SymbolLoaders.scala b/src/reflect/scala/reflect/runtime/SymbolLoaders.scala index 484053640f..bd5be44b35 100644 --- a/src/reflect/scala/reflect/runtime/SymbolLoaders.scala +++ b/src/reflect/scala/reflect/runtime/SymbolLoaders.scala @@ -73,6 +73,24 @@ 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) @@ -85,15 +103,21 @@ private[reflect] trait SymbolLoaders { self: SymbolTable => super.enter(sym) } - // 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 { + // 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 @@ -122,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..b674fc380f 100644 --- a/src/reflect/scala/reflect/runtime/SynchronizedOps.scala +++ b/src/reflect/scala/reflect/runtime/SynchronizedOps.scala @@ -8,6 +8,9 @@ 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) } @@ -16,20 +19,25 @@ private[reflect] trait SynchronizedOps extends internal.SymbolTable // 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 +46,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 = 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 cf4a3bc7e2..3b5029a263 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,27 +28,27 @@ 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 rawflags = gilSynchronized { super.rawflags } + override def rawflags_=(x: Long) = gilSynchronized { super.rawflags_=(x) } - override def rawowner = synchronized { super.rawowner } - override def owner_=(owner: Symbol) = synchronized { super.owner_=(owner) } + override def rawowner = gilSynchronized { super.rawowner } + override def owner_=(owner: Symbol) = gilSynchronized { super.owner_=(owner) } - override def validTo = synchronized { super.validTo } - override def validTo_=(x: Period) = synchronized { super.validTo_=(x) } + override def validTo = gilSynchronized { super.validTo } + override def validTo_=(x: Period) = gilSynchronized { super.validTo_=(x) } - override def pos = synchronized { super.pos } - override def setPos(pos: Position): this.type = { synchronized { super.setPos(pos) }; this } + override def pos = gilSynchronized { super.pos } + override def setPos(pos: Position): this.type = { gilSynchronized { super.setPos(pos) }; this } - override def privateWithin = synchronized { super.privateWithin } - override def privateWithin_=(sym: Symbol) = synchronized { super.privateWithin_=(sym) } + override def privateWithin = gilSynchronized { super.privateWithin } + override def privateWithin_=(sym: Symbol) = gilSynchronized { 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 info = gilSynchronized { super.info } + override def info_=(info: Type) = gilSynchronized { super.info_=(info) } + override def updateInfo(info: Type): Symbol = gilSynchronized { super.updateInfo(info) } + override def rawInfo: Type = gilSynchronized { super.rawInfo } - override def typeParams: List[Symbol] = synchronized { + override def typeParams: List[Symbol] = gilSynchronized { if (isCompilerUniverse) super.typeParams else { if (isMonomorphicType) Nil @@ -60,7 +64,7 @@ private[reflect] trait SynchronizedSymbols extends internal.Symbols { self: Symb } } } - override def unsafeTypeParams: List[Symbol] = synchronized { + override def unsafeTypeParams: List[Symbol] = gilSynchronized { if (isCompilerUniverse) super.unsafeTypeParams else { if (isMonomorphicType) Nil @@ -68,12 +72,12 @@ private[reflect] trait SynchronizedSymbols extends internal.Symbols { self: Symb } } - override def reset(completer: Type): this.type = synchronized { super.reset(completer) } + override def reset(completer: Type): this.type = gilSynchronized { super.reset(completer) } - override def infosString: String = synchronized { super.infosString } + override def infosString: String = gilSynchronized { super.infosString } - override def annotations: List[AnnotationInfo] = synchronized { super.annotations } - override def setAnnotations(annots: List[AnnotationInfo]): this.type = { synchronized { super.setAnnotations(annots) }; this } + override def annotations: List[AnnotationInfo] = gilSynchronized { super.annotations } + override def setAnnotations(annots: List[AnnotationInfo]): this.type = { gilSynchronized { super.setAnnotations(annots) }; this } // ------ creators ------------------------------------------------------------------- @@ -127,39 +131,39 @@ private[reflect] trait SynchronizedSymbols extends internal.Symbols { self: Symb // ------- 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) } + override def name_=(x: Name) = gilSynchronized { super.name_=(x) } + override def rawname = gilSynchronized { super.rawname } + override def referenced: Symbol = gilSynchronized { super.referenced } + override def referenced_=(x: Symbol) = gilSynchronized { super.referenced_=(x) } } 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 } + override def typeAsMemberOf(pre: Type): Type = gilSynchronized { super.typeAsMemberOf(pre) } + override def paramss: List[List[Symbol]] = gilSynchronized { super.paramss } + override def returnType: Type = gilSynchronized { super.returnType } } 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 } + override def name_=(x: Name) = gilSynchronized { super.name_=(x) } + override def rawname = gilSynchronized { super.rawname } + override def typeConstructor: Type = gilSynchronized { super.typeConstructor } + override def tpe: Type = gilSynchronized { 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) } + override def associatedFile = gilSynchronized { super.associatedFile } + override def associatedFile_=(f: AbstractFile) = gilSynchronized { super.associatedFile_=(f) } + override def thisSym: Symbol = gilSynchronized { super.thisSym } + override def thisType: Type = gilSynchronized { super.thisType } + override def typeOfThis: Type = gilSynchronized { super.typeOfThis } + override def typeOfThis_=(tp: Type) = gilSynchronized { super.typeOfThis_=(tp) } + override def children = gilSynchronized { super.children } + override def addChild(sym: Symbol) = gilSynchronized { super.addChild(sym) } } trait SynchronizedModuleClassSymbol extends ModuleClassSymbol with SynchronizedClassSymbol { - override def sourceModule = synchronized { super.sourceModule } - override def implicitMembers: Scope = synchronized { super.implicitMembers } + override def sourceModule = gilSynchronized { super.sourceModule } + override def implicitMembers: Scope = gilSynchronized { super.implicitMembers } } } 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 + } + } + } +} + -- cgit v1.2.3 From 735634f1d634d2d6a2f8ed44f2e6185adc46c695 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Thu, 7 Feb 2013 14:10:47 +0100 Subject: initializes lazy vals and inner objects in advance As discussed at http://groups.google.com/group/scala-internals/browse_thread/thread/97840ba4fd37b52e, `synchronized(this)` employed by lazy val and inner object initialization is an excellent way to deadlock yourself in the foot. Imagine a thread, which grabs a reflection GIL and then calls one of those lazy vals / objects that reflection exposes (e.g. a companion module of an innocently looking SingleType case class). Then imagine another thread, which calls something else in SymbolTable, grabbing symbol table's monitor, and then tries to get a reflection GIL to do something non-trivial. Hello, we've just arrived at a deadlock. Since, as discussed in the aforementioned thread, there's no easy way to change lazy vals / inner objects in reflection to use GIL instead of synchronizing on this, I bit the bullet and manually initialized all things with deferred initialization defined in reflect.runtime.SymbolTable. The list of all things `$lzycompute` has been mined by a simple Python script, then I copy/pasted that list into `JavaUniverse.scala` and went ahead forcing objects and lazy vals mentioned there. Notably, I've been able to force all lazy vals in Definitions.scala. There are some todos left, but I suggest we move forward without securing them, because the 2.10.1-RC1 release date is very close, so we'd better have a 95% solution instead of keeping reflection thread-unsafe. Though here's the list of todo lazy vals for the reference: * BaseTypeSeq.maxDepth * WeakTypeTag.tpe * AnnotationInfo.forcedInfo For each of those lazy vals we need to make sure that their initializers never call back into themselves. Otherwise, there's a danger of a deadlock. --- .../scala/reflect/internal/Definitions.scala | 2 +- src/reflect/scala/reflect/internal/Symbols.scala | 2 +- src/reflect/scala/reflect/internal/Types.scala | 4 +- .../scala/reflect/runtime/JavaMirrors.scala | 14 +- .../scala/reflect/runtime/JavaUniverse.scala | 1024 ++++++++++++++++++++ 5 files changed, 1041 insertions(+), 5 deletions(-) (limited to 'src/reflect') diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index 52873dea12..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 diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index 43832eba7f..0a600432fd 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -108,7 +108,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => def setter: Symbol = setter(owner) } - private[Symbols] case class SymbolKind(accurate: String, sanitized: String, abbreviation: String) + 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) diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index fb493fabd8..0afbdc56c8 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -3930,8 +3930,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/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala index 48d887b5c6..ac968b8e3f 100644 --- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala +++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala @@ -26,7 +26,7 @@ import scala.reflect.internal.util.Collections._ 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) @@ -68,6 +68,18 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni 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 { diff --git a/src/reflect/scala/reflect/runtime/JavaUniverse.scala b/src/reflect/scala/reflect/runtime/JavaUniverse.scala index 7321214a65..cee243fb29 100644 --- a/src/reflect/scala/reflect/runtime/JavaUniverse.scala +++ b/src/reflect/scala/reflect/runtime/JavaUniverse.scala @@ -27,6 +27,1030 @@ class JavaUniverse extends internal.SymbolTable with ReflectSetup with runtime.S 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 } } -- cgit v1.2.3 From bebd62d5665b9166c1a44b3bcdc01287220a30b7 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Sat, 2 Feb 2013 00:27:38 +0100 Subject: optimizes Scala reflection GIL First of all, GIL should only apply to runtime reflection, because noone is going to run toolboxes in multiple threads: a) that's impossible, b/c the compiler isn't thread safe, b) ToolBox api prevents that. Secondly, the only things in symbols which require synchronization are: 1) info/validTo (completers aren't thread-safe), 2) rawInfo and its dependencies (it shares a mutable field with info) 3) non-trivial caches like in typeAsMemberOfLock If you think about it, other things like sourceModule or associatedFile don't need synchronization, because they are either set up when a symbol is created or cloned or when it's completed. The former is obviously safe, while the latter is safe as well, because before acquiring init-dependent state of symbols, the compiler calls `initialize`, which is synchronized. We can say that symbols can be in four possible states: 1) being created, 2) created, but not yet initialized, 3) initializing, 4) initialized. in runtime reflection can undergo is init. #3 is dangerous and needs protection --- src/reflect/scala/reflect/internal/Symbols.scala | 13 +++- src/reflect/scala/reflect/runtime/Gil.scala | 13 ++-- .../scala/reflect/runtime/SynchronizedOps.scala | 2 +- .../reflect/runtime/SynchronizedSymbols.scala | 77 +++++++--------------- 4 files changed, 41 insertions(+), 64 deletions(-) (limited to 'src/reflect') diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index 0a600432fd..004f7d176a 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -895,6 +895,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. @@ -3008,8 +3015,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 } @@ -3085,9 +3092,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 } @@ -3098,9 +3105,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 diff --git a/src/reflect/scala/reflect/runtime/Gil.scala b/src/reflect/scala/reflect/runtime/Gil.scala index 8a8bfebf8c..cf6f1431d7 100644 --- a/src/reflect/scala/reflect/runtime/Gil.scala +++ b/src/reflect/scala/reflect/runtime/Gil.scala @@ -12,11 +12,14 @@ private[reflect] trait Gil { lazy val gil = new java.util.concurrent.locks.ReentrantLock @inline final def gilSynchronized[T](body: => T): T = { - try { - gil.lock() - body - } finally { - gil.unlock() + if (isCompilerUniverse) body + else { + try { + gil.lock() + body + } finally { + gil.unlock() + } } } } diff --git a/src/reflect/scala/reflect/runtime/SynchronizedOps.scala b/src/reflect/scala/reflect/runtime/SynchronizedOps.scala index b674fc380f..d022bf66ba 100644 --- a/src/reflect/scala/reflect/runtime/SynchronizedOps.scala +++ b/src/reflect/scala/reflect/runtime/SynchronizedOps.scala @@ -49,7 +49,7 @@ private[reflect] trait SynchronizedOps extends internal.SymbolTable // 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 = syncLock.synchronized { body } + 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) } diff --git a/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala b/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala index 3b5029a263..85bd9ff8b6 100644 --- a/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala +++ b/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala @@ -28,27 +28,16 @@ private[reflect] trait SynchronizedSymbols extends internal.Symbols { self: Symb trait SynchronizedSymbol extends Symbol { - override def rawflags = gilSynchronized { super.rawflags } - override def rawflags_=(x: Long) = gilSynchronized { super.rawflags_=(x) } - - override def rawowner = gilSynchronized { super.rawowner } - override def owner_=(owner: Symbol) = gilSynchronized { super.owner_=(owner) } - - override def validTo = gilSynchronized { super.validTo } - override def validTo_=(x: Period) = gilSynchronized { super.validTo_=(x) } - - override def pos = gilSynchronized { super.pos } - override def setPos(pos: Position): this.type = { gilSynchronized { super.setPos(pos) }; this } - - override def privateWithin = gilSynchronized { super.privateWithin } - override def privateWithin_=(sym: Symbol) = gilSynchronized { super.privateWithin_=(sym) } + def gilSynchronizedIfNotInited[T](body: => T): T = { + if (isFullyInitialized) body + else gilSynchronized { body } + } - override def info = gilSynchronized { super.info } - override def info_=(info: Type) = gilSynchronized { super.info_=(info) } - override def updateInfo(info: Type): Symbol = gilSynchronized { super.updateInfo(info) } - override def rawInfo: Type = gilSynchronized { super.rawInfo } + override def validTo = gilSynchronizedIfNotInited { super.validTo } + override def info = gilSynchronizedIfNotInited { super.info } + override def rawInfo: Type = gilSynchronizedIfNotInited { super.rawInfo } - override def typeParams: List[Symbol] = gilSynchronized { + override def typeParams: List[Symbol] = gilSynchronizedIfNotInited { if (isCompilerUniverse) super.typeParams else { if (isMonomorphicType) Nil @@ -64,7 +53,7 @@ private[reflect] trait SynchronizedSymbols extends internal.Symbols { self: Symb } } } - override def unsafeTypeParams: List[Symbol] = gilSynchronized { + override def unsafeTypeParams: List[Symbol] = gilSynchronizedIfNotInited { if (isCompilerUniverse) super.unsafeTypeParams else { if (isMonomorphicType) Nil @@ -72,14 +61,6 @@ private[reflect] trait SynchronizedSymbols extends internal.Symbols { self: Symb } } - override def reset(completer: Type): this.type = gilSynchronized { super.reset(completer) } - - override def infosString: String = gilSynchronized { super.infosString } - - override def annotations: List[AnnotationInfo] = gilSynchronized { super.annotations } - override def setAnnotations(annots: List[AnnotationInfo]): this.type = { gilSynchronized { super.setAnnotations(annots) }; this } - - // ------ creators ------------------------------------------------------------------- override protected def createAbstractTypeSymbol(name: TypeName, pos: Position, newFlags: Long): AbstractTypeSymbol = @@ -130,40 +111,26 @@ private[reflect] trait SynchronizedSymbols extends internal.Symbols { self: Symb // ------- subclasses --------------------------------------------------------------------- - trait SynchronizedTermSymbol extends TermSymbol with SynchronizedSymbol { - override def name_=(x: Name) = gilSynchronized { super.name_=(x) } - override def rawname = gilSynchronized { super.rawname } - override def referenced: Symbol = gilSynchronized { super.referenced } - override def referenced_=(x: Symbol) = gilSynchronized { super.referenced_=(x) } - } + trait SynchronizedTermSymbol extends SynchronizedSymbol trait SynchronizedMethodSymbol extends MethodSymbol with SynchronizedTermSymbol { - override def typeAsMemberOf(pre: Type): Type = gilSynchronized { super.typeAsMemberOf(pre) } - override def paramss: List[List[Symbol]] = gilSynchronized { super.paramss } - override def returnType: Type = gilSynchronized { 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) = gilSynchronized { super.name_=(x) } - override def rawname = gilSynchronized { super.rawname } - override def typeConstructor: Type = gilSynchronized { super.typeConstructor } - override def tpe: Type = gilSynchronized { 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 = gilSynchronized { super.associatedFile } - override def associatedFile_=(f: AbstractFile) = gilSynchronized { super.associatedFile_=(f) } - override def thisSym: Symbol = gilSynchronized { super.thisSym } - override def thisType: Type = gilSynchronized { super.thisType } - override def typeOfThis: Type = gilSynchronized { super.typeOfThis } - override def typeOfThis_=(tp: Type) = gilSynchronized { super.typeOfThis_=(tp) } - override def children = gilSynchronized { super.children } - override def addChild(sym: Symbol) = gilSynchronized { super.addChild(sym) } - } + trait SynchronizedClassSymbol extends ClassSymbol with SynchronizedTypeSymbol - trait SynchronizedModuleClassSymbol extends ModuleClassSymbol with SynchronizedClassSymbol { - override def sourceModule = gilSynchronized { super.sourceModule } - override def implicitMembers: Scope = gilSynchronized { super.implicitMembers } - } + trait SynchronizedModuleClassSymbol extends ModuleClassSymbol with SynchronizedClassSymbol } -- cgit v1.2.3 From 07bcb6176ac7836e81ec7c849e1140126bb6b327 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Thu, 7 Feb 2013 09:14:42 +0100 Subject: SI-7045 reflection now auto-initializes selfType selfType joins the happy family of flags, annotations and privateWithin, which automatically trigger initialization, when used within runtime reflection. --- src/reflect/scala/reflect/internal/Symbols.scala | 6 +++++- test/files/run/t7045.check | 2 ++ test/files/run/t7045.scala | 12 ++++++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 test/files/run/t7045.check create mode 100644 test/files/run/t7045.scala (limited to 'src/reflect') diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index 004f7d176a..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 } diff --git a/test/files/run/t7045.check b/test/files/run/t7045.check new file mode 100644 index 0000000000..28134535c8 --- /dev/null +++ b/test/files/run/t7045.check @@ -0,0 +1,2 @@ +D with C +D with C diff --git a/test/files/run/t7045.scala b/test/files/run/t7045.scala new file mode 100644 index 0000000000..f41baca05e --- /dev/null +++ b/test/files/run/t7045.scala @@ -0,0 +1,12 @@ +import scala.reflect.runtime.universe._ +import scala.reflect.runtime.{currentMirror => cm} + +class C +class D { self: C => } + +object Test extends App { + val d = cm.staticClass("D") + println(d.selfType) + d.typeSignature + println(d.selfType) +} \ No newline at end of file -- cgit v1.2.3 From dd148de5a875dd8d691ffdd983b7f2b978a148df Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Mon, 4 Feb 2013 11:08:21 +0100 Subject: synchronizes pendingVolatiles Called from isVolatile, which is called from isStable, which is a part of the public reflection API. --- src/reflect/scala/reflect/internal/Types.scala | 4 ---- src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala | 2 ++ 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'src/reflect') diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index 0afbdc56c8..6d91948d66 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] diff --git a/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala b/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala index 85bd9ff8b6..5a0ac01ac4 100644 --- a/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala +++ b/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala @@ -61,6 +61,8 @@ private[reflect] trait SynchronizedSymbols extends internal.Symbols { self: Symb } } + override def isStable: Boolean = gilSynchronized { super.isStable } + // ------ creators ------------------------------------------------------------------- override protected def createAbstractTypeSymbol(name: TypeName, pos: Position, newFlags: Long): AbstractTypeSymbol = -- cgit v1.2.3 From f4dd56ca5d5adb2a9183991a7ecebc2b6a1f1fc5 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Tue, 5 Feb 2013 20:59:42 +0100 Subject: synchronizes names Previously we didn't have all possible name creation facilities covered with locks, so some of them silently misbehaved and caused much grief: http://groups.google.com/group/scala-internals/browse_thread/thread/ec1d3e2c4bcb000a. This patch gets all the name factories under control. Unfortunately it comes at a performance cost, which has to be evaluated. --- src/reflect/scala/reflect/internal/Names.scala | 54 ++++++++++++---------- .../scala/reflect/runtime/SynchronizedOps.scala | 8 +++- 2 files changed, 35 insertions(+), 27 deletions(-) (limited to 'src/reflect') 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/runtime/SynchronizedOps.scala b/src/reflect/scala/reflect/runtime/SynchronizedOps.scala index d022bf66ba..f9f4a26b42 100644 --- a/src/reflect/scala/reflect/runtime/SynchronizedOps.scala +++ b/src/reflect/scala/reflect/runtime/SynchronizedOps.scala @@ -13,8 +13,12 @@ private[reflect] trait SynchronizedOps extends internal.SymbolTable // 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 -- cgit v1.2.3 From 73d079fb383f82e825c2a40b397b64288e218fe9 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Tue, 29 Jan 2013 20:36:55 +0100 Subject: removes the assertion in missingHook In the current synchronization scheme multiple threads can enter the missingHook trying to materialize a package, which hasn't been created. That's fine, because makeScalaPackage, which creates and enters package symbols is synchronized and checks whether the creation is necessary before commencing. Therefore even if makeScalaPackage is called multiple times in rapid succession, the calls will be serialized and all calls except the first one won't do anything. --- src/reflect/scala/reflect/runtime/JavaMirrors.scala | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/reflect') diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala index ac968b8e3f..58ade961a7 100644 --- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala +++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala @@ -1264,8 +1264,6 @@ 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) -- cgit v1.2.3