JET (Just Enough Time)
static AOT (Ahead Of Time)
What Is JET?
is a static compiler that lets a developer create standard exe file applications that load and run very quickly.
- With JET
you can say simply someprog.exe instead of the usual more
verbose java.exe -jar
someprog.jar on the command line.
applications will run even if the Java JRE (Java Runtime Environment)
is not installed.
- Ordinary jar files are very easy to reverse engineer.
executables are almost impossible to reverse engineer. If you are a developer this
makes it difficult for pirates to defang your licencing restrictions or to pirate
- With the use of JetPackII, JET-compiled, programs are self-installing just like
Windows apps written in C++.
- JET-compiled programs look like perfectly ordinary familiar Windows exe
- There is no royalty for JET
- The catch is, unlike the conventional jar version of the application, they are
no longer WORA (Write Once, Run Anywhere). You can only use the
Windows version of the JET-compiled application on Windows and the Linux
version on Linux, nowhere else. Unless you have Windows or Linux you must use the
conventional jar version, e.g. if you have a Mac.
applications require 32 MB run-time library which is
usually included and downloaded with every application and update. It contains only
the parts of the run time actually used. Pretty must the smallest distributable is
32 MB, for even the simplest utility and the smallest exe
file is about 8 MB.
is Excelsior’s Java optimiser and native code generator, created in
Novosibirsk Russia. There are currently versions for Windows and Linux in English.
Excelsior is not responsible for the accuracy of anything said on this page. It is
based on my personal experience with JET
over a number of years.JET
Version jet12.0-pro-x86 supports up to Java 1.8.0_131
(The most recent Oracle release is 1.8.0_131
). Last revised/verified: 2017-03-08. JET
supports Vista, W2008, W7-32, W7-64, W8-32, W2012, W10-32, W10-64, Linux, LinuxX86, LinuxX64 and Ubuntu. Mac OSX is coming soon.
JET comes with a precompiled JRE,
so you don’t actually need to install a Oracle JDK (Java Development Kit) 1.8.0_131 though obviously you will need some JDK
for development, usually JDK 1.8.0_131. JET
jet12.0-pro-x86 now lets you natively compile Tomcat and
Tomcat applications. There are currently no MPs (Modifier Packs) to download and install for Jet jet12.0-pro-x86.
Why Use JET?
Downside of JET
executables are considerably larger than the equivalent jar. They contain much
of the JRE in compiled form. In contrast, distributed jars do not contain any run
time. However, the RAM overhead of Excelsior JET
Runtime is smaller than for the JRE. The distributed bundle produced by
may be substantially smaller than the JRE alone and the installed application
will occupy less disk space than the JRE. So if you are bundling the JRE with
your app now, your JET
distributables will be smaller; if not, they will be larger. This true for small
apps even if you don’t use the Java Run-Time Slim-Down feature.
The files I send people are a minimum of 4 MB, rather than the tiny jars I
would send otherwise. (My apps tend to be quite small, usually under 100K jars). I have to post the distributables on my website for
pickup rather than sending by email. You could also send these via WinZip Courier.
is usually a month or two behind Oracle in supporting new JVMs. Currently it is 5
versions behind the 1.8.0_131
where the current Oracle JDK is 1.8.0_131.
Last revised/verified: 2008-02-18
You can still compile with the current version of javac.exe and debug with the current version of java.exe.
- The runtime must exactly match the code. You can’t run new code on old
runtimes or vice versa. This means when a new version comes out, you will likely at
some point recompile and redeploy the entire universe of every
program you ever wrote on every customer machine. In development, an executable
finds the runtime by scanning the path. If you uninstall a version of
or replace it with a newer version, all code compiled with it will stop working
since it can’t find the old runtime. You must recompile it with jc.exe.
- The scheme for distributing the support DLLs and compiled JREs seemed brittle,
at least in the early versions. I have not done any further distribution
experiments since about 2003. JET
has improved drastically in other areas since then. JET
worked beautifully on my own machine, but sometimes mysteriously stopped working
on other machines, or never worked, when I deployed. I got error messages saying
that DLLs had gone missing or that the JET
runtime had not been installed. It is hard to remotely troubleshoot such problems
with an unsophisticated customer. Until I redo my experiments and can vouch all is
now well, I suggest you experiment with the evaluation version to make sure
distribution and remote installs work smoothly for you. They are probably OK
- It installs the JET
runtime in theAppdir/ JET
RT so that if some other developer is using JET, or you are
providing several applications, there will be duplicate copies of the
runtime. With today’s terabyte disks this is not longer so much of a
When Not To Use JET
is not a replacement for Oracle’s javac.exe. You
to compile the jars that javac.exe and jar.exe produce. You still use Oracle’s javac.exe to do the source code compiling and for debugging.
does not have debug features comparable to the trace in Intellij Idea. You do your
debugging on the class files before using JET.
compiles take considerably longer than a javac.exe
compile. You don’t use JET
until you are fairly sure the code is debugged.
- The only platforms Excelsior JET
supports at the moment are Windows and Linux. If you are considering compiling
your Java applications to native code to prevent reverse engineering, but some of
your customers use Macs, Excelsior JET
6.0 won’t help you. If you are using JET
for the speed, you could ship natively compiled JET
versions of your app to Windows and Linux users and the bytecode class files to
Example of Command Line JET Use
You can define a
project and compile it, complete with installer using a GUI. It is a multi-step
process, but not complicated. You can also compile in various ways from the command
line or *.bat scripts.
Example of ANT JET Use
My projects are typically quite simple and I
compile them with ANT scripts simply by handing a jar to the
Your program can detect that is in running under
by looking at the system properties such as:
java.vm.version=1.6.0_31e.g. This may be important since
does not support Throwable. getStackTrace() by default. You must request stack trace support,
which slows the programs down.
I have been very impressed with the JET
people. Even without an official support contract, the JET
people have responded quickly and thoroughly to my bug reports and suggestions for
improvements. They have provided better service free than most companies provide for
hefty fees. I wonder what they do for an encore when you do sign up for support!
Optimising compilers are notoriously buggy, yet JET
seems to generate flawless code time after time. I have never encountered any wrong
code generated. The only serious problem I have is Jet does not have as many built-in
root SSL certificates as Oracle Java 7. This means my apps when running under Jet
have trouble screen scraping some https: websites. You can, of course, copy
Oracle’s cacerts file on top of Jet’s for your
own personal use in testing and debugging, but you cannot legally do that for
programs you distribute.
How Does It Work
See Excelsior’s simplified overview of
How does JET
work? It needs somebody else’s compiler such as Oracle’s to produce the
byte codes, then it converts class files to a native Windows EXE file. Why is it so
fast? It is able to determine if methods overriding a particular non-final method are
never actually called in a particular application and therefore inline the method or
generate direct calls of it. JET
will allocate some local objects on the stack. It can eliminate a remarkable amount
of code that is not necessary, e.g. redundant checks for null by both caller and
does loop versioning, i.e. it creates a special safe version of loop code used when
it knows that various exceptions can’t possibly happen, e.g. subscripts out of
range. This way it can avoid much of the overhead of the Java safety net.
There are now three
versions (four if you count the Embedded edition) described in their FAQ. It supports all of
Java including class.forName dynamic class loading.
Preparing An Application for Distribution
Here is an overview of the process of preparing Jet-compiled application for
distribution. I am describing the process for Windows, but it is similar for Linux.
Let us assume your application is called Rabbit and will
eventually run on the client machine as rabbit.exe.
- Write and debug your Rabbit.java java source code in
an IDE such an IntelliJ Idea.
- Compile your Rabbit.java source with javac.exe, probably
using Ant or Maven.
- Bundle your Rabbit.class files into rabbit.jar with jar.exe or genjar.jar.
- Compile (i.e. convert class files in the jar into native machine code) your
rabbit.jar from the command line with
jc.exe or for finer control use the Jet Control Panel
GUI to produce a rabbit.exe file. The
compilation tweaking hints are stored in the human-readable rabbit.prj file. The rabbit.exe file will
run locally. It is quite small since it uses the pre-installed Jet Run time and
library of precompiled JDKs. It leaves behind intermediate files in jetpdb to speed up future compiles. rabbit.xbind.script contains a list of DLLs (Dynamic Link Libraries)
that rabbit needs to run. With the Jet Control Panel
you can implement a splash screen that comes up immediately without having to
write any code.
- Use the JetPack GUI to bundle up your executable, jet
compiled parts of the JDK that it uses and library code into one big setup-rabbit.exe self installing exe bundle.
That is what you distribute. JetPack stores its tweaking
hints in the rabbit.jpn file.
- You then post the fat setup-rabbit.exe on a website or
burn it on a CD and distribute it to your client.
- When the user runs setup-rabbit.exe it unpacks itself
and places its various pieces, including rabbit.exe and
runtime on the hard disk, then sets up desktop icons and menus.
is 32-bit with 64-bit planned
for 2009. When the JET-compiled
32-bit executables run on 64-bit
windows you have a 3 GB address space. Oracle HotSpot requires a contiguous address
space for the heap, whereas Excelsior JET
(and, for that matter, JRockit) does not. So if you have lots of RAM, but the
virtual address space is fragmented due to DLLs already loaded, Excelsior
may be able to allocate more objects on the heap than HotSpot. Further, with
you don’t have to specify the heap size. You can have it automatically adjust
as it runs taking more or less memory depending on how much is available in the
system. This lets you automatically exploit the whole machine when there are no other
Have a look at the Which
utility for code to recognise JET
executables and whether they are up-to-date, compiled for the latest runtime.
||Human-readable project file.|
||Compiler. Converts *.jar to *.exe or *.class to *.exe.|
||prepares self-installing apps.|
||Adds support for yet another JVM (Java Virtual Machine).|
||Project control, GUI control of the compiler.|
Viewing Generated Assembler
versions prior to 5.0 allow you to view the assembler generated by using the
-genasm+ key (aka compiler option switch) in the project
file to generate assembler instead of object files. This was an undocumented feature.
5.0+, you will need to use a conventional disassembler to view the generated code.
-generated code is unusually difficult to reverse engineer since the compiler does
loop versioning and hiking and is so creative at devising code that does the same
thing as the original but in a quite different way.
From time to time, Excelsior issues MP (Maintenance Pack) s to upgrade the Jet compiler,
runtime and highest level of the Oracle Java runtime supported. When you install
these, for all practical purposes all your Jet application exes will stop working
until you rebuild them. It is possible to ask Jet to retain obsolete runtimes or to
regenerate them. However, I have never been able to get old apps to work without
rebuilding them. I have problems with incompatibility between versions of Java,
versions of Jet and something called binary compatibility level which might be sort
of build number. If I fully understood how this worked under the hood, presumably, I
could manage a corral of both obsolete and up-to-date Jet software and my
Jet-compiled applications of various vintages.
I impatiently cut the Gordian knot. I just delete all my old exes and rebuild
everything. The catch is my build process uses custom Jet-compiled applications. I
can’t rebuild because all my tools stop working. I kludge my way through this
chicken-egg problem mainly by reverting to executing the original jars instead of the
Jet-prepared exes. I can ease the pain of the transition by first temporarily
rebuilding my exes without first rebuilding my Java source or jars, then rebuild the
java and Jars (using recently-rebuilt Jet-complied build tools) and then rebuild all
the Jet exes a second time.
If the setup utility stops working after installing a maintenance
pack, just reboot. It might be a good idea to reboot after the install on general
I wrote a free utility called Which to, among other things, help you find obsolete
Jet-compiled application exes.
JETPack bundles up self-installing
applications. It is much like an InstallAnywhere for Java/ JET. It allows:
JETPack is very easy to use. Just fill in the blanks.
- Automatically bundle the required Excelsior JET
- Set up shortcuts on desktop and menu.
- Assign an optional *.ico icon and *.bmp splash screen for your app (done in the
project, not the JETPack installer). You don’t need to write any code to get
this feature built into your executable.
- Display a splash screen during install.
- display a EULA
- Versions 3.7 and earlier required you to have Oracle’s JRE installed as
well a JET
DLL runtime library on machines running the JET
executables. Starting with version 4.0, there is no
longer any need to have the corresponding JRE installed, just the runtime.
Unfortunately, an option to create fully self contained executables that could run
without the DLLs has gone. JETPack will bundle the application and the DLL runtime
library into a rather bulky download: about 9MB for a mid-size Swing application
such as jEdit.
JETPerfect was the global
optimiser that came with the Professional Edition. It is no longer supported. It did
a very time consuming and labour-intensive form of global optimisation creating a
When you first install JET
for development, if you don’t accept the default JVM, it has to compile the
entire JVM set of class files. This takes about an hour on modern machines or over
twelve hours on clunkers with less than 512 MB of RAM. People who just want to run
don’t have to do this.
Obviously, to use JET, you need the JDK installed on each developer machine. To run the programs you need
DLL runtime and the application. The DLL contains a compiled version of the JRE.
Even though Oracle’s license prohibits partial JRE redistribution, Excelsior
has come up with a solution that enables
you to omit the unused Java SE APIs without breaking the Oracle license. In a general
case however, the entire Java SE API has to be bundled with your
application to deploy it on a customer machine.
JET 11 Improvements
- Supports JDK
- JavaFX support
JET 10.5 Improvements
- New garbage collector.
- Apple Mac OSX 10.10 bit support.
- Smaller 64-bit executables.
- I still can’t use the 64-bit version because it does not implement
HUGECLINT. I tend to have quite a bit of static init.
- Supports only up to Java 1.7.0_55.
JET 10.0 Improvements
- 64-bit versions improved. They still fail when you have large amounts of
- Apple Mac OS 64 bit
- Supports Java 1.7.0_55.
JET 9.0 Improvements
- The big improvement is supporting Java 1.7.0_51.
- Linux 64 bit
JET 7.0 Improvements
- The big improvement is the ability to compile Tomcat and Tomcat
- The 64-bit alpha version is out. The compiler runs 64-bit and the run-time is
64-bit. The optimisations are not hooked up yet, so this is just for
- It also features multi-app executables.. With it, you
may compile several applications into a single executable to simplify deployment
and maximize code and data sharing without manually extracting common parts into
- It now supports Windows 7.
- Code runs 1.2 to 3 times
JET 6.5 Improvements
- Better Eclipse integration.
- Faster memory allocation and garbage collection.
- JIT compilation is twice as fast.
JET 6.4 Improvements
- Optional encryption of literals and resources to make reverse engineering or
- Twice as fast startup of the finished applications.
- faster compiling, both AOT
and JIT (Just In Time)
run time addition of dynamic classes).
- slimmer distributables.
- Not-so-dumb compilation: now a settings change that has no impact on generated
code results in a re-link instead of a full build.
JET 6.0 Improvements
- Keeps getting faster
- Support for Java 1.6, e.g. annotations.
- more flexible installer
- Plug-in for IntelliJ Idea
- more efficient memory management and better register allocation.
JET 5.0 Improvements
creates only one extra directory per project called jetpdb. It used to create a large directory tree with names
duplicating the branches of your packages. This caused havoc with tcc/TakeCommand CDD. The new system has a little PDB (Project DataBase) for each project for
- Slim-down. The
distributables are slimmer, 8 MB for Swing/AWT and as small as 5 MB for SWT or
LWJGL. You can distribute a package that consists of your app and just the parts
of the JRE that it uses. This prunes down the size of the distributable.
- Start up time 30% faster when compiled with the
- 1.7 times faster execution on some benchmarks because
of: new loop optimizations, faster floating-point operations, faster memory
allocation and more effective implementation of other runtime routines.
- Faster compilation.
- IntelliJ Plugin.
- To suppress the voluminous progress messages, use jc
-DECOR= on the command line.
finds its files using a registry entry at:
- Adaptive Heap Size
- A program bundle distributed to customers. When it runs, it installs the
program on the clien’ts disk. It contains the program, auxiliary DLLs, data
files, icons etc.
- The company headquartered in Novosibirsk Russia that makes
- program containing machine language code that can run on Windows or Linux. The
native compiler produces executables. You can run these directly on the machine
used to compile them. You must bundle them first into distributables if you want to
run them on other machines.
native compiler than converts class files produced by javac.exe to Windows or Linux native executables (*.exe files). You
control whether to use production or beta jc.exe by
putting the corresponding directory on the path.
- A native Java compiler for Windows and Linux from Excelsior than includes an
installer. It comes is three versions, standard, professional and enterprise.
- JET Enterprise
the high end
version of the JET Java native compiler. The main advantage over the professional
version is the optimised server runtime for extra speed.
- JET Standard
the entry level
version of the JET Java native compiler.
- JET Professional
level version of the JET
Java native compiler. The main advantage over the standard version is slimmer
distributables. This is what I use.
- The GUI used to bundle a JET
application up for distribution.
Oracle’s Java run time. It is not required on either the development or
client machine to run JET-compiled applications. A JET
-compiled version of it is automatically bundled with distributed application
along with Excelsior-written native classes and DLLs.
- JET launchpad
- the GUI used to set up JET
projects to control how they are compiled.
Oracle’s Java development tool. It is not required on either client machine
to run JET-compiled applications, though you would normally
have a copy of the JDK on the development machine.
- a powerful optimisation technique JET
uses to create several specialised versions of a loop body so that it does not
have to check conditions in the middle of the loop body. It selects the loop body
version at the top of the loop. This removes time-consuming loop body jumps and
improves code locality and avoids instruction pre-fetch cache flushing. The
technique is almost impossible to do by hand in assembler. This is one of the many
can often out-perform the best assembler hand coding.