inliners.scala

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

SCALA
505
字号
         }         inlinedBlock(bb).close       }       instrAfter.foreach(i => afterBlock.emit(i, i.pos));       afterBlock.close;       count += 1       // add exception handlers of the callee       caller.exh = (callee.exh map translateExh) ::: caller.exh;       assert(pending.isEmpty, "Pending NEW elements: " + pending)     }    def analyzeClass(cls: IClass): Unit = if (settings.inline.value) {      if (settings.debug.value)      	log("Analyzing " + cls);      cls.methods.foreach { m => if (!m.symbol.isConstructor) analyzeMethod(m)     }}    val tfa = new analysis.MethodTFA();    tfa.stat = settings.statistics.value    def analyzeMethod(m: IMethod): Unit = try {      var retry = false      var count = 0      fresh.clear      // how many times have we already inlined this method here?      val inlinedMethods: Map[Symbol, Int] = new HashMap[Symbol, Int] {        override def default(k: Symbol) = 0             }      do {        retry = false;        if (m.code ne null) {          if (settings.debug.value)            log("Analyzing " + m + " count " + count);          tfa.init(m)          tfa.run          for (bb <- linearizer.linearize(m)) {            var info = tfa.in(bb);            for (i <- bb.toList) {              if (!retry) {                i match {                  case CALL_METHOD(msym, Dynamic) =>                     val receiver = info.stack.types.drop(msym.info.paramTypes.length).head match {                      case REFERENCE(s) => s;                      case _ => NoSymbol;                    }                    var concreteMethod = msym;                    if (receiver != msym.owner && receiver != NoSymbol) {                       if (settings.debug.value)                        log("" + i + " has actual receiver: " + receiver);                    }                    if (!concreteMethod.isFinal && receiver.isFinal) {                      concreteMethod = lookupImpl(concreteMethod, receiver)                      if (settings.debug.value)                        log("\tlooked up method: " + concreteMethod.fullNameString)                    }                     if (receiver == definitions.PredefModule.moduleClass) {                      log("loading predef")                      icodes.icode(receiver, true)                    }                    if (settings.debug.value)                      log("Treating " + i                           + "\n\treceiver: " + receiver                          + "\n\ticodes.available: " + icodes.available(receiver)                          + "\n\tconcreteMethod.isFinal: " + concreteMethod.isFinal);                    if (   icodes.available(receiver)                         && (isClosureClass(receiver)                            || concreteMethod.isFinal                            || receiver.isFinal)) {                      icodes.icode(receiver).get.lookupMethod(concreteMethod) match {                        case Some(inc) =>                          if (inc.symbol != m.symbol                              && (inlinedMethods(inc.symbol) < 2)                              && (inc.code ne null)                              && shouldInline(m, inc)                              && isSafeToInline(m, inc, info.stack)) {                            retry = true;                            if (!isClosureClass(receiver)) // only count non-closures                                count = count + 1;                            inline(m, bb, i, inc);                            inlinedMethods(inc.symbol) = inlinedMethods(inc.symbol) + 1                            /* Remove this method from the cache, as the calls-private relation                               might have changed after the inlining. */                            callsPrivate -= m;                           } else {                            if (settings.debug.value)                              log("inline failed for " + inc + " because:\n\tinc.symbol != m.symbol: " + (inc.symbol != m.symbol)                                  + "\n\t(inlinedMethods(inc.symbol) < 2): " + (inlinedMethods(inc.symbol) < 2)                                  + "\n\tinc.code ne null: " + (inc.code ne null) + (if (inc.code ne null)                                    "\n\tisSafeToInline(m, inc, info.stack): " + isSafeToInline(m, inc, info.stack)                                    + "\n\tshouldInline heuristics: " + shouldInline(m, inc) else ""));                          }                        case None =>                          ();                      }                    }                  case _ => ();                }                info = tfa.interpret(info, i)              }}}        if (tfa.stat) log(m.symbol.fullNameString + " iterations: " + tfa.iterations + " (size: " + m.code.blocks.length + ")")      }} while (retry && count < 15)      m.normalize    } catch {      case e =>         Console.println("############# Cought exception: " + e + " #################");        Console.println("\nMethod: " + m +                         "\nMethod owner: " + m.symbol.owner);        e.printStackTrace();        m.dump        throw e    }        /** Cache whether a method calls private members. */    val callsPrivate: Map[IMethod, Boolean] = new HashMap;        def isRecursive(m: IMethod): Boolean = m.recursive        /** A method is safe to inline when:     *    - it does not contain calls to private methods when     *      called from another class     *    - it is not inlined into a position with non-empty stack,     *      while having a top-level finalizer (see liftedTry problem)     *    - it is not recursive     * Note:     *    - synthetic private members are made public in this pass.     */    def isSafeToInline(caller: IMethod, callee: IMethod, stack: TypeStack): Boolean = {      var callsPrivateMember = false      if (callee.recursive) return false            callsPrivate get (callee) match {        case Some(b) =>          callsPrivateMember = b        case None =>          for (b <- callee.code.blocks)            for (i <- b.toList)              i match {                case CALL_METHOD(m, style) =>                  if (m.hasFlag(Flags.PRIVATE) ||                       (style.isSuper && !m.isClassConstructor))                    callsPrivateMember = true;                case LOAD_FIELD(f, _) =>                  if (f.hasFlag(Flags.PRIVATE))                     if (f.hasFlag(Flags.SYNTHETIC) || f.hasFlag(Flags.PARAMACCESSOR)) {                      if (settings.debug.value)                        log("Making not-private symbol out of synthetic: " + f);                      f.setFlag(Flags.notPRIVATE)                    } else                      callsPrivateMember = true;                case STORE_FIELD(f, _) =>                  if (f.hasFlag(Flags.PRIVATE))                    if (f.hasFlag(Flags.SYNTHETIC) || f.hasFlag(Flags.PARAMACCESSOR)) {                      if (settings.debug.value)                        log("Making not-private symbol out of synthetic: " + f);                      f.setFlag(Flags.notPRIVATE)                    } else                      callsPrivateMember = true;                case _ => ()              }          callsPrivate += (callee -> callsPrivateMember)        }      if (callsPrivateMember && (caller.symbol.owner != callee.symbol.owner))        return false;      if (stack.length > (1 + callee.symbol.info.paramTypes.length) &&          callee.exh != Nil) {        if (settings.debug.value) log("method " + callee.symbol + " is used on a non-empty stack with finalizer.");        false      } else        true    }        private def lookupImpl(meth: Symbol, clazz: Symbol): Symbol = {      //println("\t\tlooking up " + meth + " in " + clazz.fullNameString + " meth.owner = " + meth.owner)      if (meth.owner == clazz           || clazz == definitions.AllRefClass           || clazz == definitions.AllClass) meth      else {        val implementingMethod = meth.overridingSymbol(clazz)         if (implementingMethod != NoSymbol)           implementingMethod        else if (meth.owner.isTrait)           meth        else          lookupImpl(meth, clazz.tpe.parents(0).typeSymbol)      }    }        /** small method size (in blocks) */    val SMALL_METHOD_SIZE = 4        /** Decide whether to inline or not. Heuristics:     *   - it's bad to make the caller larger (> SMALL_METHOD_SIZE)      *        if it was small     *   - it's bad to inline large methods     *   - it's good to inline higher order functions      *   - it's good to inline closures functions.      *   - it's bad (useless) to inline inside bridge methods     */    def shouldInline(caller: IMethod, callee: IMethod): Boolean = {       if (caller.symbol.hasFlag(Flags.BRIDGE)) return false;       if (callee.symbol.hasAttribute(ScalaNoInlineAttr)) return false       if (callee.symbol.hasAttribute(ScalaInlineAttr)) return true       if (settings.debug.value)         log("shouldInline: " + caller + " with " + callee)       var score = 0       if (callee.code.blocks.length <= SMALL_METHOD_SIZE) score = score + 1       if (caller.code.blocks.length <= SMALL_METHOD_SIZE            && ((caller.code.blocks.length + callee.code.blocks.length) > SMALL_METHOD_SIZE)) {         score -= 1         if (settings.debug.value)           log("shouldInline: score decreased to " + score + " because small " + caller + " would become large")       }       if (callee.code.blocks.length > MAX_INLINE_SIZE)         score -= 1                if (callee.symbol.tpe.paramTypes.exists(t => definitions.FunctionClass.contains(t.typeSymbol))) {         if (settings.debug.value)           log("increased score to: " + score)         score += 2       }       if (isClosureClass(callee.symbol.owner))         score += 2                score > 0     }  } /* class Inliner */      /** Is the given class a subtype of a function trait? */  def isClosureClass(cls: Symbol): Boolean = {    val res = cls.isFinal && cls.hasFlag(Flags.SYNTHETIC) &&        cls.tpe.parents.exists { t =>           val TypeRef(_, sym, _) = t;          definitions.FunctionClass exists sym.==        }    res  }} /* class Inliners */

⌨️ 快捷键说明

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