Jikes User FAQ
 

 

Jikes User FAQ

This FAQ is for users of Jikes, the high-performance Open Source Java compiler. It covers common questions about setting up and using binary versions of Jikes, especially where things are different from Sun's javac compiler.

If you are looking for information about installing Jikes from source, or would like to get involved in Jikes development, please see the Jikes Developer FAQ.

Table of Contents

1. Where to I get Jikes?
2. How do I use it? What options does it support?
3. Why must I define CLASSPATH? What is JIKESPATH?
4. How do I control the compiler listing?
5. What is incremental compilation?
6. How do I use Jikes to generate dependencies for make?
7. Why does Jikes reject a program that another compiler accepts, or accept one that it rejects?
8. What can I do if I don't get the same results when using class files generated by Jikes?
9. How do I report bugs?

Where do I get Jikes?

If you use Linux, check the distributions page for a list of Linux distributions known to include Jikes as a standard package. For other platforms, go to the downloads page and look for an official binary version of Jikes. A Zip file is provided for Windows users, just unzip it and place the bin directory on your PATH. If there isn't an official version for your operating system, join the jikes mailing list and search the archives. There might be an unofficial port available, or someone else might be working on one. If you're still out of luck, why not download the source and try compiling it yourself? The Developer FAQ has a lot of information about compiling Jikes. Join the the jikes-dev mailing list where other developers can help you out.

Back to top

How do I use it? What options does it support?

Invoke Jikes in the form:

jikes options filename...

Invoke Jikes with no arguments to see a short summary of the arguments. Allowed options are:

-classpath path
Set classpath.
-d dir
Write class files in specified directory.
-debug
No effect (recognized for compatibility with many compilers).
-depend
Recompile all used classes.
-deprecation
Report on use of deprecated features.
-g
Generate LocalVariableTable attribute.
-nowarn
Suppress warning messages.
-nowrite
Do not write any class files.
-O
Do not generate LineNumberTable attribute.
-verbose
List files read and written.
-Xstdout
Write error messages to standard output.
++
Compile in incremental mode.
+B
Do not generate bytecode. This is used primarily for debugging the compiler. The -nowrite option generates byte code but does not write it out.
+OLDCSO
As of Jikes 1.12, the default classpath search order has changed to be more like javac. Jikes now searches all directories for a class or java file, and then compares their dates to determine if recompilation is necessary. The +OLDCSO option is provided for backward compatibility and causes Jikes to follow the classpath search order used by older version of Jikes.
+D
List errors immediately in Emacs-form without buffering. This is only needed if Jikes is crashing and you want to see errors as soon as they are detected; ordinarily errors are sorted and listed at the end of the compilation.
+DR=filename
Write report of dependencies to specified file.
+E
List errors in a machine readilbe form commonly used by Emacs to scan for errors. By default errors are listed in a more human readable form.
+F
Do full dependence check except for Zip and Jar files.
+M
Generate makefiles with dependencies.
+P
Generate pedantic listing.
+Tnn
Set tab width for listing error messages.
+U
Do full dependence check including Zip and Jar files.
+Z
Treat cautions as errors.

Jikes can be used to compile more than one file at a time, causing a class file to be created for each Java source file. It is possible that compilation of a file named early on in the argument list will force the compilation of a file that is also named later on; however, no file will be compiled more than once. Jikes allows the same file to be named more than once; however, such files are only compiled once:

jikes Test.java x.java Test.java

Jikes also accepts arguments starting with an at-sign (@). Such arguments are taken be the name of a file, each line of which is then processed as though it were itself an argument, except that lines so read that begin with an at-sign are not processed recursively. For example, the above command could also be written as:

jikes @file.list

where file.list is a file containing the lines:

Test.java
x.java
Test.java

Back to top

Why must I define CLASSPATH? What is JIKESPATH?

You must have some version of the JDK or JRE to run Jikes, so the compiler can access the standard class files. Note that from version 1.1 of the JDK, you are not required to provide a definition of CLASSPATH to run javac and java. However, Jikes doesn't know what version of the JDK you are using and so must be told how to find the standard library files. This can be done in three ways:

  • Provide a definition of CLASSPATH; for example, in Windows using Sun's JDK, this takes the form of one of the following
    set CLASSPATH=.;C:\Java\lib\classes.zip                 (JDK 1.1)
    set CLASSPATH=.;C:\jdk1.2.2\jre\lib\rt.jar              (JDK 1.2)
    set CLASSPATH=.;C:\Program Files\JDK1.3\jre\lib\rt.jar  (JDK 1.3)
    or with the IBM Developer Kit 2.0 (compatible with Sun's J2SE version 1.3)
    set CLASSPATH=.;C:\Program Files\IBM\Java13\jre\lib\rt.jar
    or with Microsoft's SDK for Java 4.0 (after running "clspack -auto")
    set CLASSPATH=.;C:\WINNT\Java\Classes\classes.zip
    In Linux you would use
    export CLASSPATH=.:/usr/local/jdk1.1.6/lib/classes.zip  (JDK 1.1)
    export CLASSPATH=.:/usr/local/jre1.1.6/lib/rt.jar       (JRE 1.1)
    export CLASSPATH=.:/opt/jdk1.3/jre/lib/rt.jar           (JDK 1.3)
    or for csh
    setenv CLASSPATH .:/usr/local/jdk1.1.6/lib/classes.zip  (JDK 1.1)
    setenv CLASSPATH .:/usr/local/jre1.1.6/lib/rt.jar       (JRE 1.1)
    setenv CLASSPATH .:/opt/jdk1.3/jre/lib/rt.jar           (JDK 1.3)
  • Always specify a value for the -classpath option on the command line; for example:
    jikes -classpath .:/opt/jdk1.3/jre/lib/rt.jar ...
  • Use JIKESPATH as discussed below.

Jikes allows the use of JAR files, which have the standard "zip" format, provided that any contained class files are stored either using no compression or the default "DeflatedN" compression (also known as "method 8" in zip-speak). Indeed, any item in the class path that is a not a directory is assumed to be a file in zip format. The code used to do the the uncompression is based on that used in unzip532 from Info-ZIP, so we need to make the following statement:

Jikes incorporates compression code from the Info-ZIP group. There are no extra charges or costs due to the use of this code, and the original compression sources are freely available from Info-ZIP on the Internet.

Jikes looks for a definition of JIKESPATH in the environment before it looks for a definition of CLASSPATH. If JIKESPATH is defined, then its value is used when looking for a class file.

You should almost always include "." in the classpath; omit it only if you understand the implications.

The order in which the classpath is searched can also be selected using the +OLDCSO (old classpath search order) option. As of Jikes 1.12, by default the same behavior as javac is followed:

  • Find the java file which occurs leftmost in the classpath.
  • Find the class file which occurs leftmost in the classpath.
  • Use the more recent of these for compilation purposes.

If the +OLDCSO option is specified, Jikes operates in a backward-compatible mode:

  • Jikes searches the classpath from left to right.
  • In a given directory, it finds the most recent java or class file.
  • Jikes then uses the java/class found in the leftmost classpath entry for compilation purposes.

Back to top

How do I control the compiler listing?

Jikes does not produce a compiler listing in the usual sense, but only writes out warnings, cautions, and errors.

A caution is more severe than a warning, but normally does not prevent the writing of the class file. The +Z option can be used to prevent the writing of a class file if any cautions are detected.

A number of options select the kind and volume of the information produced. They are -nowarn, -verbose, +E and +P. The first two are found in most Java compilers: -nowarn requests that warning messages not be written, -verbose requests a report on the files, including source and class files, read and written by the compiler.

The error kind option +E is used to select how error messages are formatted, By default, error messages are written in a long form with the part of the text the compiler is complaining about underlined, and with detailed explanatory text. The +E option requests a terser form, suitable for automatic parsing by editors such as Emacs and Epsilon. For example, consider the mis-typed "hello world" example:

class hello {
   public static void main(String[] args) {
     system.out.println("hi there"); // should be System...
   }
}

When +E is not used, the error is reported as

Found 1 semantic error compiling "hello.java":


     3.      system.out.println("hi there"); // should be System...
             <-------->
*** Semantic Error: "system/out" is either a misplaced package name
                    or a non-existent entity.
          

With +E is used, the error is reported as:

hello.java:3:6:3:15: Semantic:"system/out" is either a misplaced
package name or a non-existent entity.

The initial part of each line contains several fields, separated by colons, giving in order the file name, the starting line in the file, the starting column in the starting line, the ending line, and the column number in the ending line.

The pedantic option +P is used to request a complete, pedantic listing. Just what is or is not pedantic depends in part on email we have received in which users have noted that Jikes complains about constructs that other compilers accept. (It is an open question whether the other compilers choose not to report this information, or whether they do not even discover it.) Select this option for a detailed listing. Currently, the following are only reported if +P is selected:

  • No type declarations:
    This compilation unit contains no type declaration
  • Empty declarations, typically the result of an extraneous semicolon:
    An EmptyDeclaration is a deprecated feature that should
    not be used
  • Attempt to overwrite a method with private access:
    Note that the method ... in class ... does not override
    the corresponding method with private access in class ...
  • Attempt to overwrite a method with default access:
    The method ... in class ... does not override the
    corresponding method with default access in class ...
  • Access to a type defined in an unnamed package. This message is issued in response to the comment in section 7.4.2 of the specification that "It is recommended that a Java system provide safeguards against unintended consequences in situations where compiliation units of named packages import types from unnamed packages."
    The type associated with this construct is (or depends on)
    the type ... which is contained in an unnamed package

We say C depends on D if and only if the constant pool for C contains a reference to D. Types so referenced may need to be incorporated into the compilation, either by reading their class file or compiling a source file to produce the needed class file. Incorporation is done as follows:

  • If there is no class file and there is a source file, then the source file is compiled.
  • If there is no source file and there is a class file, then the class file is read.
  • If both a class file and a source file exist, then the class file is read only if it is newer than the source file; otherwise the source file is compiled.
  • If there is no class file and no source file, an error is reported.

(The effect of the -depend option is to always compile a source file if there is one.)

By default, Jikes does not incorporate D unless it must.

If +F is specified, and C does not belong to a Zip or Jar file, the type D is incorporated. Otherwise, D is incorporated only if it must be.

If +U is specified, then D is always incorporated.

The option +F directs the compiler to load all other types that are referenced within a class file, and causes recompilation of such files if their source file is more up-to-date than the class file. Normally, other types are loaded only if required for the current compilation.

The option -depend (which can also be written -Xdepend, for 1.2 compatibility) directs the compiler to always compile a source file, if one exists, instead of loading its class file, even if it exists and is up-to-date.

Consider the following example:

// file A.java:
class A {
  static public void main(String[] args) {
    System.out.println("enter A");
    B.message();
  }
}

// file B.java:
class B {
  static void message() {
    System.out.println("enter B");
    C.message();
  }
}

// file C.java:
class C {
  static void message() {
    System.out.println("enter C");
  }
}

If no class files exist, then

jikes A.java

results in compilation of A, B and C.

If C.java (but not B.java) is updated, then

jikes A.java

results in compilation only of A. javac does the same thing.

However, if C.java (but not B.java) is updated, then

jikes +F A.java

results in compilation of A and C.

It is always the case, independent of time-stamps of files, that

jikes -depend A.java

results in compilation of A, B and C.

Note that

jikes -depend +F ...

has the same effect as

jikes -depend ...

i.e., +F will cause no more files to be compiled than will -depend.

You can use +F to get reports of errors and warnings resulting from the use of out-of-date or non-existent classes, at the expense of increasing compilation time. By default, Jikes assumes that class files placed in Zip and Jar files do not reference files not contained in Zip or Jar files; the +U option should be used when this is not the case.

Back to top

What is incremental compilation?

Most Java compilers support at least some form of dependency resolution, where we say that file A depends on file B if a change to B implies that A must be rebuilt. For example, A.class depends on the source file defining A, usually A.java. The make program is commonly used to record the dependencies and keep files up to date.

Many Java compilers support a simple make-like function, as follows: when compiling A check all classes referred to by A and recompile any whose class file is older than the source file. This approach can cause problems if this implies recompiling B, and B is up to date, but uses C which is out of date, in which case C may not be recompiled.

Jikes supports the option -depend and interprets it as a request to recompile all used classes whether or not they are up to date with respect to their source file.

Jikes also supports the option +F to force a fuller check of dependency. If compilation of A.java requires B.class then B will be recompiled if it is out of date. Once B.class is available, it is read, and any classes it references are also checked for dependencies. This fuller check is more expensive, but will not cause the problems that can result using the simple approach used by many compilers.

Jikes can also be run in an incremental mode that works as follows:

  • Open a window and compile your program using
    jikes ++ Main.java
    where Main.java denotes your root source file. Jikes will then compile Main.java and all the files it references, building a complete set of dependencies, and will then wait for input. (Note that ++ implies +F also.)
  • Modify your source files using your favorite editor until you are ready to rebuild your program, and then type an empty line in the window in which Jikes is waiting. Jikes will then determine which source files have been changed, and will then perform the minimum number of compilations needed to bring to class files into a complete and consistent state. You can repeat this cycle as you wish, until you
  • Terminate the compilation by typing a single line
    q
    in the window in which Jikes is waiting. Jikes will then terminate.

By the way, you may notice a substantial delay after you type q to end the incremental mode. This results from the time needed to execute the destructors invoked to delete all the nodes in the abstract syntax tree, all the symbols in the symbol table, etc. This cost is also incurred whenever the compiler must delete its current in-memory data structures before compiling a changed file. We are aware of this cost and are looking at ways to reduce it, but are making the compiler available with this known performance limitation so you can try it and test it for correctness.

Back to top

How do I use Jikes to generate dependencies for make?

Most C and C++ compilers support the option -M to generate dependency information for use with make. Jikes provides the same function for Java using the option +M, which requests that Jikes create a file X.u for each file X.class that is compiled, and include in this file a list of all the files that X.class depends on. Note that use of the +M option turns on full dependency checking (as is done by the +F option).

The contents of any zip files in CLASSPATH are assumed to be fixed, and so are not included in the generated makefiles, mainly to avoid cluttering up the dependency list with voluminous dependencies on the contents of java.*.

You can also use the option +DR=filename to request that a dependence report be written to the file filename. The format is designed to allow the use of the information as input to a tool; for example, it could be used for a tool that determines the minimum set of class files that must be included in a jar file.

Back to top

Why does Jikes reject a program that another compiler accepts, or accept one that it rejects?

You may find that Jikes accepts a program that another compiler rejects (or can't compile), or rejects programs that another compiler accepts.

Each version of Jikes represents our best effort at the proper interpretation of the language specification. Although Jikes is designed to work with all but the earliest versions of the JDK, we make no claim that any particular version supports precisely the same language as any particular version of the JDK. Since some products are designed to work with specific versions of the JDK, the compilers associated with them may not always recognize the same programs as Jikes.

This section contains some examples of issues related to interpreting the specification.

Class Literal Semantics

The Java Language Specification does not allow class literals to cause class initialization, even though javac has always done it this way. Jikes used to also cause class initialization, but starting with 1.17 it will not.

The following example demonstrates the difference in behaviour between allowing class literals to cause class initialization, and not

class Super {
   static int i = 1;
   static void m(Class c) {
     System.out.println(i);
   }
   public static void main(String[] args) {
     m(Sub.class);
   }
}
class Sub extends Super {
   static { i = 2; }
}

With old versions of jikes, or other buggy compilers, executing Super will output 2 (since the class initialization of Sub took place and changed the value of i). But with jikes 1.17 and later, the executing Super will correctly output 1.

To update your code to force class initialization (and thus preserve the semantics you were used to), an explicit call to Class.forName will help. In the above example, rewriting Super.m() as shown below will give the desired behavior of outputting 2.

static void m(Class c) {
  // we aren't sure if c is initialized, hence this try-block
  try {
    if (c != null)
      c.forName(c.getName());
  } catch (Exception e) {
    // shouldn't get here, and even if we do, we ignore it
  }
  System.out.println(i);
}

For additional details, see this posting to jikes-dev.

Extraneous Semicolons

Your program may contain extraneous semicolons that are silently ignored by many compilers. For example, given

public class Test {
   void f() {};          // first extra semicolon
};                       // second extra semicolon

Jikes accepts the program but issues:

     2.       void f() {};       // first extra semicolon
*** Warning: An EmptyDeclaration is a deprecated feature that 
             should not be used - ";" ignored

     3.    };                   // second extra semicolon
            ^
*** Warning: An EmptyDeclaration is a deprecated feature that
             should not be used - ";" ignored

The first extra semicolon is erroneous, the second is allowed by section 7.6. Jikes treats each as cause to issue a warning. You can use the -nowarn option to suppress this (and other) warnings, or, even better, you can use your editor to delete those extra semicolons.

Unreachable Statements

It is a compile-time error if a statement cannot be executed because it is unreachable (section 14.19). When Jikes first appeared, some other compilers didn't properly detect unreachable statements, and accepted programs such as the following:

class Test {
   void method(boolean b) {
      if (b) return;
      else return;
      b = !b;
   }
}

Jikes rejected this program:

        b = !b;
        <----->
*** Semantic Error: This statement is unreachable

(This is the example referrred to in PC Week (April 14, 1997): IBM, Netscape Up Web Ante.)

Another example, and one that confused many users, is shown by the following program:

class Test {
   public static void main(String[] args) {
      try {
      }
      catch (Exception e) {
         System.out.println("caught"); 
      }
   }
}

Jikes accepts this program but issues the warning:

        catch (Exception e) {
               <--------->
*** Caution: This catch block is unreachable: there is no
             exception whose type is assignable to
             "java/lang/Exception" that can be thrown during
             execution of the body of the try block

This was the most frequently reported problem when Jikes first appeared. It took several months to confirm that Jikes was right all along. See Query #2 to Sun for the full story.

Cyclic Scoping

Jikes rejects the program:

class X extends Y.Z {}
class Y extends X.Z {}

because Jikes checks for cycles by grouping types as follows:

  • Types that are package members form a group.
  • Within the body of a given type, all the inner types immediately declared in it form a group. In other words, if we look at the complete name of a type beginning with the name of its outermost enclosing type, all types that share the same prefix form a group.

When a type T "extends" or "implements" a type U, we find the innermost enclosing group that contains an enclosing type Tx of T (which may be T itself) and an enclosing type Ux of U (which may be U itself) and add a dependence edge from Tx to Ux. We then check for cycles in the graph induced by this relationship.

Consider the following example:

class Z {}

class W extends Z
{
    class A
    {
        class x extends B {}
        class y extends x {}
    }

    class B
    {
        class x extends A.x {}
    }

    class C extends B.x {}
}

Its dependence graph contains the following edges:

  • W->Z, since W and Z are both package members
  • W.A->W.B, because type W.A.x extends W.B
  • W.A.y->W.A.x, because type W.A.y extends W.A.x
  • W.B->W.A, because type W.B.x extends W.A.x
  • W.C->W.B, because type W.C extends W.B.x

This graph has a cycle: W.A->W.B->W.A. So Jikes rejects this program:

Found 3 semantic errors compiling "Z.java":

     5.     class A
                  ^
*** Semantic Error: The class "W$A" is circularly defined with
                    its super type(s)
  
    ...

Another example of cyclic dependence is found in the following code scheme used in some forms of the Swing package:

class C implements C.I {
    ...
    interface I { ... }
}

This example is cyclic by Jikes's model of dependence. We asked Sun about this usage: Query #31 to Sun: Rules of inheritance of class members. Their response agrees with our interpretation that this usage is erroneous.

Queries to Sun

Here are some more examples of issues related to interpreting the language specification:
Query #1 to Sun: Inner Static
Query #2 to Sun: Unreachable Statements
Query #3 to Sun: Dependence
Query #4 to Sun: Are block-level inner interface declarations allowed?
Query #5 to Sun: String Concatenation Operator + and void
Query #6 to Sun: Getting a line on the LineNumberTable
Query #7 to Sun: Setting of InnerClasses_attribute inner_class_access_flags
Query #8 to Sun: Scope of Local Variable Declarations and Local Classes
Query #9 to Sun: Qualifying new for static inner class
Query #10 to Sun: Can a class access its own private methods via a subclass?
Query #11 to Sun: Access to members in anonymous classes
Query #12 to Sun: Anonymous inner classes should be final for instanceof and casts
Query #13 to Sun: Access to inner classes
Query #14 to Sun: Unreachability and do-while
Query #15 to Sun: Access control bug with protected member of sibling/outer classes
Query #16 to Sun: Floating point and bitwise operators
Query #17 to Sun: Compile-time evaluation of constant expressions
Query #18 to Sun: Explicit versus implicit setting of attributes, servialVersionUID algorithm
Query #19 to Sun: Octal escapes in string literals
Query #20 to Sun: What does "package-private method" mean?
Query #21 to Sun: Name resolution
Query #22 to Sun: Circularity problem?
Query #23 to Sun: Packages and non-existing directories
Query #24 to Sun: Protected
Query #25 to Sun: Can user-deifned package have a type named "java"?
Query #26 to Sun: Acceptability of unreachable byte code
Query #27 to Sun: Representation of null value
Query #28 to Sun: Use of anonymous class in explicit constructor invocation
Query #29 to Sun: When can the ConstantValue attribute be used?
Query #30 to Sun: Labeled statements and nested classes
Query #31 to Sun: Rules of inheritance of class members
Query #32 to Sun: Verification problem
Query #33 to Sun: Field resolution for interfaces
Query #34 to Sun: Which checked exceptions need to be checked?
Query #35 to Sun: Clarification of White Space (3.6)

The Unofficial Java Spec Report

The Unofficial Java Spec Report is an unofficial site that covers problems with the Java Language Specification, the Java Virtual Machine Specification, and the core API documents. It is maintained by Roly Perera and Peter Bertelsen, and we wish to thank them for their service to the Java community.

Starting with Jikes v0.28, we will attempt to track the recommendations of the unofficial report, and implement them where feasible. The current status for the 1.1 portion in Issue 9 (22 May 1998) is as follows:

  • No definition of cyclic scoping. Jikes has its definition, as described earlier.
  • Resolution of ambiguous names. Implemented.
  • Access to protected members across nest siblings. Implemented.
  • Can nested interfaces redundantly be declared static? Yes.
  • Behavior of new when qualified with an expression that evalutes to null is undefined. Implemented.
  • Rule for making inacessible classes implicitly final is too lax. Jikes does not make this transformation.
  • Reachability of instance initializers and constructors undefined. Implemented.
  • Initialization requirements for blank final fields incorrect. Implemented.
  • When qualified new or super can be used unspecified. Implemented.
  • Blank finals and interface fields. Implemented.
  • When may this be used in an explicit constructor invocation. Implemented.
  • New hiding rules for parameters and local variables. Implemented.
  • Blank finals and try statements. Implemented.
  • Blank finals and loops. Implemented.
  • Unclear whether forward referencing rule changes. Implemented.
  • Transformations for anonymous classes unspecified. Implemented.
  • Private methods implicitly final. Implemented.

Back to top

What can I do if I don't get the same results when using class files generated by Jikes?

It is possible that your current compiler was miscompiling the program and Jikes got it right. Jikes may have miscompiled your program and we would appreciate your reporting the problem. Here are some steps that may clarify the situation.

When you run your program using the Java virtual machine, run java with the option -verify to enable bytecode verification. If verification this shows one or more class files are faulty, you've found a bug in Jikes. Please tell us about it.

You should also to see if the Java virtual machine is using a JIT, in which case you should try with the JIT disabled. We have seen cases when JIT's fail with class files produced by Jikes, even though these class files pass verification.

Otherwise build two sets of class files, one using your current compiler and one using Jikes. Then, selectively substitute those produced by Jikes until you find a class file generated by Jikes whose use results in other than the expected output. If it appears that Jikes is at fault, please tell us about it.

Back to top

How do I report bugs?

This has been documented seperately.

Back to top