Native methods

When Java applications need to access functionality from legacy code or hardware devices, you need to implement native methods. Native methods are declared in a class with the native modifier, but are called the same way as any other method is called. Native methods can either be implemented in C or assembler. Most of the runtime native methods are implemented in C, but there are some implemented in assembler for performance.

Declaring native methods

Native methods are declared in the Java source file as shown below.
    public static native void cmain();

Producing native method stubs

When you write code with native methods, the class converter has the option to produce native method stubs for all the native methods in the application or library. To do this, add the following line to the makefile.
    JAVA_NATIVE=1

This creates a number of files in the native subdirectory that contain stub functions for all the native methods. These stub functions are all in assembler as the Lightfoot Java and C calling conventions are different.

You should always copy the required stub files out of the native subdirectory to prevent your modified version from getting overwritten when you rebuild your application!

Implementing native methods in C

The easiest way to implement native methods is to modify the stub function to call a C function to do the processing. There are two soft bytecodes that can be used to call a C function from Java.
These both take the address of a C function on the stop of the stack. The Jcscalln also takes a parameter which is the number of arguments for that function. These arguments should have been pushed onto the stack.
When the C function completes, it returns to the native method with any return value in parameter register P3.
The following code snippets show various ways of calling C code from Java.

Simple no argument call

    cnst       NoArgFunction     ; Function address from the constant pool
    Jcscall0                     ; Call with no arguments
    Jxreturn                     ; No return value

Simple no argument call returning a value
    cnst       NoArgFunctionRet  ; Function address from the constant pool
    Jcscall0                     ; Call with no arguments
    lp3                          ; return value
    Jxreturn                     ; return

Single argument call returning a value
    lp0                        ; this for a virtual method, arg0 for
                               ; a static method
    cnst      ArgFunctionRet   ; Function address from the constant pool
    Jcscalln  1                ; Call with 1 argument
    lp3                        ; return value


Accessing instance variables from native methods

If you need to access instance variables from native methods, the best way to do this is to create a C structure that maps directly to the class structure and access the fields of the structure. Many of the Java hardware native methods use this technique to store the device handle in the class and read the instance number from the class.

C structure
typedef struct _JavaGPIO_t {
    /** The device handle */
    DCT_DEVHANDLE       hHandle;

    /** The port */
    int32               port;

    /** The mask */
    int32               mask;

} JavaGPIO_t;

Java class
    /** The handle used in the native methods */
    private int hHandle;

    /** The GPIO port */
    private int port;

    /** The mask to use */
    private int mask;

Java functionality available from C

The Lightfoot SDK provides a subset of JNI functionality allowing you to manipulate objects. The header file native.h provides the following functionality.
Function
Description
GetStringCChars
Given a Java string, allocate a zero terminated C string on the heap. This must be freed when finished with.
ReleaseStringCChars
Release the C string allocated by GetStringCChars
NewStringC
Create a Java string from a zero terminated C string.
NewByteArray
Create a new array of bytes
NewObjectArray
Create a new array of objects
FindClass
Find a class given the name
ThrowNew
Throw a new exception with a message
Throw
Throw an exsting exception
GetArrayLength
Get the length of the specified array
IsJavaNull
Return true if the Java object is null
GetMethodID
Get the method id given a class and method name
AllocObject
Allocate, but do not initialise a new object
NewObject
Create a new object and call the specified constructor
CallVoidMethod
Call a void method with no arguments
CallVoidMethodA
Call a void method with arguments specified in the argument array