diff options
Diffstat (limited to 'src/compiler/scala/tools/nsc/backend/icode/Members.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/icode/Members.scala | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/icode/Members.scala b/src/compiler/scala/tools/nsc/backend/icode/Members.scala new file mode 100644 index 0000000000..f12c4ef62c --- /dev/null +++ b/src/compiler/scala/tools/nsc/backend/icode/Members.scala @@ -0,0 +1,241 @@ +/* NSC -- new scala compiler + * Copyright 2005 LAMP/EPFL + * @author Martin Odersky + */ + +// $Id$ + +package scala.tools.nsc.backend.icode; + +import scala.collection.mutable.HashMap; +import scala.collection.mutable.{Set, HashSet}; +import scala.{Symbol => scala_Symbol}; + +import scala.tools.nsc.symtab.Flags; + +trait Members: ICodes { + import global._; + + /** + * This class represents the intermediate code of a method or + * other multi-block piece of code, like exception handlers. + */ + class Code(label: String) { + + /** The set of all blocks */ + val blocks: HashSet[BasicBlock] = new HashSet; + + /** The start block of the method */ + var startBlock: BasicBlock = null; + + /** The stack produced by this method */ + var producedStack: TypeStack = null; + + private var currentLabel: int = 0; + + // Constructor code + startBlock = newBlock; + startBlock.initStack(new TypeStack); + + + def removeBlock(b: BasicBlock) = { + if (settings.debug.value) { + assert(blocks.forall(p => !(p.successors.contains(b))), + "Removing block that is still referenced in method code " + label); + if (b == startBlock) + assert(b.successors.length == 1, + "Removing start block with more than one successor."); + } + + 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) + } + + def traverse(f: BasicBlock => Unit) = blocks 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.elements.map(x => Pair(x, false)); + + var blockToVisit : List[BasicBlock] = startBlock::Nil; + + while (!blockToVisit.isEmpty) { + blockToVisit match { + case b::xs => + if (!visited(b)) { + f(b, visited); + blockToVisit = b.successors ::: xs; + visited += b -> true; + } else + blockToVisit = xs; + } + } + } + + /** This methods returns a string representation of the ICode */ + override def toString() : String = "ICode '" + label + "'"; + + /** This method print the code */ +// def print() : unit = print(System.out); + +// def print(out: java.io.PrintStream) : unit = { +// traverse((bb: BasicBlock) => { +// out.println("Block #" + bb.label); +// out.println("Substituable variables : "); +// if (bb.substituteVars != null) +// bb.substituteVars.foreach(out.print); +// else +// out.println(" {Empty} "); +// out.println("Instructions:"); +// bb.traverse((ici: Instruction) => +// out.println(" "+ici.toString())); +// out.print ("Successors: "); +// bb.successors.foreach((bb: BasicBlock) => out.print(bb.label+", ")); +// out.println (""); // ?? Del +// out.println (); +// }); +// } + + /* Compute a unique new label */ + def nextLabel = { + currentLabel = currentLabel + 1; + currentLabel; + } + + /* Create a new block and append it to the list + */ + def newBlock: BasicBlock = { + val block = new BasicBlock(nextLabel, this); + blocks += block; + block; + } + } + + /** Represent a class in ICode */ + class IClass(val symbol: Symbol) { + var fields: List[IField] = Nil; + var methods: List[IMethod] = Nil; + var cunit: CompilationUnit = _; + + def addField(f: IField): this.type = { + fields = f :: fields; + this + } + + def addMethod(m: IMethod): this.type = { + methods = m :: methods; + this + } + + def setCompilationUnit(unit: CompilationUnit): this.type = { + this.cunit = unit; + this + } + + override def toString() = symbol.fullNameString; + + def lookupField(s: Symbol) = fields find ((f) => f.symbol == s); + } + + /** Represent a field in ICode */ + class IField(val symbol: Symbol) { + } + + /** + * Represents a method in ICode. Local variables contain + * both locals and parameters, similar to the way the JVM + * 'sees' them. + * + * Locals and parameters are added in reverse order, as they + * are kept in cons-lists. The 'builder' is responsible for + * reversing them and putting them back, when the generation is + * finished (GenICode does that). + */ + class IMethod(val symbol: Symbol) { + var code: Code = null; + var exh: List[ExceptionHandler] = Nil; + var sourceFile: String = _; + var returnType: TypeKind = _; + + /** local variables and method parameters */ + var locals: List[Local] = Nil; + + /** method parameters */ + var params: List[Local] = Nil; + + def setCode(code: Code): IMethod = { + this.code = code; + this + } + + def addLocal(l: Local): Unit = + if (!(locals contains l)) + locals = l :: locals; + + def addLocals(ls: List[Local]): Unit = + ls foreach addLocal; + + def addParam(p: Local): Unit = + if (!(params contains p)) { + params = p :: params; + locals = p :: locals; + } + + def addParams(as: List[Local]): Unit = + as foreach addParam; + + def lookupLocal(n: Name): Option[Local] = + locals find ((l) => l.sym.name == n); + + def lookupLocal(sym: Symbol): Option[Local] = + locals find ((l) => l.sym == sym); + + def addHandler(e: ExceptionHandler): Unit = + exh = e :: exh; + + /** Is this method deferred ('abstract' in Java sense) */ + def isDeferred = ( + symbol.hasFlag(Flags.DEFERRED) || + symbol.owner.hasFlag(Flags.INTERFACE) + ); + + override def toString() = symbol.fullNameString; + } + + /** Represent local variables and parameters */ + class Local(val sym: Symbol, val kind: TypeKind) { + var index: Int = -1; + + override def equals(other: Any): Boolean = ( + other.isInstanceOf[Local] && + other.asInstanceOf[Local].sym == this.sym + ); + + override def toString(): String = sym.toString(); + } + +} |