|
Scala example source code file (Detach.scala)
The Scala Detach.scala source code/* NSC -- new Scala compiler * Copyright 2005-2011 LAMP/EPFL * @author Stephane Micheloud */ package scala.tools.detach import scala.collection.immutable import scala.collection.mutable.{HashMap, HashSet, ListBuffer} import scala.tools.nsc._ import scala.tools.nsc.plugins.PluginComponent import scala.tools.nsc.symtab.Flags._ import scala.tools.nsc.transform._ abstract class Detach extends PluginComponent with Transform with TypingTransformers { import global._ import definitions._ /** the following two members override abstract members in Transform */ val phaseName: String = "detach" protected def newTransformer(unit: CompilationUnit): Transformer = new DetachTransformer(unit) // set with the `-P:detach:enable` plugin option (see DetachPlugin) */ protected[detach] var isEnabled = false private class DetachTransformer(unit: CompilationUnit) extends TypingTransformer(unit) { private val DEBUG = settings.debug.value private val PROXY_PREFIX = "proxy$" // local proxy objects private val PROXY_SUFFIX = "$proxy" // top-level proxy classes private val DETACH_SUFFIX = "$detach" // detached closures private val IMPL_SUFFIX = "Impl" // follows Java convention private val nme_bind = newTermName("bind") private val nme_unbind = newTermName("unbind") private val nme_unreferenced = newTermName("unreferenced") private val Functions = FunctionClass.toList // see method isFuncType private val RemoteClass = definitions.getClass("java.rmi.Remote") private val UIDClass = definitions.getClass("java.rmi.server.UID") private val UnicastRemoteObjectClass = definitions.getClass("java.rmi.server.UnicastRemoteObject") private val UnreferencedClass = definitions.getClass("java.rmi.server.Unreferenced") private val DetachModule = definitions.getModule("scala.remoting.detach") private val DebugModule = definitions.getModule("scala.remoting.Debug") private val RemoteRefModule = definitions.getModule("scala.runtime.RemoteRef") private val ThreadModule = definitions.getModule("java.lang.Thread") private val UnicastRemoteObjectModule = definitions.getModule("java.rmi.server.UnicastRemoteObject") private val remoteAnnotationInfo = { val RemoteAttr: Symbol = definitions.getClass("scala.remote") AnnotationInfo(RemoteAttr.tpe, List(), List()) } private val serializableAnnotationInfo = AnnotationInfo(SerializableAttr.tpe, List(), List()) /* private val throwsAnnotationInfo = { val RemoteExceptionClass = definitions.getClass("java.rmi.RemoteException") val ThrowsAttr = definitions.getClass("scala.throws") AnnotationInfo( ThrowsAttr.tpe, List(Literal(Constant(RemoteExceptionClass.tpe))), List() ) } */ // todo: see generation of Java version UID private def serialVersionUIDAnnotationInfo(clazz: Symbol) = { def genHash(sym: Symbol): Long = { val sym1 = if (sym.isConstructor) sym.owner else sym val ts = sym.tpe match { case MethodType(params, rt) => (params map (_.tpe)) ::: List(rt) case t => List(t) } val hashes = sym1.nameString.hashCode :: (ts map (_.typeSymbol.nameString.hashCode)) (0L /: hashes)((acc, h) => acc ^ h) } val hashes = for (sym <- clazz.info.decls.toList) yield genHash(sym) val uid: Long = (0L /: hashes) ((acc, h) => acc * 41 + h) val serialVersionUIDAttr = definitions.getClass("scala.SerialVersionUID") AnnotationInfo( serialVersionUIDAttr.tpe, List(Literal(Constant(uid))), List() ) } private def elems(suffix: String): List[(Symbol, Symbol)] = for (clazz <- ObjectRefClass :: refClass.valuesIterator.toList) yield { val name = "scala.runtime.remoting.Remote" + clazz.name + suffix (clazz, definitions.getClass(name)) } private val remoteRefClass = immutable.HashMap(elems(""): _*) private val remoteRefImpl = immutable.HashMap(elems("Impl"): _*) private val proxyInterfaceDefs = new HashMap[Symbol/*owner*/, ListBuffer[Tree]] private val detachedClosureApply = new HashMap[Tree, Apply] private type SymSet = HashSet[Symbol] private val capturedObjects = new HashMap[Symbol/*clazz*/, SymSet] private val capturedFuncs = new HashMap[Symbol/*clazz*/, SymSet] private val capturedCallers = new HashMap[Symbol/*clazz*/, SymSet] private val capturedThisClass = new HashMap[Symbol, Symbol] private val proxies = new HashMap[ Symbol, //clazz (Symbol, Symbol, HashMap[Symbol, Symbol]) //iface, impl, accessor map ] def toInterface(clazz: Symbol) = proxies(clazz)._1 private val classdefs = new HashMap[Symbol/*clazz*/, ClassDef] // detachedClosure gathers class definitions containing a "detach" apply private val detachedClosure = new HashMap[Symbol/*clazz*/, ClassDef] /** <p> * The method <code>freeObjTraverser.traverse is invoked * in the method <code>DetachPlugin.transformUnit in order to * gather information about objects referenced inside a detached * closure and which will be accessed remotely through object proxies. * </p> * <p> * Object proxies are generated in method <code>mkClosureApply * and their definitions are generated in method <code>genProxy. * </p> */ private val freeObjTraverser = new Traverser { def symSet(f: HashMap[Symbol, SymSet], sym: Symbol): SymSet = f.get(sym) match { case Some(ss) => ss case None => val ss = new HashSet[Symbol]; f(sym) = ss; ss } def getClosureApply(tree: Tree): Apply = tree match { case Block(_, expr) => getClosureApply(expr) case Typed(expr, _) => getClosureApply(expr) case apply @ Apply(Select(_, _), _) => apply // sel="<init>" or some "f$0" case Apply(fun, _) => getClosureApply(fun) case _ => throw new Error("getClosureApply: unhandled case " + tree) } def isFuncType(tp: Type): Boolean = tp match { case TypeRef(pre, sym, args) => Functions contains sym.tpe.typeSymbol case _ => false } def isOuterMember(sym: Symbol): Boolean = sym.isOuterAccessor || sym.name.endsWith(nme.OUTER/*, nme.OUTER.length*/) override def traverse(tree: Tree) { val sym = tree.symbol val owner = if (currentOwner.isModule) currentOwner else currentOwner.enclClass tree match { case cdef @ ClassDef(_, _, _, impl) => classdefs(sym) = cdef super.traverse(impl) if (detachedClosure contains sym) { detachedClosure(sym) = cdef symSet(capturedObjects, sym) += capturedThisClass(sym) } case Apply(Select(qual, _), List(arg)) if (qual.tpe <:< DetachModule.tpe) => assert(isFuncType(arg.tpe))//debug val t = getClosureApply(arg) if (!t.fun.symbol.isConstructor) unit.error(t.pos, "detach inapplicable for " +t.fun.symbol) val sym = t.fun.symbol.owner capturedThisClass(sym) = owner symSet(capturedFuncs, sym) detachedClosureApply(tree) = t classdefs get sym match { case None => detachedClosure(sym) = null // set later in case ClassDef case Some(cdef) => detachedClosure(sym) = cdef symSet(capturedObjects, sym) += capturedThisClass(sym) } super.traverse(arg) case Select(qual @ This(_), name) if qual.symbol.isModuleClass && !qual.symbol.isPackageClass => val qsym = qual.symbol symSet(capturedFuncs, owner) += sym symSet(capturedObjects, owner) += qsym case Select(qual, name) if (qual.hasSymbol && (sym.owner != owner) && !(sym.ownerChain contains ScalaPackageClass) && !(sym.owner hasFlag JAVA)) => val qsym = qual.symbol symSet(capturedFuncs, owner) += sym if (qsym.isStaticModule && !qsym.isPackage) { //println("*****1******* capturedObjects("+owner+") += "+qsym) symSet(capturedObjects, owner) += qsym } else if (!isOuterMember(qsym) && !(qsym isNestedIn owner)) { //println("*****3******* capturedCallers("+sym+") += "+qsym) symSet(capturedCallers, sym) += qsym } case _ => super.traverse(tree) } } } //freeObjTraverser private val valueClass = immutable.HashMap( (for ((sym, ref) <- refClass.toList) yield (ref, sym)): _* ) + (ObjectRefClass -> ObjectClass) private def toValueClass(tp: Type): Type = if (isRefClass(tp)) valueClass(tp.typeSymbol).tpe else if (proxies contains tp.typeSymbol) toInterface(tp.typeSymbol).tpe else tp private def isRefClass(tp: Type): Boolean = (tp ne null) && ((refClass.valuesIterator contains tp.typeSymbol) || (ObjectRefClass eq tp.typeSymbol)) private def isRemoteRefClass(tp: Type): Boolean = (tp ne null) && (remoteRefClass.valuesIterator contains tp.typeSymbol) private def mkRemoteRefClass(tp: Type): Type = { assert(isRefClass(tp)) val tp1 = remoteRefClass(tp.typeSymbol) typeRef(tp1.typeConstructor.prefix, tp1, Nil) // after erasure, no type anymore! } class TreeOuterSubstituter(from: List[Symbol], to: List[Symbol]) extends Traverser { if (DEBUG) println("\nTreeOuterSubstituter:"+ "\n\tfrom="+from.mkString(",")+ "\n\tto="+to.mkString(",")) val substMap = new HashMap[Symbol, Symbol] override def traverse(tree: Tree) { def subst(from: List[Symbol], to: List[Symbol]) { if (!from.isEmpty) if (tree.symbol.tpe == from.head.tpe) { if (DEBUG) println("\nTreeOuterSubstituter\n\tsym="+tree.symbol+ ", tpe="+tree.symbol.tpe+ "\n\towner="+tree.symbol.owner) tree.symbol updateInfo to.head.tpe } else tree.symbol.tpe match { case MethodType(params, restp) => for (p <- params if p.tpe == from.head.tpe) { p updateInfo to.head.tpe } if (restp == from.head.tpe) { if (DEBUG) println("\nTreeOuterSubstituter(2)\n\tsym="+tree.symbol+ ", tpe="+tree.symbol.tpe+ ", owner="+tree.symbol.owner) tree.symbol updateInfo MethodType(params, to.head.tpe) } case _ => subst(from.tail, to.tail) } } def isOuter(sym: Symbol): Boolean = sym.isOuterAccessor || sym.name.endsWith(nme.OUTER/*, nme.OUTER.length*/) if (tree.hasSymbol && isOuter(tree.symbol)) subst(from, to) super.traverse(tree) } } // based on class Trees.TreeTypeSubstituter private class TreeTypeRefSubstituter(clazz: Symbol) extends Traverser { override def traverse(tree: Tree) { val sym = tree.symbol if (tree.hasSymbol && isRefClass(sym.tpe) && (sym.owner.enclClass == clazz) && (sym.isValueParameter || sym.hasFlag(PARAMACCESSOR))) { sym setInfo mkRemoteRefClass(sym.tpe) tree.tpe = sym.tpe } if (isRefClass(tree.tpe)) tree.tpe = mkRemoteRefClass(tree.tpe) super.traverse(tree) } override def apply[T <: Tree](tree: T): T = super.apply(tree) } private class TreeOwnerSubstituter(from: Symbol, to: Symbol) extends Traverser { def substType(sym: Symbol): Type = { def subst(tpe: Type): Type = tpe match { case MethodType(params, restp) => println("TreeOwnerSubstituter[1]: tpe="+tpe+ ", tpe.typeSymbol="+tpe.typeSymbol+", sym="+sym)//debug for (p <- params if p.tpe == from.tpe) { println("TreeOwnerSubstituter[2]: sym="+sym+ ", sym.owner="+sym.owner+", p.tpe="+p.tpe)//debug p updateInfo to.tpe } MethodType(params, subst(restp)) case _ => if (sym.owner == from && tpe == from.tpe) { println("TreeOwnerSubstituter[3]: sym="+sym+ ", owner="+sym.owner+", tpe="+tpe)//debug to.tpe } else tpe } subst(sym.tpe) } val map = new HashMap[Symbol, Symbol] override def traverse(tree: Tree) { if (tree.hasSymbol && tree.symbol != NoSymbol) { val sym = tree.symbol if (sym.owner == from) { val sym1 = map get sym match { case Some(s) => s case None => val s = sym.cloneSymbol(to); map(sym) = s; s } tree setSymbol sym1 } val sym1 = tree.symbol val tp = substType(sym1) if (tp != sym1.tpe) { if (sym1.owner == to) println("\n%%%%%1%%%%%%% TreeOwnerSubst: tree="+tree+", sym1="+sym1+", sym1.owner="+sym1.owner)//debug sym1 setInfo tp tree setSymbol sym1 } } super.traverse(tree) } //override def apply[T <: Tree](tree: T): T = super.apply(tree/*.duplicate*/) } private var inConstructorFlag = 0L private def isCaptured(clazz: Symbol, sym: Symbol): Boolean = if (capturedFuncs contains clazz) { //log("**1** isCaptured: clazz="+clazz+", sym="+sym+", ") capturedFuncs(clazz) contains sym } else { //log("**2** isCaptured: clazz="+clazz+", sym="+sym) sym.isMethod && !sym.isConstructor } private class TreeAccessorSubstituter(clazz: Symbol, objs: List[Symbol], proxySyms: List[Symbol]) extends Transformer { def removeAccessors(tree: Tree): Tree = tree match { case Apply(fun, _) => removeAccessors(fun) case Select(qual, _) if tree.hasSymbol && tree.symbol.isOuterAccessor => removeAccessors(qual) case _ => tree } if (DEBUG) println("\nTreeAccessorSubstituter: "+ "\n\tobjs="+objs.mkString(",")+ "\n\tproxies="+proxySyms.mkString(",")) override def transform(tree: Tree): Tree = tree match { // transforms field assignment $outer.i$1.elem=.. // into setter $outer.i$1_=(..) case Assign(lhs @ Select(qual1 @ Select(qual, name), name1), rhs) if qual1.hasSymbol && !qual1.symbol.isPrivateLocal && isRemoteRefClass(qual1.tpe) => if (DEBUG) println("\nTreeAccessorSubstituter: Assign1\n\tqual1="+qual1+", sel.tpe="+lhs.tpe+ "\n\tqual1.tpe="+qual1.tpe+", name1="+name1+ "\n\tqual.tpe="+qual.tpe+", tree.tpe="+tree.tpe)//debug val iface = toInterface(qual.tpe.typeSymbol) val sym = iface.tpe.decls lookup nme.getterToSetter(name) atPos(tree.pos)(Apply( Select(super.transform(qual), sym) setType lhs.tpe, List(super.transform(rhs)) ) setType tree.tpe) // transforms local assignment this.x$1.elem=.. // into setter method this.x$1_=(..) case Assign(lhs @ Select(qual, name), rhs) if qual.hasSymbol && qual.symbol.isPrivateLocal && isRemoteRefClass(qual.tpe) => if (DEBUG) println("\nTreeAccessorSubstituter: Assign2"+ "\n\tqual="+qual+", qual.tpe="+qual.tpe+ "\n\tname="+name) // substitute the 'elem' member of the reference class with // the corresponding setter method of the remote reference class. val qual1 = super.transform(qual) val sym = qual1.tpe.decls lookup nme.getterToSetter(name) val fun = gen.mkAttributedSelect(qual1, sym) Apply(fun, List(super.transform(rhs))) setType lhs.tpe case Assign(Select(qual, name), rhs) if qual.hasSymbol && (objs contains qual.symbol) => val sym = qual.symbol val proxy = proxySyms(objs indexOf sym) if (DEBUG) println("\nTreeAccessorSubstituter: Assign3"+ "\n\tqual="+qual+", qual.tpe="+qual.tpe+ "\n\tproxy="+proxy+", proxy.tpe="+proxy.tpe+ "\n\tname="+name)//debug // substitute the member accessor of the enclosing class with // the corresponding setter method of the detached interface. val iface = toInterface(sym) val substSymbols = new TreeSymSubstituter( sym.info.decls.toList filter { isCaptured(sym, _) }, iface.info.decls.toList) substSymbols(Apply( Select(Ident(proxy), nme.getterToSetter(name)), List(super.transform(rhs)))) // transforms setter invocation this.i$1_=(..) // into setter invocation $outer.i$1_=(..) case Apply(Select(qual @ This(_), name), args) if (objs contains qual.symbol) && nme.isSetterName(name) => val proxy = proxySyms(objs indexOf qual.symbol) if (DEBUG) println("\nTreeAccessorSubstituter: Apply"+ "\n\tqual="+qual+", qual.tpe="+qual.tpe+ "\n\tproxy="+proxy+", proxy.tpe="+proxy.tpe+ "\n\tname="+name+", decoded="+name.decode) val qual1 = gen.mkAttributedSelect(gen.mkAttributedThis(proxy.owner), proxy) val sym1 = proxy.info.decls lookup name.decode val fun = gen.mkAttributedSelect(qual1, sym1) Apply(fun, args map (super.transform(_))) setType tree.tpe // transforms access to field this.name$1 // into invocation of getter method $outer.name$1() case Select(qual @ This(_), name) if objs contains qual.symbol => val proxy = proxySyms(objs indexOf qual.symbol) if (DEBUG) println("\nTreeAccessorSubstituter: Select"+ "\n\tqual="+qual+", qual.tpe="+qual.tpe+ "\n\tproxy="+proxy+", proxy.tpe="+proxy.tpe+ "\n\tname="+name+", decoded="+name.decode) val qual1 = gen.mkAttributedSelect(gen.mkAttributedThis(proxy.owner), proxy) val sym1 = proxy.info.decls lookup nme.originalName(name) //name gen.mkAttributedSelect(qual1, sym1) // transforms field $outer.name$1 into getter method $outer.name$1() case Select(qual @ Select(_, name1), name) if qual.hasSymbol && name1.endsWith(nme.OUTER/*, nme.OUTER.length*/) && !tree.symbol.isMethod => if (DEBUG) println("\nTreeAccessorSubstituter: Select0\n\tqual="+qual+ ", qual.tpe="+qual.tpe+", name="+name)//debug val sym = qual.symbol val qual1 = gen.mkAttributedSelect(gen.mkAttributedThis(sym.owner), sym) val iface = toInterface(qual.tpe.typeSymbol) val sym1 = iface.tpe.decls lookup name val fun = gen.mkAttributedSelect(qual1, sym1) Apply(fun, List()) setType tree.tpe case Select(apply @ Apply(fun @ Select(qual, _), _), name) if fun.symbol.isOuterAccessor => val tsym = fun.symbol.tpe.resultType.typeSymbol val funcs = capturedFuncs(clazz).toList filter (sym => (tsym.ownerChain contains sym.owner) || (tsym isSubClass sym.owner)) if (DEBUG) println("\nTreeAccessorSubstituter: Select1\n\tfun="+fun+ ",\n\tfun.tpe="+fun.tpe+", name="+name+ ",\n\tfuncs="+funcs)//debug funcs find (tree.symbol.==) match { case Some(sym) => val qual1 = if (currentOwner.enclClass isNestedIn clazz) apply else removeAccessors(qual) val name1 = (if (tsym isSubClass qual1.tpe.typeSymbol) "" else tsym.fullName('$')+"$")+sym.name val iface = toInterface(qual1.tpe.typeSymbol) val sym1 = iface.tpe.decls lookup name1 gen.mkAttributedSelect(qual1, sym1) case None => super.transform(tree) } // transforms field access $outer.i$1.elem // into invocation of getter method $outer.i$1() case Select(qual @ Select(qual1, name1), name) if qual.hasSymbol && !qual.symbol.isPrivateLocal && isRemoteRefClass(qual.tpe) => if (DEBUG) println("\nTreeAccessorSubstituter: Select2\n\tqual="+qual+ "\n\tqual.tpe="+qual.tpe+", tree.tpe="+tree.tpe)//debug val iface = toInterface(qual.symbol.owner) val sym1 = iface.tpe.decls lookup name1 val fun = gen.mkAttributedSelect(qual1, sym1) Apply(fun, List()) setType tree.tpe // transforms local access this.i$1.elem // into invocation of getter method this.i$1() case Select(qual, name) if qual.hasSymbol && qual.symbol.isPrivateLocal && isRemoteRefClass(qual.tpe) => if (DEBUG) println("\nTreeAccessorSubstituter: Select3\n\tqual="+qual+ "\n\tqual.tpe="+qual.tpe)//debug val sym = qual.tpe.decls lookup name val fun = gen.mkAttributedSelect(qual, sym) Apply(fun, List()) setType tree.tpe case Select(qual, name) if qual.hasSymbol && (objs contains qual.symbol) => if (DEBUG) println("\nTreeAccessorSubstituter: Select4\n\tqual="+qual+ ", qual.tpe="+qual.tpe+", name="+name)//debug val sym = qual.symbol val proxy = proxySyms(objs indexOf sym) // substitute the accessor of a member of the enclosing class // with the corresponding accessor of the detached interface val qual1 = gen.mkAttributedSelect(gen.mkAttributedThis(proxy.owner), proxy) val iface = toInterface(sym) val sym1 = iface.tpe.decls lookup name.decode gen.mkAttributedSelect(qual1, sym1) case _ => super.transform(tree) } def apply[T <: Tree](tree: T): T = transform(tree).asInstanceOf[T] } // TreeAccessorSubstituter /* private class TreeNameSubstituter(from: Name, to: Symbol) extends Transformer { override def transform(tree: Tree): Tree = tree match { case Super(qual, mix) if tree.symbol.name == from => Super(qual, mix) setSymbol to case This(name) if name == from => This(to.name) setSymbol to case _ => super.transform(tree) } def apply[T <: Tree](tree: T): T = transform(tree).asInstanceOf[T] } */ /** <p> * Given the closure definition (generated by previous phases) * </p>* class $anonfun$1 extends Object with Function1 { * def this($outer: C, x$1: Int): $anonfun$1 = .. * def apply(x: Int): Int = x + this.$outer.x() + this.x$1 * }</pre> * <p> * the method <code>mkClosureDef transforms the above code * to the following: * </p>* @serializable * class $anonfun$1$detach extends Object with Function1 { * def this($outer: C$proxy, x$1: Int): $anonfun$1$detach = .. * def apply(x: Int): Int = x + this.$outer.x() + this.x$1 * }</pre> * <p> * In particular, it performs the following operations: * 1) add constructor parameter <code>proxy_n to access * proxy of the enclosing class * 2) change reference types in constructor arguments to type * <code |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.