lazyvals.scala
来自「JAVA 语言的函数式编程扩展」· SCALA 代码 · 共 164 行
SCALA
164 行
package scala.tools.nsc.transform;import scala.tools.nsc._import scala.collection.mutable.HashMapabstract class LazyVals extends Transform { // inherits abstract value `global' and class `Phase' from Transform import global._ // the global environment import definitions._ // standard classes and methods import typer.{typed, atOwner} // methods to type trees import posAssigner.atPos // for filling in tree positions val phaseName: String = "lazyvals" def newTransformer(unit: CompilationUnit): Transformer = new LazyValues(unit) /** Create a new phase which applies transformer */ override def newPhase(prev: scala.tools.nsc.Phase): StdPhase = new Phase(prev) /** The phase defined by this transform */ class Phase(prev: scala.tools.nsc.Phase) extends StdPhase(prev) { def apply(unit: global.CompilationUnit): Unit = newTransformer(unit).transformUnit(unit); } /** * Transform local lazy accessors to check for the initialized bit. */ class LazyValues(unit: CompilationUnit) extends Transformer { import definitions.{Int_And, Int_Or, Int_==} /** map from method symbols to the number of lazy values it defines. */ private val lazyVals = new HashMap[Symbol, Int] { override def default(meth: Symbol) = 0 } import symtab.Flags._ import lazyVals._ /** Perform the following transformations: * - for a lazy accessor inside a method, make it check the initialization bitmap * - for all methods, add enough int vars to allow one flag per lazy local value * - remove ACCESSOR flags: accessors in traits are not statically implemented, * but moved to the host class. local lazy values should be statically implemented. */ override def transform(tree: Tree): Tree = { val sym = tree.symbol tree match { case DefDef(mods, name, tparams, vparams, tpt, rhs) => val res = if (!sym.owner.isClass && sym.hasFlag(LAZY)) { val idx = lazyVals(sym.enclMethod) val rhs1 = mkLazyDef(sym.enclMethod, super.transform(rhs), idx) lazyVals(sym.owner) = idx + 1 sym.resetFlag(LAZY | ACCESSOR) rhs1 } else super.transform(rhs) val bmps = bitmaps(sym) map { b => ValDef(b, Literal(Constant(0))) } val tmp = addBitmapDefs(sym, res, bmps) copy.DefDef(tree, mods, name, tparams, vparams, tpt, typed(addBitmapDefs(sym, res, bmps))) case _ => super.transform(tree) } } /** Add the bitmap definitions to the rhs of a method definition. * If the rhs has been tail-call trasnformed, insert the bitmap * definitions inside the top-level label definition, so that each * iteration has the lazy values un-initialized. Otherwise add them * at the very beginning of the method. */ private def addBitmapDefs(methSym: Symbol, rhs: Tree, bmps: List[Tree]): Tree = { if (bmps.isEmpty) rhs else rhs match { case Block(assign, l @ LabelDef(name, params, rhs1)) if (name.toString.equals("_" + methSym.name) && List.forall2(params.tail, methSym.tpe.paramTypes) { (ident, tpe) => ident.tpe == tpe }) => val sym = l.symbol Block(assign, copy.LabelDef(l, name, params, typed(Block(bmps, rhs1)))) case _ => Block(bmps, rhs) } } /** return a 'lazified' version of rhs. Rhs should conform to the * following schema: * { * l$ = <rhs> * l$ * } or * <rhs> when the lazy value has type Unit (for which there is no field * to cache it's value. * * The result will be a tree of the form * { * if ((bitmap$n & MASK) == 0) { * l$ = <rhs> * bitmap$n = bimap$n | MASK * } * l$ * } * where bitmap$n is an int value acting as a bitmap of initialized values. It is * the 'n' is (offset / 32), the MASK is (1 << (offset % 32)). If the value has type * unit, no field is used to chache the value, so the resulting code is: * { * if ((bitmap$n & MASK) == 0) { * <rhs>; * bitmap$n = bimap$n | MASK * } * () * } */ private def mkLazyDef(meth: Symbol, tree: Tree, offset: Int): Tree = { val bitmapSym = getBitmapFor(meth, offset) val mask = Literal(Constant(1 << (offset % FLAGS_PER_WORD))) val (block, res) = tree match { case Block(List(assignment), res) => (Block(List(assignment, mkSetFlag(bitmapSym, mask)), Literal(Constant(()))), res) case rhs => assert(meth.tpe.finalResultType.typeSymbol == definitions.UnitClass) (Block(List(rhs, mkSetFlag(bitmapSym, mask)), Literal(Constant(()))), Literal(())) } val result = atPos(tree.pos) { If(Apply( Select( Apply(Select(Ident(bitmapSym), Int_And), List(mask)), Int_==), List(Literal(Constant(0)))), block, EmptyTree) } typed(Block(List(result), res)) } private def mkSetFlag(bmp: Symbol, mask: Tree): Tree = Assign(Ident(bmp), Apply(Select(Ident(bmp), Int_Or), List(mask))) final val FLAGS_PER_WORD = 32 val bitmaps = new HashMap[Symbol, List[Symbol]] { override def default(meth: Symbol) = Nil } /** Return the symbol corresponding of the right bitmap int inside meth, * given offset. */ private def getBitmapFor(meth: Symbol, offset: Int): Symbol = { val n = offset / FLAGS_PER_WORD val bmps = bitmaps(meth) if (bmps.length > n) bmps(n) else { val sym = meth.newVariable(meth.pos, nme.bitmapName(n)).setInfo(IntClass.tpe) bitmaps(meth) = (sym :: bmps).reverse sym } } }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?