diff options
author | Vlad Ureche <vlad.ureche@gmail.com> | 2012-08-14 22:53:31 +0200 |
---|---|---|
committer | Vlad Ureche <vlad.ureche@gmail.com> | 2012-08-15 13:10:33 +0200 |
commit | 41bf9c3c35472fda8bb06db717850886c4270379 (patch) | |
tree | 4f0cfd078d4b79cd29a723f619451d33e62041cc /test/files | |
parent | d66c7a4fea537d142e42da91bfe87f4aaecc1821 (diff) | |
download | scala-41bf9c3c35472fda8bb06db717850886c4270379.tar.gz scala-41bf9c3c35472fda8bb06db717850886c4270379.tar.bz2 scala-41bf9c3c35472fda8bb06db717850886c4270379.zip |
Fixes backend crash due to incorrect consumedTypes
This started out as a compiler crash after Greg copied the
comprehension methods to List and made them final.
The culprit was the dead code elimination phase, which after
sweeping pieces of code was unable to restore the stack to its
original state, thus causing the ASM backend to crash notifying
the resulting bytecode is incorrect.
The dead code elimination phase uses the icode Instructions'
consumedTypes to determine what needs to be dropped from the
stack when an instruction is eliminated, but the consumedTypes
were only defined for a handful of instructions. So dce encountered
a DUP instruction for which it did not have consumedTypes defined
and did not restore the stack correctly.
The consumedTypes/producedTypes for icode instructions are
redundantly defined in 3 separate places:
- Opcodes.scala (consumedTypes/producedTypes)
- ICodeCheckers.scala (for checking icode)
- TypeFlowAnalysis.scala (for computing types on the stack at each
program point)
Since the Opcodes types are the only ones visible outside, I suggest
we use them in ICodeCheckers.scala and TypeFlowAnalysis.scala too. But
we should make such changes after the release, as we're chilling out
by the lake with a glass of good wine: SI-6234
The relevant discussion around it can be found at:
https://groups.google.com/forum/?fromgroups#!topic/scala-internals/qcyTjk8euUI[1-25]
Many thanks to Paul for his help!
Review by @magarciaEPFL or @paulp.
Diffstat (limited to 'test/files')
-rw-r--r-- | test/files/run/dead-code-elimination.check | 0 | ||||
-rw-r--r-- | test/files/run/dead-code-elimination.flags | 1 | ||||
-rw-r--r-- | test/files/run/dead-code-elimination.scala | 33 |
3 files changed, 34 insertions, 0 deletions
diff --git a/test/files/run/dead-code-elimination.check b/test/files/run/dead-code-elimination.check new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/files/run/dead-code-elimination.check diff --git a/test/files/run/dead-code-elimination.flags b/test/files/run/dead-code-elimination.flags new file mode 100644 index 0000000000..49d036a887 --- /dev/null +++ b/test/files/run/dead-code-elimination.flags @@ -0,0 +1 @@ +-optimize diff --git a/test/files/run/dead-code-elimination.scala b/test/files/run/dead-code-elimination.scala new file mode 100644 index 0000000000..1af17c936b --- /dev/null +++ b/test/files/run/dead-code-elimination.scala @@ -0,0 +1,33 @@ + +// This testcase is a snippet that did not compile correctly under +// pre-release 2.10.x. The relevant discussion around it can be +// found at: +// https://groups.google.com/forum/?fromgroups#!topic/scala-internals/qcyTjk8euUI[1-25] +// +// The reason it did not compile is related to the fact that ICode +// ops did not correctly define the stack entries they consumed and +// the dead code elimination phase was unable to correctly reconstruct +// the stack after code elimination. +// +// Originally, this did not compile, but I included it in the run +// tests because this was ASM-dependand and did not happen for GenJVM. +// +// Thus, we run the code and force the loading of class B -- if the +// bytecode is incorrect, it will fail the test. + +final class A { + def f1 = true + def f2 = true + @inline def f3 = f1 || f2 + class B { + def f() = 1 to 10 foreach (_ => f3) + } + def f = (new B).f() +} + +object Test { + def main(args: Array[String]): Unit = { + // force the loading of B + (new A).f + } +} |