diff options
author | Lukas Rytz <lukas.rytz@gmail.com> | 2015-07-07 10:04:36 +0200 |
---|---|---|
committer | Lukas Rytz <lukas.rytz@gmail.com> | 2015-07-23 15:02:18 +0200 |
commit | 1c1d8259b51ede24ccad116ce6f0590d11426a34 (patch) | |
tree | c1710fbd0fcc7989da852b419521ac53e55e9251 /src/compiler | |
parent | ef9d84567655d6f8c9b8541aef4beb706f2a13ec (diff) | |
download | scala-1c1d8259b51ede24ccad116ce6f0590d11426a34.tar.gz scala-1c1d8259b51ede24ccad116ce6f0590d11426a34.tar.bz2 scala-1c1d8259b51ede24ccad116ce6f0590d11426a34.zip |
[backport] Fix bytecode stability
When there are multiple closure allocations and invocations in the
same method, ensure that the callsites are re-written to the body
methods in a consistent order. Otherwsie the bytecode is not stable
(the local variable indices depend on the order in which the calls
are re-written)
Diffstat (limited to 'src/compiler')
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/jvm/opt/ClosureOptimizer.scala | 25 |
1 files changed, 23 insertions, 2 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/ClosureOptimizer.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/ClosureOptimizer.scala index 743a454678..8da209b269 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/ClosureOptimizer.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/ClosureOptimizer.scala @@ -24,8 +24,29 @@ class ClosureOptimizer[BT <: BTypes](val btypes: BT) { import callGraph._ def rewriteClosureApplyInvocations(): Unit = { - closureInstantiations foreach { - case (indy, (methodNode, ownerClass)) => + implicit object closureInitOrdering extends Ordering[(InvokeDynamicInsnNode, MethodNode, ClassBType)] { + // Note: this code is cleaned up in a future commit, no more tuples. + override def compare(x: (InvokeDynamicInsnNode, MethodNode, ClassBType), y: (InvokeDynamicInsnNode, MethodNode, ClassBType)): Int = { + val cls = x._3.internalName compareTo y._3.internalName + if (cls != 0) return cls + + val mName = x._2.name compareTo y._2.name + if (mName != 0) return mName + + val mDesc = x._2.desc compareTo y._2.desc + if (mDesc != 0) return mDesc + + def pos(indy: InvokeDynamicInsnNode) = x._2.instructions.indexOf(indy) + pos(x._1) - pos(y._1) + } + } + + val sorted = closureInstantiations.iterator.map({ + case (indy, (methodNode, ownerClass)) => (indy, methodNode, ownerClass) + }).to[collection.immutable.TreeSet] + + sorted foreach { + case (indy, methodNode, ownerClass) => val warnings = rewriteClosureApplyInvocations(indy, methodNode, ownerClass) warnings.foreach(w => backendReporting.inlinerWarning(w.pos, w.toString)) } |