diff options
author | Martin Odersky <odersky@gmail.com> | 2015-07-01 15:28:11 +0200 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2015-07-06 17:46:44 +0200 |
commit | 64f65182f6e4f80b03d45923e02441dafe0755b4 (patch) | |
tree | 68301908a5ce6513b43a9778a1f41b8e48bdbadf /src/dotty/tools/dotc/transform/CheckReentrant.scala | |
parent | 70f18eb4aa5aff64aa8571c16026c456bc1db5fc (diff) | |
download | dotty-64f65182f6e4f80b03d45923e02441dafe0755b4.tar.gz dotty-64f65182f6e4f80b03d45923e02441dafe0755b4.tar.bz2 dotty-64f65182f6e4f80b03d45923e02441dafe0755b4.zip |
Add reentrancy checking
New miniphase CheckRentrant verifies that compiled program is
without vars accessible through global roots if -Ycheck-reentrant
option is set.
Known shortcoming: Array elements are currently not considered as vars. This
is because in many programs arrays are used as an efficient container
for immutable fields.
Diffstat (limited to 'src/dotty/tools/dotc/transform/CheckReentrant.scala')
-rw-r--r-- | src/dotty/tools/dotc/transform/CheckReentrant.scala | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/src/dotty/tools/dotc/transform/CheckReentrant.scala b/src/dotty/tools/dotc/transform/CheckReentrant.scala new file mode 100644 index 000000000..aff8a1e7b --- /dev/null +++ b/src/dotty/tools/dotc/transform/CheckReentrant.scala @@ -0,0 +1,85 @@ +package dotty.tools.dotc +package transform + +import core._ +import Names._ +import dotty.tools.dotc.transform.TreeTransforms.{AnnotationTransformer, TransformerInfo, MiniPhaseTransform, TreeTransformer} +import ast.Trees._ +import Flags._ +import Types._ +import Constants.Constant +import Contexts.Context +import Symbols._ +import SymDenotations._ +import Decorators._ +import dotty.tools.dotc.core.Annotations.ConcreteAnnotation +import dotty.tools.dotc.core.Denotations.SingleDenotation +import scala.collection.mutable +import DenotTransformers._ +import typer.Checking +import Names.Name +import NameOps._ +import StdNames._ +import util.CtxLazy + + +/** The first tree transform + * - ensures there are companion objects for all classes except module classes + * - eliminates some kinds of trees: Imports, NamedArgs + * - stubs out native methods + */ +class CheckReentrant extends MiniPhaseTransform { thisTransformer => + import ast.tpd._ + + override def phaseName = "checkReentrant" + + def transformInfo(tp: Type, sym: Symbol)(implicit ctx: Context): Type = tp + + private var shared: Set[Symbol] = Set() + + private var seen: Set[ClassSymbol] = Set() + + private var indent: Int = 0 + + private val sharableAnnot = new CtxLazy(implicit ctx => + ctx.requiredClass("dotty.tools.sharable")) + private val unsharedAnnot = new CtxLazy(implicit ctx => + ctx.requiredClass("dotty.tools.unshared")) + + def isIgnored(sym: Symbol)(implicit ctx: Context) = + sym.hasAnnotation(sharableAnnot()) || + sym.hasAnnotation(unsharedAnnot()) + + def scanning(sym: Symbol)(op: => Unit)(implicit ctx: Context): Unit = { + println(i"${" " * indent}scanning $sym") + indent += 1 + try op + finally indent -= 1 + } + + def addVars(cls: ClassSymbol)(implicit ctx: Context): Unit = { + if (!seen.contains(cls) && !isIgnored(cls)) { + seen += cls + scanning(cls) { + for (sym <- cls.classInfo.decls) + if (sym.isTerm && !sym.isSetter && !isIgnored(sym)) + if (sym.is(Mutable)) { + println(i"GLOBAL ${sym.showLocated}: ${sym.info} <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<") + shared += sym + } else if (!sym.is(Method) || sym.is(Accessor | ParamAccessor)) { + scanning(sym) { + sym.info.widenExpr.classSymbols.foreach(addVars) + } + } + for (parent <- cls.classInfo.classParents) + addVars(parent.symbol.asClass) + } + } + } + + override def transformTemplate(tree: Template)(implicit ctx: Context, info: TransformerInfo): Tree = { + if (ctx.settings.YcheckReentrant.value && tree.symbol.owner.isStaticOwner) + addVars(tree.symbol.owner.asClass) + tree + } +}
\ No newline at end of file |