summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLukas Rytz <lukas.rytz@gmail.com>2015-07-03 08:25:30 +0200
committerLukas Rytz <lukas.rytz@gmail.com>2015-07-23 15:02:17 +0200
commit404e86239e445307fdff4fb0cb4e512993ac56b8 (patch)
treef8e31ac3c3a29e14b50a71d3bcde3fab12cc3d08 /src
parent1b0703e74d22ed54b95a134216835569a20d2325 (diff)
downloadscala-404e86239e445307fdff4fb0cb4e512993ac56b8.tar.gz
scala-404e86239e445307fdff4fb0cb4e512993ac56b8.tar.bz2
scala-404e86239e445307fdff4fb0cb4e512993ac56b8.zip
[backport] Prevent infinite recursion in ProdConsAnalyzer
When an instruction is its own producer or consumer, the `initialProducer` / `ultimateConsumer` methods would loop. While loops or @tailrec annotated methods can generate such bytecode.
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala18
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/analysis/ProdConsAnalyzer.scala12
2 files changed, 21 insertions, 9 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala b/src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala
index 0df1b2029d..cd7e0b83e8 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala
@@ -10,6 +10,7 @@ import java.io.{StringWriter, PrintWriter}
import scala.tools.asm.util.{CheckClassAdapter, TraceClassVisitor, TraceMethodVisitor, Textifier}
import scala.tools.asm.{ClassWriter, Attribute, ClassReader}
import scala.collection.convert.decorateAsScala._
+import scala.tools.nsc.backend.jvm.analysis.InitialProducer
import scala.tools.nsc.backend.jvm.opt.InlineInfoAttributePrototype
object AsmUtils {
@@ -81,13 +82,16 @@ object AsmUtils {
/**
* Returns a human-readable representation of the given instruction.
*/
- def textify(insn: AbstractInsnNode): String = {
- val trace = new TraceMethodVisitor(new Textifier)
- insn.accept(trace)
- val sw = new StringWriter
- val pw = new PrintWriter(sw)
- trace.p.print(pw)
- sw.toString.trim
+ def textify(insn: AbstractInsnNode): String = insn match {
+ case _: InitialProducer =>
+ insn.toString
+ case _ =>
+ val trace = new TraceMethodVisitor(new Textifier)
+ insn.accept(trace)
+ val sw = new StringWriter
+ val pw = new PrintWriter(sw)
+ trace.p.print(pw)
+ sw.toString.trim
}
/**
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/analysis/ProdConsAnalyzer.scala b/src/compiler/scala/tools/nsc/backend/jvm/analysis/ProdConsAnalyzer.scala
index 40f91cbed4..cf63bf54a4 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/analysis/ProdConsAnalyzer.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/analysis/ProdConsAnalyzer.scala
@@ -103,7 +103,11 @@ class ProdConsAnalyzer(methodNode: MethodNode, classInternalName: InternalName)
def initialProducersForValueAt(insn: AbstractInsnNode, slot: Int): Set[AbstractInsnNode] = {
def initialProducers(insn: AbstractInsnNode, producedSlot: Int): Set[AbstractInsnNode] = {
if (isCopyOperation(insn)) {
- _initialProducersCache.getOrElseUpdate((insn, producedSlot), {
+ val key = (insn, producedSlot)
+ _initialProducersCache.getOrElseUpdate(key, {
+ // prevent infinite recursion if an instruction is its own producer or consumer
+ // see cyclicProdCons in ProdConsAnalyzerTest
+ _initialProducersCache(key) = Set.empty
val (sourceValue, sourceValueSlot) = copyOperationSourceValue(insn, producedSlot)
sourceValue.insns.iterator.asScala.flatMap(initialProducers(_, sourceValueSlot)).toSet
})
@@ -121,7 +125,11 @@ class ProdConsAnalyzer(methodNode: MethodNode, classInternalName: InternalName)
def ultimateConsumersOfValueAt(insn: AbstractInsnNode, slot: Int): Set[AbstractInsnNode] = {
def ultimateConsumers(insn: AbstractInsnNode, consumedSlot: Int): Set[AbstractInsnNode] = {
if (isCopyOperation(insn)) {
- _ultimateConsumersCache.getOrElseUpdate((insn, consumedSlot), {
+ val key = (insn, consumedSlot)
+ _ultimateConsumersCache.getOrElseUpdate(key, {
+ // prevent infinite recursion if an instruction is its own producer or consumer
+ // see cyclicProdCons in ProdConsAnalyzerTest
+ _ultimateConsumersCache(key) = Set.empty
for {
producedSlot <- copyOperationProducedValueSlots(insn, consumedSlot)
consumer <- consumersOfValueAt(insn.getNext, producedSlot)