summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xbuild.xml4
-rw-r--r--src/compiler/scala/tools/reflect/ToolBoxFactory.scala3
-rw-r--r--src/reflect/scala/reflect/internal/BaseTypeSeqs.scala2
-rw-r--r--src/reflect/scala/reflect/internal/Definitions.scala35
-rw-r--r--src/reflect/scala/reflect/internal/Mirrors.scala48
-rw-r--r--src/reflect/scala/reflect/internal/Scopes.scala6
-rw-r--r--src/reflect/scala/reflect/internal/StdNames.scala2
-rw-r--r--src/reflect/scala/reflect/internal/SymbolTable.scala8
-rw-r--r--src/reflect/scala/reflect/internal/Symbols.scala49
-rw-r--r--src/reflect/scala/reflect/internal/Types.scala30
-rw-r--r--src/reflect/scala/reflect/internal/pickling/UnPickler.scala4
-rw-r--r--src/reflect/scala/reflect/internal/tpe/GlbLubs.scala7
-rw-r--r--src/reflect/scala/reflect/internal/tpe/TypeComparers.scala64
-rw-r--r--src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala43
-rw-r--r--src/reflect/scala/reflect/internal/tpe/TypeToStrings.scala4
-rw-r--r--src/reflect/scala/reflect/runtime/Gil.scala25
-rw-r--r--src/reflect/scala/reflect/runtime/JavaMirrors.scala52
-rw-r--r--src/reflect/scala/reflect/runtime/JavaUniverse.scala72
-rw-r--r--src/reflect/scala/reflect/runtime/JavaUniverseForce.scala496
-rw-r--r--src/reflect/scala/reflect/runtime/SymbolLoaders.scala89
-rw-r--r--src/reflect/scala/reflect/runtime/SymbolTable.scala2
-rw-r--r--src/reflect/scala/reflect/runtime/SynchronizedOps.scala53
-rw-r--r--src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala129
-rw-r--r--src/reflect/scala/reflect/runtime/SynchronizedTypes.scala85
-rw-r--r--src/reflect/scala/reflect/runtime/ThreadLocalStorage.scala28
-rw-r--r--src/reflect/scala/reflect/runtime/TwoWayCaches.scala68
-rw-r--r--test/files/run/reflection-sync-potpourri.check0
-rw-r--r--test/files/run/reflection-sync-potpourri.scala32
-rw-r--r--test/files/run/reflection-sync-subtypes.check0
-rw-r--r--test/files/run/reflection-sync-subtypes.scala20
-rw-r--r--test/files/run/t6240-universe-code-gen.check0
-rw-r--r--test/files/run/t6240-universe-code-gen.scala82
-rw-r--r--test/files/run/t6240a.check1
-rw-r--r--test/files/run/t6240a/StepOne.java41
-rw-r--r--test/files/run/t6240a/StepTwo.scala7
-rw-r--r--test/files/run/t6240a/Test.scala16
-rw-r--r--test/files/run/t6240b.check1
-rw-r--r--test/files/run/t6240b/StepOne.java41
-rw-r--r--test/files/run/t6240b/StepThree.scala4
-rw-r--r--test/files/run/t6240b/StepTwo.scala10
-rw-r--r--test/files/run/t6240b/Test.scala16
-rw-r--r--test/files/run/t7045.check2
-rw-r--r--test/files/run/t7045.scala12
43 files changed, 1373 insertions, 320 deletions
diff --git a/build.xml b/build.xml
index d28b2f209c..d99f4669e0 100755
--- a/build.xml
+++ b/build.xml
@@ -1480,6 +1480,7 @@ TODO:
<srcfiles dir="${build-pack.dir}">
<include name="**/*"/>
</srcfiles>
+ <srcfiles file="${build-pack.dir}/lib/*.jar"/>
</uptodate>
<if><not><isset property="osgi.bundles.available"/></not><then>
@@ -1541,6 +1542,7 @@ TODO:
<stopwatch name="test.osgi.timer"/>
<mkdir dir="${test.osgi.classes}"/>
+ <echo message="Running OSGi JUnit tests. Output in ${build-osgi.dir}"/>
<junit fork="yes" haltonfailure="yes">
<classpath refid="test.osgi.compiler.build.path"/>
<batchtest fork="yes" todir="${build-osgi.dir}">
@@ -1548,7 +1550,7 @@ TODO:
<include name="**/*Test.class"/>
</fileset>
</batchtest>
- <formatter type="brief" /> <!-- silenced by having it use a file; I tried for an hour to use other formatters but classpath issues drove me to this usefile="false" -->
+ <formatter type="xml" /> <!-- silenced by having it use a file; I tried for an hour to use other formatters but classpath issues drove me to this usefile="false" -->
</junit>
<stopwatch name="test.osgi.timer" action="total"/>
</target>
diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
index fdc2613810..09f795a840 100644
--- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
+++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
@@ -340,7 +340,8 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
lazy val exporter = importer.reverse
}
- def apply[T](f: CompilerApi => T): T = {
+ private val toolBoxLock = new Object
+ def apply[T](f: CompilerApi => T): T = toolBoxLock.synchronized {
try f(api)
catch { case ex: FatalError => throw ToolBoxError(s"fatal compiler error", ex) }
finally api.compiler.cleanupCaches()
diff --git a/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala b/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala
index 05aaa462c4..19c67879f5 100644
--- a/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala
+++ b/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala
@@ -38,7 +38,7 @@ trait BaseTypeSeqs {
* This is necessary because when run from reflection every base type sequence needs to have a
* SynchronizedBaseTypeSeq as mixin.
*/
- class BaseTypeSeq protected[BaseTypeSeqs] (private[BaseTypeSeqs] val parents: List[Type], private[BaseTypeSeqs] val elems: Array[Type]) {
+ class BaseTypeSeq protected[reflect] (private[BaseTypeSeqs] val parents: List[Type], private[BaseTypeSeqs] val elems: Array[Type]) {
self =>
if (Statistics.canEnable) Statistics.incCounter(baseTypeSeqCount)
if (Statistics.canEnable) Statistics.incCounter(baseTypeSeqLenTotal, elems.length)
diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala
index 99aad4f057..7b88514429 100644
--- a/src/reflect/scala/reflect/internal/Definitions.scala
+++ b/src/reflect/scala/reflect/internal/Definitions.scala
@@ -289,12 +289,6 @@ trait Definitions extends api.StandardDefinitions {
lazy val ConstantFalse = ConstantType(Constant(false))
lazy val ConstantNull = ConstantType(Constant(null))
- // Note: this is not the type alias AnyRef, it's a companion-like
- // object used by the @specialize annotation.
- lazy val AnyRefModule = getMemberModule(ScalaPackageClass, nme.AnyRef)
- @deprecated("Use AnyRefModule", "2.10.0")
- def Predef_AnyRef = AnyRefModule
-
lazy val AnyValClass: ClassSymbol = (ScalaPackageClass.info member tpnme.AnyVal orElse {
val anyval = enterNewClass(ScalaPackageClass, tpnme.AnyVal, AnyTpe :: Nil, ABSTRACT)
val av_constr = anyval.newClassConstructor(NoPosition)
@@ -1180,14 +1174,21 @@ trait Definitions extends api.StandardDefinitions {
}
lazy val AnnotationDefaultAttr: ClassSymbol = {
- val attr = enterNewClass(RuntimePackageClass, tpnme.AnnotationDefaultATTR, List(AnnotationClass.tpe))
- // This attribute needs a constructor so that modifiers in parsed Java code make sense
- attr.info.decls enter attr.newClassConstructor(NoPosition)
- attr
+ val sym = RuntimePackageClass.newClassSymbol(tpnme.AnnotationDefaultATTR, NoPosition, 0L)
+ sym setInfo ClassInfoType(List(AnnotationClass.tpe), newScope, sym)
+ RuntimePackageClass.info.decls.toList.filter(_.name == sym.name) match {
+ case existing :: _ =>
+ existing.asInstanceOf[ClassSymbol]
+ case _ =>
+ RuntimePackageClass.info.decls enter sym
+ // This attribute needs a constructor so that modifiers in parsed Java code make sense
+ sym.info.decls enter sym.newClassConstructor(NoPosition)
+ sym
+ }
}
- private def fatalMissingSymbol(owner: Symbol, name: Name, what: String = "member") = {
- throw new FatalError(owner + " does not have a " + what + " " + name)
+ private def fatalMissingSymbol(owner: Symbol, name: Name, what: String = "member", addendum: String = "") = {
+ throw new FatalError(owner + " does not have a " + what + " " + name + addendum)
}
def getLanguageFeature(name: String, owner: Symbol = languageFeatureModule): Symbol = getMember(owner, newTypeName(name))
@@ -1222,7 +1223,8 @@ trait Definitions extends api.StandardDefinitions {
def getMemberModule(owner: Symbol, name: Name): ModuleSymbol = {
getMember(owner, name.toTermName) match {
case x: ModuleSymbol => x
- case _ => fatalMissingSymbol(owner, name, "member object")
+ case NoSymbol => fatalMissingSymbol(owner, name, "member object")
+ case other => fatalMissingSymbol(owner, name, "member object", addendum = s". A symbol ${other} of kind ${other.accurateKindString} already exists.")
}
}
def getTypeMember(owner: Symbol, name: Name): TypeSymbol = {
@@ -1388,10 +1390,13 @@ trait Definitions extends api.StandardDefinitions {
else flatNameString(etp.typeSymbol, '.')
}
+ // documented in JavaUniverse.init
def init() {
if (isInitialized) return
- // force initialization of every symbol that is synthesized or hijacked by the compiler
- val _ = symbolsNotPresentInBytecode
+ ObjectClass.initialize
+ ScalaPackageClass.initialize
+ 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 6ed9de8e20..e122fa498b 100644
--- a/src/reflect/scala/reflect/internal/Mirrors.scala
+++ b/src/reflect/scala/reflect/internal/Mirrors.scala
@@ -250,6 +250,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).moduleClass
+ val ourSym = theirSym // just copy the symbol into our branch of the symbol table
+ ourOwner.info.decls enterIfNew ourSym
+ })
+ }
+
initialized = true
}
}
@@ -274,34 +287,45 @@ trait Mirrors extends api.Mirrors {
def mirror = thisMirror.asInstanceOf[Mirror]
}
- // This is the package _root_. The actual root cannot be referenced at
- // the source level, but _root_ is essentially a function => <root>.
- final object RootPackage extends ModuleSymbol(rootOwner, NoPosition, nme.ROOTPKG) with RootSymbol {
+ class RootPackage extends ModuleSymbol(rootOwner, NoPosition, nme.ROOTPKG) with RootSymbol {
this setInfo NullaryMethodType(RootClass.tpe)
RootClass.sourceModule = this
override def isRootPackage = true
}
+
+ // This is the package _root_. The actual root cannot be referenced at
+ // the source level, but _root_ is essentially a function => <root>.
+ lazy val RootPackage = new RootPackage
+
+ class RootClass extends PackageClassSymbol(rootOwner, NoPosition, tpnme.ROOT) with RootSymbol {
+ this setInfo rootLoader
+
+ override def isRoot = true
+ override def isEffectiveRoot = true
+ override def isNestedClass = false
+ }
+
// This is <root>, the actual root of everything except the package _root_.
// <root> and _root_ (RootPackage and RootClass) should be the only "well known"
// symbols owned by NoSymbol. All owner chains should go through RootClass,
// although it is probable that some symbols are created as direct children
// of NoSymbol to ensure they will not be stumbled upon. (We should designate
// a better encapsulated place for that.)
- final object RootClass extends PackageClassSymbol(rootOwner, NoPosition, tpnme.ROOT) with RootSymbol {
- this setInfo rootLoader
+ lazy val RootClass = new RootClass
- override def isRoot = true
- override def isEffectiveRoot = true
- override def isNestedClass = false
- }
- // The empty package, which holds all top level types without given packages.
- final object EmptyPackage extends ModuleSymbol(RootClass, NoPosition, nme.EMPTY_PACKAGE_NAME) with WellKnownSymbol {
+ class EmptyPackage extends ModuleSymbol(RootClass, NoPosition, nme.EMPTY_PACKAGE_NAME) with WellKnownSymbol {
override def isEmptyPackage = true
}
- final object EmptyPackageClass extends PackageClassSymbol(RootClass, NoPosition, tpnme.EMPTY_PACKAGE_NAME) with WellKnownSymbol {
+
+ // The empty package, which holds all top level types without given packages.
+ lazy val EmptyPackage = new EmptyPackage
+
+ class EmptyPackageClass extends PackageClassSymbol(RootClass, NoPosition, tpnme.EMPTY_PACKAGE_NAME) with WellKnownSymbol {
override def isEffectiveRoot = true
override def isEmptyPackageClass = true
}
+
+ lazy val EmptyPackageClass = new EmptyPackageClass
}
}
diff --git a/src/reflect/scala/reflect/internal/Scopes.scala b/src/reflect/scala/reflect/internal/Scopes.scala
index 1060b3a99c..b7a1681838 100644
--- a/src/reflect/scala/reflect/internal/Scopes.scala
+++ b/src/reflect/scala/reflect/internal/Scopes.scala
@@ -139,6 +139,12 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
enter(sym)
}
+ def enterIfNew[T <: Symbol](sym: T): T = {
+ val existing = lookupEntry(sym.name)
+ if (existing == null) enter(sym)
+ else existing.sym.asInstanceOf[T]
+ }
+
private def createHash() {
hashtable = new Array[ScopeEntry](HASHSIZE)
enterAllInHash(elems)
diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala
index af26253802..c39efa26fa 100644
--- a/src/reflect/scala/reflect/internal/StdNames.scala
+++ b/src/reflect/scala/reflect/internal/StdNames.scala
@@ -273,6 +273,8 @@ trait StdNames {
final val SourceFileATTR: NameType = "SourceFile"
final val SyntheticATTR: NameType = "Synthetic"
+ final val scala_ : NameType = "scala"
+
def dropSingletonName(name: Name): TypeName = (name dropRight SINGLETON_SUFFIX.length).toTypeName
def singletonName(name: Name): TypeName = (name append SINGLETON_SUFFIX).toTypeName
def implClassName(name: Name): TypeName = (name append IMPL_CLASS_SUFFIX).toTypeName
diff --git a/src/reflect/scala/reflect/internal/SymbolTable.scala b/src/reflect/scala/reflect/internal/SymbolTable.scala
index 98466ebb2b..0dff1adda9 100644
--- a/src/reflect/scala/reflect/internal/SymbolTable.scala
+++ b/src/reflect/scala/reflect/internal/SymbolTable.scala
@@ -242,12 +242,20 @@ abstract class SymbolTable extends macros.Universe
finally popPhase(saved)
}
+ def slowButSafeEnteringPhase[T](ph: Phase)(op: => T): T = {
+ if (isCompilerUniverse) enteringPhase(ph)(op)
+ else op
+ }
+
@inline final def exitingPhase[T](ph: Phase)(op: => T): T = enteringPhase(ph.next)(op)
@inline final def enteringPrevPhase[T](op: => T): T = enteringPhase(phase.prev)(op)
@inline final def enteringPhaseNotLaterThan[T](target: Phase)(op: => T): T =
if (isAtPhaseAfter(target)) enteringPhase(target)(op) else op
+ def slowButSafeEnteringPhaseNotLaterThan[T](target: Phase)(op: => T): T =
+ if (isCompilerUniverse) enteringPhaseNotLaterThan(target)(op) else op
+
final def isValid(period: Period): Boolean =
period != 0 && runId(period) == currentRunId && {
val pid = phaseId(period)
diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala
index 71de02ef9e..ba785c14bd 100644
--- a/src/reflect/scala/reflect/internal/Symbols.scala
+++ b/src/reflect/scala/reflect/internal/Symbols.scala
@@ -30,13 +30,13 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
//protected var lockedSyms = scala.collection.immutable.Set[Symbol]()
/** Used to keep track of the recursion depth on locked symbols */
- private var recursionTable = immutable.Map.empty[Symbol, Int]
+ private var _recursionTable = immutable.Map.empty[Symbol, Int]
+ def recursionTable = _recursionTable
+ def recursionTable_=(value: immutable.Map[Symbol, Int]) = _recursionTable = value
- private var nextexid = 0
- protected def freshExistentialName(suffix: String) = {
- nextexid += 1
- newTypeName("_" + nextexid + suffix)
- }
+ private var existentialIds = 0
+ protected def nextExistentialId() = { existentialIds += 1; existentialIds }
+ protected def freshExistentialName(suffix: String) = newTypeName("_" + nextExistentialId() + suffix)
// Set the fields which point companions at one another. Returns the module.
def connectModuleToClass(m: ModuleSymbol, moduleClass: ClassSymbol): ModuleSymbol = {
@@ -110,10 +110,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 }
@@ -127,6 +131,8 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def setter: Symbol = setter(owner)
}
+ private[reflect] 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
@@ -800,7 +806,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
*
* Stability and volatility are checked separately to allow volatile paths in patterns that amount to equality checks. SI-6815
*/
- final def isStable = isTerm && !isMutable && !(hasFlag(BYNAMEPARAM)) && (!isMethod || hasStableFlag)
+ def isStable = isTerm && !isMutable && !(hasFlag(BYNAMEPARAM)) && (!isMethod || hasStableFlag)
final def hasVolatileType = tpe.isVolatile && !hasAnnotation(uncheckedStableClass)
/** Does this symbol denote the primary constructor of its enclosing class? */
@@ -949,6 +955,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.
@@ -1563,6 +1576,8 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
* assumption: if a type starts out as monomorphic, it will not acquire
* type parameters later.
*/
+ // NOTE: overridden in SynchronizedSymbols with the code copy/pasted
+ // don't forget to modify the code over there if you modify this method
def unsafeTypeParams: List[Symbol] =
if (isMonomorphicType) Nil
else enteringPhase(unsafeTypeParamPhase)(rawInfo.typeParams)
@@ -1571,6 +1586,8 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
* assumption: if a type starts out as monomorphic, it will not acquire
* type parameters later.
*/
+ // NOTE: overridden in SynchronizedSymbols with the code copy/pasted
+ // don't forget to modify the code over there if you modify this method
def typeParams: List[Symbol] =
if (isMonomorphicType) Nil
else {
@@ -2393,7 +2410,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) ("term macro", "macro method", "MACM")
@@ -3124,8 +3140,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
}
@@ -3213,9 +3229,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
}
@@ -3226,9 +3242,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
@@ -3336,10 +3352,11 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def name = nme.NO_NAME
override def name_=(n: Name) = abort("Cannot set NoSymbol's name to " + n)
- synchronized {
- setInfo(NoType)
- privateWithin = this
- }
+ // Syncnote: no need to synchronize this, because NoSymbol's initialization is triggered by JavaUniverse.init
+ // which is called in universe's constructor - something that's inherently single-threaded
+ setInfo(NoType)
+ privateWithin = this
+
override def info_=(info: Type) = {
infos = TypeHistory(1, NoType, null)
unlock()
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala
index 9344212294..204a2e7088 100644
--- a/src/reflect/scala/reflect/internal/Types.scala
+++ b/src/reflect/scala/reflect/internal/Types.scala
@@ -115,14 +115,17 @@ trait Types
/** The current skolemization level, needed for the algorithms
* in isSameType, isSubType that do constraint solving under a prefix.
*/
- var skolemizationLevel = 0
+ private var _skolemizationLevel = 0
+ def skolemizationLevel = _skolemizationLevel
+ def skolemizationLevel_=(value: Int) = _skolemizationLevel = value
/** A map from lists to compound types that have the given list as parents.
* This is used to avoid duplication in the computation of base type sequences and baseClasses.
* It makes use of the fact that these two operations depend only on the parents,
* not on the refinement.
*/
- val intersectionWitness = perRunCaches.newWeakMap[List[Type], WeakReference[Type]]()
+ private val _intersectionWitness = perRunCaches.newWeakMap[List[Type], WeakReference[Type]]()
+ def intersectionWitness = _intersectionWitness
/** A proxy for a type (identified by field `underlying`) that forwards most
* operations to it (for exceptions, see WrappingProxy, which forwards even more operations).
@@ -1974,12 +1977,12 @@ trait Types
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]
+ private var _volatileRecursions: Int = 0
+ def volatileRecursions = _volatileRecursions
+ def volatileRecursions_=(value: Int) = _volatileRecursions = value
+
+ private val _pendingVolatiles = new mutable.HashSet[Symbol]
+ def pendingVolatiles = _pendingVolatiles
class ArgsTypeRef(pre0: Type, sym0: Symbol, args0: List[Type]) extends TypeRef(pre0, sym0, args0) {
require(args0.nonEmpty, this)
@@ -3947,9 +3950,12 @@ trait Types
*/
final def hasLength(xs: List[_], len: Int) = xs.lengthCompare(len) == 0
- private var basetypeRecursions: Int = 0
- private val pendingBaseTypes = new mutable.HashSet[Type]
+ private var _basetypeRecursions: Int = 0
+ def basetypeRecursions = _basetypeRecursions
+ def basetypeRecursions_=(value: Int) = _basetypeRecursions = value
+ private val _pendingBaseTypes = new mutable.HashSet[Type]
+ def pendingBaseTypes = _pendingBaseTypes
/** Does this type have a prefix that begins with a type variable,
* or is it a refinement type? For type prefixes that fulfil this condition,
@@ -4449,7 +4455,9 @@ trait Types
}
/** The current indentation string for traces */
- protected[internal] var indent: String = ""
+ private var _indent: String = ""
+ protected def indent = _indent
+ protected def indent_=(value: String) = _indent = value
/** Perform operation `p` on arguments `tp1`, `arg2` and print trace of computation. */
protected def explain[T](op: String, p: (Type, T) => Boolean, tp1: Type, arg2: T): Boolean = {
diff --git a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala
index c4f1f0cf96..a6c34935ad 100644
--- a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala
+++ b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala
@@ -659,7 +659,7 @@ abstract class UnPickler {
override def complete(sym: Symbol) : Unit = try {
val tp = at(i, () => readType(sym.isTerm)) // after NMT_TRANSITION, revert `() => readType(sym.isTerm)` to `readType`
if (p ne null)
- enteringPhase(p) (sym setInfo tp)
+ slowButSafeEnteringPhase(p) (sym setInfo tp)
if (currentRunId != definedAtRunId)
sym.setInfo(adaptToNewRunMap(tp))
}
@@ -677,7 +677,7 @@ abstract class UnPickler {
super.complete(sym)
var alias = at(j, readSymbol)
if (alias.isOverloaded)
- alias = enteringPhase(picklerPhase)((alias suchThat (alt => sym.tpe =:= sym.owner.thisType.memberType(alt))))
+ alias = slowButSafeEnteringPhase(picklerPhase)((alias suchThat (alt => sym.tpe =:= sym.owner.thisType.memberType(alt))))
sym.asInstanceOf[TermSymbol].setAlias(alias)
}
diff --git a/src/reflect/scala/reflect/internal/tpe/GlbLubs.scala b/src/reflect/scala/reflect/internal/tpe/GlbLubs.scala
index 6fa536d84c..6b33aca025 100644
--- a/src/reflect/scala/reflect/internal/tpe/GlbLubs.scala
+++ b/src/reflect/scala/reflect/internal/tpe/GlbLubs.scala
@@ -251,8 +251,11 @@ private[internal] trait GlbLubs {
else if (isNumericSubType(t2, t1)) t1
else IntTpe)
- private val lubResults = new mutable.HashMap[(Depth, List[Type]), Type]
- private val glbResults = new mutable.HashMap[(Depth, List[Type]), Type]
+ private val _lubResults = new mutable.HashMap[(Depth, List[Type]), Type]
+ def lubResults = _lubResults
+
+ private val _glbResults = new mutable.HashMap[(Depth, List[Type]), Type]
+ def glbResults = _glbResults
/** Given a list of types, finds all the base classes they have in
* common, then returns a list of type constructors derived directly
diff --git a/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala b/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala
index 6532bce9f0..b60fecd66e 100644
--- a/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala
+++ b/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala
@@ -14,7 +14,8 @@ trait TypeComparers {
private final val LogPendingSubTypesThreshold = TypeConstants.DefaultLogThreshhold
- private val pendingSubTypes = new mutable.HashSet[SubTypePair]
+ private val _pendingSubTypes = new mutable.HashSet[SubTypePair]
+ def pendingSubTypes = _pendingSubTypes
class SubTypePair(val tp1: Type, val tp2: Type) {
override def hashCode = tp1.hashCode * 41 + tp2.hashCode
@@ -33,7 +34,9 @@ trait TypeComparers {
override def toString = tp1+" <:<? "+tp2
}
- private var subsametypeRecursions: Int = 0
+ private var _subsametypeRecursions: Int = 0
+ def subsametypeRecursions = _subsametypeRecursions
+ def subsametypeRecursions_=(value: Int) = _subsametypeRecursions = value
private def isUnifiable(pre1: Type, pre2: Type) = (
(isEligibleForPrefixUnification(pre1) || isEligibleForPrefixUnification(pre2))
@@ -100,17 +103,13 @@ trait TypeComparers {
// isSameType1(tp1, tp2)
// }
- undoLog.lock()
+ val before = undoLog.log
+ var result = false
try {
- val before = undoLog.log
- var result = false
- try {
- result = isSameType1(tp1, tp2)
- }
- finally if (!result) undoLog.undoTo(before)
- result
+ result = isSameType1(tp1, tp2)
}
- finally undoLog.unlock()
+ finally if (!result) undoLog.undoTo(before)
+ result
}
finally {
subsametypeRecursions -= 1
@@ -256,30 +255,27 @@ trait TypeComparers {
// }
// }
- undoLog.lock()
- try {
- val before = undoLog.log
- var result = false
-
- try result = { // if subtype test fails, it should not affect constraints on typevars
- if (subsametypeRecursions >= LogPendingSubTypesThreshold) {
- val p = new SubTypePair(tp1, tp2)
- if (pendingSubTypes(p))
- false
- else
- try {
- pendingSubTypes += p
- isSubType1(tp1, tp2, depth)
- } finally {
- pendingSubTypes -= p
- }
- } else {
- isSubType1(tp1, tp2, depth)
- }
- } finally if (!result) undoLog.undoTo(before)
+ val before = undoLog.log
+ var result = false
+
+ try result = { // if subtype test fails, it should not affect constraints on typevars
+ if (subsametypeRecursions >= LogPendingSubTypesThreshold) {
+ val p = new SubTypePair(tp1, tp2)
+ if (pendingSubTypes(p))
+ false
+ else
+ try {
+ pendingSubTypes += p
+ isSubType1(tp1, tp2, depth)
+ } finally {
+ pendingSubTypes -= p
+ }
+ } else {
+ isSubType1(tp1, tp2, depth)
+ }
+ } finally if (!result) undoLog.undoTo(before)
- result
- } finally undoLog.unlock()
+ result
} finally {
subsametypeRecursions -= 1
// XXX AM TODO: figure out when it is safe and needed to clear the log -- the commented approach below is too eager (it breaks #3281, #3866)
diff --git a/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala b/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala
index fdfe376c18..e2159d30f5 100644
--- a/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala
+++ b/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala
@@ -13,34 +13,14 @@ private[internal] trait TypeConstraints {
/** A log of type variable with their original constraints. Used in order
* to undo constraints in the case of isSubType/isSameType failure.
*/
- lazy val undoLog = newUndoLog
-
- protected def newUndoLog = new UndoLog
+ private lazy val _undoLog = new UndoLog
+ def undoLog = _undoLog
class UndoLog extends Clearable {
private type UndoPairs = List[(TypeVar, TypeConstraint)]
//OPT this method is public so we can do `manual inlining`
var log: UndoPairs = List()
- /*
- * These two methods provide explicit locking mechanism that is overridden in SynchronizedUndoLog.
- *
- * The idea behind explicit locking mechanism is that all public methods that access mutable state
- * will have to obtain the lock for their entire execution so both reads and writes can be kept in
- * right order. Originally, that was achieved by overriding those public methods in
- * `SynchronizedUndoLog` which was fine but expensive. The reason is that those public methods take
- * thunk as argument and if we keep them non-final there's no way to make them inlined so thunks
- * can go away.
- *
- * By using explicit locking we can achieve inlining.
- *
- * NOTE: They are made public for now so we can apply 'manual inlining' (copy&pasting into hot
- * places implementation of `undo` or `undoUnless`). This should be changed back to protected
- * once inliner is fixed.
- */
- def lock(): Unit = ()
- def unlock(): Unit = ()
-
// register with the auto-clearing cache manager
perRunCaches.recordCache(this)
@@ -64,23 +44,16 @@ private[internal] trait TypeConstraints {
}
def clear() {
- lock()
- try {
- if (settings.debug)
- self.log("Clearing " + log.size + " entries from the undoLog.")
- log = Nil
- } finally unlock()
+ if (settings.debug)
+ self.log("Clearing " + log.size + " entries from the undoLog.")
+ log = Nil
}
// `block` should not affect constraints on typevars
def undo[T](block: => T): T = {
- lock()
- try {
- val before = log
-
- try block
- finally undoTo(before)
- } finally unlock()
+ val before = log
+ try block
+ finally undoTo(before)
}
}
diff --git a/src/reflect/scala/reflect/internal/tpe/TypeToStrings.scala b/src/reflect/scala/reflect/internal/tpe/TypeToStrings.scala
index 16929cca0f..ebc4394d25 100644
--- a/src/reflect/scala/reflect/internal/tpe/TypeToStrings.scala
+++ b/src/reflect/scala/reflect/internal/tpe/TypeToStrings.scala
@@ -10,7 +10,9 @@ private[internal] trait TypeToStrings {
*/
final val maxTostringRecursions = 50
- private var tostringRecursions = 0
+ private var _tostringRecursions = 0
+ def tostringRecursions = _tostringRecursions
+ def tostringRecursions_=(value: Int) = _tostringRecursions = value
protected def typeToString(tpe: Type): String =
if (tostringRecursions >= maxTostringRecursions) {
diff --git a/src/reflect/scala/reflect/runtime/Gil.scala b/src/reflect/scala/reflect/runtime/Gil.scala
new file mode 100644
index 0000000000..0edb1e5748
--- /dev/null
+++ b/src/reflect/scala/reflect/runtime/Gil.scala
@@ -0,0 +1,25 @@
+package scala.reflect
+package runtime
+
+private[reflect] trait Gil {
+ self: SymbolTable =>
+
+ // fixme... please...
+ // there are the following avenues of optimization we discussed with Roland:
+ // 1) replace PackageScope locks with ConcurrentHashMap, because PackageScope materializers seem to be idempotent
+ // 2) unlock unpickling completers by verifying that they are idempotent or moving non-idempotent parts
+ // 3) remove the necessity in global state for isSubType
+ private lazy val gil = new java.util.concurrent.locks.ReentrantLock
+
+ @inline final def gilSynchronized[T](body: => T): T = {
+ if (isCompilerUniverse) body
+ else {
+ try {
+ gil.lock()
+ body
+ } finally {
+ gil.unlock()
+ }
+ }
+ }
+}
diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala
index 1a15454500..1e2dd6b7d3 100644
--- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala
+++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala
@@ -22,7 +22,7 @@ import ReflectionUtils.{staticSingletonInstance, innerSingletonInstance, scalacS
import scala.language.existentials
import scala.runtime.{ScalaRunTime, BoxesRunTime}
-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]]()
@@ -44,19 +44,11 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
trait JavaClassCompleter extends FlagAssigningCompleter
- def init() = {
- definitions.AnyValClass // force it.
-
- // establish root association to avoid cyclic dependency errors later
- rootMirror.classToScala(classOf[java.lang.Object]).initialize
-
- // println("initializing definitions")
- definitions.init()
- }
-
- def runtimeMirror(cl: ClassLoader): Mirror = mirrors get cl match {
- case Some(WeakReference(m)) => m
- case _ => createMirror(rootMirror.RootClass, cl)
+ def runtimeMirror(cl: ClassLoader): Mirror = gilSynchronized {
+ mirrors get cl match {
+ case Some(WeakReference(m)) => m
+ case _ => createMirror(rootMirror.RootClass, cl)
+ }
}
/** The API of a mirror for a reflective universe */
@@ -69,6 +61,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 {
@@ -689,7 +686,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 {
@@ -894,7 +891,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
@@ -1275,11 +1272,6 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
case _ => abort(s"${sym}.enclosingRootClass = ${sym.enclosingRootClass}, which is not a RootSymbol")
}
- private lazy val syntheticCoreClasses: Map[(String, Name), Symbol] = {
- def mapEntry(sym: Symbol): ((String, Name), Symbol) = (sym.owner.fullName, sym.name) -> sym
- Map() ++ (definitions.syntheticCoreClasses map mapEntry)
- }
-
/** 1. If `owner` is a package class (but not the empty package) and `name` is a term name, make a new package
* <owner>.<name>, otherwise return NoSymbol.
* Exception: If owner is root and a java class with given name exists, create symbol in empty package instead
@@ -1289,20 +1281,20 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
override def missingHook(owner: Symbol, name: Name): Symbol = {
if (owner.hasPackageFlag) {
val mirror = mirrorThatLoaded(owner)
- // todo. this makes toolbox tests pass, but it's a mere workaround for SI-5865
-// assert((owner.info decl name) == NoSymbol, s"already exists: $owner . $name")
if (owner.isRootSymbol && mirror.tryJavaClass(name.toString).isDefined)
return mirror.EmptyPackageClass.info decl name
if (name.isTermName && !owner.isEmptyPackageClass)
return mirror.makeScalaPackage(
if (owner.isRootSymbol) name.toString else owner.fullName+"."+name)
- syntheticCoreClasses get ((owner.fullName, name)) foreach { 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
- }
+ 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 06a7db6289..a6cf3a536f 100644
--- a/src/reflect/scala/reflect/runtime/JavaUniverse.scala
+++ b/src/reflect/scala/reflect/runtime/JavaUniverse.scala
@@ -8,7 +8,7 @@ package runtime
*
* @contentDiagram hideNodes "*Api" "*Extractor"
*/
-class JavaUniverse extends internal.SymbolTable with ReflectSetup with runtime.SymbolTable { self =>
+class JavaUniverse extends internal.SymbolTable with JavaUniverseForce with ReflectSetup with runtime.SymbolTable { self =>
override def inform(msg: String): Unit = log(msg)
def picklerPhase = internal.SomePhase
@@ -27,4 +27,74 @@ class JavaUniverse extends internal.SymbolTable with ReflectSetup with runtime.S
} with internal.TreeInfo
init()
+
+ // ======= Initialization of runtime reflection =======
+ //
+ // This doc describes the carefully laid out sequence of actions used to initialize reflective universes.
+ //
+ // Before reading the text below, read up the section Mirrors in the reflection pre-SIP
+ // https://docs.google.com/document/d/1nAwSw4TmMplsIlzh2shYLUJ5mVh3wndDa1Zm1H6an9A/edit.
+ // Take an especially good look at Figure 2, because it illustrates fundamental principles underlying runtime reflection:
+ // 1) For each universe we have one mirror per classloader
+ // 2) Package symbols are per-mirror
+ // 3) Other symbols are per-universe, which means that a symbol (e.g. Seq on the picture) might be shared between multiple owners
+ //
+ // Main challenges that runtime reflection presents wrt initialization are:
+ // 1) Extravagant completion scheme that enters package members on-demand rather than a result of scanning a directory with class files.
+ // (That's a direct consequence of the fact that in general case we can't enumerate all classes in a classloader.
+ // As Paul rightfully mentioned, we could specialcase classloaders that point to filesystems, but that is left for future work).
+ // 2) Presence of synthetic symbols that aren't loaded by normal means (from classfiles) but are synthesized on-the-fly,
+ // and the necessity to propagate these synthetic symbols from rootMirror to other mirrors,
+ // complicated by the fact that such symbols depend on normal symbols (e.g. AnyRef depends on Object).
+ // 3) Necessity to remain thread-safe, which limits our options related to lazy initialization
+ // (E.g. we cannot use missingHook to enter synthetic symbols, because that's thread-unsafe).
+ //
+ // Directly addressing the challenge #3, we create all synthetic symbols fully in advance during init().
+ // However, it's not that simple as just calling definitions.symbolsNotPresentInBytecode.
+ // Before doing that, we need to first initialize ObjectClass, then ScalaPackageClass, and only then deal with synthetics.
+ // Below you can find a detailed explanation for that.
+ //
+ // ### Why ScalaPackageClass? ###
+ //
+ // 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, no crashes, no problems, right? Not quite.
+ // 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 prior to other synthetics.
+ //
+ // ### Why ObjectClass? ###
+ //
+ // 1) As explained in JavaMirrors.missingHook, initialization of ScalaPackageClass critically depends on AnyRefClass.
+ // 2) AnyRefClass is defined as "lazy val AnyRefClass = newAlias(ScalaPackageClass, tpnme.AnyRef, ObjectTpe)",
+ // which means that initialization of AnyRefClass depends on ObjectClass.
+ // 3) ObjectClass is defined as "lazy val ObjectClass = getRequiredClass(sn.Object.toString)",
+ // which means that under some classloader configurations (see JavaMirrors.missingHook for more details)
+ // dereferencing ObjectClass might trigger an avalanche of initializations calling back into AnyRefClass
+ // while another AnyRefClass initializer is still on stack.
+ // 4) That will lead to AnyRefClass being entered two times (once when the recursive call returns and once when the original one returns)
+ // 5) That will crash PackageScope.enter that helpfully detects double-enters.
+ //
+ // Therefore, before initializing ScalaPackageClass, we must pre-initialize ObjectClass
+ 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)
+
+ // TODO Convert this into a macro
+ force()
+ }
}
diff --git a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
new file mode 100644
index 0000000000..8fd58c42be
--- /dev/null
+++ b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
@@ -0,0 +1,496 @@
+// Generated Code, validated by run/t6240-universe-code-gen.scala
+package scala.reflect
+package runtime
+
+trait JavaUniverseForce { self: runtime.JavaUniverse =>
+ def force() {
+ Literal(Constant(42)).duplicate
+ nme.flattenedName()
+ nme.raw
+ 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
+
+ this.settings
+ this.treeInfo
+ // inaccessible: this.scala$reflect$runtime$Gil$$gil
+ // inaccessible: this.uniqueLock
+ // inaccessible: this._skolemizationLevel
+ // inaccessible: this._undoLog
+ // inaccessible: this._intersectionWitness
+ // inaccessible: this._volatileRecursions
+ // inaccessible: this._pendingVolatiles
+ // inaccessible: this._subsametypeRecursions
+ // inaccessible: this._pendingSubTypes
+ // inaccessible: this._basetypeRecursions
+ // inaccessible: this._pendingBaseTypes
+ // inaccessible: this._lubResults
+ // inaccessible: this._glbResults
+ // inaccessible: this._indent
+ // inaccessible: this._tostringRecursions
+ // inaccessible: this.atomicIds
+ // inaccessible: this.atomicExistentialIds
+ // inaccessible: this._recursionTable
+ // inaccessible: this.mirrors
+ this.rootMirror
+ this.treeBuild
+ // inaccessible: this.SimpleNameOrdering
+ this.traceSymbols
+ this.perRunCaches
+ this.FixedMirrorTreeCreator
+ this.FixedMirrorTypeCreator
+ this.BackquotedIdentifierAttachment
+ this.CompoundTypeTreeOriginalAttachment
+ this.noPrint
+ this.typeDebug
+ // inaccessible: this.maxFree
+ this.Range
+ // inaccessible: this.posAssigner
+ this.ConsoleWriter
+ this.RefTree
+ this.PackageDef
+ this.ClassDef
+ this.ModuleDef
+ this.ValOrDefDef
+ this.ValDef
+ this.DefDef
+ this.TypeDef
+ this.LabelDef
+ this.ImportSelector
+ this.Import
+ this.Template
+ this.Block
+ this.CaseDef
+ this.Alternative
+ this.Star
+ this.Bind
+ this.UnApply
+ this.ArrayValue
+ this.Function
+ this.Assign
+ this.AssignOrNamedArg
+ this.If
+ this.Match
+ this.Return
+ this.Try
+ this.Throw
+ this.New
+ this.Typed
+ this.TypeApply
+ this.Apply
+ this.ApplyDynamic
+ this.Super
+ this.This
+ this.Select
+ this.Ident
+ this.ReferenceToBoxed
+ this.Literal
+ this.Annotated
+ this.SingletonTypeTree
+ this.SelectFromTypeTree
+ this.CompoundTypeTree
+ this.AppliedTypeTree
+ this.TypeBoundsTree
+ this.ExistentialTypeTree
+ this.TypeTree
+ this.Modifiers
+ this.EmptyTree
+ this.noSelfType
+ this.pendingSuperCall
+ this.emptyValDef
+ this.EmptyTreeTypeSubstituter
+ // inaccessible: this.duplicator
+ this.UnmappableAnnotArg
+ this.LiteralAnnotArg
+ this.ArrayAnnotArg
+ this.NestedAnnotArg
+ this.ScalaSigBytes
+ this.AnnotationInfo
+ this.Annotation
+ this.UnmappableAnnotation
+ this.ErroneousAnnotation
+ this.ThrownException
+ // inaccessible: this.compactify
+ this.tpnme
+ this.fulltpnme
+ this.binarynme
+ this.nme
+ this.sn
+ this.Constant
+ this.definitions
+ this.LookupSucceeded
+ this.LookupAmbiguous
+ this.LookupInaccessible
+ this.LookupNotFound
+ this.Scope
+ this.EmptyScope
+ this.Flag
+ this.KindErrors
+ this.Kind
+ this.ProperTypeKind
+ this.TypeConKind
+ this.inferKind
+ // inaccessible: this.substTypeMapCache
+ this.UnmappableTree
+ this.ErrorType
+ this.WildcardType
+ this.BoundedWildcardType
+ this.NoType
+ this.NoPrefix
+ this.ThisType
+ this.SingleType
+ this.SuperType
+ this.TypeBounds
+ this.CompoundType
+ this.baseClassesCycleMonitor
+ this.RefinedType
+ this.ClassInfoType
+ this.ConstantType
+ this.TypeRef
+ this.MethodType
+ this.NullaryMethodType
+ this.PolyType
+ this.ExistentialType
+ this.OverloadedType
+ this.AntiPolyType
+ this.HasTypeMember
+ this.ArrayTypeRef
+ this.TypeVar
+ this.AnnotatedType
+ this.StaticallyAnnotatedType
+ this.NamedType
+ this.RepeatedType
+ this.ErasedValueType
+ this.GenPolyType
+ this.unwrapToClass
+ this.unwrapToStableClass
+ this.unwrapWrapperTypes
+ this.RecoverableCyclicReference
+ // inaccessible: this._undoLog
+ // inaccessible: this.numericLoBound
+ // inaccessible: this.numericHiBound
+ this.TypeConstraint
+ this.normalizeAliases
+ this.dropSingletonType
+ this.abstractTypesToBounds
+ this.dropIllegalStarTypes
+ this.IsDependentCollector
+ this.ApproximateDependentMap
+ this.wildcardToTypeVarMap
+ this.typeVarToOriginMap
+ this.ErroneousCollector
+ this.adaptToNewRunMap
+ // inaccessible: this.commonOwnerMapObj
+ this.SymbolKind
+ this.NoSymbol
+ this.CyclicReference
+ // inaccessible: this.TypeHistory
+ this.TermName
+ this.TypeName
+ this.BooleanFlag
+ this.WeakTypeTag
+ this.TypeTag
+ this.Expr
+ this.NoMods
+ definitions.JavaLangPackage
+ definitions.JavaLangPackageClass
+ definitions.ScalaPackage
+ definitions.ScalaPackageClass
+ definitions.RuntimePackage
+ definitions.RuntimePackageClass
+ definitions.AnyClass
+ definitions.AnyRefClass
+ definitions.ObjectClass
+ definitions.AnyRefTpe
+ definitions.AnyTpe
+ definitions.AnyValTpe
+ definitions.BoxedUnitTpe
+ definitions.NothingTpe
+ definitions.NullTpe
+ definitions.ObjectTpe
+ definitions.SerializableTpe
+ definitions.StringTpe
+ definitions.ThrowableTpe
+ definitions.ConstantTrue
+ definitions.ConstantFalse
+ definitions.ConstantNull
+ definitions.AnyValClass
+ definitions.RuntimeNothingClass
+ definitions.RuntimeNullClass
+ definitions.NothingClass
+ definitions.NullClass
+ definitions.ClassCastExceptionClass
+ definitions.IndexOutOfBoundsExceptionClass
+ definitions.InvocationTargetExceptionClass
+ definitions.MatchErrorClass
+ definitions.NonLocalReturnControlClass
+ definitions.NullPointerExceptionClass
+ definitions.ThrowableClass
+ definitions.UninitializedErrorClass
+ definitions.UninitializedFieldConstructor
+ definitions.PartialFunctionClass
+ definitions.AbstractPartialFunctionClass
+ definitions.SymbolClass
+ definitions.StringClass
+ definitions.StringModule
+ definitions.ClassClass
+ definitions.DynamicClass
+ definitions.SysPackage
+ definitions.UnqualifiedModules
+ definitions.UnqualifiedOwners
+ definitions.PredefModule
+ definitions.SpecializableModule
+ definitions.GroupOfSpecializable
+ definitions.ScalaRunTimeModule
+ definitions.SymbolModule
+ definitions.Symbol_apply
+ definitions.StringAddClass
+ definitions.ArrowAssocClass
+ definitions.StringAdd_$plus
+ definitions.ScalaNumberClass
+ definitions.TraitSetterAnnotationClass
+ definitions.DelayedInitClass
+ definitions.TypeConstraintClass
+ definitions.SingletonClass
+ definitions.SerializableClass
+ definitions.JavaSerializableClass
+ definitions.ComparableClass
+ definitions.JavaCloneableClass
+ definitions.JavaNumberClass
+ definitions.RemoteInterfaceClass
+ definitions.RemoteExceptionClass
+ definitions.ByNameParamClass
+ definitions.JavaRepeatedParamClass
+ definitions.RepeatedParamClass
+ definitions.ExprClassOf
+ definitions.ConsClass
+ definitions.IteratorClass
+ definitions.IterableClass
+ definitions.ListClass
+ definitions.SeqClass
+ definitions.StringBuilderClass
+ definitions.TraversableClass
+ definitions.ListModule
+ definitions.List_apply
+ definitions.NilModule
+ definitions.SeqModule
+ definitions.ArrayModule
+ definitions.ArrayModule_overloadedApply
+ definitions.ArrayClass
+ definitions.Array_apply
+ definitions.Array_update
+ definitions.Array_length
+ definitions.Array_clone
+ definitions.SoftReferenceClass
+ definitions.MethodClass
+ definitions.EmptyMethodCacheClass
+ definitions.MethodCacheClass
+ definitions.ScalaXmlTopScope
+ definitions.ScalaXmlPackage
+ definitions.ReflectPackage
+ definitions.ReflectApiPackage
+ definitions.ReflectRuntimePackage
+ definitions.PartialManifestClass
+ definitions.PartialManifestModule
+ definitions.FullManifestClass
+ definitions.FullManifestModule
+ definitions.OptManifestClass
+ definitions.NoManifest
+ definitions.TreesClass
+ definitions.TreesTreeType
+ definitions.TreeType
+ definitions.SubtreeType
+ definitions.ExprsClass
+ definitions.ExprClass
+ 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.LiftableClass
+ definitions.MacroClass
+ definitions.MacroContextClass
+ definitions.MacroImplAnnotation
+ definitions.StringContextClass
+ definitions.QuasiquoteClass
+ definitions.QuasiquoteClass_api
+ definitions.QuasiquoteClass_api_apply
+ definitions.QuasiquoteClass_api_unapply
+ definitions.ScalaSignatureAnnotation
+ definitions.ScalaLongSignatureAnnotation
+ definitions.OptionClass
+ definitions.OptionModule
+ definitions.Option_apply
+ definitions.SomeClass
+ definitions.NoneModule
+ definitions.SomeModule
+ definitions.VarArityClass
+ definitions.ProductClass
+ definitions.TupleClass
+ definitions.FunctionClass
+ definitions.AbstractFunctionClass
+ definitions.ProductRootClass
+ 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.primitiveGetClassMethods
+ definitions.getClassMethods
+ 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.SwitchClass
+ definitions.TailrecClass
+ definitions.VarargsClass
+ definitions.uncheckedStableClass
+ definitions.uncheckedVarianceClass
+ definitions.BeanPropertyAttr
+ definitions.BooleanBeanPropertyAttr
+ definitions.CompileTimeOnlyAttr
+ definitions.DeprecatedAttr
+ definitions.DeprecatedNameAttr
+ definitions.DeprecatedInheritanceAttr
+ definitions.DeprecatedOverridingAttr
+ definitions.NativeAttr
+ definitions.RemoteAttr
+ definitions.ScalaInlineClass
+ definitions.ScalaNoInlineClass
+ definitions.SerialVersionUIDAttr
+ definitions.SerialVersionUIDAnnotation
+ definitions.SpecializedClass
+ definitions.ThrowsClass
+ definitions.TransientAttr
+ definitions.UncheckedClass
+ definitions.UncheckedBoundsClass
+ definitions.UnspecializedClass
+ definitions.VolatileAttr
+ definitions.BeanGetterTargetClass
+ definitions.BeanSetterTargetClass
+ definitions.FieldTargetClass
+ definitions.GetterTargetClass
+ definitions.ParamTargetClass
+ definitions.SetterTargetClass
+ definitions.ObjectTargetClass
+ definitions.ClassTargetClass
+ 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.isUnbox
+ definitions.isBox
+ definitions.isPhantomClass
+ definitions.syntheticCoreClasses
+ definitions.syntheticCoreMethods
+ definitions.hijackedCoreClasses
+ definitions.symbolsNotPresentInBytecode
+ definitions.isPossibleSyntheticParent
+ // inaccessible: 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
+
+
+ erasure.GenericArray
+ erasure.scalaErasure
+ erasure.specialScalaErasure
+ erasure.javaErasure
+ erasure.verifiedJavaErasure
+ erasure.boxingErasure
+ }
+} \ No newline at end of file
diff --git a/src/reflect/scala/reflect/runtime/SymbolLoaders.scala b/src/reflect/scala/reflect/runtime/SymbolLoaders.scala
index 3e01a6df02..30a3855d70 100644
--- a/src/reflect/scala/reflect/runtime/SymbolLoaders.scala
+++ b/src/reflect/scala/reflect/runtime/SymbolLoaders.scala
@@ -17,37 +17,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 {
- enteringPhaseNotLaterThan(picklerPhase) {
+ slowButSafeEnteringPhaseNotLaterThan(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)
@@ -91,12 +67,52 @@ private[reflect] trait SymbolLoaders { self: SymbolTable =>
}
}
+
+ // Since runtime reflection doesn't have a luxury of enumerating all classes
+ // on the classpath, it has to materialize symbols for top-level definitions
+ // (packages, classes, objects) on demand.
+ //
+ // Someone asks us for a class named `foo.Bar`? Easy. Let's speculatively create
+ // a package named `foo` and then look up `newTypeName("bar")` in its decls.
+ // This lookup, implemented in `SymbolLoaders.PackageScope` tests the waters by
+ // trying to to `Class.forName("foo.Bar")` and then creates a ClassSymbol upon
+ // success (the whole story is a bit longer, but the rest is irrelevant here).
+ //
+ // That's all neat, but these non-deterministic mutations of the global symbol
+ // table give a lot of trouble in multi-threaded setting. One of the popular
+ // reflection crashes happens when multiple threads happen to trigger symbol
+ // materialization multiple times for the same symbol, making subsequent
+ // reflective operations stumble upon outrageous stuff like overloaded packages.
+ //
+ // Short of significantly changing SymbolLoaders I see no other way than just
+ // to slap a global lock on materialization in runtime reflection.
class PackageScope(pkgClass: Symbol) extends Scope(initFingerPrints = -1L) // disable fingerprinting as we do not know entries beforehand
with SynchronizedScope {
assert(pkgClass.isType)
- // disable fingerprinting as we do not know entries beforehand
- private val negatives = mutable.Set[Name]() // Syncnote: Performance only, so need not be protected.
- override def lookupEntry(name: Name): ScopeEntry = {
+
+ // 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 = {
+ // workaround for SI-7728
+ if (isCompilerUniverse) super.enter(sym)
+ else {
+ val existing = super.lookupEntry(sym.name)
+ assert(existing == null || existing.sym.isMethod, s"pkgClass = $pkgClass, sym = $sym, existing = $existing")
+ super.enter(sym)
+ }
+ }
+
+ override def enterIfNew[T <: Symbol](sym: T): T = {
+ val existing = super.lookupEntry(sym.name)
+ if (existing == null) enter(sym)
+ else existing.sym.asInstanceOf[T]
+ }
+
+ // 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 {
val e = super.lookupEntry(name)
if (e != null)
e
@@ -119,8 +135,21 @@ private[reflect] trait SymbolLoaders { self: SymbolTable =>
val module = origOwner.info decl name.toTermName
assert(clazz != NoSymbol)
assert(module != NoSymbol)
- pkgClass.info.decls enter clazz
- pkgClass.info.decls enter module
+ // currentMirror.mirrorDefining(cls) might side effect by entering symbols into pkgClass.info.decls
+ // therefore, even though in the beginning of this method, super.lookupEntry(name) returned null
+ // entering clazz/module now will result in a double-enter assertion in PackageScope.enter
+ // here's how it might happen
+ // 1) we are the rootMirror
+ // 2) cls.getClassLoader is different from our classloader
+ // 3) mirrorDefining(cls) looks up a mirror corresponding to that classloader and cannot find it
+ // 4) mirrorDefining creates a new mirror
+ // 5) that triggers Mirror.init() of the new mirror
+ // 6) that triggers definitions.syntheticCoreClasses
+ // 7) that might materialize symbols and enter them into our scope (because syntheticCoreClasses live in rootMirror)
+ // 8) now we come back here and try to enter one of the now entered symbols => BAM!
+ // therefore we use enterIfNew rather than just enter
+ enterIfNew(clazz)
+ enterIfNew(module)
(clazz, module)
}
debugInfo(s"created $module/${module.moduleClass} in $pkgClass")
diff --git a/src/reflect/scala/reflect/runtime/SymbolTable.scala b/src/reflect/scala/reflect/runtime/SymbolTable.scala
index bcd4d16cde..ddbf3bd629 100644
--- a/src/reflect/scala/reflect/runtime/SymbolTable.scala
+++ b/src/reflect/scala/reflect/runtime/SymbolTable.scala
@@ -9,7 +9,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 with ThreadLocalStorage {
def info(msg: => String) =
if (settings.verbose) println("[reflect-compiler] "+msg)
diff --git a/src/reflect/scala/reflect/runtime/SynchronizedOps.scala b/src/reflect/scala/reflect/runtime/SynchronizedOps.scala
index 6aa47a0405..c90901410a 100644
--- a/src/reflect/scala/reflect/runtime/SynchronizedOps.scala
+++ b/src/reflect/scala/reflect/runtime/SynchronizedOps.scala
@@ -14,20 +14,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
@@ -36,15 +41,19 @@ private[reflect] trait SynchronizedOps extends internal.SymbolTable
override def newNestedScope(outer: Scope): Scope = new Scope(outer) with SynchronizedScope
trait SynchronizedScope extends Scope {
- override def isEmpty: Boolean = synchronized { super.isEmpty }
- override def size: Int = synchronized { super.size }
- override def enter[T <: Symbol](sym: T): T = synchronized { super.enter(sym) }
- override def rehash(sym: Symbol, newname: Name) = synchronized { super.rehash(sym, newname) }
- override def unlink(e: ScopeEntry) = synchronized { super.unlink(e) }
- override def unlink(sym: Symbol) = synchronized { super.unlink(sym) }
- override def lookupAll(name: Name) = synchronized { super.lookupAll(name) }
- override def lookupEntry(name: Name) = synchronized { super.lookupEntry(name) }
- override def lookupNextEntry(entry: ScopeEntry) = synchronized { super.lookupNextEntry(entry) }
- override def toList: List[Symbol] = synchronized { super.toList }
+ // we can keep this lock fine-grained, because methods of Scope don't do anything extraordinary, which makes deadlocks impossible
+ // fancy subclasses of internal.Scopes#Scope should do synchronization themselves (e.g. see PackageScope for an example)
+ private lazy val syncLock = new Object
+ def syncLockSynchronized[T](body: => T): T = if (isCompilerUniverse) body else syncLock.synchronized { body }
+ override def isEmpty: Boolean = syncLockSynchronized { super.isEmpty }
+ override def size: Int = syncLockSynchronized { super.size }
+ override def enter[T <: Symbol](sym: T): T = syncLockSynchronized { super.enter(sym) }
+ override def rehash(sym: Symbol, newname: Name) = syncLockSynchronized { super.rehash(sym, newname) }
+ override def unlink(e: ScopeEntry) = syncLockSynchronized { super.unlink(e) }
+ override def unlink(sym: Symbol) = syncLockSynchronized { super.unlink(sym) }
+ override def lookupAll(name: Name) = syncLockSynchronized { super.lookupAll(name) }
+ override def lookupEntry(name: Name) = syncLockSynchronized { super.lookupEntry(name) }
+ override def lookupNextEntry(entry: ScopeEntry) = syncLockSynchronized { super.lookupNextEntry(entry) }
+ override def toList: List[Symbol] = syncLockSynchronized { super.toList }
}
}
diff --git a/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala b/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala
index 98cad45db1..298d0ffebd 100644
--- a/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala
+++ b/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala
@@ -3,17 +3,23 @@ package reflect
package runtime
import scala.reflect.io.AbstractFile
+import scala.collection.{ immutable, mutable }
private[reflect] trait SynchronizedSymbols extends internal.Symbols { self: SymbolTable =>
- override protected def nextId() = synchronized { super.nextId() }
+ private lazy val atomicIds = new java.util.concurrent.atomic.AtomicInteger(0)
+ override protected def nextId() = atomicIds.incrementAndGet()
- override protected def freshExistentialName(suffix: String) =
- synchronized { super.freshExistentialName(suffix) }
+ private lazy val atomicExistentialIds = new java.util.concurrent.atomic.AtomicInteger(0)
+ override protected def nextExistentialId() = atomicExistentialIds.incrementAndGet()
+
+ private lazy val _recursionTable = mkThreadLocalStorage(immutable.Map.empty[Symbol, Int])
+ override def recursionTable = _recursionTable.get
+ override def recursionTable_=(value: immutable.Map[Symbol, Int]) = _recursionTable.set(value)
// 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
@@ -25,35 +31,40 @@ private[reflect] trait SynchronizedSymbols extends internal.Symbols { self: Symb
trait SynchronizedSymbol extends Symbol {
- override def rawflags = synchronized { super.rawflags }
- override def rawflags_=(x: Long) = synchronized { super.rawflags_=(x) }
-
- override def rawowner = synchronized { super.rawowner }
- override def owner_=(owner: Symbol) = synchronized { super.owner_=(owner) }
-
- override def validTo = synchronized { super.validTo }
- override def validTo_=(x: Period) = synchronized { super.validTo_=(x) }
-
- override def pos = synchronized { super.pos }
- override def setPos(pos: Position): this.type = { synchronized { super.setPos(pos) }; this }
-
- override def privateWithin = synchronized { super.privateWithin }
- override def privateWithin_=(sym: Symbol) = synchronized { super.privateWithin_=(sym) }
-
- override def info = synchronized { super.info }
- override def info_=(info: Type) = synchronized { super.info_=(info) }
- override def updateInfo(info: Type): Symbol = synchronized { super.updateInfo(info) }
- override def rawInfo: Type = synchronized { super.rawInfo }
-
- override def typeParams: List[Symbol] = synchronized { super.typeParams }
-
- override def reset(completer: Type): this.type = synchronized { super.reset(completer) }
-
- override def infosString: String = synchronized { super.infosString }
-
- override def annotations: List[AnnotationInfo] = synchronized { super.annotations }
- override def setAnnotations(annots: List[AnnotationInfo]): this.type = { synchronized { super.setAnnotations(annots) }; this }
-
+ def gilSynchronizedIfNotInited[T](body: => T): T = {
+ if (isFullyInitialized) body
+ else gilSynchronized { body }
+ }
+
+ override def validTo = gilSynchronizedIfNotInited { super.validTo }
+ override def info = gilSynchronizedIfNotInited { super.info }
+ override def rawInfo: Type = gilSynchronizedIfNotInited { super.rawInfo }
+
+ override def typeParams: List[Symbol] = gilSynchronizedIfNotInited {
+ if (isCompilerUniverse) super.typeParams
+ else {
+ if (isMonomorphicType) Nil
+ else {
+ // analogously to the "info" getter, here we allow for two completions:
+ // one: sourceCompleter to LazyType, two: LazyType to completed type
+ if (validTo == NoPeriod)
+ rawInfo load this
+ if (validTo == NoPeriod)
+ rawInfo load this
+
+ rawInfo.typeParams
+ }
+ }
+ }
+ override def unsafeTypeParams: List[Symbol] = gilSynchronizedIfNotInited {
+ if (isCompilerUniverse) super.unsafeTypeParams
+ else {
+ if (isMonomorphicType) Nil
+ else rawInfo.typeParams
+ }
+ }
+
+ override def isStable: Boolean = gilSynchronized { super.isStable }
// ------ creators -------------------------------------------------------------------
@@ -90,50 +101,38 @@ private[reflect] trait SynchronizedSymbols extends internal.Symbols { self: Symb
override protected def createModuleSymbol(name: TermName, pos: Position, newFlags: Long): ModuleSymbol =
new ModuleSymbol(this, pos, name) with SynchronizedTermSymbol initFlags newFlags
- override protected def createPackageSymbol(name: TermName, pos: Position, newFlags: Long): ModuleSymbol = createModuleSymbol(name, pos, newFlags)
+ override protected def createPackageSymbol(name: TermName, pos: Position, newFlags: Long): ModuleSymbol =
+ createModuleSymbol(name, pos, newFlags)
+
+ override protected def createValueParameterSymbol(name: TermName, pos: Position, newFlags: Long) =
+ new TermSymbol(this, pos, name) with SynchronizedTermSymbol initFlags newFlags
- // TODO
- // override protected def createValueParameterSymbol(name: TermName, pos: Position, newFlags: Long)
- // override protected def createValueMemberSymbol(name: TermName, pos: Position, newFlags: Long)
+ override protected def createValueMemberSymbol(name: TermName, pos: Position, newFlags: Long) =
+ new TermSymbol(this, pos, name) with SynchronizedTermSymbol initFlags newFlags
}
// ------- subclasses ---------------------------------------------------------------------
- trait SynchronizedTermSymbol extends TermSymbol with SynchronizedSymbol {
- override def name_=(x: Name) = synchronized { super.name_=(x) }
- override def rawname = synchronized { super.rawname }
- override def referenced: Symbol = synchronized { super.referenced }
- override def referenced_=(x: Symbol) = synchronized { super.referenced_=(x) }
- }
+ trait SynchronizedTermSymbol extends SynchronizedSymbol
trait SynchronizedMethodSymbol extends MethodSymbol with SynchronizedTermSymbol {
- override def typeAsMemberOf(pre: Type): Type = synchronized { super.typeAsMemberOf(pre) }
- override def paramss: List[List[Symbol]] = synchronized { super.paramss }
- override def returnType: Type = synchronized { super.returnType }
+ // we can keep this lock fine-grained, because it's just a cache over asSeenFrom, which makes deadlocks impossible
+ // unfortunately we cannot elide this lock, because the cache depends on `pre`
+ private lazy val typeAsMemberOfLock = new Object
+ override def typeAsMemberOf(pre: Type): Type = gilSynchronizedIfNotInited { typeAsMemberOfLock.synchronized { super.typeAsMemberOf(pre) } }
}
+ trait SynchronizedModuleSymbol extends ModuleSymbol with SynchronizedTermSymbol
+
trait SynchronizedTypeSymbol extends TypeSymbol with SynchronizedSymbol {
- override def name_=(x: Name) = synchronized { super.name_=(x) }
- override def rawname = synchronized { super.rawname }
- override def typeConstructor: Type = synchronized { super.typeConstructor }
- override def tpe_* : Type = synchronized { super.tpe_* }
- override def tpeHK : Type = synchronized { super.tpeHK }
+ // unlike with typeConstructor, a lock is necessary here, because tpe calculation relies on
+ // temporarily assigning NoType to tpeCache to detect cyclic reference errors
+ private lazy val tpeLock = new Object
+ override def tpe_* : Type = gilSynchronizedIfNotInited { tpeLock.synchronized { super.tpe_* } }
}
- trait SynchronizedClassSymbol extends ClassSymbol with SynchronizedTypeSymbol {
- override def associatedFile = synchronized { super.associatedFile }
- override def associatedFile_=(f: AbstractFile) = synchronized { super.associatedFile_=(f) }
- override def thisSym: Symbol = synchronized { super.thisSym }
- override def thisType: Type = synchronized { super.thisType }
- override def typeOfThis: Type = synchronized { super.typeOfThis }
- override def typeOfThis_=(tp: Type) = synchronized { super.typeOfThis_=(tp) }
- override def children = synchronized { super.children }
- override def addChild(sym: Symbol) = synchronized { super.addChild(sym) }
- }
+ trait SynchronizedClassSymbol extends ClassSymbol with SynchronizedTypeSymbol
- trait SynchronizedModuleClassSymbol extends ModuleClassSymbol with SynchronizedClassSymbol {
- override def sourceModule = synchronized { super.sourceModule }
- override def implicitMembers: Scope = synchronized { super.implicitMembers }
- }
+ trait SynchronizedModuleClassSymbol extends ModuleClassSymbol with SynchronizedClassSymbol
}
diff --git a/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala b/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala
index c0146167df..de78e527a7 100644
--- a/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala
+++ b/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala
@@ -2,8 +2,9 @@ package scala
package reflect
package runtime
-import scala.collection.mutable.WeakHashMap
-import java.lang.ref.WeakReference
+import scala.collection.mutable
+import java.lang.ref.{WeakReference => jWeakRef}
+import scala.ref.{WeakReference => sWeakRef}
import scala.reflect.internal.Depth
/** This trait overrides methods in reflect.internal, bracketing
@@ -14,9 +15,10 @@ private[reflect] trait SynchronizedTypes extends internal.Types { self: SymbolTa
// No sharing of map objects:
override protected def commonOwnerMap = new CommonOwnerMap
- private object uniqueLock
-
- private val uniques = WeakHashMap[Type, WeakReference[Type]]()
+ // 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 = mutable.WeakHashMap[Type, jWeakRef[Type]]()
override def unique[T <: Type](tp: T): T = uniqueLock.synchronized {
// we need to have weak uniques for runtime reflection
// because unlike the normal compiler universe, reflective universe isn't organized in runs
@@ -30,7 +32,7 @@ private[reflect] trait SynchronizedTypes extends internal.Types { self: SymbolTa
val result = if (inCache.isDefined) inCache.get.get else null
if (result ne null) result.asInstanceOf[T]
else {
- uniques(tp) = new WeakReference(tp)
+ uniques(tp) = new jWeakRef(tp)
tp
}
} else {
@@ -38,47 +40,50 @@ 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()
- }
+ private lazy val _skolemizationLevel = mkThreadLocalStorage(0)
+ override def skolemizationLevel = _skolemizationLevel.get
+ override def skolemizationLevel_=(value: Int) = _skolemizationLevel.set(value)
- override protected def newUndoLog = new SynchronizedUndoLog
+ private lazy val _undoLog = mkThreadLocalStorage(new UndoLog)
+ override def undoLog = _undoLog.get
- override protected def baseTypeOfNonClassTypeRef(tpe: NonClassTypeRef, clazz: Symbol) =
- synchronized { super.baseTypeOfNonClassTypeRef(tpe, clazz) }
+ private lazy val _intersectionWitness = mkThreadLocalStorage(perRunCaches.newWeakMap[List[Type], sWeakRef[Type]]())
+ override def intersectionWitness = _intersectionWitness.get
- private object subsametypeLock
+ private lazy val _volatileRecursions = mkThreadLocalStorage(0)
+ override def volatileRecursions = _volatileRecursions.get
+ override def volatileRecursions_=(value: Int) = _volatileRecursions.set(value)
- override def isSameType(tp1: Type, tp2: Type): Boolean =
- subsametypeLock.synchronized { super.isSameType(tp1, tp2) }
+ private lazy val _pendingVolatiles = mkThreadLocalStorage(new mutable.HashSet[Symbol])
+ override def pendingVolatiles = _pendingVolatiles.get
- override def isDifferentType(tp1: Type, tp2: Type): Boolean =
- subsametypeLock.synchronized { super.isDifferentType(tp1, tp2) }
+ private lazy val _subsametypeRecursions = mkThreadLocalStorage(0)
+ override def subsametypeRecursions = _subsametypeRecursions.get
+ override def subsametypeRecursions_=(value: Int) = _subsametypeRecursions.set(value)
- override def isSubType(tp1: Type, tp2: Type, depth: Depth): Boolean =
- subsametypeLock.synchronized { super.isSubType(tp1, tp2, depth) }
+ private lazy val _pendingSubTypes = mkThreadLocalStorage(new mutable.HashSet[SubTypePair])
+ override def pendingSubTypes = _pendingSubTypes.get
- private object lubglbLock
+ private lazy val _basetypeRecursions = mkThreadLocalStorage(0)
+ override def basetypeRecursions = _basetypeRecursions.get
+ override def basetypeRecursions_=(value: Int) = _basetypeRecursions.set(value)
- override def glb(ts: List[Type]): Type =
- lubglbLock.synchronized { super.glb(ts) }
+ private lazy val _pendingBaseTypes = mkThreadLocalStorage(new mutable.HashSet[Type])
+ override def pendingBaseTypes = _pendingBaseTypes.get
- override def lub(ts: List[Type]): Type =
- lubglbLock.synchronized { super.lub(ts) }
+ private lazy val _lubResults = mkThreadLocalStorage(new mutable.HashMap[(Depth, List[Type]), Type])
+ override def lubResults = _lubResults.get
- 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) }
- }
+ private lazy val _glbResults = mkThreadLocalStorage(new mutable.HashMap[(Depth, List[Type]), Type])
+ override def glbResults = _glbResults.get
- private object toStringLock
+ private lazy val _indent = mkThreadLocalStorage("")
+ override def indent = _indent.get
+ override def indent_=(value: String) = _indent.set(value)
- override protected def typeToString(tpe: Type): String =
- toStringLock.synchronized(super.typeToString(tpe))
+ private lazy val _tostringRecursions = mkThreadLocalStorage(0)
+ override def tostringRecursions = _tostringRecursions.get
+ override def tostringRecursions_=(value: Int) = _tostringRecursions.set(value)
/* The idea of caches is as follows.
* When in reflexive mode, a cache is either null, or one sentinal
@@ -91,18 +96,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/ThreadLocalStorage.scala b/src/reflect/scala/reflect/runtime/ThreadLocalStorage.scala
new file mode 100644
index 0000000000..5edc051461
--- /dev/null
+++ b/src/reflect/scala/reflect/runtime/ThreadLocalStorage.scala
@@ -0,0 +1,28 @@
+package scala.reflect
+package runtime
+
+import java.lang.Thread._
+
+private[reflect] trait ThreadLocalStorage {
+ self: SymbolTable =>
+
+ // see a discussion at scala-internals for more information:
+ // http://groups.google.com/group/scala-internals/browse_thread/thread/337ce68aa5e51f79
+ trait ThreadLocalStorage[T] { def get: T; def set(newValue: T): Unit }
+ private class MyThreadLocalStorage[T](initialValue: => T) extends ThreadLocalStorage[T] {
+ // TODO: how do we use org.cliffc.high_scale_lib.NonBlockingHashMap here?
+ val values = new java.util.concurrent.ConcurrentHashMap[Thread, T]()
+ def get: T = {
+ if (values containsKey currentThread) values.get(currentThread)
+ else {
+ val value = initialValue
+ values.putIfAbsent(currentThread, value)
+ value
+ }
+ }
+ def set(newValue: T): Unit = {
+ values.put(currentThread, newValue)
+ }
+ }
+ @inline final def mkThreadLocalStorage[T](x: => T): ThreadLocalStorage[T] = new MyThreadLocalStorage(x)
+}
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
+ }
+ }
+ }
+}
+
diff --git a/test/files/run/reflection-sync-potpourri.check b/test/files/run/reflection-sync-potpourri.check
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/files/run/reflection-sync-potpourri.check
diff --git a/test/files/run/reflection-sync-potpourri.scala b/test/files/run/reflection-sync-potpourri.scala
new file mode 100644
index 0000000000..0ad5f2ab66
--- /dev/null
+++ b/test/files/run/reflection-sync-potpourri.scala
@@ -0,0 +1,32 @@
+import scala.reflect.runtime.universe._
+
+// this test checks that under heavily multithreaded conditions:
+// 1) scala.reflect.runtime.universe, its rootMirror and definitions are initialized correctly
+// 2) symbols are correctly materialized into PackageScopes (no dupes)
+// 3) unpickling works okay even we unpickle the same symbol a lot of times
+
+object Test extends App {
+ def foo[T: TypeTag](x: T) = typeOf[T].toString
+ val n = 1000
+ val rng = new scala.util.Random()
+ val types = List(
+ () => typeOf[java.lang.reflect.Method],
+ () => typeOf[java.lang.annotation.Annotation],
+ () => typeOf[scala.io.BufferedSource],
+ () => typeOf[scala.io.Codec])
+ val perms = types.permutations.toList
+ def force(lazytpe: () => Type): String = {
+ lazytpe().typeSymbol.typeSignature
+ lazytpe().toString
+ }
+ val diceRolls = List.fill(n)(rng.nextInt(perms.length))
+ val threads = (1 to n) map (i => new Thread(s"Reflector-$i") {
+ override def run(): Unit = {
+ val s1 = foo("42")
+ val s2 = perms(diceRolls(i - 1)).map(x => force(x)).sorted.mkString(", ")
+ assert(s1 == "java.lang.String")
+ assert(s2 == "java.lang.annotation.Annotation, java.lang.reflect.Method, scala.io.BufferedSource, scala.io.Codec")
+ }
+ })
+ threads foreach (_.start)
+} \ No newline at end of file
diff --git a/test/files/run/reflection-sync-subtypes.check b/test/files/run/reflection-sync-subtypes.check
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/files/run/reflection-sync-subtypes.check
diff --git a/test/files/run/reflection-sync-subtypes.scala b/test/files/run/reflection-sync-subtypes.scala
new file mode 100644
index 0000000000..7f75a464ac
--- /dev/null
+++ b/test/files/run/reflection-sync-subtypes.scala
@@ -0,0 +1,20 @@
+import scala.reflect.runtime.universe._
+
+object Test extends App {
+ val n = 1000
+ val rng = new scala.util.Random()
+ val tasks = List(
+ () => typeOf[List[Int]] <:< typeOf[List[T] forSome { type T }],
+ () => typeOf[List[T] forSome { type T }] <:< typeOf[List[Any]],
+ () => typeOf[Map[Int, Object]] <:< typeOf[Iterable[(Int, String)]],
+ () => typeOf[Expr[Any] { val mirror: rootMirror.type }] <:< typeOf[Expr[List[List[List[Int]]]]{ val mirror: rootMirror.type }])
+ val perms = tasks.permutations.toList
+ val diceRolls = List.fill(n)(rng.nextInt(perms.length))
+ val threads = (1 to n) map (i => new Thread(s"Reflector-$i") {
+ override def run(): Unit = {
+ val result = perms(diceRolls(i - 1)).map(_())
+ assert(result.sorted == List(false, false, true, true))
+ }
+ })
+ threads foreach (_.start)
+} \ No newline at end of file
diff --git a/test/files/run/t6240-universe-code-gen.check b/test/files/run/t6240-universe-code-gen.check
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/files/run/t6240-universe-code-gen.check
diff --git a/test/files/run/t6240-universe-code-gen.scala b/test/files/run/t6240-universe-code-gen.scala
new file mode 100644
index 0000000000..84691639bd
--- /dev/null
+++ b/test/files/run/t6240-universe-code-gen.scala
@@ -0,0 +1,82 @@
+import scala.tools.partest.nest.FileManager._
+
+object Test extends App {
+ val cm = reflect.runtime.currentMirror
+ val u = cm.universe
+ import u._
+
+ val JavaUniverseTpe = typeOf[reflect.runtime.JavaUniverse]
+ val DefinitionsModule = JavaUniverseTpe.member(TermName("definitions"))
+
+ def forceCode(prefix: String, tp: Type): String = {
+ def isLazyAccessorOrObject(sym: Symbol) = (
+ (sym.isMethod && sym.asMethod.isLazy)
+ || sym.isModule
+ )
+ val forcables = tp.members.sorted.filter(isLazyAccessorOrObject)
+ forcables.map {
+ sym =>
+ val path = s"$prefix.${sym.name}"
+ " " + (
+ if (sym.isPrivate || sym.isProtected) s"// inaccessible: $path"
+ else path
+ )
+ }.mkString("\n")
+ }
+
+ val code =
+ s"""|// Generated Code, validated by run/t6240-universe-code-gen.scala
+ |package scala.reflect
+ |package runtime
+ |
+ |trait JavaUniverseForce { self: runtime.JavaUniverse =>
+ | def force() {
+ | Literal(Constant(42)).duplicate
+ | nme.flattenedName()
+ | nme.raw
+ | 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
+ |
+ |${forceCode("this", JavaUniverseTpe)}
+ |${forceCode("definitions", DefinitionsModule.typeSignature)}
+ |${forceCode("refChecks", typeOf[scala.reflect.internal.transform.RefChecks])}
+ |${forceCode("uncurry", typeOf[scala.reflect.internal.transform.UnCurry])}
+ |${forceCode("erasure", typeOf[scala.reflect.internal.transform.Erasure])}
+ | }
+ |}""".stripMargin
+
+ import java.io.File
+ val testFile = new File(sys.props("partest.test-path"))
+ val actualFile = new java.io.File(testFile.getParent + "/../../../src/reflect/scala/reflect/runtime/JavaUniverseForce.scala").getCanonicalFile
+ val actual = scala.io.Source.fromFile(actualFile)
+ val actualLines = actual.getLines.toList
+ val generatedLines = code.lines.toList
+ if (actualLines != generatedLines) {
+ val msg = s"""|${actualFile} must be updated.
+ |===========================================================
+ | DIFF:
+ |===========================================================
+ |${compareContents(actualLines, generatedLines)}
+ |===========================================================
+ | NEW CONTENTS:
+ |===========================================================
+ |${code}""".stripMargin
+
+ assert(false, msg)
+ }
+}
diff --git a/test/files/run/t6240a.check b/test/files/run/t6240a.check
new file mode 100644
index 0000000000..29f695b6f4
--- /dev/null
+++ b/test/files/run/t6240a.check
@@ -0,0 +1 @@
+StepTwo.type
diff --git a/test/files/run/t6240a/StepOne.java b/test/files/run/t6240a/StepOne.java
new file mode 100644
index 0000000000..7abd148d69
--- /dev/null
+++ b/test/files/run/t6240a/StepOne.java
@@ -0,0 +1,41 @@
+import java.io.File;
+import java.io.IOException;
+import java.lang.ClassNotFoundException;
+import java.lang.NoSuchMethodException;
+import java.lang.IllegalAccessException;
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.net.MalformedURLException;
+
+public class StepOne {
+ public static void main(String[] args)
+ throws MalformedURLException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, IOException {
+ String[] launchPaths = System.getProperty("launch.classpath").split(":");
+
+ // move away StepThree
+ File tempDir = File.createTempFile("temp", Long.toString(System.nanoTime()));
+ System.setProperty("launch.step.three", tempDir.getAbsolutePath());
+ tempDir.delete();
+ tempDir.mkdir();
+ File[] testClasses = new File(launchPaths[0]).listFiles();
+ for (int i = 0; i < testClasses.length; i++) {
+ File testClass = testClasses[i];
+ if (testClass.getPath().contains("StepThree")) {
+ File testClassMoved = new File(tempDir.getAbsolutePath() + "/" + testClass.getName());
+ testClass.renameTo(testClassMoved);
+ }
+ }
+
+ // launch StepTwo
+ URL[] launchURLs = new URL[launchPaths.length];
+ for (int i = 0; i < launchPaths.length; i++) {
+ launchURLs[i] = new File(launchPaths[i]).toURL();
+ }
+ URLClassLoader classLoader = new URLClassLoader(launchURLs, Object.class.getClassLoader());
+ Class<?> stepTwo = classLoader.loadClass("StepTwo");
+ Method main = stepTwo.getDeclaredMethod("main", String[].class);
+ main.invoke(null, (Object)(new String[]{}));
+ }
+} \ No newline at end of file
diff --git a/test/files/run/t6240a/StepTwo.scala b/test/files/run/t6240a/StepTwo.scala
new file mode 100644
index 0000000000..fc3221921d
--- /dev/null
+++ b/test/files/run/t6240a/StepTwo.scala
@@ -0,0 +1,7 @@
+import java.io.File
+import java.net.URLClassLoader
+
+object StepTwo extends App {
+ import scala.reflect.runtime.universe._
+ println(typeOf[StepTwo.type])
+} \ No newline at end of file
diff --git a/test/files/run/t6240a/Test.scala b/test/files/run/t6240a/Test.scala
new file mode 100644
index 0000000000..6ae43c4809
--- /dev/null
+++ b/test/files/run/t6240a/Test.scala
@@ -0,0 +1,16 @@
+import java.io.File
+import scala.sys.process._
+
+object Test extends App {
+ def prop(key: String) = {
+ val value = System.getProperties.getProperty(key)
+ assert(value != null, key)
+ value
+ }
+ val testClassesDir = prop("partest.output")
+ assert(new File(testClassesDir).exists, testClassesDir)
+ val fullTestClassesClasspath = testClassesDir + prop("path.separator") + prop("java.class.path")
+ val javaBinary = if (new File(prop("javacmd")).isAbsolute) prop("javacmd") else prop("java.home") + "/bin/" + prop("javacmd")
+ assert(new File(javaBinary).exists, javaBinary)
+ List(javaBinary, "-cp", testClassesDir, "-Dlaunch.classpath=" + fullTestClassesClasspath, "StepOne").!
+} \ No newline at end of file
diff --git a/test/files/run/t6240b.check b/test/files/run/t6240b.check
new file mode 100644
index 0000000000..255836105a
--- /dev/null
+++ b/test/files/run/t6240b.check
@@ -0,0 +1 @@
+StepThree.type
diff --git a/test/files/run/t6240b/StepOne.java b/test/files/run/t6240b/StepOne.java
new file mode 100644
index 0000000000..7abd148d69
--- /dev/null
+++ b/test/files/run/t6240b/StepOne.java
@@ -0,0 +1,41 @@
+import java.io.File;
+import java.io.IOException;
+import java.lang.ClassNotFoundException;
+import java.lang.NoSuchMethodException;
+import java.lang.IllegalAccessException;
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.net.MalformedURLException;
+
+public class StepOne {
+ public static void main(String[] args)
+ throws MalformedURLException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, IOException {
+ String[] launchPaths = System.getProperty("launch.classpath").split(":");
+
+ // move away StepThree
+ File tempDir = File.createTempFile("temp", Long.toString(System.nanoTime()));
+ System.setProperty("launch.step.three", tempDir.getAbsolutePath());
+ tempDir.delete();
+ tempDir.mkdir();
+ File[] testClasses = new File(launchPaths[0]).listFiles();
+ for (int i = 0; i < testClasses.length; i++) {
+ File testClass = testClasses[i];
+ if (testClass.getPath().contains("StepThree")) {
+ File testClassMoved = new File(tempDir.getAbsolutePath() + "/" + testClass.getName());
+ testClass.renameTo(testClassMoved);
+ }
+ }
+
+ // launch StepTwo
+ URL[] launchURLs = new URL[launchPaths.length];
+ for (int i = 0; i < launchPaths.length; i++) {
+ launchURLs[i] = new File(launchPaths[i]).toURL();
+ }
+ URLClassLoader classLoader = new URLClassLoader(launchURLs, Object.class.getClassLoader());
+ Class<?> stepTwo = classLoader.loadClass("StepTwo");
+ Method main = stepTwo.getDeclaredMethod("main", String[].class);
+ main.invoke(null, (Object)(new String[]{}));
+ }
+} \ No newline at end of file
diff --git a/test/files/run/t6240b/StepThree.scala b/test/files/run/t6240b/StepThree.scala
new file mode 100644
index 0000000000..210795d68f
--- /dev/null
+++ b/test/files/run/t6240b/StepThree.scala
@@ -0,0 +1,4 @@
+object StepThree extends App {
+ import scala.reflect.runtime.universe._
+ println(typeOf[StepThree.type])
+} \ No newline at end of file
diff --git a/test/files/run/t6240b/StepTwo.scala b/test/files/run/t6240b/StepTwo.scala
new file mode 100644
index 0000000000..88e46492e3
--- /dev/null
+++ b/test/files/run/t6240b/StepTwo.scala
@@ -0,0 +1,10 @@
+import java.io.File
+import java.net.URLClassLoader
+
+object StepTwo extends App {
+ val classes = new File(System.getProperty("launch.step.three"))
+ val cl = new URLClassLoader(Array(classes.toURI.toURL), getClass.getClassLoader)
+ val stepThree = cl.loadClass("StepThree")
+ val main = stepThree.getDeclaredMethod("main", classOf[Array[String]])
+ main.invoke(null, Array[String]())
+} \ No newline at end of file
diff --git a/test/files/run/t6240b/Test.scala b/test/files/run/t6240b/Test.scala
new file mode 100644
index 0000000000..6ae43c4809
--- /dev/null
+++ b/test/files/run/t6240b/Test.scala
@@ -0,0 +1,16 @@
+import java.io.File
+import scala.sys.process._
+
+object Test extends App {
+ def prop(key: String) = {
+ val value = System.getProperties.getProperty(key)
+ assert(value != null, key)
+ value
+ }
+ val testClassesDir = prop("partest.output")
+ assert(new File(testClassesDir).exists, testClassesDir)
+ val fullTestClassesClasspath = testClassesDir + prop("path.separator") + prop("java.class.path")
+ val javaBinary = if (new File(prop("javacmd")).isAbsolute) prop("javacmd") else prop("java.home") + "/bin/" + prop("javacmd")
+ assert(new File(javaBinary).exists, javaBinary)
+ List(javaBinary, "-cp", testClassesDir, "-Dlaunch.classpath=" + fullTestClassesClasspath, "StepOne").!
+} \ No newline at end of file
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