The GCJ FAQ

  1. General Questions
    1. What license is used for libgcj?
    2. How can I debug my Java program?
    3. Can I interface byte-compiled and native java code?
  2. Java Feature Support
    1. What Java API's are supported? How complete is the support?
    2. Does GCJ support using straight C native methods ala JNI?
    3. Why does GCJ use CNI?
    4. What is the state of AWT support?
    5. How about support for Swing ?
    6. What support is there for RMI ?
    7. Can I use any code from other projects to supplement libgcj's current features?
    8. What features of the Java language are/arn't supported
  3. Gcj Compile/Link Questions
    1. Why do I get undefined reference to `main' errors?
    2. Can GCJ only handle source code?
    3. "gcj -C" Doesn't seem to work like javac/jikes. Whats going on?
    4. Where does GCJ look for files?
    5. How does gcj resolve wether to compile .class or .java files?
  4. Runtime Questions
    1. My program is dumping core! What's going on?
    2. When I run the debugger I get a SEGV in the GC! What's going on?
    3. I have just compiled and benchmarked my Java application and it seems to be running slower than than XXX JIT JVM. Is there anything I can do to make it go faster?
    4. Can I profile Garbage Collection?
    5. How do I increase the runtime's initial and maximum heap sizes?
    6. How can I profile my application?
  5. Programming Issues
    1. Are there any examples of how to use CNI?
    2. Is it possible to invoke GCJ compiled Java code from a C++ application?

General Questions

1.1 What license is used for libgcj?

libgcj is distributed under the GPL, with the 'libgcc exception'. This means that linking with libgcj does not by itself cause your program to fall under the GPL. See LIBGCJ_LICENSE in the source tree for more details.

1.6 How can I debug my Java program?

gdb 5.0 includes support for debugging gcj-compiled Java programs. For more information please read Java Debugging with gdb.

1.7 Can I interface byte-compiled and native java code

libgcj has a bytecode interpreter that allows you to mix .class files with compiled code. It works pretty transparently: if a compiled version of a class is not found in the application binary or linked shared libraries, the class loader will search for a bytecode version in your classpath, much like a VM would. Be sure to build libgcj with the --enable-interpreter option to enable this functionality.

The program "gij" provides a front end to the interpreter that behaves much like a traditional virtual machine. You can even use "gij" to run a shared library which is compiled from java code and contains a main method:

$ gcj -shared -o lib-HelloWorld.so HelloWorld.java
$ gij HelloWorld
          
This works because gij uses Class.forName, which knows how to load shared objects.

Java Feature Support

2.1 What Java API's are supported? How complete is the support?

Matt Welsh writes:

Just look in the 'libjava' directory of libgcj and see what classes are there. Most GUI stuff isn't there yet, that's true, but many of the other classes are easy to add if they don't yet exist.

I think it's important to stress that there is a big difference between Java and the many libraries which Java supports. Unfortunately, Sun's promise of "write once, run everywhere" assumes much more than a JVM: you also need the full set of JDK libraries. Considering that new Java APIs come out every week, it's going to be impossible to track everything.

To make things worse, you can't simply run Sun's JDK classes on any old JVM -- they assume that a bunch of native methods are also defined. Since this native method requirement isn't defined by the JDK specs, you're effectively constrained to using Sun's JVMs if you want to use Sun's JDK libraries. Oh yes -- you could also reimplement all of those native methods yourself, and make sure they behave exactly as Sun's do. Note that they're undocumented!


2.2 Does GCJ support using straight C native methods ala JNI?

Yes. libgcj now has experimental support for JNI, in addition to its native Compiled Native Interface (CNI). gcjh will generate JNI stubs and headers using the "-jni" option. However, we do prefer CNI: it is more efficient, easier to write, and (at least potentially) easier to debug.

2.3 Why does GCJ use CNI?

Per Bothner explains:

We use CNI because we think it is a better solution, especially for a Java implementation that is based on the idea that Java is just another programming language that can be implemented using standard compilation techniques. Given that, and the idea that languages implemented using Gcc should be compatible where it makes sense, it follows that the Java calling convention should be as similar as practical to that used for other languages, especially C++, since we can think of Java as a subset of C++. CNI is just a set of helper functions and conventions built on the idea that C++ and Java have the *same* calling convention and object layout; they are binary compatible. (This is a simplification, but close enough.)


2.4 What is the state of AWT support?

Work is in progress to implement AWT and Java2D. We intend to support both GTK and xlib peers written using CNI. Some components are already working atop the xlib peers.

2.5 How about support for Swing?

Once AWT support is working then Swing support can be considered. There is at least one free-software partial implementations of Swing that may be usable.

2.6 What support is there for RMI?

RMI code exists on the CVS trunk (aka gcc 3.1), but it has not been heavily tested. This code was donated by Transvirtual Technologies.

2.7 Can I use any code from other projects to supplement libgcj's current features?

Certainly, provided the licenses are compatible. However, in many cases, if you wanted to contribute the code back into the official libgcj distribution, we would require that the original author(s) assign copyright to the Free Software Foundation.

As of March 6, 2000, libgcj has been relicenced, and copyright has been assigned to the FSF. This allows us to share and merge much of the libgcj codebase with the Classpath project. Our eventual goal is for Classpath to be an upstream source provider for libgcj, however it will be some time before this becomes reality: libgcj and Classpath have different implementations of many core java classes. In order to merge them, we need to select the best (most efficient, cleanest) implementation of each method/class/package, resolve any conflicts created by the merge, and test the final result. Needless to say, this is a lot of work. If you can help out, please let us know!


2.8 What features of the Java language are/aren't supported.

GCJ supports all Java language constructs as per the Java language specification.

Gcj Compile/Link Questions

4.1 Why do I get undefined reference to `main' errors?

When using gcj to link a Java program, you must use the --main= option to indicate the class that has the desired main method. This is because every Java class can have a main method, thus you have to tell gcj which one to use.

4.2 Can GCJ only handle source code?

GCJ will compile both source (.java) and bytecode (.class) files. However, in many cases the native code produced by compiling from source is better optimized than that compiled from .class files.

Per Bothner explains:

The reason is that when you compile to bytecode you lose a lot of information about program structure etc. That information helps in generating better code. We can in theory recover the information we need by analysing the structure of the bytecodes, but it is sometimes difficult - or sometimes it just that no-one has gotten around to it.

Specific examples include loop structure (gcc generates better code with explicit loops rather than with the equivalent spaghetti code), array initializers, and the JDK 1.1 `CLASS.class' syntax, all of which are represented using more low-level constructs in bytecode.


4.3 "gcj -C" Doesn't seem to work like javac/jikes. Whats going on?

The behavior of "gcj -C" is not at all like javac or jikes, which will compile (not just scan) all .java's which are out of date with regard to their .class's.


4.4 Where does GCJ look for files?

GCJ looks for classes to compile based on the CLASSPATH environment variable. libgcj.jar and other files are found relative to the path of the compiler itself, so it is safe to move the entire compiler tree to a different path, and there is no need to include libgcj.jar in your CLASSPATH.


4.5 How does gcj resolve whether to compile .class or .java files?

GCJ compiles only the files presented to it on the command line. However, it also needs to scan other files in order to determine the layout of other classes and check for errors in your code. For these dependencies, GCJ will favour .class files if they are available because it is faster to parse a class file than source code.

Runtime Questions

5.1 My program is dumping core! What's going on?

It could be any number of things. One common mistake is having your CLASSPATH environment variable pointing at a third party's java.lang and friends. Either unset CLASSPATH, or make sure it does not refer to core libraries other than those found in libgcj.jar.Note that newwer versions of GCJ will reject the core class library if it wasn't generated by GCJ itself.

5.2 When I run the debugger I get a SEGV in the GC! What's going on?

This is "normal"; the Garbage Collector (GC) uses it to determine stack boundaries. It is ordinarily caught and handled by the GC -- you can see this in the debugger by using cont to continue to the "real" segv.

5.3 I have just compiled and benchmarked my Java application and it seems to be running slower than than XXX JIT JVM. Is there anything I can do to make it go faster?

A few things:
  • If your programs allocate many small, short lived objects, the heap could be filling and triggering GC too regularly. Try increasing the initial and maximum heap sizes as per 5.5 How do I increase the runtime's initial and maximum heap size?
  • RE - array accesses. We have sub-optimal runtime checking code, and the compiler is still not so smart about automatically removing array checks. If your code is ready, and it doesn't rely on them, try compiling with --no-bounds-check.
  • Try static linking. On many platforms, dynamic (PIC) function calls are more expensive than static ones. In particular, the interaction with boehm-gc seems to incur extra overhead when shared libraries are used.
  • If your Java application doesn't need threads, try building libgcj using --enable-threads=none. Portions of the libgcj runtime are still more efficient when single-threaded.

5.4 Can I profile Garbage Collection?

It is possible to turn on verbose GC output by suppressing the -DSILENT flag during build. One way to do this is to comment out the line with #define SILENT 1 from boehm-gc/configure before configuring libgcj.

The GC will print collection statistics to stdout. (Rebuilding boehm-gc alone without this flag doesn't seem to work.)


5.5 How do I increase the runtime's initial and maximum heap sizes?

Some programs that allocate many small, short-lived objects can cause the default-sized heap to fill quickly and GC often. With the 2.95.1 release there is no means to adjust the heap at runtime. Recent snapshots provide the -ms and -mx arguments to gij to specify the initial and maximum heap sizes, respectively.


5.6 How can I profile my application?

Currently, only single threaded Java code may be used by the profiler (gprof). POSIX threads seem to be incompatible with the gmon stuff.

A couple of other tools that have been mentioned on the GCJ mailing list are sprof and cprof. The former is part of GNU libc.

Programming Issues

6.1 Are there any examples of how to use CNI?

Glenn Chambers has created a couple of trivial examples for version 2.95 and version 3.0. As a comparison, here is the same example as a JNI application using Kaffe. The same code will work with GCJ, as shown here.

Note that for version 2.95, you must compile the C++ files used for CNI with the -fno-rtti option. This constraint does not apply in version 3.0 and later.

The primary source of documentation for CNI is this paper.


6.2 Is it possible to invoke GCJ compiled Java code from a C++ application?

Yes, GCJ 3.1 supports a CNI-based invocation interface as well as the traditional JNI invocation API. See the GCJ Manual for more details on how to use the CNI interface.