summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/backend/icode/Members.scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler/scala/tools/nsc/backend/icode/Members.scala')
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/Members.scala241
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();
+ }
+
+}