summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala1
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeDSL.scala6
-rw-r--r--src/compiler/scala/tools/nsc/transform/Constructors.scala5
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala3
-rw-r--r--src/compiler/scala/tools/nsc/transform/LazyVals.scala13
-rw-r--r--src/compiler/scala/tools/nsc/transform/Mixin.scala94
-rw-r--r--test/files/run/t3569.check2
7 files changed, 84 insertions, 40 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 8c6c927640..08cb931947 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -534,7 +534,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb
// phaseName = "lazyvals"
object lazyVals extends {
- final val FLAGS_PER_WORD = 32
val global: Global.this.type = Global.this
val runsAfter = List("erasure")
val runsRightAfter = None
diff --git a/src/compiler/scala/tools/nsc/ast/TreeDSL.scala b/src/compiler/scala/tools/nsc/ast/TreeDSL.scala
index 283bdecf26..91935854f4 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeDSL.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeDSL.scala
@@ -95,6 +95,12 @@ trait TreeDSL {
def INT_>= (other: Tree) = fn(target, getMember(IntClass, nme.GE), other)
def INT_== (other: Tree) = fn(target, getMember(IntClass, nme.EQ), other)
def INT_!= (other: Tree) = fn(target, getMember(IntClass, nme.NE), other)
+
+ // generic operations on ByteClass, IntClass, LongClass
+ def GEN_| (other: Tree, kind: ClassSymbol) = fn(target, getMember(kind, nme.OR), other)
+ def GEN_& (other: Tree, kind: ClassSymbol) = fn(target, getMember(kind, nme.AND), other)
+ def GEN_== (other: Tree, kind: ClassSymbol) = fn(target, getMember(kind, nme.EQ), other)
+ def GEN_!= (other: Tree, kind: ClassSymbol) = fn(target, getMember(kind, nme.NE), other)
def BOOL_&& (other: Tree) = fn(target, Boolean_and, other)
def BOOL_|| (other: Tree) = fn(target, Boolean_or, other)
diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala
index 4f833c82d3..bc4483923a 100644
--- a/src/compiler/scala/tools/nsc/transform/Constructors.scala
+++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala
@@ -362,9 +362,8 @@ abstract class Constructors extends Transform with ast.TreeDSL {
val tree =
If(
Apply(
- Select(
- Apply(gen.mkAttributedRef(specializedFlag), List()),
- definitions.getMember(definitions.BooleanClass, nme.UNARY_!)),
+ CODE.NOT (
+ Apply(gen.mkAttributedRef(specializedFlag), List())),
List()),
Block(stats, Literal(Constant())),
EmptyTree)
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index 338c39dc5f..7175492622 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -643,7 +643,8 @@ abstract class Erasure extends AddInterfaces
else if (isPrimitiveValueType(tree.tpe) && !isPrimitiveValueType(pt)) {
adaptToType(box(tree, pt.toString), pt)
} else if (tree.tpe.isInstanceOf[MethodType] && tree.tpe.params.isEmpty) {
- assert(tree.symbol.isStable, "adapt "+tree+":"+tree.tpe+" to "+pt)
+ // [H] this assert fails when try to call !(Some.this.bitmap) for single lazy val
+ //assert(tree.symbol.isStable, "adapt "+tree+":"+tree.tpe+" to "+pt)
adaptToType(Apply(tree, List()) setPos tree.pos setType tree.tpe.resultType, pt)
// } else if (pt <:< tree.tpe)
// cast(tree, pt)
diff --git a/src/compiler/scala/tools/nsc/transform/LazyVals.scala b/src/compiler/scala/tools/nsc/transform/LazyVals.scala
index 85ba539993..3024f3db28 100644
--- a/src/compiler/scala/tools/nsc/transform/LazyVals.scala
+++ b/src/compiler/scala/tools/nsc/transform/LazyVals.scala
@@ -12,7 +12,8 @@ abstract class LazyVals extends Transform with TypingTransformers with ast.TreeD
import CODE._
val phaseName: String = "lazyvals"
- val FLAGS_PER_WORD: Int
+ private val FLAGS_PER_BYTE: Int = 32 // Byte
+ private def bitmapKind = ByteClass
def newTransformer(unit: CompilationUnit): Transformer =
new LazyValues(unit)
@@ -206,7 +207,7 @@ abstract class LazyVals extends Transform with TypingTransformers with ast.TreeD
*/
private def mkLazyDef(methOrClass: Symbol, tree: Tree, offset: Int, lazyVal: Symbol): Tree = {
val bitmapSym = getBitmapFor(methOrClass, offset)
- val mask = LIT(1 << (offset % FLAGS_PER_WORD))
+ val mask = LIT(1 << (offset % FLAGS_PER_BYTE))
val bitmapRef = if (methOrClass.isClass) Select(This(methOrClass), bitmapSym) else Ident(bitmapSym)
def mkBlock(stmt: Tree) = BLOCK(stmt, mkSetFlag(bitmapSym, mask, bitmapRef), UNIT)
@@ -219,7 +220,7 @@ abstract class LazyVals extends Transform with TypingTransformers with ast.TreeD
(mkBlock(rhs), UNIT)
}
- val cond = (bitmapRef INT_& mask) INT_== ZERO
+ val cond = (bitmapRef GEN_& (mask, bitmapKind)) GEN_== (ZERO, bitmapKind)
atPos(tree.pos)(localTyper.typed {
def body = gen.mkDoubleCheckedLocking(methOrClass.enclClass, cond, List(block), Nil)
@@ -228,7 +229,7 @@ abstract class LazyVals extends Transform with TypingTransformers with ast.TreeD
}
private def mkSetFlag(bmp: Symbol, mask: Tree, bmpRef: Tree): Tree =
- bmpRef === (bmpRef INT_| mask)
+ bmpRef === (bmpRef GEN_| (mask, bitmapKind))
val bitmaps = mutable.Map[Symbol, List[Symbol]]() withDefaultValue Nil
@@ -236,12 +237,12 @@ abstract class LazyVals extends Transform with TypingTransformers with ast.TreeD
* given offset.
*/
private def getBitmapFor(meth: Symbol, offset: Int): Symbol = {
- val n = offset / FLAGS_PER_WORD
+ val n = offset / FLAGS_PER_BYTE
val bmps = bitmaps(meth)
if (bmps.length > n)
bmps(n)
else {
- val sym = meth.newVariable(nme.newBitmapName(nme.BITMAP_NORMAL, n), meth.pos).setInfo(IntClass.tpe)
+ val sym = meth.newVariable(nme.newBitmapName(nme.BITMAP_NORMAL, n), meth.pos).setInfo(ByteClass.tpe)
beforeTyper {
sym addAnnotation VolatileAttr
}
diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala
index 58bb7aecbd..8b1f4a5812 100644
--- a/src/compiler/scala/tools/nsc/transform/Mixin.scala
+++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala
@@ -492,6 +492,19 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
* fields count as fields defined by the class itself.
*/
private val fieldOffset = perRunCaches.newMap[Symbol, Int]()
+
+ private val bitmapKindForCategory = perRunCaches.newMap[Name, ClassSymbol]() // TODO: make it a list
+
+ // ByteClass, IntClass, LongClass
+ private def bitmapKind(field: Symbol): ClassSymbol = bitmapKindForCategory(bitmapCategory(field))
+
+ private def flagsPerBitmap(field: Symbol): Int = bitmapKind(field) match {
+ case BooleanClass => 1
+ case ByteClass => 8
+ case IntClass => 32
+ case LongClass => 64
+ }
+
/** The first transform; called in a pre-order traversal at phase mixin
* (that is, every node is processed before its children).
@@ -610,8 +623,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
if (field.accessed hasAnnotation TransientAttr) {
if (isNormal) BITMAP_TRANSIENT
else BITMAP_CHECKINIT_TRANSIENT
- }
- else {
+ } else {
if (isNormal) BITMAP_NORMAL
else BITMAP_CHECKINIT
}
@@ -696,30 +708,34 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
stat
}
- import lazyVals._
-
/**
* 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, field: Symbol): Symbol = {
val category = bitmapCategory(field)
- val bitmapName = nme.newBitmapName(category, offset / FLAGS_PER_WORD)
+ val bitmapName = nme.newBitmapName(category, offset / flagsPerBitmap(field))
val sym = clazz0.info.decl(bitmapName)
assert(!sym.isOverloaded, sym)
def createBitmap: Symbol = {
- val sym = clazz0.newVariable(bitmapName, clazz0.pos) setInfo IntClass.tpe
+ val bitmapKind = bitmapKindForCategory(category)
+ val sym = clazz0.newVariable(bitmapName, clazz0.pos) setInfo bitmapKind.tpe
beforeTyper(sym addAnnotation VolatileAttr)
category match {
case nme.BITMAP_TRANSIENT | nme.BITMAP_CHECKINIT_TRANSIENT => sym addAnnotation TransientAttr
case _ =>
}
+ val init = bitmapKind match {
+ case BooleanClass => VAL(sym) === FALSE
+ case _ => VAL(sym) === ZERO
+ }
+
sym setFlag PrivateLocal
clazz0.info.decls.enter(sym)
- addDef(clazz0.pos, VAL(sym) === ZERO)
+ addDef(clazz0.pos, init)
sym
}
@@ -728,23 +744,36 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
else
createBitmap
}
+
+ def maskForOffset(offset: Int, sym: Symbol, kind: ClassSymbol): Tree = {
+ def realOffset = offset % flagsPerBitmap(sym)
+ if (kind == LongClass ) LIT(1L << realOffset) else LIT(1 << realOffset)
+ }
/** Return an (untyped) tree of the form 'Clazz.this.bmp = Clazz.this.bmp | mask'. */
- def mkSetFlag(clazz: Symbol, offset: Int, valSym: Symbol): Tree = {
- val bmp = bitmapFor(clazz, offset, valSym)
- val mask = LIT(1 << (offset % FLAGS_PER_WORD))
- def x = This(clazz) DOT bmp
+ def mkSetFlag(clazz: Symbol, offset: Int, valSym: Symbol, kind: ClassSymbol): Tree = {
+ val bmp = bitmapFor(clazz, offset, valSym)
+ def mask = maskForOffset(offset, valSym, kind)
+ def x = This(clazz) DOT bmp
+ def newValue = if (kind == BooleanClass) TRUE else (x GEN_| (mask, kind))
- x === (x INT_| mask)
+ x === newValue
}
/** Return an (untyped) tree of the form 'clazz.this.bitmapSym & mask (==|!=) 0', the
* precise comparison operator depending on the value of 'equalToZero'.
*/
- def mkTest(clazz: Symbol, mask: Tree, bitmapSym: Symbol, equalToZero: Boolean): Tree = {
- def lhs = (This(clazz) DOT bitmapSym) INT_& mask
- if (equalToZero) lhs INT_== ZERO
- else lhs INT_!= ZERO
+ def mkTest(clazz: Symbol, mask: Tree, bitmapSym: Symbol, equalToZero: Boolean, kind: ClassSymbol): Tree = {
+ val bitmapTree = (This(clazz) DOT bitmapSym)
+ def lhs = bitmapTree GEN_& (mask, kind)
+ kind match {
+ case BooleanClass =>
+ if (equalToZero) NOT(bitmapTree)
+ else bitmapTree
+ case _ =>
+ if (equalToZero) lhs GEN_== (ZERO, kind)
+ else lhs GEN_!= (ZERO, kind)
+ }
}
/** return a 'lazified' version of rhs. It uses double-checked locking to ensure
@@ -777,10 +806,11 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
def nullify(sym: Symbol) = Select(This(clazz), sym.accessedOrSelf) === LIT(null)
val bitmapSym = bitmapFor(clazz, offset, lzyVal)
- val mask = LIT(1 << (offset % FLAGS_PER_WORD))
- def cond = mkTest(clazz, mask, bitmapSym, true)
+ val kind = bitmapKind(lzyVal)
+ val mask = maskForOffset(offset, lzyVal, kind)
+ def cond = mkTest(clazz, mask, bitmapSym, true, kind)
val nulls = lazyValNullables(lzyVal).toList sortBy (_.id) map nullify
- def syncBody = init ::: List(mkSetFlag(clazz, offset, lzyVal), UNIT)
+ def syncBody = init ::: List(mkSetFlag(clazz, offset, lzyVal, kind), UNIT)
if (nulls.nonEmpty)
log("nulling fields inside " + lzyVal + ": " + nulls)
@@ -802,11 +832,13 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
}
def mkCheckedAccessor(clazz: Symbol, retVal: Tree, offset: Int, pos: Position, fieldSym: Symbol): Tree = {
- val bitmapSym = bitmapFor(clazz, offset, fieldSym.getter(fieldSym.owner))
- val mask = LIT(1 << (offset % FLAGS_PER_WORD))
+ val sym = fieldSym.getter(fieldSym.owner)
+ val bitmapSym = bitmapFor(clazz, offset, sym)
+ val kind = bitmapKind(sym)
+ val mask = maskForOffset(offset, sym, kind)
val msg = "Uninitialized field: " + unit.source + ": " + pos.line
val result =
- IF (mkTest(clazz, mask, bitmapSym, false)) .
+ IF (mkTest(clazz, mask, bitmapSym, false, kind)) .
THEN (retVal) .
ELSE (THROW(UninitializedErrorClass, LIT(msg)))
@@ -851,7 +883,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
else if (settings.checkInit.value && !clazz.isTrait && sym.isSetter) {
val getter = sym.getter(clazz)
if (needsInitFlag(getter) && fieldOffset.isDefinedAt(getter))
- deriveDefDef(stat)(rhs => Block(List(rhs, localTyper.typed(mkSetFlag(clazz, fieldOffset(getter), getter))), UNIT))
+ deriveDefDef(stat)(rhs => Block(List(rhs, localTyper.typed(mkSetFlag(clazz, fieldOffset(getter), getter, bitmapKind(getter)))), UNIT))
else stat
}
else if (sym.isModule && (!clazz.isTrait || clazz.isImplClass) && !sym.isBridge) {
@@ -879,7 +911,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
val sym = clazz.info decl lhs.symbol.getterName suchThat (_.isGetter)
if (needsInitAndHasOffset(sym)) {
debuglog("adding checked getter for: " + sym + " " + lhs.symbol.flagString)
- List(localTyper typed mkSetFlag(clazz, fieldOffset(sym), sym))
+ List(localTyper typed mkSetFlag(clazz, fieldOffset(sym), sym, bitmapKind(sym)))
}
else Nil
}
@@ -917,16 +949,22 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
* code generation easier later.
*/
def buildBitmapOffsets() {
- def fold(zero: Int, fields: List[Symbol]) = {
- var idx = zero
+ def fold(fields: List[Symbol], category: Name) = {
+ var idx = 0
fields foreach { f =>
fieldOffset(f) = idx
idx += 1
}
+
+ if (idx == 0) ()
+ else if (idx == 1) bitmapKindForCategory(category) = BooleanClass
+ else if (idx < 9) bitmapKindForCategory(category) = ByteClass
+ else if (idx < 33) bitmapKindForCategory(category) = IntClass
+ else bitmapKindForCategory(category) = LongClass
}
clazz.info.decls.toList groupBy bitmapCategory foreach {
case (nme.NO_NAME, _) => ()
- case (_, fields) => fold(0, fields)
+ case (category, fields) => fold(fields, category)
}
}
buildBitmapOffsets()
@@ -977,7 +1015,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
val getter = sym.getter(clazz)
if (!needsInitFlag(getter)) init
- else Block(init, mkSetFlag(clazz, fieldOffset(getter), getter), UNIT)
+ else Block(init, mkSetFlag(clazz, fieldOffset(getter), getter, bitmapKind(getter)), UNIT)
}
}
else if (needsInitFlag(sym))
diff --git a/test/files/run/t3569.check b/test/files/run/t3569.check
index 47aa9292c8..a9fb5ff32e 100644
--- a/test/files/run/t3569.check
+++ b/test/files/run/t3569.check
@@ -9,7 +9,7 @@ private int Test$X.var1
private int Test$X.var2
private int Test$X.var3
private int Test$X.x
-private volatile int Test$X.bitmap$0
+private volatile byte Test$X.bitmap$0
private final int Test$Y.z1
private final int Test$Y.z2
private int Test$Y.x