summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIulian Dragos <jaguarul@gmail.com>2009-05-13 15:11:55 +0000
committerIulian Dragos <jaguarul@gmail.com>2009-05-13 15:11:55 +0000
commit1b9f19f08560f324aee6632643ec2bd1187dec1a (patch)
treefec0c59aa0f6ea02035886623b365f2efda4b012
parent62d0a710573fa6bf0d7fcac30c9df1a8b843b3d1 (diff)
downloadscala-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.
-rw-r--r--build.xml2
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/Members.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/Printers.scala6
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/Repository.scala1
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala67
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/analysis/DataFlowAnalysis.scala8
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/analysis/ReachingDefinitions.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala8
-rw-r--r--src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala43
-rw-r--r--src/compiler/scala/tools/nsc/backend/opt/Inliners.scala77
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Definitions.scala2
-rw-r--r--src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala4
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala19
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala16
-rw-r--r--src/library/scala/runtime/RichInt.scala2
17 files changed, 179 insertions, 84 deletions
diff --git a/build.xml b/build.xml
index 080a53e693..7efe28bf72 100644
--- a/build.xml
+++ b/build.xml
@@ -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