diff options
author | Iulian Dragos <jaguarul@gmail.com> | 2009-05-13 15:11:55 +0000 |
---|---|---|
committer | Iulian Dragos <jaguarul@gmail.com> | 2009-05-13 15:11:55 +0000 |
commit | 1b9f19f08560f324aee6632643ec2bd1187dec1a (patch) | |
tree | fec0c59aa0f6ea02035886623b365f2efda4b012 | |
parent | 62d0a710573fa6bf0d7fcac30c9df1a8b843b3d1 (diff) | |
download | scala-1b9f19f08560f324aee6632643ec2bd1187dec1a.tar.gz scala-1b9f19f08560f324aee6632643ec2bd1187dec1a.tar.bz2 scala-1b9f19f08560f324aee6632643ec2bd1187dec1a.zip |
Various improvements to the optimiser: more agg...
Various improvements to the optimiser: more aggresive inlining for monad
methods, bytecode reading in more cases, better copy propagation during
closure elimination.
17 files changed, 179 insertions, 84 deletions
@@ -1636,7 +1636,7 @@ TEST AND DISTRIBUTION BUNDLE (ALL) <target name="all.done" depends="dist.done, test.done"/> - <target name="all.clean" depends="locker.clean, docs.clean, dist.clean"/> + <target name="all.clean" depends="locker.clean, docs.clean, dist.clean, optimised.clean"/> <!-- =========================================================================== STABLE REFERENCE (STARR) diff --git a/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala b/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala index 4ae5df24a4..b57bb2df16 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala @@ -445,7 +445,7 @@ trait BasicBlocks { case _ => false } - override def hashCode = label + override def hashCode = label * 41 + code.hashCode // Instead of it, rather use a printer def print() { print(java.lang.System.out) } diff --git a/src/compiler/scala/tools/nsc/backend/icode/Members.scala b/src/compiler/scala/tools/nsc/backend/icode/Members.scala index 0335c27350..a13c8751db 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Members.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Members.scala @@ -303,6 +303,8 @@ trait Members { self: ICodes => other.asInstanceOf[Local].sym == this.sym ); + override def hashCode = sym.hashCode + override def toString(): String = sym.toString() } } diff --git a/src/compiler/scala/tools/nsc/backend/icode/Printers.scala b/src/compiler/scala/tools/nsc/backend/icode/Printers.scala index 3c12594d2c..f3a1096271 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Printers.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Printers.scala @@ -116,7 +116,9 @@ trait Printers { self: ICodes => def printBlock(bb: BasicBlock) { print(bb.label) if (bb.loopHeader) print("[loop header]") - print(": "); indent; println + print(": "); + if (settings.debug.value) print("pred: " + bb.predecessors + " succs: " + bb.successors) + indent; println bb.toList foreach printInstruction undent; println } @@ -125,7 +127,7 @@ trait Printers { self: ICodes => // if (settings.Xdce.value) // print(if (i.useful) " " else " * "); if (settings.debug.value) - print(i.pos.line.map(_.toString).getOrElse("No line")) + print(i.pos.line.map(_.toString).getOrElse("")) println(i.toString()) } } diff --git a/src/compiler/scala/tools/nsc/backend/icode/Repository.scala b/src/compiler/scala/tools/nsc/backend/icode/Repository.scala index 8b6a08ee1e..379ef80da4 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Repository.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Repository.scala @@ -34,6 +34,7 @@ trait Repository { def icode(sym: Symbol, force: Boolean): IClass = if (available(sym)) icode(sym).get else { + log("loading " + sym) load(sym) assert(available(sym)) loaded(sym) diff --git a/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala b/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala index e9571741f6..ed57ff06e0 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala @@ -44,7 +44,7 @@ trait TypeKinds { self: ICodes => case LONG => definitions.LongClass.tpe case FLOAT => definitions.FloatClass.tpe case DOUBLE => definitions.DoubleClass.tpe - case REFERENCE(cls) => typeRef(cls.typeConstructor.prefix, cls, Nil) + case REFERENCE(cls) => cls.tpe //typeRef(cls.typeConstructor.prefix, cls, Nil) //case VALUE(cls) => typeRef(cls.typeConstructor.prefix, cls, Nil); case ARRAY(elem) => typeRef(definitions.ArrayClass.typeConstructor.prefix, definitions.ArrayClass, 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 49342e7804..8f2b1b9797 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala @@ -121,15 +121,41 @@ abstract class CopyPropagation { * binding of that local. */ def getFieldValue(r: Record, f: Symbol): Option[Value] = { + if(!r.bindings.isDefinedAt(f)) None else { + var target: Value = r.bindings(f) + target match { + case Deref(LocalVar(l)) => Some(getBinding(l)) + case Deref(Field(r1, f1)) => getFieldValue(r1, f1) orElse Some(target) +// case Deref(This) => Some(target) +// case Const(k) => Some(target) + case _ => Some(target) + } + } + } + + /** The same as getFieldValue, but never returns Record/Field values. Use + * this when you want to find a replacement for a field value (either a local, + * or a constant/this value). + */ + def getFieldNonRecordValue(r: Record, f: Symbol): Option[Value] = { assert(r.bindings.isDefinedAt(f), "Record " + r + " does not contain a field " + f); var target: Value = r.bindings(f) target match { - case Deref(LocalVar(l)) => Some(Deref(LocalVar(getAlias(l)))) - case Deref(This) => Some(target) - case Const(k) => Some(target) - case _ => None + case Deref(LocalVar(l)) => + val alias = getAlias(l) + getBinding(alias) match { + case Record(_, _) => Some(Deref(LocalVar(alias))) + case Deref(Field(r1, f1)) => + getFieldNonRecordValue(r1, f1) orElse Some(Deref(LocalVar(alias))) + case v => Some(v) + } + case Deref(Field(r1, f1)) => + getFieldNonRecordValue(r1, f1) orElse None + case Deref(This) => Some(target) + case Const(k) => Some(target) + case _ => None } } @@ -159,8 +185,8 @@ abstract class CopyPropagation { if (a.stack eq exceptionHandlerStack) a.stack else if (b.stack eq exceptionHandlerStack) b.stack else { - if (a.stack.length != b.stack.length) - throw new LubError(a, b, "Invalid stacks in states: "); +// if (a.stack.length != b.stack.length) +// throw new LubError(a, b, "Invalid stacks in states: "); List.map2(a.stack, b.stack) { (v1, v2) => if (v1 == v2) v1 else Unknown } @@ -172,9 +198,9 @@ abstract class CopyPropagation { if (v1 == v2) v1 else Unknown } */ - val commonPairs = a.bindings.toList intersect (b.bindings.toList) val resBindings = new HashMap[Location, Value] - for ((k, v) <- commonPairs) + + for ((k, v) <- a.bindings if b.bindings.isDefinedAt(k) && v == b.bindings(k)) resBindings += (k -> v); new State(resBindings, resStack) } @@ -254,6 +280,20 @@ abstract class CopyPropagation { case (r @ Record(cls, bindings)) :: xs => Deref(Field(r, field)) + case Deref(LocalVar(l)) :: _ => + in.getBinding(l) match { + case r @ Record(cls, bindings) => Deref(Field(r, field)) + case _ => Unknown + } + + case Deref(Field(r, f)) :: _ => + val fld = in.getFieldValue(r, f) + fld match { + case Some(r @ Record(cls, bindings)) if bindings.isDefinedAt(f) => + in.getFieldValue(r, f).getOrElse(Unknown) + case _ => Unknown + } + case _ => Unknown } out.stack = v1 :: out.stack.drop(1) @@ -474,17 +514,22 @@ abstract class CopyPropagation { * @param state ... */ final def invalidateRecords(state: copyLattice.State) { + def shouldRetain(sym: Symbol): Boolean = { + if (sym.hasFlag(symtab.Flags.MUTABLE)) + log("dropping binding for " + sym.fullNameString) + !sym.hasFlag(symtab.Flags.MUTABLE) + } state.stack = state.stack map { v => v match { case Record(cls, bindings) => - bindings.retain { (sym: Symbol, v: Value) => !sym.hasFlag(symtab.Flags.MUTABLE) } + bindings.retain { (sym: Symbol, v: Value) => shouldRetain(sym) } Record(cls, bindings) case _ => v }} state.bindings retain {(loc, value) => value match { - case Deref(Field(_, _)) => false - case Boxed(Field(_, _)) => false + case Deref(Field(rec, sym)) => shouldRetain(sym) + case Boxed(Field(rec, sym)) => shouldRetain(sym) case _ => true } } diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/DataFlowAnalysis.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/DataFlowAnalysis.scala index 848cd657e7..144223f866 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/analysis/DataFlowAnalysis.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/DataFlowAnalysis.scala @@ -55,19 +55,21 @@ trait DataFlowAnalysis[L <: CompleteLattice] { def forwardAnalysis(f: (P, lattice.Elem) => lattice.Elem): Unit = try { while (!worklist.isEmpty) { if (stat) iterations += 1 -// Console.println("worklist in: " + worklist); + //Console.println("worklist in: " + worklist); val point = worklist.elements.next; worklist -= point; visited += point; //Console.println("taking out point: " + point + " worklist out: " + worklist); val output = f(point, in(point)) if ((lattice.bottom == out(point)) || output != out(point)) { -// Console.println("Output changed at " + point + " from: " + out(point) + " to: " + output + " and they are different: " + (output != out(point))) +// Console.println("Output changed at " + point +// + " from: " + out(point) + " to: " + output +// + " for input: " + in(point) + " and they are different: " + (output != out(point))) out(point) = output val succs = point.successors succs foreach { p => if (!worklist.contains(p)) worklist += p; - in(p) = lattice.lub(in(p) :: (p.predecessors map out.apply)) + in(p) = lattice.lub(/*in(p) :: */(p.predecessors map out.apply)) } } } diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/ReachingDefinitions.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/ReachingDefinitions.scala index e11a22fa37..96f5500fb1 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/analysis/ReachingDefinitions.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/ReachingDefinitions.scala @@ -229,7 +229,7 @@ abstract class ReachingDefinitions { } else { val stack = this.in(bb).stack assert(stack.length >= m, "entry stack is too small, expected: " + m + " found: " + stack) - stack.take(m) flatMap (_.toList) + stack.drop(depth).take(m) flatMap (_.toList) } /** Return the definitions that produced the topmost 'm' elements on the stack, diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala index c341d28ca8..c5464a272e 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala @@ -51,8 +51,8 @@ abstract class TypeFlowAnalysis { else if (s1 eq exceptionHandlerStack) s1 else if (s2 eq exceptionHandlerStack) s2 else { - if (s1.length != s2.length) - throw new CheckerError("Incompatible stacks: " + s1 + " and " + s2); +// if (s1.length != s2.length) +// throw new CheckerError("Incompatible stacks: " + s1 + " and " + s2); new TypeStack(List.map2(s1.types, s2.types) (icodes.lub)) } } @@ -89,12 +89,12 @@ abstract class TypeFlowAnalysis { for (binding1 <- env1.elements) { val tp2 = env2(binding1._1) - resultingLocals += (binding1._1 -> typeLattice.lub2(binding1._2, tp2)) + resultingLocals += ((binding1._1, typeLattice.lub2(binding1._2, tp2))) } for (binding2 <- env2.elements if resultingLocals(binding2._1) eq typeLattice.bottom) { val tp1 = env1(binding2._1) - resultingLocals += (binding2._1 -> typeLattice.lub2(binding2._2, tp1)) + resultingLocals += ((binding2._1, typeLattice.lub2(binding2._2, tp1))) } IState(resultingLocals, typeStackLattice.lub2(a.stack, b.stack)) diff --git a/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala b/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala index 7cee5e5b61..f597a050da 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala @@ -123,31 +123,36 @@ abstract class ClosureElimination extends SubComponent { } - case LOAD_FIELD(f, false) if accessible(f, m.symbol) => + 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.stack(0) match { - case r @ Record(cls, bindings) if bindings.isDefinedAt(f) => - info.getFieldValue(r, f) match { - case Some(v) => - bb.replaceInstruction(i, - DROP(REFERENCE(cls)) :: valueToInstruction(v) :: Nil); - log("Replaced " + i + " with " + info.getBinding(r, f)); - case None => (); - } + case r @ Record(_, bindings) if bindings.isDefinedAt(f) => + replaceFieldAccess(r) case Deref(LocalVar(l)) => info.getBinding(l) match { - case r @ Record(cls, bindings) if bindings.isDefinedAt(f) => - info.getFieldValue(r, f) match { - case Some(v) => - bb.replaceInstruction(i, - DROP(REFERENCE(cls)) :: valueToInstruction(v) :: Nil); - log("Replaced " + i + " with " + info.getBinding(r, f)); - case None => (); - } - case _ => (); + case r @ Record(_, bindings) if bindings.isDefinedAt(f) => + replaceFieldAccess(r) + case _ => + } + case Deref(Field(r1, f1)) => + info.getFieldValue(r1, f1) match { + case Some(r @ Record(_, bindings)) if bindings.isDefinedAt(f) => + replaceFieldAccess(r) + case _ => } - case _ => (); + case _ => } case UNBOX(_) => diff --git a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala index 3673e42afb..0ac08e0d6a 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala @@ -277,20 +277,22 @@ abstract class Inliners extends SubComponent { val tfa = new analysis.MethodTFA(); tfa.stat = settings.statistics.value - def analyzeMethod(m: IMethod): Unit = try { + // how many times have we already inlined this method here? + private val inlinedMethods: Map[Symbol, Int] = new HashMap[Symbol, Int] { + override def default(k: Symbol) = 0 + } + + def analyzeMethod(m: IMethod): Unit = {//try { var retry = false var count = 0 fresh.clear - // how many times have we already inlined this method here? - val inlinedMethods: Map[Symbol, Int] = new HashMap[Symbol, Int] { - override def default(k: Symbol) = 0 - } + inlinedMethods.clear do { retry = false; if (m.code ne null) { if (settings.debug.value) - log("Analyzing " + m + " count " + count); + log("Analyzing " + m + " count " + count + " with " + m.code.blocks.length + " blocks"); tfa.init(m) tfa.run for (bb <- linearizer.linearize(m)) { @@ -314,8 +316,7 @@ abstract class Inliners extends SubComponent { log("\tlooked up method: " + concreteMethod.fullNameString) } - if (receiver == definitions.PredefModule.moduleClass) { - log("loading predef") + if (shouldLoad(receiver, concreteMethod)) { icodes.icode(receiver, true) } if (settings.debug.value) @@ -331,12 +332,11 @@ abstract class Inliners extends SubComponent { icodes.icode(receiver).get.lookupMethod(concreteMethod) match { case Some(inc) => if (inc.symbol != m.symbol - && (inlinedMethods(inc.symbol) < 2) && (inc.code ne null) && shouldInline(m, inc) && isSafeToInline(m, inc, info.stack)) { retry = true; - if (!isClosureClass(receiver)) // only count non-closures + if (!(isClosureClass(receiver) && (concreteMethod.name == nme.apply))) // only count non-closures count = count + 1; inline(m, bb, i, inc); inlinedMethods(inc.symbol) = inlinedMethods(inc.symbol) + 1 @@ -353,7 +353,8 @@ abstract class Inliners extends SubComponent { + "\n\tshouldInline heuristics: " + shouldInline(m, inc) else "")); } case None => - (); + if (settings.debug.value) + log("could not find icode\n\treceiver: " + receiver + "\n\tmethod: " + concreteMethod) } } @@ -364,14 +365,29 @@ abstract class Inliners extends SubComponent { if (tfa.stat) log(m.symbol.fullNameString + " iterations: " + tfa.iterations + " (size: " + m.code.blocks.length + ")") }} while (retry && count < 15) m.normalize - } catch { - case e => - Console.println("############# Caught exception: " + e + " #################"); - Console.println("\nMethod: " + m + - "\nMethod owner: " + m.symbol.owner); - e.printStackTrace(); - m.dump - throw e +// } catch { +// case e => +// Console.println("############# Caught exception: " + e + " #################"); +// Console.println("\nMethod: " + m + +// "\nMethod owner: " + m.symbol.owner); +// e.printStackTrace(); +// m.dump +// throw e + } + + + def isMonadMethod(method: Symbol): Boolean = + (method.name == nme.foreach + || method.name == nme.filter + || method.name == nme.map + || method.name == nme.flatMap) + + /** Should the given method be loaded from disk? */ + def shouldLoad(receiver: Symbol, method: Symbol): Boolean = { + if (settings.debug.value) log("shouldLoad: " + receiver + "." + method) + ((method.isFinal && isMonadMethod(method) && isHigherOrderMethod(method)) + || (receiver.enclosingPackage == definitions.ScalaRunTimeModule.enclosingPackage) + || (receiver == definitions.PredefModule.moduleClass)) } /** Cache whether a method calls private members. */ @@ -407,7 +423,8 @@ abstract class Inliners extends SubComponent { case LOAD_FIELD(f, _) => if (f.hasFlag(Flags.PRIVATE)) - if (f.hasFlag(Flags.SYNTHETIC) || f.hasFlag(Flags.PARAMACCESSOR)) { + if ((callee.sourceFile ne null) + && (f.hasFlag(Flags.SYNTHETIC) || f.hasFlag(Flags.PARAMACCESSOR))) { if (settings.debug.value) log("Making not-private symbol out of synthetic: " + f); f.setFlag(Flags.notPRIVATE) @@ -416,7 +433,8 @@ abstract class Inliners extends SubComponent { case STORE_FIELD(f, _) => if (f.hasFlag(Flags.PRIVATE)) - if (f.hasFlag(Flags.SYNTHETIC) || f.hasFlag(Flags.PARAMACCESSOR)) { + if ((callee.sourceFile ne null) + && (f.hasFlag(Flags.SYNTHETIC) || f.hasFlag(Flags.PARAMACCESSOR))) { if (settings.debug.value) log("Making not-private symbol out of synthetic: " + f); f.setFlag(Flags.notPRIVATE) @@ -456,7 +474,7 @@ abstract class Inliners extends SubComponent { } /** small method size (in blocks) */ - val SMALL_METHOD_SIZE = 4 + val SMALL_METHOD_SIZE = 1 /** Decide whether to inline or not. Heuristics: * - it's bad to make the caller larger (> SMALL_METHOD_SIZE) @@ -483,14 +501,15 @@ abstract class Inliners extends SubComponent { if (callee.code.blocks.length > MAX_INLINE_SIZE) score -= 1 - if (callee.symbol.tpe.paramTypes.exists(t => definitions.FunctionClass.contains(t.typeSymbol))) { - if (settings.debug.value) - log("increased score to: " + score) + if (isMonadMethod(callee.symbol)) score += 2 - } + else if (isHigherOrderMethod(callee.symbol)) + score += 1 if (isClosureClass(callee.symbol.owner)) score += 2 + if (inlinedMethods(callee.symbol) > 2) score -= 2 + if (settings.debug.value) log("shouldInline(" + callee + ") score: " + score) score > 0 } } /* class Inliner */ @@ -504,4 +523,10 @@ abstract class Inliners extends SubComponent { } res } + + /** Does 'sym' denote a higher order method? */ + def isHigherOrderMethod(sym: Symbol): Boolean = + (sym.isMethod + && atPhase(currentRun.erasurePhase.prev)(sym.info.paramTypes exists definitions.isFunctionType)) + } /* class Inliners */ diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/tools/nsc/symtab/Definitions.scala index 727cd16d20..9427897040 100644 --- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala +++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala @@ -424,7 +424,7 @@ trait Definitions { clazz.setInfo( PolyType( List(tparam), - ClassInfoType(List(p), newClassScope(clazz), clazz))) + ClassInfoType(List(AnyRefClass.tpe, p), newClassScope(clazz), clazz))) } private def newAlias(owner: Symbol, name: Name, alias: Type): Symbol = { diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala index 7e04e9c5fe..4e0c0cb65b 100644 --- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala +++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala @@ -166,8 +166,8 @@ abstract class SymbolLoaders { def refresh() { /** Is the given name a valid input file base name? */ def isValid(name: String): Boolean = - name.length() > 0 && !name.endsWith("$class") && - (/*settings.XO.value*/true || name.indexOf("$anon") == -1) + name.length() > 0 /*&& !name.endsWith("$class") && + (/*settings.XO.value*/true || name.indexOf("$anon") == -1) */ val classes = new HashMap[String, global.classPath0.Context] val packages = new HashMap[String, global.classPath0.Context] diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index 033d3ba89d..77cc8359b8 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -51,8 +51,10 @@ abstract class ClassfileParser { } def parse(file: AbstractFile, root: Symbol) = try { - def handleMissing(e: MissingRequirementError) = + def handleMissing(e: MissingRequirementError) = { + if (settings.debug.value) e.printStackTrace throw new IOException("Missing dependency '" + e.req + "', required by " + in.file) + } def handleError(e: Exception) = { if (settings.debug.value) e.printStackTrace() @@ -217,15 +219,22 @@ abstract class ClassfileParser { //assert(name.endsWith("$"), "Not a module class: " + name) f = definitions.getModule(name.subName(0, name.length - 1)) } else { + val origName = nme.originalName(name) val owner = if (static) ownerTpe.typeSymbol.linkedClassOfClass else ownerTpe.typeSymbol // println("\t" + owner.info.member(name).tpe.widen + " =:= " + tpe) - f = owner.info.member(name).suchThat(_.tpe.widen =:= tpe) + f = owner.info.member(origName).suchThat(_.tpe.widen =:= tpe) if (f == NoSymbol) - f = owner.info.member(newTermName(name.toString + nme.LOCAL_SUFFIX)).suchThat(_.tpe =:= tpe) + f = owner.info.member(newTermName(origName.toString + nme.LOCAL_SUFFIX)).suchThat(_.tpe =:= tpe) if (f == NoSymbol) { // if it's an impl class, try to find it's static member inside the class - assert(ownerTpe.typeSymbol.isImplClass, "Not an implementation class: " + owner + " couldn't find " + name + ": " + tpe + " inside: \n" + ownerTpe.members); - f = ownerTpe.member(name).suchThat(_.tpe =:= tpe) + if (ownerTpe.typeSymbol.isImplClass) + f = ownerTpe.member(origName).suchThat(_.tpe =:= tpe) + else { + log("Couldn't find " + name + ": " + tpe + " inside: \n" + ownerTpe) + f = if (tpe.isInstanceOf[MethodType]) owner.newMethod(owner.pos, name).setInfo(tpe) + else owner.newValue(owner.pos, name).setInfo(tpe).setFlag(MUTABLE) + log("created fake member " + f.fullNameString) + } // println("\townerTpe.decls: " + ownerTpe.decls) // println("Looking for: " + name + ": " + tpe + " inside: " + ownerTpe.typeSymbol + "\n\tand found: " + ownerTpe.members) } diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala index c17a754d31..6753ae3194 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala @@ -44,6 +44,7 @@ abstract class ICodeReader extends ClassfileParser { var classFile: AbstractFile = null; var sym = cls sym.info // ensure accurate type information + isScalaModule = cls.isModule && !cls.hasFlag(JAVA) log("Reading class: " + cls + " isScalaModule?: " + isScalaModule) val name = cls.fullNameString(java.io.File.separatorChar) + (if (sym.hasFlag(MODULE)) "$" else "") @@ -191,8 +192,8 @@ abstract class ICodeReader extends ClassfileParser { definitions.NullClass else if (name.endsWith("$class")) { val iface = definitions.getClass(name.subName(0, name.length - "$class".length)) - log("forcing " + iface) - iface.info // force the mixin type-transformer + log("forcing " + iface.owner + " at phase: " + phase + " impl: " + iface.implClass) + iface.owner.info // force the mixin type-transformer definitions.getClass(name) } else if (name.endsWith("$")) definitions.getModule(name.subName(0, name.length - 1)) @@ -926,16 +927,19 @@ abstract class ICodeReader extends ClassfileParser { for ((i, idx) <- bb.toList.zipWithIndex) i match { case CALL_METHOD(m, Static(true)) if m.isClassConstructor => val defs = rdef.findDefs(bb, idx, 1, m.info.paramTypes.length) - //println("ctor: " + i + " found defs: " + defs) - assert(defs.length == 1) + if (settings.debug.value) log("ctor: " + i + " found defs: " + defs) + assert(defs.length == 1, "wrong defs at bb " + bb + "\n" + method.dump + rdef) val (bb1, idx1) = defs.head var producer = bb1(idx1) while (producer.isInstanceOf[DUP]) { val (bb2, idx2) = rdef.findDefs(bb1, idx1, 1).head producer = bb2(idx2) } - assert(producer.isInstanceOf[NEW], producer) - producer.asInstanceOf[NEW].init = i.asInstanceOf[CALL_METHOD] + producer match { + case nw: NEW => nw.init = i.asInstanceOf[CALL_METHOD] + case _: THIS => () // super constructor call + case _ => assert(false, producer + "\n" + method.dump) + } case _ => } } diff --git a/src/library/scala/runtime/RichInt.scala b/src/library/scala/runtime/RichInt.scala index c62d8fcd06..bb01e0de35 100644 --- a/src/library/scala/runtime/RichInt.scala +++ b/src/library/scala/runtime/RichInt.scala @@ -12,7 +12,7 @@ package scala.runtime -final class RichInt(start: Int) extends Proxy with Ordered[Int] { +final class RichInt(val start: Int) extends Proxy with Ordered[Int] { // Proxy def self: Any = start |