summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/transform/Mixin.scala
diff options
context:
space:
mode:
authorHubert Plociniczak <hubert.plociniczak@epfl.ch>2010-10-20 13:26:11 +0000
committerHubert Plociniczak <hubert.plociniczak@epfl.ch>2010-10-20 13:26:11 +0000
commit2014160121a62681bdc0e873a3f7e9b5e3bbae16 (patch)
tree5da2d4ad44f798bbf210f583139b302390ff8c8e /src/compiler/scala/tools/nsc/transform/Mixin.scala
parentadd9be644fd7b2864e4dcdd792980622622c934a (diff)
downloadscala-2014160121a62681bdc0e873a3f7e9b5e3bbae16.tar.gz
scala-2014160121a62681bdc0e873a3f7e9b5e3bbae16.tar.bz2
scala-2014160121a62681bdc0e873a3f7e9b5e3bbae16.zip
Closes #3059, #3895 (the only difference betwee...
Closes #3059, #3895 (the only difference between this and r23232 is the forced info transformation that ensures that nested objects are viewed as lazy vals). sbt integration requires new starr for this commit to work.
Diffstat (limited to 'src/compiler/scala/tools/nsc/transform/Mixin.scala')
-rw-r--r--src/compiler/scala/tools/nsc/transform/Mixin.scala130
1 files changed, 89 insertions, 41 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala
index 71472e1fcf..e1e4375378 100644
--- a/src/compiler/scala/tools/nsc/transform/Mixin.scala
+++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala
@@ -206,6 +206,9 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
/** Map a lazy, mixedin field accessor to it's trait member accessor */
val initializer = new mutable.HashMap[Symbol, Symbol]
+ /** Deferred bitmaps that will be added during the transformation of a class */
+ val deferredBitmaps: collection.mutable.Map[Symbol, List[Tree]] = new collection.mutable.HashMap[Symbol, List[Tree]]
+
/** Add all members to be mixed in into a (non-trait-) class
* These are:
* for every mixin trait T that is not also inherited by the superclass:
@@ -614,6 +617,11 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
else newDefs ::: stats.filter(isNotDuplicate)
}
+ def addDeferredBitmap(clazz: Symbol, tree: Tree) {
+ // Append the set of deffered defs
+ deferredBitmaps(clazz) = typedPos(clazz.pos)(tree)::deferredBitmaps.getOrElse(clazz, List())
+ }
+
/** If `stat' is a superaccessor, complete it by adding a right-hand side.
* Note: superaccessors are always abstract until this point.
* The method to call in a superaccessor is stored in the accessor symbol's alias field.
@@ -638,23 +646,64 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
import lazyVals._
- /** Return the bitmap field for 'offset', create one if not inheriting it already. */
- def bitmapFor(clazz: Symbol, offset: Int): Symbol = {
- var sym = clazz.info.member(nme.bitmapName(offset / FLAGS_PER_WORD))
- assert(!sym.hasFlag(OVERLOADED))
- if (sym == NoSymbol) {
- sym = clazz.newVariable(clazz.pos, nme.bitmapName(offset / FLAGS_PER_WORD))
+ /**
+ * Return the bitmap field for 'offset'. Depending on the hierarchy it is possible to reuse
+ * the bitmap of its parents. If that does not exist yet we create one.
+ */
+ def bitmapFor(clazz0: Symbol, offset: Int, searchParents:Boolean = true): Symbol = {
+ def createBitmap: Symbol = {
+ val sym = clazz0.newVariable(clazz0.pos, nme.bitmapName(offset / FLAGS_PER_WORD))
.setInfo(IntClass.tpe)
.setFlag(PROTECTED)
atPhase(currentRun.typerPhase) {
sym addAnnotation AnnotationInfo(VolatileAttr.tpe, Nil, Nil)
}
- clazz.info.decls.enter(sym)
- addDef(clazz.pos, VAL(sym) === ZERO)
+ clazz0.info.decls.enter(sym)
+ if (clazz0 == clazz)
+ addDef(clazz.pos, VAL(sym) === ZERO)
+ else
+ addDeferredBitmap(clazz0, VAL(sym) === ZERO)
+ sym
+ }
+ var sym = clazz0.info.member(nme.bitmapName(offset / FLAGS_PER_WORD))
+ assert(!sym.hasFlag(OVERLOADED))
+ if (sym == NoSymbol) {
+ if (searchParents)
+ bitmapForParents(clazz0, offset) match {
+ case Some(bitmap) =>
+ sym = bitmap
+ case None =>
+ sym = createBitmap
+ }
+ else
+ sym = createBitmap
}
+ //assert(sym != NoSymbol)
sym
}
+ def bitmapForParents(clazz0: Symbol, offset: Int): Option[Symbol] = {
+ def requiredBitmaps(fs: Int): Int = if (fs == 0) -1 else (fs - 1) / FLAGS_PER_WORD
+
+ var res:Option[Symbol] = None
+ val bitmapNum = offset / FLAGS_PER_WORD
+
+ // on what else should we filter?
+ for (cl <- clazz0.info.baseClasses.tail.filter(c => !c.isTrait && !c.hasFlag(JAVA))
+ if res == None) {
+ val fields0 = usedBits(cl)
+
+ if (requiredBitmaps(fields0) < bitmapNum) {
+ val fields1 = cl.info.decls.filter(fieldWithBitmap).size
+ if (requiredBitmaps(fields0 + fields1) >= bitmapNum)
+ // assert(cl.sourceFile != null)
+ res = Some(bitmapFor(cl, offset, false))
+ else return None // Don't waste time, since we won't find bitmap anyway
+ }
+ }
+ res
+ }
+
/** Return an (untyped) tree of the form 'Clazz.this.bmp = Clazz.this.bmp | mask'. */
def mkSetFlag(clazz: Symbol, offset: Int): Tree = {
val bmp = bitmapFor(clazz, offset)
@@ -705,7 +754,6 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
Select(This(clazz), sym1) === LIT(null)
}
-
val bitmapSym = bitmapFor(clazz, offset)
val mask = LIT(1 << (offset % FLAGS_PER_WORD))
def cond = mkTest(clazz, mask, bitmapSym, true)
@@ -734,10 +782,6 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
* the class constructor is changed to set the initialized bits.
*/
def addCheckedGetters(clazz: Symbol, stats: List[Tree]): List[Tree] = {
- // TODO: not used?
- def findLazyAssignment(stats: List[Tree]): Tree = (
- for (s @ Assign(lhs, _) <- stats ; if lhs.symbol hasFlag LAZY) yield s
- ) head // if there's no assignment then it's a bug and we crash
val stats1 = for (stat <- stats; sym = stat.symbol) yield stat match {
case DefDef(mods, name, tp, vp, tpt, rhs)
@@ -818,50 +862,54 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
}.transform(rhs)
}
- /** Return the number of bits used by superclass fields.
- * This number is a conservative approximation of what is actually used:
- * - fields initialized to the default value don't get a checked initializer
- * but there is no way to recover this information from types alone.
- */
- def usedBits(clazz: Symbol): Int = {
- def isField(sym: Symbol) =
- sym.hasFlag(PRIVATE) && sym.isTerm && !sym.isMethod
-
- def needsBitmapField(sc: Type, field: Symbol) =
- !sc.typeSymbol.isTrait &&
- field.owner != clazz &&
- (settings.checkInit.value && isField(field) ||
- field.hasFlag(LAZY))
-
- // parents != baseClasses.map(_.tpe): bug #1535
- val fields = for {
- sc <- clazz.info.baseClasses.map(_.tpe)
- field <- sc.decls.iterator.toList
- if needsBitmapField(sc, field)
- } yield field
-
- if (settings.debug.value) log("Found inherited fields in " + clazz + " : " + fields)
- fields.length
+ def fieldWithBitmap(field: Symbol) = {
+ field.info // ensure that nested objects are tranformed
+ // For checkinit consider normal value getters
+ // but for lazy values only take into account lazy getters
+ (needsInitFlag(field) || field.hasFlag(LAZY) && field.isMethod) && !field.isDeferred
}
+ /**
+ * Return the number of bits used by superclass fields.
+ */
+ def usedBits(clazz0: Symbol): Int = {
+ def needsBitmap(field: Symbol) =
+ field.owner != clazz0 &&
+ fieldWithBitmap(field)
+
+ val fs = for {
+ cl <- clazz0.info.baseClasses.tail.filter(cl => !cl.isTrait && !cl.hasFlag(JAVA))
+ field <- cl.info.decls.iterator.toList if needsBitmap(field)
+ } yield field
+ fs.length
+ }
+
/** Fill the map from fields to offset numbers.
* Instead of field symbols, the map keeps their getter symbols. This makes
* code generation easier later.
*/
- def buildFieldPositions(clazz: Symbol) {
- var fields = usedBits(clazz)
- for (f <- clazz.info.decls.iterator if needsInitFlag(f) || f.hasFlag(LAZY)) {
+ def buildFieldPositions(clazz0: Symbol) {
+ var fields = usedBits(clazz0)
+ for (f <- clazz0.info.decls.iterator if fieldWithBitmap(f)) {
if (settings.debug.value) log(f.fullName + " -> " + fields)
+
fieldOffset(f) = fields
fields += 1
}
}
- buildFieldPositions(clazz)
// begin addNewDefs
+ buildFieldPositions(clazz)
var stats1 = addCheckedGetters(clazz, stats)
+ // add deffered bitmaps
+ deferredBitmaps.remove(clazz) match {
+ case Some(deferred) =>
+ stats1 = add(stats1, deferred)
+ case None =>
+ }
+
// for all symbols `sym' in the class definition, which are mixed in:
for (sym <- clazz.info.decls.toList) {
if (sym hasFlag MIXEDIN) {