summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/reflect/internal/NameManglers.scala33
-rw-r--r--src/compiler/scala/reflect/internal/Names.scala6
-rw-r--r--src/compiler/scala/reflect/internal/Symbols.scala11
-rw-r--r--src/compiler/scala/tools/ant/Scalac.scala2
-rw-r--r--src/compiler/scala/tools/ant/templates/tool-windows.tmpl4
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/GenICode.scala4
-rw-r--r--src/compiler/scala/tools/nsc/backend/opt/Inliners.scala122
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/ILoop.scala6
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/IMain.scala4
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala6
-rw-r--r--src/compiler/scala/tools/nsc/transform/AddInterfaces.scala68
-rw-r--r--src/compiler/scala/tools/nsc/transform/LambdaLift.scala44
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala15
-rw-r--r--src/compiler/scala/tools/nsc/util/Statistics.scala4
-rw-r--r--src/library/scala/Predef.scala2
-rw-r--r--src/library/scala/collection/immutable/List.scala21
-rw-r--r--src/library/scala/collection/immutable/Stream.scala10
-rw-r--r--src/library/scala/collection/mutable/ListBuffer.scala46
-rw-r--r--src/partest/scala/tools/partest/nest/ReflectiveRunner.scala15
19 files changed, 280 insertions, 143 deletions
diff --git a/src/compiler/scala/reflect/internal/NameManglers.scala b/src/compiler/scala/reflect/internal/NameManglers.scala
index ef092f16bb..97a74c2383 100644
--- a/src/compiler/scala/reflect/internal/NameManglers.scala
+++ b/src/compiler/scala/reflect/internal/NameManglers.scala
@@ -85,7 +85,7 @@ trait NameManglers {
def isConstructorName(name: Name) = name == CONSTRUCTOR || name == MIXIN_CONSTRUCTOR
def isExceptionResultName(name: Name) = name startsWith EXCEPTION_RESULT_PREFIX
- def isImplClassName(name: Name) = stripAnonNumberSuffix(name) endsWith IMPL_CLASS_SUFFIX
+ def isImplClassName(name: Name) = name endsWith IMPL_CLASS_SUFFIX
def isLocalDummyName(name: Name) = name startsWith LOCALDUMMY_PREFIX
def isLocalName(name: Name) = name endsWith LOCAL_SUFFIX_STRING
def isLoopHeaderLabel(name: Name) = (name startsWith WHILE_PREFIX) || (name startsWith DO_WHILE_PREFIX)
@@ -176,25 +176,18 @@ trait NameManglers {
else name.toTermName
}
- /** !!! I'm putting this logic in place because I can witness
- * trait impls get lifted and acquiring names like 'Foo$class$1'
- * while clearly still being what they were. It's only being used on
- * isImplClassName. However, it's anyone's guess how much more
- * widely this logic actually ought to be applied. Anything which
- * tests for how a name ends is a candidate for breaking down once
- * something is lifted from a method.
- *
- * TODO: resolve this significant problem.
- */
- def stripAnonNumberSuffix(name: Name): Name = {
- val str = "" + name
- if (str == "" || !str.endChar.isDigit) name
- else {
- val idx = name.lastPos('$')
- if (idx < 0 || str.substring(idx + 1).exists(c => !c.isDigit)) name
- else name.subName(0, idx)
- }
- }
+ // This isn't needed at the moment since I fixed $class$1 but
+ // I expect it will be at some point.
+ //
+ // def anonNumberSuffix(name: Name): Name = {
+ // ("" + name) lastIndexOf '$' match {
+ // case -1 => nme.EMPTY
+ // case idx =>
+ // val s = name drop idx
+ // if (s.toString forall (_.isDigit)) s
+ // else nme.EMPTY
+ // }
+ // }
def stripModuleSuffix(name: Name): Name = (
if (isModuleName(name)) name dropRight MODULE_SUFFIX_STRING.length else name
diff --git a/src/compiler/scala/reflect/internal/Names.scala b/src/compiler/scala/reflect/internal/Names.scala
index b960695f51..907b564d4c 100644
--- a/src/compiler/scala/reflect/internal/Names.scala
+++ b/src/compiler/scala/reflect/internal/Names.scala
@@ -77,7 +77,11 @@ trait Names extends api.Names {
def newTermName(cs: Array[Char]): TermName = newTermName(cs, 0, cs.length)
def newTypeName(cs: Array[Char]): TypeName = newTypeName(cs, 0, cs.length)
- /** Create a term name from the characters in cs[offset..offset+len-1]. */
+ /** Create a term name from the characters in cs[offset..offset+len-1].
+ * TODO - have a mode where name validation is performed at creation time
+ * (e.g. if a name has the string "$class" in it, then fail if that
+ * string is not at the very end.)
+ */
protected def newTermName(cs: Array[Char], offset: Int, len: Int, cachedString: String): TermName = {
val h = hashValue(cs, offset, len) & HASH_MASK
var n = termHashtable(h)
diff --git a/src/compiler/scala/reflect/internal/Symbols.scala b/src/compiler/scala/reflect/internal/Symbols.scala
index b4d2b1531f..a943b6fe24 100644
--- a/src/compiler/scala/reflect/internal/Symbols.scala
+++ b/src/compiler/scala/reflect/internal/Symbols.scala
@@ -1425,7 +1425,10 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
*/
def sourceModule: Symbol = NoSymbol
- /** The implementation class of a trait. */
+ /** The implementation class of a trait. If available it will be the
+ * symbol with the same owner, and the name of this symbol with $class
+ * appended to it.
+ */
final def implClass: Symbol = owner.info.decl(nme.implClassName(name))
/** The class that is logically an outer class of given `clazz`.
@@ -2538,7 +2541,6 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
override def enclClass: Symbol = this
override def toplevelClass: Symbol = this
override def enclMethod: Symbol = this
- override def owner: Symbol = abort("no-symbol does not have owner")
override def sourceFile: AbstractFileType = null
override def ownerChain: List[Symbol] = List()
override def ownersIterator: Iterator[Symbol] = Iterator.empty
@@ -2551,6 +2553,11 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
override def accessBoundary(base: Symbol): Symbol = RootClass
def cloneSymbolImpl(owner: Symbol, newFlags: Long): Symbol = abort()
override def originalEnclosingMethod = this
+
+ override def owner: Symbol =
+ abort("no-symbol does not have an owner (this is a bug: scala " + scala.util.Properties.versionString + ")")
+ override def typeConstructor: Type =
+ abort("no-symbol does not have a type constructor (this may indicate scalac cannot find fundamental classes)")
}
/** Derives a new list of symbols from the given list by mapping the given
diff --git a/src/compiler/scala/tools/ant/Scalac.scala b/src/compiler/scala/tools/ant/Scalac.scala
index 7aff4e3e8e..04ff0c440d 100644
--- a/src/compiler/scala/tools/ant/Scalac.scala
+++ b/src/compiler/scala/tools/ant/Scalac.scala
@@ -608,7 +608,7 @@ class Scalac extends ScalaMatchingTask with ScalacShared {
if (!deprecation.isEmpty) settings.deprecation.value = deprecation.get
if (!nobootcp.isEmpty) settings.nobootcp.value = nobootcp.get
if (!nowarn.isEmpty) settings.nowarn.value = nowarn.get
- if (!optimise.isEmpty) settings.XO.value = optimise.get
+ if (!optimise.isEmpty) settings.optimise.value = optimise.get
if (!unchecked.isEmpty) settings.unchecked.value = unchecked.get
if (!usejavacp.isEmpty) settings.usejavacp.value = usejavacp.get
diff --git a/src/compiler/scala/tools/ant/templates/tool-windows.tmpl b/src/compiler/scala/tools/ant/templates/tool-windows.tmpl
index 9f1fbc4524..5949689b24 100644
--- a/src/compiler/scala/tools/ant/templates/tool-windows.tmpl
+++ b/src/compiler/scala/tools/ant/templates/tool-windows.tmpl
@@ -86,4 +86,6 @@ goto :eof
:end
@@endlocal
-exit /b %errorlevel%
+
+REM exit code fix, see http://stackoverflow.com/questions/4632891/exiting-batch-with-exit-b-x-where-x-1-acts-as-if-command-completed-successfu
+@@%COMSPEC% /C exit %errorlevel% >nul
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
index 15b4c8c708..badf5d70d1 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
@@ -1528,7 +1528,7 @@ abstract class GenICode extends SubComponent {
if (mustUseAnyComparator) {
// when -optimise is on we call the @inline-version of equals, found in ScalaRunTime
val equalsMethod =
- if (!settings.XO.value) {
+ if (!settings.optimise.value) {
def default = platform.externalEquals
platform match {
case x: JavaPlatform =>
@@ -1550,7 +1550,7 @@ abstract class GenICode extends SubComponent {
val ctx1 = genLoad(l, ctx, ObjectReference)
val ctx2 = genLoad(r, ctx1, ObjectReference)
- ctx2.bb.emit(CALL_METHOD(equalsMethod, if (settings.XO.value) Dynamic else Static(false)))
+ ctx2.bb.emit(CALL_METHOD(equalsMethod, if (settings.optimise.value) Dynamic else Static(false)))
ctx2.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, NE, BOOL))
ctx2.bb.close
}
diff --git a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala
index 3e8ef3f611..66f802f74f 100644
--- a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala
+++ b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala
@@ -62,6 +62,15 @@ abstract class Inliners extends SubComponent {
override def apply(c: IClass) {
inliner analyzeClass c
}
+
+ override def run() {
+ try {
+ super.run()
+ } finally {
+ inliner.NonPublicRefs.usesNonPublics.clear()
+ inliner.recentTFAs.clear
+ }
+ }
}
def isBottomType(sym: Symbol) = sym == NullClass || sym == NothingClass
@@ -79,17 +88,10 @@ abstract class Inliners extends SubComponent {
val Private, Protected, Public = Value
/** Cache whether a method calls private members. */
- val usesNonPublics: mutable.Map[IMethod, Value] = perRunCaches.newMap()
+ val usesNonPublics = mutable.Map.empty[IMethod, Value]
}
import NonPublicRefs._
- /* fresh name counter */
- val fresh = perRunCaches.newMap[String, Int]() withDefaultValue 0
- def freshName(s: String): TermName = {
- fresh(s) += 1
- newTermName(s + fresh(s))
- }
-
private def hasInline(sym: Symbol) = sym hasAnnotation ScalaInlineClass
private def hasNoInline(sym: Symbol) = sym hasAnnotation ScalaNoInlineClass
@@ -97,6 +99,28 @@ abstract class Inliners extends SubComponent {
private var currentIClazz: IClass = _
private def warn(pos: Position, msg: String) = currentIClazz.cunit.warning(pos, msg)
+ val recentTFAs = mutable.Map.empty[Symbol, Tuple2[Boolean, analysis.MethodTFA]]
+ private def getRecentTFA(incm: IMethod): (Boolean, analysis.MethodTFA) = {
+
+ def containsRETURN(blocks: List[BasicBlock]) = blocks exists { bb => bb.lastInstruction.isInstanceOf[RETURN] }
+
+ val opt = recentTFAs.get(incm.symbol)
+ if(opt.isDefined) {
+ // FYI val cachedBBs = opt.get._2.in.keySet
+ // FYI assert(incm.blocks.toSet == cachedBBs)
+ // incm.code.touched plays no role here
+ return opt.get
+ }
+
+ val hasRETURN = containsRETURN(incm.code.blocksList) || (incm.exh exists { eh => containsRETURN(eh.blocks) })
+ var a: analysis.MethodTFA = null
+ if(hasRETURN) { a = new analysis.MethodTFA(incm); a.run }
+
+ if(hasInline(incm.symbol)) { recentTFAs.put(incm.symbol, (hasRETURN, a)) }
+
+ (hasRETURN, a)
+ }
+
def analyzeClass(cls: IClass): Unit =
if (settings.inline.value) {
debuglog("Analyzing " + cls)
@@ -106,7 +130,7 @@ abstract class Inliners extends SubComponent {
ms foreach { im =>
if(hasInline(im.symbol)) {
log("Not inlining into " + im.symbol.originalName.decode + " because it is marked @inline.")
- } else if(im.hasCode) {
+ } else if(im.hasCode && !im.symbol.isBridge) {
analyzeMethod(im)
}
}
@@ -114,20 +138,21 @@ abstract class Inliners extends SubComponent {
val tfa = new analysis.MTFAGrowable()
tfa.stat = global.opt.printStats
- val staleOut = new mutable.ListBuffer[BasicBlock]
+ val staleOut = new mutable.ListBuffer[BasicBlock]
val splicedBlocks = mutable.Set.empty[BasicBlock]
- val staleIn = mutable.Set.empty[BasicBlock]
-
- // how many times have we already inlined this method here?
- private val inlinedMethodCount = perRunCaches.newMap[Symbol, Int]() withDefaultValue 0
+ val staleIn = mutable.Set.empty[BasicBlock]
def analyzeMethod(m: IMethod): Unit = {
- var sizeBeforeInlining = if (m.hasCode) m.code.blockCount else 0
- var instrBeforeInlining = if (m.hasCode) m.code.instructionCount else 0
+ var sizeBeforeInlining = m.code.blockCount
+ var instrBeforeInlining = m.code.instructionCount
var retry = false
var count = 0
- fresh.clear()
- inlinedMethodCount.clear()
+
+ // fresh name counter
+ val fresh = mutable.HashMap.empty[String, Int] withDefaultValue 0
+ // how many times have we already inlined this method here?
+ val inlinedMethodCount = mutable.HashMap.empty[Symbol, Int] withDefaultValue 0
+
val caller = new IMethodInfo(m)
var info: tfa.lattice.Elem = null
@@ -146,17 +171,20 @@ abstract class Inliners extends SubComponent {
warn(i.pos, "Could not inline required method %s because %s.".format(msym.originalName.decode, reason))
}
- if (shouldLoadImplFor(concreteMethod, receiver)) {
+ def isAvailable = icodes available concreteMethod.enclClass
+
+ if (!isAvailable && shouldLoadImplFor(concreteMethod, receiver)) {
// Until r22824 this line was:
// icodes.icode(concreteMethod.enclClass, true)
//
- // Changing it to the below was the proximate cause for SI-3882:
+ // Changing it to
+ // icodes.load(concreteMethod.enclClass)
+ // was the proximate cause for SI-3882:
// error: Illegal index: 0 overlaps List((variable par1,LONG))
// error: Illegal index: 0 overlaps List((variable par1,LONG))
icodes.load(concreteMethod.enclClass)
}
- def isAvailable = icodes available concreteMethod.enclClass
def isCandidate = (
isClosureClass(receiver)
|| concreteMethod.isEffectivelyFinal
@@ -179,7 +207,7 @@ abstract class Inliners extends SubComponent {
lookupIMethod(concreteMethod, receiver) match {
case Some(callee) =>
val inc = new IMethodInfo(callee)
- val pair = new CallerCalleeInfo(caller, inc)
+ val pair = new CallerCalleeInfo(caller, inc, fresh, inlinedMethodCount)
if (pair isStampedForInlining info.stack) {
retry = true
@@ -196,6 +224,7 @@ abstract class Inliners extends SubComponent {
* might have changed after the inlining.
*/
usesNonPublics -= m
+ recentTFAs -= m.symbol
}
else {
if (settings.debug.value)
@@ -315,11 +344,10 @@ abstract class Inliners extends SubComponent {
def inline = hasInline(sym)
def noinline = hasNoInline(sym)
- def numInlined = inlinedMethodCount(sym)
def isBridge = sym.isBridge
def isInClosure = isClosureClass(owner)
- def isHigherOrder = isHigherOrderMethod(sym)
+ val isHigherOrder = isHigherOrderMethod(sym)
def isMonadic = isMonadicMethod(sym)
def handlers = m.exh
@@ -328,7 +356,7 @@ abstract class Inliners extends SubComponent {
def length = blocks.length
def openBlocks = blocks filterNot (_.closed)
def instructions = m.code.instructions
- def linearized = linearizer linearize m
+ // def linearized = linearizer linearize m
def isSmall = (length <= SMALL_METHOD_SIZE) && blocks(0).length < 10
def isLarge = length > MAX_INLINE_SIZE
@@ -347,9 +375,14 @@ abstract class Inliners extends SubComponent {
def addHandlers(exhs: List[ExceptionHandler]) = m.exh = exhs ::: m.exh
}
- class CallerCalleeInfo(val caller: IMethodInfo, val inc: IMethodInfo) {
+ class CallerCalleeInfo(val caller: IMethodInfo, val inc: IMethodInfo, fresh: mutable.Map[String, Int], inlinedMethodCount: collection.Map[Symbol, Int]) {
def isLargeSum = caller.length + inc.length - 1 > SMALL_METHOD_SIZE
+ private def freshName(s: String): TermName = {
+ fresh(s) += 1
+ newTermName(s + fresh(s))
+ }
+
/** Inline 'inc' into 'caller' at the given block and instruction.
* The instruction must be a CALL_METHOD.
*/
@@ -364,7 +397,7 @@ abstract class Inliners extends SubComponent {
def newLocal(baseName: String, kind: TypeKind) =
new Local(caller.sym.newVariable(freshName(baseName), targetPos), kind, false)
- val a = new analysis.MethodTFA(inc.m)
+ val (hasRETURN, a) = getRecentTFA(inc.m)
/* The exception handlers that are active at the current block. */
val activeHandlers = caller.handlers filter (_ covered block)
@@ -393,7 +426,7 @@ abstract class Inliners extends SubComponent {
case x => newLocal("$retVal", x)
}
- val inlinedLocals = perRunCaches.newMap[Local, Local]()
+ val inlinedLocals = mutable.HashMap.empty[Local, Local]
/** Add a new block in the current context. */
def newBlock() = {
@@ -475,9 +508,6 @@ abstract class Inliners extends SubComponent {
inlinedBlock(b).varsInScope ++= (b.varsInScope map inlinedLocals)
}
- // analyse callee
- a.run
-
// re-emit the instructions before the call
block.open
block.clear
@@ -494,7 +524,7 @@ abstract class Inliners extends SubComponent {
// duplicate the other blocks in the callee
val calleeLin = inc.m.linearizedBlocks()
calleeLin foreach { bb =>
- var info = a in bb
+ var info = if(hasRETURN) (a in bb) else null
def emitInlined(i: Instruction) = inlinedBlock(bb).emit(i, targetPos)
def emitDrops(toDrop: Int) = info.stack.types drop toDrop foreach (t => emitInlined(DROP(t)))
@@ -510,7 +540,7 @@ abstract class Inliners extends SubComponent {
case _ => ()
}
emitInlined(map(i))
- info = a.interpret(info, i)
+ info = if(hasRETURN) a.interpret(info, i) else null
}
inlinedBlock(bb).close
}
@@ -538,7 +568,7 @@ abstract class Inliners extends SubComponent {
| isSafeToInline: %s
| shouldInline: %s
""".stripMargin.format(
- inc.m, sameSymbols, inc.numInlined < 2,
+ inc.m, sameSymbols, inlinedMethodCount(inc.sym) < 2,
inc.m.hasCode, isSafeToInline(stack), shouldInline
)
)
@@ -635,28 +665,22 @@ abstract class Inliners extends SubComponent {
var score = 0
- // better not inline inside closures, but hope that the closure itself
- // is repeatedly inlined
- if (caller.isInClosure) score -= 2
+ // better not inline inside closures, but hope that the closure itself is repeatedly inlined
+ if (caller.isInClosure) score -= 2
else if (caller.inlinedCalls < 1) score -= 1 // only monadic methods can trigger the first inline
- if (inc.isSmall)
- score += 1
+ if (inc.isSmall) score += 1;
+ if (inc.isLarge) score -= 1;
if (caller.isSmall && isLargeSum) {
score -= 1
debuglog("shouldInline: score decreased to " + score + " because small " + caller + " would become large")
}
- if (inc.isLarge)
- score -= 1
- if (inc.isMonadic)
- score += 3
- else if (inc.isHigherOrder)
- score += 1
- if (inc.isInClosure)
- score += 2
- if (inc.numInlined > 2)
- score -= 2
+ if (inc.isMonadic) score += 3
+ else if (inc.isHigherOrder) score += 1
+
+ if (inc.isInClosure) score += 2;
+ if (inlinedMethodCount(inc.sym) > 2) score -= 2;
log("shouldInline(" + inc.m + ") score: " + score)
diff --git a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala
index 0dc51d5eb0..7c71438b98 100644
--- a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala
@@ -110,7 +110,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
class ILoopInterpreter extends IMain(settings, out) {
outer =>
- private class ThreadStoppingLineManager extends Line.Manager(parentClassLoader) {
+ private class ThreadStoppingLineManager(classLoader: ClassLoader) extends Line.Manager(classLoader) {
override def onRunaway(line: Line[_]): Unit = {
val template = """
|// She's gone rogue, captain! Have to take her out!
@@ -126,8 +126,8 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
override lazy val formatting = new Formatting {
def prompt = ILoop.this.prompt
}
- override protected def createLineManager(): Line.Manager =
- new ThreadStoppingLineManager
+ override protected def createLineManager(classLoader: ClassLoader): Line.Manager =
+ new ThreadStoppingLineManager(classLoader)
override protected def parentClassLoader =
settings.explicitParentLoader.getOrElse( classOf[ILoop].getClassLoader )
diff --git a/src/compiler/scala/tools/nsc/interpreter/IMain.scala b/src/compiler/scala/tools/nsc/interpreter/IMain.scala
index 0f0ab69e6d..8cdd2334ab 100644
--- a/src/compiler/scala/tools/nsc/interpreter/IMain.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/IMain.scala
@@ -269,7 +269,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
/** Create a line manager. Overridable. */
protected def noLineManager = ReplPropsKludge.noThreadCreation(settings)
- protected def createLineManager(): Line.Manager = new Line.Manager(_classLoader)
+ protected def createLineManager(classLoader: ClassLoader): Line.Manager = new Line.Manager(classLoader)
/** Instantiate a compiler. Overridable. */
protected def newCompiler(settings: Settings, reporter: Reporter) = {
@@ -304,7 +304,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
final def ensureClassLoader() {
if (_classLoader == null) {
_classLoader = makeClassLoader()
- _lineManager = if (noLineManager) null else createLineManager()
+ _lineManager = if (noLineManager) null else createLineManager(_classLoader)
}
}
def classLoader: AbstractFileClassLoader = {
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
index 099145d3ae..b818927ceb 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
@@ -606,7 +606,7 @@ abstract class ClassfileParser {
def parseField() {
val jflags = in.nextChar
var sflags = toScalaFieldFlags(jflags)
- if ((sflags & PRIVATE) != 0L && !global.settings.XO.value) {
+ if ((sflags & PRIVATE) != 0L && !global.settings.optimise.value) {
in.skip(4); skipAttributes()
} else {
val name = pool.getName(in.nextChar)
@@ -637,7 +637,7 @@ abstract class ClassfileParser {
def parseMethod() {
val jflags = in.nextChar.toInt
var sflags = toScalaMethodFlags(jflags)
- if (isPrivate(jflags) && !global.settings.XO.value) {
+ if (isPrivate(jflags) && !global.settings.optimise.value) {
val name = pool.getName(in.nextChar)
if (name == nme.CONSTRUCTOR)
sawPrivateConstructor = true
@@ -645,7 +645,7 @@ abstract class ClassfileParser {
} else {
if ((jflags & JAVA_ACC_BRIDGE) != 0)
sflags |= BRIDGE
- if ((sflags & PRIVATE) != 0L && global.settings.XO.value) {
+ if ((sflags & PRIVATE) != 0L && global.settings.optimise.value) {
in.skip(4); skipAttributes()
} else {
val name = pool.getName(in.nextChar)
diff --git a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala
index 8f5d308b8f..17d63ea439 100644
--- a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala
+++ b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala
@@ -77,31 +77,51 @@ abstract class AddInterfaces extends InfoTransform {
def implClassPhase = currentRun.erasurePhase.next
/** Return the implementation class of a trait; create a new one of one does not yet exist */
- def implClass(iface: Symbol): Symbol = implClassMap.getOrElse(iface, {
- atPhase(implClassPhase) {
- val implName = nme.implClassName(iface.name)
- var impl = if (iface.owner.isClass) iface.owner.info.decl(implName) else NoSymbol
- if (impl != NoSymbol && settings.XO.value) {
- log("unlinking impl class " + impl)
- iface.owner.info.decls.unlink(impl)
- impl = NoSymbol
- }
- if (impl == NoSymbol) {
- impl = iface.cloneSymbolImpl(iface.owner)
- impl.name = implName
- impl.sourceFile = iface.sourceFile
- if (iface.owner.isClass)
- iface.owner.info.decls enter impl
+ def implClass(iface: Symbol): Symbol = {
+ iface.info
+
+ implClassMap.getOrElse(iface, {
+ atPhase(implClassPhase) {
+ log("%s.implClass == %s".format(iface, iface.implClass))
+ val implName = nme.implClassName(iface.name)
+ var impl = if (iface.owner.isClass) iface.owner.info.decl(implName) else NoSymbol
+ impl.info
+
+ val originalImpl = impl
+ val originalImplString = originalImpl.hasFlagsToString(-1L)
+ if (impl != NoSymbol) {
+ // Unlink a pre-existing symbol only if the implementation class is
+ // visible on the compilation classpath. In general this is true under
+ // -optimise and not otherwise, but the classpath can use arbitrary
+ // logic so the classpath must be queried.
+ if (classPath.context.isValidName(implName + ".class")) {
+ log("unlinking impl class " + impl)
+ iface.owner.info.decls.unlink(impl)
+ impl = NoSymbol
+ }
+ else log("not unlinking existing " + impl + " as the impl class is not visible on the classpath.")
+ }
+ if (impl == NoSymbol) {
+ impl = iface.cloneSymbolImpl(iface.owner)
+ impl.name = implName
+ impl.sourceFile = iface.sourceFile
+ if (iface.owner.isClass)
+ iface.owner.info.decls enter impl
+ }
+ if (currentRun.compiles(iface)) currentRun.symSource(impl) = iface.sourceFile
+ impl setPos iface.pos
+ impl.flags = iface.flags & ~(INTERFACE | lateINTERFACE) | IMPLCLASS
+ impl setInfo new LazyImplClassType(iface)
+ implClassMap(iface) = impl
+ debuglog(
+ "generating impl class " + impl + " " + impl.hasFlagsToString(-1L) + " in " + iface.owner + (
+ if (originalImpl == NoSymbol) "" else " (cloned from " + originalImpl.fullLocationString + " " + originalImplString + ")"
+ )
+ )
+ impl
}
- if (currentRun.compiles(iface)) currentRun.symSource(impl) = iface.sourceFile
- impl setPos iface.pos
- impl.flags = iface.flags & ~(INTERFACE | lateINTERFACE) | IMPLCLASS
- impl setInfo new LazyImplClassType(iface)
- implClassMap(iface) = impl
- debuglog("generating impl class " + impl + " in " + iface.owner)//debug
- impl
- }
- })
+ })
+ }
/** A lazy type to set the info of an implementation class
* The parents of an implementation class for trait iface are:
diff --git a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
index 0f11161914..712298bd89 100644
--- a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
+++ b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
@@ -9,7 +9,8 @@ package transform
import symtab._
import Flags._
import util.TreeSet
-import scala.collection.mutable.{ LinkedHashMap, ListBuffer }
+import scala.collection.{ mutable, immutable }
+import scala.collection.mutable.LinkedHashMap
abstract class LambdaLift extends InfoTransform {
import global._
@@ -64,6 +65,8 @@ abstract class LambdaLift extends InfoTransform {
/** The set of symbols that need to be renamed. */
private val renamable = newSymSet
+ private val renamableImplClasses = mutable.HashMap[Name, Symbol]() withDefaultValue NoSymbol
+
/** A flag to indicate whether new free variables have been found */
private var changedFreeVars: Boolean = _
@@ -152,7 +155,21 @@ abstract class LambdaLift extends InfoTransform {
tree match {
case ClassDef(_, _, _, _) =>
liftedDefs(tree.symbol) = Nil
- if (sym.isLocal) renamable addEntry sym
+ if (sym.isLocal) {
+ // Don't rename implementation classes independently of their interfaces. If
+ // the interface is to be renamed, then we will rename the implementation
+ // class at that time. You'd think we could call ".implClass" on the trait
+ // rather than collecting them in another map, but that seems to fail for
+ // exactly the traits being renamed here (i.e. defined in methods.)
+ //
+ // !!! - it makes no sense to have methods like "implClass" and
+ // "companionClass" which fail for an arbitrary subset of nesting
+ // arrangements, and then have separate methods which attempt to compensate
+ // for that failure. There should be exactly one method for any given
+ // entity which always gives the right answer.
+ if (sym.isImplClass) renamableImplClasses(nme.interfaceName(sym.name)) = sym
+ else renamable addEntry sym
+ }
case DefDef(_, _, _, _, _, _) =>
if (sym.isLocal) {
renamable addEntry sym
@@ -196,8 +213,8 @@ abstract class LambdaLift extends InfoTransform {
for (caller <- called.keys ; callee <- called(caller) ; fvs <- free get callee ; fv <- fvs)
markFree(fv, caller)
} while (changedFreeVars)
-
- for (sym <- renamable) {
+
+ def renameSym(sym: Symbol) {
val originalName = sym.name
val base = sym.name + nme.NAME_JOIN_STRING + (
if (sym.isAnonymousFunction && sym.owner.isMethod)
@@ -211,6 +228,25 @@ abstract class LambdaLift extends InfoTransform {
debuglog("renaming in %s: %s => %s".format(sym.owner.fullLocationString, originalName, sym.name))
}
+ /** Rename a trait's interface and implementation class in coordinated fashion.
+ */
+ def renameTrait(traitSym: Symbol, implSym: Symbol) {
+ val originalImplName = implSym.name
+ renameSym(traitSym)
+ implSym.name = nme.implClassName(traitSym.name)
+
+ debuglog("renaming impl class in step with %s: %s => %s".format(traitSym, originalImplName, implSym.name))
+ }
+
+ for (sym <- renamable) {
+ // If we renamed a trait from Foo to Foo$1, we must rename the implementation
+ // class from Foo$class to Foo$1$class. (Without special consideration it would
+ // become Foo$class$1 instead.)
+ val implClass = if (sym.isTrait) renamableImplClasses(sym.name) else NoSymbol
+ if ((implClass ne NoSymbol) && (sym.owner == implClass.owner)) renameTrait(sym, implClass)
+ else renameSym(sym)
+ }
+
atPhase(phase.next) {
for ((owner, freeValues) <- free.toList) {
val newFlags = SYNTHETIC | ( if (owner.isClass) PARAMACCESSOR | PrivateLocal else PARAM )
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 0fbde03e97..216ad6cd4c 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -2838,9 +2838,22 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
def packSymbols(hidden: List[Symbol], tp: Type): Type =
if (hidden.isEmpty) tp
else existentialTransform(hidden, tp)(existentialAbstraction)
+
+ def isReferencedFrom(ctx: Context, sym: Symbol): Boolean =
+ ctx.owner.isTerm &&
+ (ctx.scope.exists { dcl => dcl.isInitialized && (dcl.info contains sym) }) ||
+ {
+ var ctx1 = ctx.outer
+ while ((ctx1 != NoContext) && (ctx1.scope eq ctx.scope)) ctx1 = ctx1.outer
+ (ctx1 != NoContext) && isReferencedFrom(ctx1, sym)
+ }
def isCapturedExistential(sym: Symbol) =
- sym hasAllFlags (EXISTENTIAL | CAPTURED) // todo refine this
+ (sym hasAllFlags (EXISTENTIAL | CAPTURED)) && {
+ val start = startTimer(isReferencedNanos)
+ try !isReferencedFrom(context, sym)
+ finally stopTimer(isReferencedNanos, start)
+ }
def packCaptured(tpe: Type): Type = {
val captured = mutable.Set[Symbol]()
diff --git a/src/compiler/scala/tools/nsc/util/Statistics.scala b/src/compiler/scala/tools/nsc/util/Statistics.scala
index 27239b9b9f..f7c27dceb5 100644
--- a/src/compiler/scala/tools/nsc/util/Statistics.scala
+++ b/src/compiler/scala/tools/nsc/util/Statistics.scala
@@ -20,7 +20,7 @@ class Statistics extends scala.reflect.internal.util.Statistics {
val typedSelectCount = new Counter
val typerNanos = new Timer
val classReadNanos = new Timer
-
+
val failedApplyNanos = new Timer
val failedOpEqNanos = new Timer
val failedSilentNanos = new Timer
@@ -48,6 +48,7 @@ class Statistics extends scala.reflect.internal.util.Statistics {
val subtypeImprovCount = new SubCounter(subtypeCount)
val subtypeETNanos = new Timer
val matchesPtNanos = new Timer
+ val isReferencedNanos = new Timer
val ctr1 = new Counter
val ctr2 = new Counter
val ctr3 = new Counter
@@ -137,6 +138,7 @@ abstract class StatisticsInfo {
inform("time spent in failed : "+showRelTyper(failedSilentNanos))
inform(" failed apply : "+showRelTyper(failedApplyNanos))
inform(" failed op= : "+showRelTyper(failedOpEqNanos))
+ inform("time spent ref scanning : "+showRelTyper(isReferencedNanos))
inform("micros by tree node : "+showCounts(microsByType))
inform("#visits by tree node : "+showCounts(visitsByType))
val average = new ClassCounts
diff --git a/src/library/scala/Predef.scala b/src/library/scala/Predef.scala
index b175fb9e1d..824e048e73 100644
--- a/src/library/scala/Predef.scala
+++ b/src/library/scala/Predef.scala
@@ -269,7 +269,7 @@ object Predef extends LowPriorityImplicits {
def printf(text: String, xs: Any*) = Console.print(text.format(xs: _*))
def readLine(): String = Console.readLine()
- def readLine(text: String, args: Any*) = Console.readLine(text, args)
+ def readLine(text: String, args: Any*) = Console.readLine(text, args: _*)
def readBoolean() = Console.readBoolean()
def readByte() = Console.readByte()
def readShort() = Console.readShort()
diff --git a/src/library/scala/collection/immutable/List.scala b/src/library/scala/collection/immutable/List.scala
index c6f056bd81..e9ecc75e0f 100644
--- a/src/library/scala/collection/immutable/List.scala
+++ b/src/library/scala/collection/immutable/List.scala
@@ -316,28 +316,7 @@ final case class ::[B](private var hd: B, private[scala] var tl: List[B]) extend
override def tail : List[B] = tl
override def isEmpty: Boolean = false
- import java.io._
- private def writeObject(out: ObjectOutputStream) {
- var xs: List[B] = this
- while (!xs.isEmpty) { out.writeObject(xs.head); xs = xs.tail }
- out.writeObject(ListSerializeEnd)
- }
-
- private def readObject(in: ObjectInputStream) {
- hd = in.readObject.asInstanceOf[B]
- assert(hd != ListSerializeEnd)
- var current: ::[B] = this
- while (true) in.readObject match {
- case ListSerializeEnd =>
- current.tl = Nil
- return
- case a : Any =>
- val list : ::[B] = new ::(a.asInstanceOf[B], Nil)
- current.tl = list
- current = list
- }
- }
}
/** $factoryInfo
diff --git a/src/library/scala/collection/immutable/Stream.scala b/src/library/scala/collection/immutable/Stream.scala
index e6587f9615..2eb2f8eb09 100644
--- a/src/library/scala/collection/immutable/Stream.scala
+++ b/src/library/scala/collection/immutable/Stream.scala
@@ -929,13 +929,19 @@ self =>
/** A specialized, extra-lazy implementation of a stream iterator, so it can
* iterate as lazily as it traverses the tail.
*/
-final class StreamIterator[+A](self: Stream[A]) extends AbstractIterator[A] with Iterator[A] {
+final class StreamIterator[+A] private() extends AbstractIterator[A] with Iterator[A] {
+ def this(self: Stream[A]) {
+ this()
+ these = new LazyCell(self)
+ }
+
// A call-by-need cell.
class LazyCell(st: => Stream[A]) {
lazy val v = st
}
- private var these = new LazyCell(self)
+ private var these: LazyCell = _
+
def hasNext: Boolean = these.v.nonEmpty
def next(): A =
if (isEmpty) Iterator.empty.next
diff --git a/src/library/scala/collection/mutable/ListBuffer.scala b/src/library/scala/collection/mutable/ListBuffer.scala
index 131cdd0005..eb871135df 100644
--- a/src/library/scala/collection/mutable/ListBuffer.scala
+++ b/src/library/scala/collection/mutable/ListBuffer.scala
@@ -13,6 +13,7 @@ package mutable
import generic._
import immutable.{List, Nil, ::}
+import java.io._
/** A `Buffer` implementation back up by a list. It provides constant time
* prepend and append. Most other operations are linear.
@@ -53,6 +54,7 @@ final class ListBuffer[A]
override def companion: GenericCompanion[ListBuffer] = ListBuffer
import scala.collection.Traversable
+ import scala.collection.immutable.ListSerializeEnd
private var start: List[A] = Nil
private var last0: ::[A] = _
@@ -60,7 +62,49 @@ final class ListBuffer[A]
private var len = 0
protected def underlying: immutable.Seq[A] = start
-
+
+ private def writeObject(out: ObjectOutputStream) {
+ // write start
+ var xs: List[A] = start
+ while (!xs.isEmpty) { out.writeObject(xs.head); xs = xs.tail }
+ out.writeObject(ListSerializeEnd)
+
+ // no need to write last0
+
+ // write if exported
+ out.writeBoolean(exported)
+
+ // write the length
+ out.writeInt(len)
+ }
+
+ private def readObject(in: ObjectInputStream) {
+ // read start, set last0 appropriately
+ var elem: A = in.readObject.asInstanceOf[A]
+ if (elem == ListSerializeEnd) {
+ start = Nil
+ last0 = null
+ } else {
+ var current = new ::(elem, Nil)
+ start = current
+ elem = in.readObject.asInstanceOf[A]
+ while (elem != ListSerializeEnd) {
+ val list = new ::(elem, Nil)
+ current.tl = list
+ current = list
+ elem = in.readObject.asInstanceOf[A]
+ }
+ last0 = current
+ start
+ }
+
+ // read if exported
+ exported = in.readBoolean()
+
+ // read the length
+ len = in.readInt()
+ }
+
/** The current length of the buffer.
*
* This operation takes constant time.
diff --git a/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala b/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala
index f39debf31d..7c6dd0848f 100644
--- a/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala
+++ b/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala
@@ -58,10 +58,17 @@ class ReflectiveRunner {
if (isPartestDebug)
println("Loading classes from:\n" + sepUrls.mkString("\n"))
- val paths = classPath match {
- case Some(cp) => Nil
- case _ => files.toList map (_.path)
- }
+ // @partest maintainer: it seems to me that commented lines are incorrect
+ // if classPath is not empty, then it has been provided by the --classpath option
+ // which points to the root of Scala home (see ConsoleFileManager's testClasses and the true flag in the ctor for more information)
+ // this doesn't mean that we had custom Java classpath set, so we don't have to override latestXXXFiles from the file manager
+ //
+ //val paths = classPath match {
+ // case Some(cp) => Nil
+ // case _ => files.toList map (_.path)
+ //}
+ val paths = files.toList map (_.path)
+
val newClasspath = ClassPath.join(paths: _*)
setProp("java.class.path", newClasspath)