diff options
Diffstat (limited to 'src')
6 files changed, 83 insertions, 39 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)) |