summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc
diff options
context:
space:
mode:
authorIulian Dragos <jaguarul@gmail.com>2006-02-14 12:50:40 +0000
committerIulian Dragos <jaguarul@gmail.com>2006-02-14 12:50:40 +0000
commit2197e9485a681f72068c5768263bcd1757664775 (patch)
tree3bc2b962af4209f182925724ec7f089ca91a3bb9 /src/compiler/scala/tools/nsc
parent9392e582986c3d54cde992c3141b52c97f7d6e16 (diff)
downloadscala-2197e9485a681f72068c5768263bcd1757664775.tar.gz
scala-2197e9485a681f72068c5768263bcd1757664775.tar.bz2
scala-2197e9485a681f72068c5768263bcd1757664775.zip
Refactored ICode and added basic inlining capab...
Refactored ICode and added basic inlining capabilities.
Diffstat (limited to 'src/compiler/scala/tools/nsc')
-rw-r--r--src/compiler/scala/tools/nsc/CompilerRun.scala1
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala20
-rw-r--r--src/compiler/scala/tools/nsc/Settings.scala5
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala24
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/Checkers.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/GenICode.scala24
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/ICodes.scala17
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/Linearizers.scala9
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/Members.scala23
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/Printers.scala6
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala6
-rw-r--r--src/compiler/scala/tools/nsc/backend/opt/Inliners.scala190
-rw-r--r--src/compiler/scala/tools/nsc/util/ClassPath.scala3
-rw-r--r--src/compiler/scala/tools/nsc/util/NameTransformer.scala1
14 files changed, 278 insertions, 53 deletions
diff --git a/src/compiler/scala/tools/nsc/CompilerRun.scala b/src/compiler/scala/tools/nsc/CompilerRun.scala
index 7677fc2cb8..94b5be7409 100644
--- a/src/compiler/scala/tools/nsc/CompilerRun.scala
+++ b/src/compiler/scala/tools/nsc/CompilerRun.scala
@@ -15,6 +15,7 @@ class CompilerRun {
def erasurePhase: Phase = NoPhase;
def flattenPhase: Phase = NoPhase;
def mixinPhase: Phase = NoPhase;
+ def icodePhase: Phase = NoPhase;
def phaseNamed(name: String): Phase = NoPhase;
}
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 2f41ae9194..35373f9914 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -25,6 +25,7 @@ import transform._;
import backend.icode.{ICodes, GenICode, Checkers};
import backend.ScalaPrimitives;
import backend.jvm.GenJVM;
+import backend.opt.Inliners;
class Global(val settings: Settings, val reporter: Reporter) extends SymbolTable
with Trees
@@ -267,6 +268,10 @@ class Global(val settings: Settings, val reporter: Reporter) extends SymbolTable
val global: Global.this.type = Global.this;
}
+ object inliner extends Inliners {
+ val global: Global.this.type = Global.this
+ }
+
object genJVM extends GenJVM {
val global: Global.this.type = Global.this;
}
@@ -293,6 +298,7 @@ class Global(val settings: Settings, val reporter: Reporter) extends SymbolTable
flatten,
mixer,
genicode,
+ inliner,
genJVM,
sampleTransform);
@@ -350,6 +356,7 @@ class Global(val settings: Settings, val reporter: Reporter) extends SymbolTable
override val erasurePhase = phaseNamed("erasure");
override val flattenPhase = phaseNamed("flatten");
override val mixinPhase = phaseNamed("mixin");
+ override val icodePhase = phaseNamed("icode");
private var unitbuf = new ListBuffer[CompilationUnit];
private var fileset = new HashSet[AbstractFile];
@@ -393,7 +400,9 @@ class Global(val settings: Settings, val reporter: Reporter) extends SymbolTable
val startTime = System.currentTimeMillis();
phase = globalPhase;
globalPhase.run;
- if (settings.print contains globalPhase.name) treePrinter.printAll();
+ if (settings.print contains globalPhase.name)
+ if (globalPhase.id >= icodePhase.id) writeICode()
+ else treePrinter.printAll();
if (settings.browse contains globalPhase.name) treeBrowser.browse(units);
informTime(globalPhase.description, startTime);
globalPhase = globalPhase.next;
@@ -408,7 +417,6 @@ class Global(val settings: Settings, val reporter: Reporter) extends SymbolTable
if (settings.Xshowcls.value != "") showDef(newTermName(settings.Xshowcls.value), false);
if (settings.Xshowobj.value != "") showDef(newTermName(settings.Xshowobj.value), true);
- if (settings.Xshowicode.value) writeICode();
if (reporter.errors == 0) {
assert(symData.isEmpty, symData.elements.toList);
@@ -513,9 +521,11 @@ class Global(val settings: Settings, val reporter: Reporter) extends SymbolTable
}
private def writeICode(): Unit = {
- val printer = new icodePrinter.TextPrinter(null);
- icodes.classes.foreach((cls) => {
- val file = getFile(cls.symbol, ".icode");
+ val printer = new icodePrinter.TextPrinter(null, icodes.linearizer);
+ icodes.classes.values.foreach((cls) => {
+ var file = getFile(cls.symbol, ".icode");
+ if (file.exists())
+ file = new File(file.getParentFile(), file.getName() + "1");
try {
val stream = new FileOutputStream(file);
printer.setWriter(new PrintWriter(stream, true));
diff --git a/src/compiler/scala/tools/nsc/Settings.scala b/src/compiler/scala/tools/nsc/Settings.scala
index 0ce0b34a07..0a1d10d8ae 100644
--- a/src/compiler/scala/tools/nsc/Settings.scala
+++ b/src/compiler/scala/tools/nsc/Settings.scala
@@ -18,7 +18,7 @@ class Settings(error: String => unit) {
concatPath(
getProperty("java.class.path"),
getProperty("scala.class.path")),
- ".")
+ "")
private val bootclasspathDefault =
alternatePath(
@@ -57,7 +57,7 @@ class Settings(error: String => unit) {
val noassertions = BooleanSetting("-noassert", "Generate no assertions and assumptions")
val verbose = BooleanSetting("-verbose", "Output messages about what the compiler is doing")
val classpath = StringSetting ("-classpath", "path", "Specify where to find user class files", classpathDefault)
- val sourcepath = StringSetting ("-sourcepath", "path", "Specify where to find input source files", ".")
+ val sourcepath = StringSetting ("-sourcepath", "path", "Specify where to find input source files", "")
val bootclasspath = StringSetting ("-bootclasspath", "path", "Override location of bootstrap class files", bootclasspathDefault)
val extdirs = StringSetting ("-extdirs", "dirs", "Override location of installed extensions", extdirsDefault)
val outdir = StringSetting ("-d", "directory", "Specify where to place generated class files", ".")
@@ -84,6 +84,7 @@ class Settings(error: String => unit) {
val log = PhasesSetting ("-log", "Log operations in")
val version = BooleanSetting("-version", "Print product version and exit")
val help = BooleanSetting("-help", "Print a synopsis of standard options")
+ val inline = BooleanSetting("-inline", "Perform inlining when possible")
val Xshowcls = StringSetting ("-Xshowcls", "class", "Show class info", "")
val Xshowobj = StringSetting ("-Xshowobj", "object", "Show object info", "")
diff --git a/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala b/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala
index 83128a8274..aa42da4273 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala
@@ -57,7 +57,10 @@ mixin class BasicBlocks requires ICodes {
/** Apply a function to all the instructions of the block. */
def traverse(f: Instruction => unit) = {
- assert(closed, "Traversing an open block!: ");
+ if (!closed) {
+ dump;
+ global.abort("Traversing an open block!: " + label);
+ }
instrs foreach f;
}
@@ -160,7 +163,6 @@ mixin class BasicBlocks requires ICodes {
assert (!closed || ignore, "BasicBlock closed");
if (!ignore) {
-// Console.println("block " + label + ": " + instr);
instr.pos = pos;
instructionList = instr :: instructionList;
_lastInstruction = instr;
@@ -172,7 +174,19 @@ mixin class BasicBlocks requires ICodes {
assert(instructionList.length > 0,
"Empty block.");
closed = true;
- instrs = toInstructionArray(instructionList.reverse);
+ instructionList = instructionList.reverse;
+ instrs = toInstructionArray(instructionList);
+ }
+
+ def open = {
+ closed = false;
+ }
+
+ def instructions: List[Instruction] = instructionList;
+
+ def clear: Unit = {
+ instructionList = Nil;
+ instrs = null;
}
def isEmpty: Boolean = instructionList.isEmpty;
@@ -222,8 +236,10 @@ mixin class BasicBlocks requires ICodes {
case RETURN(_) => Nil;
case THROW() => Nil;
case _ =>
- if (isClosed)
+ if (isClosed) {
+ dump;
global.abort("The last instruction is not a control flow instruction: " + lastInstruction);
+ }
else Nil;
}
diff --git a/src/compiler/scala/tools/nsc/backend/icode/Checkers.scala b/src/compiler/scala/tools/nsc/backend/icode/Checkers.scala
index 00741a1e0e..0963a89bc9 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/Checkers.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/Checkers.scala
@@ -59,7 +59,7 @@ abstract class Checkers {
def checkICodes: Unit = {
Console.println("[[consistency check at beginning of phase " + globalPhase.name + "]]");
- classes foreach check;
+ classes.values foreach check;
}
def check(cls: IClass): Unit = {
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
index 553a797f93..23b1584c82 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
@@ -75,7 +75,7 @@ abstract class GenICode extends SubComponent {
log("Generating class: " + tree.symbol.fullNameString);
ctx setClass (new IClass(tree.symbol) setCompilationUnit unit);
addClassFields(ctx, tree.symbol);
- classes = ctx.clazz :: classes;
+ classes += tree.symbol -> ctx.clazz;
gen(impl, ctx);
ctx setClass null;
@@ -83,13 +83,6 @@ abstract class GenICode extends SubComponent {
case ModuleDef(mods, name, impl) =>
abort("Modules should not reach backend!");
- log("Generating module: " + tree.symbol.fullNameString);
- ctx setClass (new IClass(tree.symbol) setCompilationUnit unit);
- addClassFields(ctx, tree.symbol);
- classes = ctx.clazz :: classes;
- gen(impl, ctx);
- ctx setClass null;
-
case ValDef(mods, name, tpt, rhs) => ctx; // we use the symbol to add fields
case DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
@@ -646,7 +639,7 @@ abstract class GenICode extends SubComponent {
log("synchronized block start");
ctx1 = ctx1.Try(
bodyCtx => {
- val ctx1 = genLoad(args.head, bodyCtx, toTypeKind(tree.tpe.resultType));
+ val ctx1 = genLoad(args.head, bodyCtx, expectedType /* toTypeKind(tree.tpe.resultType) */);
ctx1.bb.emit(LOAD_LOCAL(monitor, false));
ctx1.bb.emit(MONITOR_EXIT(), tree.pos);
ctx1
@@ -655,6 +648,7 @@ abstract class GenICode extends SubComponent {
exhCtx.bb.emit(LOAD_LOCAL(monitor, false));
exhCtx.bb.emit(MONITOR_EXIT(), tree.pos);
exhCtx.bb.emit(THROW());
+ exhCtx.bb.enterIgnoreMode;
exhCtx
})));
if (settings.debug.value)
@@ -1303,20 +1297,21 @@ abstract class GenICode extends SubComponent {
if (block.size == 1 && optCont != None) {
val Some(cont) = optCont;
val pred = block.predecessors;
- log("Preds: " + pred + " of " + block);
+ log("Preds: " + pred + " of " + block + " (" + optCont + ")");
pred foreach { p =>
p.lastInstruction match {
case CJUMP(succ, fail, cond, kind) =>
if (settings.debug.value)
log("Pruning empty if branch.");
changed = true;
- p.replaceInstruction(p.lastInstruction,
+ assert(p.replaceInstruction(p.lastInstruction,
if (block == succ)
CJUMP(cont, fail, cond, kind)
else if (block == fail)
CJUMP(succ, cont, cond, kind)
else
- abort("Could not find block in preds"));
+ abort("Could not find block in preds")),
+ "Didn't find p.lastInstruction");
case CZJUMP(succ, fail, cond, kind) =>
if (settings.debug.value)
@@ -1334,7 +1329,8 @@ abstract class GenICode extends SubComponent {
if (settings.debug.value)
log("Pruning empty if branch.");
changed = true;
- p.replaceInstruction(p.lastInstruction, JUMP(cont));
+ assert(p.replaceInstruction(p.lastInstruction, JUMP(cont)),
+ "Didn't find p.lastInstruction");
case SWITCH(tags, labels) =>
if (settings.debug.value)
@@ -1632,6 +1628,8 @@ abstract class GenICode extends SubComponent {
case _ => instr;
}
}
+
+ override def toString() = symbol.toString();
}
///////////////// Fake instructions //////////////////////////
diff --git a/src/compiler/scala/tools/nsc/backend/icode/ICodes.scala b/src/compiler/scala/tools/nsc/backend/icode/ICodes.scala
index 99ecc1b1c2..03c9976437 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/ICodes.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/ICodes.scala
@@ -7,7 +7,10 @@
package scala.tools.nsc.backend.icode;
+import java.io.PrintWriter;
+
import scala.tools.nsc.symtab._;
+import scala.collection.mutable.HashMap;
/** Glue together ICode parts.
*/
@@ -24,7 +27,7 @@ abstract class ICodes extends AnyRef
val global: Global;
/** The ICode representation of classes */
- var classes: List[IClass] = _;
+ var classes: HashMap[global.Symbol, IClass] = new HashMap();
/** The ICode linearizer. */
val linearizer: Linearizer =
@@ -37,6 +40,16 @@ abstract class ICodes extends AnyRef
else
global.abort("Unknown linearizer: " + global.settings.Xlinearizer.value);
- def init = { classes = Nil }
+
+ /** Print all classes and basic blocks. Used for debugging. */
+ def dump: Unit = {
+ val printer = new global.icodePrinter.TextPrinter(new PrintWriter(System.out, true),
+ new global.icodes.DumpLinearizer());
+
+ global.icodes.classes.values foreach { c => printer.printClass(c); }
+ }
+
+
+ def init = { }
}
diff --git a/src/compiler/scala/tools/nsc/backend/icode/Linearizers.scala b/src/compiler/scala/tools/nsc/backend/icode/Linearizers.scala
index 52611fd4d5..ae326c0714 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/Linearizers.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/Linearizers.scala
@@ -155,4 +155,13 @@ mixin class Linearizers requires ICodes {
if (!blocks.contains(b))
blocks = b :: blocks;
}
+
+ /** A 'dump' of the blocks in this method, which does not
+ * require any well-formedness of the basic blocks (like
+ * the last instruction being a jump).
+ */
+ class DumpLinearizer extends Linearizer {
+ def linearize(m: IMethod): List[BasicBlock] =
+ m.code.blocks.toList;
+ }
}
diff --git a/src/compiler/scala/tools/nsc/backend/icode/Members.scala b/src/compiler/scala/tools/nsc/backend/icode/Members.scala
index 28826a5439..02af695f37 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/Members.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/Members.scala
@@ -99,27 +99,6 @@ mixin class Members requires ICodes {
/** This methods returns a string representation of the ICode */
override def toString() : String = "ICode '" + label + "'";
- /** This method print the code */
-// def print() : unit = print(System.out);
-
-// def print(out: java.io.PrintStream) : unit = {
-// traverse((bb: BasicBlock) => {
-// out.println("Block #" + bb.label);
-// out.println("Substituable variables : ");
-// if (bb.substituteVars != null)
-// bb.substituteVars.foreach(out.print);
-// else
-// out.println(" {Empty} ");
-// out.println("Instructions:");
-// bb.traverse((ici: Instruction) =>
-// out.println(" "+ici.toString()));
-// out.print ("Successors: ");
-// bb.successors.foreach((bb: BasicBlock) => out.print(bb.label+", "));
-// out.println (""); // ?? Del
-// out.println ();
-// });
-// }
-
/* Compute a unique new label */
def nextLabel = {
currentLabel = currentLabel + 1;
@@ -159,6 +138,8 @@ mixin class Members requires ICodes {
override def toString() = symbol.fullNameString;
def lookupField(s: Symbol) = fields find ((f) => f.symbol == s);
+ def lookupMethod(s: Symbol) = methods find ((m) => m.symbol == s);
+ def lookupMethod(s: Name) = methods find ((m) => m.symbol.name == s);
}
/** Represent a field in ICode */
diff --git a/src/compiler/scala/tools/nsc/backend/icode/Printers.scala b/src/compiler/scala/tools/nsc/backend/icode/Printers.scala
index 68ead723d7..7dbb3e1313 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/Printers.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/Printers.scala
@@ -18,7 +18,7 @@ abstract class Printers {
import global.icodes.opcodes._;
import global.icodes._;
- class TextPrinter(writer: PrintWriter) {
+ class TextPrinter(writer: PrintWriter, lin: Linearizer) {
var margin = 0;
var out = writer;
@@ -88,7 +88,7 @@ abstract class Printers {
println(" {");
println("locals: " + m.locals.mkString("", ", ", ""));
println;
- linearizer.linearize(m) foreach printBlock;
+ lin.linearize(m) foreach printBlock;
println("}");
indent;println("Exception handlers: ");
@@ -114,7 +114,7 @@ abstract class Printers {
def printBlock(bb: BasicBlock): Unit = {
print(bb.label); print(": "); indent; println;
- bb traverse printInstruction;
+ bb.instructions foreach printInstruction;
undent; println;
}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
index b4f4fd87f2..7b56547433 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
@@ -36,8 +36,10 @@ abstract class GenJVM extends SubComponent {
override def erasedTypes = true;
val codeGenerator = new BytecodeGenerator;
- override def run: Unit =
- classes foreach codeGenerator.genClass;
+ override def run: Unit = {
+ if (settings.debug.value) inform("[running phase " + name + " on icode]");
+ classes.values foreach codeGenerator.genClass;
+ }
override def apply(unit: CompilationUnit): Unit =
abort("JVM works on icode classes, not on compilation units!");
diff --git a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala
new file mode 100644
index 0000000000..b60ab3055c
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala
@@ -0,0 +1,190 @@
+/* NSC -- new scala compiler
+ * Copyright 2005 LAMP/EPFL
+ * @author Iulian Dragos
+ */
+
+// $Id: $
+
+package scala.tools.nsc.backend.opt;
+
+import scala.collection.mutable.{Map, HashMap};
+import scala.tools.nsc.symtab._;
+
+/**
+ */
+abstract class Inliners extends SubComponent {
+ import global._;
+ import icodes._;
+ import icodes.opcodes._;
+
+ val phaseName = "inliner";
+
+ /** Create a new phase */
+ override def newPhase(p: Phase) = new InliningPhase(p);
+
+ /** The Inlining phase.
+ */
+ class InliningPhase(prev: Phase) extends GlobalPhase(prev) {
+ def name = phaseName;
+ override def newFlags = phaseNewFlags;
+
+ override def erasedTypes = true;
+ val inliner = new Inliner;
+
+ override def run: Unit = {
+ if (settings.debug.value) inform("[running phase " + name + " on icode]");
+ classes.values foreach inliner.analyzeClass;
+ }
+ override def apply(unit: CompilationUnit): Unit =
+ abort("Inlining works on icode classes, not on compilation units!");
+ }
+
+ /**
+ * Simple inliner.
+ *
+ */
+ class Inliner {
+
+ def inline(caller: IMethod,
+ block: BasicBlock,
+ instr: Instruction,
+ callee: IMethod): Unit = {
+ if (settings.debug.value)
+ log("Inlining " + callee + " in " + caller + " at pos: " +
+ classes(caller.symbol.owner).cunit.position(instr.pos));
+
+ /* The exception handlers that are active at the current block. */
+ val activeHandlers = caller.exh.filter(.covered.contains(block));
+
+ /* Map 'original' blocks to the ones inlined in the caller. */
+ val inlinedBlock: Map[BasicBlock, BasicBlock] = new HashMap;
+
+ val instrBefore = block.instructions.takeWhile( i => i != instr);
+ val instrAfter = block.instructions.drop(instrBefore.length + 1);
+
+ if (settings.debug.value) {
+ log("instrBefore: " + instrBefore);
+ log("instrAfter: " + instrAfter);
+ }
+ assert(!instrAfter.isEmpty, "CALL_METHOD cannot be the last instrcution in block!");
+
+ // store the '$this' into the special local
+ val inlinedThis = new Local(caller.symbol.newVariable(instr.pos,"$inlThis"), REFERENCE(definitions.ObjectClass));
+
+ /** Add a new block in the current context. */
+ def newBlock = {
+ val b = caller.code.newBlock;
+ activeHandlers.foreach (.addBlock(b));
+ b
+ }
+
+ val afterBlock = newBlock;
+
+ /** Map an instruction from the callee to one suitable for the caller. */
+ def map(i: Instruction): Instruction = i match {
+ case THIS(clasz) =>
+ LOAD_LOCAL(inlinedThis, false);
+
+ case LOAD_LOCAL(local, isArg) if (isArg) =>
+ LOAD_LOCAL(local, false);
+
+ case STORE_LOCAL(local, isArg) if (isArg) =>
+ STORE_LOCAL(local, false);
+
+ case JUMP(where) =>
+ JUMP(inlinedBlock(where));
+
+ 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 RETURN(kind) =>
+ JUMP(afterBlock);
+
+ case _ => i
+ }
+
+ addLocals(caller, callee.locals);
+ addLocal(caller, inlinedThis);
+ callee.code.blocks.foreach { b =>
+ if (b != callee.code.startBlock)
+ inlinedBlock += b -> newBlock;
+ }
+
+ // re-emit the instructions before the call
+ block.open;
+ block.clear;
+ instrBefore.foreach(block.emit);
+
+ // store the arguments into special locals
+ callee.params.reverse.foreach { param =>
+ block.emit(STORE_LOCAL(param, false));
+ }
+ block.emit(STORE_LOCAL(inlinedThis, false));
+
+ // inline the start block of the callee
+ callee.code.startBlock.traverse { i =>
+ block.emit(map(i), 0);
+ }
+ block.close;
+
+ // duplicate the other blocks in the callee
+ callee.code.traverse { bb =>
+ if (bb != callee.code.startBlock) {
+ bb.traverse( i => inlinedBlock(bb).emit(map(i), 0) );
+ inlinedBlock(bb).close;
+ }
+ }
+
+ instrAfter.foreach(afterBlock.emit);
+ afterBlock.close;
+ }
+
+
+ /** Add a local to this method, performing alfa-renaming
+ * if necessary.
+ */
+ def addLocals(m: IMethod, ls: List[Local]): Unit = {
+ m.locals = m.locals ::: ls;
+ }
+
+ def addLocal(m: IMethod, l: Local): Unit =
+ m.locals = m.locals ::: List(l);
+
+ val InlineAttr = if (settings.inline.value) global.definitions.getClass("scala.inline").tpe;
+
+ def analyzeClass(cls: IClass): Unit = if (settings.inline.value) {
+ cls.methods.foreach { m => analyzeMethod(m)
+ }}
+
+
+ def analyzeMethod(m: IMethod): Unit = {
+ var retry = false;
+ var count = 0;
+
+ do {
+ retry = false;
+ if (m.code ne null)
+ m.code.traverse { bb =>
+ bb.traverse { i =>
+ if (!retry)
+ i match {
+ case CALL_METHOD(msym, _) =>
+ if (definitions.isFunctionType(msym.owner.tpe)
+ || msym.attributes.exists(a => a._1 == InlineAttr))
+ classes(msym.owner).lookupMethod(msym.name) match {
+ case Some(inc) =>
+ retry = true;
+ count = count + 1;
+ inline(m, bb, i, inc);
+ case None =>
+ log("Couldn't find " + msym.name);
+ }
+ case _ => ();
+ }}}
+ } while (retry && count < 5);
+ }
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/util/ClassPath.scala b/src/compiler/scala/tools/nsc/util/ClassPath.scala
index c72bf3beb4..1cd1c757a0 100644
--- a/src/compiler/scala/tools/nsc/util/ClassPath.scala
+++ b/src/compiler/scala/tools/nsc/util/ClassPath.scala
@@ -33,6 +33,7 @@ class ClassPath(onlyPresentation : Boolean) {
// assert(location != null, "cannot find classpath location");
// assert(location.getFile() != null, "cannot find classpath location " + " " + location + " " + location.getClass());
def source : Source;
+ override def toString() = location.toString();
}
@@ -206,6 +207,8 @@ class ClassPath(onlyPresentation : Boolean) {
}
}
}
+
+ override def toString() = entries.toList.mkString("", ":", "");
} // class Build
}
diff --git a/src/compiler/scala/tools/nsc/util/NameTransformer.scala b/src/compiler/scala/tools/nsc/util/NameTransformer.scala
index 982285c5f3..5fe825eb5e 100644
--- a/src/compiler/scala/tools/nsc/util/NameTransformer.scala
+++ b/src/compiler/scala/tools/nsc/util/NameTransformer.scala
@@ -37,6 +37,7 @@ object NameTransformer {
enterOp(':', "$colon");
enterOp('\\', "$bslash");
enterOp('?', "$qmark");
+ enterOp('@', "$at");
/** Replace operator symbols by corresponding "$op_name" */
def encode(name: String): String = {