An exotic flavor of coffee? A misspelling? Well, neither, actually. There’s no need to keep you guessing: Kaffe is a complete Java implementation. And to top it off, its source code is freely available via the Gnu Public License. But that’s just part of the story.
What does “complete” mean? Many people still think of Java as a language for Web-centric applications. That falls far short of its real meaning. Java is actually a whole, portable programming environment, providing services like file/network I/O, graphics, exception handling, memory management (with garbage collection), threading, persistency (by means of serialization), and much more. All these functions are wrapped up in portable abstractions, effectively moving the boundary of non-portable code out of the application and down into the Java implementation. As a consequence, each Java implementation resembles a kind of middleware operating system, consisting of at least three layers.
The central part of this picture is the JVM (Java Virtual Machine), but apart from performance enhancements, the focus has been shifted to the huge standard class libraries sitting on top of it.
How does Kaffe fit in? Of course, it includes a JVM, which has always had a JIT (Just in Time) compiler. It also has its own class libraries, including a Java-1.1-compatible AWT (Abstract Windowing Toolkit). The only part that is missing is a freely available Java bytecode compiler, but there are several javac alternatives to choose from (e.g., Jikes, Pizza or GJ).
Kaffe does not contain any third-party copyrights. It is a “cleanroom” implementation and was built from scratch.
Is it free or commercial?
Kaffe has been ported to more operating systems than any other form of Java.
“Free” is the not the right word — Kaffe is an Open Source project. The sources of its Desktop Edition are protected by the GPL (Gnu Public License), which basically means that nobody can use or modify the sources without publishing the modified sources under the GPL, as well. The Desktop Edition is targeted at various Unix-like platforms, most notably Linux. It is by no means a crippled or limited “light” version and comes with both the JIT and the AWT library.
There is also a commercial Kaffe version. Transvirtual Technologies Inc. provides the Custom Edition, based on the sources for which it holds the copyright. The two versions don’t differ much with respect to functionality, with the notable exception of the Custom Edition’s AWT, which does not require a native window system (like X or Win32). The Custom Edition has been ported to many non-Unix like operating systems (e.g., DOS, VxWorks, ThreadX, SMX, QNX, LynxOS), most of which find use in embedded systems such as set-top boxes or telecommunications equipment.
How do these versions coexist? The answer is: by means of separation and controlled flow.
Both versions have their own, separate CVS repositories. Most new components (like the new JIT) are still propagated from the Custom Edition into the Desktop, where they are exposed to a much larger user community. This unveils bugs and design flaws more rapidly. The flow back into the Custom Edition is not limited to patches; it also consists of useful input from mailing list discussions. No major contribution to the Desktop is incorporated into the Custom Edition without the permission of its author. There is no “pseudo-Open Source outsourcing” — it is a classical win-win situation.
But why do we need another “Java”?Well, that’s a bit of a misdirected question. Kaffe has been around since early 1996 (long before other JVMs had JITs, or tackled portability), and it still is the only Java implementation for a number of platforms. But there is more than just history. Besides the fact that the people involved in developing Kaffe started this project because they simply like to work on it (the fuel that drives Open Source), there are good technical reasons, as well.
An Open Source project like Kaffe has contributors all over the world.
Portability — Everyone talks about the portability of Java applications, but nobody cares for the portability of Java implementations. Nobody? Well, actually, Kaffe is very aware of this. All platform-specific parts are encapsulated by means of interfaces, in order to keep them from proliferating through the whole system. The sources are organized so that platform-specific things (headers) are kept strictly apart from the portable kernel (e.g., class management), to be linked in by means of an automake-based build process (using automated tests to deduce mandatory platform characteristics). The JVM and native libraries are written in portable C. The public Desktop Edition has recently been adapted to use the libtool package (in order to sort out linkage differences). And last but not least, the amount of source code is kept as small as possible. The complete source tree of the Custom Edition (including all supported platforms) is still less than 4 MB (with about 2 MB of C code and 1.5 MB of Java code).
As a consequence, Kaffe has been ported to more operating systems than any other form of Java (from Linux to DOS) and runs on a number of different architectures (including i386, Alpha, m68k, MIPS, StrongARM, and PowerPC). Not all ports have all features (e.g., JIT, AWT libraries) or are at the same level of maturity, or have GPLed sources. But a typical port usually takes less than three months to get fully functional, with the JIT and the AWT being the most challenging pieces. Of course, one can always start with the simple interpreter and a non-graphical system, and build from there.
Modularity — We have all learned that modular design is good “per se.” But there aren’t many systems that both qualify and benefit from such design the same way that a Java implementation does. Its OS-like functionality makes it natural to separate things like threading and memory management. Again, well-defined interfaces are the best way to approximate the ideal of “plug-in” JITs, garbage collectors, and other components. Of course, due to efficiency reasons, some interfaces don’t qualify for runtime or loadtime configuration, they need to be resolved at compile time (e.g., the thread/locking subsystem).
The effects of suitable modularization can’t be overestimated. If Java is going to be ubiquitous, there will be a huge variety of different platforms (set-top boxes, PDAs, desktops, servers) and applications (graphical, non-graphical, embedded, standalone). It does not make sense to serve all of them with the same components. A server might not need graphics, a set-top box application might not require filesystem I/O, and a multiprocessor system cannot benefit from non-kernel threads. “Scalability” is the magic word, and configurable modules are the road to success.
But there is more to it than that. An Open Source project like Kaffe has contributors all over the world. If this were a “monolithic” system, the effort to synchronize work would be difficult, tremendously boring, and would probably scare away most programmers who do this for fun. It seems to be a mandatory prerequisite for large Open Source projects to provide a sufficient level of modularization so that people can work independently of each other. In addition, being able to replace existing modules without touching the rest of the system is the best way to keep a complex system like Kaffe healthy (and up-to-date).
Besides these technical things, there are also a few significant legal reasons. Because Kaffe is not leashed by the Java trademark or license, people can publicly tweak their versions of Kaffe in directions that do not necessarily correspond to Sun’s Java specifications (e.g., by supporting other languages). Even if it is not a good idea to pollute the Java standard (after all, Java is a success because it provides these standards), it is useful for many research projects (like Guaraná), new languages (like Kiev), or system integration (Java didn’t start the fire — there are standards outside of Java, too).
The main modulesWe can’t delve too deeply into implementation details here. (That would turn this article into a book, which would probably be outdated by the time it got published.) But we certainly can identify the main modules and their future directions. If you aren’t interested in this techie snapshot, you might want to skip ahead to the next section.
The complete source tree for the Custom Edition is still less than 4 MB.
Execution enginesCurrently, there is a somewhat outdated JIT, a simple interpreter, and an AOT (Ahead of Time) compiler interface to the Cygnus-GCJ system. The JIT suffers from a simple translation scheme and superfluous register loads/spills. But it has a portable design (which is a great achievement for multiple architectures) and already offers speed improvements of a factor of 2-3 compared to fast interpreters.
Looking for utmost optimizations (peephole, common subexpressions, etc.) is certainly the wrong idea for a JIT, because it usually doesn’t make sense to spend a lot of time on the compilation of a method when it’s only executed once. Global register allocation and inlining can make good improvements and qualify for a solution to the underlying optimization problem. The new JIT, soon to be released in both Kaffe versions, will feature both of the aforementioned techniques.
The interpreter can be accelerated, too (by means of jump optimizations). But with the advent of high-performance JITs, it is becoming increasingly ignored. Given the role of Java in small, embedded systems, this is not really justified, because the difference in memory consumption and disk footprint between JITs and interpreters is even getting bigger.
Using native, precompiled, heavily optimized class libraries is another very interesting approach. While the exclusive use of completely AOT compiled libraries (native applications) seems to be too restrictive, coexisting AOT libraries (e.g., for standard classes) and JITed/interpreted (application) classes are not. In fact, this might be the choice to speed up loadtime and bottlenecks.
Memory managementKaffe’s heap management still has a non-incremental mark&sweep garbage collector. While the Desktop Edition recently introduced precise garbage collection (for reference fields), this is not yet the big overhaul, which is due during the second half of the year. Its main goals will be faster allocations and a much more incremental collection. This will also involve the introduction of write barriers.
Thread systemsThe most heavily used thread system of Kaffe is the jthreads module. It is a sophisticated, portable user-thread model that is specifically tailored to the needs of Java and supports asynchronous I/O (by means of SIGIO). There are several different kernel-thread implementations in the Custom Edition and a not-yet-finished pthreads system in the Desktop Edition.
The AWT does not require any public or proprietary native toolkit.
Of course, user threads are no choice for multiprocessor systems, and are less efficient for heavy I/O (i.e., for servers). But they come with a silver lining for all other applications — lock efficiency. The lock interface (e.g., for synchronized blocks and explicit waits) is another hot spot of current Kaffe development. With large, multi-threaded libraries like Swing, it will become even more important.
Graphics support (AWT)With respect to 1.1 functionality, the AWT implementations are complete (and run Swing smoothly). All widgets (like Buttons, Lists, and TextAreas) are implemented in Java (as so-called lightweights).
There are some remaining minor compatibility issues, which are mainly caused by the different behavior of native widgets and lightweights (e.g., Panel vs. Container derived Components), but many of these problems are platform-specific and can be seen on other AWT implementations, too (which indicates a need to improve the AWT specification).
The main conceptual difference to look for when comparing Kaffe to other AWT implementations is the lack of peer functionality. The reason behind this is very simple: with the current native interface (implemented in Toolkit), the pure lightweight AWT shares the same Java classes for all supported platforms (just the native library “backend” needs to be exchanged). Peer implementations would just increase the number of objects/classes, or would even end up in hidden, platform-specific classes (in addition to platform-specific native libraries). This assumes a homogenous AWT (all objects are served by the same native library), but heterogeneous implementations are currently rather exotic (e.g., rendering windows on different displays from within the same Java process). Moreover, a native widget-based AWT is already in the works (there even is a GTK-based prototype), and it shows that the Peer-less design can be used there, too.
Otherwise, the lightweight approach often outperforms native toolkit-based implementations. It also uses fewer resources, eases ports, and is much better suited for adaptation to specific look-and-feel needs (with a fraction of the overhead involved in comparable Swing-based solutions).
The Desktop Edition AWT is based on plain Xlib and does not require any public or proprietary native toolkit library, like GTK or Motif.
The standalone AWT of the Custom Edition, which works on top of simple graphics libraries (providing only primitives like DrawLine, etc.), has been further factorized and can be easily adapted to new libraries (typically, less than 2000 lines of code). This turns it into a preferred choice for small systems with non-standard display.
Human resourcesWho are the driving forces behind Kaffe? People, not companies or organizations. These people represent very typical groups, having their own interests in Kaffe.
Tim Wilkinson is the first one to mention. He started the whole project in January 1996. Bored by a dinosaur project he had to work on in Stockholm, Sweden, he wrote and released the first version of Kaffe in less than a month. The name Kaffe is a reminiscence of that era (it’s Swedish for coffee). Tim founded Transvirtual in November 1997 and continues to do most of the core JVM work.
Ongoing performance improvements will bring Kaffe to the same level as proprietary, state-of-the-art JVMs.
Tim represents the group that is fully committed to Kaffe, building a business around it.
Godmar Back gets the credit for keeping the Desktop Edition and the community of developers that work on the project together. Besides maintaining the www.kaffe.org Web site, he does quite a bit of development and integration work in the JVM area (namely, the thread systems). Godmar is also involved in the KaffeOS project.
Alexandre Oliva uses Kaffe as the basis for his Guaraná research project. He improved the build process, by means of the Libtool package.
Both Godmar and Alexandre are from the academic research community, where Kaffe has always been popular, because of its availability of sources (and the right to modify them).
Archie Cobbs of Whistle Inc. did a lot of work on the libraries and related JVM parts. He joined the team because Whistle considers Kaffe to be useful for their products, which shows that there can be commercial prospects in the GPLed Desktop Edition, too.
Of course, there are many more. Daniel Veillard of W3, managing the mailing lists. Eduard Parmelan, constantly improving the libraries. Kiyo Inaba, sorting out various porting problems. There are simply too many for this article, who would deserve to be mentioned. Browse the mailing list archive, and you will find all of them. This is less surprising when you take into account the fact that Kaffe is included in every Open Source Linux distribution and has been around for four years.
Step into the futureThis leaves us with the question of Kaffe’s future. Two facts seem to be obvious: (1) Kaffe already has a significant level of maturity, and (2) there already is enough “critical mass” in its developer community to keep it vivid, even when facing new Open Source Java projects like Japhar, ElectricalFire or Classpath. With its Custom Edition, Kaffe has also found a commercial niche, not threatened by one of the larger players (who can’t provide Kaffe’s portability and scalability, even with quite a bit more manpower).
Moreover, the ongoing performance improvements will bring Kaffe to the same level as proprietary, state-of-the-art JITed JVMs. With the expected tremendous growth of the embedded systems market and the ever-increasing role of Java as a general application platform, the future is wide open. And Kaffe already has its share of success in that game.
About the author
Peter Mehlitz is co-founder of Transvirtual Technologies. He designed and implemented the AWT libraries of Kaffe. Prior to that, he worked as a technical lead for BISS GmbH, developing systems like the BSA C++-framework, the CThrough development environment, and the BISS-AWT Java libraries. Peter has about 20 years of experience in software development, using about a dozen different programming languages, with a strong focus on design issues and large, object-oriented frameworks (written in C++, Smalltalk, and Java). He holds an M.S. in aerospace engineering from the university of the German armed forces, Munich.