summaryrefslogblamecommitdiff
path: root/sources/scala/tools/nsc/backend/icode/Members.scala
blob: 35fe48bcbefc1f1955d44514728f6072adbd198a (plain) (tree)
1
2
3
4
5
6
7
8
9
10









                                        
                                               
                                      
 

                                    

                       
 


                                                               












                                                  




                                        














                                                                                  






















                                                                                  
























                                                                                    


















                                                                               
 







                                                   

                                                  
























                                                                



                                                                    





                                    









                                                                 

                                     
                                          
                               
                                 

                                                
                                  

                            
                                  





                                        


                                  
 
                                          

                          



                                  
       
 
                                          

                          




                                                 



                                               



                                                             

                                                    
   











                                                     
 
/* 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();
  }

}