diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2012-11-03 13:34:20 +0100 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2012-11-03 23:25:13 +0100 |
commit | dad886659faca4fba2d4937c9bc6780591b02c27 (patch) | |
tree | 0fcb5ab4e20c6570bd15cf773c9ec9d1d74f7e81 | |
parent | b5e3eafabe4b9cfe1e6de9eeedfe1140afeaa4eb (diff) | |
download | scala-dad886659faca4fba2d4937c9bc6780591b02c27.tar.gz scala-dad886659faca4fba2d4937c9bc6780591b02c27.tar.bz2 scala-dad886659faca4fba2d4937c9bc6780591b02c27.zip |
SI-6611 Tighten up an unsafe array optimization
The net was cast too wide and was unsafely optimizing away array
copies.
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/CleanUp.scala | 13 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/TreeInfo.scala | 14 | ||||
-rw-r--r-- | test/files/instrumented/t6611.check | 1 | ||||
-rw-r--r-- | test/files/instrumented/t6611.scala | 13 | ||||
-rw-r--r-- | test/files/run/t6611.scala | 6 |
5 files changed, 42 insertions, 5 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala index 1f353bb31c..bdcebf47b8 100644 --- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala +++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala @@ -15,6 +15,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL { import global._ import definitions._ import CODE._ + import treeInfo.StripCast /** the following two members override abstract members in Transform */ val phaseName: String = "cleanup" @@ -618,14 +619,16 @@ abstract class CleanUp extends Transform with ast.TreeDSL { } transformApply - // This transform replaces Array(Predef.wrapArray(Array(...)), <tag>) - // with just Array(...) - case Apply(appMeth, List(Apply(wrapRefArrayMeth, List(array)), _)) + // Replaces `Array(Predef.wrapArray(ArrayValue(...).$asInstanceOf[...]), <tag>)` + // with just `ArrayValue(...).$asInstanceOf[...]` + // + // See SI-6611; we must *only* do this for literal vararg arrays. + case Apply(appMeth, List(Apply(wrapRefArrayMeth, List(arg @ StripCast(ArrayValue(_, _)))), _)) if (wrapRefArrayMeth.symbol == Predef_wrapRefArray && appMeth.symbol == ArrayModule_overloadedApply.suchThat { - _.tpe.resultType.dealias.typeSymbol == ObjectClass + _.tpe.resultType.dealias.typeSymbol == ObjectClass // [T: ClassTag](xs: T*): Array[T] post erasure }) => - super.transform(array) + super.transform(arg) case _ => super.transform(tree) diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala index 66326c90e9..bee92b446b 100644 --- a/src/reflect/scala/reflect/internal/TreeInfo.scala +++ b/src/reflect/scala/reflect/internal/TreeInfo.scala @@ -265,6 +265,20 @@ abstract class TreeInfo { tree } + /** Strips layers of `.asInstanceOf[T]` / `_.$asInstanceOf[T]()` from an expression */ + def stripCast(tree: Tree): Tree = tree match { + case TypeApply(sel @ Select(inner, _), _) if isCastSymbol(sel.symbol) => + stripCast(inner) + case Apply(TypeApply(sel @ Select(inner, _), _), Nil) if isCastSymbol(sel.symbol) => + stripCast(inner) + case t => + t + } + + object StripCast { + def unapply(tree: Tree): Some[Tree] = Some(stripCast(tree)) + } + /** Is tree a self or super constructor call? */ def isSelfOrSuperConstrCall(tree: Tree) = { // stripNamedApply for SI-3584: adaptToImplicitMethod in Typers creates a special context diff --git a/test/files/instrumented/t6611.check b/test/files/instrumented/t6611.check new file mode 100644 index 0000000000..5cd691e93a --- /dev/null +++ b/test/files/instrumented/t6611.check @@ -0,0 +1 @@ +Method call statistics: diff --git a/test/files/instrumented/t6611.scala b/test/files/instrumented/t6611.scala new file mode 100644 index 0000000000..821d5f3fbf --- /dev/null +++ b/test/files/instrumented/t6611.scala @@ -0,0 +1,13 @@ +import scala.tools.partest.instrumented.Instrumentation._ + +object Test { + def main(args: Array[String]) { + startProfiling() + + // tests optimization in Cleanup for varargs reference arrays + val a = Array("") + + stopProfiling() + printStatistics() + } +} diff --git a/test/files/run/t6611.scala b/test/files/run/t6611.scala new file mode 100644 index 0000000000..c0297372f0 --- /dev/null +++ b/test/files/run/t6611.scala @@ -0,0 +1,6 @@ +object Test extends App { + val a = Array("1") + val a2 = Array(a: _*) + a2(0) = "2" + assert(a(0) == "1") +} |