inliners.scala

来自「JAVA 语言的函数式编程扩展」· SCALA 代码 · 共 505 行 · 第 1/2 页

SCALA
505
字号
/* NSC -- new Scala compiler * Copyright 2005-2008 LAMP/EPFL * @author  Iulian Dragos */// $Id: Inliners.scala 14416 2008-03-19 01:17:25Z mihaylov $package scala.tools.nsc.backend.optimport scala.collection.mutable.{Map, HashMap, Set, HashSet}import scala.tools.nsc.symtab._/** *  @author Iulian Dragos */abstract class Inliners extends SubComponent {  import global._  import icodes._  import icodes.opcodes._  val phaseName = "inliner"  /** The maximum size in basic blocks of methods considered for inlining. */  final val MAX_INLINE_SIZE = 16    /** Create a new phase */  override def newPhase(p: Phase) = new InliningPhase(p)  /** The Inlining phase.   */  class InliningPhase(prev: Phase) extends ICodePhase(prev) {    def name = phaseName    val inliner = new Inliner    override def apply(c: IClass) {      inliner.analyzeClass(c)    }  }  /**    * Simple inliner.   *   */  class Inliner {    val fresh = new HashMap[String, Int]        /* fresh name counter */    var count = 0        def freshName(s: String) = fresh.get(s) match {      case Some(count) =>        fresh(s) = count + 1        s + count      case None =>        fresh(s) = 1        s + "0"    }        lazy val ScalaInlineAttr   = definitions.getClass("scala.inline")    lazy val ScalaNoInlineAttr = definitions.getClass("scala.noinline")    /** Inline the 'callee' method inside the 'caller' in the given      *  basic block, at the given instruction (which has to be a CALL_METHOD).     */    def inline(caller: IMethod,               block:  BasicBlock,               instr:  Instruction,               callee: IMethod) {       log("Inlining " + callee + " in " + caller + " at pos: " +            (try {             instr.pos.offset.get                        } catch {             case _ => "<nopos>"           }));       val targetPos = instr.pos       val a = new analysis.MethodTFA(callee)       /* The exception handlers that are active at the current block. */       val activeHandlers = caller.exh.filter(_.covered.contains(block))       /* Map 'original' blocks to the ones inlined in the caller. */       val inlinedBlock: Map[BasicBlock, BasicBlock] = new HashMap              val varsInScope: Set[Local] = new HashSet[Local] ++ block.varsInScope.elements       val instrBefore = block.toList.takeWhile {         case i @ SCOPE_ENTER(l) => varsInScope += l           i ne instr         case i =>           i ne instr       }       val instrAfter  = block.toList.drop(instrBefore.length + 1);       assert(!instrAfter.isEmpty, "CALL_METHOD cannot be the last instrcution in block!");       // store the '$this' into the special local       val inlinedThis = new Local(caller.symbol.newVariable(instr.pos, freshName("$inlThis")), REFERENCE(definitions.ObjectClass), false);       /** buffer for the returned value */       val retVal =          if (callee.returnType != UNIT)           new Local(caller.symbol.newVariable(instr.pos, freshName("$retVal")), callee.returnType, false);         else            null;       /** Add a new block in the current context. */       def newBlock = {         val b = caller.code.newBlock         activeHandlers.foreach (_.addCoveredBlock(b))         if (retVal ne null) b.varsInScope += retVal         b.varsInScope += inlinedThis         b.varsInScope ++= varsInScope         b       }       def translateExh(e: ExceptionHandler) = {         var handler: ExceptionHandler = e.dup         handler.covered = handler.covered.map(inlinedBlock)         handler.setStartBlock(inlinedBlock(e.startBlock))         handler       }              var inlinedLocals: Map[Local, Local] = new HashMap              /** alfa-rename `l' in caller's context. */       def dupLocal(l: Local): Local = {         val sym = caller.symbol.newVariable(l.sym.pos, freshName(l.sym.name.toString()));//         sym.setInfo(l.sym.tpe);         val dupped = new Local(sym, l.kind, false)         inlinedLocals(l) = dupped         dupped       }       def addLocals(m: IMethod, ls: List[Local]) =          m.locals = m.locals ::: ls;       def addLocal(m: IMethod, l: Local): Unit =          addLocals(m, List(l));       val afterBlock = newBlock;              /** Map from nw.init instructions to their matching NEW call */       val pending: collection.jcl.Map[Instruction, NEW] = new collection.jcl.HashMap              /** Map an instruction from the callee to one suitable for the caller. */       def map(i: Instruction): Instruction = {         val newInstr = i match {           case THIS(clasz) =>             LOAD_LOCAL(inlinedThis);           case JUMP(whereto) =>             JUMP(inlinedBlock(whereto));           case CJUMP(success, failure, cond, kind) =>             CJUMP(inlinedBlock(success), inlinedBlock(failure), cond, kind);           case CZJUMP(success, failure, cond, kind) =>             CZJUMP(inlinedBlock(success), inlinedBlock(failure), cond, kind);           case SWITCH(tags, labels) =>             SWITCH(tags, labels map inlinedBlock);           case RETURN(kind) =>             JUMP(afterBlock);           case LOAD_LOCAL(l) if inlinedLocals.isDefinedAt(l) =>              LOAD_LOCAL(inlinedLocals(l))           case STORE_LOCAL(l) if inlinedLocals.isDefinedAt(l) =>              STORE_LOCAL(inlinedLocals(l))                        case LOAD_LOCAL(l) =>             assert(caller.locals contains l,                  "Could not find local '" + l + "' in locals, nor in inlinedLocals: " + inlinedLocals)             i           case STORE_LOCAL(l) =>             assert(caller.locals contains l,                  "Could not find local '" + l + "' in locals, nor in inlinedLocals: " + inlinedLocals)             i                        case SCOPE_ENTER(l) if inlinedLocals.isDefinedAt(l) =>             SCOPE_ENTER(inlinedLocals(l))           case SCOPE_EXIT(l) if inlinedLocals.isDefinedAt(l) =>             SCOPE_EXIT(inlinedLocals(l))           case nw @ NEW(sym) =>             val r = NEW(sym)             pending(nw.init) = r             r                        case CALL_METHOD(meth, Static(true)) if (meth.isClassConstructor) =>             CALL_METHOD(meth, Static(true))                        case _ => i         }         // check any pending NEW's         if (pending isDefinedAt i) {           pending(i).init = newInstr.asInstanceOf[CALL_METHOD]           pending -= i         }         newInstr       }       addLocals(caller, callee.locals map dupLocal);       addLocal(caller, inlinedThis);       if (retVal ne null)         addLocal(caller, retVal);       callee.code.blocks.foreach { b =>          inlinedBlock += (b -> newBlock)          inlinedBlock(b).varsInScope ++= (b.varsInScope map inlinedLocals)       }       // analyse callee       a.run       // re-emit the instructions before the call       block.open       block.clear       instrBefore.foreach(i => block.emit(i, i.pos))       // store the arguments into special locals       callee.params.reverse.foreach { param =>         block.emit(STORE_LOCAL(inlinedLocals(param)), targetPos);       }       block.emit(STORE_LOCAL(inlinedThis), targetPos);       // jump to the start block of the callee       block.emit(JUMP(inlinedBlock(callee.code.startBlock)), targetPos);       block.close       // duplicate the other blocks in the callee       linearizer.linearize(callee).foreach { bb =>          var info = a.in(bb);         bb traverse { i =>            i match {             case RETURN(kind) => kind match {                 case UNIT =>                   if (!info.stack.types.isEmpty) {                     info.stack.types foreach { t => inlinedBlock(bb).emit(DROP(t), targetPos); }                   }                 case _ =>                   if (info.stack.length > 1) {                     inlinedBlock(bb).emit(STORE_LOCAL(retVal), targetPos);                     info.stack.types.drop(1) foreach { t => inlinedBlock(bb).emit(DROP(t), targetPos); }                     inlinedBlock(bb).emit(LOAD_LOCAL(retVal), targetPos);                   }               }             case _ => ();           }           inlinedBlock(bb).emit(map(i), targetPos);           info = a.interpret(info, i);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?