scala.tools.nsc.backend.opt.ClosureElimination.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of scala-compiler Show documentation
Show all versions of scala-compiler Show documentation
Compiler for the SubScript extension of the Scala Programming Language
The newest version!
/* NSC -- new Scala compiler
* Copyright 2005-2013 LAMP/EPFL
* @author Iulian Dragos
*/
package scala.tools.nsc
package backend.opt
import scala.tools.nsc.backend.icode.analysis.LubException
/**
* @author Iulian Dragos
*/
abstract class ClosureElimination extends SubComponent {
import global._
import icodes._
import icodes.opcodes._
val phaseName = "closelim"
override val enabled: Boolean = settings.Xcloselim
/** Create a new phase */
override def newPhase(p: Phase) = new ClosureEliminationPhase(p)
/** A simple peephole optimizer. */
val peephole = new PeepholeOpt {
def peep(bb: BasicBlock, i1: Instruction, i2: Instruction) = (i1, i2) match {
case (CONSTANT(c), DROP(_)) =>
if (c.tag == UnitTag) Some(List(i2)) else Some(Nil)
case (LOAD_LOCAL(x), STORE_LOCAL(y)) =>
if (x eq y) Some(Nil) else None
case (STORE_LOCAL(x), LOAD_LOCAL(y)) if (x == y) =>
var liveOut = liveness.out(bb)
if (!liveOut(x)) {
debuglog("store/load to a dead local? " + x)
val instrs = bb.getArray
var idx = instrs.length - 1
while (idx > 0 && (instrs(idx) ne i2)) {
liveOut = liveness.interpret(liveOut, instrs(idx))
idx -= 1
}
if (!liveOut(x)) {
log("Removing dead store/load of " + x.sym.initialize.defString)
Some(Nil)
} else None
} else
Some(List(DUP(x.kind), STORE_LOCAL(x)))
case (LOAD_LOCAL(_), DROP(_)) | (DUP(_), DROP(_)) =>
Some(Nil)
case (BOX(t1), UNBOX(t2)) if (t1 == t2) =>
Some(Nil)
case (LOAD_FIELD(sym, /* isStatic */false), DROP(_)) if !sym.hasAnnotation(definitions.VolatileAttr) && inliner.isClosureClass(sym.owner) =>
Some(DROP(REFERENCE(definitions.ObjectClass)) :: Nil)
case _ => None
}
}
/** The closure elimination phase.
*/
class ClosureEliminationPhase(prev: Phase) extends ICodePhase(prev) {
def name = phaseName
val closser = new ClosureElim
override def apply(c: IClass): Unit = {
if (closser ne null)
closser analyzeClass c
}
}
/**
* Remove references to the environment through fields of a closure object.
* This has to be run after an 'apply' method has been inlined, but it still
* references the closure object.
*
*/
class ClosureElim {
def analyzeClass(cls: IClass): Unit = if (settings.Xcloselim) {
log(s"Analyzing ${cls.methods.size} methods in $cls.")
cls.methods foreach { m =>
analyzeMethod(m)
peephole(m)
}}
val cpp = new copyPropagation.CopyAnalysis
import copyPropagation._
/* Some embryonic copy propagation. */
def analyzeMethod(m: IMethod): Unit = try {if (m.hasCode) {
cpp.init(m)
cpp.run()
m.linearizedBlocks() foreach { bb =>
var info = cpp.in(bb)
debuglog("Cpp info at entry to block " + bb + ": " + info)
for (i <- bb) {
i match {
case LOAD_LOCAL(l) if info.bindings isDefinedAt LocalVar(l) =>
val t = info.getBinding(l)
t match {
case Deref(This) | Const(_) =>
bb.replaceInstruction(i, valueToInstruction(t))
debuglog(s"replaced $i with $t")
case _ =>
val t = info.getAlias(l)
bb.replaceInstruction(i, LOAD_LOCAL(t))
debuglog(s"replaced $i with $t")
}
case LOAD_FIELD(f, false) /* if accessible(f, m.symbol) */ =>
def replaceFieldAccess(r: Record) {
val Record(cls, _) = r
info.getFieldNonRecordValue(r, f) foreach { v =>
bb.replaceInstruction(i, DROP(REFERENCE(cls)) :: valueToInstruction(v) :: Nil)
debuglog(s"replaced $i with $v")
}
}
info.stack(0) match {
case r @ Record(_, bindings) if bindings isDefinedAt f =>
replaceFieldAccess(r)
case Deref(LocalVar(l)) =>
info.getBinding(l) match {
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 UNBOX(boxType) =>
info.stack match {
case Deref(LocalVar(loc1)) :: _ if info.bindings isDefinedAt LocalVar(loc1) =>
val value = info.getBinding(loc1)
value match {
case Boxed(LocalVar(loc2)) if loc2.kind == boxType =>
bb.replaceInstruction(i, DROP(icodes.ObjectReference) :: valueToInstruction(info.getBinding(loc2)) :: Nil)
debuglog("replaced " + i + " with " + info.getBinding(loc2))
case _ =>
()
}
case Boxed(LocalVar(loc1)) :: _ if loc1.kind == boxType =>
val loc2 = info.getAlias(loc1)
bb.replaceInstruction(i, DROP(icodes.ObjectReference) :: valueToInstruction(Deref(LocalVar(loc2))) :: Nil)
debuglog("replaced " + i + " with " + LocalVar(loc2))
case _ =>
}
case _ =>
}
info = cpp.interpret(info, i)
}
}
}} catch {
case e: LubException =>
Console.println("In method: " + m)
Console.println(e)
e.printStackTrace
}
/* Partial mapping from values to instructions that load them. */
def valueToInstruction(v: Value): Instruction = (v: @unchecked) match {
case Deref(LocalVar(v)) =>
LOAD_LOCAL(v)
case Const(k) =>
CONSTANT(k)
case Deref(This) =>
THIS(definitions.ObjectClass)
case Boxed(LocalVar(v)) =>
LOAD_LOCAL(v)
}
} /* class ClosureElim */
/** Peephole optimization. */
abstract class PeepholeOpt {
/** Concrete implementations will perform their optimizations here */
def peep(bb: BasicBlock, i1: Instruction, i2: Instruction): Option[List[Instruction]]
var liveness: global.icodes.liveness.LivenessAnalysis = null
def apply(m: IMethod): Unit = if (m.hasCode) {
liveness = new global.icodes.liveness.LivenessAnalysis
liveness.init(m)
liveness.run()
m foreachBlock transformBlock
}
def transformBlock(b: BasicBlock): Unit = if (b.size >= 2) {
var newInstructions: List[Instruction] = b.toList
var redo = false
do {
var h = newInstructions.head
var t = newInstructions.tail
var seen: List[Instruction] = Nil
redo = false
while (t != Nil) {
peep(b, h, t.head) match {
case Some(newInstrs) =>
newInstructions = seen reverse_::: newInstrs ::: t.tail
redo = true
case None =>
()
}
seen = h :: seen
h = t.head
t = t.tail
}
} while (redo)
b fromList newInstructions
}
}
} /* class ClosureElimination */