pickler.scala

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

SCALA
963
字号
/* NSC -- new Scala compiler * Copyright 2005-2007 LAMP/EPFL * @author  Martin Odersky */// $Id: Pickler.scala 14135 2008-02-26 10:02:33Z odersky $package scala.tools.nsc.symtab.classfileimport java.lang.{Float, Double}import scala.tools.nsc.util.{Position, NoPosition, ShowPickled}import Flags._import PickleFormat._/** * Serialize a top-level module and/or class. * * @see <code>EntryTags.scala</code> for symbol table attribute format. * * @author Martin Odersky * @version 1.0 */abstract class Pickler extends SubComponent {  import global._  val phaseName = "pickler"  def newPhase(prev: Phase): StdPhase = new PicklePhase(prev)  class PicklePhase(prev: Phase) extends StdPhase(prev) {    def apply(unit: CompilationUnit) {      def pickle(tree: Tree) {        def add(sym: Symbol, pickle: Pickle) = {          if (currentRun.compiles(sym) && !currentRun.symData.contains(sym)) {            if (settings.debug.value) log("pickling " + sym)            pickle.putSymbol(sym)            currentRun.symData(sym) = pickle          }        }        tree match {          case PackageDef(_, stats) =>            stats foreach pickle          case ClassDef(_, _, _, _) | ModuleDef(_, _, _) =>            val sym = tree.symbol            val pickle = new Pickle(sym, sym.name.toTermName, sym.owner)            add(sym, pickle)            add(sym.linkedSym, pickle)            pickle.finish            val doPickleHash = global.doPickleHash            if (doPickleHash) {              var i = 0              while (i < pickle.writeIndex) {                unit.pickleHash += pickle.bytes(i).toLong // toLong needed to work around bug                i += 1              }            }          case _ =>        }      }      pickle(unit.body)    }  }  private class Pickle(root: Symbol, rootName: Name, rootOwner: Symbol)        extends PickleBuffer(new Array[Byte](4096), -1, 0) {    import scala.collection.jcl.LinkedHashMap    private var entries = new Array[AnyRef](256)    private var ep = 0    private val index = new LinkedHashMap[AnyRef, Int]    /** Is symbol an existentially bound variable with a package as owner?      *  Such symbols should be treated as if they were local.     */    private def isUnrootedExistential(sym: Symbol) =       sym.isAbstractType && sym.hasFlag(EXISTENTIAL) && sym.owner.isPackageClass     private def normalizedOwner(sym: Symbol) =       if (isUnrootedExistential(sym)) root else sym.owner    /** Is root in symbol.owner*?     *     *  @param sym ...     *  @return    ...     */    private def isLocal(sym: Symbol): Boolean =      sym.isRefinementClass ||      sym.name.toTermName == rootName && sym.owner == rootOwner ||      sym != NoSymbol && isLocal(sym.owner) ||      isUnrootedExistential(sym)    // Phase 1 methods: Populate entries/index ------------------------------------    /** Store entry <code>e</code> in index at next available position unless     *  it is already there.     *     *  @param entry ...     *  @return      <code>true</code> iff entry is new.     */    private def putEntry(entry: AnyRef): Boolean = index.get(entry) match {      case Some(_) => false      case None =>        if (ep == entries.length) {          val entries1 = new Array[AnyRef](ep * 2)          Array.copy(entries, 0, entries1, 0, ep)          entries = entries1        }        entries(ep) = entry        index(entry) = ep        ep = ep + 1        true    }    /** Store symbol in <code>index</code>. If symbol is local, also store     * everything it refers to.     *     *  @param sym ...     */    def putSymbol(sym: Symbol) {      if (putEntry(sym)) {        if (isLocal(sym)) {          putEntry(sym.name)          putSymbol(sym.owner)          putSymbol(sym.privateWithin)          putType(sym.info)          if (sym.thisSym.tpeHK != sym.tpeHK)            putType(sym.typeOfThis);          putSymbol(sym.alias)          if (!sym.children.isEmpty) {            val (locals, globals) = sym.children.toList.partition(_.isLocalClass)            val children =               if (locals.isEmpty) globals              else {                val localChildDummy = sym.newClass(sym.pos, nme.LOCALCHILD)                localChildDummy.setInfo(ClassInfoType(List(sym.tpe), EmptyScope, localChildDummy))                localChildDummy :: globals              }            putChildren(sym, children.sort((x, y) => x isLess y))          }          for (attr <- sym.attributes.reverse) {            if (attr.atp.typeSymbol isNonBottomSubClass definitions.StaticAnnotationClass)              putAnnotation(sym, attr)          }        } else if (sym != NoSymbol) {          putEntry(if (sym.isModuleClass) sym.name.toTermName else sym.name)          if (!sym.owner.isRoot) putSymbol(sym.owner)        }      }    }    private def putSymbols(syms: List[Symbol]) =      syms foreach putSymbol    /** Store type and everythig it refers to in map <code>index</code>.     *     *  @param tp ...     */    private def putType(tp: Type): Unit = if (putEntry(tp)) {      tp match {        case NoType | NoPrefix | DeBruijnIndex(_, _) =>          ;        case ThisType(sym) =>          putSymbol(sym)        case SingleType(pre, sym) =>          putType(pre); putSymbol(sym)        case ConstantType(value) =>	  putConstant(value)        case TypeRef(pre, sym, args) =>          putType(pre); putSymbol(sym); putTypes(args)        case TypeBounds(lo, hi) =>          putType(lo); putType(hi)        case RefinedType(parents, decls) =>          val rclazz = tp.typeSymbol          for (m <- decls.elements)            if (m.owner != rclazz) assert(false, "bad refinement member "+m+" of "+tp+", owner = "+m.owner)          putSymbol(rclazz); putTypes(parents); putSymbols(decls.toList)        case ClassInfoType(parents, decls, clazz) =>          putSymbol(clazz); putTypes(parents); putSymbols(decls.toList)        case MethodType(formals, restpe) =>          putType(restpe); putTypes(formals)        case PolyType(tparams, restpe) =>          putType(restpe); putSymbols(tparams)        case ExistentialType(tparams, restpe) =>          putType(restpe); putSymbols(tparams)        case AnnotatedType(attribs, tp, selfsym) =>          putType(tp); putAnnotations(attribs)	  if (settings.selfInAnnots.value) putSymbol(selfsym)        case _ =>          throw new FatalError("bad type: " + tp + "(" + tp.getClass + ")")      }    }    private def putTypes(tps: List[Type]) { tps foreach putType }    private def putTree(tree: Tree): Unit = if (putEntry(tree)) {      if (tree != EmptyTree)	putType(tree.tpe)      if (tree.hasSymbol)	putSymbol(tree.symbol)      tree match {	case EmptyTree =>	case tree@PackageDef(name, stats) =>	  putEntry(name)          putTrees(stats)	case ClassDef(mods, name, tparams, impl) =>	  putMods(mods)	  putEntry(name)          putTree(impl)	  putTrees(tparams)	  	case ModuleDef(mods, name, impl) =>	  putMods(mods)	  putEntry(name)	  putTree(impl)  	case ValDef(mods, name, tpt, rhs) =>	  putMods(mods)	  putEntry(name)	  putTree(tpt)	  putTree(rhs)		case DefDef(mods, name, tparams, vparamss, tpt, rhs) =>	  putMods(mods)	  putEntry(name)	  putTrees(tparams)	  putTreess(vparamss)	  putTree(tpt)	  putTree(rhs)  	case TypeDef(mods, name, tparams, rhs) =>	  putMods(mods)	  putEntry(name)	  putTree(rhs)	  putTrees(tparams)	case LabelDef(name, params, rhs) =>	  putTree(rhs)	  putTrees(params)	case Import(expr, selectors) =>	  putTree(expr)	  for ((from,to) <- selectors) {	    putEntry(from)	    putEntry(to)	  }	case Annotation(constr, elements) =>                            	  putTree(constr)	  putTrees(elements)	case DocDef(comment, definition) =>	  putConstant(Constant(comment))	  putTree(definition)	case Template(parents, self, body) =>          writeNat(parents.length)	  putTrees(parents)	  putTree(self)	  putTrees(body)	case Block(stats, expr) =>	  putTree(expr)	  putTrees(stats)	case CaseDef(pat, guard, body) =>	  putTree(pat)	  putTree(guard)	  putTree(body)	case Sequence(trees) =>	  putTrees(trees)	case Alternative(trees) =>	  putTrees(trees)	case Star(elem) =>	  putTree(elem)	case Bind(name, body) =>	  putEntry(name)	  putTree(body)	case UnApply(fun: Tree, args) =>	  putTree(fun)	  putTrees(args)	case ArrayValue(elemtpt, trees) =>	  putTree(elemtpt)	  putTrees(trees)	case Function(vparams, body) =>	  putTree(body)	  putTrees(vparams)	case Assign(lhs, rhs) =>	  putTree(lhs)	  putTree(rhs)	case If(cond, thenp, elsep) =>	  putTree(cond)	  putTree(thenp)	  putTree(elsep)	case Match(selector, cases) =>	  putTree(selector)	  putTrees(cases)	case Return(expr) =>	  putTree(expr)	case Try(block, catches, finalizer) =>	  putTree(block)	  putTree(finalizer)	  putTrees(catches)	case Throw(expr) =>	  putTree(expr)	case New(tpt) =>	  putTree(tpt)  	case Typed(expr, tpt) =>	  putTree(expr)	  putTree(tpt)	case TypeApply(fun, args) =>	  putTree(fun)	  putTrees(args)	  	case Apply(fun, args) =>	  putTree(fun)	  putTrees(args)	case ApplyDynamic(qual, args) =>	  writeEntry(qual)	  putTrees(args)	case Super(qual, mix) =>	  putEntry(qual:Name)	  putEntry(mix:Name)        case This(qual) =>	  putEntry(qual)        case Select(qualifier, selector) =>	  putTree(qualifier)	  putEntry(selector)	case Ident(name) =>	  putEntry(name)	case Literal(value) =>	  putEntry(value)	case TypeTree() =>	case Annotated(annot, arg) =>	  putTree(annot)	  putTree(arg)	case SingletonTypeTree(ref) =>	  putTree(ref)	case SelectFromTypeTree(qualifier, selector) =>	  putTree(qualifier)	  putEntry(selector)	case CompoundTypeTree(templ: Template) =>	  putTree(templ)	case AppliedTypeTree(tpt, args) =>	  putTree(tpt)	  putTrees(args)	case TypeBoundsTree(lo, hi) =>	  putTree(lo)	  putTree(hi)	case ExistentialTypeTree(tpt, whereClauses) =>	  putTree(tpt)	  putTrees(whereClauses)      }    }    private def putTrees(trees: List[Tree]) =      trees.foreach(putTree _)    private def putTreess(treess: List[List[Tree]]) =      treess.foreach(putTrees _)    private def putMods(mods: Modifiers) = if (putEntry(mods)) {      val Modifiers(flags, privateWithin, annotations) = mods      putEntry(privateWithin)      putTrees(annotations)    }    /** Store a constant in map <code>index</code> along with     *  anything it references.     */    private def putConstant(c: Constant) =      if (putEntry(c)) {        if (c.tag == StringTag) putEntry(newTermName(c.stringValue))        else if (c.tag == ClassTag) putEntry(c.typeValue)      }    private def putChildren(sym: Symbol, children: List[Symbol]) {      assert(putEntry((sym, children)))      children foreach putSymbol    }    private def putAnnotation(sym: Symbol, annot: AnnotationInfo) {      assert(putEntry((sym, annot)))      val AnnotationInfo(atp, args, assocs) = annot      putType(atp)      args foreach putAnnotationArg      for ((name, c) <- assocs) { putEntry(name); putAnnotationArg(c) }    }    private def putAnnotation(annot: AnnotationInfo) {      if (putEntry(annot)) {        val AnnotationInfo(tpe, args, assocs) = annot        putType(tpe)        args foreach putAnnotationArg        for ((name, rhs) <- assocs) { putEntry(name); putAnnotationArg(rhs) }      }    }        private def putAnnotationArg(arg: AnnotationArgument) {      if (putEntry(arg)) {        arg.constant match {	  case Some(c) => putConstant(c)	  case _ => putTree(arg.intTree)	}      }    }    private def putAnnotations(annots: List[AnnotationInfo]) {      annots foreach putAnnotation    }    // Phase 2 methods: Write all entries to byte array ------------------------------    private val buf = new PickleBuffer(new Array[Byte](4096), -1, 0)    /** Write a reference to object, i.e., the object's number in the map     *  <code>index</code>.     *     *  @param ref ...     */    private def writeRef(ref: AnyRef) { writeNat(index(ref)) }    private def writeRefs(refs: List[AnyRef]) { refs foreach writeRef }    /** Write name, owner, flags, and info of a symbol.     *     *  @param sym ...     *  @return    the position offset     */    private def writeSymInfo(sym: Symbol): Int = {      var posOffset = 0      writeRef(sym.name)      writeRef(normalizedOwner(sym))      writeNat((sym.flags & PickledFlags).asInstanceOf[Int])      if (sym.privateWithin != NoSymbol) writeRef(sym.privateWithin)      writeRef(sym.info)      posOffset    }    /** Write a name in UTF8 format. */    def writeName(name: Name) {      ensureCapacity(name.length * 3)      writeIndex = name.copyUTF8(bytes, writeIndex)    }    /** Write an entry */    private def writeEntry(entry: AnyRef) {      def writeBody(entry: AnyRef): Int = entry match {

⌨️ 快捷键说明

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