summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/ExceptionHandlers.scala18
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/GenICode.scala9
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/Members.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/analysis/DataFlowAnalysis.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala10
-rw-r--r--src/compiler/scala/tools/nsc/backend/opt/Inliners.scala98
-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