Understanding subtle new behaviours of JDK 7
As I said in my previous post, a few months ago I've put under my CI a number of projects of mine to be tested in parallel with JDK 6 and JDK 7. After a few minor issues, they were ok and have been working even in production under (Open)JDK 7 since the end of the past year. Given that now Oracle has started releasing JDK 7 for Mac OS X too and that the latest NetBeans 7.1.2 works fine under Mac OS X and JDK 7, I'm going to start dropping support for JDK 6 and gradually move all my projects to JDK 7. This means to set -source 1.7 and -target 1.7, so I'll be able to start using the new Java 7 features.
But yesterday night the new -source and -target options gave me a strange result: all of a sudden, some tests failed with funny messages such as:
Failed tests: setUp(it.tidalwave.northernwind.core.impl.filter.NodeLinkMacroFilterTest):
Expecting a stackmap frame at branch target 94 in method
at offset 22 setupFixture(it.tidalwave.northernwind.core.impl.filter.XsltMacroFilterTest):
Expecting a stackmap frame at branch target 21 in method it.tidalwave.northernwind.core.impl.filter.XsltMacroFilter.filter(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
at offset 6 setupFixture(it.tidalwave.northernwind.core.impl.model.DefaultSiteProviderTest):
Expecting a stackmap frame at branch target 14 in method it.tidalwave.northernwind.core.impl.model.DefaultSite.r(Ljava/lang/String;)Ljava/lang/String;
at offset 6
Turns out they are error from the bytecode verifier. Now, before starting the migration to JDK 7 you should read the document prepared by Oracle: at section 4.1.1 there's something about the new bytecode format and bytecode verifier. Trying to keep the things simple, the new bytecode verifier performs stricter checks and relies upon changed data format in the bytecode. The VM in JDK 7 uses the new verifier for code compiled in Java 7 mode, but falls back to the old one for code compiled in Java 6 mode. Thus, in theory there should be no problem.
Problems actually arise if you're using bytecode manipulating tools, such as AspectJ in static weaving mode - I do - that haven't been updated yet. They basically read the bytecode, tagged as Java 7 bytecode, and perform changes in Java 6 mode, saving the results still tagged in Java 7 mode. Thus, the VM in JDK 7 sees Java 7 bytecode and activates the new Java 7 verifier, which fails (or can fail) when it meet the bytecode manipulated in Java 6 mode.
It seems complicated, but the simple solution is to force the use of the old verifier in JDK 7 by adding this VM runtime option: -XX:-UseSplitVerifier.
When AspectJ is updated (AspectJ 1.7.0.M1 is the first release targeted at JDK 7, but it's still a milestone so it's probably not a good idea to try it in production) everything will be fine again and there will be no more need for the -XX option.