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 + -
显示快捷键?