Contents Previous Next

Chapter   6

Compilation Flags, Definitions and Macros


This section lists various C preprocessor flags, definitions and macros that are defined in VmCommon/h/main.h. Understanding the meaning of these flags helps you in porting efforts, so please read the documentation below and in file VmCommon/h/main.h.


Note – Rather than changing the values provided in VmCommon/h/main.h, these values should be preferably be overridden in your port-specific machine_md.h file.

Also note that in our reference implementation, many of these flags are commonly overridden from makefiles.

For each definition, we give a brief summary and its default definition. These flags and macros are documented also in VmCommon/h/main.h.

6.1 General compilation options

The following definitions control the general platform-dependent compiler options that you must set before starting your porting efforts. Incorrect settings typically cause the virtual machine to malfunction.

#define COMPILER_SUPPORTS_LONG 1 

Turn this flag on if your compiler has support for long (64 bit) integers.

#define NEED_LONG_ALIGNMENT 0 

Instructs the KVM to know that your host operating system and compiler generally assume all 64-bit integers to be aligned on eight-byte boundaries.

#define NEED_DOUBLE_ALIGNMENT 0 

Instructs the KVM to know that your host operating system and compiler generally assume all double floating point numbers to be aligned on eight-byte boundaries (this flag is meaningful only if floating point support is turned on.)

Additional notes. The compiler generates better code if it knows the “endianness” of your machine. You should set one of the following two variables to “1” in your machine-specific header file.

   #define BIG_ENDIAN 0 
   #define LITTLE_ENDIAN 0 

It is unnecessary to set one of these “endian” variables to “1” if you reset COMPILER_SUPPORTS_LONG to zero. (See Chapter 9 for more details.)

Also note that if your compiler supports 64-bit integer arithmetic and you have set the flag

#define COMPILER_SUPPORTS_LONG  

you should supply definitions for the types long64 and ulong64. If your compiler does not support 64-bit integers (or you have set the flag to 0 for some other reason), structure definitions of these two types are created for you automatically. (See Chapter 9.)

6.2 General system configuration options

The following definitions allow you to control which components and features to include in your port.

#define IMPLEMENTS_FLOAT 1 

Turns floating point support in KVM on or off. Should be ‘1’ in those implementations that are compliant with CLDC Specification version 1.1, and ‘0’ in those implementations that are compliant with CLDC Specification version 1.0.

#define PATH_SEPARATOR ‘:’ 

Path separator character used in CLASSPATH. This definition is meaningful only when utilizing the default class loader for command line based systems. (Defined in VmCommon/h/loader.h.)

#define ROMIZING 1 

Turns class prelinking/preloading (JavaCodeCompact) support on or off. If this option is turned on, KVM prelinks all the system classes directly in the virtual machine, speeding up application startup considerably. Refer to Chapter 14 for details.

#define USE_JAM 0 

Includes or excludes the optional Java Application Manager (JAM) component in the virtual machine. Refer to Chapter 15 for details.

#define ASYNCHRONOUS_NATIVE_FUNCTIONS 0 

Instructs the KVM to use optional asynchronous native functions. Refer to Section 11.4 "Asynchronous native methods” and Chapter 12 for details.

#define USE_KNI 1 

This option was introduced in KVM 1.0.4. When enabled, the system will include some code that is needed by the K Native Interface (KNI). If you do not intend to use KNI (you should!), we recommend you to turn this option off, because old-style native functions will run slightly faster with this option turned off. Refer to the KNI Specification for further information on KNI.

6.3 Palm-specific system configuration options

The following definitions allow you to control certain Palm-specific system configuration options. All these features were originally designed for the Palm OS version of KVM, but they may be useful also for other ports.


Note – The CLDC implementation for the Palm OS is no longer available.
#define USESTATIC 0 

Instructs the KVM to use a Palm-specific optimization in which certain immutable runtime data structures are moved from “dynamic RAM” to “storage RAM” to conserve Java heap space. A fake implementation of this mechanism is available also for the Windows and Solaris versions of KVM (for debugging purposes.)

#define CHUNKY_HEAP 0 

Instructs the KVM to use an optimization which allows the KVM to allocate the Java heap in multiple chunks or segments. This makes it possible for the virtual machine to allocate more heap space on certain platforms such as Palm OS.

#define RELOCATABLE_ROM 0 

Instructs the KVM to use an optimization in which the prelinked system classes are stored using a relocatable (movable) representation. This allows romized (JavaCodeCompacted) system classes to be stored in devices such as Palm OS.

6.4 Memory allocation settings

The following definitions affect the amount of memory KVM allocates.

#define DEFAULTHEAPSIZE 256*1024 

The Java heap size that KVM allocates upon virtual machine startup. This value is commonly overridden from makefiles. Note that, starting from KVM 1.0.3, it is possible to override the heap size value from the command line (in those ports that support command line operation.) The heap size value must be a number that is divisible by four. The number must be in the range of 16k to 64 M.

#define INLINECACHESIZE 128 

The size of a special inline cache area that KVM reserves upon virtual machine startup if the ENABLEFASTBYTECODES option is turned on. The inline caching mechanism speeds up method lookups in the KVM by utilizing a technique popularized by Deutsch & Schiffman in the early 1980s. The size here is expressed as a number of inline cache entries (each entry requires 12-16 bytes depending on your target platform.)

#define STACKCHUNKSIZE 128 

The execution stacks of Java threads inside the KVM grow and shrink automatically as necessary. This value defines the default size of a new stack frame chunk when a new stack chunk needs to be allocated. Reducing the default stack chunk size will make the creation of new Java threads less expensive, but will slow down the execution of the VM when running programs that require a lot of stack space (that is, programs that have a lot of nested method calls.)

#define STRINGBUFFERSIZE 512 

The size (in bytes) of a statically allocated area that the virtual machine uses internally in various string operations.


Note – As a general principle, KVM allocates all the memory it needs upon virtual machine startup. At runtime, all the memory is allocated inside the preallocated areas. Of course, the situation may change if the virtual machine calls host-system specific native functions (such as graphics functions) that perform dynamic memory allocation outside the Java heap.

6.5 Garbage collection options

The following option turns on compacting garbage collection. Note that currently compaction cannot be used on those platforms that have a segmented (non-contiguous) memory architecture.

   #define ENABLE_HEAP_COMPACTION 1 

The following option, if set to a non-zero value, causes a garbage collection to occur on every allocation. This makes it easier to find garbage collection problems. Since this option makes the virtual machine run extremely slowly, the option should be turned off in production builds.

   #define EXCESSIVE_GARBAGE_COLLECTION 0 

6.6 Class loading options

Some KVM ports may want to forbid any new classes from being loaded into any system package. The following macro defines whether a package name is one of these restricted packages. By default, the system prevents dynamic class loading to java.* and javax.* packages.

   #define IS_RESTRICTED_PACKAGE_NAME(name) \ 
   ((strncmp(name, "java/", 5) == 0) || \ 
    (strncmp(name, "javax/", 6) == 0))  

6.7 Interpreter execution options (since KVM 1.0)

The following macros allow you to turn on and off certain features controlling interpreter execution. The default values for a production release are shown below.

#define ENABLEFASTBYTECODES 1 

Turns runtime bytecode replacement and method inline caching on or off. This option improves the performance of the virtual machine by about 10-20%, but increases the size of the virtual machine by a few kilobytes. Note that bytecode replacement cannot be performed on those target platforms in which bytecodes are stored in non-volatile memory such as ROM.

#define VERIFYCONSTANTPOOLINTEGRITY 1 

Instructs the virtual machine to verify the types of constant pool entries at runtime when performing constant pool lookups. Reduces runtime performance slightly, but is generally recommended to be kept on for safety and security reasons.

Additional definitions and interpreter macros:

#define BASETIMESLICE 

The value of this variable determines the basic frequency (as a number of bytecodes executed) in which the virtual machine performs thread switching, event notification and other periodically needed operations. A smaller number reduces event handling and thread switching latency, but causes the interpreter to run more slowly.

#define DOUBLE_REMAINDER(x, y) fmod(x,y) 

A compiler macro, defined in interpret.h, that is used to find the modulus of two floating point numbers.

#define SLEEP_UNTIL(wakeupTime) 

This macro makes the virtual machine sleep until the current time (as indicated by the return value of the function CurrentTime_md()) is greater than or equal to the wakeup time. The default implementation of SLEEP_UNTIL is a busy loop. Most ports should usually provide a more efficient implementation for battery conservation reasons. Refer to Section 12.4 "Battery power conservation” for further details.

6.8 Interpreter execution techniques (after KVM 1.0.2)

Since the release 1.0.2, KVM has an interpreter design that gives up to 15-30% better performance than KVM 1.0 without any loss of ANSI C portability. The actual performance improvement percentage depends on the target platform and the capabilities of the C compiler that is used for compiling the KVM. The performance improvement is the result of the following four techniques that can be used independently of each other:

These techniques do not depend on any compiler-specific features, and are therefore portable across a wide variety of C compilers. Each of the techniques and the corresponding macros are discussed in more detail below.

6.8.1 Copying the virtual machine registers to local variables

The virtual machine registers of the KVM (ip, sp, lp, fp, cp) are accessed very frequently when bytecodes are being executed. In KVM 1.0, all these virtual machine registers are defined as global C variables. Starting from KVM 1.0.2, these registers are still principally defined as global variables, but if the LOCALVMREGISTERS option is on, they are copied to local variables when the interpreter is executing. A good C compiler will then optimize the interpreter loop so that these local variables are put into machine registers for substantially faster execution.

#define LOCALVMREGISTERS 1 

Turns the localization of virtual machine registers on or off.

#define IPISLOCAL 1 
#define SPISLOCAL 1 
#define LPISLOCAL 0 
#define FPISLOCAL 0 
#define CPISLOCAL 0 

These macros allow you to control specifically which of the virtual machine registers should be used locally by the interpreter loop. These macros have been added to provide better control over register allocation, as many resource-constrained platforms may not have many physical hardware registers available.

The optimal selection of these options for a specific platform will require careful examination of the machine code produced by the compiler, along with a good deal of experimentation. By default, ip (instruction pointer), and sp (stack pointer) are allocated locally, while lp (locals pointer), fp (frame pointer) and cp (constant pool pointer) are kept in global variables.


Note – If you use the LOCALVMREGISTERS option and you want to make further changes to the code implementing Java bytecodes, the single most important thing to remember is to make sure that the local copies of the virtual machine registers are copied back to their global variables before calling functions in the virtual machine that expects them to be in their global variables. Failure to do so will lead to obscure bugs. The virtual machine registers can be saved to their global variables by using the macro VMSAVE. They are restored back to their local variables by using the macro VMRESTORE. For instance the RETURN bytecodes may need to call monitorExit(), and to do this the call must be done as follows:

VMSAVE
result = monitorExit(...);
VMRESTORE

6.8.2 Splitting uncommon bytecodes into a separate subroutine

The KVM 1.0 interpreter had the code for all the Java bytecodes in a single large switch statement. However, a majority of Java bytecodes are executed very rarely. If the code for the more frequently and less frequently used bytecodes is placed in separate routines, the C compiler can often do a better job optimizing the resulting smaller interpreter loops. This also helps the compiler find hardware registers for the virtual machine registers more easily when the LOCALVMREGISTERS option is in use.

#define SPLITINFREQUENTBYTECODES 1 

Turning this option on allows the C compiler to generate separate interpreter loops for the frequently and infrequently used bytecodes.

Note that the code to process the bytecodes is now contained in a file called bytecodes.c. The code for all the bytecodes is kept here and is selectively compiled by utilizing a number of internal macro definitions (STANDARDBYTECODES, INFREQUENTSTANDARDBYTECODES, FLOATBYTECODES and FASTBYTECODES).

The code in bytecodes.c is executed from another new file called execute.c. If the SPLITINFREQUENTBYTECODES option is enabled, the file bytecodes.c is included twice into execute.c: once for the routine called SlowInterpret() and once for the routine Interpret(). The four macros mentioned above are used to control the expansion of the appropriate bytecodes into the correct subroutines.

6.8.3 Moving the test for thread rescheduling to branchpoints

The old KVM 1.0 interpreter tested for the need to reschedule (switch threads) before the execution of each bytecode. The performance of the interpreter was improved by about 5% by changing the location of this test so that the test is performed only after every branch, goto, call and return instruction.

Thread scheduling in the old interpreter took place when a certain number of bytecodes had been executed. This number was, by default, 100 times the priority of the thread. In the new interpreter, thread rescheduling occurs by default when 1000 times the number of branch, call, or return bytecodes have been executed.

#define RESCHEDULEATBRANCH 1 

Turning this option on changes the thread switching mechanism so that tests for thread switching are moved to branchpoints. Note that enabling this option affects the value of the BASETIMESLICE macro inherited from KVM 1.0. When this option is off, thread scheduling operates as in KVM 1.0.

6.8.4 Padding out the bytecode space

The Java Virtual Machine Specification defines 200 standard bytecodes, plus additionally reserves four other bytecodes for other use. However, many C compilers produce better code when the size of the bytecode (switch) table is exactly 256.

#define PADTABLE 0 

Turning this option on will pad the interpreter switch tables so that the number of instructions is 256. This will increase the size of the virtual machine, but allows the interpreter to run faster on some platforms.

6.9 Java-level debugging options

The KVM 1.0.2 release introduced a new Java-level debugger interface that allows the KVM to be plugged into third party Java debugger environments and integrated development environments (IDEs) that supports the JDWP (Java Debug Wire Protocol) protocol. The macros in this subsection are related to the Java-level debugger options.


Note – It is important to notice that there is a fundamental difference between the debugging facilities intended for Java-level debugging and VM-level debugging.

Java-level debugging facilities are related to the debugging of the Java programs that the KVM executes. VM-level debugging facilities are used for debugging the KVM itself at the native (C) code level.
#define ENABLE_JAVA_DEBUGGER 0 

Includes a large amount of debugger support code that is needed for plugging KVM into a third-party Java debugger or integrated development environment such as Forte or Borland JBuilder.

More information about the Java-level debugger facilities and the KDWP interface is provided in Chapter 16, "Java-Level Debugging Support (KDWP).”

6.10 VM-level debugging and tracing options

KVM provides a large number of debugging and tracing facilities that can be used for inspecting the behavior of the KVM itself at the native (C) code level. These facilities can be extremely helpful during porting efforts.

All the VM-level debugging and tracing options should be turned off in a production release.

6.10.1 Including and excluding debugging code

#define INCLUDEDEBUGCODE 0 

Includes a large amount of debugging and logging code that is useful when porting the virtual machine onto a new platform. This option should be turned off in production builds.

#define ENABLEPROFILING 0 

Turns on or off certain profiling features that allow you to monitor virtual machine execution and get execution statistics. Turning this option on slows down the virtual machine execution speed considerably. This option should be turned off in production builds.

6.10.2 Tracing options

In KVM 1.0, all the tracing options were compilation flags that could be changed only by recompiling the virtual machine. In KVM 1.0.2, all these tracing options were changed into global variables that can be controlled from the command line. This makes it much easier to turn individual tracing options on and off. These global variables (and command line switches) are available only if the virtual machine has been compiled with the INCLUDEDEBUGCODE mode turned on.

TABLE 6  –  Command line tracing options
Option
Description
-traceallocation
trace memory allocation
-tracedebugger
trace the debugging interface (since KVM 1.0.3)
-tracegc
trace garbage collection
-tracegcverbose
trace garbage collection, more verbose
-traceclassloading
trace class loading
-traceclassloadingverbose
trace class loading, more verbose
-traceverifier
trace class file verifier
-tracestackmaps
trace the behavior of stack maps
-tracebytecodes
trace bytecode execution
-tracemethods
trace method calls
-tracemethodsverbose
trace method calls, more verbose
-traceframes
trace stack frames
-tracestackchunks
trace the allocation of new stack chunks
-traceexceptions
trace exception handling
-traceevents
trace the behavior of the event system
-tracethreading
trace the behavior of the multithreading system
-tracemonitors
trace the behavior of monitor objects
-tracenetworking
trace the network access
-traceall
activates all the tracing options above simultaneously

If your target platform does not support command line operation, you can control these options directly by changing their default values in file VmCommon/src/global.c, or by defining a graphical user interface that sets and resets these options.

Additionally, you can control whether the tracing messages printed out are terse or more verbose by modifying the following option:

    #define TERSE_MESSAGES 0 

KVM also contains a stack trace printing facility that can be turned on to help debugging of exceptions and errors in more detail (at the cost of some additional memory footprint). By default, this mode is turned on automatically when the INCLUDEDEBUGCODE flag is turned on.

    #define PRINT_BACKTRACE 0 

6.11 Error handling macros


Note – The internal error handling macros used by the KVM have been redesigned in KVM 1.1 to support the redesigned class loader.

The interpreter uses the internal error handling macros shown in CODE EXAMPLE 1.

If there is a call to the macro THROW(error), anywhere inside the “normal code,” the VM jumps immediately to error handling code. Uses of this macro can be nested, either lexically or dynamically. The THROW jumps to the innermost CATCH error handling code. (The various TRY, THROW, and CATCH macros are defined in VmCommon/h/global.h.)

CODE EXAMPLE 1 Error handling macros
TRY { 
   normal code 
} CATCH (error) { 
   error handling code 
} END_CATCH 
   always continue here 

By default, this behavior is emulated using setjmp and longjmp. However, platforms (such as PalmOS) that already provide a similar mechanism should use the native mechanism.

KVM 1.1 also has new macros for controlling the shutdown of the virtual machine. These macros have been illustrated in CODE EXAMPLE 2

CODE EXAMPLE 2 VM shutdown macros
VM_START { 
   normal VM code 
} VM_FINISH (value) { 
   code to execute before VM shuts down 
} VM_END_FINISH 

Rather than calling the normal C exit function, the proper way to exit from the VM is to call macro VM_EXIT(value). Calling this macro will cause the control of the VM to be immediately transferred to the code that follows the VM_FINISH(value) macro. The value to be passed to this code typically represents the exit code that the VM will return when it shuts down.

6.12 Miscellaneous macros and options

#define UNUSEDPARAMETER(var) 

Some functions in the reference implementation take arguments that they do not use. Some compilers issue warnings; others do not. For those compilers that do issue warnings, they differ in how you indicate that the non-use of the variable is intentional and that you do not wish to get a warning. This macro should do whatever is necessary to get your compiler to remain quiet.

6.13 Overriding the compilation flags and other options from makefiles

The following parameters are commonly used when using gnumake to build the KVM.

 
gnumake ROMIZING=false 

Build the KVM with romizing disabled. That is, do not link all the system classes statically into the KVM executable. (The default is to build the KVM with romizing enabled.)

 
gnumake DEBUG=true 

Build the KVM with the Java-level debugger and VM-internal debugging code enabled.

 
gnumake USE_JAM=true 

Build the KVM with the Java Application Manager (JAM) enabled.

 
gnumake GCC=true 

Use GNU C compiler instead of the standard Sun compiler (on Solaris.)

GCC=true is the default option when developing on Linux, and this is the setting for compiling on Windows using CygWin tools.

 
gnumake USE_KNI=false 

Build the KVM without the K Native Interface (KNI) functionality. (The default is to build the KVM with KNI enabled.)

 


Contents Previous Next KVM Porting Guide
, CLDC 1.1