scala.tools.nsc.backend.icode.Linearizers.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 Martin Odersky
*/
package scala
package tools.nsc
package backend
package icode
import scala.collection.{ mutable, immutable }
import mutable.ListBuffer
trait Linearizers {
self: ICodes =>
import global.debuglog
import opcodes._
abstract class Linearizer {
def linearize(c: IMethod): List[BasicBlock]
def linearizeAt(c: IMethod, start: BasicBlock): List[BasicBlock]
}
/**
* A simple linearizer which predicts all branches to
* take the 'success' branch and tries to schedule those
* blocks immediately after the test. This is in sync with
* how 'while' statements are translated (if the test is
* 'true', the loop continues).
*/
class NormalLinearizer extends Linearizer with WorklistAlgorithm {
type Elem = BasicBlock
val worklist: WList = new mutable.Stack()
var blocks: List[BasicBlock] = Nil
def linearize(m: IMethod): List[BasicBlock] = {
val b = m.startBlock
blocks = Nil
run {
worklist pushAll (m.exh map (_.startBlock))
worklist.push(b)
}
blocks.reverse
}
def linearizeAt(m: IMethod, start: BasicBlock): List[BasicBlock] = {
blocks = Nil
worklist.clear()
linearize(start)
}
/** Linearize another subtree and append it to the existing blocks. */
def linearize(startBlock: BasicBlock): List[BasicBlock] = {
//blocks = startBlock :: Nil;
run( { worklist.push(startBlock); } )
blocks.reverse
}
def processElement(b: BasicBlock) =
if (b.nonEmpty) {
add(b)
b.lastInstruction match {
case JUMP(whereto) =>
add(whereto)
case CJUMP(success, failure, _, _) =>
add(success)
add(failure)
case CZJUMP(success, failure, _, _) =>
add(success)
add(failure)
case SWITCH(_, labels) =>
add(labels)
case RETURN(_) => ()
case THROW(clasz) => ()
}
}
def dequeue: Elem = worklist.pop()
/**
* Prepend b to the list, if not already scheduled.
* TODO: use better test than linear search
*/
def add(b: BasicBlock) {
if (blocks.contains(b))
()
else {
blocks = b :: blocks
worklist push b
}
}
def add(bs: List[BasicBlock]): Unit = bs foreach add
}
/**
* Linearize code using a depth first traversal.
*/
class DepthFirstLinerizer extends Linearizer {
var blocks: List[BasicBlock] = Nil
def linearize(m: IMethod): List[BasicBlock] = {
blocks = Nil
dfs(m.startBlock)
m.exh foreach (b => dfs(b.startBlock))
blocks.reverse
}
def linearizeAt(m: IMethod, start: BasicBlock): List[BasicBlock] = {
blocks = Nil
dfs(start)
blocks.reverse
}
def dfs(b: BasicBlock): Unit =
if (b.nonEmpty && add(b))
b.successors foreach dfs
/**
* Prepend b to the list, if not already scheduled.
* TODO: use better test than linear search
* @return Returns true if the block was added.
*/
def add(b: BasicBlock): Boolean =
!(blocks contains b) && {
blocks = b :: blocks
true
}
}
/**
* Linearize code in reverse post order. In fact, it does
* a post order traversal, prepending visited nodes to the list.
* This way, it is constructed already in reverse post order.
*/
class ReversePostOrderLinearizer extends Linearizer {
var blocks: List[BasicBlock] = Nil
val visited = new mutable.HashSet[BasicBlock]
val added = new mutable.BitSet
def linearize(m: IMethod): List[BasicBlock] = {
blocks = Nil
visited.clear()
added.clear()
m.exh foreach (b => rpo(b.startBlock))
rpo(m.startBlock)
// if the start block has predecessors, it won't be the first one
// in the linearization, so we need to enforce it here
if (m.startBlock.predecessors eq Nil)
blocks
else
m.startBlock :: (blocks.filterNot(_ == m.startBlock))
}
def linearizeAt(m: IMethod, start: BasicBlock): List[BasicBlock] = {
blocks = Nil
visited.clear()
added.clear()
rpo(start)
blocks
}
def rpo(b: BasicBlock): Unit =
if (b.nonEmpty && !visited(b)) {
visited += b
b.successors foreach rpo
add(b)
}
/**
* Prepend b to the list, if not already scheduled.
* @return Returns true if the block was added.
*/
def add(b: BasicBlock) = {
debuglog("Linearizer adding block " + b.label)
if (!added(b.label)) {
added += b.label
blocks = b :: blocks
}
}
}
/** A 'dump' of the blocks in this method, which does not
* require any well-formedness of the basic blocks (like
* the last instruction being a jump).
*/
class DumpLinearizer extends Linearizer {
def linearize(m: IMethod): List[BasicBlock] = m.blocks
def linearizeAt(m: IMethod, start: BasicBlock): List[BasicBlock] = sys.error("not implemented")
}
}