summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIulian Dragos <jaguarul@gmail.com>2009-11-16 18:24:40 +0000
committerIulian Dragos <jaguarul@gmail.com>2009-11-16 18:24:40 +0000
commitff7183ddeb831558ec9c09848e0507d098a751df (patch)
treeb62f4bebed8ad4fdc32d7805771af89f2bea5023
parent0b236faf92a219bd5a9fa4899c9f7ade677b26f4 (diff)
downloadscala-ff7183ddeb831558ec9c09848e0507d098a751df.tar.gz
scala-ff7183ddeb831558ec9c09848e0507d098a751df.tar.bz2
scala-ff7183ddeb831558ec9c09848e0507d098a751df.zip
Faster optimizer by caching successors/predeces...
Faster optimizer by caching successors/predecessors in basic blocks, and better lub for icode
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala122
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/GenICode.scala4
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/Members.scala60
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/Printers.scala4
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala20
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/analysis/DataFlowAnalysis.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/analysis/Liveness.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala13
-rw-r--r--src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/opt/Inliners.scala17
11 files changed, 135 insertions, 113 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala b/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala
index a774473167..b708d4df80 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala
@@ -40,8 +40,8 @@ trait BasicBlocks {
def hasFlag(flag: Int): Boolean = (flags & flag) != 0
/** Set the given flag. */
- def setFlag(flag: Int): Unit = flags |= flag
- def resetFlag(flag: Int) {
+ private def setFlag(flag: Int): Unit = flags |= flag
+ private def resetFlag(flag: Int) {
flags &= ~flag
}
@@ -63,9 +63,16 @@ trait BasicBlocks {
def exceptionHandlerStart_=(b: Boolean) =
if (b) setFlag(EX_HEADER) else resetFlag(EX_HEADER)
- /** Has this basic block been modified since the last call to 'toList'? */
- private def touched = hasFlag(TOUCHED)
- private def touched_=(b: Boolean) = if (b) setFlag(TOUCHED) else resetFlag(TOUCHED)
+ /** Has this basic block been modified since the last call to 'successors'? */
+ def touched = hasFlag(DIRTYSUCCS)
+ def touched_=(b: Boolean) = if (b) {
+ setFlag(DIRTYSUCCS | DIRTYPREDS)
+ } else {
+ resetFlag(DIRTYSUCCS | DIRTYPREDS)
+ }
+
+ // basic blocks start in a dirty state
+ setFlag(DIRTYSUCCS | DIRTYPREDS)
/** Cached predecessors. */
var preds: List[BasicBlock] = null
@@ -85,9 +92,9 @@ trait BasicBlocks {
private var instrs: Array[Instruction] = _
override def toList: List[Instruction] = {
- if (closed && touched)
- instructionList = instrs.toList
- instructionList
+ if (closed)
+ instrs.toList
+ else instructionList
}
/** Return an iterator over the instructions in this basic block. */
@@ -101,12 +108,11 @@ trait BasicBlocks {
}
def fromList(is: List[Instruction]) {
+ code.touched = true
instrs = toInstructionArray(is)
closed = true
}
- // public:
-
/** Return the index of inst. Uses reference equality.
* Returns -1 if not found.
*/
@@ -166,9 +172,9 @@ trait BasicBlocks {
*/
def replaceInstruction(pos: Int, instr: Instruction): Boolean = {
assert(closed, "Instructions can be replaced only after the basic block is closed")
-
instr.setPos(instrs(pos).pos)
instrs(pos) = instr
+ code.touched = true
true
}
@@ -187,6 +193,7 @@ trait BasicBlocks {
newInstr.setPos(oldInstr.pos)
instrs(i) = newInstr
changed = true
+ code.touched = true
}
i += 1
}
@@ -213,6 +220,8 @@ trait BasicBlocks {
if (i < instrs.length) {
val newInstrs = new Array[Instruction](instrs.length + is.length - 1);
changed = true
+ code.touched = true
+
Array.copy(instrs, 0, newInstrs, 0, i)
var j = i
for (x <- is) {
@@ -244,6 +253,7 @@ trait BasicBlocks {
Array.copy(instrs, i + 1, newInstrs, j, instrs.length - i)
instrs = newInstrs;
}
+ code.touched = true
}
/** Removes instructions found at the given positions.
@@ -264,6 +274,7 @@ trait BasicBlocks {
i += 1
}
instrs = newInstrs
+ code.touched = true
}
/** Remove the last instruction of this basic block. It is
@@ -274,7 +285,7 @@ trait BasicBlocks {
removeInstructionsAt(size)
else {
instructionList = instructionList.tail
- touched = true
+ code.touched = true
}
}
@@ -287,7 +298,9 @@ trait BasicBlocks {
var i = 0
while (i < instrs.length) {
map get instrs(i) match {
- case Some(instr) => touched = replaceInstruction(i, instr)
+ case Some(instr) =>
+ val changed = replaceInstruction(i, instr)
+ code.touched |= changed
case None => ()
}
i += 1
@@ -321,6 +334,10 @@ trait BasicBlocks {
emit(instr, NoPosition)
}
+ /** Emitting does not set touched to true. During code generation this is a hotspot and
+ * setting the flag for each emit is a waste. Caching should happend only after a block
+ * is closed, which sets the DIRTYSUCCS flag.
+ */
def emit(instr: Instruction, pos: Position) {
if (closed) {
print()
@@ -329,7 +346,6 @@ trait BasicBlocks {
assert(!closed || ignore, "BasicBlock closed")
if (!ignore) {
- touched = true
instr.setPos(pos)
instructionList = instr :: instructionList
_lastInstruction = instr
@@ -357,6 +373,7 @@ trait BasicBlocks {
def close {
assert(instructionList.length > 0, "Empty block.")
closed = true
+ setFlag(DIRTYSUCCS)
instructionList = instructionList.reverse
instrs = toInstructionArray(instructionList)
}
@@ -365,6 +382,7 @@ trait BasicBlocks {
assert(closed)
closed = false
ignore = false
+ touched = true
instructionList = instructionList.reverse // prepare for appending to the head
}
@@ -409,25 +427,37 @@ trait BasicBlocks {
array
}
- def successors : List[BasicBlock] = if (isEmpty) Nil else {
- var res = lastInstruction match {
- case JUMP (whereto) => List(whereto)
- case CJUMP(success, failure, _, _) => failure :: success :: Nil
- case CZJUMP(success, failure, _, _) => failure :: success :: Nil
- case SWITCH(_,labels) => labels
- case RETURN(_) => Nil
- case THROW() => Nil
- case _ =>
- if (closed) {
- dump
- global.abort("The last instruction is not a control flow instruction: " + lastInstruction)
+ /** Cached value of successors. Must be recomputed whenver a block in the current method is changed. */
+ private var succs: List[BasicBlock] = Nil
+
+ def successors : List[BasicBlock] = {
+ if (touched) {
+ resetFlag(DIRTYSUCCS)
+ succs = if (isEmpty) Nil else {
+ var res = lastInstruction match {
+ case JUMP(whereto) => List(whereto)
+ case CJUMP(success, failure, _, _) => failure :: success :: Nil
+ case CZJUMP(success, failure, _, _) => failure :: success :: Nil
+ case SWITCH(_, labels) => labels
+ case RETURN(_) => Nil
+ case THROW() => Nil
+ case _ =>
+ if (closed) {
+ dump
+ global.abort("The last instruction is not a control flow instruction: " + lastInstruction)
+ }
+ else Nil
}
- else Nil
- }
- method.exh.foreach { e: ExceptionHandler =>
- if (e.covers(this)) res = e.startBlock :: res
+ method.exh.foreach {
+ e: ExceptionHandler =>
+ if (e.covers(this)) res = e.startBlock :: res
+ }
+ val res1 = res ++ exceptionalSucc(this, res)
+ res1
+ }
}
- res ++ exceptionalSucc(this, res)
+// println("reusing cached successors for " + this + " in method " + method)
+ succs
}
/** Return a list of successors for 'b' that come from exception handlers
@@ -446,12 +476,12 @@ trait BasicBlocks {
succs.flatMap(findSucc).removeDuplicates
}
- /** Returns the precessors of this block, in the current 'code' chunk.
- * This is signifficant only if there are exception handlers, which live
- * in different code 'chunks' than the rest of the method.
- */
+ /** Returns the precessors of this block. */
def predecessors: List[BasicBlock] = {
- preds = code.blocks.iterator.filter (_.successors.contains(this)).toList
+ if (hasFlag(DIRTYPREDS)) {
+ resetFlag(DIRTYPREDS)
+ preds = code.blocks.iterator.filter (_.successors.contains(this)).toList
+ }
preds
}
@@ -467,7 +497,7 @@ trait BasicBlocks {
def print(out: java.io.PrintStream) {
out.println("block #"+label+" :")
- toList.foreach(i => out.println(" " + i))
+ foreach(i => out.println(" " + i))
out.print("Successors: ")
successors.foreach((x: BasicBlock) => out.print(" "+x.label.toString()))
out.println()
@@ -482,6 +512,17 @@ trait BasicBlocks {
}
override def toString(): String = "" + label
+
+ def flagsString: String =
+ ("block " + label + (
+ if (hasFlag(LOOP_HEADER)) " <loopheader> "
+ else if (hasFlag(IGNORING)) " <ignore> "
+ else if (hasFlag(EX_HEADER)) " <exheader> "
+ else if (hasFlag(CLOSED)) " <closed> "
+ else if (hasFlag(DIRTYSUCCS)) " <dirtysuccs> "
+ else if (hasFlag(DIRTYPREDS)) " <dirtypreds> "
+ else ""
+ ))
}
}
@@ -499,6 +540,9 @@ object BBFlags {
/** This block is closed. No new instructions can be added. */
final val CLOSED = 0x00000008
- /** This block has been changed, cached results are recomputed. */
- final val TOUCHED = 0x00000010
+ /** Code has been changed, recompute successors. */
+ final val DIRTYSUCCS = 0x00000010
+
+ /** Code has been changed, recompute predecessors. */
+ final val DIRTYPREDS = 0x00000020
}
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
index f0c44bb227..4628d58a98 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
@@ -1624,7 +1624,7 @@ abstract class GenICode extends SubComponent {
do {
changed = false
n += 1
- method.code traverse prune0
+ method.code.blocks foreach prune0
} while (changed)
if (settings.debug.value)
@@ -2061,7 +2061,7 @@ abstract class GenICode extends SubComponent {
}
val map = substMap
- code traverse (_.subst(map))
+ code.blocks foreach (_.subst(map))
}
/**
diff --git a/src/compiler/scala/tools/nsc/backend/icode/Members.scala b/src/compiler/scala/tools/nsc/backend/icode/Members.scala
index 19f78626e9..35eeec316e 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/Members.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/Members.scala
@@ -36,6 +36,14 @@ trait Members { self: ICodes =>
var producedStack: TypeStack = null
private var currentLabel: Int = 0
+ private var _touched = false
+
+ def touched = _touched
+ def touched_=(b: Boolean): Unit = if (b) {
+ blocks foreach (_.touched = true)
+ _touched = true
+ } else
+ _touched = false
// Constructor code
startBlock = newBlock
@@ -52,52 +60,11 @@ trait Members { self: ICodes =>
if (b == startBlock)
startBlock = b.successors.head;
blocks -= b
- }
-
- /**
- * Apply a function to all basic blocks, for side-effects. It starts at
- * the given startBlock and checks that are no predecessors of the given node.
- * Only blocks that are reachable via a path from startBlock are ever visited.
- */
- def traverseFrom(startBlock: BasicBlock, f: BasicBlock => Unit) = {
- val visited: Set[BasicBlock] = new HashSet();
-
- def traverse0(toVisit: List[BasicBlock]): Unit = toVisit match {
- case Nil => ();
- case b :: bs => if (!visited.contains(b)) {
- f(b);
- visited += b;
- traverse0(bs ::: b.successors);
- } else
- traverse0(bs);
- }
- assert(startBlock.predecessors == Nil,
- "Starting traverse from a block with predecessors: " + this);
- traverse0(startBlock :: Nil)
- }
+ assert(!blocks.contains(b))
+ for (handler <- method.exh if handler.covers(b))
+ handler.covered -= b
- def traverse(f: BasicBlock => Unit) = blocks.toList foreach f;
-
- /* This method applies the given function to each basic block. */
- def traverseFeedBack(f: (BasicBlock, HashMap[BasicBlock, Boolean]) => Unit) = {
- val visited : HashMap[BasicBlock, Boolean] = new HashMap;
- visited ++= blocks.iterator.map(x => (x, false));
-
- var blockToVisit: List[BasicBlock] = List(startBlock)
-
- while (!blockToVisit.isEmpty) {
- blockToVisit match {
- case b::xs =>
- if (!visited(b)) {
- f(b, visited);
- blockToVisit = b.successors ::: xs;
- visited += (b -> true)
- } else
- blockToVisit = xs
- case _ =>
- error("impossible match")
- }
- }
+ touched = true
}
/** This methods returns a string representation of the ICode */
@@ -112,6 +79,7 @@ trait Members { self: ICodes =>
/* Create a new block and append it to the list
*/
def newBlock: BasicBlock = {
+ touched = true
val block = new BasicBlock(nextLabel, method);
blocks += block;
block
@@ -230,7 +198,7 @@ trait Members { self: ICodes =>
import opcodes._
def checkLocals: Unit = if (code ne null) {
Console.println("[checking locals of " + this + "]")
- for (bb <- code.blocks; i <- bb.toList) i match {
+ for (bb <- code.blocks; i <- bb) i match {
case LOAD_LOCAL(l) =>
if (!this.locals.contains(l))
Console.println("Local " + l + " is not declared in " + this)
diff --git a/src/compiler/scala/tools/nsc/backend/icode/Printers.scala b/src/compiler/scala/tools/nsc/backend/icode/Printers.scala
index f03b84a50e..e50260b651 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/Printers.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/Printers.scala
@@ -119,9 +119,9 @@ trait Printers { self: ICodes =>
print(bb.label)
if (bb.loopHeader) print("[loop header]")
print(": ");
- if (settings.debug.value) print("pred: " + bb.predecessors + " succs: " + bb.successors)
+ if (settings.debug.value) print("pred: " + bb.predecessors + " succs: " + bb.successors + " flags: " + bb.flagsString)
indent; println
- bb.toList foreach printInstruction
+ bb foreach printInstruction
undent; println
}
diff --git a/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala b/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala
index 2d586ba7ea..81461c1bf7 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala
@@ -108,6 +108,8 @@ trait TypeKinds { self: ICodes =>
def dimensions: Int = 0
}
+ var lubs0 = 0
+
/**
* The least upper bound of two typekinds. They have to be either
* REFERENCE or ARRAY kinds.
@@ -116,16 +118,11 @@ trait TypeKinds { self: ICodes =>
*/
def lub(a: TypeKind, b: TypeKind): TypeKind = {
def lub0(t1: Type, t2: Type): Type = {
- val lubTpe = global.lub(t1 :: t2 :: Nil)
- assert(lubTpe.typeSymbol.isClass,
- "Least upper bound of " + t1 + " and " + t2 + " is not a class: " + lubTpe)
- lubTpe
+ //lubs0 += 1
+ global.lub(t1 :: t2 :: Nil)
}
- if ((a.isReferenceType || a.isArrayType) &&
- (b.isReferenceType || b.isArrayType))
- toTypeKind(lub0(a.toType, b.toType))
- else if (a == b) a
+ if (a == b) a
else if (a == REFERENCE(NothingClass)) b
else if (b == REFERENCE(NothingClass)) a
else (a, b) match {
@@ -136,7 +133,12 @@ trait TypeKinds { self: ICodes =>
case (SHORT, INT) | (INT, SHORT) => INT
case (CHAR, INT) | (INT, CHAR) => INT
case (BOOL, INT) | (INT, BOOL) => INT
- case _ => throw new CheckerError("Incompatible types: " + a + " with " + b)
+ case _ =>
+ if ((a.isReferenceType || a.isArrayType) &&
+ (b.isReferenceType || b.isArrayType))
+ toTypeKind(lub0(a.toType, b.toType))
+ else
+ throw new CheckerError("Incompatible types: " + a + " with " + b)
}
}
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 9ee628ef19..048c44c467 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala
@@ -245,7 +245,7 @@ abstract class CopyPropagation {
}
def blockTransfer(b: BasicBlock, in: lattice.Elem): lattice.Elem =
- b.toList.foldLeft(in)(interpret)
+ b.foldLeft(in)(interpret)
import opcodes._
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 09a39f4280..8e14159197 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/analysis/DataFlowAnalysis.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/DataFlowAnalysis.scala
@@ -70,6 +70,8 @@ trait DataFlowAnalysis[L <: CompleteLattice] {
succs foreach { p =>
if (!worklist.contains(p))
worklist += p;
+ if (!in.isDefinedAt(p))
+ assert(false, "Invalid successor for: " + point + " successor " + p + " does not exist")
// if (!p.exceptionHandlerHeader) {
// println("lubbing " + p.predecessors + " outs: " + p.predecessors.map(out.apply).mkString("\n", "\n", ""))
in(p) = lattice.lub(/*in(p) :: */(p.predecessors map out.apply), p.exceptionHandlerStart)
diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/Liveness.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/Liveness.scala
index 46e24c18ec..0d301347b1 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/analysis/Liveness.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/Liveness.scala
@@ -71,7 +71,7 @@ abstract class Liveness {
def genAndKill(b: BasicBlock): (Set[Local], Set[Local]) = {
var genSet = new ListSet[Local]
var killSet = new ListSet[Local]
- for (i <- b.toList) i match {
+ for (i <- b) i match {
case LOAD_LOCAL(local) if (!killSet(local)) => genSet = genSet + local
case STORE_LOCAL(local) if (!genSet(local)) => killSet = killSet + local
case _ => ()
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 32a6037d41..fc097956a8 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala
@@ -81,10 +81,14 @@ abstract class TypeFlowAnalysis {
override val top = new Elem(new VarBinding, typeStackLattice.top)
override val bottom = new Elem(new VarBinding, typeStackLattice.bottom)
+// var lubs = 0
+
def lub2(exceptional: Boolean)(a: Elem, b: Elem) = {
val IState(env1, s1) = a
val IState(env2, s2) = b
+// lubs += 1
+
val resultingLocals = new VarBinding
for (binding1 <- env1.iterator) {
@@ -118,7 +122,7 @@ abstract class TypeFlowAnalysis {
/** Initialize the in/out maps for the analysis of the given method. */
def init(m: icodes.IMethod) {
this.method = m
-
+ //typeFlowLattice.lubs = 0
init {
worklist += m.code.startBlock
worklist ++= (m.exh map (_.startBlock))
@@ -168,14 +172,17 @@ abstract class TypeFlowAnalysis {
def run = {
timer.start
+// icodes.lubs0 = 0
forwardAnalysis(blockTransfer)
- timer.stop
+ val t = timer.stop
if (settings.debug.value) {
linearizer.linearize(method).foreach(b => if (b != method.code.startBlock)
assert(visited.contains(b),
"Block " + b + " in " + this.method + " has input equal to bottom -- not visited? .." + visited));
}
- //println("iterations: " + iterations + " for " + method.code.blocks.size)
+// log("" + method.symbol.fullNameString + " [" + method.code.blocks.size + " blocks] "
+// + "\n\t" + iterations + " iterations: " + t + " ms."
+// + "\n\tlubs: " + typeFlowLattice.lubs + " out of which " + icodes.lubs0 + " typer lubs")
}
def blockTransfer(b: BasicBlock, in: lattice.Elem): lattice.Elem = {
diff --git a/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala b/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala
index 248b24bc43..1e53627273 100644
--- a/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala
+++ b/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala
@@ -105,7 +105,7 @@ abstract class ClosureElimination extends SubComponent {
var info = cpp.in(bb)
log("Cpp info at entry to block " + bb + ": " + info)
- for (i <- bb.toList) {
+ for (i <- bb) {
i match {
case LOAD_LOCAL(l) if (info.bindings.isDefinedAt(LocalVar(l))) =>
val t = info.getBinding(l)
diff --git a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala
index 321b27b030..39955f7003 100644
--- a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala
+++ b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala
@@ -290,13 +290,12 @@ abstract class Inliners extends SubComponent {
do {
retry = false;
if (m.code ne null) {
- if (settings.debug.value)
- log("Analyzing " + m + " count " + count + " with " + m.code.blocks.length + " blocks");
+ log("Analyzing " + m + " count " + count + " with " + m.code.blocks.length + " blocks");
tfa.init(m)
tfa.run
for (bb <- linearizer.linearize(m)) {
var info = tfa.in(bb);
- for (i <- bb.toList) {
+ for (i <- bb) {
if (!retry) {
i match {
case CALL_METHOD(msym, Dynamic) =>
@@ -308,11 +307,11 @@ abstract class Inliners extends SubComponent {
if (receiver != msym.owner && receiver != NoSymbol) {
if (settings.debug.value)
log("" + i + " has actual receiver: " + receiver);
- }
- if (!concreteMethod.isFinal && receiver.isFinal) {
- concreteMethod = lookupImpl(concreteMethod, receiver)
- if (settings.debug.value)
- log("\tlooked up method: " + concreteMethod.fullNameString)
+ if (!concreteMethod.isFinal && receiver.isFinal) {
+ concreteMethod = lookupImpl(concreteMethod, receiver)
+ if (settings.debug.value)
+ log("\tlooked up method: " + concreteMethod.fullNameString)
+ }
}
if (shouldLoad(receiver, concreteMethod)) {
@@ -427,7 +426,7 @@ abstract class Inliners extends SubComponent {
callsNonPublic = b
case None =>
breakable {
- for (b <- callee.code.blocks; i <- b.toList)
+ for (b <- callee.code.blocks; i <- b)
i match {
case CALL_METHOD(m, style) =>
if (m.hasFlag(Flags.PRIVATE) ||