|
From: Arno P. <ar...@pu...> - 2011-08-03 15:30:15
|
there was a question on the mailing list regarding the native interface
for the C backend. While XMLVM already makes extensive use of the native
interface when cross-compiling Apache Harmony, we have not exposed this
functionality in a proper way for applications. However, here a little
how-to showing how this can be done. 'Proper' support would just do a
better job at integrating the following steps into the XMLVM toolchain,
but the basic principles would remain the same.
Consider the following class NativeTest. The idea is to provide an
implementation for nativeMethod() that prints out the array and then
calls back to a Java method:
package xmlvm;
public class NativeTest {
native void nativeMethod(int[] intArray);
void methodToBeCalledFromNative() {
System.out.println("Hello from methodToBeCalledFromNative()");
}
public static void main(String[] args) {
int intArray[] = {2, 4, 6, 8};
NativeTest instance = new NativeTest();
instance.nativeMethod(intArray);
}
}
javac NativeTest.java
xmlvm --in=NativeTest.class --out=out --target=posix
mv out/src/xmlvm.m out/src/xmlvm.c
xmlvm --in=NativeTest.class --out=native \
--target=gen-c-wrappers --gen-native-skeletons
# Ignore the error that the last command will generate. This command
# will generate a skeleton file for nativeMethod().
# In file native/native_xmlvm_NativeTest.c out/src/ inject the following
code:
//XMLVM_BEGIN_NATIVE[xmlvm_NativeTest_nativeMethod___int_1ARRAY]
xmlvm_NativeTest* thiz = me;
printf("Hello from nativeMethod()\n");
org_xmlvm_runtime_XMLVMArray* intArray = n1;
JAVA_ARRAY_INT* data = (JAVA_ARRAY_INT*)
intArray->fields.org_xmlvm_runtime_XMLVMArray.array_;
int length = intArray->fields.org_xmlvm_runtime_XMLVMArray.length_;
for (int i = 0; i < length; i++) {
printf("%d, ", data[i]);
}
printf("\n");
#ifdef XMLVM_VTABLE_IDX_xmlvm_NativeTest_methodToBeCalledFromNative__
VTABLE_PTR func =
thiz->tib->vtable[XMLVM_VTABLE_IDX_xmlvm_NativeTest_methodToBeCalledFromNative__];
(*(void (*)(JAVA_OBJECT)) func)(me);
#else
xmlvm_NativeTest_methodToBeCalledFromNative__(me);
#endif
//XMLVM_END_NATIVE
cp native/native_xmlvm_NativeTest.c out/src/
cd out/dist/
make
./build/out
A few comments: the purpose of the special comment markers
//XMLVM_BEGIN_* and //XMLVM_END_NATIVE is to clearly distinguish between
generated portions of the file (outside the special markers) and
injected code (inside the markers). When the skeleton is regenerated via
--gen-native-skeletons (e.g., because of new added native methods in
NativeTest), the injected code will be automatically migrated.
Another comment regarding the ominous #ifdef: XMLVM performs various
optimizations on the generated C code. If a method is never overridden
in an application, XMLVM will not put it in the vtable of the class. The
#ifdef will be true iff the method in question was overridden. In this
case the method needs to be called via the vtable (the funky looking
function pointer). If the #ifdef is false, it means the method was never
overridden in the application and can therefore be called directly.
Note that the application does not terminate. That is because the
garbage collection thread is not yet a daemon thread and therefore
blocks termination of the application. This will be fixed.
Hope this helps,
Arno
|