Bug 110182 - [compiler] Eclipse does not recompile rt.jar properly
Summary: [compiler] Eclipse does not recompile rt.jar properly
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.1   Edit
Hardware: PC All
: P3 normal (vote)
Target Milestone: 3.1.1   Edit
Assignee: Philipe Mulet CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2005-09-21 10:53 EDT by Pascal Filion CLA
Modified: 2005-09-29 16:26 EDT (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Pascal Filion CLA 2005-09-21 10:53:37 EDT
For the past several versions, perhaps since the introduction of 1.5 support,
Eclipse does not recompile rt.jar properly. After recompiling rt.jar with debug
info and replacing the existing jar in jdk_home/jre/lib, the focus in any
dialogs of a Swing application does not work. rt.jar is recompiled using the
src.zip included in the JDK and then the new classes are added to rt.jar to
replace those compiled by Sun. The problem appears with either 1.4.2 or 1.5.0.

The problem seems to be the byte code generated is different from the byte code
generated by Sun's JDK compiler. Especially in the class
java.awt.KeyboardFocusManager. If that class is not replaced, then the focus is
working.

If one decompile the 2 different versions one will see a slight difference in
the stuff surrounding sychronize()
Comment 1 Brian Vosburgh CLA 2005-09-21 14:57:19 EDT
Here's some more information: When I start up a Swing application using a Sun
JDK 1.5.0_04 rt.jar compiled by the Eclipse compiler, I get an IllegalAccessError in
    KeyboardFocusManager.shouldNativelyFocusHeavyweight
        (Component heavyweight, Component descendant, boolean temporary,
         boolean focusedWindowChangeAllowed, long time)
on the line where the method synchronizes on 'heavyweightRequests'.

The stack trace looks like this:
    KeyboardFocusManager.shouldNativelyFocusHeavyweight(Component, Component,
        boolean, boolean, long) line: 2247
    WToolkit.eventLoop() line: not available [native method]
    WToolkit.run() line: 269
    Thread.run() line: 595

I'm not a byte code expert, but I can tell (via jad and looking at the byte
codes), that the byte codes generated by the JDK compiler and those generated by
the Eclipse compiler are different for the chunk of code that synchronizes on
'heavyweightRequests'. Why this would cause an IllegalAccessError, I have no
idea. :-)
Comment 2 Philipe Mulet CLA 2005-09-21 15:56:21 EDT
Which Eclipse build number are you using ?
Can you provide exact steps to reproduce ? (i.e. a simple and detailed scenario
which would not work on the recompiled library).

Olivier - pls investigate, and ping me once you isolated the offending pattern. 
Comment 3 Olivier Thomann CLA 2005-09-21 17:37:30 EDT
what compliance are you using?
1.5? I guess you use 1.5 for at least compiling the 1.5 source, but when you
compile the 1.4 source.
Are you inlining the subroutines?
This could explain the difference for the synchronize code generation.
Comment 4 Brian Vosburgh CLA 2005-09-22 00:01:51 EDT
Eclipse release: 3.1.0

For the JDK 1.5.0_05 rt.jar:
    Compiler Compliance Level: 5.0
    Use default compliance settings
    Include all debug information
    I don't know about an option for "inlining the subroutines"
    but I do see an option that cannot be disabled for "Inline finally blocks"

For the JDK 1.4.2_09 rt.jar
    Compiler Compliance Level: 1.4
    Use default compliance settings
    Include all debug information
    I don't know about an option for "inlining the subroutines"
    but I do see an option that cannot be disabled for "Inline finally blocks"

The following program will re-create the problem when run with the rt.jar
compiled by the Eclipse compiler:

package foo;
public class EclipseCompilerProblem {
	public static void main(String[] args) {
		javax.swing.JOptionPane.showConfirmDialog(null, new
javax.swing.JTextField("can you type here?"));
	}
}

Execute the program and you will not be able to type in the text field - it will
never take the focus. Debug the program and you will see an IllegalAccessError
as described earlier. (This error is swallowed when executing the program
outside the debugger; so you will not see a stack trace.) These problems do not
occur when using the rt.jar compiled by the JDK compiler.
Comment 5 Brian Vosburgh CLA 2005-09-22 00:06:16 EDT
(re: comment #4)
Sorry, I meant to say that, for the JDK 1.4.2_09 rt.jar, the option to "Inline
finally blocks" was NOT enabled.
Comment 6 Philipe Mulet CLA 2005-09-22 03:55:30 EDT
I cannot reproduce this using latest 3.1 maintenance build (3.1.1 candidate).
This would indicate it is a dup of one of the 50 compiler issues we did resolve
since 3.1.0.

Brian - could you pls get Eclipse SDK Version: 3.1.1, Build id: M20050914-1235
        or better and confirm the problem has been resolved ?
Comment 7 Pascal Filion CLA 2005-09-22 10:20:12 EDT
I compiled JDK 1.5.0_05 and 1.4.2_08 with Eclipse build M20050914-1235 and I 
still have the problem. When I compile rt.jar, I have the following 
configuration:
- All errors/warnings are set to Ignore
- JavaDoc comment are not processed
- No Task tags

For JDK 1.5.0_0x
- The compiler compliance level is set to 5.0
- Inline finally block is disabled and selected

For JDK 1.4.2_0x
- I unchecked Inline finally block
- The compiler compliance level is set to 1.4, the generated .class files and 
source compatibility is also set to 1.4.

I added the jar xmlparserv2.jar on my build path. I make sure the JRE Library 
is after the source folder on the build path.

Once the classes are compiled, I add them to rt.jar. I replaced the default 
rt.jar in my jdk_home/jre/lib directory with the new one. I ran Brian's 
example and I am still seeing the problem.
Comment 8 Brian Vosburgh CLA 2005-09-22 10:44:34 EDT
I just re-compiled the jdk 1.5.0_04 rt.jar with Eclipse SDK 3.1.1 stream build
M20050914-1235 and the same problem occurs. Is there something else I should try
or some other configuration setting you need to know about to re-create the problem?

The original jdk source for KeyboardFocusManager (starting at line 2247) looks
like this:
        synchronized (heavyweightRequests) {
            HeavyweightFocusRequest hwFocusRequest = (HeavyweightFocusRequest)
                ((heavyweightRequests.size() > 0)
                 ? heavyweightRequests.getLast() : null);
            if (focusLog.isLoggable(Level.FINEST)) {
                focusLog.finest("Request " + hwFocusRequest);
            }

The decompiled JDK byte code looks like this:
/*2247*/        LinkedList linkedlist = heavyweightRequests;
/*2247*/        JVM INSTR monitorenter ;
                HeavyweightFocusRequest heavyweightfocusrequest;
/*2248*/        heavyweightfocusrequest =
(HeavyweightFocusRequest)(heavyweightRequests.size() <= 0 ? null :
heavyweightRequests.getLast());
/*2251*/        if (focusLog.isLoggable(Level.FINEST))
/*2252*/            focusLog.finest((new StringBuilder()).append("Request
").append(heavyweightfocusrequest).toString());


The decompiled ECLIPSE byte code looks like this:
/*2247*/            synchronized (heavyweightRequests) {
/*2249*/                hwFocusRequest =
(HeavyweightFocusRequest)(heavyweightRequests.size() <= 0 ? null :
heavyweightRequests.getLast());
/*2251*/                if (focusLog.isLoggable(Level.FINEST))
/*2252*/                    focusLog.finest((new StringBuilder("Request
")).append(hwFocusRequest).toString());

Obviously jad had some problems decompiling the JDK byte code, but it did not
have any problems with the Eclipse byte code. Anyway, it does indicate some sort
of difference....
Comment 9 Olivier Thomann CLA 2005-09-22 11:08:39 EDT
We are investigating.
Comment 10 Olivier Thomann CLA 2005-09-22 12:50:52 EDT
I could reproduce the problem in the debugger.
It seems to be a side-effect of the code generation for the if(dbg.on) {...}
statement.
This is an access to a static field done by using a static variable. So we don't
consider the field access to be a constant expression. We end up generating some
dead code in the body of the method with:
iconst_0
ifeq 41
...

The then block is never executed. If I comment out these if statements it works
fine and I cannot reproduce the problem anymore.
The IllegalAccessError is thrown on the access to the field dbg. It has nothing
to do with the synchronize block.
Comment 11 Brian Vosburgh CLA 2005-09-22 14:29:25 EDT
Sorry about the misleading information. I guess I was paying too much attention
to the line number specified by the stack trace and the fact that jad seemed to
have problems centered on that same line of code; but that may have been a
side-effect of the earlier code generated for the 'if(dbg.on) {...'
statement(?). Anyway, is this a bug? It appears to be a regression from Eclipse
3.0, since I have not seen this problem before.
Comment 12 Olivier Thomann CLA 2005-09-22 14:33:07 EDT
Could you please try to get rid of the if (dbg.on) {....} statement everywhere?
I'd like you to confirm that this is working fine once the if statement is gone.
Thanks.
Comment 13 Philipe Mulet CLA 2005-09-22 15:35:13 EDT
Before Eclipse 3.0, we were aggressively optimizing out many of such cases,
missing potential null checks along the line. Now we are a bit less optimized on
unoptimal expressions (like here, when reaching a constant boolean through a
non-static slot, which we flag as a warning btw). 

Though the generated code is unoptimal, it is still ok (though dead), and it
seems that the VM cannot properly handle deadcode, and issuing an unexpected
exception (complaining about a field access which it performs just fine a few
lines before).

Anyhow, I think I have a fix. There are more than just qualified name to fix. I
also found field references and hedging on assignments.
Comment 14 Brian Vosburgh CLA 2005-09-23 00:32:43 EDT
I got rid of all the if '(dbg.on) {...}' statements and recompiled with the
Eclipse compiler and things seem to work fine for me.
Comment 15 Philipe Mulet CLA 2005-09-23 04:42:49 EDT
Ok, I take back my previous comment. Though our codegen is unoptimal in this
rare situation, the problem comes from the fact we do not generate a synthetic
access method when reaching the dbg field from inside the member class; and thus
hit an IllegalAccessError.

Only first field fragment of a qualified name exhibits this missing synthetic
(in the only case its value isn't needed, but still we generate its access to
get possible side effects). It is a scenario where we optimized too much during
emulation, compared to our codegen strategy.

Will align them (note that strategy is different in 1.3 compliant mode, where we
are right to optimize out the access method, since the field access is not
generated).

Will not release changes to avoid deadcode generation, since we are really close
to 3.1.1, and I do not want to take too much risk there. So for 3.1.1, we will
address the actual problem, and in 3.2 we will also fix the dead codegen
secondary issue.

Fix is in QualifiedNameReference. Added InnerEmulationTest#test123.
Released in 3.1 maintenance branch.
Comment 16 Philipe Mulet CLA 2005-09-23 04:46:12 EDT
Removing [1.5] prefix in title, since bug is not 1.5 specific (affects both 1.4
and 1.4 compliance modes).
Comment 17 Olivier Thomann CLA 2005-09-23 11:57:32 EDT
Verified with build M20050923-0800.

I also checked that the acces method is used:
  java.awt.KeyboardFocusManager$HeavyweightFocusRequest(Component heavyweight,
Component descendant, boolean temporary);
     0  aload_0 [this]
     1  invokespecial java.lang.Object() [21]
     4  invokestatic java.awt.KeyboardFocusManager.access$0() :
sun.awt.DebugHelper  [33]
     7  pop
     8  iconst_0
     9  ifeq 27
....
Comment 18 Philipe Mulet CLA 2005-09-26 03:56:43 EDT
Released fix in 3.2 (HEAD) stream, along with boolean optimization for codegen
(all but assignment expression as this would break some definite assignment
semantics). Tuned the above regression tests accordingly.
Comment 19 Philipe Mulet CLA 2005-09-26 03:57:16 EDT
Fix will be available in HEAD for builds > 3.2m2
Comment 20 Pascal Filion CLA 2005-09-29 13:13:01 EDT
Thanks for the fix, I just recompiled JDK 1.4.2 and 1.5 and everything is 
working well. I used build 3.1.2 N20050928-0010.
Comment 21 Philipe Mulet CLA 2005-09-29 16:26:55 EDT
Thanks for verifying