Trebuchet Transcompiler is a Java to C++ source code translator
Java C++ CMake
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
src
.gitignore
CMakeLists.txt
LICENSE
README.md
pom.xml
trebuchet.cpp
trebuchet.h
universe.cpp
universe.h

README.md

Trebuchet Transcompiler

Trebuchet is a Java to C++ source code translator.

ZOMG WHY WOULD YOU DO THAT??

For the most part there is no good reason not to run a Java program on a Java Virtual Machine or Android Device. Modern JVMs provide many benefits and are really really fast.

But sometimes there is a situation where you might want to statically compile your Java program or some parts of it.

  • #1589F0 Cross-platform development such as targeting both Android and iOS.
  • #1589F0 Porting Java based games to consoles or platforms which rely heavily on native APIs.
  • #1589F0 Sharing data models and code from your Java server application with non-java devices.
  • #1589F0 Moving strategic Java classes to the native side of JNI libraries.
  • #1589F0 Targeting embedded platforms such as 32 bit microcontollers.
  • #1589F0 Utilities that make sense distributed as a small native executables.
  • #1589F0 Porting Java code to real-time environments. Code does not not magically become real time but the C++ equivelant of Java can be given clearer fixed time constraints.
  • #1589F0 Trebuchet can be used as a basis for the experiemenation with new memory models and compiler teqniques.

Pop the code into Trebuchet and pull the handle.

Language transcoders often include a support library to implement language features, garbage collection etc. Our approach is to have supply the leanest possible support code but then allow optional extensions for mode advanced features. This should assist when integrating generated code into various platforms. You may wish to integrate with your own platform's memory management.

Development Roadmap

Trebuchet uses the Spoon Java source code parser https://github.com/INRIA/spoon.

#33ff15 Implemented features. #1589F0 High Priority features. #ecd217 Lower priority features. #f03c15 Maybe never. Use a JVM?

  • #33ff15 Bean Parameter Assignment, Return Values, Constructors
  • #33ff15 Simple Arithmetic (some working cases)
  • #33ff15 Interfaces, Abstract methods, Inner Classes
  • #33ff15 Static Initializers, Class Field Initializers
  • #33ff15 Incrementing heap allocator with no garbage collection
  • #1589F0 The remaining flow control, assignment and math which is not yet implemented.
  • #1589F0 Non-C++ operators. eg. instanceof
  • #1589F0 Common java.lang.Object and java.lang.Class methods
  • #1589F0 Exceptions
  • #1589F0 Generics handling (not templates)
  • #ecd217 Synchronization, Volatile references, Threads
  • #ecd217 JNI Folding (removal of JNI stubs)
  • #ecd217 Alternate Memory Management
  • #ecd217 Custom Collections Implementations
  • #f03c15 Reflection, Bytecode Class Loading
  • #f03c15 Extensive API support (AWT etc.)

Optimisations

Modern C++ compilers can produce some amazing optimisations. We will rely on this to do most of the heavy lifting. Yet there are some quick wins we can apply in the translation process. Examples..

  • #1589F0 As all Java methods are virtual, demoting virtual methods to non-virtual where no inheritance or cast occurs.
  • #1589F0 Do not generate java.lang.Class definitions where the class's definition is never referenced.
  • #1589F0 Do not extend java.lang.Object (which introduces the overhead of a vtable to all object instances) where never referenced.
  • #1589F0 Demote heap allocated objects to local scope where reference doesn't escape scope.
  • #1589F0 Convert regular getters and setters to direct field access. (This would be something an optimising compiler does anyway so this might be more of a code style transformation.)
  • #1589F0 Disable index and type safety checks when logically safe to do so.
  • #1589F0 Use of different memory pools or memory managment by type.

Example Translation

Trebuchet will scan a source directory for Java source files, generating single CPP and Header files. Class re-ordering needs to occur to support C++'s forward declaration requirements for inheritated classes. The example source generates universe.cpp and universe.h. These can then be compiled with trebuchet.cpp which replaces the new operator and will provide support functions.

The following test case demonstrates a simple code structure featuring interfaces, abstract methods, Bean assignment and return values etc...

Java input

public class Spaceship {
    public static final int FIRSTSHIP = 100;
    private String name = "Nostromo";
    private int serialNumber = 120;
    private LongRangeScanner longRangeScanner;

    public Spaceship(LongRangeScanner longRangeScanner) {
        this.longRangeScanner = longRangeScanner;
    }

    public LongRangeScanner getLongRangeScanner() {
        return longRangeScanner;
    }

    public void reset(LongRangeScanner longRangeScanner, int serialNumber) {
        this.longRangeScanner = longRangeScanner;
        this.serialNumber = serialNumber;
    }
}

public abstract class Device {
    public void explode() {
    }

    public abstract int getDeviceId();
}

public class LongRangeScanner extends Device implements Scanner {
    private int range;

    public int getRange() {
        return this.range;
    }

    public void setRange(int range) {
        this.range = range;
    }

    public void scan() {
        range = range + 234;
        range = range - 123;
    }

    public int getDeviceId() {
        return 1337;
    }

    private class YourInnerScanner {
        private long someNumber;

        public YourInnerScanner() {
            this.someNumber = 10;
        }
        public void scanAhoy() {
            someNumber = someNumber + 2;
        }
    }

    private class MyInnerScanner {
        private long anotherNumber;

        MyInnerScanner() {
            this.anotherNumber = 20;
        }

        public void scanAhoy() {
            this.anotherNumber = this.anotherNumber + 4;
        }
    }
}

public interface Scanner {
    void scan();
}

C++ header output

/*** trebuchet.equipment.Scanner ***/
class Scanner {
public:
    virtual void scan() = 0;
};

/*** trebuchet.equipment.Device ***/
class Device {
public:
    Device();
    void explode();
    virtual int getDeviceId() = 0;
};

/*** trebuchet.equipment.LongRangeScanner ***/
class LongRangeScanner: public Device, public Scanner {
private:
    int range;

public:
    LongRangeScanner();
    int getRange();
    void setRange(int range);
    void scan();
    int getDeviceId();

    /*** trebuchet.equipment.LongRangeScanner$TachyonScanner ***/
    class MyInnerScanner {
    private:
        long long anotherNumber;

    public:
        MyInnerScanner();
        void scanAhoy();
    };

    /*** trebuchet.equipment.LongRangeScanner$SubspaceScanner ***/
    class YourInnerScanner {
    private:
        long long someNumber;

    public:
        YourInnerScanner();
        void scanAhoy();
    };

};

/*** trebuchet.craft.TowingVessel ***/
class Spaceship {
public:
    static int FIRSTSHIP;
private:
    const char * name;
    int serialNumber;
    LongRangeScanner * longRangeScanner;

public:
    Spaceship(LongRangeScanner * longRangeScanner);
    LongRangeScanner * getLongRangeScanner();
    void reset(LongRangeScanner * longRangeScanner, int serialNumber);
};

/*** trebuchet.Universe ***/
class Universe {
public:
    Universe();
    static void main(char * args);
};

C++ code output

/*** trebuchet.equipment.Scanner ***/
void Scanner::scan() {
}

/*** trebuchet.equipment.Device ***/
Device::Device() {
}

void Device::explode() {
}

/*** trebuchet.equipment.LongRangeScanner$TachyonScanner ***/
LongRangeScanner::MyInnerScanner::MyInnerScanner() {
    this->anotherNumber = 20;
}

void LongRangeScanner::MyInnerScanner::scanAhoy() {
    this->anotherNumber = this->anotherNumber + 4;
}

/*** trebuchet.equipment.LongRangeScanner$SubspaceScanner ***/
LongRangeScanner::YourInnerScanner::YourInnerScanner() {
    this->someNumber = 10;
}

void LongRangeScanner::YourInnerScanner::scanAhoy() {
    this->someNumber = this->someNumber + 2;
}

/*** trebuchet.equipment.LongRangeScanner ***/
LongRangeScanner::LongRangeScanner() {
}

int LongRangeScanner::getRange() {
    return this->range;
}

void LongRangeScanner::setRange(int range) {
    this->range = range;
}

void LongRangeScanner::scan() {
    this->range = this->range + 234;
    this->range = this->range - 123;
}

int LongRangeScanner::getDeviceId() {
    return 1337;
}

/*** trebuchet.craft.TowingVessel ***/
int Spaceship::FIRSTSHIP = 100;

Spaceship::Spaceship(LongRangeScanner * longRangeScanner) {
    this->name = "Nostromo";
    this->serialNumber = 120;

    this->longRangeScanner = longRangeScanner;
}

LongRangeScanner * Spaceship::getLongRangeScanner() {
    return this->longRangeScanner;
}

void Spaceship::reset(LongRangeScanner * longRangeScanner, int serialNumber) {
    this->longRangeScanner = longRangeScanner;
    this->serialNumber = serialNumber;
}

/*** trebuchet.Universe ***/
Universe::Universe() {
}

void Universe::main(char * args) {
    ;
}

int main(int argc, char* argv[]) {
    Universe::main(0);
    return 0;
}