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 |