Static compilation alone could not work for the Java applications that load classes unknown at compile time. To cope with it, the JET Runtime includes a just-in-time (JIT) compiler to support dynamic compilation of the Java bytecode. That enables you to statically compile a part of the application and remain the other part "as is" - in the form of .class or .jar files. This technique is called Mixed Compilation Model (MCM.) Though MCM is always enabled in the JET Runtime, dynamic compilation is demand-driven, that is, it occurs when the application attempts to load a class that was not pre-compiled.
A typical use case for MCM would be a Java program whose client installation is extensible with plug-ins. The core of such an application can be pre-compiled and then deployed to target systems as the native executable. If the user installs a plug-in distributed as a .jar file, the JET Runtime loads it using the dynamic compiler. This way, an application backed by MCM is able to correctly load the classes that were not or could not be compiled before execution.
Let us consider an example that does not work without dynamic compilation. The Java SE platform includes Dynamic Proxy API, a mechanism that allows programs to dynamically create bytecode that represents classes and create new instances of those classes. A dynamic proxy class is a class that implements a list of interfaces specified at run time.
Obviously, Dynamic Proxy API cannot operate without dynamic compilation because bytecodes are created on-the-fly, literally as arrays of bytes, which are then fed to the virtual machine and it works flawlessly with the JET Runtime.
This chapter describes MCM in details and also points out certain Java technologies that definitely require Mixed Compilation Model.
Mixed Compilation Model is always enabled so the classes, that were not pre-compiled statically, will be handled by the JIT compiler at run time.
For certain types of application, the JET Runtime definitely employs the mixed model. That is the case, if some of loaded classes are not known at the moment of static compilation. In general, there are two reasons for that:
For example, dynamic compilation occurs, if your application features the following:
|loading classes from remote host||RMI Distributed Object Model|
|generation of bytecode at run time||Dynamic Proxy API|
|generation of class files at run time||JasperReports|
|custom classloading and third-party plug-ins||NetBeans|
|dynamic deployment of components||Java application servers, such as JBoss|
Even though certain classes of your application can be compiled statically, you may enable the mixed model for them explicitly. It is useful if your application contains a lot of similar classes but loads just a few. A good example is country-specific or language-specific classes in internationalized applications. Instead of precompiling all of them, you may supply those classes in a .jar file. You may optionally pack that .jar to the executable as described in Resource packing.
If you want to have the shortest possible JIT compilation pauses, specify the jet.jit.disable.resolution property at runtime (see JET Runtime-specific properties). Note that setting this property may negatively affect JITed code performance.
In general, it is not recommended to force MCM for "hot" classes that take a significant fraction in total execution time. It would be better to pre-compile such classes because the JIT compiler incurs run time overheads and employs less efficient optimizations as compared to the static compiler.
Many JVM implementations, e.g. Oracle HotSpot, load classes on the first use (class instantiation, static method call or static field access), not on the first reference. This is called lazy class loading. Therefore, if a referenced class is not available at application launch time but becomes available at run time before it is actually used by a method, the program executes normally.
By default, the JET static compiler resolves all references to classes at compile time so if you create a project that includes classes with unresolved import dependencies, JET Control Panel displays detailed warnings on the Class view dialog.
Sometimes class absence is just an inconsistency that may be easily fixed. For example, it may appear if you forget to add a .jar to the compilation set. However, if you have double checked your project and not found the missing classes in a jar file or directory, still there is a chance that the classes in question are made available at run time.
To cope with it, the compiler will generate special stubs at all places where an unavailable class is used. On the first execution, such a stub checks if the referenced class has already been loaded. If not, the stub attempts to load it using the JIT compiler and then uses reflection information (hence the term reflective shield) to resolve the field or method that was referenced in the code. On subsequent executions, the stub will determine that the resolution has already occurred and proceed to the actual use of the field or method.
If a shielded class has not become available at run time, the respective stubs will throw java.lang.NoClassDefFoundError.
You may also use this reflective shield facility to pick out the classes and packages that you do not want to precompile by simply making them unavailable to the JET static compiler. However, take into account that reflective stubs create overhead that may lead to considerable performance degradation if methods of the shielded classes are frequently executed.
Note: The JIT compiler is also capable of generating reflective stubs for imported classes that are not available yet.
Code protection is an important benefit of the Excelsior JET JVM. The JET Optimizer converts your classes to optimized native code, which is very hard to reverse engineer, so understanding your algorithms becomes a headache even for the most experienced hackers.
However, Excelsior JET has some limitations with respect to code protection: class files that will be JITed on end user systems cannot be protected. When creating a JET project file for your application, make sure to set protect to all classes for all jar files that contain the proprietary code (refer to Classpath grid for details).