diff options
author | Josh Suereth <Joshua.Suereth@gmail.com> | 2012-09-11 11:24:50 -0700 |
---|---|---|
committer | Josh Suereth <Joshua.Suereth@gmail.com> | 2012-09-11 11:24:50 -0700 |
commit | ad9b6bcdbcd48566f0b7f03b29c9252fcebc3926 (patch) | |
tree | 9be5bfa443383414e30e35ea1bf7d6b62fd42da0 | |
parent | 7b26b1f71e6a6bb70fdeb2db8416db5b9fb12e3a (diff) | |
parent | f4a81fe69a13136ce66b963774476277d4464d87 (diff) | |
download | scala-ad9b6bcdbcd48566f0b7f03b29c9252fcebc3926.tar.gz scala-ad9b6bcdbcd48566f0b7f03b29c9252fcebc3926.tar.bz2 scala-ad9b6bcdbcd48566f0b7f03b29c9252fcebc3926.zip |
Merge pull request #1286 from paulp/topic/inliner-logging
Topic/inliner logging
22 files changed, 270 insertions, 246 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 98a8359f89..d101337087 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -266,9 +266,8 @@ class Global(var currentSettings: Settings, var reporter: Reporter) log("Running operation '%s' after every phase.\n".format(msg) + describeAfterEveryPhase(op)) } - def shouldLogAtThisPhase = ( - (settings.log.isSetByUser) - && ((settings.log containsPhase globalPhase) || (settings.log containsPhase phase)) + override def shouldLogAtThisPhase = settings.log.isSetByUser && ( + (settings.log containsPhase globalPhase) || (settings.log containsPhase phase) ) // Over 200 closure objects are eliminated by inlining this. @inline final def log(msg: => AnyRef) { diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index 739aa2b184..24662e2ac3 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -128,7 +128,6 @@ abstract class GenICode extends SubComponent { if (staticfield != NoSymbol) { // in companion object accessors to @static fields, we access the static field directly val hostClass = m.symbol.owner.companionClass - if (m.symbol.isGetter) { ctx1.bb.emit(LOAD_FIELD(staticfield, true) setHostClass hostClass, tree.pos) ctx1.bb.closeWith(RETURN(m.returnType)) @@ -662,16 +661,16 @@ abstract class GenICode extends SubComponent { } else { val sym = tree.symbol val local = ctx.method.addLocal(new Local(sym, toTypeKind(sym.info), false)) - + if (rhs == EmptyTree) { debuglog("Uninitialized variable " + tree + " at: " + (tree.pos)); ctx.bb.emit(getZeroOf(local.kind)) } - + var ctx1 = ctx if (rhs != EmptyTree) ctx1 = genLoad(rhs, ctx, local.kind); - + ctx1.bb.emit(STORE_LOCAL(local), tree.pos) ctx1.scope.add(local) ctx1.bb.emit(SCOPE_ENTER(local)) @@ -730,10 +729,10 @@ abstract class GenICode extends SubComponent { ctx1.bb.enterIgnoreMode generatedType = expectedType ctx1 - } + } genLoadReturn - case t @ Try(_, _, _) => + case t @ Try(_, _, _) => genLoadTry(t, ctx, generatedType = _) case Throw(expr) => @@ -753,7 +752,7 @@ abstract class GenICode extends SubComponent { case Object_asInstanceOf => true case _ => abort("Unexpected type application " + fun + "[sym: " + sym.fullName + "]" + " in: " + tree) } - + val Select(obj, _) = fun val l = toTypeKind(obj.tpe) val r = toTypeKind(targs.head.tpe) @@ -797,7 +796,7 @@ abstract class GenICode extends SubComponent { ctx.bb.emit(THIS(ctx.clazz.symbol), tree.pos) val ctx1 = genLoadArguments(args, fun.symbol.info.paramTypes, ctx) - + ctx1.bb.emit(CALL_METHOD(fun.symbol, invokeStyle), tree.pos) generatedType = if (fun.symbol.isConstructor) UNIT @@ -815,7 +814,7 @@ abstract class GenICode extends SubComponent { val ctor = fun.symbol debugassert(ctor.isClassConstructor, "'new' call to non-constructor: " + ctor.name) - + generatedType = toTypeKind(tpt.tpe) debugassert(generatedType.isReferenceType || generatedType.isArrayType, "Non reference type cannot be instantiated: " + generatedType) @@ -861,7 +860,7 @@ abstract class GenICode extends SubComponent { ctx1 } ctx2 - + case _ => abort("Cannot instantiate " + tpt + " of kind: " + generatedType) } @@ -902,7 +901,7 @@ abstract class GenICode extends SubComponent { ctx1 case app @ Apply(fun @ Select(qual, _), args) - if !ctx.method.symbol.isStaticConstructor + if !ctx.method.symbol.isStaticConstructor && fun.symbol.isAccessor && fun.symbol.accessed.hasStaticAnnotation && qual.tpe.typeSymbol.orElse(fun.symbol.owner).companionClass != NoSymbol => // bypass the accessor to the companion object and load the static field directly @@ -941,11 +940,11 @@ abstract class GenICode extends SubComponent { } } genLoadApply5 - + case app @ Apply(fun, args) => def genLoadApply6 = { val sym = fun.symbol - + if (sym.isLabel) { // jump to a label val label = ctx.labels.getOrElse(sym, { // it is a forward jump, scan for labels @@ -982,7 +981,7 @@ abstract class GenICode extends SubComponent { Static(true) else Dynamic - + var ctx1 = if (invokeStyle.hasInstance) { if (forMSIL && !(invokeStyle.isInstanceOf[SuperCall]) && msil_IsValuetypeInstMethod(sym)) @@ -990,24 +989,26 @@ abstract class GenICode extends SubComponent { else genLoadQualifier(fun, ctx) } else ctx - + ctx1 = genLoadArguments(args, sym.info.paramTypes, ctx1) val cm = CALL_METHOD(sym, invokeStyle) - + /** In a couple cases, squirrel away a little extra information in the * CALL_METHOD for use by GenJVM. */ fun match { case Select(qual, _) => val qualSym = findHostClass(qual.tpe, sym) - - if (qualSym == ArrayClass) cm setTargetTypeKind toTypeKind(qual.tpe) - else cm setHostClass qualSym - - log( - if (qualSym == ArrayClass) "Stored target type kind " + toTypeKind(qual.tpe) + " for " + sym.fullName - else s"Set more precise host class for ${sym.fullName} hostClass: $qualSym" - ) + if (qualSym == ArrayClass) { + val kind = toTypeKind(qual.tpe) + cm setTargetTypeKind kind + log(s"Stored target type kind for {$sym.fullName} as $kind") + } + else { + cm setHostClass qualSym + if (qual.tpe.typeSymbol != qualSym) + log(s"Precisified host class for $sym from ${qual.tpe.typeSymbol.fullName} to ${qualSym.fullName}") + } case _ => } ctx1.bb.emit(cm, tree.pos) @@ -1143,7 +1144,7 @@ abstract class GenICode extends SubComponent { val elmKind = toTypeKind(tpt.tpe) generatedType = ARRAY(elmKind) val elems = _elems.toIndexedSeq - + ctx1.bb.emit(CONSTANT(new Constant(elems.length)), tree.pos) ctx1.bb.emit(CREATE_ARRAY(elmKind, 1)) // inline array literals @@ -1166,7 +1167,7 @@ abstract class GenICode extends SubComponent { val afterCtx = ctx1.newBlock var caseCtx: Context = null generatedType = toTypeKind(tree.tpe) - + var targets: List[BasicBlock] = Nil var tags: List[Int] = Nil var default: BasicBlock = afterCtx.bb @@ -1193,7 +1194,7 @@ abstract class GenICode extends SubComponent { abort("Invalid case statement in switch-like pattern match: " + tree + " at: " + (tree.pos)) } - + caseCtx = genLoad(body, tmpCtx, generatedType) // close the block unless it's already been closed by the body, which closes the block if it ends in a jump (which is emitted to have alternatives share their body) caseCtx.bb.closeWith(JUMP(afterCtx.bb) setPos caze.pos) diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala index d1d8e4a385..df158a29ea 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala @@ -200,7 +200,7 @@ abstract class CopyPropagation { in(b) = lattice.bottom out(b) = lattice.bottom assert(out.contains(b), out) - log("Added point: " + b) + debuglog("CopyAnalysis added point: " + b) } m.exh foreach { e => in(e.startBlock) = new copyLattice.State(copyLattice.emptyBinding, copyLattice.exceptionHandlerStack); @@ -531,11 +531,11 @@ abstract class CopyPropagation { case 0 => () case 1 if ctor.tpe.paramTypes.head == ctor.owner.rawowner.tpe => // it's an unused outer - log("considering unused outer at position 0 in " + ctor.tpe.paramTypes) + debuglog("considering unused outer at position 0 in " + ctor.tpe.paramTypes) paramTypes = paramTypes.tail values = values.tail case _ => - log("giving up on " + ctor + "(diff: " + diff + ")") + debuglog("giving up on " + ctor + "(diff: " + diff + ")") return bindings } @@ -566,7 +566,7 @@ abstract class CopyPropagation { method.blocks map { b => "\nIN(%s):\t Bindings: %s".format(b.label, in(b).bindings) + "\nIN(%s):\t Stack: %s".format(b.label, in(b).stack) - } + } ).mkString } /* class CopyAnalysis */ diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala index b57f5e86a3..ea0a0148e4 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala @@ -154,8 +154,10 @@ abstract class GenASM extends SubComponent with BytecodeWriters { inform("[running phase " + name + " on icode]") if (settings.Xdce.value) - for ((sym, cls) <- icodes.classes if inliner.isClosureClass(sym) && !deadCode.liveClosures(sym)) + for ((sym, cls) <- icodes.classes if inliner.isClosureClass(sym) && !deadCode.liveClosures(sym)) { + log(s"Optimizer eliminated ${sym.fullNameString}") icodes.classes -= sym + } // For predictably ordered error messages. var sortedClasses = classes.values.toList sortBy ("" + _.symbol.fullName) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala index 930791d88d..0f64a55d70 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala @@ -122,8 +122,10 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with inform("[running phase " + name + " on icode]") if (settings.Xdce.value) - for ((sym, cls) <- icodes.classes if inliner.isClosureClass(sym) && !deadCode.liveClosures(sym)) + for ((sym, cls) <- icodes.classes if inliner.isClosureClass(sym) && !deadCode.liveClosures(sym)) { + log(s"Optimizer eliminated ${sym.fullNameString}") icodes.classes -= sym + } // For predictably ordered error messages. val sortedClasses = classes.values.toList sortBy ("" + _.symbol.fullName) diff --git a/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala b/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala index 7772ccbdd5..eb2da72401 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala @@ -35,7 +35,7 @@ abstract class ClosureElimination extends SubComponent { case (STORE_LOCAL(x), LOAD_LOCAL(y)) if (x == y) => var liveOut = liveness.out(bb) if (!liveOut(x)) { - log("store/load to a dead local? " + x) + debuglog("store/load to a dead local? " + x) val instrs = bb.getArray var idx = instrs.length - 1 while (idx > 0 && (instrs(idx) ne i2)) { @@ -43,7 +43,7 @@ abstract class ClosureElimination extends SubComponent { idx -= 1 } if (!liveOut(x)) { - log("removing dead store/load " + x) + log("Removing dead store/load of " + x.sym.initialize.defString) Some(Nil) } else None } else @@ -84,6 +84,7 @@ abstract class ClosureElimination extends SubComponent { */ class ClosureElim { def analyzeClass(cls: IClass): Unit = if (settings.Xcloselim.value) { + log(s"Analyzing ${cls.methods.size} methods in $cls.") cls.methods foreach { m => analyzeMethod(m) peephole(m) @@ -95,7 +96,6 @@ abstract class ClosureElimination extends SubComponent { /* Some embryonic copy propagation. */ def analyzeMethod(m: IMethod): Unit = try {if (m.hasCode) { - log("Analyzing " + m) cpp.init(m) cpp.run @@ -110,23 +110,20 @@ abstract class ClosureElimination extends SubComponent { t match { case Deref(This) | Const(_) => bb.replaceInstruction(i, valueToInstruction(t)); - log("replaced " + i + " with " + t) + debuglog(s"replaced $i with $t") case _ => - bb.replaceInstruction(i, LOAD_LOCAL(info.getAlias(l))) - log("replaced " + i + " with " + info.getAlias(l)) - + val t = info.getAlias(l) + bb.replaceInstruction(i, LOAD_LOCAL(t)) + debuglog(s"replaced $i with $t") } case LOAD_FIELD(f, false) /* if accessible(f, m.symbol) */ => def replaceFieldAccess(r: Record) { val Record(cls, bindings) = r - info.getFieldNonRecordValue(r, f) match { - case Some(v) => - bb.replaceInstruction(i, - DROP(REFERENCE(cls)) :: valueToInstruction(v) :: Nil); - log("Replaced " + i + " with " + info.getFieldNonRecordValue(r, f)); - case None => + info.getFieldNonRecordValue(r, f) foreach { v => + bb.replaceInstruction(i, DROP(REFERENCE(cls)) :: valueToInstruction(v) :: Nil) + debuglog(s"replaced $i with $v") } } @@ -157,14 +154,14 @@ abstract class ClosureElimination extends SubComponent { value match { case Boxed(LocalVar(loc2)) => bb.replaceInstruction(i, DROP(icodes.ObjectReference) :: valueToInstruction(info.getBinding(loc2)) :: Nil) - log("replaced " + i + " with " + info.getBinding(loc2)) + debuglog("replaced " + i + " with " + info.getBinding(loc2)) case _ => () } case Boxed(LocalVar(loc1)) :: _ => val loc2 = info.getAlias(loc1) bb.replaceInstruction(i, DROP(icodes.ObjectReference) :: valueToInstruction(Deref(LocalVar(loc2))) :: Nil) - log("replaced " + i + " with " + LocalVar(loc2)) + debuglog("replaced " + i + " with " + LocalVar(loc2)) case _ => } diff --git a/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala b/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala index fd949576e1..36a5d61cfb 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala @@ -44,6 +44,7 @@ abstract class DeadCodeElimination extends SubComponent { class DeadCode { def analyzeClass(cls: IClass) { + log(s"Analyzing ${cls.methods.size} methods in $cls.") cls.methods.foreach { m => this.method = m dieCodeDie(m) @@ -73,7 +74,7 @@ abstract class DeadCodeElimination extends SubComponent { def dieCodeDie(m: IMethod) { if (m.hasCode) { - log("dead code elimination on " + m); + debuglog("dead code elimination on " + m); dropOf.clear() m.code.blocks.clear() accessedLocals = m.params.reverse @@ -82,8 +83,10 @@ abstract class DeadCodeElimination extends SubComponent { mark sweep(m) accessedLocals = accessedLocals.distinct - if ((m.locals diff accessedLocals).nonEmpty) { - log("Removed dead locals: " + (m.locals diff accessedLocals)) + val diff = m.locals diff accessedLocals + if (diff.nonEmpty) { + val msg = diff.map(_.sym.name)mkString(", ") + log(s"Removed ${diff.size} dead locals: $msg") m.locals = accessedLocals.reverse } } @@ -126,7 +129,7 @@ abstract class DeadCodeElimination extends SubComponent { case RETURN(_) | JUMP(_) | CJUMP(_, _, _, _) | CZJUMP(_, _, _, _) | STORE_FIELD(_, _) | THROW(_) | LOAD_ARRAY_ITEM(_) | STORE_ARRAY_ITEM(_) | SCOPE_ENTER(_) | SCOPE_EXIT(_) | STORE_THIS(_) | LOAD_EXCEPTION(_) | SWITCH(_, _) | MONITOR_ENTER() | MONITOR_EXIT() => worklist += ((bb, idx)) - case CALL_METHOD(m1, _) if isSideEffecting(m1) => worklist += ((bb, idx)); log("marking " + m1) + case CALL_METHOD(m1, _) if isSideEffecting(m1) => worklist += ((bb, idx)); debuglog("marking " + m1) case CALL_METHOD(m1, SuperCall(_)) => worklist += ((bb, idx)) // super calls to constructor case DROP(_) => @@ -173,7 +176,7 @@ abstract class DeadCodeElimination extends SubComponent { instr match { case LOAD_LOCAL(l1) => for ((l2, bb1, idx1) <- defs((bb, idx)) if l1 == l2; if !useful(bb1)(idx1)) { - log("\tAdding " + bb1(idx1)) + debuglog("\tAdding " + bb1(idx1)) worklist += ((bb1, idx1)) } @@ -197,7 +200,7 @@ abstract class DeadCodeElimination extends SubComponent { case _ => for ((bb1, idx1) <- rdef.findDefs(bb, idx, instr.consumed) if !useful(bb1)(idx1)) { - log("\tAdding " + bb1(idx1)) + debuglog("\tAdding " + bb1(idx1)) worklist += ((bb1, idx1)) } } @@ -232,7 +235,7 @@ abstract class DeadCodeElimination extends SubComponent { } else { i match { case NEW(REFERENCE(sym)) => - log("skipped object creation: " + sym + "inside " + m) + log(s"Eliminated instantation of $sym inside $m") case _ => () } debuglog("Skipped: bb_" + bb + ": " + idx + "( " + i + ")") @@ -240,7 +243,7 @@ abstract class DeadCodeElimination extends SubComponent { } if (bb.nonEmpty) bb.close - else log("empty block encountered") + else log(s"empty block encountered in $m") } } @@ -252,7 +255,7 @@ abstract class DeadCodeElimination extends SubComponent { foreachWithIndex(bb.toList) { (i, idx) => if (!useful(bb)(idx)) { foreachWithIndex(i.consumedTypes.reverse) { (consumedType, depth) => - log("Finding definitions of: " + i + "\n\t" + consumedType + " at depth: " + depth) + debuglog("Finding definitions of: " + i + "\n\t" + consumedType + " at depth: " + depth) val defs = rdef.findDefs(bb, idx, 1, depth) for (d <- defs) { val (bb, idx) = d diff --git a/src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala b/src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala index f1f597322e..98120f0614 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala @@ -93,10 +93,9 @@ abstract class InlineExceptionHandlers extends SubComponent { val startTime = System.currentTimeMillis currentClass = c - log("Starting " + c) + debuglog("Starting InlineExceptionHandlers on " + c) c.methods foreach applyMethod - - log("Finished " + c + "... " + (System.currentTimeMillis - startTime) + "ms") + debuglog("Finished InlineExceptionHandlers on " + c + "... " + (System.currentTimeMillis - startTime) + "ms") currentClass = null } diff --git a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala index 5464b6fc3b..62bb23c3a7 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala @@ -44,7 +44,7 @@ abstract class Inliners extends SubComponent { import definitions.{ NullClass, NothingClass, ObjectClass, PredefModule, RuntimePackage, ScalaInlineClass, ScalaNoInlineClass, - isFunctionType + isFunctionType, isByNameParamType } val phaseName = "inliner" @@ -143,7 +143,6 @@ abstract class Inliners extends SubComponent { } def isBottomType(sym: Symbol) = sym == NullClass || sym == NothingClass - def posToStr(pos: scala.reflect.internal.util.Position) = if (pos.isDefined) pos.point.toString else "<nopos>" /** Is the given class a closure? */ def isClosureClass(cls: Symbol): Boolean = @@ -194,6 +193,27 @@ abstract class Inliners extends SubComponent { private var currentIClazz: IClass = _ private def warn(pos: Position, msg: String) = currentIClazz.cunit.inlinerWarning(pos, msg) + private def ownedName(sym: Symbol): String = afterUncurry { + val count = ( + if (!sym.isMethod) 1 + else if (sym.owner.isAnonymousFunction) 3 + else 2 + ) + (sym.ownerChain take count filterNot (_.isPackageClass)).reverseMap(_.nameString).mkString(".") + } + private def inlineLog(what: String, main: => String, comment: => String) { + def cstr = comment match { + case "" => "" + case str => " // " + str + } + val width = if (currentIClazz eq null) 40 else currentIClazz.symbol.enclosingPackage.fullName.length + 25 + val fmt = "%8s %-" + width + "s" + cstr + log(fmt.format(what, main)) + } + private def inlineLog(what: String, main: Symbol, comment: => String) { + inlineLog(what, ownedName(main), comment) + } + val recentTFAs = mutable.Map.empty[Symbol, Tuple2[Boolean, analysis.MethodTFA]] private def getRecentTFA(incm: IMethod, forceable: Boolean): (Boolean, analysis.MethodTFA) = { @@ -244,14 +264,15 @@ abstract class Inliners extends SubComponent { def analyzeClass(cls: IClass): Unit = if (settings.inline.value) { - debuglog("Analyzing " + cls) + inlineLog("class", s"${cls.symbol.decodedName}", s"analyzing ${cls.methods.size} methods in $cls") this.currentIClazz = cls val ms = cls.methods sorted imethodOrdering ms foreach { im => - if(hasInline(im.symbol)) { - log("Not inlining into " + im.symbol.originalName.decode + " because it is marked @inline.") - } else if(im.hasCode && !im.symbol.isBridge) { + if (hasInline(im.symbol)) { + inlineLog("skip", im.symbol, "no inlining into @inline methods") + } + else if(im.hasCode && !im.symbol.isBridge) { analyzeMethod(im) } } @@ -296,6 +317,8 @@ abstract class Inliners extends SubComponent { * */ def analyzeMethod(m: IMethod): Unit = { // m.normalize + if (settings.debug.value) + inlineLog("caller", ownedName(m.symbol), "in " + m.symbol.owner.fullName) var sizeBeforeInlining = m.code.blockCount var instrBeforeInlining = m.code.instructionCount @@ -306,8 +329,8 @@ abstract class Inliners extends SubComponent { 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) + def analyzeMessage = s"Analyzing ${caller.length} blocks of $m for inlining sites." def preInline(isFirstRound: Boolean): Int = { val inputBlocks = caller.m.linearizedBlocks() @@ -354,15 +377,17 @@ abstract class Inliners extends SubComponent { */ def analyzeInc(i: CALL_METHOD, bb: BasicBlock, receiver: Symbol, stackLength: Int, concreteMethod: Symbol): Boolean = { assert(bb.toList contains i, "Candidate callsite does not belong to BasicBlock.") - - var inlined = false val shouldWarn = hasInline(i.method) - def warnNoInline(reason: String) = { - if (shouldWarn) { - warn(i.pos, "Could not inline required method %s because %s.".format(i.method.originalName.decode, reason)) - } - } + def warnNoInline(reason: String): Boolean = { + def msg = "Could not inline required method %s because %s.".format(i.method.originalName.decode, reason) + if (settings.debug.value) + inlineLog("fail", i.method.fullName, reason) + if (shouldWarn) + warn(i.pos, msg) + + false + } var isAvailable = icodes available concreteMethod.enclClass @@ -378,92 +403,69 @@ abstract class Inliners extends SubComponent { isAvailable = icodes.load(concreteMethod.enclClass) } - def isCandidate = ( - isClosureClass(receiver) - || concreteMethod.isEffectivelyFinal - || receiver.isEffectivelyFinal - ) + def isCandidate = ( + isClosureClass(receiver) + || concreteMethod.isEffectivelyFinal + || receiver.isEffectivelyFinal + ) - def isApply = concreteMethod.name == nme.apply + def isApply = concreteMethod.name == nme.apply - def isCountable = !( - isClosureClass(receiver) - || isApply - || isMonadicMethod(concreteMethod) - || receiver.enclosingPackage == definitions.RuntimePackage - ) // only count non-closures + def isCountable = !( + isClosureClass(receiver) + || isApply + || isMonadicMethod(concreteMethod) + || receiver.enclosingPackage == definitions.RuntimePackage + ) // only count non-closures debuglog("Treating " + i + "\n\treceiver: " + receiver + "\n\ticodes.available: " + isAvailable + "\n\tconcreteMethod.isEffectivelyFinal: " + concreteMethod.isEffectivelyFinal) - if (isAvailable && isCandidate) { - lookupIMethod(concreteMethod, receiver) match { - - case Some(callee) if callee.hasCode => - val inc = new IMethodInfo(callee) - val pair = new CallerCalleeInfo(caller, inc, fresh, inlinedMethodCount) - - if(inc.hasHandlers && (stackLength == -1)) { - // no inlining is done, yet don't warn about it, stackLength == -1 indicates we're trying to inlineWithoutTFA. - // Shortly, a TFA will be computed and an error message reported if indeed inlining not possible. - return false - } - - (pair isStampedForInlining stackLength) match { - - case inlInfo if inlInfo.isSafe => - - (inlInfo: @unchecked) match { - - case FeasibleInline(accessNeeded, toBecomePublic) => - for(f <- toBecomePublic) { - debuglog("Making public (synthetic) field-symbol: " + f) - f setFlag Flags.notPRIVATE - f setFlag Flags.notPROTECTED - } - // only add to `knownSafe` after all `toBecomePublic` fields actually made public. - if(accessNeeded == NonPublicRefs.Public) { tfa.knownSafe += inc.sym } - - case InlineableAtThisCaller => () - - } - - retry = true - inlined = true - if (isCountable) { count += 1 }; + if (!isCandidate) warnNoInline("it can be overridden") + else if (!isAvailable) warnNoInline("bytecode unavailable") + else lookupIMethod(concreteMethod, receiver) filter (callee => callee.hasCode || warnNoInline("callee has no code")) exists { callee => + val inc = new IMethodInfo(callee) + val pair = new CallerCalleeInfo(caller, inc, fresh, inlinedMethodCount) - pair.doInline(bb, i) - if (!pair.isInlineForced || inc.isMonadic) { caller.inlinedCalls += 1 }; - inlinedMethodCount(inc.sym) += 1 - - // Remove the caller from the cache (this inlining might have changed its calls-private relation). - usesNonPublics -= m - recentTFAs -= m.symbol - - - case DontInlineHere(msg) => - debuglog("inline failed, reason: " + msg) - warnNoInline(msg) - - case NeverSafeToInline => () - } - - case Some(callee) => - assert(!callee.hasCode, "The case clause right before this one should have handled this case.") - warnNoInline("callee (" + callee + ") has no code") - () + if (inc.hasHandlers && (stackLength == -1)) { + // no inlining is done, yet don't warn about it, stackLength == -1 indicates we're trying to inlineWithoutTFA. + // Shortly, a TFA will be computed and an error message reported if indeed inlining not possible. + false + } + else { + val isSafe = pair isStampedForInlining stackLength match { + case DontInlineHere(msg) => warnNoInline(msg) + case NeverSafeToInline => false + case InlineableAtThisCaller => true + case inl @ FeasibleInline(_, _) if !inl.isSafe => false + case FeasibleInline(required, toPublicize) => + for (f <- toPublicize) { + inlineLog("access", f, "making public") + f setFlag Flags.notPRIVATE + f setFlag Flags.notPROTECTED + } + // only add to `knownSafe` after all `toPublicize` fields actually made public. + if (required == NonPublicRefs.Public) + tfa.knownSafe += inc.sym - case None => - warnNoInline("bytecode was not available") - debuglog("could not find icode\n\treceiver: " + receiver + "\n\tmethod: " + concreteMethod) + true + } + isSafe && { + retry = true + if (isCountable) count += 1 + pair.doInline(bb, i) + if (!pair.isInlineForced || inc.isMonadic) caller.inlinedCalls += 1 + inlinedMethodCount(inc.sym) += 1 + + // Remove the caller from the cache (this inlining might have changed its calls-private relation). + usesNonPublics -= m + recentTFAs -= m.symbol + true + } } - } else { - warnNoInline(if(!isAvailable) "bytecode was not available" else "it can be overridden") } - - inlined } /* Pre-inlining consists in invoking the usual inlining subroutine with (receiver class, concrete method) pairs as input @@ -485,7 +487,7 @@ abstract class Inliners extends SubComponent { do { retry = false - log("Analyzing " + m + " count " + count + " with " + caller.length + " blocks") + debuglog(analyzeMessage) /* it's important not to inline in unreachable basic blocks. linearizedBlocks() returns only reachable ones. */ tfa.callerLin = caller.m.linearizedBlocks() @@ -567,9 +569,16 @@ abstract class Inliners extends SubComponent { m.normalize if (sizeBeforeInlining > 0) { val instrAfterInlining = m.code.instructionCount - val prefix = if ((instrAfterInlining > 2 * instrBeforeInlining) && (instrAfterInlining > 200)) " !! " else "" - log(prefix + " %s blocks before inlining: %d (%d) after: %d (%d)".format( - m.symbol.fullName, sizeBeforeInlining, instrBeforeInlining, m.code.blockCount, instrAfterInlining)) + val prefix = if ((instrAfterInlining > 2 * instrBeforeInlining) && (instrAfterInlining > 200)) "!!" else "" + val inlinings = caller.inlinedCalls + if (inlinings > 0) { + val s1 = s"instructions $instrBeforeInlining -> $instrAfterInlining" + val s2 = if (sizeBeforeInlining == m.code.blockCount) "" else s", blocks $sizeBeforeInlining -> ${m.code.blockCount}" + val callees = inlinedMethodCount.toList map { case (k, v) => k.fullNameString + ( if (v == 1) "" else "/" + v ) } + + inlineLog("inlined", m.symbol.fullName, callees.sorted.mkString(inlinings + " inlined: ", ", ", "")) + inlineLog("<<tldr>>", m.symbol.fullName, s"${m.symbol.nameString}: $s1$s2") + } } } @@ -589,6 +598,8 @@ abstract class Inliners extends SubComponent { } class IMethodInfo(val m: IMethod) { + override def toString = m.toString + val sym = m.symbol val name = sym.name def owner = sym.owner @@ -608,10 +619,11 @@ abstract class Inliners extends SubComponent { def instructions = m.code.instructions // def linearized = linearizer linearize m - def isSmall = (length <= SMALL_METHOD_SIZE) && blocks(0).length < 10 - def isLarge = length > MAX_INLINE_SIZE - def isRecursive = m.recursive - def hasHandlers = handlers.nonEmpty || m.bytecodeHasEHs + def isSmall = (length <= SMALL_METHOD_SIZE) && blocks(0).length < 10 + def isLarge = length > MAX_INLINE_SIZE + def isRecursive = m.recursive + def hasHandlers = handlers.nonEmpty || m.bytecodeHasEHs + def hasClosureParam = paramTypes exists (tp => isByNameParamType(tp) || isFunctionType(tp)) def isSynchronized = sym.hasFlag(Flags.SYNCHRONIZED) def hasNonFinalizerHandler = handlers exists { @@ -661,9 +673,9 @@ abstract class Inliners extends SubComponent { * * TODO handle more robustly the case of a trait var changed at the source-level from public to private[this] * (eg by having ICodeReader use unpickler, see SI-5442). - + DISABLED - + def potentiallyPublicized(f: Symbol): Boolean = { (m.sourceFile eq NoSourceFile) && f.name.containsChar('$') } @@ -687,7 +699,7 @@ abstract class Inliners extends SubComponent { val i = iter.next() getAccess(i) match { case Private => - log("instruction " + i + " requires private access.") + inlineLog("access", s"instruction $i requires private access", "pos=" + i.pos) toBecomePublic = Nil seen = Private case Protected => seen = Protected @@ -764,11 +776,10 @@ abstract class Inliners extends SubComponent { tfa.warnIfInlineFails.remove(instr) val targetPos = instr.pos - log("Inlining " + inc.m + " in " + caller.m + " at pos: " + posToStr(targetPos)) def blockEmit(i: Instruction) = block.emit(i, targetPos) def newLocal(baseName: String, kind: TypeKind) = - new Local(caller.sym.newVariable(freshName(baseName), targetPos), kind, false) + new Local(caller.sym.newVariable(freshName(baseName), targetPos) setInfo kind.toType, kind, false) val (hasRETURN, a) = getRecentTFA(inc.m, isInlineForced) @@ -955,6 +966,7 @@ abstract class Inliners extends SubComponent { if(reasonWhyNever != null) { tfa.knownNever += inc.sym + inlineLog("never", inc.sym, reasonWhyNever) // next time around NeverSafeToInline is returned, thus skipping (duplicate) msg, this is intended. return DontInlineHere(inc.m + " " + reasonWhyNever) } @@ -977,10 +989,15 @@ abstract class Inliners extends SubComponent { * As a result of (b), some synthetic private members can be chosen to become public. */ - if(!isInlineForced && !isScoreOK) { + val score = inlinerScore + val scoreStr = if (score > 0) "+" + score else "" + score + val what = if (score > 0) "ok to" else "don't" + inlineLog(scoreStr, inc.m.symbol, s"$what inline into ${ownedName(caller.m.symbol)}") + + if (!isInlineForced && score <= 0) { // During inlining retry, a previous caller-callee pair that scored low may pass. // Thus, adding the callee to tfa.knownUnsafe isn't warranted. - return DontInlineHere("too low score (heuristics)") + return DontInlineHere(s"inliner heuristic") } if(inc.hasHandlers && (stackLength > inc.minimumStack)) { @@ -999,7 +1016,9 @@ abstract class Inliners extends SubComponent { val accReq = inc.accessRequirements if(!canAccess(accReq.accessNeeded)) { tfa.knownUnsafe += inc.sym - return DontInlineHere("access level required by callee not matched by caller") + val msg = "access level required by callee not matched by caller" + inlineLog("fail", inc.sym, msg) + return DontInlineHere(msg) } FeasibleInline(accReq.accessNeeded, accReq.toBecomePublic) @@ -1021,9 +1040,7 @@ abstract class Inliners extends SubComponent { * - it's good to inline closures functions. * - it's bad (useless) to inline inside bridge methods */ - def isScoreOK: Boolean = { - debuglog("shouldInline: " + caller.m + " , callee:" + inc.m) - + def inlinerScore: Int = { var score = 0 // better not inline inside closures, but hope that the closure itself is repeatedly inlined @@ -1031,21 +1048,19 @@ abstract class Inliners extends SubComponent { else if (caller.inlinedCalls < 1) score -= 1 // only monadic methods can trigger the first inline if (inc.isSmall) score += 1; + // if (inc.hasClosureParam) score += 2 if (inc.isLarge) score -= 1; if (caller.isSmall && isLargeSum) { score -= 1 - debuglog("shouldInline: score decreased to " + score + " because small " + caller + " would become large") + debuglog(s"inliner score decreased to $score because small caller $caller would become large") } 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) - - score > 0 + if (inc.isInClosure) score += 2 + if (inlinedMethodCount(inc.sym) > 2) score -= 2 + score } } diff --git a/src/compiler/scala/tools/nsc/interpreter/IMain.scala b/src/compiler/scala/tools/nsc/interpreter/IMain.scala index 96d7dadbd7..a2df1494ef 100644 --- a/src/compiler/scala/tools/nsc/interpreter/IMain.scala +++ b/src/compiler/scala/tools/nsc/interpreter/IMain.scala @@ -387,8 +387,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends newSym <- req.definedSymbols get name oldSym <- oldReq.definedSymbols get name.companionName } { - replwarn("warning: previously defined %s is not a companion to %s.".format( - stripString("" + oldSym), stripString("" + newSym))) + afterTyper(replwarn(s"warning: previously defined $oldSym is not a companion to $newSym.")) replwarn("Companions must be defined together; you may wish to use :paste mode for this.") } diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala index 437a5e1434..175c322786 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala @@ -37,7 +37,7 @@ abstract class ICodeReader extends ClassfileParser { cls.info // ensure accurate type information isScalaModule = cls.isModule && !cls.isJavaDefined - log("Reading class: " + cls + " isScalaModule?: " + isScalaModule) + log("ICodeReader reading " + cls) val name = cls.javaClassName classPath.findSourceFile(name) match { @@ -99,11 +99,9 @@ abstract class ICodeReader extends ClassfileParser { if (sym == NoSymbol) sym = owner.info.findMember(newTermName(name + nme.LOCAL_SUFFIX_STRING), 0, 0, false).suchThat(_.tpe =:= tpe) if (sym == NoSymbol) { - log("Could not find symbol for " + name + ": " + tpe) - log(owner.info.member(name).tpe + " : " + tpe) sym = if (field) owner.newValue(name, owner.pos, toScalaFieldFlags(jflags)) else dummySym sym setInfoAndEnter tpe - log("added " + sym + ": " + sym.tpe) + log(s"ICodeReader could not locate ${name.decode} in $owner. Created ${sym.defString}.") } (jflags, sym) } @@ -172,10 +170,7 @@ abstract class ICodeReader extends ClassfileParser { } else if (nme.isModuleName(name)) { val strippedName = nme.stripModuleSuffix(name) - val sym = forceMangledName(newTermName(strippedName.decode), true) - - if (sym == NoSymbol) rootMirror.getModule(strippedName) - else sym + forceMangledName(newTermName(strippedName.decode), true) orElse rootMirror.getModule(strippedName) } else { forceMangledName(name, false) @@ -956,7 +951,7 @@ abstract class ICodeReader extends ClassfileParser { case None => checkValidIndex val l = freshLocal(idx, kind, false) - log("Added new local for idx " + idx + ": " + kind) + debuglog("Added new local for idx " + idx + ": " + kind) locals += (idx -> List((l, kind))) l } diff --git a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala index a8cdee7154..4a668d4c61 100644 --- a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala +++ b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala @@ -79,12 +79,11 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure => // -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 " + implSym) iface.owner.info.decls unlink implSym NoSymbol } else { - log("not unlinking existing " + implSym + " as the impl class is not visible on the classpath.") + log(s"not unlinking $iface's existing implClass ${implSym.name} because it is not on the classpath.") implSym } } @@ -113,9 +112,10 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure => iface.info implClassMap.getOrElse(iface, atPhase(implClassPhase) { - log("Creating implClass for " + iface) - if (iface.implClass ne NoSymbol) - log("%s.implClass already exists: %s".format(iface, iface.implClass)) + if (iface.implClass eq NoSymbol) + debuglog(s"${iface.fullLocationString} has no implClass yet, creating it now.") + else + log(s"${iface.fullLocationString} impl class is ${iface.implClass.nameString}") newImplClass(iface) }) @@ -137,7 +137,7 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure => * given the decls ifaceDecls of its interface. */ private def implDecls(implClass: Symbol, ifaceDecls: Scope): Scope = { - log("LazyImplClassType calculating decls for " + implClass) + debuglog("LazyImplClassType calculating decls for " + implClass) val decls = newScope if ((ifaceDecls lookup nme.MIXIN_CONSTRUCTOR) == NoSymbol) { @@ -152,16 +152,16 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure => for (sym <- ifaceDecls) { if (isInterfaceMember(sym)) { if (needsImplMethod(sym)) { - log("Cloning " + sym + " for implementation method in " + implClass) val clone = sym.cloneSymbol(implClass).resetFlag(lateDEFERRED) if (currentRun.compiles(implClass)) implMethodMap(sym) = clone decls enter clone sym setFlag lateDEFERRED + if (!sym.isSpecialized) + log(s"Cloned ${sym.name} from ${sym.owner} into implClass ${implClass.fullName}") } - else log(sym + " needs no implementation method in " + implClass) } else { - log("Destructively modifying owner of %s from %s to %s".format(sym, sym.owner, implClass)) + log(s"Destructively modifying owner of $sym from ${sym.owner} to $implClass") sym.owner = implClass // note: OK to destructively modify the owner here, // because symbol will not be accessible from outside the sourcefile. @@ -174,7 +174,7 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure => } override def complete(implSym: Symbol) { - log("LazyImplClassType completing " + implSym) + debuglog("LazyImplClassType completing " + implSym) /** If `tp` refers to a non-interface trait, return a * reference to its implementation class. Otherwise return `tp`. diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 4b0a6ab44a..ae1a2c7e8e 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -490,7 +490,7 @@ abstract class Erasure extends AddInterfaces @inline private def box(tree: Tree, target: => String): Tree = { val result = box1(tree) - log("boxing "+tree+":"+tree.tpe+" to "+target+" = "+result+":"+result.tpe) + log(s"boxing ${tree.summaryString}: ${tree.tpe} into $target: ${result.tpe}") result } @@ -525,7 +525,7 @@ abstract class Erasure extends AddInterfaces * fields (see TupleX). (ID) */ case Apply(boxFun, List(arg)) if isUnbox(tree.symbol) && safeToRemoveUnbox(arg.tpe.typeSymbol) => - log("boxing an unbox: " + tree + "/" + tree.symbol + " and replying with " + arg + " of type " + arg.tpe) + log(s"boxing an unbox: ${tree.symbol} -> ${arg.tpe}") arg case _ => (REF(boxMethod(x)) APPLY tree) setPos (tree.pos) setType ObjectClass.tpe @@ -537,7 +537,7 @@ abstract class Erasure extends AddInterfaces private def unbox(tree: Tree, pt: Type): Tree = { val result = unbox1(tree, pt) - log("unboxing "+tree+":"+tree.tpe+" to "+pt+" = "+result+":"+result.tpe) + log(s"unboxing ${tree.summaryString}: ${tree.tpe} with pt=$pt as type ${result.tpe}") result } @@ -614,7 +614,7 @@ abstract class Erasure extends AddInterfaces * @return the adapted tree */ private def adaptToType(tree: Tree, pt: Type): Tree = { - //if (settings.debug.value && pt != WildcardType) + if (settings.debug.value && pt != WildcardType) log("adapting " + tree + ":" + tree.tpe + " : " + tree.tpe.parents + " to " + pt)//debug if (tree.tpe <:< pt) tree diff --git a/src/compiler/scala/tools/nsc/transform/Flatten.scala b/src/compiler/scala/tools/nsc/transform/Flatten.scala index 94eaba67d7..3bbf429fc2 100644 --- a/src/compiler/scala/tools/nsc/transform/Flatten.scala +++ b/src/compiler/scala/tools/nsc/transform/Flatten.scala @@ -22,12 +22,14 @@ abstract class Flatten extends InfoTransform { */ private def replaceSymbolInCurrentScope(sym: Symbol): Symbol = afterFlatten { val scope = sym.owner.info.decls - val old = scope lookup sym.name - if (old ne NoSymbol) - scope unlink old - + val old = scope lookup sym.name andAlso scope.unlink scope enter sym - log("lifted " + sym.fullLocationString) + + if (old eq NoSymbol) + log(s"lifted ${sym.fullLocationString}") + else + log(s"lifted ${sym.fullLocationString} after unlinking existing $old from scope.") + old } @@ -35,9 +37,7 @@ abstract class Flatten extends InfoTransform { if (!sym.isLifted) { sym setFlag LIFTED debuglog("re-enter " + sym.fullLocationString) - val old = replaceSymbolInCurrentScope(sym) - if (old ne NoSymbol) - log("unlinked " + old.fullLocationString + " after lifting " + sym) + replaceSymbolInCurrentScope(sym) } } private def liftSymbol(sym: Symbol) { diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala index fc9e611d20..5097ecc3fe 100644 --- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala +++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala @@ -436,7 +436,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { val sClassMap = anyrefSpecCache.getOrElseUpdate(sClass, mutable.Map[Symbol, Symbol]()) sClassMap.getOrElseUpdate(tparam, - tparam.cloneSymbol(sClass, tparam.flags, (tparam.name append tpnme.SPECIALIZED_SUFFIX).asInstanceOf[Name]) // [Eugene] why do we need this cast? + tparam.cloneSymbol(sClass, tparam.flags, tparam.name append tpnme.SPECIALIZED_SUFFIX) modifyInfo (info => TypeBounds(info.bounds.lo, AnyRefClass.tpe)) ).tpe } @@ -811,12 +811,17 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { specializingOn = specializingOn filterNot (unusedStvars contains) } for (env0 <- specializations(specializingOn) if needsSpecialization(env0, sym)) yield { + // !!! Can't this logic be structured so that the new symbol's name is + // known when the symbol is cloned? It is much cleaner not to be mutating + // names after the fact. And it adds about a billion lines of + // "Renaming value _1 in class Tuple2 to _1$mcZ$sp" to obscure the small + // number of other (important) actual symbol renamings. val tps = survivingParams(sym.info.typeParams, env0) - val specMember = sym.cloneSymbol(owner, (sym.flags | SPECIALIZED) & ~DEFERRED) + val specMember = sym.cloneSymbol(owner, (sym.flags | SPECIALIZED) & ~DEFERRED) // <-- this needs newName = ... val env = mapAnyRefsInSpecSym(env0, sym, specMember) val (keys, vals) = env.toList.unzip - specMember setName specializedName(sym, env) + specMember setName specializedName(sym, env) // <-- but the name is calculated based on the cloned symbol // debuglog("%s normalizes to %s%s".format(sym, specMember, // if (tps.isEmpty) "" else " with params " + tps.mkString(", "))) @@ -897,7 +902,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { private def specializedOverload(owner: Symbol, sym: Symbol, env: TypeEnv): Symbol = { val newFlags = (sym.flags | SPECIALIZED) & ~(DEFERRED | CASEACCESSOR) // this method properly duplicates the symbol's info - ( sym.cloneSymbol(owner, newFlags, specializedName(sym, env)) + ( sym.cloneSymbol(owner, newFlags, newName = specializedName(sym, env)) modifyInfo (info => subst(env, info.asSeenFrom(owner.thisType, sym.owner))) ) } @@ -912,7 +917,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { * * this method will return List('apply$mcII$sp') */ - private def specialOverrides(clazz: Symbol) = logResultIf[List[Symbol]]("specialOverrides(" + clazz + ")", _.nonEmpty) { + private def specialOverrides(clazz: Symbol) = logResultIf[List[Symbol]]("specialized overrides in " + clazz, _.nonEmpty) { /** Return the overridden symbol in syms that needs a specialized overriding symbol, * together with its specialization environment. The overridden symbol may not be * the closest to 'overriding', in a given hierarchy. diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index 181463657b..5bff653499 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -484,11 +484,7 @@ abstract class UnCurry extends InfoTransform arg setType functionType(Nil, arg.tpe) } else { - log("byname | %s | %s | %s".format( - arg.pos.source.path + ":" + arg.pos.line, fun.fullName, - if (fun.isPrivate) "private" else "") - ) - + log(s"Argument '$arg' at line ${arg.pos.safeLine} is $formal from ${fun.fullName}") arg match { // don't add a thunk for by-name argument if argument already is an application of // a Function0. We can then remove the application and use the existing Function0. diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala index d227f485c2..67afb0c118 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala @@ -63,7 +63,7 @@ trait SyntheticMethods extends ast.TreeDSL { // in the original order. def accessors = clazz.caseFieldAccessors sortBy { acc => originalAccessors indexWhere { orig => - (acc.name == orig.name) || (acc.name startsWith (orig.name append "$").asInstanceOf[Name]) // [Eugene] why do we need this cast? + (acc.name == orig.name) || (acc.name startsWith (orig.name append "$")) } } val arity = accessors.size @@ -87,7 +87,7 @@ trait SyntheticMethods extends ast.TreeDSL { ) def forwardToRuntime(method: Symbol): Tree = - forwardMethod(method, getMember(ScalaRunTimeModule, (method.name prepend "_").asInstanceOf[Name]))(mkThis :: _) // [Eugene] why do we need this cast? + forwardMethod(method, getMember(ScalaRunTimeModule, (method.name prepend "_")))(mkThis :: _) def callStaticsMethod(name: String)(args: Tree*): Tree = { val method = termMember(RuntimeStaticsModule, name) diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index d48f5a4145..d90141b732 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1877,7 +1877,7 @@ trait Typers extends Modes with Adaptations with Tags { * @param rhs ... */ def computeParamAliases(clazz: Symbol, vparamss: List[List[ValDef]], rhs: Tree) { - log("computing param aliases for "+clazz+":"+clazz.primaryConstructor.tpe+":"+rhs)//debug + debuglog(s"computing param aliases for $clazz:${clazz.primaryConstructor.tpe}:$rhs") def decompose(call: Tree): (Tree, List[Tree]) = call match { case Apply(fn, args) => val (superConstr, args1) = decompose(fn) @@ -3444,7 +3444,7 @@ trait Typers extends Modes with Adaptations with Tags { } if (hasError) annotationError - else AnnotationInfo(annType, List(), nvPairs map {p => (p._1.asInstanceOf[Name], p._2.get)}).setOriginal(Apply(typedFun, args).setPos(ann.pos)) // [Eugene] why do we need this cast? + else AnnotationInfo(annType, List(), nvPairs map {p => (p._1, p._2.get)}).setOriginal(Apply(typedFun, args).setPos(ann.pos)) } } else if (requireJava) { reportAnnotationError(NestedAnnotationError(ann, annType)) diff --git a/src/reflect/scala/reflect/internal/Names.scala b/src/reflect/scala/reflect/internal/Names.scala index 2fdf27d847..3f85db0f54 100644 --- a/src/reflect/scala/reflect/internal/Names.scala +++ b/src/reflect/scala/reflect/internal/Names.scala @@ -149,11 +149,15 @@ trait Names extends api.Names with LowPriorityNames { type ThisNameType >: Null <: Name protected[this] def thisName: ThisNameType + // Note that "Name with ThisNameType" should be redundant + // because ThisNameType <: Name, but due to SI-6161 the + // compile loses track of this fact. + /** Index into name table */ def start: Int = index /** The next name in the same hash bucket. */ - def next: ThisNameType + def next: Name with ThisNameType /** The length of this name. */ final def length: Int = len @@ -169,13 +173,13 @@ trait Names extends api.Names with LowPriorityNames { def bothNames: List[Name] = List(toTermName, toTypeName) /** Return the subname with characters from from to to-1. */ - def subName(from: Int, to: Int): ThisNameType + def subName(from: Int, to: Int): Name with ThisNameType /** Return a new name of the same variety. */ - def newName(str: String): ThisNameType + def newName(str: String): Name with ThisNameType /** Return a new name based on string transformation. */ - def mapName(f: String => String): ThisNameType = newName(f(toString)) + def mapName(f: String => String): Name with ThisNameType = newName(f(toString)) /** Copy bytes of this name to buffer cs, starting at position `offset`. */ final def copyChars(cs: Array[Char], offset: Int) = diff --git a/src/reflect/scala/reflect/internal/SymbolTable.scala b/src/reflect/scala/reflect/internal/SymbolTable.scala index 4100e97cdd..2424e75949 100644 --- a/src/reflect/scala/reflect/internal/SymbolTable.scala +++ b/src/reflect/scala/reflect/internal/SymbolTable.scala @@ -47,6 +47,8 @@ abstract class SymbolTable extends macros.Universe def globalError(msg: String): Unit = abort(msg) def abort(msg: String): Nothing = throw new FatalError(supplementErrorMessage(msg)) + def shouldLogAtThisPhase = false + @deprecated("Give us a reason", "2.10.0") def abort(): Nothing = abort("unknown error") diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index a1c774c545..b1e81de037 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -114,7 +114,12 @@ trait Symbols extends api.Symbols { self: SymbolTable => // with the proper specific type. def rawname: NameType def name: NameType - def name_=(n: Name): Unit + def name_=(n: Name): Unit = { + if (shouldLogAtThisPhase) { + val msg = s"Renaming $fullLocationString to $n" + if (isSpecialized) debuglog(msg) else log(msg) + } + } def asNameType(n: Name): NameType private[this] var _rawowner = initOwner // Syncnote: need not be protected, as only assignment happens in owner_=, which is not exposed to api @@ -966,7 +971,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => /** If this symbol has an expanded name, its original name, otherwise its name itself. * @see expandName */ - def originalName: Name = nme.originalName(name) + def originalName: Name = nme.originalName(nme.dropLocalSuffix(name)) /** The name of the symbol before decoding, e.g. `\$eq\$eq` instead of `==`. */ @@ -1011,7 +1016,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => private def fullNameInternal(separator: Char): Name = ( if (isRoot || isRootPackage || this == NoSymbol) name else if (owner.isEffectiveRoot) name - else effectiveOwner.enclClass.fullNameAsName(separator) append separator append name + else ((effectiveOwner.enclClass.fullNameAsName(separator) append separator): Name) append name ) def fullNameAsName(separator: Char): Name = nme.dropLocalSuffix(fullNameInternal(separator)) @@ -2199,10 +2204,10 @@ trait Symbols extends api.Symbols { self: SymbolTable => * If settings.Yshowsymkinds, adds abbreviated symbol kind. */ def nameString: String = ( - if (!settings.uniqid.value && !settings.Yshowsymkinds.value) "" + decodedName - else if (settings.uniqid.value && !settings.Yshowsymkinds.value) decodedName + "#" + id - else if (!settings.uniqid.value && settings.Yshowsymkinds.value) decodedName + "#" + abbreviatedKindString - else decodedName + "#" + id + "#" + abbreviatedKindString + if (!settings.uniqid.value && !settings.Yshowsymkinds.value) "" + originalName.decode + else if (settings.uniqid.value && !settings.Yshowsymkinds.value) originalName.decode + "#" + id + else if (!settings.uniqid.value && settings.Yshowsymkinds.value) originalName.decode + "#" + abbreviatedKindString + else originalName.decode + "#" + id + "#" + abbreviatedKindString ) def fullNameString: String = { @@ -2312,9 +2317,9 @@ trait Symbols extends api.Symbols { self: SymbolTable => if (Statistics.hotEnabled) Statistics.incCounter(nameCount) _rawname } - def name_=(name: Name) { + override def name_=(name: Name) { if (name != rawname) { - log("Renaming %s %s %s to %s".format(shortSymbolClass, debugFlagString, rawname, name)) + super.name_=(name) // logging changeNameInOwners(name) _rawname = name.toTermName } @@ -2615,9 +2620,9 @@ trait Symbols extends api.Symbols { self: SymbolTable => // TODO - don't allow names to be renamed in this unstructured a fashion. // Rename as little as possible. Enforce invariants on all renames. - def name_=(name: Name) { + override def name_=(name: Name) { if (name != rawname) { - log("Renaming %s %s %s to %s".format(shortSymbolClass, debugFlagString, rawname, name)) + super.name_=(name) // logging changeNameInOwners(name) _rawname = name.toTypeName } @@ -3088,7 +3093,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => def asNameType(n: Name) = n.toTermName def rawname = nme.NO_NAME def name = nme.NO_NAME - def name_=(n: Name) = abort("Cannot set NoSymbol's name to " + n) + override def name_=(n: Name) = abort("Cannot set NoSymbol's name to " + n) synchronized { setInfo(NoType) diff --git a/test/files/run/compiler-asSeenFrom.check b/test/files/run/compiler-asSeenFrom.check index 96e257d303..47d40b0331 100644 --- a/test/files/run/compiler-asSeenFrom.check +++ b/test/files/run/compiler-asSeenFrom.check @@ -269,8 +269,8 @@ value jZ { // after parser value jZ { // after explicitouter protected val $outer: D.this.type - val ll$D$J$$$outer(): D.this.type - val ll$C$I$$$outer(): C.this.type + val $outer(): D.this.type + val $outer(): C.this.type def thisI(): I.this.type def thisC(): C.this.type def t2(): T2 @@ -279,9 +279,9 @@ value jZ { // after explicitouter value jZ { // after erasure protected val $outer: ll.D - val ll$D$J$$$outer(): ll.D + val $outer(): ll.D protected val $outer: ll.C - val ll$C$I$$$outer(): ll.C + val $outer(): ll.C def thisI(): ll.C#I def thisC(): ll.C def t2(): Object @@ -290,9 +290,9 @@ value jZ { // after erasure value jZ { // after flatten protected val $outer: ll.D - val ll$D$J$$$outer(): ll.D + val $outer(): ll.D protected val $outer: ll.C - val ll$C$I$$$outer(): ll.C + val $outer(): ll.C def thisI(): ll.C#C$I def thisC(): ll.C def t2(): Object |