Next: Overview of Harissa
Up: Harissa: a Flexible and
Previous: Introduction
Several strategies have been presented to optimize execution of Java
programs. They range from aggressive compilation schemes to specific
hardware processors. Advantages and drawbacks of these schemes are
the following:
- Native Java compilers - Compiling source code into
native code is the most common way of compiling a language. But this
approach is contrary to the Java philosophy since all the advantages
of having an platform independent language disappear. For instance,
the source code of Java programs is often not available. However,
this strategy may be useful to obtain very efficient target binaries
for very specific environments. This approach is implemented
in the Vortex project [12].
- Bytecode compilers - Unlike native compiler, bytecode
compilers take bytecode as input. One of the interesting
characteristics of Java is that the bytecode contains nearly the
same amount of information as the source itself. It has even been
shown by Ford [13] and by Vliet [14] that it is
possible to decompile the bytecode of a program and produce a Java
source program similar to the original one. This is mostly due to
the fact that the signature of the classes in the program must be
kept in the bytecode to allow classes to be dynamically loaded at
runtime. The only significant loss of information in the bytecode
concerns structured loops, which are transformed into goto
statements. Hence, a bytecode compiler can easily be as efficient
as a native compiler. There are two types of bytecode compilers:
those that generate native code and those that generate an
intermediate language, such as C. The advantages of these two
approaches are discussed below.
- Just In Time compilers - A just-in-time compiler differs
from the a ``classical'' off-line compiler, in that the code is
compiled only when needed at execution time. The difference in
performance between those approaches is the time that can be spent
during execution to perform optimizations. Vendors such as
Borland [4], Symantec [5],
Softway [6], and others have already released JIT
compilers. The basic scheme is to compile a method when it is called
for the first time, pausing execution while doing so. Refinement to
this approach has been recently described by Plezbert and
Cytron [7]. They mix interpretation and JIT compilation
by taking advantage of multi-threading (on a multiprocessor)
- Java Processors - A Java processor is a dedicated processor
that implements the Java Virtual machine and directly executes the
Java bytecode. Such processor can be used as the main processor in a
dedicated Java machine (workstations, embedded systems) or as a
co-processor in a workstation. Sun and other manufacturers are
already designing such chips. However, their competitiveness has not
yet been proved [15]. Since such processors are not
currently available, in this paper we only consider approaches that
do not require specific hardware.
Although Java was originally designed for programming embedded
applications, it has recently spread to many domains. Therefore, to
choose the appropriate execution scheme many factors, such as the
frequency of reuse of the same code or the heterogeneity level of the
set of target machines, have to be considered. The most frequent
situations are the following:
- Small software components integrated in Web services - These
components can undergo frequent changes from one load to another by
the same client.
As a result, in this context, a JIT compiler is the most appropriate
solution.
- Platform-independent large software - Such programs may or
may not be related to Web services. Java technology is used because
of its machine independence. The Java tools themselves are examples
of such programs (e.g., compiler, disassembler, ...). These
programs change infrequently and are often used by many users.
Therefore, keeping a local, optimized version of the compiled code
is advantageous. By comparison to a JIT, that always get the latest
version of the software, this approaches requires the management of
local optimized versions. This can be implemented by a revision
control system that compiles and installs new software versions as
they are released, in a automatic and transparent way.
- Platform-dedicated software - Examples are operating
system components [3] and embedded applications. For
these applications, the Java technology provides safety. These
applications are characterized by very infrequent changes. Hence, it
is advantageous to optimize the final code for the target system.
Finally, it should be noticed that even some statically configured
tools, such as Javadoc, dynamically choose and load classes at
execution time. For these applications, it is thus worthwhile to combine
the binary code with an interpreter or a JIT compiler to allow dynamic
(over)loading of new features.
As was already stated, there are two types of off-line bytecode
compilers: native and non-native. Native compilers produce code that
is directly executable, while non-native compilers produce code in an
intermediate language.
Designing a native compiler has two advantages: (i) the generated
binary code may be more efficient than that resulting from code
written in an intermediate language and (ii) compilation is fast since
it does not require successive tools. However, this choice has
drawbacks: (i) it is not portable and (ii) generation of efficient
code requires extensive knowledge of the features of the target
processor.
Non-native compilers are more flexible and also achieve competitive
performance. In particular, choosing C as an intermediate language
permits the reuse of extensive compiler technology that has already
been developed. In fact,
- There are very good C compilers.
- C compilers are available for all machines. The developer does not
have to address subtle differences that exist between a processor
and its successors.
- The development process is safer, quicker, and in some ways
simpler since optimizations can be done on the generated C code.
- It is possible to reuse existing, aggressive optimizers such as
Suif [16] or partial evaluators for C such as
C-mix [17] or
Tempo [18, 19].
These reasons led us to develop a non-native off-line compiler for
Java bytecode that generates C programs.
Next: Overview of Harissa
Up: Harissa: a Flexible and
Previous: Introduction
Gilles Muller
Wed Apr 30 16:15:21 MET DST 1997