diff options
author | Paul Phillips <paulp@improving.org> | 2010-09-22 20:24:08 +0000 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2010-09-22 20:24:08 +0000 |
commit | a992ec2d579b65b79d61c7c2997812deb58250cd (patch) | |
tree | cfc2a9bb128935788f6e01cc36655817532e3742 /src | |
parent | 285d2182f1aeb113aba55be804eefa2f61ce2624 (diff) | |
download | scala-a992ec2d579b65b79d61c7c2997812deb58250cd.tar.gz scala-a992ec2d579b65b79d61c7c2997812deb58250cd.tar.bz2 scala-a992ec2d579b65b79d61c7c2997812deb58250cd.zip |
A cleanup of the inliner.
and still came out of the washing machine smiling. Already reviewed by a
certain i. dragos so no review.
Diffstat (limited to 'src')
21 files changed, 450 insertions, 743 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index dbe4a587ba..70641f9037 100644 --- a/src/compiler/scala/tools/nsc/ast/Trees.scala +++ b/src/compiler/scala/tools/nsc/ast/Trees.scala @@ -60,6 +60,11 @@ trait Trees extends reflect.generic.Trees { self: SymbolTable => /** Apply `f' to each subtree */ def foreach(f: Tree => Unit) { new ForeachTreeTraverser(f).traverse(tree) } + /** If 'pf' is defined for a given subtree, call super.traverse(pf(tree)), + * otherwise super.traverse(tree). + */ + def foreachPartial(pf: PartialFunction[Tree, Tree]) { new ForeachPartialTreeTraverser(pf).traverse(tree) } + /** Find all subtrees matching predicate `p' */ def filter(f: Tree => Boolean): List[Tree] = { val ft = new FilterTreeTraverser(f) @@ -1019,6 +1024,13 @@ trait Trees extends reflect.generic.Trees { self: SymbolTable => tree } + class ForeachPartialTreeTraverser(pf: PartialFunction[Tree, Tree]) extends Traverser { + override def traverse(tree: Tree) { + val t = if (pf isDefinedAt tree) pf(tree) else tree + super.traverse(t) + } + } + class ForeachTreeTraverser(f: Tree => Unit) extends Traverser { override def traverse(t: Tree) { f(t) diff --git a/src/compiler/scala/tools/nsc/backend/Platform.scala b/src/compiler/scala/tools/nsc/backend/Platform.scala index 90075687c6..e0f755323a 100644 --- a/src/compiler/scala/tools/nsc/backend/Platform.scala +++ b/src/compiler/scala/tools/nsc/backend/Platform.scala @@ -29,3 +29,4 @@ trait Platform[T] { /** The various ways a boxed primitive might materialize at runtime. */ def isMaybeBoxed(sym: Symbol): Boolean } + diff --git a/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala b/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala index 9b0e52ffac..3ce61cf65e 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala @@ -8,11 +8,10 @@ package scala.tools.nsc package backend package icode -//import scala.tools.nsc.ast._ -import scala.collection.mutable.{Map, Set} -import scala.collection.mutable.LinkedHashSet -import scala.tools.nsc.util.{Position,NoPosition} -import scala.tools.nsc.backend.icode.analysis.ProgramPoint +import scala.collection.{ mutable, immutable } +import mutable.{ ArrayBuffer } +import util.{ Position, NoPosition } +import backend.icode.analysis.ProgramPoint trait BasicBlocks { self: ICodes => @@ -79,7 +78,7 @@ trait BasicBlocks { /** Local variables that are in scope at entry of this basic block. Used * for debugging information. */ - var varsInScope: Set[Local] = new LinkedHashSet() + var varsInScope: mutable.Set[Local] = new mutable.LinkedHashSet() /** ICode instructions, used as temporary storage while emitting code. * Once closed is called, only the `instrs' array should be used. @@ -90,11 +89,8 @@ trait BasicBlocks { private var instrs: Array[Instruction] = _ - override def toList: List[Instruction] = { - if (closed) - instrs.toList - else instructionList.reverse - } + override def toList: List[Instruction] = + if (closed) instrs.toList else instructionList.reverse /** Return an iterator over the instructions in this basic block. */ def iterator: Iterator[Instruction] = @@ -108,7 +104,7 @@ trait BasicBlocks { def fromList(is: List[Instruction]) { code.touched = true - instrs = toInstructionArray(is) + instrs = is.toArray closed = true } @@ -117,17 +113,9 @@ trait BasicBlocks { */ def indexOf(inst: Instruction): Int = { assert(closed) - var i = 0 - while (i < instrs.length) { - if (instrs(i) eq inst) return i - i += 1 - } - -1 + instrs indexWhere (_ eq inst) } - /** Compute an hashCode for the block */ -// override def hashCode() = label; - /** Apply a function to all the instructions of the block. */ override def foreach[U](f: Instruction => U) = { if (!closed) { @@ -138,26 +126,7 @@ trait BasicBlocks { } /** The number of instructions in this basic block so far. */ - def length: Int = - if (closed) instrs.length else instructionList.length - - /** Return the index of the instruction which produced the value - * consumed by the given instruction. - */ - def findDef(pos: Int): Option[Int] = { - assert(closed) - var i = pos - var d = 0 - while (i > 0) { - i -= 1 - val prod = instrs(i).produced - if (prod > 0 && d == 0) - return Some(i) - d += (instrs(i).consumed - instrs(i).produced) - } - None - } - + def length = if (closed) instrs.length else instructionList.length /** Return the n-th instruction. */ def apply(n: Int): Instruction = @@ -185,21 +154,17 @@ trait BasicBlocks { def replaceInstruction(oldInstr: Instruction, newInstr: Instruction): Boolean = { assert(closed, "Instructions can be replaced only after the basic block is closed") - var i = 0 - var changed = false - while (i < instrs.length && !changed) { - if (instrs(i) eq oldInstr) { - newInstr.setPos(oldInstr.pos) - instrs(i) = newInstr - changed = true + indexOf(oldInstr) match { + case -1 => false + case idx => + newInstr setPos oldInstr.pos + instrs(idx) = newInstr code.touched = true - } - i += 1 + true } - changed } - /** Replaces <code>iold</code> with <code>is</code>. It does not update + /** Replaces <code>oldInstr</code> with <code>is</code>. It does not update * the position field in the newly inserted instructions, so it behaves * differently than the one-instruction versions of this function. * @@ -207,51 +172,23 @@ trait BasicBlocks { * @param is .. * @return .. */ - def replaceInstruction(iold: Instruction, is: List[Instruction]): Boolean = { + def replaceInstruction(oldInstr: Instruction, is: List[Instruction]): Boolean = { assert(closed, "Instructions can be replaced only after the basic block is closed") - var i = 0 - var changed = false - - while (i < instrs.length && (instrs(i) ne iold)) - i += 1 - - if (i < instrs.length) { - val newInstrs = new Array[Instruction](instrs.length + is.length - 1); - changed = true - code.touched = true - - Array.copy(instrs, 0, newInstrs, 0, i) - var j = i - for (x <- is) { - newInstrs(j) = x - j += 1 - } - if (i + 1 < instrs.length) - Array.copy(instrs, i + 1, newInstrs, j, instrs.length - i - 1) - instrs = newInstrs; + indexOf(oldInstr) match { + case -1 => false + case idx => + instrs = instrs.patch(idx, is, 1) + code.touched = true + true } - - changed } /** Insert instructions in 'is' immediately after index 'idx'. */ def insertAfter(idx: Int, is: List[Instruction]) { assert(closed, "Instructions can be replaced only after the basic block is closed") - var i = idx + 1 - if (i < instrs.length) { - val newInstrs = new Array[Instruction](instrs.length + is.length); - Array.copy(instrs, 0, newInstrs, 0, i) - var j = i - for (x <- is) { - newInstrs(j) = x - j += 1 - } - if (i + 1 < instrs.length) - Array.copy(instrs, i + 1, newInstrs, j, instrs.length - i) - instrs = newInstrs; - } + instrs = instrs.patch(idx + 1, is, 0) code.touched = true } @@ -261,18 +198,7 @@ trait BasicBlocks { */ def removeInstructionsAt(positions: Int*) { assert(closed) - val removed = positions.toList - val newInstrs = new Array[Instruction](instrs.length - positions.length) - var i = 0 - var j = 0 - while (i < instrs.length) { - if (!removed.contains(i)) { - newInstrs(j) = instrs(i) - j += 1 - } - i += 1 - } - instrs = newInstrs + instrs = instrs.indices.toArray filterNot positions.toSet map instrs code.touched = true } @@ -292,33 +218,14 @@ trait BasicBlocks { * * @param map ... */ - def subst(map: Map[Instruction, Instruction]) { - if (!closed) substOnList(map) else { - var i = 0 - while (i < instrs.length) { - map get instrs(i) match { - case Some(instr) => - val changed = replaceInstruction(i, instr) - code.touched |= changed - case None => () - } - i += 1 + def subst(map: Map[Instruction, Instruction]): Unit = + if (!closed) + instructionList = instructionList map (x => map.getOrElse(x, x)) + else + instrs.zipWithIndex collect { + case (oldInstr, i) if map contains oldInstr => + code.touched |= replaceInstruction(i, map(oldInstr)) } - } - } - - private def substOnList(map: Map[Instruction, Instruction]) { - def subst(l: List[Instruction]): List[Instruction] = l match { - case Nil => Nil - case x :: xs => - map.get(x) match { - case Some(newInstr) => newInstr :: subst(xs) - case None => x :: subst(xs) - } - } - - instructionList = subst(instructionList) - } ////////////////////// Emit ////////////////////// @@ -327,10 +234,8 @@ trait BasicBlocks { * using the same source position as the last emitted instruction */ def emit(instr: Instruction) { - if (!instructionList.isEmpty) - emit(instr, instructionList.head.pos) - else - emit(instr, NoPosition) + val pos = if (instructionList.isEmpty) NoPosition else instructionList.head.pos + emit(instr, pos) } /** Emitting does not set touched to true. During code generation this is a hotspot and @@ -390,7 +295,7 @@ trait BasicBlocks { closed = true setFlag(DIRTYSUCCS) instructionList = instructionList.reverse - instrs = toInstructionArray(instructionList) + instrs = instructionList.toArray } def open { @@ -422,67 +327,38 @@ trait BasicBlocks { /** Return the last instruction of this basic block. */ def lastInstruction = - if (closed) - instrs(instrs.length - 1) - else - instructionList.head + if (closed) instrs.last + else instructionList.head def firstInstruction = - if (closed) - instrs(0) - else - instructionList.last - - /** Convert the list to an array */ - private def toInstructionArray(l: List[Instruction]): Array[Instruction] = { - var array = new Array[Instruction](l.length) - var i: Int = 0 + if (closed) instrs(0) + else instructionList.last - l foreach (x => { array(i) = x; i += 1 }) - array - } + def exceptionSuccessorsForBlock(block: BasicBlock): List[BasicBlock] = + method.exh collect { case x if x covers block => x.startBlock } /** Cached value of successors. Must be recomputed whenver a block in the current method is changed. */ private var succs: List[BasicBlock] = Nil + private def updateSuccs() { + resetFlag(DIRTYSUCCS) + succs = + if (isEmpty) Nil + else exceptionSuccessors ++ directSuccessors ++ indirectExceptionSuccessors + } def successors : List[BasicBlock] = { - if (touched) { - resetFlag(DIRTYSUCCS) - succs = if (isEmpty) Nil else { - var res = lastInstruction match { - case JUMP(whereto) => List(whereto) - case CJUMP(success, failure, _, _) => failure :: success :: Nil - case CZJUMP(success, failure, _, _) => failure :: success :: Nil - case SWITCH(_, labels) => labels - case RETURN(_) => Nil - case THROW() => Nil - case _ => - if (closed) { - dump - global.abort("The last instruction is not a control flow instruction: " + lastInstruction) - } - else Nil - } - method.exh.foreach { - e: ExceptionHandler => - if (e.covers(this)) res = e.startBlock :: res - } - val res1 = res ++ exceptionalSucc(this, res) - res1 - } - } -// println("reusing cached successors for " + this + " in method " + method) + if (touched) updateSuccs() succs } - def directSuccessors: List[BasicBlock] = { + def directSuccessors: List[BasicBlock] = if (isEmpty) Nil else lastInstruction match { - case JUMP(whereto) => List(whereto) - case CJUMP(success, failure, _, _) => failure :: success :: Nil - case CZJUMP(success, failure, _, _) => failure :: success :: Nil - case SWITCH(_, labels) => labels - case RETURN(_) => Nil - case THROW() => Nil + case JUMP(whereto) => List(whereto) + case CJUMP(succ, fail, _, _) => fail :: succ :: Nil + case CZJUMP(succ, fail, _, _) => fail :: succ :: Nil + case SWITCH(_, labels) => labels + case RETURN(_) => Nil + case THROW() => Nil case _ => if (closed) { dump @@ -490,29 +366,23 @@ trait BasicBlocks { } else Nil } - } + + def exceptionSuccessors: List[BasicBlock] = + exceptionSuccessorsForBlock(this) /** Return a list of successors for 'b' that come from exception handlers * covering b's (non-exceptional) successors. These exception handlers * might not cover 'b' itself. This situation corresponds to an * exception being thrown as the first thing of one of b's successors. */ - private def exceptionalSucc(b: BasicBlock, succs: List[BasicBlock]): List[BasicBlock] = { - def findSucc(s: BasicBlock): List[BasicBlock] = { - val ss = method.exh flatMap { h => - if (h.covers(s) /*&& mayThrow(h.startBlock.firstInstruction)*/) List(h.startBlock) else Nil - } - ss ++ (ss flatMap findSucc) - } - - succs.flatMap(findSucc).distinct - } + def indirectExceptionSuccessors: List[BasicBlock] = + directSuccessors flatMap exceptionSuccessorsForBlock distinct /** Returns the predecessors of this block. */ def predecessors: List[BasicBlock] = { if (hasFlag(DIRTYPREDS)) { resetFlag(DIRTYPREDS) - preds = code.blocks.iterator.filter (_.successors.contains(this)).toList + preds = code.blocks.iterator filter (_.successors contains this) toList } preds } diff --git a/src/compiler/scala/tools/nsc/backend/icode/Checkers.scala b/src/compiler/scala/tools/nsc/backend/icode/Checkers.scala index 6067dc6e42..2b4d66fc49 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Checkers.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Checkers.scala @@ -573,24 +573,16 @@ abstract class Checkers { def error(msg: String) { Console.println(method.toString() + " in block: " + basicBlock.label) - printLastIntructions + printLastInstructions Checkers.this.global.error("ICode checker: " + method + ": " + msg) } /** Prints the last 4 instructions. */ - def printLastIntructions { - var printed = 0 - var buf: List[Instruction] = Nil - - for (i <- basicBlock.reverse) { - if (i == instruction || (printed > 0 && printed < 3)) { - buf = i :: buf - printed += 1 - } - } - buf foreach Console.println - Console.println("at: " + (buf.head.pos)) + def printLastInstructions { + val buf = basicBlock.reverse dropWhile (_ != instruction) take 4 reverse; + buf foreach (Console println _) + Console.println("at: " + buf.head.pos) } def error(msg: String, stack: TypeStack) { @@ -602,8 +594,6 @@ abstract class Checkers { /** Return true if <code>k1</code> is a subtype of any of the following * types. */ - def isOneOf(k1: TypeKind, kinds: TypeKind*) = - kinds.exists( k => k1 <:< k) - + def isOneOf(k1: TypeKind, kinds: TypeKind*) = kinds exists (k1 <:< _) } } diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index a5b7370f8d..ec8ffd1ddb 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -26,10 +26,10 @@ abstract class GenICode extends SubComponent { import icodes._ import icodes.opcodes._ import definitions.{ - ArrayClass, ObjectClass, ThrowableClass, StringClass, NothingClass, NullClass, + ArrayClass, ObjectClass, ThrowableClass, StringClass, NothingClass, NullClass, AnyRefClass, Object_equals, Object_isInstanceOf, Object_asInstanceOf, ScalaRunTimeModule, BoxedNumberClass, BoxedCharacterClass, - getMember + getMember, getPrimitiveCompanion } import scalaPrimitives.{ isArrayOp, isComparisonOp, isLogicalOp, @@ -894,10 +894,10 @@ abstract class GenICode extends SubComponent { } else { // normal method call if (settings.debug.value) log("Gen CALL_METHOD with sym: " + sym + " isStaticSymbol: " + sym.isStaticMember); - var invokeStyle = + val invokeStyle = if (sym.isStaticMember) Static(false) - else if (sym.hasFlag(Flags.PRIVATE) || sym.isClassConstructor) + else if (sym.isPrivate || sym.isClassConstructor) Static(true) else Dynamic @@ -1168,58 +1168,44 @@ abstract class GenICode extends SubComponent { * Generate code that loads args into label parameters. */ private def genLoadLabelArguments(args: List[Tree], label: Label, ctx: Context): Context = { - if (settings.debug.value) + if (settings.debug.value) { assert(args.length == label.params.length, "Wrong number of arguments in call to label " + label.symbol) + } + var ctx1 = ctx - var arg = args - var param = label.params - val stores: ListBuffer[Instruction] = new ListBuffer - // store arguments in reverse order on the stack - while (arg != Nil) { - arg.head match { - case This(_) if param.head.name == nme.THIS => - //println("skipping trivial argument for " + param.head) - () // skip trivial arguments - case Ident(_) if arg.head.symbol == param.head => - //println("skipping trivial argument for " + param.head) - () // skip trivial arguments - case _ => - val Some(l) = ctx.method.lookupLocal(param.head) - ctx1 = genLoad(arg.head, ctx1, l.kind) - if (param.head.name == nme.THIS) - STORE_THIS(toTypeKind(ctx1.clazz.symbol.tpe)).setPos(arg.head.pos) +=: stores - else { - STORE_LOCAL(l).setPos(arg.head.pos) +=: stores - } - } - arg = arg.tail - param = param.tail + def isTrivial(kv: (Tree, Symbol)) = kv match { + case (This(_), p) if p.name == nme.THIS => true + case (arg @ Ident(_), p) if arg.symbol == p => true + case _ => false } - //println("stores: " + stores) - ctx1.bb.emit(stores) - ctx1 - } + val stores = args zip label.params filterNot isTrivial map { + case (arg, param) => + val local = ctx.method.lookupLocal(param).get + ctx1 = genLoad(arg, ctx1, local.kind) - private def genLoadArguments(args: List[Tree], tpes: List[Type], ctx: Context): Context = { - var ctx1 = ctx - var arg = args - var tpe = tpes - while (arg != Nil) { - ctx1 = genLoad(arg.head, ctx1, toTypeKind(tpe.head)) - arg = arg.tail - tpe = tpe.tail + val store = + if (param.name == nme.THIS) STORE_THIS(toTypeKind(ctx1.clazz.symbol.tpe)) + else STORE_LOCAL(local) + + store setPos arg.pos } + + // store arguments in reverse order on the stack + ctx1.bb.emit(stores.reverse) ctx1 } + private def genLoadArguments(args: List[Tree], tpes: List[Type], ctx: Context): Context = + (args zip tpes).foldLeft(ctx) { + case (res, (arg, tpe)) => + genLoad(arg, res, toTypeKind(tpe)) + } + private def genLoadModule(ctx: Context, sym: Symbol, pos: Position) { - if (definitions.primitiveCompanions(sym)) - ctx.bb.emit(LOAD_MODULE(definitions.getModule("scala.runtime." + sym.name)), pos) - else - ctx.bb.emit(LOAD_MODULE(sym), pos) + ctx.bb.emit(LOAD_MODULE(getPrimitiveCompanion(sym) getOrElse sym), pos) } def genConversion(from: TypeKind, to: TypeKind, ctx: Context, cast: Boolean) = { @@ -1409,21 +1395,17 @@ abstract class GenICode extends SubComponent { * TODO: restrict the scanning to smaller subtrees than the whole method. * It is sufficient to scan the trees of the innermost enclosing block. */ - private def scanForLabels(tree: Tree, ctx: Context): Unit = - new Traverser() { - override def traverse(tree: Tree): Unit = tree match { - - case LabelDef(name, params, rhs) => - if (!ctx.labels.contains(tree.symbol)) { - ctx.labels += (tree.symbol -> (new Label(tree.symbol) setParams(params map (_.symbol)))); - ctx.method.addLocals(params map (p => new Local(p.symbol, toTypeKind(p.symbol.info), false))); - } - super.traverse(rhs) - - case _ => - super.traverse(tree) - } - } traverse(tree); + // + private def scanForLabels(tree: Tree, ctx: Context): Unit = tree foreachPartial { + case t @ LabelDef(_, params, rhs) => + ctx.labels.getOrElseUpdate(t.symbol, { + val locals = params map (p => new Local(p.symbol, toTypeKind(p.symbol.info), false)) + ctx.method addLocals locals + + new Label(t.symbol) setParams (params map (_.symbol)) + }) + rhs + } /** * Generate code for conditional expressions. The two basic blocks @@ -1535,7 +1517,7 @@ abstract class GenICode extends SubComponent { def getTempLocal: Local = ctx.method.lookupLocal(eqEqTempName) match { case Some(local) => local case None => - val local = ctx.makeLocal(l.pos, definitions.AnyRefClass.typeConstructor, eqEqTempName.toString) + val local = ctx.makeLocal(l.pos, AnyRefClass.typeConstructor, eqEqTempName.toString) //assert(!l.pos.source.isEmpty, "bad position, unit = "+unit+", tree = "+l+", pos = "+l.pos.source) // Note - I commented these out because they were crashing the test case in ticket #2426 // (and I have also had to comment them out at various times while working on equality.) @@ -1667,15 +1649,9 @@ abstract class GenICode extends SubComponent { } /** Does this tree have a try-catch block? */ - def mayCleanStack(tree: Tree): Boolean = { - var hasTry = false - new Traverser() { - override def traverse(t: Tree) = t match { - case Try(_, _, _) => hasTry = true - case _ => super.traverse(t) - } - }.traverse(tree); - hasTry + def mayCleanStack(tree: Tree): Boolean = tree exists { + case Try(_, _, _) => true + case _ => false } /** @@ -1770,13 +1746,8 @@ abstract class GenICode extends SubComponent { log("Prune fixpoint reached in " + n + " iterations."); } - def getMaxType(ts: List[Type]): TypeKind = { - def maxType(a: TypeKind, b: TypeKind): TypeKind = - a maxType b; - - val kinds = ts map toTypeKind - kinds reduceLeft maxType - } + def getMaxType(ts: List[Type]): TypeKind = + ts map toTypeKind reduceLeft (_ maxType _) def isLoopHeaderLabel(name: Name): Boolean = name.startsWith("while$") || name.startsWith("doWhile$") @@ -1796,7 +1767,7 @@ abstract class GenICode extends SubComponent { * All LabelDefs are entered into the context label map, since it makes no sense * to delay it any more: they will be used at some point. */ - class DuplicateLabels(boundLabels: collection.Set[Symbol]) extends Transformer { + class DuplicateLabels(boundLabels: Set[Symbol]) extends Transformer { val labels: mutable.Map[Symbol, Symbol] = new HashMap var method: Symbol = _ var ctx: Context = _ @@ -1808,31 +1779,26 @@ abstract class GenICode extends SubComponent { } override def transform(t: Tree): Tree = { + val sym = t.symbol + def getLabel(pos: Position, name: Name) = + labels.getOrElseUpdate(sym, + method.newLabel(sym.pos, unit.fresh.newName(pos, name.toString)) setInfo sym.tpe + ) + t match { - case t @ Apply(fun, args) if (t.symbol.isLabel && !boundLabels(t.symbol)) => - if (!labels.isDefinedAt(t.symbol)) { - val oldLabel = t.symbol - val sym = method.newLabel(oldLabel.pos, unit.fresh.newName(oldLabel.pos, oldLabel.name.toString)) - sym.setInfo(oldLabel.tpe) - labels(oldLabel) = sym - } - val tree = Apply(global.gen.mkAttributedRef(labels(t.symbol)), transformTrees(args)).setPos(t.pos) + case t @ Apply(_, args) if sym.isLabel && !boundLabels(sym) => + val newSym = getLabel(sym.pos, sym.name) + val tree = Apply(global.gen.mkAttributedRef(newSym), transformTrees(args)) setPos t.pos tree.tpe = t.tpe tree case t @ LabelDef(name, params, rhs) => - val name1 = unit.fresh.newName(t.pos, name.toString) - if (!labels.isDefinedAt(t.symbol)) { - val oldLabel = t.symbol - val sym = method.newLabel(oldLabel.pos, name1) - sym.setInfo(oldLabel.tpe) - labels(oldLabel) = sym - } - val tree = treeCopy.LabelDef(t, name1, params, transform(rhs)) - tree.symbol = labels(t.symbol) + val newSym = getLabel(t.pos, name) + val tree = treeCopy.LabelDef(t, newSym.name, params, transform(rhs)) + tree.symbol = newSym - ctx.labels += (tree.symbol -> (new Label(tree.symbol) setParams(params map (_.symbol)))); - ctx.method.addLocals(params map (p => new Local(p.symbol, toTypeKind(p.symbol.info), false))); + ctx.labels += (newSym -> (new Label(newSym) setParams (params map (_.symbol)))) + ctx.method.addLocals(params map (p => new Local(p.symbol, toTypeKind(p.symbol.info), false))) tree @@ -1853,7 +1819,7 @@ abstract class GenICode extends SubComponent { override def equals(other: Any) = f == other; } - def duplicateFinalizer(boundLabels: collection.Set[Symbol], targetCtx: Context, finalizer: Tree) = { + def duplicateFinalizer(boundLabels: Set[Symbol], targetCtx: Context, finalizer: Tree) = { (new DuplicateLabels(boundLabels))(targetCtx, finalizer) } @@ -1987,10 +1953,9 @@ abstract class GenICode extends SubComponent { /** Return a new context for a new basic block. */ def newBlock: Context = { val block = method.code.newBlock - handlers foreach (h => h addCoveredBlock block) - currentExceptionHandlers foreach (h => h.addBlock(block)) - block.varsInScope = new HashSet() - block.varsInScope ++= scope.varsInScope + handlers foreach (_ addCoveredBlock block) + currentExceptionHandlers foreach (_ addBlock block) + block.varsInScope = new HashSet() ++= scope.varsInScope new Context(this) setBasicBlock block } @@ -2035,7 +2000,7 @@ abstract class GenICode extends SubComponent { * exception handler. */ def enterHandler(exh: ExceptionHandler): Context = { - currentExceptionHandlers = exh :: currentExceptionHandlers + currentExceptionHandlers ::= exh val ctx = newBlock exh.setStartBlock(ctx.bb) ctx @@ -2086,7 +2051,7 @@ abstract class GenICode extends SubComponent { * } ))</code> */ def Try(body: Context => Context, - handlers: List[(Symbol, TypeKind, (Context => Context))], + handlers: List[(Symbol, TypeKind, Context => Context)], finalizer: Tree, tree: Tree) = if (forMSIL) TryMsil(body, handlers, finalizer, tree) else { @@ -2099,7 +2064,7 @@ abstract class GenICode extends SubComponent { // we need to save bound labels before any code generation is performed on // the current context (otherwise, any new labels in the finalizer that need to // be duplicated would be incorrectly considered bound -- see #2850). - val boundLabels: collection.Set[Symbol] = Set.empty ++ labels.keySet + val boundLabels: Set[Symbol] = Set.empty ++ labels.keySet if (guardResult) { tmp = this.makeLocal(tree.pos, tree.tpe, "tmp") @@ -2259,15 +2224,8 @@ abstract class GenICode extends SubComponent { * jumps to the given basic block. */ def patch(code: Code) { - def substMap: mutable.Map[Instruction, Instruction] = { - val map = new HashMap[Instruction, Instruction]() - - toPatch foreach (i => map += (i -> patch(i))) - map - } - - val map = substMap - code.blocks foreach (_.subst(map)) + val map = toPatch map (i => (i -> patch(i))) toMap; + code.blocks foreach (_ subst map) } /** @@ -2350,17 +2308,13 @@ abstract class GenICode extends SubComponent { class Scope(val outer: Scope) { val locals: ListBuffer[Local] = new ListBuffer - def add(l: Local) = - locals += l - - def remove(l: Local) = - locals -= l + def add(l: Local) = locals += l + def remove(l: Local) = locals -= l /** Return all locals that are in scope. */ def varsInScope: Buffer[Local] = outer.varsInScope.clone() ++= locals - override def toString() = - outer.toString() + locals.mkString("[", ", ", "]") + override def toString() = locals.mkString(outer.toString + "[", ", ", "]") } object EmptyScope extends Scope(null) { diff --git a/src/compiler/scala/tools/nsc/backend/icode/Members.scala b/src/compiler/scala/tools/nsc/backend/icode/Members.scala index 32a3c550ed..68360776b3 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Members.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Members.scala @@ -10,11 +10,14 @@ package icode import java.io.PrintWriter -import scala.collection.mutable.HashMap -import scala.collection.mutable.{Set, HashSet, ListBuffer} -import scala.{Symbol => scala_Symbol} +import scala.collection.{ mutable, immutable } +import mutable.{ HashMap, ListBuffer } +import symtab.Flags.{ DEFERRED } -import scala.tools.nsc.symtab.Flags +trait ReferenceEquality { + override def hashCode = System.identityHashCode(this) + override def equals(that: Any) = this eq that.asInstanceOf[AnyRef] +} trait Members { self: ICodes => import global._ @@ -38,31 +41,32 @@ trait Members { self: ICodes => private var _touched = false def touched = _touched - def touched_=(b: Boolean): Unit = if (b) { - blocks foreach (_.touched = true) - _touched = true - } else - _touched = false + def touched_=(b: Boolean): Unit = { + if (b) + blocks foreach (_.touched = true) + + _touched = b + } // Constructor code startBlock = newBlock def removeBlock(b: BasicBlock) { if (settings.debug.value) { - assert(blocks.forall(p => !(p.successors.contains(b))), - "Removing block that is still referenced in method code " + b + "preds: " + b.predecessors); - if (b == startBlock) - assert(b.successors.length == 1, - "Removing start block with more than one successor."); + assert(blocks forall (p => !(p.successors contains b)), + "Removing block that is still referenced in method code " + b + "preds: " + b.predecessors + ) + assert(b != startBlock || b.successors.length == 1, + "Removing start block with more than one successor." + ) } if (b == startBlock) - startBlock = b.successors.head; + startBlock = b.successors.head + blocks -= b assert(!blocks.contains(b)) - for (handler <- method.exh if handler.covers(b)) - handler.covered -= b - + method.exh filter (_ covers b) foreach (_.covered -= b) touched = true } @@ -109,19 +113,16 @@ trait Members { self: ICodes => override def toString() = symbol.fullName - def lookupField(s: Symbol) = fields find (_.symbol == s) + def lookupField(s: Symbol) = fields find (_.symbol == s) def lookupMethod(s: Symbol) = methods find (_.symbol == s) - def lookupMethod(s: Name) = methods find (_.symbol.name == s) + def lookupMethod(s: Name) = methods find (_.symbol.name == s) - /* determines whether or not this class contains a static ctor. */ - def containsStaticCtor: Boolean = methods.exists(_.isStaticCtor) /* returns this methods static ctor if it has one. */ - def lookupStaticCtor: Option[IMethod] = methods.find(_.isStaticCtor) + def lookupStaticCtor: Option[IMethod] = methods find (_.symbol.isStaticConstructor) } /** Represent a field in ICode */ - class IField(val symbol: Symbol) { - } + class IField(val symbol: Symbol) { } /** * Represents a method in ICode. Local variables contain @@ -150,69 +151,56 @@ trait Members { self: ICodes => /** method parameters */ var params: List[Local] = Nil + def hasCode = code != null def setCode(code: Code): IMethod = { this.code = code; this } def addLocal(l: Local): Local = - locals find (l.==) match { - case Some(loc) => loc - case None => - locals = l :: locals; - l + locals find (_ == l) getOrElse { + locals ::= l + l } - def addLocals(ls: List[Local]) { - ls foreach addLocal - } - def addParam(p: Local) { - if (!(params contains p)) { - params = p :: params; - locals = p :: locals; + def addParam(p: Local): Unit = + if (params contains p) () + else { + params ::= p + locals ::= p } - } - def addParams(as: List[Local]) { - as foreach addParam - } - - def lookupLocal(n: Name): Option[Local] = - locals find ((l) => l.sym.name == n); + def addLocals(ls: List[Local]) = ls foreach addLocal + def addParams(as: List[Local]) = as foreach addParam - def lookupLocal(sym: Symbol): Option[Local] = - locals find ((l) => l.sym == sym); + def lookupLocal(n: Name): Option[Local] = locals find (_.sym.name == n) + def lookupLocal(sym: Symbol): Option[Local] = locals find (_.sym == sym) - def addHandler(e: ExceptionHandler) { - exh = e :: exh - } + def addHandler(e: ExceptionHandler) = exh ::= e - /** Is this method deferred ('abstract' in Java sense) */ - def isDeferred = ( - symbol.hasFlag(Flags.DEFERRED) || - symbol.owner.hasFlag(Flags.INTERFACE) || - native - ); + /** Is this method deferred ('abstract' in Java sense)? + * This differs from sym.isDeferred because the symbol only examines the + * flag, which may not be set in the other covered cases. + */ + def isDeferred = (symbol hasFlag DEFERRED) || symbol.owner.isInterface || native def isStatic: Boolean = symbol.isStaticMember - /* determines whether or not this method is the class static constructor. */ - def isStaticCtor: Boolean = isStatic && symbol.rawname == nme.CONSTRUCTOR - override def toString() = symbol.fullName import opcodes._ - def checkLocals: Unit = if (code ne null) { - Console.println("[checking locals of " + this + "]") - for (bb <- code.blocks; i <- bb) i match { - case LOAD_LOCAL(l) => - if (!this.locals.contains(l)) - Console.println("Local " + l + " is not declared in " + this) - case STORE_LOCAL(l) => - if (!this.locals.contains(l)) - Console.println("Local " + l + " is not declared in " + this) - case _ => () + def checkLocals: Unit = { + def localsSet = code.blocks.flatten collect { + case LOAD_LOCAL(l) => l + case STORE_LOCAL(l) => l + } toSet + + if (code != null) { + Console.println("[checking locals of " + this + "]") + locals filterNot localsSet foreach { l => + Console.println("Local " + l + " is not declared in " + this) + } } } @@ -276,13 +264,11 @@ trait Members { self: ICodes => /** PC-based ranges for this local variable's visibility */ var ranges: List[(Int, Int)] = Nil - override def equals(other: Any): Boolean = ( - other.isInstanceOf[Local] && - other.asInstanceOf[Local].sym == this.sym - ); - + override def equals(other: Any): Boolean = other match { + case x: Local => sym == x.sym + case _ => false + } override def hashCode = sym.hashCode - - override def toString(): String = sym.toString() + override def toString(): String = sym.toString } } diff --git a/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala b/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala index 7024687e0e..7f2dd7684a 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala @@ -319,12 +319,12 @@ trait Opcodes { self: ICodes => * ->: ...:result * */ - case class CALL_METHOD(method: Symbol, style: InvokeStyle) extends Instruction { + case class CALL_METHOD(method: Symbol, style: InvokeStyle) extends Instruction with ReferenceEquality { /** Returns a string representation of this instruction */ override def toString(): String = "CALL_METHOD " + hostClass.fullName + method.fullName +" ("+style.toString()+")"; - var hostClass: Symbol = method.owner; + var hostClass: Symbol = method.owner def setHostClass(cls: Symbol): this.type = { hostClass = cls; this } /** This is specifically for preserving the target native Array type long @@ -333,38 +333,32 @@ trait Opcodes { self: ICodes => var targetTypeKind: TypeKind = UNIT // the default should never be used, so UNIT should fail fast. def setTargetTypeKind(tk: TypeKind) = targetTypeKind = tk - override def consumed = method.tpe.paramTypes.length + ( - style match { - case Dynamic | InvokeDynamic => 1 - case Static(true) => 1 - case Static(false) => 0 - case SuperCall(_) => 1 - } - ) + private def params = method.info.paramTypes + private def consumesInstance = style match { + case Static(false) => 0 + case _ => 1 + } + override def consumed = params.length + consumesInstance override def consumedTypes = { - val args = method.tpe.paramTypes map toTypeKind - style match { - case Dynamic | Static(true) => AnyRefReference :: args - case _ => args - } + val args = params map toTypeKind + if (consumesInstance > 0) AnyRefReference :: args + else args } override def produced = - if(toTypeKind(method.tpe.resultType) == UNIT) - 0 - else if(method.isConstructor) - 0 + if (producedType == UNIT || method.isConstructor) 0 else 1 + private def producedType: TypeKind = toTypeKind(method.info.resultType) + override def producedTypes = + if (produced == 0) Nil + else List(producedType) + /** object identity is equality for CALL_METHODs. Needed for * being able to store such instructions into maps, when more * than one CALL_METHOD to the same method might exist. */ - override def equals(other: Any) = other match { - case o: AnyRef => this eq o - case _ => false - } } case class BOX(boxType: TypeKind) extends Instruction { @@ -614,7 +608,6 @@ trait Opcodes { self: ICodes => /** This class represents a method invocation style. */ sealed abstract class InvokeStyle { - /** Is this a dynamic method call? */ def isDynamic: Boolean = this match { case Dynamic => true diff --git a/src/compiler/scala/tools/nsc/backend/icode/Repository.scala b/src/compiler/scala/tools/nsc/backend/icode/Repository.scala index 23e79c1a24..edbbd54769 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Repository.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Repository.scala @@ -24,17 +24,13 @@ trait Repository { def available(sym: Symbol) = classes.contains(sym) || loaded.contains(sym) /** The icode of the given class, if available */ - def icode(sym: Symbol): Option[IClass] = - if (classes.contains(sym)) Some(classes(sym)) - else if (loaded.contains(sym)) Some(loaded(sym)) - else None + def icode(sym: Symbol): Option[IClass] = (classes get sym) orElse (loaded get sym) /** The icode of the given class. If not available, it loads * its bytecode. */ def icode(sym: Symbol, force: Boolean): IClass = - if (available(sym)) icode(sym).get - else { + icode(sym) getOrElse { log("loading " + sym) load(sym) assert(available(sym)) @@ -46,7 +42,8 @@ trait Repository { try { val (c1, c2) = icodeReader.readClass(sym) - assert(c1.symbol == sym || c2.symbol == sym, "c1.symbol = %s, c2.symbol = %s, sym = %s".format(c1.symbol, c2.symbol, sym)) + assert(c1.symbol == sym || c2.symbol == sym, + "c1.symbol = %s, c2.symbol = %s, sym = %s".format(c1.symbol, c2.symbol, sym)) loaded += (c1.symbol -> c1) loaded += (c2.symbol -> c2) } catch { diff --git a/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala b/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala index 24e025518e..62042ce3ce 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala @@ -94,9 +94,6 @@ trait TypeKinds { self: ICodes => case _ => this eq other }) - override def equals(other: Any): Boolean = - this eq other.asInstanceOf[AnyRef] - /** Is this type a category 2 type in JVM terms? */ def isWideType: Boolean = this match { case DOUBLE | LONG => true @@ -288,11 +285,6 @@ trait TypeKinds { self: ICodes => } override def isReferenceType: Boolean = true; - - override def equals(other: Any): Boolean = other match { - case REFERENCE(cls2) => cls == cls2 - case _ => false - } } // final case class VALUE(cls: Symbol) extends TypeKind { @@ -356,12 +348,6 @@ trait TypeKinds { self: ICodes => true // TODO: platform dependent! case _ => false } - - override def equals(other: Any): Boolean = other match { - case ARRAY(elem2) => elem == elem2 - case _ => false - } - } /** A boxed value. */ @@ -393,12 +379,6 @@ trait TypeKinds { self: ICodes => case _ => false } - - override def equals(other: Any): Boolean = other match { - case BOXED(kind2) => kind == kind2 - case _ => false - } - } /** diff --git a/src/compiler/scala/tools/nsc/backend/icode/TypeStacks.scala b/src/compiler/scala/tools/nsc/backend/icode/TypeStacks.scala index d334af525f..4c52d36d33 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/TypeStacks.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/TypeStacks.scala @@ -3,7 +3,6 @@ * @author Martin Odersky */ - package scala.tools.nsc package backend package icode @@ -13,23 +12,18 @@ package icode * @author Iulian Dragos * @version 1.0 */ -trait TypeStacks { self: ICodes => +trait TypeStacks { + self: ICodes => + import opcodes._ - import global.{Symbol, Type, definitions} /* This class simulates the type of the operand * stack of the ICode. */ type Rep = List[TypeKind] - class TypeStack { - var types: Rep = Nil - - def this(stack: Rep) = { - this() - this.types = stack - } - + class TypeStack(var types: Rep) { + def this() = this(Nil) def this(that: TypeStack) = this(that.types) def length: Int = types.length @@ -82,7 +76,7 @@ trait TypeStacks { self: ICodes => override def hashCode() = types.hashCode() override def equals(other: Any): Boolean = other match { - case x: TypeStack => x.types sameElements types + case x: TypeStack => x.types == types case _ => false } } diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala index 5d6f5045bc..1c484c7d8e 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala @@ -56,14 +56,16 @@ abstract class CopyPropagation { def emptyBinding = new HashMap[Location, Value]() class State(val bindings: Bindings, var stack: List[Value]) { - override def equals(that: Any): Boolean = - (this eq that.asInstanceOf[AnyRef]) || (that match { - /* comparison with bottom is reference equality! */ - case other: State if (this ne bottom) && (other ne bottom) => - (this.bindings == other.bindings) && - (this.stack corresponds other.stack)(_ == _) // @PP: corresponds - case _ => false - }) + + override def hashCode = bindings.hashCode + stack.hashCode + /* comparison with bottom is reference equality! */ + override def equals(that: Any): Boolean = that match { + case x: State => + if ((this eq bottom) || (this eq top) || (x eq bottom) || (x eq top)) this eq x + else bindings == x.bindings && stack == x.stack + case _ => + false + } /* Return an alias for the given local. It returns the last * local in the chain of aliased locals. Cycles are not allowed @@ -84,30 +86,20 @@ abstract class CopyPropagation { /* Return the value bound to the given local. */ def getBinding(l: Local): Value = { - var target = l - var stop = false - var value: Value = Deref(LocalVar(target)) - - while (bindings.isDefinedAt(LocalVar(target)) && !stop) { -// Console.println("finding binding for " + target) - value = bindings(LocalVar(target)) - value match { - case Deref(LocalVar(t)) => target = t - case _ => stop = true - } + def loop(lv: Local): Option[Value] = (bindings get LocalVar(lv)) match { + case Some(Deref(LocalVar(t))) => loop(t) + case x => x } - value + loop(l) getOrElse Deref(LocalVar(l)) } /* Return the binding for the given field of the given record */ def getBinding(r: Record, f: Symbol): Value = { - assert(r.bindings.isDefinedAt(f), - "Record " + r + " does not contain a field " + f); + assert(r.bindings contains f, "Record " + r + " does not contain a field " + f) - var target: Value = r.bindings(f); - target match { + r.bindings(f) match { case Deref(LocalVar(l)) => getBinding(l) - case _ => target + case target => target } } @@ -115,17 +107,10 @@ abstract class CopyPropagation { * If the field holds a reference to a local, the returned value is the * binding of that local. */ - def getFieldValue(r: Record, f: Symbol): Option[Value] = { - if(!r.bindings.isDefinedAt(f)) None else { - var target: Value = r.bindings(f) - target match { - case Deref(LocalVar(l)) => Some(getBinding(l)) - case Deref(Field(r1, f1)) => getFieldValue(r1, f1) orElse Some(target) -// case Deref(This) => Some(target) -// case Const(k) => Some(target) - case _ => Some(target) - } - } + def getFieldValue(r: Record, f: Symbol): Option[Value] = r.bindings get f map { + case Deref(LocalVar(l)) => getBinding(l) + case target @ Deref(Field(r1, f1)) => getFieldValue(r1, f1) getOrElse target + case target => target } /** The same as getFieldValue, but never returns Record/Field values. Use @@ -133,26 +118,23 @@ abstract class CopyPropagation { * or a constant/this value). */ def getFieldNonRecordValue(r: Record, f: Symbol): Option[Value] = { - assert(r.bindings.isDefinedAt(f), - "Record " + r + " does not contain a field " + f); + assert(r.bindings contains f, "Record " + r + " does not contain a field " + f) - var target: Value = r.bindings(f) - target match { + r.bindings(f) match { case Deref(LocalVar(l)) => val alias = getAlias(l) val derefAlias = Deref(LocalVar(alias)) - getBinding(alias) match { - case Record(_, _) => Some(derefAlias) - case Deref(Field(r1, f1)) => - getFieldNonRecordValue(r1, f1) orElse Some(derefAlias) - case Boxed(_) => Some(derefAlias) - case v => Some(v) - } - case Deref(Field(r1, f1)) => - getFieldNonRecordValue(r1, f1) orElse None - case Deref(This) => Some(target) - case Const(k) => Some(target) - case _ => None + + Some(getBinding(alias) match { + case Record(_, _) => derefAlias + case Deref(Field(r1, f1)) => getFieldNonRecordValue(r1, f1) getOrElse derefAlias + case Boxed(_) => derefAlias + case v => v + }) + case Deref(Field(r1, f1)) => getFieldNonRecordValue(r1, f1) + case target @ Deref(This) => Some(target) + case target @ Const(k) => Some(target) + case _ => None } } @@ -174,7 +156,7 @@ abstract class CopyPropagation { val exceptionHandlerStack = Unknown :: Nil def lub2(exceptional: Boolean)(a: Elem, b: Elem): Elem = { - if (a eq bottom) b + if (a eq bottom) b else if (b eq bottom) a else if (a == b) a else { diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/Liveness.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/Liveness.scala index c1e5a0eac7..654acc7fe9 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/analysis/Liveness.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/Liveness.scala @@ -5,7 +5,8 @@ package scala.tools.nsc -package backend.icode.analysis +package backend.icode +package analysis import scala.collection.mutable.{HashMap, Map} import scala.collection.immutable.{Set, ListSet} @@ -24,13 +25,8 @@ abstract class Liveness { object livenessLattice extends SemiLattice { type Elem = Set[Local] - val top: Elem = new ListSet[Local]() { - override def equals(that: Any): Boolean = this eq that.asInstanceOf[AnyRef] - } - - val bottom: Elem = new ListSet[Local]() { - override def equals(that: Any): Boolean = this eq that.asInstanceOf[AnyRef] - } + object top extends ListSet[Local] with ReferenceEquality + object bottom extends ListSet[Local] with ReferenceEquality def lub2(exceptional: Boolean)(a: Elem, b: Elem): Elem = a ++ b } diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/ReachingDefinitions.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/ReachingDefinitions.scala index e993a38dfa..c0de380b02 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/analysis/ReachingDefinitions.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/ReachingDefinitions.scala @@ -5,10 +5,12 @@ package scala.tools.nsc -package backend.icode.analysis +package backend.icode +package analysis -import scala.collection.immutable.{Set, ListSet, HashSet} -import scala.collection.mutable.{HashMap, Map} +import scala.collection.{ mutable, immutable } +import immutable.ListSet +import mutable.HashMap /** Compute reaching definitions. We are only interested in reaching * definitions for local variables, since values on the stack @@ -29,12 +31,12 @@ abstract class ReachingDefinitions { type StackPos = Set[(BasicBlock, Int)] type Stack = List[StackPos] - val top: Elem = IState(new ListSet[Definition](), Nil) + private def referenceEqualSet(name: String) = new ListSet[Definition] with ReferenceEquality { + override def toString = "<" + name + ">" + } - val bottom: Elem = IState(new ListSet[Definition]() { - override def equals(that: Any): Boolean = this eq that.asInstanceOf[AnyRef] - override def toString = "<bottom>" - }, Nil) + val top: Elem = IState(referenceEqualSet("top"), Nil) + val bottom: Elem = IState(referenceEqualSet("bottom"), Nil) /** The least upper bound is set inclusion for locals, and pairwise set inclusion for stacks. */ def lub2(exceptional: Boolean)(a: Elem, b: Elem): Elem = @@ -43,8 +45,8 @@ abstract class ReachingDefinitions { else { val locals = a.vars ++ b.vars val stack = - if (a.stack == Nil) b.stack - else if (b.stack == Nil) a.stack + if (a.stack.isEmpty) b.stack + else if (b.stack.isEmpty) a.stack else (a.stack, b.stack).zipped map (_ ++ _) IState(locals, stack) @@ -67,10 +69,10 @@ abstract class ReachingDefinitions { var method: IMethod = _ - val gen: Map[BasicBlock, Set[Definition]] = new HashMap() - val kill:Map[BasicBlock, Set[Local]] = new HashMap() - val drops: Map[BasicBlock, Int] = new HashMap() - val outStack: Map[BasicBlock, Stack] = new HashMap() + val gen: mutable.Map[BasicBlock, Set[Definition]] = new HashMap() + val kill: mutable.Map[BasicBlock, Set[Local]] = new HashMap() + val drops: mutable.Map[BasicBlock, Int] = new HashMap() + val outStack: mutable.Map[BasicBlock, Stack] = new HashMap() def init(m: IMethod) { this.method = m @@ -102,8 +104,8 @@ abstract class ReachingDefinitions { import opcodes._ def genAndKill(b: BasicBlock): (Set[Definition], Set[Local]) = { - var genSet: Set[Definition] = new HashSet - var killSet: Set[Local] = new HashSet + var genSet: Set[Definition] = new immutable.HashSet + var killSet: Set[Local] = new immutable.HashSet for ((i, idx) <- b.toList.zipWithIndex) i match { case STORE_LOCAL(local) => killSet = killSet + local diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/SemiLattice.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/SemiLattice.scala index 10c03f4455..2b41f34967 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/analysis/SemiLattice.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/SemiLattice.scala @@ -5,7 +5,8 @@ package scala.tools.nsc -package backend.icode.analysis +package backend.icode +package analysis /** A complete lattice. */ @@ -16,17 +17,18 @@ trait SemiLattice { * equals method uses reference equality for top and bottom, * and structural equality for other values. */ - case class IState[V, S](val vars: V, val stack: S) { + final case class IState[V, S](vars: V, stack: S) { + override def hashCode = vars.hashCode + stack.hashCode override def equals(other: Any): Boolean = other match { - case that: IState[_, _] => - if ((this eq bottom) || (that eq bottom)) this eq that - else if ((this eq top) || (that eq top)) this eq that - else (stack == that.stack && vars == that.vars) - case _ => false + case x: IState[_, _] => + if ((this eq bottom) || (this eq top) || (x eq bottom) || (x eq top)) this eq x + else stack == x.stack && vars == x.vars + case _ => + false } } - /** Return the least upper bound of <code>a</code> and <code>b</code> */ + /** Return the least upper bound of a and b. */ def lub2(exceptional: Boolean)(a: Elem, b: Elem): Elem /** Return the top element. */ @@ -36,11 +38,8 @@ trait SemiLattice { def bottom: Elem /** Compute the least upper bound of a list of elements. */ - def lub(xs: List[Elem], exceptional: Boolean): Elem = try { - if (xs == Nil) bottom else xs reduceLeft lub2(exceptional) - } catch { - case e: LubException => - Console.println("Lub on blocks: " + xs) - throw e - } + def lub(xs: List[Elem], exceptional: Boolean): Elem = + if (xs.isEmpty) bottom + else try xs reduceLeft lub2(exceptional) + catch { case e: LubException => Console.println("Lub on blocks: " + xs) ; throw e } } diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala index fd38ae0ff4..b26b799f6d 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala @@ -16,17 +16,15 @@ import scala.collection.{mutable, immutable} abstract class TypeFlowAnalysis { val global: Global import global._ + import definitions.{ ObjectClass, NothingClass, AnyRefClass, StringClass } /** The lattice of ICode types. */ object typeLattice extends SemiLattice { type Elem = icodes.TypeKind - val Object = icodes.REFERENCE(global.definitions.ObjectClass) - val All = icodes.REFERENCE(global.definitions.NothingClass) - - def top = Object - def bottom = All + val top = icodes.REFERENCE(ObjectClass) + val bottom = icodes.REFERENCE(NothingClass) def lub2(exceptional: Boolean)(a: Elem, b: Elem) = if (a eq bottom) b @@ -41,9 +39,9 @@ abstract class TypeFlowAnalysis { import icodes._ type Elem = TypeStack - override val top = new TypeStack - override val bottom = new TypeStack - val exceptionHandlerStack: TypeStack = new TypeStack(List(REFERENCE(definitions.AnyRefClass))) + val top = new TypeStack + val bottom = new TypeStack + val exceptionHandlerStack: TypeStack = new TypeStack(List(REFERENCE(AnyRefClass))) def lub2(exceptional: Boolean)(s1: TypeStack, s2: TypeStack) = { if (s1 eq bottom) s2 @@ -59,10 +57,7 @@ abstract class TypeFlowAnalysis { /** A map which returns the bottom type for unfound elements */ class VarBinding extends mutable.HashMap[icodes.Local, icodes.TypeKind] { - override def get(l: icodes.Local) = super.get(l) match { - case Some(t) => Some(t) - case None => Some(typeLattice.bottom) - } + override def get(l: icodes.Local) = super.get(l) orElse Some(typeLattice.bottom) def this(o: VarBinding) = { this() @@ -77,32 +72,25 @@ abstract class TypeFlowAnalysis { import icodes._ type Elem = IState[VarBinding, icodes.TypeStack] - override val top = new Elem(new VarBinding, typeStackLattice.top) - override val bottom = new Elem(new VarBinding, typeStackLattice.bottom) - -// var lubs = 0 + val top = new Elem(new VarBinding, typeStackLattice.top) + val bottom = new Elem(new VarBinding, typeStackLattice.bottom) def lub2(exceptional: Boolean)(a: Elem, b: Elem) = { - val IState(env1, s1) = a - val IState(env2, s2) = b - -// lubs += 1 + val IState(env1, _) = a + val IState(env2, _) = b val resultingLocals = new VarBinding - - for (binding1 <- env1.iterator) { - val tp2 = env2(binding1._1) - resultingLocals += ((binding1._1, typeLattice.lub2(exceptional)(binding1._2, tp2))) + env1 foreach { case (k, v) => + resultingLocals += ((k, typeLattice.lub2(exceptional)(v, env2(k)))) } - - for (binding2 <- env2.iterator if resultingLocals(binding2._1) eq typeLattice.bottom) { - val tp1 = env1(binding2._1) - resultingLocals += ((binding2._1, typeLattice.lub2(exceptional)(binding2._2, tp1))) + env2 collect { case (k, v) if resultingLocals(k) eq typeLattice.bottom => + resultingLocals += ((k, typeLattice.lub2(exceptional)(v, env1(k)))) } - - IState(resultingLocals, + val stack = if (exceptional) typeStackLattice.exceptionHandlerStack - else typeStackLattice.lub2(exceptional)(a.stack, b.stack)) + else typeStackLattice.lub2(exceptional)(a.stack, b.stack) + + IState(resultingLocals, stack) } } @@ -115,7 +103,7 @@ abstract class TypeFlowAnalysis { type P = BasicBlock val lattice = typeFlowLattice - val STRING = icodes.REFERENCE(TypeFlowAnalysis.this.global.definitions.StringClass) + val STRING = icodes.REFERENCE(StringClass) var method: IMethod = _ /** Initialize the in/out maps for the analysis of the given method. */ @@ -131,8 +119,7 @@ abstract class TypeFlowAnalysis { } // start block has var bindings for each of its parameters - val entryBindings = new VarBinding - m.params.foreach(p => entryBindings += ((p, p.kind))) + val entryBindings = new VarBinding ++= (m.params map (p => ((p, p.kind)))) in(m.code.startBlock) = lattice.IState(entryBindings, typeStackLattice.bottom) m.exh foreach { e => @@ -143,7 +130,7 @@ abstract class TypeFlowAnalysis { /** reinitialize the analysis, keeping around solutions from a previous run. */ def reinit(m: icodes.IMethod) { - if ((this.method eq null) || (this.method.symbol != m.symbol)) + if (this.method == null || this.method.symbol != m.symbol) init(m) else reinit { for (b <- m.code.blocks; if !in.isDefinedAt(b)) { @@ -154,12 +141,12 @@ abstract class TypeFlowAnalysis { } /* else in(b) = typeFlowLattice.bottom -*/ } +*/ } out(b) = typeFlowLattice.bottom } - for (exh <- m.exh; if !in.isDefinedAt(exh.startBlock)) { - worklist += exh.startBlock - in(exh.startBlock) = lattice.IState(in(exh.startBlock).vars, typeStackLattice.exceptionHandlerStack) + m.exh map (_.startBlock) filterNot (in contains _) foreach { start => + worklist += start + in(start) = lattice.IState(in(start).vars, typeStackLattice.exceptionHandlerStack) } } } @@ -187,12 +174,12 @@ abstract class TypeFlowAnalysis { def blockTransfer(b: BasicBlock, in: lattice.Elem): lattice.Elem = { b.foldLeft(in)(interpret) } - /** The flow function of a given basic block. */ - var flowFun: immutable.Map[BasicBlock, TransferFunction] = new immutable.HashMap + /* var flowFun: immutable.Map[BasicBlock, TransferFunction] = new immutable.HashMap */ /** Fill flowFun with a transfer function per basic block. */ -/* private def buildFlowFunctions(blocks: List[BasicBlock]) { +/* + private def buildFlowFunctions(blocks: List[BasicBlock]) { def transfer(b: BasicBlock): TransferFunction = { var gens: List[Gen] = Nil var consumed: Int = 0 @@ -487,25 +474,9 @@ abstract class TypeFlowAnalysis { stack push ConcatClass } - case CALL_METHOD(method, style) => style match { - case Dynamic | InvokeDynamic => - stack.pop(1 + method.info.paramTypes.length) - stack.push(toTypeKind(method.info.resultType)) - - case Static(onInstance) => - if (onInstance) { - stack.pop(1 + method.info.paramTypes.length) - if (!method.isConstructor) - stack.push(toTypeKind(method.info.resultType)); - } else { - stack.pop(method.info.paramTypes.length) - stack.push(toTypeKind(method.info.resultType)) - } - - case SuperCall(mix) => - stack.pop(1 + method.info.paramTypes.length) - stack.push(toTypeKind(method.info.resultType)) - } + case cm @ CALL_METHOD(_, _) => + stack pop cm.consumed + cm.producedTypes foreach (stack push _) case BOX(kind) => stack.pop @@ -566,7 +537,7 @@ abstract class TypeFlowAnalysis { case LOAD_EXCEPTION() => stack.pop(stack.length) - stack.push(typeLattice.Object) + stack.push(typeLattice.top) case _ => dump diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala index 2d2146d113..57e41d9867 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala @@ -29,6 +29,12 @@ abstract class GenJVM extends SubComponent { import global._ import icodes._ import icodes.opcodes._ + import definitions.{ + NullClass, RuntimeNullClass, NothingClass, RuntimeNothingClass, + AnyClass, ObjectClass, ThrowsClass, ThrowableClass, ClassfileAnnotationClass, + DeprecatedAttr, + getPrimitiveCompanion + } val phaseName = "jvm" @@ -78,6 +84,10 @@ abstract class GenJVM extends SubComponent { val MIN_SWITCH_DENSITY = 0.7 val INNER_CLASSES_FLAGS = (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL | ACC_INTERFACE | ACC_ABSTRACT) + + val PublicStatic = ACC_PUBLIC | ACC_STATIC + val PublicStaticFinal = ACC_PUBLIC | ACC_STATIC | ACC_FINAL + val StringBuilderClass = definitions.getClass2("scala.StringBuilder", "scala.collection.mutable.StringBuilder").fullName val BoxesRunTime = "scala.runtime.BoxesRunTime" @@ -205,7 +215,7 @@ abstract class GenJVM extends SubComponent { (parents contains ParcelableInterface.tpe) if (parents.isEmpty) - parents = definitions.ObjectClass.tpe :: parents; + parents = ObjectClass.tpe :: parents; for (annot <- c.symbol.annotations) annot match { case AnnotationInfo(tp, _, _) if tp.typeSymbol == SerializableAttr => @@ -249,7 +259,7 @@ abstract class GenJVM extends SubComponent { } } else { - if (c.containsStaticCtor) addStaticInit(jclass, c.lookupStaticCtor) + c.lookupStaticCtor foreach (constructor => addStaticInit(jclass, Some(constructor))) // it must be a top level class (name contains no $s) def isCandidateForForwarders(sym: Symbol): Boolean = @@ -312,7 +322,7 @@ abstract class GenJVM extends SubComponent { !m.symbol.isGetter && !m.symbol.isSetter) yield javaName(m.symbol) - val constructor = beanInfoClass.addNewMethod(JAccessFlags.ACC_PUBLIC, "<init>", JType.VOID, javaTypes(Nil), javaNames(Nil)) + val constructor = beanInfoClass.addNewMethod(ACC_PUBLIC, "<init>", JType.VOID, javaTypes(Nil), javaNames(Nil)) val jcode = constructor.getCode().asInstanceOf[JExtendedCode] val strKind = new JObjectType(javaName(definitions.StringClass)) val stringArrayKind = new JArrayType(strKind) @@ -371,7 +381,7 @@ abstract class GenJVM extends SubComponent { // put some random value; the actual number is determined at the end buf.putShort(0xbaba.toShort) - for (AnnotationInfo(tp, List(exc), _) <- excs.distinct if tp.typeSymbol == definitions.ThrowsClass) { + for (AnnotationInfo(tp, List(exc), _) <- excs.distinct if tp.typeSymbol == ThrowsClass) { val Literal(const) = exc buf.putShort( cpool.addClass( @@ -389,7 +399,7 @@ abstract class GenJVM extends SubComponent { */ private def shouldEmitAnnotation(annot: AnnotationInfo) = (annot.atp.typeSymbol.initialize.hasFlag(Flags.JAVA) && - annot.atp.typeSymbol.isNonBottomSubClass(definitions.ClassfileAnnotationClass) && + annot.atp.typeSymbol.isNonBottomSubClass(ClassfileAnnotationClass) && annot.args.isEmpty) private def emitJavaAnnotations(cpool: JConstantPool, buf: ByteBuffer, annotations: List[AnnotationInfo]): Int = { @@ -515,7 +525,7 @@ abstract class GenJVM extends SubComponent { jmember addAttribute attr } - val toEmit = annotations.filter(shouldEmitAnnotation(_)) + val toEmit = annotations filter shouldEmitAnnotation if (toEmit.isEmpty) return val buf: ByteBuffer = ByteBuffer.allocate(2048) @@ -524,8 +534,8 @@ abstract class GenJVM extends SubComponent { } def addParamAnnotations(jmethod: JMethod, pannotss: List[List[AnnotationInfo]]) { - val annotations = pannotss map (annots => annots.filter(shouldEmitAnnotation(_))) - if (annotations.forall(_.isEmpty)) return; + val annotations = pannotss map (_ filter shouldEmitAnnotation) + if (annotations forall (_.isEmpty)) return val buf: ByteBuffer = ByteBuffer.allocate(2048) @@ -553,10 +563,8 @@ abstract class GenJVM extends SubComponent { } def addInnerClasses(jclass: JClass) { - def addOwnInnerClasses(cls: Symbol) { - for (sym <- cls.info.decls.iterator if sym.isClass) - innerClasses = innerClasses + sym; - } + def addOwnInnerClasses(cls: Symbol): Unit = + innerClasses ++= (cls.info.decls filter (_.isClass)) // add inner classes which might not have been referenced yet atPhase(currentRun.erasurePhase.next) { @@ -572,10 +580,10 @@ abstract class GenJVM extends SubComponent { var outerName = javaName(innerSym.rawowner) // remove the trailing '$' if (outerName.endsWith("$") && isTopLevelModule(innerSym.rawowner)) - outerName = outerName.substring(0, outerName.length - 1) + outerName = outerName dropRight 1 var flags = javaFlags(innerSym) if (innerSym.rawowner.hasFlag(Flags.MODULE)) - flags |= JAccessFlags.ACC_STATIC + flags |= ACC_STATIC innerClassesAttr.addEntry(javaName(innerSym), outerName, @@ -596,30 +604,29 @@ abstract class GenJVM extends SubComponent { def genField(f: IField) { if (settings.debug.value) - log("Adding field: " + f.symbol.fullName); - var attributes = 0 - - f.symbol.annotations foreach { a => a match { - case AnnotationInfo(tp, _, _) if tp.typeSymbol == TransientAtt => - attributes = attributes | JAccessFlags.ACC_TRANSIENT - case AnnotationInfo(tp, _, _) if tp.typeSymbol == VolatileAttr => - attributes = attributes | JAccessFlags.ACC_VOLATILE - case _ => (); - }} + log("Adding field: " + f.symbol.fullName) + + val attributes = f.symbol.annotations.map(_.atp.typeSymbol).foldLeft(0) { + case (res, TransientAtt) => res | ACC_TRANSIENT + case (res, VolatileAttr) => res | ACC_VOLATILE + case (res, _) => res + } + var flags = javaFlags(f.symbol) - if (!f.symbol.hasFlag(Flags.MUTABLE)) - flags = flags | JAccessFlags.ACC_FINAL + if (!f.symbol.isMutable) + flags |= ACC_FINAL val jfield = jclass.addNewField(flags | attributes, javaName(f.symbol), - javaType(f.symbol.tpe)); + javaType(f.symbol.tpe)) + addGenericSignature(jfield, f.symbol, clasz.symbol) addAnnotations(jfield, f.symbol.annotations) } def genMethod(m: IMethod) { - if (m.isStaticCtor) return + if (m.symbol.isStaticConstructor) return log("Generating method " + m.symbol.fullName) method = m @@ -632,11 +639,11 @@ abstract class GenJVM extends SubComponent { var flags = javaFlags(m.symbol) if (jclass.isInterface()) - flags = flags | JAccessFlags.ACC_ABSTRACT; + flags |= ACC_ABSTRACT // native methods of objects are generated in mirror classes if (method.native) - flags = flags | JAccessFlags.ACC_NATIVE + flags |= ACC_NATIVE jmethod = jclass.addNewMethod(flags, javaName(m.symbol), @@ -679,7 +686,7 @@ abstract class GenJVM extends SubComponent { } addGenericSignature(jmethod, m.symbol, clasz.symbol) - val (excs, others) = splitAnnotations(m.symbol.annotations, definitions.ThrowsClass) + val (excs, others) = splitAnnotations(m.symbol.annotations, ThrowsClass) addExceptionsAttribute(jmethod, excs) addAnnotations(jmethod, others) addParamAnnotations(jmethod, m.params.map(_.sym.annotations)) @@ -687,7 +694,7 @@ abstract class GenJVM extends SubComponent { private def addRemoteException(jmethod: JMethod, meth: Symbol) { def isRemoteThrows(ainfo: AnnotationInfo) = ainfo match { - case AnnotationInfo(tp, List(arg), _) if tp.typeSymbol == definitions.ThrowsClass => + case AnnotationInfo(tp, List(arg), _) if tp.typeSymbol == ThrowsClass => arg match { case Literal(Constant(tpe: Type)) if tpe.typeSymbol == RemoteException.typeSymbol => true case _ => false @@ -698,7 +705,7 @@ abstract class GenJVM extends SubComponent { if (isRemoteClass || (meth.hasAnnotation(RemoteAttr) && jmethod.isPublic())) { val c = Constant(RemoteException) - val ainfo = AnnotationInfo(definitions.ThrowsClass.tpe, List(Literal(c).setType(c.tpe)), List()) + val ainfo = AnnotationInfo(ThrowsClass.tpe, List(Literal(c).setType(c.tpe)), List()) if (!meth.annotations.exists(isRemoteThrows)) { meth addAnnotation ainfo } @@ -726,15 +733,13 @@ abstract class GenJVM extends SubComponent { } def addModuleInstanceField { - import JAccessFlags._ - jclass.addNewField(ACC_PUBLIC | ACC_FINAL | ACC_STATIC, + jclass.addNewField(PublicStaticFinal, nme.MODULE_INSTANCE_FIELD.toString, jclass.getType()) } def addStaticInit(cls: JClass, mopt: Option[IMethod]) { - import JAccessFlags._ - val clinitMethod = cls.addNewMethod(ACC_PUBLIC | ACC_STATIC, + val clinitMethod = cls.addNewMethod(PublicStatic, "<clinit>", JType.VOID, JType.EMPTY_ARRAY, @@ -809,10 +814,9 @@ abstract class GenJVM extends SubComponent { serialVUID match { case Some(value) => val fieldName = "serialVersionUID" - jclass.addNewField(ACC_STATIC | ACC_PUBLIC | ACC_FINAL, - fieldName, - JType.LONG) + jclass.addNewField(PublicStaticFinal, fieldName, JType.LONG) clinit emitPUSH value + clinit.emitPUSH(value) clinit.emitPUTSTATIC(jclass.getName(), fieldName, JType.LONG) case None => () } @@ -858,8 +862,7 @@ abstract class GenJVM extends SubComponent { def addForwarder(jclass: JClass, module: Symbol, m: Symbol) { import JAccessFlags._ val moduleName = javaName(module) // + "$" - val mirrorName = moduleName.substring(0, moduleName.length() - 1) - + val mirrorName = moduleName dropRight 1 val methodInfo = module.thisType.memberInfo(m) val paramJavaTypes = methodInfo.paramTypes map toTypeKind @@ -868,7 +871,8 @@ abstract class GenJVM extends SubComponent { for (i <- 0 until paramJavaTypes.length) paramNames(i) = "x_" + i - val mirrorMethod = jclass.addNewMethod(ACC_PUBLIC | ACC_FINAL | ACC_STATIC, + val mirrorMethod = jclass.addNewMethod( + PublicStaticFinal, javaName(m), javaType(methodInfo.resultType), javaTypes(paramJavaTypes), @@ -894,7 +898,7 @@ abstract class GenJVM extends SubComponent { if (!m.hasFlag(Flags.DEFERRED)) addGenericSignature(mirrorMethod, m, module) - val (throws, others) = splitAnnotations(m.annotations, definitions.ThrowsClass) + val (throws, others) = splitAnnotations(m.annotations, ThrowsClass) addExceptionsAttribute(mirrorMethod, throws) addAnnotations(mirrorMethod, others) addParamAnnotations(mirrorMethod, m.info.params.map(_.annotations)) @@ -931,14 +935,14 @@ abstract class GenJVM extends SubComponent { /** Should method `m' get a forwarder in the mirror class? */ def shouldForward(m: Symbol): Boolean = atPhase(currentRun.picklerPhase) ( - m.owner != definitions.ObjectClass + m.owner != ObjectClass && m.isMethod && !m.hasFlag(Flags.CASE | Flags.PRIVATE | Flags.PROTECTED | Flags.DEFERRED | Flags.SPECIALIZED) && !m.isConstructor && !m.isStaticMember - && !(m.owner == definitions.AnyClass) + && !(m.owner == AnyClass) && !module.isSubClass(module.companionClass) - && !conflictsIn(definitions.ObjectClass, m.name) + && !conflictsIn(ObjectClass, m.name) && !conflictsInCommonParent(m.name) && !conflictsIn(module.companionClass, m.name) ) @@ -960,7 +964,7 @@ abstract class GenJVM extends SubComponent { def dumpMirrorClass(clasz: Symbol, sourceFile: String) { import JAccessFlags._ val moduleName = javaName(clasz) // + "$" - val mirrorName = moduleName.substring(0, moduleName.length() - 1) + val mirrorName = moduleName dropRight 1 val mirrorClass = fjbgContext.JClass(ACC_SUPER | ACC_PUBLIC | ACC_FINAL, mirrorName, "java.lang.Object", @@ -1083,7 +1087,7 @@ abstract class GenJVM extends SubComponent { if (settings.debug.value) log("Adding exception handler " + e + "at block: " + e.startBlock + " for " + method + " from: " + p._1 + " to: " + p._2 + " catching: " + e.cls); - val cls = if (e.cls == NoSymbol || e.cls == definitions.ThrowableClass) null + val cls = if (e.cls == NoSymbol || e.cls == ThrowableClass) null else javaName(e.cls) jcode.addExceptionHandler(p._1, p._2, labels(e.startBlock).getAnchor(), @@ -1422,10 +1426,11 @@ abstract class GenJVM extends SubComponent { lv.start = jcode.getPC() case SCOPE_EXIT(lv) => - if (varsInBlock contains lv) { + if (varsInBlock(lv)) { lv.ranges = (lv.start, jcode.getPC()) :: lv.ranges varsInBlock -= lv - } else if (b.varsInScope contains lv) { + } + else if (b.varsInScope(lv)) { lv.ranges = (labels(b).getAnchor(), jcode.getPC()) :: lv.ranges b.varsInScope -= lv } else @@ -1798,21 +1803,20 @@ abstract class GenJVM extends SubComponent { def javaName(sym: Symbol): String = { val suffix = moduleSuffix(sym) - if (sym == definitions.NothingClass) - return javaName(definitions.RuntimeNothingClass) - else if (sym == definitions.NullClass) - return javaName(definitions.RuntimeNullClass) - else if (definitions.primitiveCompanions(sym.companionModule)) - return javaName(definitions.getModule("scala.runtime." + sym.name)) + if (sym == NothingClass) javaName(RuntimeNothingClass) + else if (sym == NullClass) javaName(RuntimeNullClass) + else getPrimitiveCompanion(sym.companionModule) match { + case Some(sym) => javaName(sym) + case _ => + if (sym.isClass && !sym.rawowner.isPackageClass && !sym.isModuleClass) + innerClasses = innerClasses + sym - if (sym.isClass && !sym.rawowner.isPackageClass && !sym.isModuleClass) { - innerClasses = innerClasses + sym; - } + val prefix = + if (sym.isClass || (sym.isModule && !sym.isMethod)) sym.fullName('/') + else sym.simpleName.toString.trim() - (if (sym.isClass || (sym.isModule && !sym.isMethod)) - sym.fullName('/') - else - sym.simpleName.toString.trim()) + suffix + prefix + suffix + } } def javaNames(syms: List[Symbol]): Array[String] = { @@ -1879,7 +1883,7 @@ abstract class GenJVM extends SubComponent { sym.hasFlag(Flags.INTERFACE) || (sym.hasFlag(Flags.JAVA) && - sym.isNonBottomSubClass(definitions.ClassfileAnnotationClass)) + sym.isNonBottomSubClass(ClassfileAnnotationClass)) } diff --git a/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala b/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala index fc824bb8cd..bc7c88fcb8 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala @@ -212,8 +212,7 @@ abstract class ClosureElimination extends SubComponent { /** is field 'f' accessible from method 'm'? */ def accessible(f: Symbol, m: Symbol): Boolean = - f.isPublic || (f.hasFlag(Flags.PROTECTED) && (f.enclosingPackageClass == m.enclosingPackageClass)) - + f.isPublic || (f.isProtected && (f.enclosingPackageClass == m.enclosingPackageClass)) } /* class ClosureElim */ diff --git a/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala b/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala index 4149ef2ab6..224893d60b 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala @@ -7,9 +7,8 @@ package scala.tools.nsc package backend.opt -import scala.collection._ -import scala.collection.immutable.{Map, HashMap, Set, HashSet} -import scala.tools.nsc.symtab._ +import scala.collection.{ mutable, immutable } +import symtab._ /** */ @@ -54,7 +53,7 @@ abstract class DeadCodeElimination extends SubComponent { val rdef = new reachingDefinitions.ReachingDefinitionsAnalysis; /** Use-def chain: give the reaching definitions at the beginning of given instruction. */ - var defs: Map[(BasicBlock, Int), Set[rdef.lattice.Definition]] = HashMap.empty + var defs: immutable.Map[(BasicBlock, Int), immutable.Set[rdef.lattice.Definition]] = immutable.HashMap.empty /** Useful instructions which have not been scanned yet. */ val worklist: mutable.Set[(BasicBlock, Int)] = new mutable.LinkedHashSet @@ -91,7 +90,7 @@ abstract class DeadCodeElimination extends SubComponent { /** collect reaching definitions and initial useful instructions for this method. */ def collectRDef(m: IMethod): Unit = if (m.code ne null) { - defs = HashMap.empty; worklist.clear; useful.clear; + defs = immutable.HashMap.empty; worklist.clear; useful.clear; rdef.init(m); rdef.run; @@ -264,19 +263,11 @@ abstract class DeadCodeElimination extends SubComponent { } private def findInstruction(bb: BasicBlock, i: Instruction): (BasicBlock, Int) = { - def find(bb: BasicBlock): Option[(BasicBlock, Int)] = { - var xs = bb.toList - xs.zipWithIndex find { hd => hd._1 eq i } match { - case Some((_, idx)) => Some(bb, idx) - case None => None - } + for (b <- linearizer.linearizeAt(method, bb)) { + val idx = b.toList indexWhere (_ eq i) + if (idx != -1) + return (b, idx) } - - for (b <- linearizer.linearizeAt(method, bb)) - find(b) match { - case Some(p) => return p - case None => () - } abort("could not find init in: " + method) } diff --git a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala index f662a40a26..4005b4e5c9 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala @@ -325,7 +325,6 @@ abstract class Inliners extends SubComponent { class CallerCalleeInfo(val caller: IMethodInfo, val inc: IMethodInfo) { def isLargeSum = caller.length + inc.length - 1 > SMALL_METHOD_SIZE - /** Inline 'inc' into 'caller' at the given block and instruction. * The instruction must be a CALL_METHOD. */ @@ -408,41 +407,19 @@ abstract class Inliners extends SubComponent { def isInlined(l: Local) = inlinedLocals isDefinedAt l val newInstr = i match { - case THIS(clasz) => - LOAD_LOCAL(inlinedThis) - - case STORE_THIS(_) => - STORE_LOCAL(inlinedThis) - - case JUMP(whereto) => - JUMP(inlinedBlock(whereto)) - - case CJUMP(success, failure, cond, kind) => - CJUMP(inlinedBlock(success), inlinedBlock(failure), cond, kind) - - case CZJUMP(success, failure, cond, kind) => - CZJUMP(inlinedBlock(success), inlinedBlock(failure), cond, kind) - - case SWITCH(tags, labels) => - SWITCH(tags, labels map inlinedBlock) - - case RETURN(kind) => - JUMP(afterBlock) - - case LOAD_LOCAL(l) if isInlined(l) => - LOAD_LOCAL(inlinedLocals(l)) - - case STORE_LOCAL(l) if isInlined(l) => - STORE_LOCAL(inlinedLocals(l)) - - case LOAD_LOCAL(l) => assertLocal(l) - case STORE_LOCAL(l) => assertLocal(l) - - case SCOPE_ENTER(l) if isInlined(l) => - SCOPE_ENTER(inlinedLocals(l)) - - case SCOPE_EXIT(l) if isInlined(l) => - SCOPE_EXIT(inlinedLocals(l)) + case THIS(clasz) => LOAD_LOCAL(inlinedThis) + case STORE_THIS(_) => STORE_LOCAL(inlinedThis) + case JUMP(whereto) => JUMP(inlinedBlock(whereto)) + case CJUMP(succ, fail, cond, kind) => CJUMP(inlinedBlock(succ), inlinedBlock(fail), cond, kind) + case CZJUMP(succ, fail, cond, kind) => CZJUMP(inlinedBlock(succ), inlinedBlock(fail), cond, kind) + case SWITCH(tags, labels) => SWITCH(tags, labels map inlinedBlock) + case RETURN(_) => JUMP(afterBlock) + case LOAD_LOCAL(l) if isInlined(l) => LOAD_LOCAL(inlinedLocals(l)) + case STORE_LOCAL(l) if isInlined(l) => STORE_LOCAL(inlinedLocals(l)) + case LOAD_LOCAL(l) => assertLocal(l) + case STORE_LOCAL(l) => assertLocal(l) + case SCOPE_ENTER(l) if isInlined(l) => SCOPE_ENTER(inlinedLocals(l)) + case SCOPE_EXIT(l) if isInlined(l) => SCOPE_EXIT(inlinedLocals(l)) case nw @ NEW(sym) => val r = NEW(sym) diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/tools/nsc/symtab/Definitions.scala index 1d11e31a19..4b5632f7d8 100644 --- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala +++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala @@ -589,9 +589,14 @@ trait Definitions extends reflect.generic.StandardDefinitions { val boxedClass = new HashMap[Symbol, Symbol] val boxedModule = new HashMap[Symbol, Symbol] - val unboxMethod = new HashMap[Symbol, Symbol] // Type -> Method - val boxMethod = new HashMap[Symbol, Symbol] // Type -> Method - val primitiveCompanions = new HashSet[Symbol] + val unboxMethod = new HashMap[Symbol, Symbol] // Type -> Method + val boxMethod = new HashMap[Symbol, Symbol] // Type -> Method + val primitiveCompanions = new HashSet[Symbol] // AnyVal -> Companion + + /** Maps a companion object like scala.Int to scala.runtime.Int. */ + def getPrimitiveCompanion(sym: Symbol) = + if (primitiveCompanions(sym)) Some(getModule("scala.runtime." + sym.name)) + else None def isUnbox(m: Symbol) = unboxMethod.valuesIterator contains m def isBox(m: Symbol) = boxMethod.valuesIterator contains m diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala index 44bfbc5d27..b5e3366893 100644 --- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala +++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala @@ -538,6 +538,10 @@ trait Symbols extends reflect.generic.Symbols { self: SymbolTable => final def isStatic: Boolean = hasFlag(STATIC) || isRoot || owner.isStaticOwner + /** Is this symbol a static constructor? */ + final def isStaticConstructor: Boolean = + isStaticMember && isClassConstructor + /** Is this symbol a static member of its class? (i.e. needs to be implemented as a Java static?) */ final def isStaticMember: Boolean = hasFlag(STATIC) || owner.isImplClass |