Saturday, July 4, 2009

My first project using SWIG

Problem Summary:

We've a byte array in java which has 10000 elements. We have a shared library built with C , which contains some native functions who take char*,signed or unsigned char * parameters.
Now the task is to pass the byte array into the native functions and get the desired result.


Solution Summary:

We used SWIG to make a bridge between C and Java. There are two major tasks. One is to make the byte array acceptable as a char pointer in native functions and the other thing is to retrieve the array via pinning.

To do the first task I need to use the typemapping feature of SWIG. To do the second task I call the getByteArrayElements method which is a JNI method depends on JRE implementation on the desired platform.

Let we have a C file which contains the native functions and we have a Java file from which we call those functions. Here the sample files are given:


FILE: sample.c



















FILE: Runner.java




Now the task is to pass the byte array into the native functions and get the desired results. So a SWIG input file is needed to do the task. The warapper files will be used to make the bridge between two languages. The main challenge is to make the typemapping in that file. Here is the file I wrote to create the wrappers.


FILE: sample.i





Generating the warapper files:



Warning: This is a platform specific solution. Compilationa may vary from platform to platform. Here I used Ububtu 9.04 with openjdk implementation.

I generated my first required files by this SWIG command:
swig -java sample.i

Now I compiled demo1.cpp file with the following command
gcc -c -fpic sample.c

Then I compiled the wrapper file generarted by SWIG with the help of following
command which can be varied if the JDK header files location is different.
gcc -c -fpic sample_wrap.c -I/usr/lib/jvm/java-6-openjdk/include/ -I/usr/lib/jvm/java-6-openjdk/include/linux


Now its the time to make the library which will be used to access the array by native
methods. I used Linux platform, So the library will be libsample.so. If you are using Windows OS, hen
you should generate libsample.dll file.
gcc -shared sample.o sample_wrap.o -o libsample.so

I should add my directory's address to my System's PATH variable to avoid library
linking error with this command.
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH

It's the time to compile the source java file:
javac Runner.java

Showing Output:
To view the output, I used this command.
java Runner

We shall see the output in the console.





Technical Details of sample.i File:




In the first portion of sample.i file we included sample.h file. Otherwise we need to manually declare the prototypes of the native functions.
After that part I include the various.i file of SWIG's library which is needed to do the necessary typemapping from byte datatype to char ponter. Then I declared the first function's (add() function)prototype that doesn't require typemapping.
The second function addIntArray also doesn't require typemapping. So I simply write its prototype. Now we proceed to the third native function testAddByteArray which returns int value and takes char pointer.Here we need to do little coding.
At first we need to rewrite the prototype like this: extern int testAddByteArray(int n,char *BYTE);
Look we use BYTE and INPUTkeyword here. This is must for making the typemaps of byte datatype.
Then I write an in method which describes the parameters and also the way to receive the parameters.
%typemap(in) (int INPUT,char *BYTE) {
$1= JCALL2(GetArrayLength,jenv,$input,0);
$2 = (char *) JCALL2(GetByteArrayElements, jenv, $input, 0);
//Pinning is occured here
}


The local variable $1 receives the array size and $2 receives the byte array by using getByteArrayElements JNI method. If the JRE supports pinning then the array will be retrieved via pinning, that means no copying will be occurred when the array passed to the native functions. The garbage collector must support pinning. In many implementations, pinning is undesirable because it complicates garbage collection algorithms and leads to memory fragmentation. If the garbage collector supports pinning, and the layout of the array is the same as that of a native array of the same type, then no copying is needed. Otherwise, the array is copied to a nonmovable memory block (for example, in the C heap) and the necessary format conversion is performed. A pointer to the copy is returned.


Similarly I've to write code to release memory with this code.
%typemap(argout) char *BYTE {
JCALL3(ReleaseByteArrayElements, jenv, $input, (jbyte *) $1, 0);
//Prevent default freearg typemap from being used
%typemap(freearg) char *BYTE ""

8 comments:

Anonymous said...

Top site, I hadn't noticed prachcho.blogspot.com earlier in my searches!
Keep up the wonderful work!

Anonymous said...

Thanks for sharing the link, but unfortunately it seems to be offline... Does anybody have a mirror or another source? Please reply to my post if you do!

I would appreciate if a staff member here at prachcho.blogspot.com could post it.

Thanks,
Jack

Anonymous said...

Hi there,

This is a message for the webmaster/admin here at prachcho.blogspot.com.

May I use some of the information from this post right above if I provide a link back to this website?

Thanks,
William

Anonymous said...

Good point, though sometimes it's hard to arrive to definite conclusions

Anonymous said...

thank you

Anonymous said...

Greetings,

Thanks for sharing the link - but unfortunately it seems to be down? Does anybody here at prachcho.blogspot.com have a mirror or another source?


Thanks,
William

Anonymous said...

Hi - I am certainly happy to discover this. cool job!

Anonymous said...

Hi - I am certainly delighted to find this. great job!