summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIulian Dragos <jaguarul@gmail.com>2007-10-08 14:34:59 +0000
committerIulian Dragos <jaguarul@gmail.com>2007-10-08 14:34:59 +0000
commitc4181f656d306a986549ef990a1f531313bee420 (patch)
treeb2d4e4cd6ca20ed36e359bfaab4d25f0aa9e2d3c
parent9ce1dd8d50095a64a68bc86d5f5a856209eaf1f2 (diff)
downloadscala-c4181f656d306a986549ef990a1f531313bee420.tar.gz
scala-c4181f656d306a986549ef990a1f531313bee420.tar.bz2
scala-c4181f656d306a986549ef990a1f531313bee420.zip
Improved/refactored parts of the optimization p...
Improved/refactored parts of the optimization phases, removed option Ybytecode-read (enabled now by -optimise).
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala6
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/ICodes.scala6
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/analysis/ReachingDefinitions.scala46
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala53
-rw-r--r--src/compiler/scala/tools/nsc/backend/opt/Inliners.scala11
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Definitions.scala1
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala12
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala115
9 files changed, 175 insertions, 77 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 4037a0a5c7..45a68c5a16 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -17,7 +17,7 @@ import scala.tools.nsc.util.{ClassPath, SourceFile, BatchSourceFile}
import scala.collection.mutable.{HashSet, HashMap, ListBuffer}
import symtab._
-import symtab.classfile.{PickleBuffer, Pickler, ICodeReader}
+import symtab.classfile.{PickleBuffer, Pickler}
import util.Statistics
import plugins.Plugins
import ast._
@@ -72,10 +72,6 @@ class Global(var settings: Settings, var reporter: Reporter) extends Trees
val global: Global.this.type = Global.this
}
- object icodeReader extends ICodeReader {
- val global: Global.this.type = Global.this
- }
-
object analysis extends TypeFlowAnalysis {
val global: Global.this.type = Global.this
}
diff --git a/src/compiler/scala/tools/nsc/backend/icode/ICodes.scala b/src/compiler/scala/tools/nsc/backend/icode/ICodes.scala
index dc4afa22c0..46d0c9ab0a 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/ICodes.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/ICodes.scala
@@ -12,6 +12,7 @@ import java.io.PrintWriter
import scala.collection.mutable.HashMap
import scala.tools.nsc.symtab._
import analysis.{Liveness, ReachingDefinitions}
+import scala.tools.nsc.symtab.classfile.ICodeReader
/** Glue together ICode parts.
*
@@ -27,6 +28,7 @@ abstract class ICodes extends AnyRef
with Primitives
with Linearizers
with Printers
+ with Repository
{
val global: Global
@@ -74,6 +76,10 @@ abstract class ICodes extends AnyRef
settings.Xdce.value = true
}
+ object icodeReader extends ICodeReader {
+ lazy val global: ICodes.this.global.type = ICodes.this.global
+ }
+
/** A phase which works on icode. */
abstract class ICodePhase(prev: Phase) extends global.GlobalPhase(prev) {
override def erasedTypes = true
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 27342deb85..79e1764a31 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/analysis/ReachingDefinitions.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/ReachingDefinitions.scala
@@ -192,6 +192,52 @@ abstract class ReachingDefinitions {
IState(locals, stack)
}
+ /** Return the instructions that produced the 'm' elements on the stack, below given 'depth'.
+ * for instance, findefs(bb, idx, 1, 1) returns the instructions that might have produced the
+ * value found below the topmost element of the stack.
+ */
+ def findDefs(bb: BasicBlock, idx: Int, m: Int, depth: Int): List[(BasicBlock, Int)] = if (idx > 0) {
+ assert(bb.isClosed)
+ var instrs = bb.getArray
+ var res: List[(BasicBlock, Int)] = Nil
+ var i = idx
+ var n = m
+ var d = depth
+ // "I look for who produced the 'n' elements below the 'd' topmost slots of the stack"
+ while (n > 0 && i > 0) {
+ i -= 1
+ val prod = instrs(i).produced
+ if (prod > d) {
+ res = (bb, i) :: res
+ n = n - (prod - d)
+ if (bb(i) != LOAD_EXCEPTION)
+ d = instrs(i).consumed
+ } else {
+ d -= prod
+ d += instrs(i).consumed
+ }
+ }
+
+ if (n > 0) {
+ val stack = this.in(bb).stack
+ assert(stack.length >= n, "entry stack is too small, expected: " + n + " found: " + stack)
+ stack.drop(d).take(n) foreach { defs =>
+ res = defs.toList ::: res
+ }
+ }
+ res
+ } else {
+ val stack = this.in(bb).stack
+ assert(stack.length >= m, "entry stack is too small, expected: " + m + " found: " + stack)
+ stack.take(m) flatMap (_.toList)
+ }
+
+ /** Return the definitions that produced the topmost 'm' elements on the stack,
+ * and that reach the instruction at index 'idx' in basic block 'bb'.
+ */
+ def findDefs(bb: BasicBlock, idx: Int, m: Int): List[(BasicBlock, Int)] =
+ findDefs(bb, idx, m, 0)
+
override def toString: String = {
val sb = new compat.StringBuilder
sb.append("rdef: \n")
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
index da9a38eef7..f793346d66 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
@@ -1348,7 +1348,7 @@ abstract class GenJVM extends SubComponent {
&& !sym.enclClass.hasFlag(Flags.INTERFACE)
&& !sym.isClassConstructor) ACC_FINAL else 0)
jf = jf | (if (isStaticSymbol(sym)) ACC_STATIC else 0)
- jf = jf | (if (sym hasFlag Flags.SYNTHETIC) ACC_SYNTHETIC else 0)
+ jf = jf | (if (sym hasFlag Flags.ACCESSOR) ACC_SYNTHETIC else 0)
jf
}
diff --git a/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala b/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala
index de00968145..3bcb9e98bf 100644
--- a/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala
+++ b/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala
@@ -105,7 +105,7 @@ abstract class DeadCodeElimination extends SubComponent {
case CALL_METHOD(m1, SuperCall(_)) =>
worklist += ((bb, idx)) // super calls to constructor
case DROP(_) =>
- val necessary = findDefs(bb, idx, 1) exists { p =>
+ val necessary = rdef.findDefs(bb, idx, 1) exists { p =>
val (bb1, idx1) = p
bb1(idx1) match {
case CALL_METHOD(m1, _) if isSideEffecting(m1) => true
@@ -152,7 +152,7 @@ abstract class DeadCodeElimination extends SubComponent {
()
case _ =>
- for ((bb1, idx1) <- findDefs(bb, idx, instr.consumed) if !useful(bb1)(idx1)) {
+ for ((bb1, idx1) <- rdef.findDefs(bb, idx, instr.consumed) if !useful(bb1)(idx1)) {
log("\tAdding " + bb1(idx1))
worklist += ((bb1, idx1))
}
@@ -210,7 +210,8 @@ abstract class DeadCodeElimination extends SubComponent {
for ((i, idx) <- bb.toList.zipWithIndex) {
if (!useful(bb)(idx)) {
for ((consumedType, depth) <- i.consumedTypes.reverse.zipWithIndex) {
- val defs = findDefs(bb, idx, i.consumed, depth)
+ log("Finding definitions of: " + i + "\n\t" + consumedType + " at depth: " + depth)
+ val defs = rdef.findDefs(bb, idx, 1, depth)
for (d <- defs) {
if (!compensations.isDefinedAt(d))
compensations(d) = List(DROP(consumedType))
@@ -246,52 +247,6 @@ abstract class DeadCodeElimination extends SubComponent {
abort("could not find init in: " + method)
}
- /** Return the instructions that produced the 'm' elements on the stack, below given 'depth'.
- * for instance, findefs(bb, idx, 1, 1) returns the instructions that might have produced the
- * value found below the topmost element of the stack.
- */
- def findDefs(bb: BasicBlock, idx: Int, m: Int, depth: Int): List[(BasicBlock, Int)] = if (idx > 0) {
- assert(bb.isClosed)
- var instrs = bb.getArray
- var res: List[(BasicBlock, Int)] = Nil
- var i = idx
- var n = m
- var d = 0
- // "I look for who produced the 'n' elements below the 'd' topmost slots of the stack"
- while (n > 0 && i > 0) {
- i -= 1
- val prod = instrs(i).produced
- if (prod > d) {
- res = (bb, i) :: res
- n = n - (prod - d)
- if (bb(i) != LOAD_EXCEPTION)
- d = instrs(i).consumed
- } else {
- d -= prod
- d += instrs(i).consumed
- }
- }
-
- if (n > 0) {
- val stack = rdef.in(bb).stack
- assert(stack.length >= n, "entry stack is too small, expected: " + n + " found: " + stack)
- stack.drop(d).take(n) foreach { defs =>
- res = defs.toList ::: res
- }
- }
- res
- } else {
- val stack = rdef.in(bb).stack
- assert(stack.length >= m, "entry stack is too small, expected: " + m + " found: " + stack)
- stack.take(m) flatMap (_.toList)
- }
-
- /** Return the definitions that produced the topmost 'm' elements on the stack,
- * and that reach the instruction at index 'idx' in basic block 'bb'.
- */
- def findDefs(bb: BasicBlock, idx: Int, m: Int): List[(BasicBlock, Int)] =
- findDefs(bb, idx, m, 0)
-
/** Is 'sym' a side-effecting method? TODO: proper analysis. */
private def isSideEffecting(sym: Symbol): Boolean = {
!(sym.isGetter // for testing only
diff --git a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala
index c7d33a7693..8dabbd3173 100644
--- a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala
+++ b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala
@@ -309,16 +309,21 @@ abstract class Inliners extends SubComponent {
log("\tlooked up method: " + concreteMethod.fullNameString)
}
+ if (receiver == definitions.PredefModule.moduleClass) {
+ log("loading predef")
+ icodes.icode(receiver, true)
+ }
if (settings.debug.value)
log("Treating " + i
- + "\n\tclasses.contains: " + classes.contains(receiver)
+ + "\n\treceiver: " + receiver
+ + "\n\ticodes.available: " + icodes.available(receiver)
+ "\n\tconcreteMethod.isFinal: " + concreteMethod.isFinal);
- if ( classes.contains(receiver)
+ if ( icodes.available(receiver)
&& (isClosureClass(receiver)
|| concreteMethod.isFinal
|| receiver.isFinal)) {
- classes(receiver).lookupMethod(concreteMethod) match {
+ icodes.icode(receiver).get.lookupMethod(concreteMethod) match {
case Some(inc) =>
if (inc.symbol != m.symbol
&& (inlinedMethods(inc.symbol) < 2)
diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
index 13180aade2..c9dc436b6d 100644
--- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
@@ -301,6 +301,7 @@ trait Definitions {
var PatternWildcard: Symbol = _
// boxed classes
+ lazy val BoxesUtilityClass = getModule("scala.runtime.BoxesUtility")
lazy val BoxedArrayClass = getClass("scala.runtime.BoxedArray")
lazy val BoxedAnyArrayClass = getClass("scala.runtime.BoxedAnyArray")
lazy val BoxedObjectArrayClass = getClass("scala.runtime.BoxedObjectArray")
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
index d9300c8a17..66ef759e79 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
@@ -263,9 +263,10 @@ abstract class ClassfileParser {
c = sigToType(null, name)
values(index) = c
} else {
- val sym = if (name.endsWith("$")) definitions.getModule(name.subName(0, name.length - 1))
+ val sym = classNameToSymbol(name)
+ /*if (name.endsWith("$")) definitions.getModule(name.subName(0, name.length - 1))
else if (name.endsWith("$class")) definitions.getModule(name)
- else definitions.getClass(name)
+ else definitions.getClass(name)*/
values(index) = sym
c = sym.tpe
}
@@ -403,7 +404,7 @@ abstract class ClassfileParser {
val jflags = in.nextChar
var sflags = transFlags(jflags)
if ((sflags & FINAL) == 0) sflags = sflags | MUTABLE
- if ((sflags & PRIVATE) != 0 && !global.settings.XbytecodeRead.value) {
+ if ((sflags & PRIVATE) != 0 && !global.settings.XO.value) {
in.skip(4); skipAttributes()
} else {
val name = pool.getName(in.nextChar)
@@ -420,14 +421,14 @@ abstract class ClassfileParser {
def parseMethod() {
val jflags = in.nextChar
var sflags = transFlags(jflags)
- if ((jflags & JAVA_ACC_PRIVATE) != 0 && !global.settings.XbytecodeRead.value) {
+ if ((jflags & JAVA_ACC_PRIVATE) != 0 && !global.settings.XO.value) {
val name = pool.getName(in.nextChar)
if (name == nme.CONSTRUCTOR)
sawPrivateConstructor = true
in.skip(2); skipAttributes()
} else {
if ((jflags & JAVA_ACC_BRIDGE) != 0) sflags = sflags | BRIDGE //PRIVATE
- if ((sflags & PRIVATE) != 0 && !global.settings.XbytecodeRead.value) {
+ if ((sflags & PRIVATE) != 0 && global.settings.XO.value) {
in.skip(4); skipAttributes()
} else {
val name = pool.getName(in.nextChar)
@@ -478,6 +479,7 @@ abstract class ClassfileParser {
case BOOL_TAG => definitions.BooleanClass.tpe
case 'L' => {
val classSym = classNameToSymbol(subName(c => ((c == ';') || (c == '<'))))
+ assert(!classSym.hasFlag(OVERLOADED), classSym.alternatives)
val existentials = new ListBuffer[Symbol]()
val tpe: Type = if (sig(index) == '<') {
assert(sym != null)
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala
index eedee0a048..9dce5031ea 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala
@@ -45,7 +45,7 @@ abstract class ICodeReader extends ClassfileParser {
var sym = cls
isScalaModule = cls.isModule && !cls.hasFlag(JAVA)
log("Reading class: " + cls + " isScalaModule?: " + isScalaModule)
- val name = cls.fullNameString(java.io.File.separatorChar) + (if (isScalaModule) "$" else "")
+ val name = cls.fullNameString(java.io.File.separatorChar) + (if (sym.hasFlag(MODULE)) "$" else "")
val entry = classPath.root.find(name, false)
if (entry ne null) {
classFile = entry.classFile
@@ -53,7 +53,6 @@ abstract class ICodeReader extends ClassfileParser {
//sym = cls.linkedClassOfModule
assert(classFile ne null, "No classfile for " + cls)
- println("sym = " + sym)
// for (s <- cls.info.members)
// Console.println("" + s + ": " + s.tpe)
this.instanceCode = new IClass(sym)
@@ -94,12 +93,12 @@ abstract class ICodeReader extends ClassfileParser {
}
override def parseField(): Unit = {
- val (jflags, sym) = parseMember()
+ val (jflags, sym) = parseMember(true)
getCode(jflags).addField(new IField(sym))
skipAttributes()
}
- private def parseMember(): (Int, Symbol) = {
+ private def parseMember(field: Boolean): (Int, Symbol) = {
val jflags = in.nextChar
val name = pool.getName(in.nextChar)
var tpe = pool.getType(in.nextChar)
@@ -113,19 +112,55 @@ abstract class ICodeReader extends ClassfileParser {
if ("<clinit>" == name.toString)
(jflags, NoSymbol)
else {
- var sym = getOwner(jflags).info.member(name).suchThat(old => old.tpe =:= tpe);
+ val owner = getOwner(jflags)
+ var sym = owner.info.member(name).suchThat(old => sameType(old.tpe, tpe));
if (sym == NoSymbol)
- sym = getOwner(jflags).info.member(newTermName(name.toString + nme.LOCAL_SUFFIX)).suchThat(old => old.tpe =:= tpe);
- if (sym == NoSymbol)
- Console.println("Could not find symbol for " + name + ": " + tpe);
+ sym = owner.info.member(newTermName(name.toString + nme.LOCAL_SUFFIX)).suchThat(old => old.tpe =:= tpe);
+ if (sym == NoSymbol) {
+ log("Could not find symbol for " + name + ": " + tpe/* + " in " + owner.info.decls*/)
+ log(owner.info.member(name).tpe + " : " + tpe)
+ if (field)
+ sym = owner.newValue(owner.pos, name).setInfo(tpe).setFlag(MUTABLE | javaToScalaFlags(jflags))
+ else
+ sym = owner.newMethod(owner.pos, name).setInfo(tpe).setFlag(javaToScalaFlags(jflags))
+ owner.info.decls.enter(sym)
+ log("added " + sym + ": " + sym.tpe)
+ }
(jflags, sym)
}
}
+ private def javaToScalaFlags(flags: Int): Long = {
+ import ch.epfl.lamp.fjbg.JAccessFlags._
+
+ var res = 0L
+ if ((flags & ACC_PRIVATE) == 1) res |= Flags.PRIVATE
+ if ((flags & ACC_PROTECTED) == 1) res |= Flags.PROTECTED
+ if ((flags & ACC_FINAL) == 1) res |= Flags.FINAL
+ if ((flags & ACC_ABSTRACT) == 1) res |= Flags.DEFERRED
+ if ((flags & ACC_SYNTHETIC) == 1) res |= Flags.SYNTHETIC
+
+ res
+ }
+
+ /** Checks if tp1 is the same type as tp2, modulo implict methods.
+ * We don't care about the distinction between implcit and explicit
+ * methods as this point, and we can't get back the information from
+ * bytecode anyway.
+ */
+ private def sameType(tp1: Type, tp2: Type): Boolean = (tp1, tp2) match {
+ case (MethodType(args1, resTpe1), MethodType(args2, resTpe2)) =>
+ if (tp1.isInstanceOf[ImplicitMethodType] || tp2.isInstanceOf[ImplicitMethodType]) {
+ MethodType(args1, resTpe1) =:= MethodType(args2, resTpe2)
+ } else
+ tp1 =:= tp2
+ case _ => tp1 =:= tp2
+ }
+
override def parseMethod() {
- val (jflags, sym) = parseMember()
+ val (jflags, sym) = parseMember(false)
if (sym != NoSymbol) {
- Console.println("Parsing method " + sym.fullNameString + ": " + sym.tpe);
+ log("Parsing method " + sym.fullNameString + ": " + sym.tpe);
this.method = new IMethod(sym);
getCode(jflags).addMethod(this.method)
if ((jflags & JAVA_ACC_NATIVE) != 0)
@@ -154,10 +189,16 @@ abstract class ICodeReader extends ClassfileParser {
definitions.AllClass
else if (name == nullName)
definitions.AllRefClass
- else if (name.endsWith("$"))
+ else if (name.endsWith("$class")) {
+ val iface = definitions.getClass(name.subName(0, name.length - "$class".length))
+ log("forcing " + iface)
+ iface.info // force the mixin type-transformer
+ definitions.getClass(name)
+ } else if (name.endsWith("$"))
definitions.getModule(name.subName(0, name.length - 1))
else
definitions.getClass(name)
+ //super.classNameToSymbol(name)
if (sym.isModule)
sym.moduleClass
else
@@ -478,7 +519,12 @@ abstract class ICodeReader extends ClassfileParser {
code.emit(CALL_METHOD(m, style))
case JVM.invokestatic =>
val m = pool.getMemberSymbol(in.nextChar, true); size += 2
- code.emit(CALL_METHOD(m, Static(false)))
+ if (isBox(m))
+ code.emit(BOX(toTypeKind(m.info.paramTypes.head)))
+ else if (isUnbox(m))
+ code.emit(UNBOX(toTypeKind(m.info.resultType)))
+ else
+ code.emit(CALL_METHOD(m, Static(false)))
case JVM.new_ =>
code.emit(NEW(REFERENCE(pool.getClassSymbol(in.nextChar))))
@@ -574,12 +620,22 @@ abstract class ICodeReader extends ClassfileParser {
code.toBasicBlock
assert(method.code ne null)
+ // reverse parameters, as they were prepended during code generation
+ method.params = method.params.reverse
if (code.containsDUPX) {
-
code.resolveDups
}
+ if (code.containsNEW) code.resolveNEWs
}
+ /** TODO: move in Definitions and remove obsolete isBox/isUnbox found there. */
+ def isBox(m: Symbol): Boolean =
+ (m.owner == definitions.BoxesUtilityClass.moduleClass
+ && m.name.startsWith("boxTo"))
+ def isUnbox(m: Symbol): Boolean =
+ (m.owner == definitions.BoxesUtilityClass.moduleClass
+ && m.name.startsWith("unboxTo"))
+
/** Return the icode class that should include members with the given flags.
* There are two possible classes, the static part and the instance part.
*/
@@ -592,12 +648,14 @@ abstract class ICodeReader extends ClassfileParser {
var locals: Map[Int, List[(Local, TypeKind)]] = new HashMap()
var containsDUPX = false
+ var containsNEW = false
def emit(i: Instruction) = {
-// Console.println(i);
instrs += (pc, i)
if (i.isInstanceOf[DupX])
containsDUPX = true
+ if (i.isInstanceOf[opcodes.NEW])
+ containsNEW = true
}
/** Break this linear code in basic block representation
@@ -852,6 +910,35 @@ abstract class ICodeReader extends ClassfileParser {
}
}
+ /** Recover def-use chains for NEW and initializers. */
+ def resolveNEWs {
+ import opcodes._
+
+ val rdef = new reachingDefinitions.ReachingDefinitionsAnalysis;
+ rdef.init(method)
+ rdef.run
+
+ for (bb <- method.code.blocks) {
+ var info = rdef.in(bb)
+ for ((i, idx) <- bb.toList.zipWithIndex) i match {
+ case CALL_METHOD(m, Static(true)) if m.isClassConstructor =>
+ val defs = rdef.findDefs(bb, idx, 1, m.info.paramTypes.length)
+ //println("ctor: " + i + " found defs: " + defs)
+ assert(defs.length == 1)
+ val (bb1, idx1) = defs.head
+ var producer = bb1(idx1)
+ while (producer.isInstanceOf[DUP]) {
+ val (bb2, idx2) = rdef.findDefs(bb1, idx1, 1).head
+ producer = bb2(idx2)
+ }
+ assert(producer.isInstanceOf[NEW], producer)
+ producer.asInstanceOf[NEW].init = i.asInstanceOf[CALL_METHOD]
+ case _ =>
+ }
+ }
+
+ }
+
/** Return the local at given index, with the given type. */
def getLocal(idx: Int, kind: TypeKind): Local = {
assert(idx < maxLocals, "Index too large for local variable.");