|
| 1 | +Functional Overview |
| 2 | +=================== |
| 3 | + |
| 4 | +JNA's platform-specific functionality is provided by the [libffi |
| 5 | +library](https://github.com/atgreen/libffi). Previous to the integration of |
| 6 | +libffi into JNA (largely performed by wmeissner), hand-coded assembly was used |
| 7 | +to support linux, sparc, windows, and Mac OSX (intel and PPC targets). The |
| 8 | +libffi library provides an abstraction for calling arbitrary target addresses |
| 9 | +with an arbitrary set of typed arguments. |
| 10 | + |
| 11 | +The `ffi_prep_cif()` call describes how the target function wishes to be |
| 12 | +called, while `ffi_call()` actually performs the call, provided the CIF |
| 13 | +structure returned by `ffi_prep_cif()`, an arguments array, and a buffer for a |
| 14 | +return value. |
| 15 | + |
| 16 | + |
| 17 | +Interface Mapping |
| 18 | +----------------- |
| 19 | +When you instantiate a native library interface via `Native.loadLibrary()`, |
| 20 | +JNA creates a proxy which routes all method invocations through a single |
| 21 | +`invoke` function in `Library.Handler`. This method looks up an appropriate |
| 22 | +`Function` object which represents a function exported by the native library. |
| 23 | +The proxy handler may perform some initial name translation to derive the |
| 24 | +actual native library function name from the invoked proxy function. |
| 25 | + |
| 26 | +Once the `Function` object is found, its generic `invoke` method is called |
| 27 | +with all available arguments. The proxy function signature is used to figure |
| 28 | +out the types of the incoming arguments and the desired return type. |
| 29 | + |
| 30 | +The `Function` object performs any necessary conversion of arguments, |
| 31 | +converting `NativeMapped` types into their native representation, or applying |
| 32 | +a `TypeMapper` to any incoming types which have registered for `TypeMapper` |
| 33 | +conversion. Similar conversion is performed on function return. By default, |
| 34 | +all `Structure` objects have their Java fields copied into their native memory |
| 35 | +before the native function call, and copied back out after the call. |
| 36 | + |
| 37 | +All `Function` invocations are routed through different native methods based |
| 38 | +on their return type, but all those native methods are dispatched through the |
| 39 | +same `dispatch` call in `native/dispatch.c`. That function performs any final |
| 40 | +conversions of Java objects into native representations before building a |
| 41 | +function call description for use by libffi. |
| 42 | + |
| 43 | +The libffi library requires a description of the target function's arguments |
| 44 | +and return type in order to perform a platform-specific construction of the |
| 45 | +stack suitable for the final native call invocation. Once libffi has |
| 46 | +performed the native call (via `ffi_call()`), it copies the result into a |
| 47 | +buffer provided by JNA, which then converts it back into an appropriate Java |
| 48 | +object. |
| 49 | + |
| 50 | +Direct Mapping |
| 51 | +-------------- |
| 52 | +JNI provides for registering a native function to be called directly when a |
| 53 | +method marked `native` is called from Java. JNA constructs code stubs with |
| 54 | +libffi for each native method registered via the `Native.register()` call (JNA |
| 55 | +uses reflection to identify all methods with the `native` qualifier in the |
| 56 | +direct-mapped class). Each stub dispatches to the function `dispatch_direct` |
| 57 | +in `native/dispatch.c`, and has an associated structure allocated which fully |
| 58 | +describes the function invocation to avoid any reflection costs at runtime. |
| 59 | + |
| 60 | +The central `dispatch_direct` function attempts to pass the Java call stack |
| 61 | +as-is to the native function (again, using `ffi_call()` from libffi). |
| 62 | +The more non-primitive arguments are used, the more the direct dispatch has to |
| 63 | +do extra work to convert Java objects into native representations on the |
| 64 | +stack. Ideal performance is achieved by using only primitive or `Pointer` |
| 65 | +arguments. |
0 commit comments