diff options
Diffstat (limited to 'src')
8 files changed, 104 insertions, 59 deletions
diff --git a/src/compiler/scala/reflect/internal/Symbols.scala b/src/compiler/scala/reflect/internal/Symbols.scala index b4d2b1531f..0e729bc7ea 100644 --- a/src/compiler/scala/reflect/internal/Symbols.scala +++ b/src/compiler/scala/reflect/internal/Symbols.scala @@ -2538,7 +2538,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 +2550,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/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/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/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() |