diff options
author | Iulian Dragos <jaguarul@gmail.com> | 2006-04-06 09:49:46 +0000 |
---|---|---|
committer | Iulian Dragos <jaguarul@gmail.com> | 2006-04-06 09:49:46 +0000 |
commit | 9ce18b19b66f73cd872158b6b28efd480fc5c5d1 (patch) | |
tree | 61885ddf670127e4b85f23f6d39d9c7ca1de79c2 | |
parent | 99a204f18789c0e628cd73b8cb485fc46e57e3de (diff) | |
download | scala-9ce18b19b66f73cd872158b6b28efd480fc5c5d1.tar.gz scala-9ce18b19b66f73cd872158b6b28efd480fc5c5d1.tar.bz2 scala-9ce18b19b66f73cd872158b6b28efd480fc5c5d1.zip |
Fixed several bugs in Inliners and the monitor ...
Fixed several bugs in Inliners and the monitor crash in jvm.
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/icode/ExceptionHandlers.scala | 18 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/icode/GenICode.scala | 9 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/icode/Members.scala | 2 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/icode/analysis/DataFlowAnalysis.scala | 2 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala | 10 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/opt/Inliners.scala | 98 | ||||
-rw-r--r-- | test/files/pos/Transactions.scala (renamed from test/pending/pos/Transactions.scala) | 0 |
7 files changed, 105 insertions, 34 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/icode/ExceptionHandlers.scala b/src/compiler/scala/tools/nsc/backend/icode/ExceptionHandlers.scala index aa20ecb932..c22cfa26eb 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/ExceptionHandlers.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/ExceptionHandlers.scala @@ -20,8 +20,7 @@ import scala.collection.mutable.HashSet; trait ExceptionHandlers requires ICodes { import global.{Symbol, NoSymbol}; - class ExceptionHandler(val method: IMethod, label: String, val cls: Symbol) { - private var coveredBlocks: List[BasicBlock] = Nil; + class ExceptionHandler(val method: IMethod, val label: String, val cls: Symbol) { private var _startBlock: BasicBlock = _; var finalizer: Finalizer = _; @@ -29,17 +28,28 @@ trait ExceptionHandlers requires ICodes { def startBlock = _startBlock; def addBlock(b: BasicBlock): ExceptionHandler = { - coveredBlocks = b :: coveredBlocks; + covered = b :: covered; this } - def covered: List[BasicBlock] = coveredBlocks; + var covered: List[BasicBlock] = Nil; override def toString() = "exh_" + label + "(" + cls.simpleName + ")"; + + def this(other: ExceptionHandler) = { + this(other.method, other.label, other.cls); + covered = other.covered; + setStartBlock(other.startBlock); + finalizer = other.finalizer; + } + + def dup: ExceptionHandler = new ExceptionHandler(this); } class Finalizer(method: IMethod, label: String) extends ExceptionHandler(method, label, NoSymbol) { override def toString() = "finalizer_" + label; + + override def dup: Finalizer = new Finalizer(method, label); } object NoFinalizer extends Finalizer(null, "<no finalizer>") { diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index 401a378def..95909722ce 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -1343,8 +1343,14 @@ abstract class GenICode extends SubComponent { SWITCH(tags, labels map (l => if (l == block) cont else l))); } } - if (changed) + if (changed) { method.code.removeBlock(block); + for (val e <- method.exh) { + e.covered = e.covered filter (.!=(block)) + if (e.startBlock eq block) + e setStartBlock cont; + } + } } } @@ -1466,6 +1472,7 @@ abstract class GenICode extends SubComponent { def exitSynchronized(monitor: Local): this.type = { assert(monitors.head == monitor, "Bad nesting of monitors: " + monitors + " trying to exit from: " + monitor); + monitors = monitors.tail; this } diff --git a/src/compiler/scala/tools/nsc/backend/icode/Members.scala b/src/compiler/scala/tools/nsc/backend/icode/Members.scala index e9e6445185..6eb47ac8f7 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Members.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Members.scala @@ -158,6 +158,8 @@ trait Members requires ICodes { */ class IMethod(val symbol: Symbol) { var code: Code = null; + + /** The list of exception handlers, ordered from innermost to outermost. */ var exh: List[ExceptionHandler] = Nil; var sourceFile: String = _; var returnType: TypeKind = _; diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/DataFlowAnalysis.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/DataFlowAnalysis.scala index 6107e66645..93d265caac 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/analysis/DataFlowAnalysis.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/DataFlowAnalysis.scala @@ -7,7 +7,7 @@ import scala.collection.mutable.{Map, HashMap, Set, HashSet}; trait DataFlowAnalysis[L <: CompleteLattice] { /** A type for program points. */ type P <: ProgramPoint[P]; - val lattice: L; + val lattice: L; val worklist: Set[P] = new HashSet; 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 c2e1169f0b..91b4ee4e68 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala @@ -103,9 +103,10 @@ abstract class TypeFlowAnalysis { val STRING = icodes.REFERENCE(TypeFlowAnalysis.this.global.definitions.StringClass); var method: IMethod = _; - def this(m: icodes.IMethod) = { - this(); + /** Initialize the in/out maps for the analysis of the given method. */ + def init(m: icodes.IMethod): Unit = { this.method = m; + init { worklist += m.code.startBlock; worklist ++= (m.exh map (.startBlock)); @@ -122,6 +123,11 @@ abstract class TypeFlowAnalysis { } } + def this(m: icodes.IMethod) = { + this(); + init(m) + } + def run = { forwardAnalysis(blockTransfer); if (settings.debug.value) { diff --git a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala index 901745fa5c..62692cdec9 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala @@ -3,7 +3,7 @@ * @author Iulian Dragos */ -// $Id: $ +// $Id$ package scala.tools.nsc.backend.opt; @@ -54,6 +54,9 @@ abstract class Inliners extends SubComponent { ret } + /** Inline the 'callee' method inside the 'caller' in the given + * basic block, at the given instruction (which has to be a CALL_METHOD). + */ def inline(caller: IMethod, block: BasicBlock, instr: Instruction, @@ -69,7 +72,7 @@ abstract class Inliners extends SubComponent { /* Map 'original' blocks to the ones inlined in the caller. */ val inlinedBlock: Map[BasicBlock, BasicBlock] = new HashMap; - val instrBefore = block.toList.takeWhile( i => i != instr); + val instrBefore = block.toList.takeWhile( i => i ne instr); val instrAfter = block.toList.drop(instrBefore.length + 1); assert(!instrAfter.isEmpty, "CALL_METHOD cannot be the last instrcution in block!"); @@ -91,6 +94,13 @@ abstract class Inliners extends SubComponent { b } + def translateExh(e: ExceptionHandler) = { + var handler: ExceptionHandler = e.dup; + handler.covered = handler.covered.map(inlinedBlock); + handler.setStartBlock(inlinedBlock(e.startBlock)); + handler + } + val afterBlock = newBlock; /** Map an instruction from the callee to one suitable for the caller. */ @@ -178,6 +188,9 @@ abstract class Inliners extends SubComponent { instrAfter.foreach(afterBlock.emit); afterBlock.close; count = count + 1; + + // add exception handlers of the callee + caller.exh = (callee.exh map translateExh) ::: caller.exh; } @@ -199,6 +212,8 @@ abstract class Inliners extends SubComponent { }} + val tfa = new analysis.MethodTFA(); + def analyzeMethod(m: IMethod): Unit = try { var retry = false; var count = 0; @@ -209,11 +224,11 @@ abstract class Inliners extends SubComponent { this.count = 0; if (settings.debug.value) log("Analyzing " + m + " count " + count); - val a = new analysis.MethodTFA(m); - a.run; - linearizer.linearize(m).foreach { bb => - var info = a.in(bb); - bb.traverse { i => + tfa.init(m); + tfa.run; + for (val bb <- linearizer.linearize(m)) { + var info = tfa.in(bb); + for (val i <- bb.toList) { if (!retry) { i match { case CALL_METHOD(msym, Dynamic) => @@ -234,10 +249,16 @@ abstract class Inliners extends SubComponent { classes(receiver).lookupMethod(concreteMethod) match { case Some(inc) => if (inc != m && (inc.code ne null) - && isSafeToInline(m, inc, info._2)) { + && { + val res = isSafeToInline(m, inc, info._2) + log("isSafeToInline: " + inc + " " + res); res }) { retry = true; count = count + 1; inline(m, bb, i, inc); + + /* Remove this method from the cache, as the calls-private relation + might have changed after the inlining. */ + callsPrivate -= m; } case None => log("Couldn't find " + msym.name); @@ -246,7 +267,7 @@ abstract class Inliners extends SubComponent { case _ => (); } - info = a.interpret(info, i); + info = tfa.interpret(info, i); }}}} } while (retry && count < 5); } catch { @@ -264,37 +285,62 @@ abstract class Inliners extends SubComponent { val TypeRef(_, sym, _) = t; definitions.FunctionClass exists sym.== } - Console.println("isClosureClass: " + cls + " is: " + res); res } + /** Cache whether a method calls private members. */ + val callsPrivate: Map[IMethod, Boolean] = new HashMap; /** A method is safe to inline when: * - it does not contain calls to private methods when * called from another class * - it is not inlined into a position with non-empty stack, * while having a top-level finalizer (see liftedTry problem) + * Note: + * - synthetic private members are made public in this pass. */ def isSafeToInline(caller: IMethod, callee: IMethod, stack: TypeStack): Boolean = { - if (caller.symbol.owner != callee.symbol.owner) { - var callsPrivateMember = false; - for (val b <- callee.code.blocks) - for (val i <- b.toList) - i match { - case CALL_METHOD(m, style) => - if (m.hasFlag(Flags.PRIVATE) || style.isSuper) - callsPrivateMember = true; - case LOAD_FIELD(f, _) => - if (f.hasFlag(Flags.PRIVATE)) callsPrivateMember = true; - case _ => () - } - if (callsPrivateMember) return false; - } + var callsPrivateMember = false; + + callsPrivate get (callee) match { + case Some(b) => callsPrivateMember = b; + case None => + for (val b <- callee.code.blocks) + for (val i <- b.toList) + i match { + case CALL_METHOD(m, style) => + if (m.hasFlag(Flags.PRIVATE) || + (style.isSuper && !m.isClassConstructor)) + callsPrivateMember = true; + + case LOAD_FIELD(f, _) => + if (f.hasFlag(Flags.PRIVATE)) + if (f.hasFlag(Flags.SYNTHETIC) || f.hasFlag(Flags.PARAMACCESSOR)) { + log("Making not-private symbol out of synthetic: " + f); + f.setFlag(Flags.notPRIVATE) + } else + callsPrivateMember = true; + + case STORE_FIELD(f, _) => + if (f.hasFlag(Flags.PRIVATE)) + if (f.hasFlag(Flags.SYNTHETIC) || f.hasFlag(Flags.PARAMACCESSOR)) { + log("Making not-private symbol out of synthetic: " + f); + f.setFlag(Flags.notPRIVATE) + } else + callsPrivateMember = true; + + case _ => () + } + callsPrivate += callee -> callsPrivateMember; + } + + if (callsPrivateMember && (caller.symbol.owner != callee.symbol.owner)) + return false; if (stack.length > (1 + callee.symbol.info.paramTypes.length) && - (callee.exh exists (.covered.contains(callee.code.startBlock)))) + (callee.exh exists (.covered.contains(callee.code.startBlock)))) { false; - else + } else true } diff --git a/test/pending/pos/Transactions.scala b/test/files/pos/Transactions.scala index 8fb23268dc..8fb23268dc 100644 --- a/test/pending/pos/Transactions.scala +++ b/test/files/pos/Transactions.scala |