Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.
Difference between revisions of "JDT Core Programmer Guide/ECJ/Investigating"
(Created page with "<css> →box for bash listings: .source-bash { border:#2F6FAB 1px dashed; background-color:#F9F9F9; padding:4px; } </css> ==Strategies for investigating compiler bugs== ==...") |
|||
Line 86: | Line 86: | ||
It is useful to have a git clone and eclipse workspace dedicated only to bisecting, so that you never mess up your regular workspace. This is reflected by a copy of <code>ecj-HEAD.sh</code> where <code>${JDT_GIT}</code> points to that instance of org.eclipse.jdt.core. | It is useful to have a git clone and eclipse workspace dedicated only to bisecting, so that you never mess up your regular workspace. This is reflected by a copy of <code>ecj-HEAD.sh</code> where <code>${JDT_GIT}</code> points to that instance of org.eclipse.jdt.core. | ||
+ | ===Comparing compiler output=== | ||
+ | |||
+ | In most cases, it is sufficient to check which compiler version accepts / rejects the given test program, possibly checking also for warnings. | ||
+ | |||
+ | In other cases it is also necessary to compare executions of the compiled test program. | ||
+ | |||
+ | In rare case it may even be necessary to also check the compiler output (e.g., to check class file attributes like annotations etc). When different compiler versions generate different byte code, the following sequence would identify that difference: | ||
+ | |||
+ | <source lang="bash"> | ||
+ | $ ecj.sh 4.10 Hello.java | ||
+ | $ javap -p -v -c Hello.class > Hello-4.10.list | ||
+ | $ ecj.sh 4.11 Hello.java | ||
+ | $ javap -p -v -c Hello.class > Hello-4.11.list | ||
+ | $ diff Hello-4.10.list Hello-4.11.list | ||
+ | </source> | ||
+ | |||
+ | Obviously, a graphical diff tool (like <code>kompare</code>) comes in handy for this task. | ||
[[Category:JDT]] | [[Category:JDT]] |
Revision as of 14:41, 2 July 2020
Contents
Strategies for investigating compiler bugs
Comparing compiler versions
For initial triage it is useful to test how different compiler versions respond to a given source file. This can be done quickly using a shell and a few shell scripts. The following assumes bash
.
ecj-HEAD.sh
: Run the compiler from class files of an existing JDT/Core workspace / git clone:
#!/bin/sh # Adjust path to the root of a git clone of JDT/Core: JDT_GIT=/home/git/eclipse.jdt.core # Adjust path to a suitable Java installation: JAVA_HOME=${JAVA_HOME:-/home/java/jdk1.8.0} ECJ_BINS=${JDT_GIT}/org.eclipse.jdt.core/bin:${JDT_GIT}/org.eclipse.jdt.compiler.apt/bin PATH=${JAVA_HOME}/bin:${PATH} java -classpath $ECJ_BINS org.eclipse.jdt.internal.compiler.batch.Main $*
ecj.sh
Run the compiler from one out of a set of stored ecj jar files:
Assume you have a directory ($BASE
in the script below) holding different versions of ecj, with file names like ecj-4.16.jar
, then the following script can be used to pick and use any of the stored versions:
#!/bin/sh BASE=${HOME}/jdt/ecj ECJ=${BASE}/ecj-${1}.jar if [ -f ${ECJ} ] then echo "Compiling with $ECJ" else echo "Not found: ${ECJ}" echo "Available:" cd ${BASE} ls ecj-*.jar exit 2 fi EXTRA="-proc:none" case ${1} in 4.[4-7]*) JAVA_HOME=/home/java/jdk1.8.0 PATH=${JAVA_HOME}/bin:${PATH} ;; 4.[0-3].*) JAVA_HOME=/home/java/jdk1.6.0 PATH=${JAVA_HOME}/bin:${PATH} ;; 3.[0-9]*) JAVA_HOME=/home/java/jdk1.5.0 PATH=${JAVA_HOME}/bin:${PATH} EXTRA="" ;; esac shift echo java -jar ${ECJ} ${EXTRA} $* java -jar ${ECJ} ${EXTRA} $*
Example invocation:
$ ecj.sh 4.16 -1.8 Hello.java
The extra argument -proc:none
is useful because some history ecj versions lack the annotation processing classes and thus crash when trying to perform annotation processing.
Also note, that different version ranges of ecj require different Java versions to run. Adjust paths in the script to your local installations.
Speedy bisecting
If the compiler behavior changed significantly at a yet unknown point in time, the following appears to be the fasted approach to find the exact commit causing the change:
- Use the parametric script
ecj.sh
to find the release or even milestone that first introduced the change. - Identify git tags of last version with old behavior and first version with new behavior
- In a shell inside a JDT/Core git clone perform the
git bisect
subcommands - In an Eclipse workspace that has org.eclipse.jdt.core from that git imported, refresh the git repo and wait for auto build to complete
- In another shell where you have your test source invoke
ecj-HEAD.sh
- Check the result and go back to 3. until done
It is useful to have a git clone and eclipse workspace dedicated only to bisecting, so that you never mess up your regular workspace. This is reflected by a copy of ecj-HEAD.sh
where ${JDT_GIT}
points to that instance of org.eclipse.jdt.core.
Comparing compiler output
In most cases, it is sufficient to check which compiler version accepts / rejects the given test program, possibly checking also for warnings.
In other cases it is also necessary to compare executions of the compiled test program.
In rare case it may even be necessary to also check the compiler output (e.g., to check class file attributes like annotations etc). When different compiler versions generate different byte code, the following sequence would identify that difference:
$ ecj.sh 4.10 Hello.java $ javap -p -v -c Hello.class > Hello-4.10.list $ ecj.sh 4.11 Hello.java $ javap -p -v -c Hello.class > Hello-4.11.list $ diff Hello-4.10.list Hello-4.11.list
Obviously, a graphical diff tool (like kompare
) comes in handy for this task.