The GNU Compiler for Java (GCJ) is a discontinued free compiler for the Java programming language. It was part of the GNU Compiler Collection.
GCJ compiles Java source code to Java virtual machine (JVM) bytecode or to machine code for a number of CPU architectures. It could also compile class files and whole JARs that contain bytecode into machine code.
History
The GCJ runtime-libraries original source is from GNU Classpath project, but there is a code difference between the ' libraries. GCJ 4.3 uses the Eclipse Compiler for Java as a front-end.
In 2007, a lot of work was done to implement support for Java's two graphical APIs in GNU Classpath: AWT and Swing. Software support for AWT was incomplete.<!--Note, "Optional SWT support" also available for micro-libgcj (that is a subset - not maintained, not sure if this SWT support also applies to GCJ)--> "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.". By the time of its removal, GCC had support for up to version 1.4 of Java (and thus lacked support for most of the later features, such as generics, annotations, or JPMS modules; despite this, portions of the library were implemented). GNU Classpath was never completed to even Java 1.2 status and now appears to have been abandoned completely.
<!--Not sure if this non-development for years contradicts above "AWT is still in development" as that is not a compiler (but would appear in "News"?)-->As of 2015, there were no new developments announced from GCJ and the product was in maintenance mode, with open-source Java toolchain development mostly happening within OpenJDK. GCJ was removed from the GCC trunk on September 30, 2016. Announcement of its removal was made with the release of the GCC 7.1, which does not contain it. GCJ remains part of GCC 6.
Performance
The compilation function in GCJ should have a faster start-up time than the equivalent bytecode launched in a JVM when compiling Java code into machine code.
Compiled Native Interface (CNI)
The Compiled Native Interface (CNI), previously named "Cygnus Native Interface", is a software framework for the GCJ that allows Java code to call, and be called by, native applications (programs specific to a hardware and operating-system platform) and libraries written in C++. It could work with C++ up to C++17 (the latest version of C++ supported by GCC 6.5, the final version of GCJ).
CNI closely resembles the Java Native Interface (JNI) framework which comes as a standard with various Java virtual machines.
GCJ additionally supports a "Java linkage" with <syntaxhighlight lang="cpp" inline>extern "Java"</syntaxhighlight>, which is used when referencing Java code compiled by GCJ and used in C++ code to indicate that a symbol that is consumed originates from Java.
For example, consider the following Java code:
<syntaxhighlight lang="java">
package org.wikipedia.examples;
public class Foo {
public int add(int a, int b) {
return a + b;
}
}
</syntaxhighlight>
Then, from C++ it can be consumed as so:
<!--Please do not update the C++ code beyond C++17; the final version of GCC which supported GCJ was GCC 6.5, which supported up to C++17.-->
<syntaxhighlight lang="cpp">
- include <gcj/cni.h>
- include <java/lang/Object.h>
// Automatically generated header
- include <org/wikipedia/examples/Foo.h>
using namespace java::lang;
using org::wikipedia::examples::Foo;
extern "Java" {
int addThroughJava(int a, int b) {
Foo* foo = new Foo();
return foo->add(a, b);
// Note: foo should not be deleted, as it is garbage collected
}
namespace org::wikipedia::examples {
// Inheriting a Java object
// Only single inheritance supported
class Bar: public Object {
// ...
};
}
}
</syntaxhighlight>
An implementation of ' (which contains the C++ headers for the Java Class Library) may be found here (in a GCC 6 release). Java classes are exposed to C++ as (auto-generated) header files by one class per header, preserving namespace structure per Java package.
All Java reference types <code>X</code> are translated to a pointer <code>X*</code> in C++. For example, <code>java.lang.String</code> becomes <code>java::lang::String*</code>. Because Java classes are managed by the Java garbage collector, they should not be deleted using the <code>delete</code> operator from C++, even though they are both instantiated using <code>new</code>; the Java objects are automatically deleted by the garbage collector. Java classes, when used in C++, maintain the same field order and alignment, and will not widen 8-bit and 16-bit native types to 32 bits. While Java generics were never implemented by the time GCJ was removed, some discussions regarding how they would operate with C++ (for example, directly translating generics to templates or omitting them entirely, which the JVM does at runtime) had taken place.
Java primitives may map exactly to the corresponding C/C++ primitive. However, in the case where they do not (as C/C++ do not specify the exact width of integer types), typedefs are provided as the following:
{| class="wikitable"
|-
! Java type !! C/C++ alias !! Description
|-
| <code>char</code> || <code>jchar</code> || 16-bit Unicode character
|-
| <code>boolean</code> || <code>jboolean</code> || Boolean (logical true/false value)
|-
| <code>byte</code> || <code>jbyte</code> || 8-bit signed integer
|-
| <code>short</code> || <code>jshort</code> || 16-bit signed integer
|-
| <code>int</code> || <code>jint</code> || 32-bit signed integer
|-
| <code>long</code> || <code>jlong</code> || 64-bit signed integer
|-
| <code>float</code> || <code>jfloat</code> || 32-bit IEEE floating-point number
|-
| <code>double</code> || <code>jdouble</code> || 64-bit IEEE floating-point number
|}
<code>void</code> maps exactly the same between languages, as it does not refer to any value. It was recommended to use these Java typedefs over the native C++ types, to avoid possible errors.
Additionally, common classes receive the following typedefs:
In C++, <code>java::lang::String*</code> (or <code>jstring</code>) must be created manually using CNI utility functions (analogous to those of JNI); they cannot be implicitly converted from <code>const char*</code> or C++ <code>std::string</code>.
The Java <syntaxhighlight lang="java" inline>synchronized</syntaxhighlight> blocks are implemented in C++ using the <code>::JvSynchronize</code> class. For example, the following is equivalent to Java <syntaxhighlight lang="java" inline>synchronized (obj) { /* code... */ }</syntaxhighlight>
<syntaxhighlight lang="cpp">
{
JvSynchronize _(obj); // create dummy lock, destroyed upon scope end
// code...
}
</syntaxhighlight>
In C++, any class which enforces the Java inheritance model must inherit the <code>java::lang::Object</code> base class, and may inherit at most one base class. Although it was planned, interface inheritance awareness was never implemented in GCJ by the time of its removal. Despite this, an attribute <syntaxhighlight lang="cpp" inline>gnu::java_interface</syntaxhighlight> existed to mark a class as a Java interface, along with a pragma <syntaxhighlight lang="cpp" inline>#pragma interface</syntaxhighlight>.
Methods map directly between Java and C++ with the same names and corresponding types, and preserved static methods (still called using <code>::</code> for resolution). Name mangling for overloaded methods use the same encoding scheme between Java and C++. While Java does not allow a constructor to be a native method itself, a constructor may call a native method.
Failed allocation of a Java class will throw a <code>java::lang::OutOfMemoryError</code>.
' use POSIX signals internally, and using the same signal may interfere with ' or even cause it to fail. For example, <code>SIGSEGV</code> generates a <code>java::lang::NullPointerException</code>, <code>java::lang::Runtime::exec()</code> makes use of <code>SIGCHLD</code>, while other signals (potentially platform-dependent) may be used by the memory manager or <code>java::lang::Thread::interrupt()</code>.
CNI depends on Java classes appearing as C++ classes. For example,
given a Java class,
<syntaxhighlight lang="java">
package org.wikipedia.examples;
public class MyInteger {
private int i;
public MyInteger(int i) {
this.i = i;
}
public int get() {
return i;
}
public void set(int j) {
i = j;
}
public static final MyInteger ZERO = new MyInteger(0);
}
</syntaxhighlight>
one can use the class thus:
<syntaxhighlight lang="cpp">
- include <gcj/cni.h>
- include <org/wikipedia/examples/MyInteger.h>
using org::wikipedia::examples::MyInteger;
MyInteger* mult(MyInteger& p, jint k) {
if (k == 0) {
return MyInteger::ZERO; // Static member access.
}
return new MyInteger(p.get() * k);
}
</syntaxhighlight>
GCJ allows the usage of Java exceptions in C++, but they cannot be used in the same translation unit with C++ exceptions. The pragma <syntaxhighlight lang="cpp" inline>#pragma GCC java_exceptions</syntaxhighlight> must be used to ensure destructors are called upon propagating a Java exception through C++. Despite this, no support for <code>finally</code> blocks were ever included.
For example, the following catches a Java exception, while using the Invocation API:
<syntaxhighlight lang="cpp">
- pragma GCC java_exceptions
- include <gcj/cni.h>
- include <java/lang/Integer.h>
- include <java/lang/Math.h>
- include <java/lang/NumberFormatException.h>
- include <java/lang/String.h>
- include <java/lang/System.h>
- include <java/io/File.h>
- include <java/io/IOException.h>
- include <java/net/URI.h>
using namespace java::lang;
using java::io::File;
using java::io::IOException;
using java::net::URI;
int main(int argc, char* argv[]) {
try {
::JvCreateJavaVM(nullptr);
::JvAttachCurrentThread(nullptr, nullptr);
::JvInitClass(&System::class$);
::JvInitClass(&Math::class$);
JArray<String*>* args = ::JvConvertArgv(argc, argv); // String[] args
jdouble one = Math::sin(Math::PI / 2);
URI* location = new URI(::JvNewStringLatin1("file:///C:/temp/example.txt"));
File* file = new File(location);
System::out->println(file->getAbsolutePath());
String* invalid = ::JvNewStringLatin1("not a number");
jint result = Integer::parseInt(invalid);
} catch (NumberFormatException* e) {
System::err->println(::JvNewStringLatin1("Failed to format number: ")->concat(e->getMessage()));
e->printStackTrace();
} catch (IOException* e) {
System::err->println(::JvNewStringLatin1("Failed I/O operation: ")->concat(e->getMessage()));
e->printStackTrace();
}
return 0;
}
</syntaxhighlight>
See also
- Comparison of Java and C++
- Excelsior JET (Excelsior Java native code compiler)
- IcedTea
- Kaffe
- SableVM
- JamVM
- Apache Harmony
- Jikes
- GraalVM
- Java virtual machine
- Free Java implementations
- Kotlin/Native, which uses LLVM for AOT compilation
- C++/CX and C++/CLI, both modified C++ for interop with .NET
