Eclipse Goes Native
July 1st, 2004 by John Healy, Andrew Haley and Tom Tromey in
Eclipse is an open-source, extensible integrated development environment (IDE) that's growing quickly in popularity. Written in Java, it provides a multilanguage development environment that allows developers to code in Java, C and C++. In response to the need for improved performance and additional platform coverage for the Red Hat Developer Suite, of which Eclipse is the core, we created a version of Eclipse that's compiled natively. Instead of running on top of a virtual machine the way Java programs usually do—although that can still be done if the user prefers—Red Hat's version of Eclipse is compiled to binary and runs natively using the libgcj runtime libraries, similar to the way a C program runs using the GNU C libraries.
To compile Eclipse natively, Red Hat's Eclipse Engineering team used GCJ, a free, optimizing, ahead-of-time compiler for Java. GCJ can compile Java source code to native machine code, Java source code to Java bytecode and Java bytecode to native machine code. The approach we took involves using GCJ to compile Java bytecode to native machine code.
This article discusses why native compilation was an attractive choice; explains what we had to do to GCJ, libgcj and Eclipse to make it possible; and shows, using a real-world example, that open-source Java has come a long way and now is useful commercially.
Two main factors from the early days of Developer Suite planning and engineering drove us toward native compilation: platform coverage and performance. Red Hat Enterprise Linux was scheduled to ship on several 64-bit architectures, and we wanted to make sure Developer Suite could run on all of them. One big problem was Eclipse had never been run on a 64-bit platform and it contained some code, specifically the interface between SWT, the graphics toolkit in Eclipse, and its native C libraries, that assumed 32-bit addresses. Aside from having to create a clean 64-bit version of SWT, we were faced with a more significant problem: no 64-bit Java Virtual Machine (JVM) for x86_64, AMD's 64-bit architecture, existed at the time, and it didn't look hopeful that one would be available before we had to ship.
Another problem we had was performance. Eclipse worked well on Microsoft Windows but the version available at the time was pretty slow on Linux. We found that startup alone took well over a minute, and early user testing found that the interface was a little too sluggish for comfortable use. For example, Eclipse is based on perspectives, which are collections of views and editors, only one of which is visible at a time. Switching between them is something that a user does fairly frequently. However, changing perspectives introduced substantial delays we thought unacceptable for the enterprise development market Red Hat Developer Suite was targeting.
The solution we came up with was to use GCJ to compile Eclipse into native binaries that could run without having a JVM installed. We knew that native compilation would help with the performance problems, because we would no longer have the overhead that comes with the JVM layer. It also would solve the platform coverage problem, as GCJ/libgcj was available on all of the 64-bit platforms we had to support, although in some cases, such as x86_64, it still needed a lot of work. Native compilation solved the technical problems we had and gave us the additional benefits of reducing our external dependencies, allowing us to make some significant improvements to open-source Java and to demonstrate that open-source Java has matured to the point of being useful commercially.
At the outset of this project, we really didn't know if it was possible to compile Eclipse with GCJ and expect it to run. First, Eclipse is a large program—more than two million lines of code as counted by wc. We didn't know much about Eclipse internals or what runtime facilities it might use. Second, GCJ's background is in embedded systems, and we knew that work remained on parts of the Java programming language, class loaders in particular, which are used heavily by Eclipse. Third, the free class libraries were not complete. We didn't know if Eclipse could use facilities we hadn't written yet or even whether Eclipse might break the rules and use internal, undocumented com.sun.* interfaces, as too many Java programs seem to do.
We therefore took a two-pronged approach to determining whether a project like this could succeed. First, we used GCJ to make a list of the APIs used by Eclipse that we did not or could not implement. To accomplish this, we wrote a shell script that would try to compile each Eclipse Java archive library (jar file) to object code. We then looked through the error messages to see what was missing. The results of this script were not encouraging: we found a large number of missing packages. Still, more investigation was required because some things didn't make sense. For instance, there were dependencies on the Swing graphical user interface classes, but we knew that Eclipse used SWT and not Swing.
Further investigation showed that many of the weird undefined references came not from Eclipse itself but from the third-party jar files included with it. For example, Eclipse includes its own copy of the Ant build tool and its own copy of the Apache Tomcat dynamic Web server. We knew that in many cases, the referenced classes would not actually be invoked in the Eclipse environment. This encouraged us to take another look at how to get Eclipse working.
Our second angle of attack was to try running Eclipse using the bytecode interpreter that comes with libgcj. By doing this, we reasoned, we would concentrate on runtime bugs, including the aforementioned class loader problems and missing functionality actually used by Eclipse.
This approach also was discouraging initially. We ran into problems not only with class loading, but also with the fact that libgcj's implementation of protection domains needed work. These are the bases for Java's secure sandbox architecture, which allows untrusted code to be run in a secure way. Problems in this area had an unfortunate shadowing effect—we had to fix each bug before we could discover the next one.
Our first round of changes to libgcj was bug fixing only. We implemented protection domains properly. Then, we made a pass over the entire runtime, fixing bugs related to class loading. Because of the way class loading had been implemented in libgcj, we had to modify all the places in the native code that conceivably might load a class to forward the request to the appropriate class loader.
Once this was done, we were able to start Eclipse using the libgcj bytecode interpreter. At this point the question became, how can we take real advantage of GCJ to compile Eclipse?
The naïve approach to this dilemma, namely precompiling all the classes and linking them all together, had been ruled out by our investigations into Eclipse's internals. This approach would clash with Eclipse's relatively sophisticated class loading strategy.
More investigation revealed that most classes are loaded by instances of the DelegatingURLClassLoader, which is a subclass of the standard URLClassLoader that has been extended to understand Eclipse's plugin architecture. It seemed like the best approach was to modify Eclipse to allow it to load precompiled shared libraries as well as bytecode files. We reasoned that the required changes would be localized due to the way plugin class loading had been structured.
In fact, we had to go one step further and extend libgcj a bit as well. libgcj knew how to load shared libraries invisibly in response to a call to, for example, Class.forName(). However, this magic always happened at the level of the bootstrap class loader. That wouldn't work well for Eclipse or for any other application that defines its own class loaders, so we invented a new gcjlib URL type. This is like a jar URL, but it points to a shared library. We also made some minor extensions to our implementation of URLClassLoader so that gcjlib URLs would be treated specially.
Doing this wasn't enough, however. We also had to solve the linkage problems. In particular, if we compiled a jar file to a shared library, how could we prevent the dlopen() of such a shared library from immediately failing due to unresolved symbols? The solution to this problem was to resurrect and clean up the -fno-assume-compiled option in GCJ. This option, which never had been finished, enabled an alternative ABI that caused GCJ's output to resolve most references at runtime rather than at link time.
The -f-no-assume-compiled option has various limitations and inefficiencies. On the boards for the future is a cleaner way to achieve this same goal. On the GCJ mailing list (see the on-line Resources section) this option is referred to either as the binary compatibility ABI or -findirect-dispatch. This new ABI does everything -fno-assume-compiled does, but in a much more efficient and compatible way. Development is underway and is coming along nicely on this new feature, one of several contributing to GCJ's enterprise readiness.
Once all this was in place, we finally were ready to make our changes to Eclipse. These turned out to be remarkably small. Most of the work involved making the same sort of change in three different places. In essence, we modified Eclipse so that when it's looking for a plugin's jar file, it also looks for a similarly named shared library installed alongside it. If there is one, we rewrite the URL passed to the class loader from a jar URL to a gcjlib URL. All rewriting is done conditionally, so our natively compiled Eclipse still works with an unmodified JVM. In other words, users are not locked in to native compilation if they would rather use a JVM instead.
Once that was done, we wrote our own launcher that understood how to bootstrap the Eclipse platform from shared libraries. This was accomplished in a modest 90 lines of code.
After all that, Eclipse was mysteriously slow. Had we done something wrong? Was GCJ-compiled code substantially worse than the code generated on the fly by the current crop of just-in-time (JIT) compilers? Did -fno-assume-compiled have enormous overhead?
One nice advantage of GCJ is its output generally can be treated in the same way one treats any object code. That is, existing tools such as OProfile can be applied to it directly without any change. And that, in fact, is how we investigated our performance problem.
The first thing we noticed was a large number of exceptions being thrown during platform startup. Amid the grumblings of compiler writers (exceptions should be for exceptional circumstances), and although we were considering changes to the GCJ runtime that would violate Java semantics, we noticed a strange symbol in the OProfile output. It turned out that a small bit of buggy assembly code deep in the libgcj runtime was causing a linear search of exception handling tables rather than the expected binary search. The overhead of this search through the entire program every time an exception was thrown was vast. A fix to the errant assembly code proved this was the problem, and suddenly our natively compiled Eclipse was able to start a second faster than the stock version using a JVM. To quantify it a bit further, the startup time dropped from more than a minute before the fix to less than 15 seconds after it.
Currently, we don't compile Eclipse directly from source to object code. Instead, we compile to bytecode and then compile the jar files to shared libraries. This is done for two reasons. First, a few bugs in the GCJ source compiler haven't been fixed. Second, Eclipse comes with its own build scripts that compile from source to bytecode. Reworking the Eclipse build system to allow building directly from source to binary seemed like a much larger divergence from the upstream sources than we were willing to maintain.
Also, we currently don't precompile all the jar files to shared libraries—some remain as jar files and are interpreted at runtime. This is done because the class libraries still are incomplete, and these jar files refer to classes that have not been implemented yet.
One of our patches is unsuitable for the public GCJ. We had to disable the compile-time bytecode verifier, as it was too buggy to compile some of the Eclipse jar files. We're in the process of replacing this verifier with a more robust one.
In addition, one limitation of natively compiled Eclipse deserves mention. You can't use natively compiled Eclipse to debug a GCJ-compiled application, because JDWP, the Java Debug Wire Protocol used by Eclipse, hasn't been implemented in libgcj yet.
The achievement of the native compilation of Eclipse is a strong indication that open-source Java based on GCJ and libgcj/classpath has reached the point of being commercially useful. That said, it's still not complete. Some fairly substantial gaps still need to be filled in before open-source Java can be a proper drop-in substitute for proprietary JVMs.
One of the major areas that needs work is the development/integration of a JIT compiler. JIT would allow a GCJ-based open-source Java environment to be used in a manner similar to a conventional JVM, meaning that native compilation and platform-specific binaries would not be necessary for performance reasons.
The other major piece that needs work also is, by far, the most visible missing piece—Swing. Work on an open-source implementation of Swing is coming along nicely as part of the GNU Classpath Project, but Swing is a huge undertaking and the GNU Classpath implementation is still not quite usable.
A full-featured and completely open-source Java environment is an attractive alternative to proprietary JVMs, and it's now within reach. During the past six months, Red Hat has more than doubled the number of engineers working in support of the Open Source Java solution and community. Eclipse is a large, complicated piece of software, and natively compiling and running it was an excellent test of and testament to the progress being made on open-source Java. The power of open source lies in its communities, so please consider joining the open-source Java community and contributing to the GCJ and GNU Classpath Projects in any way that interests you.
Resources for this article: /article/7549.
Special Magazine Offer -- Free Gift with Subscription
Receive a free digital copy of Linux Journal's System Administration Special Edition as well as instant online access to current and past issues. CLICK HERE for offer
Linux Journal: delivering readers the advice and inspiration they need to get the most out of their Linux systems since 1994.
Subscribe now!
The Latest
Newsletter
Tech Tip Videos
- Nov-04-09
- Oct-29-09
- Oct-26-09
Recently Popular
From the Magazine
December 2009, #188
If last month's Infrastrucuture issue was too "big" for you then try on this month's Embedded issue. Find out how to use Player for programming mobile robots, build a humidity controller for your root cellar, find out how to reduce the boot time of your embedded system, and if you're new to embedded systems find out the basics that go into one. You can also read about the Beagle Board, the Mesh Potato and a spate of other interestingly named items. And along with our regular columns don't miss our new monthly column: Economy Size Geek.
Delicious
Digg
StumbleUpon
Reddit
Facebook








Ill stick to my linux box
On June 20th, 2007 Charles (not verified) says:
Ill stick to my linux box thanks
Re: Eclipse Goes Native -- Eclipse went native in Dec 2003
On July 27th, 2004 Anonymous says:
Sweeping out the custom classloaders from source code is bad idea. Eclipse evolves rapidly so you have to introduce these patches into each new release not to mention weekly integration builds if you wanna try them. It nails the compiled Eclipse down to a particular fixed version.
Even more problems exist for server-side apps. Imagine you use an application server (free, open source, etc.) on which you deploy your web app and want to compile it to native code. The EJB mechanism employed by any J2EE app servers *heavily* relies on custom classloading (and class reloading, BTW). Would you like to patch the app server souce code to get your app working after native compilation?
Check, for instance, JBoss and you get convinced that the custom classloaders are used everywhere around the JBoss' code. A solution would be appropriate handling custom classloaders not patching the source.
-----------
One of possible ways around the custom clasloading problem for static compiler is used in a proprietary JVM (Excelsior JET available for both Windows and Linux). They have a static Java compiler and caching Just-In-Time compiler which saves the results of dynamic compilation. The innovative point is that the JIT cache can be later optimized by the static compiler! I think that a similar technique has to be implemented in GCJ as well to really harness the advantages of native Java compilation.
Guess what's the app on which they illustrated such an approach? Right, that's Eclipse platform "AS IS" (without code patching). See
http://www.excelsior-usa.com/kb/000010.html
for details. BTW, this article is dated back to Dec 2003. Nothing is new in this world. ;)
Re: Eclipse Goes Native
On July 22nd, 2004 Anonymous says:
What about a Fedora Core 2 port?
The FC2 tree seems to already contain native ports of many java tools, it seems most of the work is done and yet no native eclipse for Fedora!
Are there any announced plans for that?
Best Regards,
rkpr
Re: Eclipse Goes Native
On July 6th, 2004 Anonymous says:
Agreed with the last poster. The important thing is that it has been freed...as in freedom...from a proprietary piece of software.
Perhaps more examples like this will get Sun off of its duff so that they GPL their Java implementation. Note that this strategy worked pretty darned well for getting Troll Tech to GPL the Qt library; in that case, it was the GNOME dev team with Harmony.
For those who want to dog Red Hat for making a buck selling Free Software, that same buck is what funds efforts like this, which is a contribution back to the entire community. I thank them for being around and for doing what they do, as long as they keep doing stuff like this.
Re: Eclipse Goes Native
On January 29th, 2006 John Raller (not verified) says:
Well - didn't I read in the las week that Sun is going GNU with this piece of software?
Re: Eclipse Goes Native
On January 29th, 2006 Cindy Banter (not verified) says:
Hi John, thats wrong - I think. Eclipse is not GNU.
Re: Eclipse Goes Native
On January 29th, 2006 John Raller (not verified) says:
Oh, thanks a lot. I think that was my mistake then 8-)
Re: Eclipse Goes Native
On July 16th, 2004 Anonymous says:
This may be naive but sense when do you have to pay for a JVM? And what isn't free about Sun's JVM? Please enlighten me.
Re: Eclipse Goes Native
On August 2nd, 2004 Anonymous says:
Sun's JVM is not Free Software (http://www.gnu.org), even if it costs nothing. It doesn't come with a source and you can't modify it and distribute your modifications.
"Sun's JVM is not Free
On June 15th, 2007 Green Laser Pointer (not verified) says:
"Sun's JVM is not Free Software (http://www.gnu.org), even if it costs nothing. It doesn't come with a source and you can't modify it and distribute your modifications."
Agreed, alot of people make this assumption without realizing the importance of obtaining source (hi open source!)
~Doug
It's about freedom!
On July 1st, 2004 Anonymous says:
A lot of the comment here seem to be missing the point: "[RH] has FREED [Eclipse] from its ties to a PROPRIETARY [JVM]!" Frankly, I'm excited by this - it means I may finally get to try Eclipse! I've been hearing great things about it, but the requirement to install Sun's non-free, unsupported (at least by my vendor) software to get it to run has just been more of a hassle than I've been willing to undergo. I'd have been just as happy if they'd gotten it to run with kaffee (which my vendor also supports), but from what I hear, gjc is more advanced, so the approach RH took here doesn't suprise me.
Another quote from the article: "A full-featured and completely open-source Java environment is an attractive alternative to proprietary JVMs, and it's now within reach." To which I can only say, amen!
I suspect this will also be popular with the Gentoo, "I want everything optimized for *my* machine," crowd.
Re: Eclipse Goes Native
On June 25th, 2004 Anonymous says:
All this work just to find out that throwing exceptions is expensive?
Where are the real results? Improving the startup time is nice, but I only start my IDE about once a week.
Re: Eclipse Goes Native
On June 25th, 2004 Anonymous says:
The real results are the improvements made to gcj and libgcj.
Compiling eclipse is a major challenge, and the fact that it now works is testament to how far the gcj project has come.
And that is a very important result, IMHO, since having a full free software implementation of Java, with the added bonus of native compilation for multiple platforms would mean quite a lot for the acceptance of Java in the Linux and Free Software communities, which have long been quite wary of Java.
> The real results are the improvements made to gcj and libgcj.
On January 27th, 2006 Barney (not verified) says:
Yes, but will these improvements be seen outside of Redhat? These are gcc projects, and the Free Software Foundation generally says that for large contributions they want either copyright assinged to the FSF, or the code to be put in the public domain, although not for small changes, presumably so that they can re-licence the code in future under GPL v.3, or something else.
I imagine Redhat would be reluctant to either assign its work to the fsf or to make it public domain.
Seems a shame that the fsf is rigid about this issue. Isn't that what split Emacs in two? (no flame war intended.)
Re: Eclipse Goes Native
On June 25th, 2004 Anonymous says:
For swing maybe they should use SwingWT ? (a swing implementation based on SWT)
Re: Eclipse Goes Native
On June 25th, 2004 Anonymous says:
Eclipse already uses SWT, they invented the whole SWT thing...
Re: Eclipse Goes Native
On June 27th, 2004 Anonymous says:
Either you can't read or you're very, very stupid, or both.
Re: Eclipse Goes Native
On October 19th, 2004 Anonymous says:
Either you can't read or you're very, very stupid, or both.I'd say *you're* the stupid one for suggesting SWT on Swing. The whole design of SWT is philosophically different than Swing, the designers of Eclipse wrote SWT simply because they couldn't get by with the poor performance and non-native look and feel of Swing. Read up.
Poor performance?
On September 6th, 2005 Anonymous (not verified) says:
Both of which are complete non-issues today
Re: Eclipse Goes Native
On June 25th, 2004 Anonymous says:
NEWS FLASH! Man compiles program! Story at Eleven.
Zzzzzz. Wake me when there's some real news.
Re: Eclipse Goes Native
On June 13th, 2004 Anonymous says:
Hi from Joe in Edmonton joejoseph00@hotmail.com
I read your article on Eclipse java byte-code being compiled into native code. Isn't that what the JVM does on the fly already? Is this to speed up startup times? Why would a compiled Eclipse run any faster than a JVM Eclipse aside from startup time?
In Microsoft.NET the .NET environment plugs into non-virtual machine api's such as the proprietary platform dependant unmanaged win32 api.
With processing speeds astronomically fast these days isn't platform independance worth the performance hit? I mean, when I first ran SunONE on my Athlon 550 mhz, it was a bit slow, but after running it on my AthlonXP 1800+ it became lightning fast instantly. And now with a 64-bit JVM on the horizon, programming time becomes a lot more costly than the cost of a new 3800+ Athlon64 :)
Yes yes, I do see the point of your efforts with Eclipse, I might have to try that some day, hearing lots of good things about it. I am thrilled with SunONE though, it is super cool. Once I figure out CVS versioning control over WAN that will be cool.
Joe (joe@k9k.net if you're not on the spammer blacklist you might be able to send me an e-mail) or joejoseph00@hotmail.com
Re: Eclipse Goes Native
On June 15th, 2004 Anonymous says:
Some VMs, known as JIT (Just in time compilers) do compile some of the code into native machine code on running. Usually, what the JIT does is figure out which parts need to run fast, and compiles those.
That process takes some time, and JIT VMs usually are a bit slower starting up than ordinary VMs.
Anyway, a completely native binary will always be significantly faster than any VM.
Whenether platform independence is worth the performance hit is obviously a judgement call on the programmers part. Note the idea is that for most programs, you don't need to sacrifice the platform-independence of the source code to be able to compile it to native. As noted in the article, it's if you use classloaders you have to be careful. Given that it is already quite possible to write nonportable programs in Java, I personally don't see that as a major problem.
Or why not distribute your software as both bytecode and as well as native for the supported platforms? Best of both worlds. It's nice to have that option.
It's also worth noting that GCJ can also compile to java bytecode and work as an ordinary VM if you want that.
Re: Eclipse Goes Native
On July 25th, 2004 Anonymous says:
I have done some tests for java programs compiled by gcj (native) versus running them on JDK 1.4.2, and the latter was almost always faster. It has been claimed often that a JIT can do a better job in principle (since it knows the dynamic access path of the code and thus knows what optimisation variant to choose), and I have found that it also does a better job in reality.
I think this native eclipse is a very very bad idea. It probably won't perform much better (rather worse) and binds the release to a specific platform (incl. specific versions of libraries etc).
Re: Eclipse Goes Native
On July 27th, 2004 Anonymous says:
You have compared old GNU C-based native compiler with the modern HotSpot dynamic compiler. It does not relate to comparison of static vs. dynamic compilation approaches.
HotSpot compiler employs the state-of-the-art SSA (Static Single Assignment) form to highly optimize code. As for GNU compilers, the work has started only recently by Kenneth Zadeck
http://www.naturalbridge.com/
His one of the first implementors of SSA for IBM compilers (Hi Kenny!).
No doubts, Kenny is the right person to do this in the GNU compiler family (wish good luck to him) but right now GCJ is far away from the state-of-the-art of the compiler construction technology.
If you wanna compare dynamic vs. native Java compilers, check out Excelsior JET for Linux which employs many modern optimizations including SSA-based ones.
http://www.excelsior-usa.com/jetlatest.html
If you do not use proprietary JVMs, this solution is not for you. However, it shows the strength of native Java compilers that can be potentially achieved by GCJ at some point in the future.
Re: Eclipse Goes Native
On June 26th, 2004 Anonymous says:
> Anyway, a completely native binary will always be significantly
> faster than any VM.
Not necessarily.
State-of-the-art JVMs contain JITs that create machine code that is tailored to the current execution. Not only do such systems choose which methods are important to optimize, but they also optimize those methods based on the paths/values being used during the current execution. An ahead-of-time compiler does not have this advantage. It typically assumes all paths through a method are equally likely.
Well, state-of-the-art ahead-
On December 10th, 2004 HRJ (not verified) says:
Well, state-of-the-art ahead-of-time compilers can also incorporate runtime profile information to generate optimal code.
gcc can do this (investigate
On June 2nd, 2005 Anonymous (not verified) says:
gcc can do this (investigate -fprofile-arcs). You build the program with profiling, run it for a while, and then rebuild it with the profile information which is then used to reprioritize code paths.
Re: Eclipse Goes Native
On June 11th, 2004 Anonymous says:
Can you compile AWT? Was compiling SWT a challenge?
Re: Eclipse Goes Native
On June 11th, 2004 Anonymous says:
You can compile AWT. Will it work? A little, but not enough for real programs.
AWT support is almost there though, and Swing is being worked on (Swing being heavily AWT dependent).
There is a gui-branch of gcj in which Swing and AWT is rapidly being developed, and Redhat is very active in this.
(Note: I'm not the author or a Redhat employee.. but big kudos to them for their contributions to gcj and indeed gcc)
Re: Eclipse Goes Native
On June 24th, 2004 Anonymous says:
You could use the SwingWT,
Re: Eclipse Goes Native
On June 11th, 2004 Anonymous says:
"Posted on Thursday, July 01, 2004"
yeah right... (june 11th)
Re: Eclipse Goes Native
On June 11th, 2004 Anonymous says:
Someone needs to read that article on NTP.. :-)
Re: Eclipse Goes Native
On June 11th, 2004 Anonymous says:
What is a performance of native ???
Post new comment