Various improvements to the optimiser: more aggresive inlining for monad methods, bytecode reading in more cases, better copy propagation during closure elimination.
git-svn-id: http://lampsvn.epfl.ch/svn-repos/scala/scala/trunk@17722 5e8d7ff9-d8ef-0310-90f0-a4852d11357a
This commit is contained in:
parent
f35a52954a
commit
9064ccb93e
|
@ -1638,7 +1638,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)
|
||||
|
|
|
@ -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) }
|
||||
|
|
|
@ -302,6 +302,8 @@ trait Members { self: ICodes =>
|
|||
other.isInstanceOf[Local] &&
|
||||
other.asInstanceOf[Local].sym == this.sym
|
||||
);
|
||||
|
||||
override def hashCode = sym.hashCode
|
||||
|
||||
override def toString(): String = sym.toString()
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
@ -253,7 +279,21 @@ abstract class CopyPropagation {
|
|||
val v1 = in.stack match {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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(_) =>
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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 _ =>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue