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