17. Bigloo -- The Java interface

Browsing
Home: | Bigloo A ``practical Scheme compiler'' User manual for version 2.6b December 2003
Previous chapter: | The C interface
Next chapter: | Bigloo Libraries
The Java interface
17.1 | Compiling with the JVM back-end
| 17.1.1 | Compiler JVM options
| 17.1.2 | Compiling multi-modules applications
17.2 | JVM back-end and SRFI-0
17.3 | Limitation of the JVM back-end
17.4 | Connecting Scheme and Java code
| 17.4.1 | Automatic Java clauses generation
| 17.4.2 | Declaring Java classes
| 17.4.3 | Declaring abstract Java classes
| 17.4.4 | Extending Java classes
| 17.4.5 | Declaring Java arrays
| 17.4.6 | Exporting Scheme variables
| 17.4.7 | Bigloo runtime customization
17.5 | Performance of the JVM back-end
Chapters
| Acknowledgements
1. | Table of contents
2. | Overview of Bigloo
3. | Modules
4. | Core Language
5. | Standard Library
6. | Pattern Matching
7. | Object System
8. | Threads
9. | Regular parsing
10. | Lalr(1) parsing
11. | Errors and Assertions
12. | Eval and code interpretation
13. | Macro expansion
14. | Command Line Parsing
15. | Explicit typing
16. | The C interface
17. | The Java interface
18. | Bigloo Libraries
19. | Extending the Runtime System
20. | SRFIs
21. | DSSSL support
22. | Compiler description
23. | User Extensions
24. | Bigloo Development Environment
25. | Global Index
26. | Library Index
| Bibliography
| When the Bigloo is configured for a JVM back-end support, the compiler is able to produce Java class file instead of C files. In order to produce JVM class files instead of C, use the `-jvm` compiler option. Example:
    $ cat > foo.scm
    (module foo (main main))
    (define (main argv)
       (print "Hello world: " argv))
    $ bigloo -jvm foo.scm
    $ a.out
      -| Hello world: (/users/serrano/trashcan)

17.1 Compiling with the JVM back-end

### 17.1.1 Compiler JVM options

All the compiler options that control the compilation (optimization options, debugging options, etc.), can be use in conjunction of the `-jvm` option. However, the `-jvm` option MUST be the first compiler option on the command line.
In order to prevent the compiler to produce a JVM `jar` file, it is required to use simultaneously the `-jvm` and `-c` options.

### 17.1.2 Compiling multi-modules applications

In order to compile and link multi-modules applications, it is require to specify the association between Scheme source modules and Java qualified type names. This task is generally complex because of the annoying mapping that exists from Java class names and the operating file system names. In order to get rid of this problem, the Bigloo standard distribution contains a tool, `jfile`, that automatically produces Bigloo Module/Java classes association files. The default name for such a table is `.jfile`. When compiling a module, Bigloo check if a `.jfile` exists in the current directory, if it exists, the file is read. The compilation option `-jfile` may be used to specify an alternative jfile name. Example:

    $ cat > foo.scm
    (module foo (export (foo))) (define (foo) 'foo)
    $ cat > bar.scm
    (module bar (export (bar))) (define (bar) 'bar)
    $ cat > hux.scm
    (module hux (export (hux))) (define (hux) 'hux)
    $ cat > main.scm
    (module main (main main) (import foo bar hux)
    (define (main argv)
       (print (foo))
       (print (bar))
       (print (fhux)))
    $ afile *.scm > .afile
    $ jfile *.scm > .jfile
    $ bigloo -jvm -c foo.scm
    $ bigloo -jvm -c bar.scm
    $ bigloo -jvm -c hux.scm
    $ bigloo -jvm main.scm foo.class bar.class hux.class

For an explanation about the `.afile`, see Modules.

17.2 JVM back-end and SRFI-0

The currently running back-end may be tested by the means of the SRFI-0 `cond-expand` form (see SRFIs). That is, when the JVM is ran, the `bigloo-jvm` clause is true. Otherwise, the `bigloo-c` is true. Example:

    $ cat > foo.scm
    (module foo (main main))
    (define (main argv)
       (cond-expand
          (bigloo-jvm (print "JVM back-end"))
          (bigloo-c (print "C back-end"))
          (else (error "main" "unsupported back-end" #unspecified))))
    $ bigloo -jvm foo.scm
    $ a.out
      -| JVM back-end
    $ bigloo foo.scm
    $ a.out
      -| C back-end

17.3 Limitation of the JVM back-end

The JVM back-end supports the entire Bigloo source language but the `call/cc` function. More precisely, using the JVM back-end, the continuation reified in a `call/cc` form can only be invoked in the dynamic extent of that form.
The other restrictions of the C back-end apply to the JVM back-end. Mainly,

- Bigloo is not able to compile all the tail recursive call without stack consumption (however, most of the tail recursive calls are optimized by Bigloo and don't use stack activation frames).
- Bigloo compiled applications do not check for arithmetic overflow.
- When compiling to Jvm, the `extern` module clauses are not used.
- Jvm runtime system does support the following function `chdir`.
- Jvm runtime system support for `chmod` is restricted.
- In order to read a shell variable from a Bigloo compiled Jvm program, you have to use the Bigloo link option `-jvm-env` when linking that program. However, some shell variables are automatically defined (`HOME`, `USER`, `CLASSPATH` and `TMPDIR`.
- JVM code generation does not support `pragma` forms.

17.4 Connecting Scheme and Java code

When compiling and linking with the JVM back-end, Bigloo source code may use Java API. That is, Bigloo Scheme source code may use (refer or set) Java static variables, Bigloo source code may call static or virtual Java methods. In addition, Bigloo variables and functions may be exported to Java, that is use, set or called in Java source code. Java module clause are enabled (read and parsed) only when compiling to JVM byte code.
Java definitions are declared in Bigloo module by the mean of a Bigloo module clause: the java module clause. The syntax of a Java clause is defined by:

    <java> ==> <declare-class-clause>
         | <declare-abstract-class-clause>
         | <extend-class-clause>
         | <array-clause>
         | <export-clause>

As for extern clause, java clauses are automatically ``transmitted'' by the importation process. That is, if module `module1` imports a module `module2`, `module` treats the `java` clauses of `module2` as though they were included in its own module declaration. Redefinition of a variable or a function already defined in an java clause is an error. However, the definition of a Java class or an Java abstract class may be enriched from module to module.

### 17.4.1 Automatic Java clauses generation

Java clauses can be automatically generated using the Jigloo program which is distributed in the same package as Bigloo. Using Jigloo may be a good way to understand how Java API have to be declared in Bigloo. Jigloo reads Java class files and generate the Bigloo java clauses for that classes.

### 17.4.2 Declaring Java classes

The <declare-class-clause> clause denotes importation of Java classes.

    <declare-class-clause> ==> (class <typed-ident> <slot>* <string>)
    <slot> ==> <field> | <method> | <constructor>
    <field> ==> (field <modifier> <typed-ident> <string>)
    <method> ==> (field <modifier> <typed-ident> (<typed-ident>*) <string>)
    <constructor> ==> (constructor <ident> (<typed-ident>*))
    <modifier> ==> public | private | protected
         | static | final | synchronized | abstract

When the compiler encounters a Java class declaration, it automatically creates a predicate. If the class identifier is `id`, the predicate is named `id?`. In addition, the compiler generates functions that fetch and set the field values. For a field named `f`, these functions are named `id-f` and `id-f-set!`. Methods and constructors are also always prefixed the name of the class. That is, for a method named `m` of a class `k`, the Scheme name of the method is `k-m`.
Example:

    (module java-example
       (java (class point
                (constructor new-default ())
                (field x::int "x")
                (method show::void (::point) "show")
                (method static statistics::int () "PointStatistics")
                "Point")
             (class point-3d::point
                "Point3D")))

    (let ((p (point-new-default)))
       (print (point? p))   -| #t
       (point-x-set! p 3)
       (print (point-x p))) -| 3

### 17.4.3 Declaring abstract Java classes

A Bigloo abstract Java class declaration corresponds to a Java interface. It cannot be instantiate but regular classes may inherit from it.

    <declare-abstract-class-clause> ==> (abstract-class <typed-ident> <slot>* <string>)

### 17.4.4 Extending Java classes

A class definition may be split into several pieces. One class declaration (see <declare-class-clause>) and several extensions. The syntax for a Java class extension is:

    <extend-class-clause> ==> (class <typed-ident> <slot>*)

Example:

    (module java-example2
       (import java-example)
       (java (class point
                (field y::int "y")
                (field static num::int "point_num")
                (constructor new (::int ::int)))))

### 17.4.5 Declaring Java arrays

Java arrays may be allocated and used inside Scheme code. The syntax of a Java array module clause is:

    <array-clause> ==> (array <ident> <typed-ident>)

The <typed-ident> must refer to the name of an existing type (i.e., a primitive Bigloo type, a Bigloo class, an already defined Java class or an already defined Java array). For an array named `ar`, Bigloo generates:

- a creator named `make-ar` which is a function of one integer argument.
- a predicate named `ar?`.
- a getter named `ar-ref` which is a function of one integer argument.
- a setter named `ar-set!` which is a function of two arguments, an integer and a value of the array item types.

Example:

    (module foo
       (java (array int* ::int)
             (class bar
                (method static hello::int (::int*) "hello")
                "bar"))
       (main main))

    (define (main argv)
       (let ((tab (make-int* 2)))
          (int*-set! tab 0 3)
          (int*-set! tab 1 6)
          (print (bar-hello tab))))

### 17.4.6 Exporting Scheme variables

As for the C connection, a Scheme variable (or function) can be exported to the Java world if and only if it is also exported using an `export` Java clause. Type information is given in the Scheme exportation, thus, the only requirement for a variable to be Java exported is to be given a Java name. The Java <export-clause> does this:

    <export-clause> ==> (export <ident> <string>)

Here is an example of exportation:

    (module example
       (export (fib::long ::long))
       (java (export fib "scheme_fib")))

    (define (fib x) (if (< x 2) 1 ...))

### 17.4.7 Bigloo runtime customization

When the Scheme program completes normally, that is when the last expression of the Bigloo main is executed without error, the Bigloo runtime system explicitly call the Java function `System.exit`. In some situation, it may be useful to disable this call. For this, one must set the `boolean` Java static variable `bigloo.foreign.must_exitp` to `false`. This can be implemented in Java or in Scheme. Here is a Scheme module that sets the variable to `false`.

    (module no-exit
      (java (class bigloo
               (field static must-exitp::bool "must_exitp")
               "bigloo.foreign")))

    (cond-expand
      (bigloo-jvm (set! bigloo-must-exitp #f)))

17.5 Performance of the JVM back-end

We are currently improving and investigating about the performance of the JVM back-end. JVM performance is extremely sensitive to the host platform (for instance, very unfortunately, Linux seems to be a poor platform to run JVM code). Currently, it seems that the JVM back-end produces codes that are in between 4 times and 10 times slower than codes produced by the C back-end. The ratio between JVM and C is subject to changes. The gap between JVM and C code is bound to bridge because of the huge amount of efforts applied to efficiently implement Java virtual machines.

This Scribe page has been generated by `scribeinfo`.
Last update Tue Dec 16 13:46:41 2003