Jump to content

GNU Compiler for Java

From Wikipedia, the free encyclopedia
GNU Compiler for Java
DeveloperThe GNU Project
Initial releaseSeptember 6, 1998; 27 years ago (1998-09-06)[1]
Written inC, C++, Java
Operating systemUnix-like
PlatformGNU and many others
TypeCompiler
LicenseGNU GPL
Websitegcc.gnu.org

The GNU Compiler for Java (GCJ) is a discontinued free compiler for the Java programming language. It was part of the GNU Compiler Collection.[2][3]

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.[4][5]

History

[edit]

The GCJ runtime-libraries original source is from GNU Classpath project, but there is a code difference between the libgcj libraries. GCJ 4.3 uses the Eclipse Compiler for Java as a front-end.[6]

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. "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.".[7] 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 java.nio library were implemented).[8] GNU Classpath was never completed to even Java 1.2 status and now appears to have been abandoned completely.

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.[9] GCJ was removed from the GCC trunk on September 30, 2016.[10][11] Announcement of its removal was made with the release of the GCC 7.1, which does not contain it.[12] GCJ remains part of GCC 6.

Performance

[edit]

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.[13]

Compiled Native Interface (CNI)

[edit]

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++.[14] 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 extern "Java", 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.[15]

For example, consider the following Java code:

package org.wikipedia.examples;

public class Foo {
    public int add(int a, int b) {
        return a + b;
    }
}

Then, from C++ it can be consumed as so:

#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 {
        // ...
    };
}

}

An implementation of libjava (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[16], preserving namespace structure per Java package.[17]

All Java reference types X are translated to a pointer X* in C++. For example, java.lang.String becomes java::lang::String*.[18] Because Java classes are managed by the Java garbage collector, they should not be deleted using the delete operator from C++, even though they are both instantiated using new[19]; the Java objects are automatically deleted by the garbage collector.[20] 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.[21]

Java reflection on Java objects in C++ possible using CNI, featuring the jfieldID and jmethodID (as seen in JNI).[22] 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:[23]

Java type C/C++ alias Description
char jchar 16-bit Unicode character
boolean jboolean Boolean (logical true/false value)
byte jbyte 8-bit signed integer
short jshort 16-bit signed integer
int jint 32-bit signed integer
long jlong 64-bit signed integer
float jfloat 32-bit IEEE floating-point number
double jdouble 64-bit IEEE floating-point number

void 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.[23]

Java arrays are implemented with the class template JArray<T>, and inherit java::lang::Object (and implement operator[]). Additional typedefs for each pointer to array of Java primitives are provided.[24]

Additionally, common classes receive the following typedefs:[18]

Java type C/C++ alias Description
java.lang.Object jobject (for java::lang::Object*) Universal supertype of all reference types, representing an object
java.lang.String jstring (for java::lang::String*) String type
java.lang.Class jclass (for java::lang::Class*)[a] Runtime state and metadata of any reference type in Java

Additionally, all Java classes X expose a static field X::class$ in C++, which behaves equivalently to X.class in Java. However, the class$ field is of type java::lang::Class (not java::lang::Class*). The Java null was originally translated to the older C++ NULL (however the null pointer constant nullptr may be substituted due to implicit conversions).[25] Additional classes, gnu::gcj::RawData and gnu::gcj::RawDataManaged respectively denote non-scanned reference types (which will not be checked by the compiler and can store any C/C++ data structure), and data which may be marked by the memory manager and be garbage-collected.[26]

In C++, java::lang::String* (or jstring) must be created manually using CNI utility functions (analogous to those of JNI); they cannot be implicitly converted from const char* or C++ std::string.[27]

The Java synchronized blocks are implemented in C++ using the ::JvSynchronize class.[28] For example, the following is equivalent to Java synchronized (obj) { /* code... */ }

{
    JvSynchronize _(obj); // create dummy lock, destroyed upon scope end
    // code...
}

In C++, any class which enforces the Java inheritance model must inherit the java::lang::Object 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.[29] Despite this, an attribute [[gnu::java_interface]] existed to mark a class as a Java interface, along with a pragma #pragma interface.[15] Methods of interfaces, however, could be implemented, but calling a method of a superinterface required casting the class back to the superinterface.[29] Additionally, Java access specifiers were never enforced strictly in C++; only private fields and methods from Java were properly mapped to private in C++, but everything else was mapped to public.[21]

Methods map directly between Java and C++ with the same names and corresponding types, and preserved static methods (still called using :: 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.[30]

Failed allocation of a Java class will throw a java::lang::OutOfMemoryError.[31]

libgcj use POSIX signals internally, and using the same signal may interfere with libgcj or even cause it to fail. For example, SIGSEGV generates a java::lang::NullPointerException, java::lang::Runtime::exec() makes use of SIGCHLD, while other signals (potentially platform-dependent) may be used by the memory manager or java::lang::Thread::interrupt().[26]

Comparison of language use

[edit]

The authors of CNI claim for various advantages over JNI:[32]

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.)

CNI depends on Java classes appearing as C++ classes. For example,[33] given a Java class,

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);
}

one can use the class thus:

#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);
}

GCJ allows the usage of Java exceptions in C++, but they cannot be used in the same translation unit with C++ exceptions.[34] The pragma #pragma GCC java_exceptions must be used to ensure destructors are called upon propagating a Java exception through C++.[35] Despite this, no support for finally blocks were ever included.[36]

For example, the following catches a Java exception, while using the Invocation API: [25]

#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;
}

See also

[edit]

Notes

[edit]
  1. ^ Note that as generics were never implemented in GCJ, Class did not have template parameters.

References

[edit]
  1. ^ Anthony Green, Cygnus Solutions. "GCJ announcement".
  2. ^ "GCJ: The GNU Compiler for Java - GNU Project - Free Software Foundation (FSF)". Archived from the original on 2007-05-09. Retrieved 2010-04-22.
  3. ^ Campbell, Bill (2013). Introduction to Compiler Construction in a Java World. CRC Press Taylor & Francis Group. ISBN 978-1-4398-6088-5. Retrieved 2014-02-06.
  4. ^ "Compiling Java with GCJ | Linux Journal".
  5. ^ "GNU Compiler for Java".
  6. ^ "gcj to use Eclipse compiler as a front end". 2007-01-08. Archived from the original on 2007-05-09. Retrieved 2007-05-20.
  7. ^ The GCJ FAQ
  8. ^ GCC Wiki (7 August 2017). "GCJ - GCC Wiki". gcc.gnu.org. GNU Project.
  9. ^ GCC Looks To Turn Off Java, Replace With Go Or ADA
  10. ^ Andrew Haley (September 30, 2016). "[gcc] Revision 240661".
  11. ^ Tromey, Tom (October 2, 2016). "The Deletion of gcj". The Cliffs of Inanity. Retrieved October 3, 2016.
  12. ^ "GCC 7 Release Series: Changes, New Features, and Fixes". Retrieved May 9, 2017.
  13. ^ "GCJ: The GNU Static Java Compiler" (PDF). Archived from the original (PDF) on 2011-06-07. Retrieved 2009-08-02.
  14. ^ Bothner, Per (January 2003). "Compiling Java with GCJ". Linux J. 2003 (105). Belltown Media: 4. ISSN 1075-3583.
  15. ^ a b GNU Project. "7.7 C++-Specific Variable, Function, and Type Attributes". gcc.gnu.org. GNU Project. Retrieved 19 May 2026.
  16. ^ GNU Project. "11.1 Basic concepts". gcc.gnu.org. GNU Project. Retrieved 22 May 2026.
  17. ^ GNU Project. "11.2 Packages". gcc.gnu.org. GNU Project. Retrieved 22 May 2026.
  18. ^ a b GNU Project. "11.4 Reference types". gcc.gnu.org. GNU Project. Retrieved 22 May 2026.
  19. ^ GNU Project. "11.7 Class Initialization". gcc.gnu.org. GNU Project. Retrieved 22 May 2026.
  20. ^ GNU Project. "11.8 Object allocation". gcc.gnu.org. GNU Project. Retrieved 22 May 2026.
  21. ^ a b GNU Project. "11.6 Objects and Classes". gcc.gnu.org. GNU Project. Retrieved 22 May 2026.
  22. ^ GNU Project. "11.17 Reflection". gcc.gnu.org. GNU Project. Retrieved 22 May 2026.
  23. ^ a b GNU Project. "11.3 Primitive types". gcc.gnu.org. GNU Project. Retrieved 22 May 2026.
  24. ^ GNU Project. "11.10 Arrays". gcc.gnu.org. GNU Project. Retrieved 22 May 2026.
  25. ^ a b GNU Project. "11.16 Invocation". gcc.gnu.org. GNU Project. Retrieved 22 May 2026.
  26. ^ a b GNU Project. "11.13 Interoperating with C/C++". gcc.gnu.org. GNU Project. Retrieved 22 May 2026.
  27. ^ GNU Project. "11.12 Strings". gcc.gnu.org. GNU Project. Retrieved 22 May 2026.
  28. ^ GNU Project. "11.15 Synchronization". gcc.gnu.org. GNU Project. Retrieved 22 May 2026.
  29. ^ a b GNU Project. "11.5 Interfaces". gcc.gnu.org. GNU Project. Retrieved 22 May 2026.
  30. ^ GNU Project. "11.11 Methods". gcc.gnu.org. GNU Project. Retrieved 22 May 2026.
  31. ^ GNU Project. "11.9 Memory allocation". gcc.gnu.org. GNU Project. Retrieved 22 May 2026.
  32. ^ The GCJ FAQ – GNU Project – Free Software Foundation (FSF)
  33. ^ The example comes from: https://gcc.gnu.org/onlinedocs/gcj/Objects-and-Classes.html#Objects-and-Classes Archived 2016-10-20 at the Wayback Machine
  34. ^ GNU Project. "6.10 Java Exceptions". gcc.gnu.org. GNU Project. Retrieved 21 May 2026.
  35. ^ Tom Tromey (27 June 2011). "GNU gcj" (PDF). GNU Project.
  36. ^ Per Bothner; Tom Tromey (April 2001). "Java/C++ integration: Writing native Java methods in natural C++" (PDF). Proceedings of the First Java Virtual Machine Research and Technology Symposium. Monterey, California: USENIX.
[edit]